📄 isar.c
字号:
if ((skb = dev_alloc_skb(2))) { memcpy(skb_put(skb, 2), dleetx, 2); skb_queue_tail(&bcs->rqueue, skb); isar_sched_event(bcs, B_RCVBUFREADY); } else { printk(KERN_WARNING "HiSax: skb out of memory\n"); }}static inline intdle_count(unsigned char *buf, int len){ int count = 0; while (len--) if (*buf++ == DLE) count++; return count;}static inline voidinsert_dle(unsigned char *dest, unsigned char *src, int count) { /* <DLE> in input stream have to be flagged as <DLE><DLE> */ while (count--) { *dest++ = *src; if (*src++ == DLE) *dest++ = DLE; }} static inline voidisar_rcv_frame(struct IsdnCardState *cs, struct BCState *bcs){ u_char *ptr; struct sk_buff *skb; struct isar_reg *ireg = bcs->hw.isar.reg; if (!ireg->clsb) { debugl1(cs, "isar zero len frame"); cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0); return; } switch (bcs->mode) { case L1_MODE_NULL: debugl1(cs, "isar mode 0 spurious IIS_RDATA %x/%x/%x", ireg->iis, ireg->cmsb, ireg->clsb); printk(KERN_WARNING"isar mode 0 spurious IIS_RDATA %x/%x/%x\n", ireg->iis, ireg->cmsb, ireg->clsb); cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0); break; case L1_MODE_TRANS: case L1_MODE_V32: if ((skb = dev_alloc_skb(ireg->clsb))) { rcv_mbox(cs, ireg, (u_char *)skb_put(skb, ireg->clsb)); skb_queue_tail(&bcs->rqueue, skb); isar_sched_event(bcs, B_RCVBUFREADY); } else { printk(KERN_WARNING "HiSax: skb out of memory\n"); cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0); } break; case L1_MODE_HDLC: if ((bcs->hw.isar.rcvidx + ireg->clsb) > HSCX_BUFMAX) { if (cs->debug & L1_DEB_WARN) debugl1(cs, "isar_rcv_frame: incoming packet too large"); cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0); bcs->hw.isar.rcvidx = 0; } else if (ireg->cmsb & HDLC_ERROR) { if (cs->debug & L1_DEB_WARN) debugl1(cs, "isar frame error %x len %d", ireg->cmsb, ireg->clsb);#ifdef ERROR_STATISTIC if (ireg->cmsb & HDLC_ERR_RER) bcs->err_inv++; if (ireg->cmsb & HDLC_ERR_CER) bcs->err_crc++;#endif bcs->hw.isar.rcvidx = 0; cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0); } else { if (ireg->cmsb & HDLC_FSD) bcs->hw.isar.rcvidx = 0; ptr = bcs->hw.isar.rcvbuf + bcs->hw.isar.rcvidx; bcs->hw.isar.rcvidx += ireg->clsb; rcv_mbox(cs, ireg, ptr); if (ireg->cmsb & HDLC_FED) { if (bcs->hw.isar.rcvidx < 3) { /* last 2 bytes are the FCS */ if (cs->debug & L1_DEB_WARN) debugl1(cs, "isar frame to short %d", bcs->hw.isar.rcvidx); } else if (!(skb = dev_alloc_skb(bcs->hw.isar.rcvidx-2))) { printk(KERN_WARNING "ISAR: receive out of memory\n"); } else { memcpy(skb_put(skb, bcs->hw.isar.rcvidx-2), bcs->hw.isar.rcvbuf, bcs->hw.isar.rcvidx-2); skb_queue_tail(&bcs->rqueue, skb); isar_sched_event(bcs, B_RCVBUFREADY); } bcs->hw.isar.rcvidx = 0; } } break; case L1_MODE_FAX: if (bcs->hw.isar.state != STFAX_ACTIV) { if (cs->debug & L1_DEB_WARN) debugl1(cs, "isar_rcv_frame: not ACTIV"); cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0); bcs->hw.isar.rcvidx = 0; break; } if (bcs->hw.isar.cmd == PCTRL_CMD_FRM) { rcv_mbox(cs, ireg, bcs->hw.isar.rcvbuf); bcs->hw.isar.rcvidx = ireg->clsb + dle_count(bcs->hw.isar.rcvbuf, ireg->clsb); if (cs->debug & L1_DEB_HSCX) debugl1(cs, "isar_rcv_frame: raw(%d) dle(%d)", ireg->clsb, bcs->hw.isar.rcvidx); if ((skb = dev_alloc_skb(bcs->hw.isar.rcvidx))) { insert_dle((u_char *)skb_put(skb, bcs->hw.isar.rcvidx), bcs->hw.isar.rcvbuf, ireg->clsb); skb_queue_tail(&bcs->rqueue, skb); isar_sched_event(bcs, B_RCVBUFREADY); if (ireg->cmsb & SART_NMD) { /* ABORT */ if (cs->debug & L1_DEB_WARN) debugl1(cs, "isar_rcv_frame: no more data"); bcs->hw.isar.rcvidx = 0; send_DLE_ETX(bcs); sendmsg(cs, SET_DPS(bcs->hw.isar.dpath) | ISAR_HIS_PUMPCTRL, PCTRL_CMD_ESC, 0, NULL); bcs->hw.isar.state = STFAX_ESCAPE; isar_sched_event(bcs, B_LL_NOCARRIER); } } else { printk(KERN_WARNING "HiSax: skb out of memory\n"); } break; } if (bcs->hw.isar.cmd != PCTRL_CMD_FRH) { if (cs->debug & L1_DEB_WARN) debugl1(cs, "isar_rcv_frame: unknown fax mode %x", bcs->hw.isar.cmd); cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0); bcs->hw.isar.rcvidx = 0; break; } /* PCTRL_CMD_FRH */ if ((bcs->hw.isar.rcvidx + ireg->clsb) > HSCX_BUFMAX) { if (cs->debug & L1_DEB_WARN) debugl1(cs, "isar_rcv_frame: incoming packet too large"); cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0); bcs->hw.isar.rcvidx = 0; } else if (ireg->cmsb & HDLC_ERROR) { if (cs->debug & L1_DEB_WARN) debugl1(cs, "isar frame error %x len %d", ireg->cmsb, ireg->clsb); bcs->hw.isar.rcvidx = 0; cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0); } else { if (ireg->cmsb & HDLC_FSD) { bcs->hw.isar.rcvidx = 0; } ptr = bcs->hw.isar.rcvbuf + bcs->hw.isar.rcvidx; bcs->hw.isar.rcvidx += ireg->clsb; rcv_mbox(cs, ireg, ptr); if (ireg->cmsb & HDLC_FED) { int len = bcs->hw.isar.rcvidx + dle_count(bcs->hw.isar.rcvbuf, bcs->hw.isar.rcvidx); if (bcs->hw.isar.rcvidx < 3) { /* last 2 bytes are the FCS */ if (cs->debug & L1_DEB_WARN) debugl1(cs, "isar frame to short %d", bcs->hw.isar.rcvidx); printk(KERN_WARNING "ISAR: frame to short %d\n", bcs->hw.isar.rcvidx); } else if (!(skb = dev_alloc_skb(bcs->hw.isar.rcvidx))) { printk(KERN_WARNING "ISAR: receive out of memory\n"); } else { insert_dle((u_char *)skb_put(skb, len), bcs->hw.isar.rcvbuf, bcs->hw.isar.rcvidx); skb_queue_tail(&bcs->rqueue, skb); isar_sched_event(bcs, B_RCVBUFREADY); send_DLE_ETX(bcs); isar_sched_event(bcs, B_LL_OK); test_and_clear_bit(BC_FLG_FRH_WAIT, &bcs->Flag); } bcs->hw.isar.rcvidx = 0; } } if (ireg->cmsb & SART_NMD) { /* ABORT */ if (cs->debug & L1_DEB_WARN) debugl1(cs, "isar_rcv_frame: no more data"); bcs->hw.isar.rcvidx = 0; sendmsg(cs, SET_DPS(bcs->hw.isar.dpath) | ISAR_HIS_PUMPCTRL, PCTRL_CMD_ESC, 0, NULL); bcs->hw.isar.state = STFAX_ESCAPE; if (test_and_clear_bit(BC_FLG_FRH_WAIT, &bcs->Flag)) { send_DLE_ETX(bcs); isar_sched_event(bcs, B_LL_NOCARRIER); } } break; default: printk(KERN_ERR"isar_rcv_frame mode (%x)error\n", bcs->mode); cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0); break; }}voidisar_fill_fifo(struct BCState *bcs){ struct IsdnCardState *cs = bcs->cs; int count; u_char msb; u_char *ptr; long flags; if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO)) debugl1(cs, "isar_fill_fifo"); if (!bcs->tx_skb) return; if (bcs->tx_skb->len <= 0) return; if (!(bcs->hw.isar.reg->bstat & (bcs->hw.isar.dpath == 1 ? BSTAT_RDM1 : BSTAT_RDM2))) return; if (bcs->tx_skb->len > bcs->hw.isar.mml) { msb = 0; count = bcs->hw.isar.mml; } else { count = bcs->tx_skb->len; msb = HDLC_FED; } save_flags(flags); cli(); ptr = bcs->tx_skb->data; if (!bcs->hw.isar.txcnt) { msb |= HDLC_FST; if ((bcs->mode == L1_MODE_FAX) && (bcs->hw.isar.cmd == PCTRL_CMD_FTH)) { if (bcs->tx_skb->len > 1) { if ((ptr[0]== 0xff) && (ptr[1] == 0x13)) /* last frame */ test_and_set_bit(BC_FLG_LASTDATA, &bcs->Flag); } } } skb_pull(bcs->tx_skb, count); bcs->tx_cnt -= count; bcs->hw.isar.txcnt += count; switch (bcs->mode) { case L1_MODE_NULL: printk(KERN_ERR"isar_fill_fifo wrong mode 0\n"); break; case L1_MODE_TRANS: case L1_MODE_V32: sendmsg(cs, SET_DPS(bcs->hw.isar.dpath) | ISAR_HIS_SDATA, 0, count, ptr); break; case L1_MODE_HDLC: sendmsg(cs, SET_DPS(bcs->hw.isar.dpath) | ISAR_HIS_SDATA, msb, count, ptr); break; case L1_MODE_FAX: if (bcs->hw.isar.state != STFAX_ACTIV) { if (cs->debug & L1_DEB_WARN) debugl1(cs, "isar_fill_fifo: not ACTIV"); } else if (bcs->hw.isar.cmd == PCTRL_CMD_FTH) { sendmsg(cs, SET_DPS(bcs->hw.isar.dpath) | ISAR_HIS_SDATA, msb, count, ptr); } else if (bcs->hw.isar.cmd == PCTRL_CMD_FTM) { sendmsg(cs, SET_DPS(bcs->hw.isar.dpath) | ISAR_HIS_SDATA, 0, count, ptr); } else { if (cs->debug & L1_DEB_WARN) debugl1(cs, "isar_fill_fifo: not FTH/FTM"); } break; default: if (cs->debug) debugl1(cs, "isar_fill_fifo mode(%x) error", bcs->mode); printk(KERN_ERR"isar_fill_fifo mode(%x) error\n", bcs->mode); break; } restore_flags(flags);}inlinestruct BCState *sel_bcs_isar(struct IsdnCardState *cs, u_char dpath){ if ((!dpath) || (dpath == 3)) return(NULL); if (cs->bcs[0].hw.isar.dpath == dpath) return(&cs->bcs[0]); if (cs->bcs[1].hw.isar.dpath == dpath) return(&cs->bcs[1]); return(NULL);}inline voidsend_frames(struct BCState *bcs){ if (bcs->tx_skb) { if (bcs->tx_skb->len) { isar_fill_fifo(bcs); return; } else { if (bcs->st->lli.l1writewakeup && (PACKET_NOACK != bcs->tx_skb->pkt_type)) bcs->st->lli.l1writewakeup(bcs->st, bcs->hw.isar.txcnt); if (bcs->mode == L1_MODE_FAX) { if (bcs->hw.isar.cmd == PCTRL_CMD_FTH) { if (test_bit(BC_FLG_LASTDATA, &bcs->Flag)) { test_and_set_bit(BC_FLG_NMD_DATA, &bcs->Flag); } } else if (bcs->hw.isar.cmd == PCTRL_CMD_FTM) { if (test_bit(BC_FLG_DLEETX, &bcs->Flag)) { test_and_set_bit(BC_FLG_LASTDATA, &bcs->Flag); test_and_set_bit(BC_FLG_NMD_DATA, &bcs->Flag); } } } dev_kfree_skb_any(bcs->tx_skb); bcs->hw.isar.txcnt = 0; bcs->tx_skb = NULL; } } if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) { bcs->hw.isar.txcnt = 0; test_and_set_bit(BC_FLG_BUSY, &bcs->Flag); isar_fill_fifo(bcs); } else { if (test_and_clear_bit(BC_FLG_DLEETX, &bcs->Flag)) { if (test_and_clear_bit(BC_FLG_LASTDATA, &bcs->Flag)) { if (test_and_clear_bit(BC_FLG_NMD_DATA, &bcs->Flag)) { u_char dummy = 0; sendmsg(bcs->cs, SET_DPS(bcs->hw.isar.dpath) | ISAR_HIS_SDATA, 0x01, 1, &dummy); } test_and_set_bit(BC_FLG_LL_OK, &bcs->Flag); } else { isar_sched_event(bcs, B_LL_CONNECT); } } test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); isar_sched_event(bcs, B_XMTBUFREADY); }}inline voidcheck_send(struct IsdnCardState *cs, u_char rdm){ struct BCState *bcs; if (rdm & BSTAT_RDM1) { if ((bcs = sel_bcs_isar(cs, 1))) { if (bcs->mode) { send_frames(bcs); } } } if (rdm & BSTAT_RDM2) { if ((bcs = sel_bcs_isar(cs, 2))) { if (bcs->mode) { send_frames(bcs); } } } }const char *dmril[] = {"NO SPEED", "1200/75", "NODEF2", "75/1200", "NODEF4", "300", "600", "1200", "2400", "4800", "7200", "9600nt", "9600t", "12000", "14400", "WRONG"};const char *dmrim[] = {"NO MOD", "NO DEF", "V32/V32b", "V22", "V21", "Bell103", "V23", "Bell202", "V17", "V29", "V27ter"};static voidisar_pump_status_rsp(struct BCState *bcs, struct isar_reg *ireg) { struct IsdnCardState *cs = bcs->cs; u_char ril = ireg->par[0]; u_char rim; if (!test_and_clear_bit(ISAR_RATE_REQ, &bcs->hw.isar.reg->Flags)) return; if (ril > 14) { if (cs->debug & L1_DEB_WARN) debugl1(cs, "wrong pstrsp ril=%d",ril); ril = 15; } switch(ireg->par[1]) { case 0: rim = 0; break; case 0x20: rim = 2; break; case 0x40: rim = 3; break; case 0x41: rim = 4; break; case 0x51: rim = 5; break; case 0x61: rim = 6; break; case 0x71: rim = 7; break; case 0x82: rim = 8; break; case 0x92: rim = 9; break; case 0xa2: rim = 10; break; default: rim = 1; break; } sprintf(bcs->hw.isar.conmsg,"%s %s", dmril[ril], dmrim[rim]); bcs->conmsg = bcs->hw.isar.conmsg; if (cs->debug & L1_DEB_HSCX) debugl1(cs, "pump strsp %s", bcs->conmsg);}static voidisar_pump_statev_modem(struct BCState *bcs, u_char devt) { struct IsdnCardState *cs = bcs->cs; u_char dps = SET_DPS(bcs->hw.isar.dpath); switch(devt) { case PSEV_10MS_TIMER: if (cs->debug & L1_DEB_HSCX) debugl1(cs, "pump stev TIMER"); break; case PSEV_CON_ON: if (cs->debug & L1_DEB_HSCX) debugl1(cs, "pump stev CONNECT"); l1_msg_b(bcs->st, PH_ACTIVATE | REQUEST, NULL); break; case PSEV_CON_OFF: if (cs->debug & L1_DEB_HSCX) debugl1(cs, "pump stev NO CONNECT"); sendmsg(cs, dps | ISAR_HIS_PSTREQ, 0, 0, NULL); l1_msg_b(bcs->st, PH_DEACTIVATE | REQUEST, NULL); break; case PSEV_V24_OFF: if (cs->debug & L1_DEB_HSCX) debugl1(cs, "pump stev V24 OFF"); break; case PSEV_CTS_ON: if (cs->debug & L1_DEB_HSCX) debugl1(cs, "pump stev CTS ON"); break; case PSEV_CTS_OFF: if (cs->debug & L1_DEB_HSCX) debugl1(cs, "pump stev CTS OFF"); break; case PSEV_DCD_ON: if (cs->debug & L1_DEB_HSCX) debugl1(cs, "pump stev CARRIER ON"); test_and_set_bit(ISAR_RATE_REQ, &bcs->hw.isar.reg->Flags); sendmsg(cs, dps | ISAR_HIS_PSTREQ, 0, 0, NULL); break; case PSEV_DCD_OFF: if (cs->debug & L1_DEB_HSCX) debugl1(cs, "pump stev CARRIER OFF"); break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -