summaryrefslogtreecommitdiffstats
path: root/drivers/isdn/hisax/isar.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/isdn/hisax/isar.c')
-rw-r--r--drivers/isdn/hisax/isar.c700
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);