diff options
Diffstat (limited to 'drivers/isdn/eicon/eicon_idi.c')
-rw-r--r-- | drivers/isdn/eicon/eicon_idi.c | 224 |
1 files changed, 158 insertions, 66 deletions
diff --git a/drivers/isdn/eicon/eicon_idi.c b/drivers/isdn/eicon/eicon_idi.c index d8634bdbe..e53469070 100644 --- a/drivers/isdn/eicon/eicon_idi.c +++ b/drivers/isdn/eicon/eicon_idi.c @@ -1,10 +1,10 @@ -/* $Id: eicon_idi.c,v 1.24 1999/10/26 21:15:33 armin Exp $ +/* $Id: eicon_idi.c,v 1.29 2000/01/23 21:21:23 armin Exp $ * - * ISDN lowlevel-module for Eicon.Diehl active cards. + * ISDN lowlevel-module for Eicon active cards. * IDI interface * - * Copyright 1998,99 by Armin Schindler (mac@melware.de) - * Copyright 1999 Cytronics & Melware (info@melware.de) + * Copyright 1998-2000 by Armin Schindler (mac@melware.de) + * Copyright 1999,2000 Cytronics & Melware (info@melware.de) * * Thanks to Deutsche Mailbox Saar-Lor-Lux GmbH * for sponsoring and testing fax @@ -26,6 +26,25 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: eicon_idi.c,v $ + * Revision 1.29 2000/01/23 21:21:23 armin + * Added new trace capability and some updates. + * DIVA Server BRI now supports data for ISDNLOG. + * + * Revision 1.28 2000/01/20 19:55:34 keil + * Add FAX Class 1 support + * + * Revision 1.27 1999/11/29 13:12:03 armin + * Autoconnect on L2_TRANS doesn't work with link_level correctly, + * changed back to former mode. + * + * Revision 1.26 1999/11/25 11:43:27 armin + * Fixed statectrl and connect message. + * X.75 fix and HDLC/transparent with autoconnect. + * Minor cleanup. + * + * Revision 1.25 1999/11/18 20:30:55 armin + * removed old workaround for ISA cards. + * * Revision 1.24 1999/10/26 21:15:33 armin * using define for checking phone number len to avoid buffer overflow. * @@ -130,7 +149,7 @@ #undef EICON_FULL_SERVICE_OKTETT -char *eicon_idi_revision = "$Revision: 1.24 $"; +char *eicon_idi_revision = "$Revision: 1.29 $"; eicon_manifbuf *manbuf; @@ -187,16 +206,13 @@ idi_assign_req(eicon_REQ *reqbuf, int signet, eicon_chan *chan) reqbuf->XBuffer.P[l++] = LLC; reqbuf->XBuffer.P[l++] = 2; switch(chan->l2prot) { - case ISDN_PROTO_L2_HDLC: - reqbuf->XBuffer.P[l++] = 2; + case ISDN_PROTO_L2_TRANS: + reqbuf->XBuffer.P[l++] = 2; /* transparent */ break; case ISDN_PROTO_L2_X75I: case ISDN_PROTO_L2_X75UI: case ISDN_PROTO_L2_X75BUI: - reqbuf->XBuffer.P[l++] = 5; - break; - case ISDN_PROTO_L2_TRANS: - reqbuf->XBuffer.P[l++] = 2; + reqbuf->XBuffer.P[l++] = 5; /* X.75 */ break; case ISDN_PROTO_L2_MODEM: if (chan->fsm_state == EICON_STATE_IWAIT) @@ -204,17 +220,18 @@ idi_assign_req(eicon_REQ *reqbuf, int signet, eicon_chan *chan) else reqbuf->XBuffer.P[l++] = 10; /* V.42 */ break; + case ISDN_PROTO_L2_HDLC: case ISDN_PROTO_L2_FAX: if (chan->fsm_state == EICON_STATE_IWAIT) reqbuf->XBuffer.P[l++] = 3; /* autoconnect on incoming */ else - reqbuf->XBuffer.P[l++] = 2; + reqbuf->XBuffer.P[l++] = 2; /* transparent */ break; default: reqbuf->XBuffer.P[l++] = 1; } switch(chan->l3prot) { - case ISDN_PROTO_L3_FAX: + case ISDN_PROTO_L3_FCLASS2: #ifdef CONFIG_ISDN_TTY_FAX reqbuf->XBuffer.P[l++] = 6; reqbuf->XBuffer.P[l++] = NLC; @@ -404,8 +421,10 @@ eicon_idi_listen_req(eicon_card *card, eicon_chan *chan) idi_do_req(card, chan, ASSIGN, 0); } if (chan->fsm_state == EICON_STATE_NULL) { - idi_do_req(card, chan, INDICATE_REQ, 0); - chan->fsm_state = EICON_STATE_LISTEN; + if (!(chan->statectrl & HAVE_CONN_REQ)) { + idi_do_req(card, chan, INDICATE_REQ, 0); + chan->fsm_state = EICON_STATE_LISTEN; + } } return(0); } @@ -462,6 +481,7 @@ idi_hangup(eicon_card *card, eicon_chan *chan) } if (chan->e.B2Id) idi_do_req(card, chan, REMOVE, 1); if (chan->fsm_state != EICON_STATE_NULL) { + chan->statectrl |= WAITING_FOR_HANGUP; idi_do_req(card, chan, HANGUP, 0); chan->fsm_state = EICON_STATE_NULL; } @@ -479,7 +499,6 @@ idi_connect_res(eicon_card *card, eicon_chan *chan) return 1; chan->fsm_state = EICON_STATE_IWAIT; - idi_do_req(card, chan, CALL_RES, 0); /* check if old NetID has been removed */ if (chan->e.B2Id) { @@ -489,6 +508,7 @@ idi_connect_res(eicon_card *card, eicon_chan *chan) } idi_do_req(card, chan, ASSIGN, 1); + idi_do_req(card, chan, CALL_RES, 0); return(0); } @@ -656,9 +676,18 @@ idi_connect_req(eicon_card *card, eicon_chan *chan, char *phone, reqbuf->XBuffer.length = l; reqbuf->Reference = 0; /* Sig Entity */ - skb_queue_tail(&chan->e.X, skb); - skb_queue_tail(&card->sndq, skb2); - eicon_schedule_tx(card); + if (chan->statectrl & WAITING_FOR_HANGUP) { + /* If the line did not disconnect yet, + we have to delay this command */ + eicon_log(card, 32, "idi_req: Ch%d: delaying conn_req\n", chan->No); + chan->statectrl |= HAVE_CONN_REQ; + chan->tskb1 = skb; + chan->tskb2 = skb2; + } else { + skb_queue_tail(&chan->e.X, skb); + skb_queue_tail(&card->sndq, skb2); + eicon_schedule_tx(card); + } eicon_log(card, 8, "idi_req: Ch%d: Conn_Req %s -> %s\n",chan->No, eazmsn, phone); return(0); @@ -1433,6 +1462,7 @@ idi_edata_action(eicon_card *ccard, eicon_chan *chan, char *buffer, int len) cmd.driver = ccard->myid; cmd.command = ISDN_STAT_BCONN; cmd.arg = chan->No; + strcpy(cmd.parm.num, ""); ccard->interface.statcallb(&cmd); cmd.driver = ccard->myid; @@ -1489,6 +1519,8 @@ idi_edata_action(eicon_card *ccard, eicon_chan *chan, char *buffer, int len) break; case 2: /* session end */ default: + /* send_edata produces error on some */ + /* fax-machines here, so we don't */ /* idi_send_edata(ccard, chan); */ break; } @@ -1505,6 +1537,7 @@ idi_edata_action(eicon_card *ccard, eicon_chan *chan, char *buffer, int len) cmd.driver = ccard->myid; cmd.command = ISDN_STAT_BCONN; cmd.arg = chan->No; + strcpy(cmd.parm.num, ""); ccard->interface.statcallb(&cmd); cmd.driver = ccard->myid; @@ -2277,6 +2310,51 @@ idi_parse_udata(eicon_card *ccard, eicon_chan *chan, unsigned char *buffer, int } void +eicon_parse_trace(eicon_card *ccard, unsigned char *buffer, int len) +{ + int i,j,n; + int buflen = len * 3 + 30; + char *p; + struct trace_s { + unsigned long time; + unsigned short size; + unsigned short code; + unsigned char data[1]; + } *q; + + if (!(p = kmalloc(buflen, GFP_KERNEL))) { + eicon_log(ccard, 1, "idi_err: Ch??: could not allocate trace buffer\n"); + return; + } + memset(p, 0, buflen); + q = (struct trace_s *)buffer; + + if (DebugVar & 512) { + if ((q->code == 3) || (q->code == 4)) { + n = (short) *(q->data); + if (n) { + j = sprintf(p, "DTRC:"); + for (i = 0; i < n; i++) { + j += sprintf(p + j, "%02x ", q->data[i+2]); + } + j += sprintf(p + j, "\n"); + } + } + } else { + j = sprintf(p, "XLOG: %lx %04x %04x ", + q->time, q->size, q->code); + + for (i = 0; i < q->size; i++) { + j += sprintf(p + j, "%02x ", q->data[i]); + } + j += sprintf(p + j, "\n"); + } + if (strlen(p)) + eicon_putstatus(ccard, p); + kfree(p); +} + +void idi_handle_ind(eicon_card *ccard, struct sk_buff *skb) { int tmp; @@ -2307,7 +2385,7 @@ idi_handle_ind(eicon_card *ccard, struct sk_buff *skb) else dlev = 128; - eicon_log(ccard, dlev, "idi_hdl: Ch%d: Ind=%d Id=%x Ch=%d MInd=%d MLen=%d Len=%d\n", chan->No, + eicon_log(ccard, dlev, "idi_hdl: Ch%d: Ind=%x Id=%x Ch=%x MInd=%x MLen=%x Len=%x\n", chan->No, ind->Ind,ind->IndId,ind->IndCh,ind->MInd,ind->MLength,ind->RBuffer.length); free_buff = 1; @@ -2347,12 +2425,25 @@ idi_handle_ind(eicon_card *ccard, struct sk_buff *skb) } else { if (chan->e.B2Id) idi_do_req(ccard, chan, REMOVE, 1); - chan->fsm_state = EICON_STATE_NULL; - cmd.driver = ccard->myid; - cmd.arg = chan->No; - cmd.command = ISDN_STAT_DHUP; - ccard->interface.statcallb(&cmd); - eicon_idi_listen_req(ccard, chan); + chan->statectrl &= ~WAITING_FOR_HANGUP; + if (chan->statectrl & HAVE_CONN_REQ) { + eicon_log(ccard, 32, "idi_req: Ch%d: queueing delayed conn_req\n", chan->No); + chan->statectrl &= ~HAVE_CONN_REQ; + if ((chan->tskb1) && (chan->tskb2)) { + skb_queue_tail(&chan->e.X, chan->tskb1); + skb_queue_tail(&ccard->sndq, chan->tskb2); + eicon_schedule_tx(ccard); + } + chan->tskb1 = NULL; + chan->tskb2 = NULL; + } else { + chan->fsm_state = EICON_STATE_NULL; + cmd.driver = ccard->myid; + cmd.arg = chan->No; + cmd.command = ISDN_STAT_DHUP; + ccard->interface.statcallb(&cmd); + eicon_idi_listen_req(ccard, chan); + } } break; case INDICATE_IND: @@ -2450,8 +2541,12 @@ idi_handle_ind(eicon_card *ccard, struct sk_buff *skb) case ISDN_PROTO_L2_MODEM: /* do nothing, wait for connect */ break; - default: + case ISDN_PROTO_L2_TRANS: idi_do_req(ccard, chan, IDI_N_CONNECT, 1); + break; + default: + /* On most incoming calls we use automatic connect */ + /* idi_do_req(ccard, chan, IDI_N_CONNECT, 1); */ } } else idi_hangup(ccard, chan); @@ -2495,8 +2590,12 @@ idi_handle_ind(eicon_card *ccard, struct sk_buff *skb) if (chan->No == ccard->nchannels) { /* Management Indication */ - idi_IndParse(ccard, chan, &message, ind->RBuffer.P, ind->RBuffer.length); - chan->fsm_state = 1; + if (ind->Ind == 0x04) { /* Trace_Ind */ + eicon_parse_trace(ccard, ind->RBuffer.P, ind->RBuffer.length); + } else { + idi_IndParse(ccard, chan, &message, ind->RBuffer.P, ind->RBuffer.length); + chan->fsm_state = 1; + } } else switch(ind->Ind) { @@ -2530,6 +2629,7 @@ idi_handle_ind(eicon_card *ccard, struct sk_buff *skb) cmd.driver = ccard->myid; cmd.command = ISDN_STAT_BCONN; cmd.arg = chan->No; + strcpy(cmd.parm.num, "64000"); ccard->interface.statcallb(&cmd); break; case IDI_N_CONNECT: @@ -2546,6 +2646,7 @@ idi_handle_ind(eicon_card *ccard, struct sk_buff *skb) cmd.driver = ccard->myid; cmd.command = ISDN_STAT_BCONN; cmd.arg = chan->No; + strcpy(cmd.parm.num, "64000"); ccard->interface.statcallb(&cmd); break; case IDI_N_DISC: @@ -2576,6 +2677,7 @@ idi_handle_ind(eicon_card *ccard, struct sk_buff *skb) cmd.arg = chan->No; ccard->interface.statcallb(&cmd); chan->fsm_state = EICON_STATE_NULL; + chan->statectrl |= WAITING_FOR_HANGUP; } #ifdef CONFIG_ISDN_TTY_FAX chan->fax = 0; @@ -2631,7 +2733,8 @@ idi_handle_ack_ok(eicon_card *ccard, eicon_chan *chan, eicon_RC *ack) isdn_ctrl cmd; if (ack->RcId != ((chan->e.ReqCh) ? chan->e.B2Id : chan->e.D3Id)) { - /* I dont know why this happens, just ignoring this RC */ + /* I dont know why this happens, should not ! */ + /* just ignoring this RC */ eicon_log(ccard, 16, "idi_ack: Ch%d: RcId %d not equal to last %d\n", chan->No, ack->RcId, (chan->e.ReqCh) ? chan->e.B2Id : chan->e.D3Id); return 1; @@ -2640,16 +2743,16 @@ idi_handle_ack_ok(eicon_card *ccard, eicon_chan *chan, eicon_RC *ack) /* Management Interface */ if (chan->No == ccard->nchannels) { /* Managementinterface: changing state */ - if (chan->e.Req == 0x04) + if (chan->e.Req != 0x02) chan->fsm_state = 1; } /* Remove an Id */ if (chan->e.Req == REMOVE) { if (ack->Reference != chan->e.ref) { + /* This should not happen anymore */ eicon_log(ccard, 16, "idi_ack: Ch%d: Rc-Ref %d not equal to stored %d\n", chan->No, ack->Reference, chan->e.ref); - return 0; } save_flags(flags); cli(); @@ -2807,11 +2910,14 @@ idi_handle_ack(eicon_card *ccard, struct sk_buff *skb) dCh, ack->Rc, ack->RcId, ack->RcCh); break; default: - eicon_log(ccard, 1, "eicon_err: Ch%d: Ack Not OK !!: Rc=%d Id=%x Ch=%d Req=%d\n", - dCh, ack->Rc, ack->RcId, ack->RcCh, chan->e.Req); + if (dCh != ccard->nchannels) + eicon_log(ccard, 1, "eicon_err: Ch%d: Ack Not OK !!: Rc=%d Id=%x Ch=%d Req=%d\n", + dCh, ack->Rc, ack->RcId, ack->RcCh, chan->e.Req); } if (dCh == ccard->nchannels) { /* Management */ chan->fsm_state = 2; + eicon_log(ccard, 8, "eicon_err: Ch%d: Ack Not OK !!: Rc=%d Id=%x Ch=%d Req=%d\n", + dCh, ack->Rc, ack->RcId, ack->RcCh, chan->e.Req); } else if (dCh >= 0) { /* any other channel */ /* card reports error: we hangup */ @@ -3011,38 +3117,36 @@ eicon_idi_manage(eicon_card *card, eicon_manifbuf *mb) chan = &(card->bch[card->nchannels]); - if (chan->e.D3Id) - return -EBUSY; - chan->e.D3Id = 1; - while((skb2 = skb_dequeue(&chan->e.X))) - dev_kfree_skb(skb2); - chan->e.busy = 0; + if (!(chan->e.D3Id)) { + chan->e.D3Id = 1; + while((skb2 = skb_dequeue(&chan->e.X))) + dev_kfree_skb(skb2); + chan->e.busy = 0; - if ((ret = eicon_idi_manage_assign(card))) { - chan->e.D3Id = 0; - return(ret); - } + if ((ret = eicon_idi_manage_assign(card))) { + chan->e.D3Id = 0; + return(ret); + } - timeout = jiffies + 50; - while (timeout > jiffies) { - if (chan->e.B2Id) break; - SLEEP(10); - } - if (!chan->e.B2Id) { - chan->e.D3Id = 0; - return -EIO; + timeout = jiffies + 50; + while (timeout > jiffies) { + if (chan->e.B2Id) break; + SLEEP(10); + } + if (!chan->e.B2Id) { + chan->e.D3Id = 0; + return -EIO; + } } chan->fsm_state = 0; if (!(manbuf = kmalloc(sizeof(eicon_manifbuf), GFP_KERNEL))) { eicon_log(card, 1, "idi_err: alloc_manifbuf failed\n"); - chan->e.D3Id = 0; return -ENOMEM; } if (copy_from_user(manbuf, mb, sizeof(eicon_manifbuf))) { kfree(manbuf); - chan->e.D3Id = 0; return -EFAULT; } @@ -3056,7 +3160,6 @@ eicon_idi_manage(eicon_card *card, eicon_manifbuf *mb) if (skb2) dev_kfree_skb(skb2); kfree(manbuf); - chan->e.D3Id = 0; return -ENOMEM; } @@ -3093,25 +3196,14 @@ eicon_idi_manage(eicon_card *card, eicon_manifbuf *mb) SLEEP(10); } if ((!chan->fsm_state) || (chan->fsm_state == 2)) { - eicon_idi_manage_remove(card); kfree(manbuf); - chan->e.D3Id = 0; return -EIO; } - - if ((ret = eicon_idi_manage_remove(card))) { - kfree(manbuf); - chan->e.D3Id = 0; - return(ret); - } - if (copy_to_user(mb, manbuf, sizeof(eicon_manifbuf))) { kfree(manbuf); - chan->e.D3Id = 0; return -EFAULT; } kfree(manbuf); - chan->e.D3Id = 0; return(0); } |