diff options
Diffstat (limited to 'drivers/isdn/hisax/isar.c')
-rw-r--r-- | drivers/isdn/hisax/isar.c | 700 |
1 files changed, 604 insertions, 96 deletions
diff --git a/drivers/isdn/hisax/isar.c b/drivers/isdn/hisax/isar.c index 417f2157d..bfff86707 100644 --- a/drivers/isdn/hisax/isar.c +++ b/drivers/isdn/hisax/isar.c @@ -1,4 +1,4 @@ -/* $Id: isar.c,v 1.7 1999/10/14 20:25:29 keil Exp $ +/* $Id: isar.c,v 1.9 2000/01/20 19:47:45 keil Exp $ * isar.c ISAR (Siemens PSB 7110) specific routines * @@ -6,6 +6,12 @@ * * * $Log: isar.c,v $ + * Revision 1.9 2000/01/20 19:47:45 keil + * Add Fax Class 1 support + * + * Revision 1.8 1999/12/19 13:00:56 keil + * Fix races in setting a new mode + * * Revision 1.7 1999/10/14 20:25:29 keil * add a statistic for error monitoring * @@ -42,7 +48,17 @@ #define MIN(a,b) ((a<b)?a:b) +#define DLE 0x10 +#define ETX 0x03 + + +const u_char faxmodulation_s[] = "3,24,48,72,73,74,96,97,98,121,122,145,146"; +const u_char faxmodulation[] = {3,24,48,72,73,74,96,97,98,121,122,145,146}; +#define FAXMODCNT 13 + void isar_setup(struct IsdnCardState *cs); +static void isar_pump_cmd(struct BCState *bcs, u_char cmd, u_char para); +static inline void ll_deliver_faxstat(struct BCState *bcs, u_char status); static inline int waitforHIA(struct IsdnCardState *cs, int timeout) @@ -432,6 +448,12 @@ static void isar_bh(struct BCState *bcs) { BChannel_bh(bcs); + if (test_and_clear_bit(B_LL_NOCARRIER, &bcs->event)) + ll_deliver_faxstat(bcs, ISDN_FAX_CLASS1_NOCARR); + if (test_and_clear_bit(B_LL_CONNECT, &bcs->event)) + ll_deliver_faxstat(bcs, ISDN_FAX_CLASS1_CONNECT); + if (test_and_clear_bit(B_LL_OK, &bcs->event)) + ll_deliver_faxstat(bcs, ISDN_FAX_CLASS1_OK); } static void @@ -443,6 +465,42 @@ isar_sched_event(struct BCState *bcs, int event) } static inline void +send_DLE_ETX(struct BCState *bcs) +{ + u_char dleetx[2] = {DLE,ETX}; + struct sk_buff *skb; + + 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 int +dle_count(unsigned char *buf, int len) +{ + int count = 0; + + while (len--) + if (*buf++ == DLE) + count++; + return count; +} + +static inline void +insert_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 void isar_rcv_frame(struct IsdnCardState *cs, struct BCState *bcs) { u_char *ptr; @@ -512,6 +570,88 @@ isar_rcv_frame(struct IsdnCardState *cs, struct BCState *bcs) } } 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"); + cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0); + 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"); + cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0); + } + 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) { + if (bcs->hw.isar.rcvidx < 3) { /* last 2 bytes are the FCS */ + printk(KERN_WARNING "ISAR: HDLC frame too 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 { + memcpy(skb_put(skb, bcs->hw.isar.rcvidx), + 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); + } + } + } + break; default: printk(KERN_ERR"isar_rcv_frame mode (%x)error\n", bcs->mode); cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0); @@ -544,38 +684,57 @@ isar_fill_fifo(struct BCState *bcs) count = bcs->tx_skb->len; msb = HDLC_FED; } - if (!bcs->hw.isar.txcnt) - msb |= HDLC_FST; 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: - if (!sendmsg(cs, SET_DPS(bcs->hw.isar.dpath) | ISAR_HIS_SDATA, - 0, count, ptr)) { - if (cs->debug) - debugl1(cs, "isar bin data send dp%d failed", - bcs->hw.isar.dpath); - } - break; - case L1_MODE_HDLC: - if (!sendmsg(cs, SET_DPS(bcs->hw.isar.dpath) | ISAR_HIS_SDATA, - msb, count, ptr)) { + 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 hdlc data send dp%d failed", - bcs->hw.isar.dpath); - } - break; - default: - printk(KERN_ERR"isar_fill_fifo mode (%x)error\n", bcs->mode); - break; + 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); } @@ -603,6 +762,18 @@ send_frames(struct BCState *bcs) 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(bcs->tx_skb); bcs->hw.isar.txcnt = 0; bcs->tx_skb = NULL; @@ -613,6 +784,18 @@ send_frames(struct BCState *bcs) 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); } @@ -639,6 +822,7 @@ check_send(struct IsdnCardState *cs, u_char rdm) } } + const char *dmril[] = {"NO SPEED", "1200/75", "NODEF2", "75/1200", "NODEF4", "300", "600", "1200", "2400", "4800", "7200", "9600nt", "9600t", "12000", "14400", "WRONG"}; @@ -700,7 +884,7 @@ isar_pump_status_rsp(struct BCState *bcs, struct isar_reg *ireg) { } static void -isar_pump_status_ev(struct BCState *bcs, u_char devt) { +isar_pump_statev_modem(struct BCState *bcs, u_char devt) { struct IsdnCardState *cs = bcs->cs; u_char dps = SET_DPS(bcs->hw.isar.dpath); @@ -769,6 +953,192 @@ isar_pump_status_ev(struct BCState *bcs, u_char devt) { } } +static inline void +ll_deliver_faxstat(struct BCState *bcs, u_char status) +{ + isdn_ctrl ic; + struct Channel *chanp = (struct Channel *) bcs->st->lli.userdata; + + if (bcs->cs->debug & L1_DEB_HSCX) + debugl1(bcs->cs, "HL->LL FAXIND %x", status); + ic.driver = bcs->cs->myid; + ic.command = ISDN_STAT_FAXIND; + ic.arg = chanp->chan; + ic.parm.aux.cmd = status; + bcs->cs->iif.statcallb(&ic); +} + +static void +isar_pump_statev_fax(struct BCState *bcs, u_char devt) { + struct IsdnCardState *cs = bcs->cs; + u_char dps = SET_DPS(bcs->hw.isar.dpath); + u_char p1; + + switch(devt) { + case PSEV_10MS_TIMER: + if (cs->debug & L1_DEB_HSCX) + debugl1(cs, "pump stev TIMER"); + break; + case PSEV_RSP_READY: + if (cs->debug & L1_DEB_HSCX) + debugl1(cs, "pump stev RSP_READY"); + bcs->hw.isar.state = STFAX_READY; + l1_msg_b(bcs->st, PH_ACTIVATE | REQUEST, NULL); + if (test_bit(BC_FLG_ORIG, &bcs->Flag)) { + isar_pump_cmd(bcs, ISDN_FAX_CLASS1_FRH, 3); + } else { + isar_pump_cmd(bcs, ISDN_FAX_CLASS1_FTH, 3); + } + break; + case PSEV_LINE_TX_H: + if (bcs->hw.isar.state == STFAX_LINE) { + if (cs->debug & L1_DEB_HSCX) + debugl1(cs, "pump stev LINE_TX_H"); + bcs->hw.isar.state = STFAX_CONT; + sendmsg(cs, dps | ISAR_HIS_PUMPCTRL, PCTRL_CMD_CONT, 0, NULL); + } else { + if (cs->debug & L1_DEB_WARN) + debugl1(cs, "pump stev LINE_TX_H wrong st %x", + bcs->hw.isar.state); + } + break; + case PSEV_LINE_RX_H: + if (bcs->hw.isar.state == STFAX_LINE) { + if (cs->debug & L1_DEB_HSCX) + debugl1(cs, "pump stev LINE_RX_H"); + bcs->hw.isar.state = STFAX_CONT; + sendmsg(cs, dps | ISAR_HIS_PUMPCTRL, PCTRL_CMD_CONT, 0, NULL); + } else { + if (cs->debug & L1_DEB_WARN) + debugl1(cs, "pump stev LINE_RX_H wrong st %x", + bcs->hw.isar.state); + } + break; + case PSEV_LINE_TX_B: + if (bcs->hw.isar.state == STFAX_LINE) { + if (cs->debug & L1_DEB_HSCX) + debugl1(cs, "pump stev LINE_TX_B"); + bcs->hw.isar.state = STFAX_CONT; + sendmsg(cs, dps | ISAR_HIS_PUMPCTRL, PCTRL_CMD_CONT, 0, NULL); + } else { + if (cs->debug & L1_DEB_WARN) + debugl1(cs, "pump stev LINE_TX_B wrong st %x", + bcs->hw.isar.state); + } + break; + case PSEV_LINE_RX_B: + if (bcs->hw.isar.state == STFAX_LINE) { + if (cs->debug & L1_DEB_HSCX) + debugl1(cs, "pump stev LINE_RX_B"); + bcs->hw.isar.state = STFAX_CONT; + sendmsg(cs, dps | ISAR_HIS_PUMPCTRL, PCTRL_CMD_CONT, 0, NULL); + } else { + if (cs->debug & L1_DEB_WARN) + debugl1(cs, "pump stev LINE_RX_B wrong st %x", + bcs->hw.isar.state); + } + break; + case PSEV_RSP_CONN: + if (bcs->hw.isar.state == STFAX_CONT) { + if (cs->debug & L1_DEB_HSCX) + debugl1(cs, "pump stev RSP_CONN"); + bcs->hw.isar.state = STFAX_ACTIV; + test_and_set_bit(ISAR_RATE_REQ, &bcs->hw.isar.reg->Flags); + sendmsg(cs, dps | ISAR_HIS_PSTREQ, 0, 0, NULL); + if (bcs->hw.isar.cmd == PCTRL_CMD_FTH) { + /* 1s Flags before data */ + if (test_and_set_bit(BC_FLG_FTI_RUN, &bcs->Flag)) + del_timer(&bcs->hw.isar.ftimer); + /* 1000 ms */ + bcs->hw.isar.ftimer.expires = + jiffies + ((1000 * HZ)/1000); + test_and_set_bit(BC_FLG_LL_CONN, + &bcs->Flag); + add_timer(&bcs->hw.isar.ftimer); + } else { + isar_sched_event(bcs, B_LL_CONNECT); + } + } else { + if (cs->debug & L1_DEB_WARN) + debugl1(cs, "pump stev RSP_CONN wrong st %x", + bcs->hw.isar.state); + } + break; + case PSEV_FLAGS_DET: + if (cs->debug & L1_DEB_HSCX) + debugl1(cs, "pump stev FLAGS_DET"); + break; + case PSEV_RSP_DISC: + if (cs->debug & L1_DEB_HSCX) + debugl1(cs, "pump stev RSP_DISC"); + if (bcs->hw.isar.state == STFAX_ESCAPE) { + switch(bcs->hw.isar.newcmd) { + case PCTRL_CMD_FTH: + case PCTRL_CMD_FTM: + p1 = 10; + sendmsg(cs, dps | ISAR_HIS_PUMPCTRL, + PCTRL_CMD_SILON, 1, &p1); + bcs->hw.isar.state = STFAX_SILDET; + break; + case PCTRL_CMD_FRH: + case PCTRL_CMD_FRM: + p1 = bcs->hw.isar.newmod; + bcs->hw.isar.newmod = 0; + bcs->hw.isar.cmd = bcs->hw.isar.newcmd; + bcs->hw.isar.newcmd = 0; + sendmsg(cs, dps | ISAR_HIS_PUMPCTRL, + bcs->hw.isar.cmd, 1, &p1); + bcs->hw.isar.state = STFAX_LINE; + break; + default: + if (cs->debug & L1_DEB_HSCX) + debugl1(cs, "RSP_DISC unknown newcmd %x", bcs->hw.isar.newcmd); + break; + } + } else if (bcs->hw.isar.state == STFAX_ACTIV) { + if (test_and_clear_bit(BC_FLG_LL_OK, &bcs->Flag)) { + isar_sched_event(bcs, B_LL_OK); + } else if (bcs->hw.isar.cmd == PCTRL_CMD_FRM) { + send_DLE_ETX(bcs); + isar_sched_event(bcs, B_LL_NOCARRIER); + } else { + ll_deliver_faxstat(bcs, ISDN_FAX_CLASS1_FCERROR); + } + bcs->hw.isar.state = STFAX_READY; + } else { + bcs->hw.isar.state = STFAX_READY; + ll_deliver_faxstat(bcs, ISDN_FAX_CLASS1_FCERROR); + } + break; + case PSEV_RSP_SILDET: + if (cs->debug & L1_DEB_HSCX) + debugl1(cs, "pump stev RSP_SILDET"); + if (bcs->hw.isar.state == STFAX_SILDET) { + p1 = bcs->hw.isar.newmod; + bcs->hw.isar.newmod = 0; + bcs->hw.isar.cmd = bcs->hw.isar.newcmd; + bcs->hw.isar.newcmd = 0; + sendmsg(cs, dps | ISAR_HIS_PUMPCTRL, + bcs->hw.isar.cmd, 1, &p1); + bcs->hw.isar.state = STFAX_LINE; + } + break; + case PSEV_RSP_SILOFF: + if (cs->debug & L1_DEB_HSCX) + debugl1(cs, "pump stev RSP_SILOFF"); + break; + case PSEV_RSP_FCERR: + if (cs->debug & L1_DEB_HSCX) + debugl1(cs, "pump stev RSP_FCERR"); + bcs->hw.isar.state = STFAX_ESCAPE; + sendmsg(cs, dps | ISAR_HIS_PUMPCTRL, PCTRL_CMD_ESC, 0, NULL); + ll_deliver_faxstat(bcs, ISDN_FAX_CLASS1_FCERROR); + break; + default: + break; + } +} + static char debbuf[128]; void @@ -788,8 +1158,6 @@ isar_int_main(struct IsdnCardState *cs) } else { debugl1(cs, "isar spurious IIS_RDATA %x/%x/%x", ireg->iis, ireg->cmsb, ireg->clsb); - printk(KERN_WARNING"isar spurious IIS_RDATA %x/%x/%x\n", - ireg->iis, ireg->cmsb, ireg->clsb); cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0); } break; @@ -815,12 +1183,18 @@ isar_int_main(struct IsdnCardState *cs) case ISAR_IIS_PSTEV: if ((bcs = sel_bcs_isar(cs, ireg->iis >> 6))) { rcv_mbox(cs, ireg, (u_char *)ireg->par); - isar_pump_status_ev(bcs, ireg->cmsb); + if (bcs->mode == L1_MODE_V32) { + isar_pump_statev_modem(bcs, ireg->cmsb); + } else if (bcs->mode == L1_MODE_FAX) { + isar_pump_statev_fax(bcs, ireg->cmsb); + } else { + if (cs->debug & L1_DEB_WARN) + debugl1(cs, "isar IIS_PSTEV pmode %d stat %x", + bcs->mode, ireg->cmsb); + } } else { debugl1(cs, "isar spurious IIS_PSTEV %x/%x/%x", ireg->iis, ireg->cmsb, ireg->clsb); - printk(KERN_WARNING"isar spurious IIS_PSTEV %x/%x/%x\n", - ireg->iis, ireg->cmsb, ireg->clsb); cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0); } break; @@ -831,8 +1205,6 @@ isar_int_main(struct IsdnCardState *cs) } else { debugl1(cs, "isar spurious IIS_PSTRSP %x/%x/%x", ireg->iis, ireg->cmsb, ireg->clsb); - printk(KERN_WARNING"isar spurious IIS_PSTRSP %x/%x/%x\n", - ireg->iis, ireg->cmsb, ireg->clsb); cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0); } break; @@ -867,6 +1239,17 @@ isar_int_main(struct IsdnCardState *cs) } static void +ftimer_handler(struct BCState *bcs) { + if (bcs->cs->debug) + debugl1(bcs->cs, "ftimer flags %04x", + bcs->Flag); + test_and_clear_bit(BC_FLG_FTI_RUN, &bcs->Flag); + if (test_and_clear_bit(BC_FLG_LL_CONN, &bcs->Flag)) { + isar_sched_event(bcs, B_LL_CONNECT); + } +} + +static void setup_pump(struct BCState *bcs) { struct IsdnCardState *cs = bcs->cs; u_char dps = SET_DPS(bcs->hw.isar.dpath); @@ -876,11 +1259,7 @@ setup_pump(struct BCState *bcs) { case L1_MODE_NULL: case L1_MODE_TRANS: case L1_MODE_HDLC: - if (!sendmsg(cs, dps | ISAR_HIS_PUMPCFG, PMOD_BYPASS, 0, NULL)) { - if (cs->debug) - debugl1(cs, "isar pump bypass cfg dp%d failed", - bcs->hw.isar.dpath); - } + sendmsg(cs, dps | ISAR_HIS_PUMPCFG, PMOD_BYPASS, 0, NULL); break; case L1_MODE_V32: ctrl = PMOD_DATAMODEM; @@ -896,11 +1275,7 @@ setup_pump(struct BCState *bcs) { param[2] = PV32P3_AMOD | PV32P3_V32B | PV32P3_V23B; param[3] = PV32P4_UT144; param[4] = PV32P5_UT144; - if (!sendmsg(cs, dps | ISAR_HIS_PUMPCFG, ctrl, 6, param)) { - if (cs->debug) - debugl1(cs, "isar pump datamodem cfg dp%d failed", - bcs->hw.isar.dpath); - } + sendmsg(cs, dps | ISAR_HIS_PUMPCFG, ctrl, 6, param); break; case L1_MODE_FAX: ctrl = PMOD_FAX; @@ -911,18 +1286,16 @@ setup_pump(struct BCState *bcs) { param[1] = PFAXP2_ATN; } param[0] = 6; /* 6 db */ - if (!sendmsg(cs, dps | ISAR_HIS_PUMPCFG, ctrl, 2, param)) { - if (cs->debug) - debugl1(cs, "isar pump faxmodem cfg dp%d failed", - bcs->hw.isar.dpath); - } + sendmsg(cs, dps | ISAR_HIS_PUMPCFG, ctrl, 2, param); + bcs->hw.isar.state = STFAX_NULL; + bcs->hw.isar.newcmd = 0; + bcs->hw.isar.newmod = 0; + test_and_set_bit(BC_FLG_FTI_RUN, &bcs->Flag); break; } - if (!sendmsg(cs, dps | ISAR_HIS_PSTREQ, 0, 0, NULL)) { - if (cs->debug) - debugl1(cs, "isar pump status req dp%d failed", - bcs->hw.isar.dpath); - } + udelay(1000); + sendmsg(cs, dps | ISAR_HIS_PSTREQ, 0, 0, NULL); + udelay(1000); } static void @@ -933,44 +1306,30 @@ setup_sart(struct BCState *bcs) { switch (bcs->mode) { case L1_MODE_NULL: - if (!sendmsg(cs, dps | ISAR_HIS_SARTCFG, SMODE_DISABLE, 0, NULL)) { - if (cs->debug) - debugl1(cs, "isar sart disable dp%d failed", - bcs->hw.isar.dpath); - } + sendmsg(cs, dps | ISAR_HIS_SARTCFG, SMODE_DISABLE, 0, + NULL); break; case L1_MODE_TRANS: - if (!sendmsg(cs, dps | ISAR_HIS_SARTCFG, SMODE_BINARY, 2, "\0\0")) { - if (cs->debug) - debugl1(cs, "isar sart binary dp%d failed", - bcs->hw.isar.dpath); - } + sendmsg(cs, dps | ISAR_HIS_SARTCFG, SMODE_BINARY, 2, + "\0\0"); break; case L1_MODE_HDLC: case L1_MODE_FAX: param[0] = 0; - if (!sendmsg(cs, dps | ISAR_HIS_SARTCFG, SMODE_HDLC, 1, param)) { - if (cs->debug) - debugl1(cs, "isar sart hdlc dp%d failed", - bcs->hw.isar.dpath); - } + sendmsg(cs, dps | ISAR_HIS_SARTCFG, SMODE_HDLC, 1, + param); break; case L1_MODE_V32: ctrl = SMODE_V14 | SCTRL_HDMC_BOTH; param[0] = S_P1_CHS_8; param[1] = S_P2_BFT_DEF; - if (!sendmsg(cs, dps | ISAR_HIS_SARTCFG, ctrl, 2, param)) { - if (cs->debug) - debugl1(cs, "isar sart v14 dp%d failed", - bcs->hw.isar.dpath); - } + sendmsg(cs, dps | ISAR_HIS_SARTCFG, ctrl, 2, + param); break; } - if (!sendmsg(cs, dps | ISAR_HIS_BSTREQ, 0, 0, NULL)) { - if (cs->debug) - debugl1(cs, "isar buf stat req dp%d failed", - bcs->hw.isar.dpath); - } + udelay(1000); + sendmsg(cs, dps | ISAR_HIS_BSTREQ, 0, 0, NULL); + udelay(1000); } static void @@ -995,15 +1354,10 @@ setup_iom2(struct BCState *bcs) { cmsb |= IOM_CTRL_ALAW | IOM_CTRL_RCV; break; } - if (!sendmsg(cs, dps | ISAR_HIS_IOM2CFG, cmsb, 5, msg)) { - if (cs->debug) - debugl1(cs, "isar iom2 dp%d failed", bcs->hw.isar.dpath); - } - if (!sendmsg(cs, dps | ISAR_HIS_IOM2REQ, 0, 0, NULL)) { - if (cs->debug) - debugl1(cs, "isar IOM2 cfg req dp%d failed", - bcs->hw.isar.dpath); - } + sendmsg(cs, dps | ISAR_HIS_IOM2CFG, cmsb, 5, msg); + udelay(1000); + sendmsg(cs, dps | ISAR_HIS_IOM2REQ, 0, 0, NULL); + udelay(1000); } int @@ -1041,8 +1395,8 @@ modeisar(struct BCState *bcs, int mode, int bc) &bcs->hw.isar.reg->Flags)) bcs->hw.isar.dpath = 1; else { - printk(KERN_WARNING"isar modeisar analog works only with DP1\n"); - debugl1(cs, "isar modeisar analog works only with DP1"); + printk(KERN_WARNING"isar modeisar analog funktions only with DP1\n"); + debugl1(cs, "isar modeisar analog funktions only with DP1"); return(1); } break; @@ -1066,6 +1420,107 @@ modeisar(struct BCState *bcs, int mode, int bc) return(0); } +static void +isar_pump_cmd(struct BCState *bcs, u_char cmd, u_char para) +{ + struct IsdnCardState *cs = bcs->cs; + u_char dps = SET_DPS(bcs->hw.isar.dpath); + u_char ctrl = 0, nom = 0, p1 = 0; + + switch(cmd) { + case ISDN_FAX_CLASS1_FTM: + if (bcs->hw.isar.state == STFAX_READY) { + p1 = para; + ctrl = PCTRL_CMD_FTM; + nom = 1; + bcs->hw.isar.state = STFAX_LINE; + bcs->hw.isar.cmd = ctrl; + bcs->hw.isar.mod = para; + bcs->hw.isar.newmod = 0; + bcs->hw.isar.newcmd = 0; + } else if ((bcs->hw.isar.state == STFAX_ACTIV) && + (bcs->hw.isar.cmd == PCTRL_CMD_FTM) && + (bcs->hw.isar.mod == para)) { + ll_deliver_faxstat(bcs, ISDN_FAX_CLASS1_CONNECT); + } else { + bcs->hw.isar.newmod = para; + bcs->hw.isar.newcmd = PCTRL_CMD_FTM; + nom = 0; + ctrl = PCTRL_CMD_ESC; + bcs->hw.isar.state = STFAX_ESCAPE; + } + break; + case ISDN_FAX_CLASS1_FTH: + if (bcs->hw.isar.state == STFAX_READY) { + p1 = para; + ctrl = PCTRL_CMD_FTH; + nom = 1; + bcs->hw.isar.state = STFAX_LINE; + bcs->hw.isar.cmd = ctrl; + bcs->hw.isar.mod = para; + bcs->hw.isar.newmod = 0; + bcs->hw.isar.newcmd = 0; + } else if ((bcs->hw.isar.state == STFAX_ACTIV) && + (bcs->hw.isar.cmd == PCTRL_CMD_FTH) && + (bcs->hw.isar.mod == para)) { + ll_deliver_faxstat(bcs, ISDN_FAX_CLASS1_CONNECT); + } else { + bcs->hw.isar.newmod = para; + bcs->hw.isar.newcmd = PCTRL_CMD_FTH; + nom = 0; + ctrl = PCTRL_CMD_ESC; + bcs->hw.isar.state = STFAX_ESCAPE; + } + break; + case ISDN_FAX_CLASS1_FRM: + if (bcs->hw.isar.state == STFAX_READY) { + p1 = para; + ctrl = PCTRL_CMD_FRM; + nom = 1; + bcs->hw.isar.state = STFAX_LINE; + bcs->hw.isar.cmd = ctrl; + bcs->hw.isar.mod = para; + bcs->hw.isar.newmod = 0; + bcs->hw.isar.newcmd = 0; + } else if ((bcs->hw.isar.state == STFAX_ACTIV) && + (bcs->hw.isar.cmd == PCTRL_CMD_FRM) && + (bcs->hw.isar.mod == para)) { + ll_deliver_faxstat(bcs, ISDN_FAX_CLASS1_CONNECT); + } else { + bcs->hw.isar.newmod = para; + bcs->hw.isar.newcmd = PCTRL_CMD_FRM; + nom = 0; + ctrl = PCTRL_CMD_ESC; + bcs->hw.isar.state = STFAX_ESCAPE; + } + break; + case ISDN_FAX_CLASS1_FRH: + if (bcs->hw.isar.state == STFAX_READY) { + p1 = para; + ctrl = PCTRL_CMD_FRH; + nom = 1; + bcs->hw.isar.state = STFAX_LINE; + bcs->hw.isar.cmd = ctrl; + bcs->hw.isar.mod = para; + bcs->hw.isar.newmod = 0; + bcs->hw.isar.newcmd = 0; + } else if ((bcs->hw.isar.state == STFAX_ACTIV) && + (bcs->hw.isar.cmd == PCTRL_CMD_FRH) && + (bcs->hw.isar.mod == para)) { + ll_deliver_faxstat(bcs, ISDN_FAX_CLASS1_CONNECT); + } else { + bcs->hw.isar.newmod = para; + bcs->hw.isar.newcmd = PCTRL_CMD_FRH; + nom = 0; + ctrl = PCTRL_CMD_ESC; + bcs->hw.isar.state = STFAX_ESCAPE; + } + break; + } + if (ctrl) + sendmsg(cs, dps | ISAR_HIS_PUMPCTRL, ctrl, nom, &p1); +} + void isar_setup(struct IsdnCardState *cs) { @@ -1076,11 +1531,8 @@ isar_setup(struct IsdnCardState *cs) msg = 61; for (i=0; i<2; i++) { /* Buffer Config */ - if (!sendmsg(cs, (i ? ISAR_HIS_DPS2 : ISAR_HIS_DPS1) | - ISAR_HIS_P12CFG, 4, 1, &msg)) { - if (cs->debug) - debugl1(cs, "isar P%dCFG failed", i+1); - } + sendmsg(cs, (i ? ISAR_HIS_DPS2 : ISAR_HIS_DPS1) | + ISAR_HIS_P12CFG, 4, 1, &msg); cs->bcs[i].hw.isar.mml = msg; cs->bcs[i].mode = 0; cs->bcs[i].hw.isar.dpath = i + 1; @@ -1147,6 +1599,7 @@ isar_l2l1(struct PStack *st, int pr, void *arg) l1_msg_b(st, PH_ACTIVATE | REQUEST, arg); break; case L1_MODE_V32: + case L1_MODE_FAX: if (modeisar(st->l1.bcs, st->l1.mode, st->l1.bc)) l1_msg_b(st, PH_DEACTIVATE | REQUEST, arg); break; @@ -1185,6 +1638,7 @@ close_isarstate(struct BCState *bcs) debugl1(bcs->cs, "closeisar clear BC_FLG_BUSY"); } } + del_timer(&bcs->hw.isar.ftimer); } int @@ -1206,6 +1660,9 @@ open_isarstate(struct IsdnCardState *cs, struct BCState *bcs) bcs->event = 0; bcs->hw.isar.rcvidx = 0; bcs->tx_cnt = 0; + bcs->hw.isar.ftimer.function = (void *) ftimer_handler; + bcs->hw.isar.ftimer.data = (long) bcs; + init_timer(&bcs->hw.isar.ftimer); return (0); } @@ -1226,15 +1683,66 @@ setstack_isar(struct PStack *st, struct BCState *bcs) int isar_auxcmd(struct IsdnCardState *cs, isdn_ctrl *ic) { u_long adr; - int features; + int features, i; + struct BCState *bcs; if (cs->debug & L1_DEB_HSCX) debugl1(cs, "isar_auxcmd cmd/ch %x/%d", ic->command, ic->arg); switch (ic->command) { + case (ISDN_CMD_FAXCMD): + bcs = cs->channel[ic->arg].bcs; + if (cs->debug & L1_DEB_HSCX) + debugl1(cs, "isar_auxcmd cmd/subcmd %d/%d", + ic->parm.aux.cmd, ic->parm.aux.subcmd); + switch(ic->parm.aux.cmd) { + case ISDN_FAX_CLASS1_CTRL: + if (ic->parm.aux.subcmd == ETX) + test_and_set_bit(BC_FLG_DLEETX, + &bcs->Flag); + break; + case ISDN_FAX_CLASS1_FRM: + case ISDN_FAX_CLASS1_FRH: + case ISDN_FAX_CLASS1_FTM: + case ISDN_FAX_CLASS1_FTH: + if (ic->parm.aux.subcmd == AT_QUERY) { + sprintf(ic->parm.aux.para, + "%d", bcs->hw.isar.mod); + ic->command = ISDN_STAT_FAXIND; + ic->parm.aux.cmd = ISDN_FAX_CLASS1_QUERY; + cs->iif.statcallb(ic); + return(0); + } else if (ic->parm.aux.subcmd == AT_EQ_QUERY) { + strcpy(ic->parm.aux.para, faxmodulation_s); + ic->command = ISDN_STAT_FAXIND; + ic->parm.aux.cmd = ISDN_FAX_CLASS1_QUERY; + cs->iif.statcallb(ic); + return(0); + } else if (ic->parm.aux.subcmd == AT_EQ_VALUE) { + for(i=0;i<FAXMODCNT;i++) + if (faxmodulation[i]==ic->parm.aux.para[0]) + break; + if ((FAXMODCNT > i) && + test_bit(BC_FLG_INIT, &bcs->Flag)) { + isar_pump_cmd(bcs, + ic->parm.aux.cmd, + ic->parm.aux.para[0]); + return(0); + } + } + /* wrong modulation or not activ */ + /* fall through */ + default: + ic->command = ISDN_STAT_FAXIND; + ic->parm.aux.cmd = ISDN_FAX_CLASS1_ERROR; + cs->iif.statcallb(ic); + } + break; case (ISDN_CMD_IOCTL): switch (ic->arg) { case (9): /* load firmware */ - features = ISDN_FEATURE_L2_MODEM; + features = ISDN_FEATURE_L2_MODEM | + ISDN_FEATURE_L2_FAX | + ISDN_FEATURE_L3_FCLASS1; memcpy(&adr, ic->parm.num, sizeof(ulong)); if (isar_load_firmware(cs, (u_char *)adr)) return(1); |