patch-2.2.14 linux/drivers/isdn/eicon/eicon_idi.c
Next file: linux/drivers/isdn/eicon/eicon_idi.h
Previous file: linux/drivers/isdn/eicon/eicon.h
Back to the patch index
Back to the overall index
- Lines: 2545
- Date:
Tue Jan 4 10:12:15 2000
- Orig file:
v2.2.13/linux/drivers/isdn/eicon/eicon_idi.c
- Orig date:
Tue Jan 4 11:10:34 2000
diff -u --recursive --new-file v2.2.13/linux/drivers/isdn/eicon/eicon_idi.c linux/drivers/isdn/eicon/eicon_idi.c
@@ -1,4 +1,4 @@
-/* $Id: eicon_idi.c,v 1.18 1999/09/07 12:48:05 armin Exp $
+/* $Id: eicon_idi.c,v 1.27 1999/11/29 13:12:03 armin Exp $
*
* ISDN lowlevel-module for Eicon.Diehl active cards.
* IDI interface
@@ -6,6 +6,11 @@
* Copyright 1998,99 by Armin Schindler (mac@melware.de)
* Copyright 1999 Cytronics & Melware (info@melware.de)
*
+ * Thanks to Deutsche Mailbox Saar-Lor-Lux GmbH
+ * for sponsoring and testing fax
+ * capabilities with Diva Server cards.
+ * (dor@deutschemailbox.de)
+ *
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
@@ -21,6 +26,38 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: eicon_idi.c,v $
+ * 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.
+ *
+ * Revision 1.23 1999/10/11 18:13:25 armin
+ * Added fax capabilities for Eicon Diva Server cards.
+ *
+ * Revision 1.22 1999/10/08 22:09:33 armin
+ * Some fixes of cards interface handling.
+ * Bugfix of NULL pointer occurence.
+ * Changed a few log outputs.
+ *
+ * Revision 1.21 1999/09/26 14:17:53 armin
+ * Improved debug and log via readstat()
+ *
+ * Revision 1.20 1999/09/21 20:35:43 armin
+ * added more error checking.
+ *
+ * Revision 1.19 1999/09/21 20:06:40 armin
+ * Added pointer checks.
+ *
* Revision 1.18 1999/09/07 12:48:05 armin
* Prepared for sub-address usage.
*
@@ -105,7 +142,7 @@
#undef EICON_FULL_SERVICE_OKTETT
-char *eicon_idi_revision = "$Revision: 1.18 $";
+char *eicon_idi_revision = "$Revision: 1.27 $";
eicon_manifbuf *manbuf;
@@ -162,16 +199,13 @@
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)
@@ -179,11 +213,12 @@
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;
@@ -289,8 +324,7 @@
reqbuf->XBuffer.P[8] = 0;
reqbuf->XBuffer.length = l;
reqbuf->Reference = 0; /* Sig Entity */
- if (DebugVar & 8)
- printk(KERN_DEBUG"idi_req: Ch%d: Call_Res\n", chan->No);
+ eicon_log(NULL, 8, "idi_req: Ch%d: Call_Res\n", chan->No);
return(0);
}
@@ -306,8 +340,7 @@
skb2 = alloc_skb(sizeof(eicon_chan_ptr), GFP_ATOMIC);
if ((!skb) || (!skb2)) {
- if (DebugVar & 1)
- printk(KERN_WARNING "idi_err: Ch%d: alloc_skb failed in do_req()\n", chan->No);
+ eicon_log(card, 1, "idi_err: Ch%d: alloc_skb failed in do_req()\n", chan->No);
if (skb)
dev_kfree_skb(skb);
if (skb2)
@@ -319,8 +352,7 @@
chan2->ptr = chan;
reqbuf = (eicon_REQ *)skb_put(skb, 270 + sizeof(eicon_REQ));
- if (DebugVar & 8)
- printk(KERN_DEBUG "idi_req: Ch%d: req %x (%s)\n", chan->No, cmd, (layer)?"Net":"Sig");
+ eicon_log(card, 8, "idi_req: Ch%d: req %x (%s)\n", chan->No, cmd, (layer)?"Net":"Sig");
if (layer) cmd |= 0x700;
switch(cmd) {
case ASSIGN:
@@ -359,8 +391,7 @@
idi_put_req(reqbuf, IDI_N_DISC_ACK, 1);
break;
default:
- if (DebugVar & 1)
- printk(KERN_ERR "idi_req: Ch%d: Unknown request\n", chan->No);
+ eicon_log(card, 1, "idi_req: Ch%d: Unknown request\n", chan->No);
dev_kfree_skb(skb);
dev_kfree_skb(skb2);
return(-1);
@@ -375,14 +406,18 @@
int
eicon_idi_listen_req(eicon_card *card, eicon_chan *chan)
{
- if (DebugVar & 16)
- printk(KERN_DEBUG"idi_req: Ch%d: Listen_Req eazmask=0x%x\n",chan->No, chan->eazmask);
+ if ((!card) || (!chan))
+ return 1;
+
+ eicon_log(card, 16, "idi_req: Ch%d: Listen_Req eazmask=0x%x\n",chan->No, chan->eazmask);
if (!chan->e.D3Id) {
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);
}
@@ -430,15 +465,20 @@
int
idi_hangup(eicon_card *card, eicon_chan *chan)
{
+ if ((!card) || (!chan))
+ return 1;
+
if ((chan->fsm_state == EICON_STATE_ACTIVE) ||
(chan->fsm_state == EICON_STATE_WMCONN)) {
if (chan->e.B2Id) idi_do_req(card, chan, IDI_N_DISC, 1);
}
if (chan->e.B2Id) idi_do_req(card, chan, REMOVE, 1);
- idi_do_req(card, chan, HANGUP, 0);
- chan->fsm_state = EICON_STATE_NULL;
- if (DebugVar & 8)
- printk(KERN_DEBUG"idi_req: Ch%d: Hangup\n", chan->No);
+ 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;
+ }
+ eicon_log(card, 8, "idi_req: Ch%d: Hangup\n", chan->No);
#ifdef CONFIG_ISDN_TTY_FAX
chan->fax = 0;
#endif
@@ -448,18 +488,20 @@
int
idi_connect_res(eicon_card *card, eicon_chan *chan)
{
+ if ((!card) || (!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) {
- if (DebugVar & 1)
- printk(KERN_WARNING "idi_err: Ch%d: Old NetID %x was not removed.\n",
- chan->No, chan->e.B2Id);
+ eicon_log(card, 1, "eicon: Ch%d: old net_id %x still exist, removing.\n",
+ chan->No, chan->e.B2Id);
idi_do_req(card, chan, REMOVE, 1);
}
idi_do_req(card, chan, ASSIGN, 1);
+ idi_do_req(card, chan, CALL_RES, 0);
return(0);
}
@@ -478,12 +520,14 @@
eicon_REQ *reqbuf;
eicon_chan_ptr *chan2;
+ if ((!card) || (!chan))
+ return 1;
+
skb = alloc_skb(270 + sizeof(eicon_REQ), GFP_ATOMIC);
skb2 = alloc_skb(sizeof(eicon_chan_ptr), GFP_ATOMIC);
if ((!skb) || (!skb2)) {
- if (DebugVar & 1)
- printk(KERN_WARNING "idi_err: Ch%d: alloc_skb failed in connect_req()\n", chan->No);
+ eicon_log(card, 1, "idi_err: Ch%d: alloc_skb failed in connect_req()\n", chan->No);
if (skb)
dev_kfree_skb(skb);
if (skb2)
@@ -625,12 +669,20 @@
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);
+ }
- if (DebugVar & 8)
- printk(KERN_DEBUG"idi_req: Ch%d: Conn_Req %s -> %s\n",chan->No, eazmsn, phone);
+ eicon_log(card, 8, "idi_req: Ch%d: Conn_Req %s -> %s\n",chan->No, eazmsn, phone);
return(0);
}
@@ -647,9 +699,10 @@
__u16 code;
isdn_ctrl cmd;
- memset(message, 0, sizeof(idi_ind_message));
+ memset(message, 0, sizeof(idi_ind_message));
+
+ if ((!len) || (!buffer[pos])) return;
- if ((!len) || (!buffer[pos])) return;
while(pos <= len) {
w = buffer[pos++];
if (!w) return;
@@ -679,8 +732,18 @@
else code = w;
code |= (codeset<<8);
+ if (pos + wlen > len) {
+ eicon_log(ccard, 1, "idi_err: Ch%d: IElen %d of %x exceeds Ind_Length (+%d)\n", chan->No,
+ wlen, code, (pos + wlen) - len);
+ return;
+ }
+
switch(code) {
case OAD:
+ if (wlen > sizeof(message->oad)) {
+ pos += wlen;
+ break;
+ }
j = 1;
if (wlen) {
message->plan = buffer[pos++];
@@ -693,11 +756,14 @@
}
for(i=0; i < wlen-j; i++)
message->oad[i] = buffer[pos++];
- if (DebugVar & 2)
- printk(KERN_DEBUG"idi_inf: Ch%d: OAD=(0x%02x,0x%02x) %s\n", chan->No,
- message->plan, message->screen, message->oad);
+ eicon_log(ccard, 2, "idi_inf: Ch%d: OAD=(0x%02x,0x%02x) %s\n", chan->No,
+ message->plan, message->screen, message->oad);
break;
case RDN:
+ if (wlen > sizeof(message->rdn)) {
+ pos += wlen;
+ break;
+ }
j = 1;
if (wlen) {
if (!(buffer[pos++] & 0x80)) {
@@ -707,92 +773,116 @@
}
for(i=0; i < wlen-j; i++)
message->rdn[i] = buffer[pos++];
- if (DebugVar & 2)
- printk(KERN_DEBUG"idi_inf: Ch%d: RDN= %s\n", chan->No,
+ eicon_log(ccard, 2, "idi_inf: Ch%d: RDN= %s\n", chan->No,
message->rdn);
break;
case CPN:
+ if (wlen > sizeof(message->cpn)) {
+ pos += wlen;
+ break;
+ }
for(i=0; i < wlen; i++)
message->cpn[i] = buffer[pos++];
- if (DebugVar & 2)
- printk(KERN_DEBUG"idi_inf: Ch%d: CPN=(0x%02x) %s\n", chan->No,
- (__u8)message->cpn[0], message->cpn + 1);
+ eicon_log(ccard, 2, "idi_inf: Ch%d: CPN=(0x%02x) %s\n", chan->No,
+ (__u8)message->cpn[0], message->cpn + 1);
break;
case DSA:
+ if (wlen > sizeof(message->dsa)) {
+ pos += wlen;
+ break;
+ }
pos += 2;
for(i=0; i < wlen-2; i++)
message->dsa[i] = buffer[pos++];
- if (DebugVar & 2)
- printk(KERN_DEBUG"idi_inf: Ch%d: DSA=%s\n", chan->No, message->dsa);
+ eicon_log(ccard, 2, "idi_inf: Ch%d: DSA=%s\n", chan->No, message->dsa);
break;
case OSA:
+ if (wlen > sizeof(message->osa)) {
+ pos += wlen;
+ break;
+ }
pos += 2;
for(i=0; i < wlen-2; i++)
message->osa[i] = buffer[pos++];
- if (DebugVar & 2)
- printk(KERN_DEBUG"idi_inf: Ch%d: OSA=%s\n", chan->No, message->osa);
+ eicon_log(ccard, 2, "idi_inf: Ch%d: OSA=%s\n", chan->No, message->osa);
break;
case BC:
+ if (wlen > sizeof(message->bc)) {
+ pos += wlen;
+ break;
+ }
for(i=0; i < wlen; i++)
message->bc[i] = buffer[pos++];
- if (DebugVar & 4)
- printk(KERN_DEBUG"idi_inf: Ch%d: BC = 0x%02x 0x%02x 0x%02x\n", chan->No,
- message->bc[0],message->bc[1],message->bc[2]);
+ eicon_log(ccard, 4, "idi_inf: Ch%d: BC = 0x%02x 0x%02x 0x%02x\n", chan->No,
+ message->bc[0],message->bc[1],message->bc[2]);
break;
case 0x800|BC:
+ if (wlen > sizeof(message->e_bc)) {
+ pos += wlen;
+ break;
+ }
for(i=0; i < wlen; i++)
message->e_bc[i] = buffer[pos++];
- if (DebugVar & 4)
- printk(KERN_DEBUG"idi_inf: Ch%d: ESC/BC=%d\n", chan->No, message->bc[0]);
+ eicon_log(ccard, 4, "idi_inf: Ch%d: ESC/BC=%d\n", chan->No, message->bc[0]);
break;
case LLC:
+ if (wlen > sizeof(message->llc)) {
+ pos += wlen;
+ break;
+ }
for(i=0; i < wlen; i++)
message->llc[i] = buffer[pos++];
- if (DebugVar & 4)
- printk(KERN_DEBUG"idi_inf: Ch%d: LLC=%d %d %d %d\n", chan->No, message->llc[0],
- message->llc[1],message->llc[2],message->llc[3]);
+ eicon_log(ccard, 4, "idi_inf: Ch%d: LLC=%d %d %d %d\n", chan->No, message->llc[0],
+ message->llc[1],message->llc[2],message->llc[3]);
break;
case HLC:
+ if (wlen > sizeof(message->hlc)) {
+ pos += wlen;
+ break;
+ }
for(i=0; i < wlen; i++)
message->hlc[i] = buffer[pos++];
- if (DebugVar & 4)
- printk(KERN_DEBUG"idi_inf: Ch%d: HLC=%x %x %x %x %x\n", chan->No,
- message->hlc[0], message->hlc[1],
- message->hlc[2], message->hlc[3], message->hlc[4]);
+ eicon_log(ccard, 4, "idi_inf: Ch%d: HLC=%x %x %x %x %x\n", chan->No,
+ message->hlc[0], message->hlc[1],
+ message->hlc[2], message->hlc[3], message->hlc[4]);
break;
case DSP:
case 0x600|DSP:
+ if (wlen > sizeof(message->display)) {
+ pos += wlen;
+ break;
+ }
for(i=0; i < wlen; i++)
message->display[i] = buffer[pos++];
- if (DebugVar & 4)
- printk(KERN_DEBUG"idi_inf: Ch%d: Display: %s\n", chan->No,
- message->display);
+ eicon_log(ccard, 4, "idi_inf: Ch%d: Display: %s\n", chan->No,
+ message->display);
break;
case 0x600|KEY:
+ if (wlen > sizeof(message->keypad)) {
+ pos += wlen;
+ break;
+ }
for(i=0; i < wlen; i++)
message->keypad[i] = buffer[pos++];
- if (DebugVar & 4)
- printk(KERN_DEBUG"idi_inf: Ch%d: Keypad: %s\n", chan->No,
- message->keypad);
+ eicon_log(ccard, 4, "idi_inf: Ch%d: Keypad: %s\n", chan->No,
+ message->keypad);
break;
case NI:
case 0x600|NI:
if (wlen) {
- if (DebugVar & 4) {
- switch(buffer[pos] & 127) {
- case 0:
- printk(KERN_DEBUG"idi_inf: Ch%d: User suspended.\n", chan->No);
- break;
- case 1:
- printk(KERN_DEBUG"idi_inf: Ch%d: User resumed.\n", chan->No);
- break;
- case 2:
- printk(KERN_DEBUG"idi_inf: Ch%d: Bearer service change.\n", chan->No);
- break;
- default:
- printk(KERN_DEBUG"idi_inf: Ch%d: Unknown Notification %x.\n",
- chan->No, buffer[pos] & 127);
- }
+ switch(buffer[pos] & 127) {
+ case 0:
+ eicon_log(ccard, 4, "idi_inf: Ch%d: User suspended.\n", chan->No);
+ break;
+ case 1:
+ eicon_log(ccard, 4, "idi_inf: Ch%d: User resumed.\n", chan->No);
+ break;
+ case 2:
+ eicon_log(ccard, 4, "idi_inf: Ch%d: Bearer service change.\n", chan->No);
+ break;
+ default:
+ eicon_log(ccard, 4, "idi_inf: Ch%d: Unknown Notification %x.\n",
+ chan->No, buffer[pos] & 127);
}
pos += wlen;
}
@@ -800,80 +890,91 @@
case PI:
case 0x600|PI:
if (wlen > 1) {
- if (DebugVar & 4) {
- switch(buffer[pos+1] & 127) {
- case 1:
- printk(KERN_DEBUG"idi_inf: Ch%d: Call is not end-to-end ISDN.\n", chan->No);
- break;
- case 2:
- printk(KERN_DEBUG"idi_inf: Ch%d: Destination address is non ISDN.\n", chan->No);
- break;
- case 3:
- printk(KERN_DEBUG"idi_inf: Ch%d: Origination address is non ISDN.\n", chan->No);
- break;
- case 4:
- printk(KERN_DEBUG"idi_inf: Ch%d: Call has returned to the ISDN.\n", chan->No);
- break;
- case 5:
- printk(KERN_DEBUG"idi_inf: Ch%d: Interworking has occurred.\n", chan->No);
- break;
- case 8:
- printk(KERN_DEBUG"idi_inf: Ch%d: In-band information available.\n", chan->No);
- break;
- default:
- printk(KERN_DEBUG"idi_inf: Ch%d: Unknown Progress %x.\n",
- chan->No, buffer[pos+1] & 127);
- }
+ switch(buffer[pos+1] & 127) {
+ case 1:
+ eicon_log(ccard, 4, "idi_inf: Ch%d: Call is not end-to-end ISDN.\n", chan->No);
+ break;
+ case 2:
+ eicon_log(ccard, 4, "idi_inf: Ch%d: Destination address is non ISDN.\n", chan->No);
+ break;
+ case 3:
+ eicon_log(ccard, 4, "idi_inf: Ch%d: Origination address is non ISDN.\n", chan->No);
+ break;
+ case 4:
+ eicon_log(ccard, 4, "idi_inf: Ch%d: Call has returned to the ISDN.\n", chan->No);
+ break;
+ case 5:
+ eicon_log(ccard, 4, "idi_inf: Ch%d: Interworking has occurred.\n", chan->No);
+ break;
+ case 8:
+ eicon_log(ccard, 4, "idi_inf: Ch%d: In-band information available.\n", chan->No);
+ break;
+ default:
+ eicon_log(ccard, 4, "idi_inf: Ch%d: Unknown Progress %x.\n",
+ chan->No, buffer[pos+1] & 127);
}
}
pos += wlen;
break;
case CAU:
+ if (wlen > sizeof(message->cau)) {
+ pos += wlen;
+ break;
+ }
for(i=0; i < wlen; i++)
message->cau[i] = buffer[pos++];
memcpy(&chan->cause, &message->cau, 2);
- if (DebugVar & 4)
- printk(KERN_DEBUG"idi_inf: Ch%d: CAU=%d %d\n", chan->No,
- message->cau[0],message->cau[1]);
+ eicon_log(ccard, 4, "idi_inf: Ch%d: CAU=%d %d\n", chan->No,
+ message->cau[0],message->cau[1]);
break;
case 0x800|CAU:
+ if (wlen > sizeof(message->e_cau)) {
+ pos += wlen;
+ break;
+ }
for(i=0; i < wlen; i++)
message->e_cau[i] = buffer[pos++];
- if (DebugVar & 4)
- printk(KERN_DEBUG"idi_inf: Ch%d: ECAU=%d %d\n", chan->No,
- message->e_cau[0],message->e_cau[1]);
+ eicon_log(ccard, 4, "idi_inf: Ch%d: ECAU=%d %d\n", chan->No,
+ message->e_cau[0],message->e_cau[1]);
break;
case 0x800|CHI:
+ if (wlen > sizeof(message->e_chi)) {
+ pos += wlen;
+ break;
+ }
for(i=0; i < wlen; i++)
message->e_chi[i] = buffer[pos++];
- if (DebugVar & 4)
- printk(KERN_DEBUG"idi_inf: Ch%d: ESC/CHI=%d\n", chan->No,
- message->e_cau[0]);
+ eicon_log(ccard, 4, "idi_inf: Ch%d: ESC/CHI=%d\n", chan->No,
+ message->e_cau[0]);
break;
case 0x800|0x7a:
pos ++;
message->e_mt=buffer[pos++];
- if (DebugVar & 2)
- printk(KERN_DEBUG"idi_inf: Ch%d: EMT=0x%x\n", chan->No, message->e_mt);
+ eicon_log(ccard, 4, "idi_inf: Ch%d: EMT=0x%x\n", chan->No, message->e_mt);
break;
case DT:
+ if (wlen > sizeof(message->dt)) {
+ pos += wlen;
+ break;
+ }
for(i=0; i < wlen; i++)
message->dt[i] = buffer[pos++];
- if (DebugVar & 4)
- printk(KERN_DEBUG"idi_inf: Ch%d: DT: %02d.%02d.%02d %02d:%02d:%02d\n", chan->No,
- message->dt[2], message->dt[1], message->dt[0],
- message->dt[3], message->dt[4], message->dt[5]);
+ eicon_log(ccard, 4, "idi_inf: Ch%d: DT: %02d.%02d.%02d %02d:%02d:%02d\n", chan->No,
+ message->dt[2], message->dt[1], message->dt[0],
+ message->dt[3], message->dt[4], message->dt[5]);
break;
case 0x600|SIN:
+ if (wlen > sizeof(message->sin)) {
+ pos += wlen;
+ break;
+ }
for(i=0; i < wlen; i++)
message->sin[i] = buffer[pos++];
- if (DebugVar & 2)
- printk(KERN_DEBUG"idi_inf: Ch%d: SIN=%d %d\n", chan->No,
- message->sin[0],message->sin[1]);
+ eicon_log(ccard, 2, "idi_inf: Ch%d: SIN=%d %d\n", chan->No,
+ message->sin[0],message->sin[1]);
break;
case 0x600|CPS:
- if (DebugVar & 2)
- printk(KERN_DEBUG"idi_inf: Ch%d: Called Party Status in ind\n", chan->No);
+ eicon_log(ccard, 2, "idi_inf: Ch%d: Called Party Status in ind\n", chan->No);
pos += wlen;
break;
case 0x600|CIF:
@@ -881,8 +982,7 @@
if (buffer[pos + i] != '0') break;
memcpy(&cmd.parm.num, &buffer[pos + i], wlen - i);
cmd.parm.num[wlen - i] = 0;
- if (DebugVar & 2)
- printk(KERN_DEBUG"idi_inf: Ch%d: CIF=%s\n", chan->No, cmd.parm.num);
+ eicon_log(ccard, 2, "idi_inf: Ch%d: CIF=%s\n", chan->No, cmd.parm.num);
pos += wlen;
cmd.driver = ccard->myid;
cmd.command = ISDN_STAT_CINF;
@@ -890,8 +990,11 @@
ccard->interface.statcallb(&cmd);
break;
case 0x600|DATE:
- if (DebugVar & 2)
- printk(KERN_DEBUG"idi_inf: Ch%d: Date in ind\n", chan->No);
+ eicon_log(ccard, 2, "idi_inf: Ch%d: Date in ind\n", chan->No);
+ pos += wlen;
+ break;
+ case 0xa1:
+ eicon_log(ccard, 2, "idi_inf: Ch%d: Sending Complete in ind.\n", chan->No);
pos += wlen;
break;
case 0xe08:
@@ -911,8 +1014,7 @@
case 0x880:
/* Managment Information Element */
if (!manbuf) {
- if (DebugVar & 1)
- printk(KERN_WARNING"idi_err: manbuf not allocated\n");
+ eicon_log(ccard, 1, "idi_err: manbuf not allocated\n");
}
else {
memcpy(&manbuf->data[manbuf->pos], &buffer[pos], wlen);
@@ -924,9 +1026,8 @@
break;
default:
pos += wlen;
- if (DebugVar & 6)
- printk(KERN_WARNING"idi_inf: Ch%d: unknown information element 0x%x in ind, len:%x\n",
- chan->No, code, wlen);
+ eicon_log(ccard, 6, "idi_inf: Ch%d: unknown information element 0x%x in ind, len:%x\n",
+ chan->No, code, wlen);
}
}
}
@@ -967,110 +1068,1099 @@
int
idi_fill_in_T30(eicon_chan *chan, unsigned char *buffer)
{
+ eicon_t30_s *t30 = (eicon_t30_s *) buffer;
- /* TODO , code follows */
+ if (!chan->fax) {
+ eicon_log(NULL, 1,"idi_T30: fill_in with NULL fax struct, ERROR\n");
+ return 0;
+ }
+ memset(t30, 0, sizeof(eicon_t30_s));
+ t30->station_id_len = EICON_FAXID_LEN;
+ memcpy(&t30->station_id[0], &chan->fax->id[0], EICON_FAXID_LEN);
+ t30->resolution = chan->fax->resolution;
+ t30->rate = chan->fax->rate + 1; /* eicon rate starts with 1 */
+ t30->format = T30_FORMAT_SFF;
+ t30->pages_low = 0;
+ t30->pages_high = 0;
+ t30->atf = 1; /* optimised for AT+F command set */
+ t30->code = 0;
+ t30->feature_bits_low = 0;
+ t30->feature_bits_high = 0;
+ t30->control_bits_low = 0;
+ t30->control_bits_high = 0;
+
+ if (chan->fax->nbc) {
+ /* set compression by DCC value */
+ switch(chan->fax->compression) {
+ case (0): /* 1-D modified */
+ break;
+ case (1): /* 2-D modified Read */
+ t30->control_bits_low |= T30_CONTROL_BIT_ENABLE_2D_CODING;
+ t30->feature_bits_low |= T30_FEATURE_BIT_2D_CODING;
+ break;
+ case (2): /* 2-D uncompressed */
+ t30->control_bits_low |= T30_CONTROL_BIT_ENABLE_UNCOMPR;
+ t30->control_bits_low |= T30_CONTROL_BIT_ENABLE_2D_CODING;
+ t30->feature_bits_low |= T30_FEATURE_BIT_UNCOMPR_ENABLED;
+ t30->feature_bits_low |= T30_FEATURE_BIT_2D_CODING;
+ break;
+ case (3): /* 2-D modified Read */
+ t30->control_bits_low |= T30_CONTROL_BIT_ENABLE_T6_CODING;
+ t30->control_bits_low |= T30_CONTROL_BIT_ENABLE_2D_CODING;
+ t30->control_bits_low |= T30_CONTROL_BIT_ENABLE_UNCOMPR;
+ t30->feature_bits_low |= T30_FEATURE_BIT_UNCOMPR_ENABLED;
+ t30->feature_bits_low |= T30_FEATURE_BIT_T6_CODING;
+ t30->feature_bits_low |= T30_FEATURE_BIT_2D_CODING;
+ t30->control_bits_low |= T30_CONTROL_BIT_ENABLE_ECM;
+ t30->feature_bits_low |= T30_FEATURE_BIT_ECM;
+ break;
+ }
+ } else {
+ /* set compression to best */
+ t30->control_bits_low |= T30_CONTROL_BIT_ENABLE_T6_CODING;
+ t30->control_bits_low |= T30_CONTROL_BIT_ENABLE_2D_CODING;
+ t30->control_bits_low |= T30_CONTROL_BIT_ENABLE_UNCOMPR;
+ t30->feature_bits_low |= T30_FEATURE_BIT_UNCOMPR_ENABLED;
+ t30->feature_bits_low |= T30_FEATURE_BIT_T6_CODING;
+ t30->feature_bits_low |= T30_FEATURE_BIT_2D_CODING;
+ t30->control_bits_low |= T30_CONTROL_BIT_ENABLE_ECM;
+ t30->feature_bits_low |= T30_FEATURE_BIT_ECM;
+ }
+ switch(chan->fax->ecm) {
+ case (0): /* disable ECM */
+ break;
+ case (1):
+ t30->control_bits_low |= T30_CONTROL_BIT_ENABLE_ECM;
+ t30->control_bits_low |= T30_CONTROL_BIT_ECM_64_BYTES;
+ t30->feature_bits_low |= T30_FEATURE_BIT_ECM;
+ t30->feature_bits_low |= T30_FEATURE_BIT_ECM_64_BYTES;
+ break;
+ case (2):
+ t30->control_bits_low |= T30_CONTROL_BIT_ENABLE_ECM;
+ t30->feature_bits_low |= T30_FEATURE_BIT_ECM;
+ break;
+ }
- return(0);
+ if (DebugVar & 128) {
+ char st[40];
+ eicon_log(NULL, 128, "sT30:code = %x\n", t30->code);
+ eicon_log(NULL, 128, "sT30:rate = %x\n", t30->rate);
+ eicon_log(NULL, 128, "sT30:res = %x\n", t30->resolution);
+ eicon_log(NULL, 128, "sT30:format = %x\n", t30->format);
+ eicon_log(NULL, 128, "sT30:pages_low = %x\n", t30->pages_low);
+ eicon_log(NULL, 128, "sT30:pages_high = %x\n", t30->pages_high);
+ eicon_log(NULL, 128, "sT30:atf = %x\n", t30->atf);
+ eicon_log(NULL, 128, "sT30:control_bits_low = %x\n", t30->control_bits_low);
+ eicon_log(NULL, 128, "sT30:control_bits_high = %x\n", t30->control_bits_high);
+ eicon_log(NULL, 128, "sT30:feature_bits_low = %x\n", t30->feature_bits_low);
+ eicon_log(NULL, 128, "sT30:feature_bits_high = %x\n", t30->feature_bits_high);
+ //eicon_log(NULL, 128, "sT30:universal_5 = %x\n", t30->universal_5);
+ //eicon_log(NULL, 128, "sT30:universal_6 = %x\n", t30->universal_6);
+ //eicon_log(NULL, 128, "sT30:universal_7 = %x\n", t30->universal_7);
+ eicon_log(NULL, 128, "sT30:station_id_len = %x\n", t30->station_id_len);
+ eicon_log(NULL, 128, "sT30:head_line_len = %x\n", t30->head_line_len);
+ strncpy(st, t30->station_id, t30->station_id_len);
+ st[t30->station_id_len] = 0;
+ eicon_log(NULL, 128, "sT30:station_id = <%s>\n", st);
+ }
+ return(sizeof(eicon_t30_s));
}
/* send fax struct */
int
idi_send_edata(eicon_card *card, eicon_chan *chan)
{
+ struct sk_buff *skb;
+ struct sk_buff *skb2;
+ eicon_REQ *reqbuf;
+ eicon_chan_ptr *chan2;
+
+ if ((chan->fsm_state == EICON_STATE_NULL) || (chan->fsm_state == EICON_STATE_LISTEN)) {
+ eicon_log(card, 1, "idi_snd: Ch%d: send edata on state %d !\n", chan->No, chan->fsm_state);
+ return -ENODEV;
+ }
+ eicon_log(card, 128, "idi_snd: Ch%d: edata (fax)\n", chan->No);
+
+ skb = alloc_skb(sizeof(eicon_REQ) + sizeof(eicon_t30_s), GFP_ATOMIC);
+ skb2 = alloc_skb(sizeof(eicon_chan_ptr), GFP_ATOMIC);
+
+ if ((!skb) || (!skb2)) {
+ eicon_log(card, 1, "idi_err: Ch%d: alloc_skb failed in send_edata()\n", chan->No);
+ if (skb)
+ dev_kfree_skb(skb);
+ if (skb2)
+ dev_kfree_skb(skb2);
+ return -ENOMEM;
+ }
+
+ chan2 = (eicon_chan_ptr *)skb_put(skb2, sizeof(eicon_chan_ptr));
+ chan2->ptr = chan;
+
+ reqbuf = (eicon_REQ *)skb_put(skb, sizeof(eicon_t30_s) + sizeof(eicon_REQ));
- /* TODO , code follows */
+ reqbuf->Req = IDI_N_EDATA;
+ reqbuf->ReqCh = 0;
+ reqbuf->ReqId = 1;
+
+ reqbuf->XBuffer.length = idi_fill_in_T30(chan, reqbuf->XBuffer.P);
+ reqbuf->Reference = 1; /* Net Entity */
+ skb_queue_tail(&chan->e.X, skb);
+ skb_queue_tail(&card->sndq, skb2);
+ eicon_schedule_tx(card);
return (0);
}
void
idi_parse_edata(eicon_card *ccard, eicon_chan *chan, unsigned char *buffer, int len)
{
+ eicon_t30_s *p = (eicon_t30_s *)buffer;
+ int i;
- /* TODO , code follows */
+ if (DebugVar & 128) {
+ char st[40];
+ eicon_log(ccard, 128, "rT30:len %d , size %d\n", len, sizeof(eicon_t30_s));
+ eicon_log(ccard, 128, "rT30:code = %x\n", p->code);
+ eicon_log(ccard, 128, "rT30:rate = %x\n", p->rate);
+ eicon_log(ccard, 128, "rT30:res = %x\n", p->resolution);
+ eicon_log(ccard, 128, "rT30:format = %x\n", p->format);
+ eicon_log(ccard, 128, "rT30:pages_low = %x\n", p->pages_low);
+ eicon_log(ccard, 128, "rT30:pages_high = %x\n", p->pages_high);
+ eicon_log(ccard, 128, "rT30:atf = %x\n", p->atf);
+ eicon_log(ccard, 128, "rT30:control_bits_low = %x\n", p->control_bits_low);
+ eicon_log(ccard, 128, "rT30:control_bits_high = %x\n", p->control_bits_high);
+ eicon_log(ccard, 128, "rT30:feature_bits_low = %x\n", p->feature_bits_low);
+ eicon_log(ccard, 128, "rT30:feature_bits_high = %x\n", p->feature_bits_high);
+ //eicon_log(ccard, 128, "rT30:universal_5 = %x\n", p->universal_5);
+ //eicon_log(ccard, 128, "rT30:universal_6 = %x\n", p->universal_6);
+ //eicon_log(ccard, 128, "rT30:universal_7 = %x\n", p->universal_7);
+ eicon_log(ccard, 128, "rT30:station_id_len = %x\n", p->station_id_len);
+ eicon_log(ccard, 128, "rT30:head_line_len = %x\n", p->head_line_len);
+ strncpy(st, p->station_id, p->station_id_len);
+ st[p->station_id_len] = 0;
+ eicon_log(ccard, 128, "rT30:station_id = <%s>\n", st);
+ }
+ if (!chan->fax) {
+ eicon_log(ccard, 1, "idi_edata: parse to NULL fax struct, ERROR\n");
+ return;
+ }
+ chan->fax->code = p->code;
+ i = (p->station_id_len < FAXIDLEN) ? p->station_id_len : (FAXIDLEN - 1);
+ memcpy(chan->fax->r_id, p->station_id, i);
+ chan->fax->r_id[i] = 0;
+ chan->fax->r_resolution = p->resolution;
+ chan->fax->r_rate = p->rate - 1;
+ chan->fax->r_binary = 0; /* no binary support */
+ chan->fax->r_width = 0;
+ chan->fax->r_length = 2;
+ chan->fax->r_scantime = 0;
+ chan->fax->r_compression = 0;
+ chan->fax->r_ecm = 0;
+ if (p->feature_bits_low & T30_FEATURE_BIT_2D_CODING) {
+ chan->fax->r_compression = 1;
+ if (p->feature_bits_low & T30_FEATURE_BIT_UNCOMPR_ENABLED) {
+ chan->fax->r_compression = 2;
+ }
+ }
+ if (p->feature_bits_low & T30_FEATURE_BIT_T6_CODING) {
+ chan->fax->r_compression = 3;
+ }
+ if (p->feature_bits_low & T30_FEATURE_BIT_ECM) {
+ chan->fax->r_ecm = 2;
+ if (p->feature_bits_low & T30_FEATURE_BIT_ECM_64_BYTES)
+ chan->fax->r_ecm = 1;
+ }
}
void
idi_fax_send_header(eicon_card *card, eicon_chan *chan, int header)
{
+ static __u16 wd2sff[] = {
+ 1728, 2048, 2432, 1216, 864
+ };
+ static __u16 ln2sff[2][3] = {
+ { 1143, 1401, 0 } , { 2287, 2802, 0 }
+ };
+ struct sk_buff *skb;
+ eicon_sff_dochead *doc;
+ eicon_sff_pagehead *page;
+ u_char *docp;
+
+ if (!chan->fax) {
+ eicon_log(card, 1, "idi_fax: send head with NULL fax struct, ERROR\n");
+ return;
+ }
+ if (header == 2) { /* DocHeader + PageHeader */
+ skb = alloc_skb(sizeof(eicon_sff_dochead) + sizeof(eicon_sff_pagehead), GFP_ATOMIC);
+ } else {
+ skb = alloc_skb(sizeof(eicon_sff_pagehead), GFP_ATOMIC);
+ }
+ if (!skb) {
+ eicon_log(card, 1, "idi_err: Ch%d: alloc_skb failed in fax_send_header()\n", chan->No);
+ return;
+ }
- /* TODO , code follows */
+ if (header == 2) { /* DocHeader + PageHeader */
+ docp = skb_put(skb, sizeof(eicon_sff_dochead) + sizeof(eicon_sff_pagehead));
+ doc = (eicon_sff_dochead *) docp;
+ page = (eicon_sff_pagehead *) (docp + sizeof(eicon_sff_dochead));
+ memset(docp, 0,sizeof(eicon_sff_dochead) + sizeof(eicon_sff_pagehead));
+ doc->id = 0x66666653;
+ doc->version = 0x01;
+ doc->off1pagehead = sizeof(eicon_sff_dochead);
+ } else {
+ page = (eicon_sff_pagehead *)skb_put(skb, sizeof(eicon_sff_pagehead));
+ memset(page, 0, sizeof(eicon_sff_pagehead));
+ }
+ switch(header) {
+ case 1: /* PageHeaderEnd */
+ page->pageheadid = 254;
+ page->pageheadlen = 0;
+ break;
+ case 0: /* PageHeader */
+ case 2: /* DocHeader + PageHeader */
+ page->pageheadid = 254;
+ page->pageheadlen = sizeof(eicon_sff_pagehead) - 2;
+ page->resvert = chan->fax->resolution;
+ page->reshoriz = 0; /* always 203 dpi */
+ page->coding = 0; /* always 1D */
+ page->linelength = wd2sff[chan->fax->width];
+ page->pagelength = ln2sff[chan->fax->resolution][chan->fax->length];
+ eicon_log(card, 128, "sSFF-Head: linelength = %d\n", page->linelength);
+ eicon_log(card, 128, "sSFF-Head: pagelength = %d\n", page->pagelength);
+ break;
+ }
+ idi_send_data(card, chan, 0, skb, 0);
}
void
idi_fax_cmd(eicon_card *card, eicon_chan *chan)
{
+ isdn_ctrl cmd;
+
+ if ((!card) || (!chan))
+ return;
+
+ if (!chan->fax) {
+ eicon_log(card, 1, "idi_fax: cmd with NULL fax struct, ERROR\n");
+ return;
+ }
+ switch (chan->fax->code) {
+ case ISDN_TTY_FAX_DT:
+ if (chan->fax->phase == ISDN_FAX_PHASE_B) {
+ idi_send_edata(card, chan);
+ break;
+ }
+ if (chan->fax->phase == ISDN_FAX_PHASE_D) {
+ idi_send_edata(card, chan);
+ break;
+ }
+ break;
+
+ case ISDN_TTY_FAX_DR:
+ if (chan->fax->phase == ISDN_FAX_PHASE_B) {
+ idi_send_edata(card, chan);
+
+ cmd.driver = card->myid;
+ cmd.command = ISDN_STAT_FAXIND;
+ cmd.arg = chan->No;
+ chan->fax->r_code = ISDN_TTY_FAX_CFR;
+ card->interface.statcallb(&cmd);
+
+ cmd.driver = card->myid;
+ cmd.command = ISDN_STAT_FAXIND;
+ cmd.arg = chan->No;
+ chan->fax->r_code = ISDN_TTY_FAX_RID;
+ card->interface.statcallb(&cmd);
- /* TODO , code follows */
+ /* telling 1-D compression */
+ chan->fax->r_compression = 0;
+ cmd.driver = card->myid;
+ cmd.command = ISDN_STAT_FAXIND;
+ cmd.arg = chan->No;
+ chan->fax->r_code = ISDN_TTY_FAX_DCS;
+ card->interface.statcallb(&cmd);
+
+ chan->fax2.NextObject = FAX_OBJECT_DOCU;
+ chan->fax2.PrevObject = FAX_OBJECT_DOCU;
+
+ break;
+ }
+ if (chan->fax->phase == ISDN_FAX_PHASE_D) {
+ idi_send_edata(card, chan);
+ break;
+ }
+ break;
+ case ISDN_TTY_FAX_ET:
+ switch(chan->fax->fet) {
+ case 0:
+ case 1:
+ idi_fax_send_header(card, chan, 0);
+ break;
+ case 2:
+ idi_fax_send_header(card, chan, 1);
+ break;
+ }
+ break;
+ }
}
void
idi_edata_rcveop(eicon_card *card, eicon_chan *chan)
{
+ isdn_ctrl cmd;
- /* TODO , code follows */
-
+ if (!chan->fax) {
+ eicon_log(card, 1, "idi_edata: rcveop with NULL fax struct, ERROR\n");
+ return;
+ }
+ cmd.driver = card->myid;
+ cmd.command = ISDN_STAT_FAXIND;
+ cmd.arg = chan->No;
+ chan->fax->r_code = ISDN_TTY_FAX_ET;
+ card->interface.statcallb(&cmd);
}
void
idi_reset_fax_stat(eicon_chan *chan)
{
-
- /* TODO , code follows */
-
+ chan->fax2.LineLen = 0;
+ chan->fax2.LineData = 0;
+ chan->fax2.LineDataLen = 0;
+ chan->fax2.NullByteExist = 0;
+ chan->fax2.Dle = 0;
+ chan->fax2.PageCount = 0;
+ chan->fax2.Eop = 0;
}
void
idi_edata_action(eicon_card *ccard, eicon_chan *chan, char *buffer, int len)
{
+ isdn_ctrl cmd;
+
+ if (!chan->fax) {
+ eicon_log(ccard, 1, "idi_edata: action with NULL fax struct, ERROR\n");
+ return;
+ }
+ if (chan->fax->direction == ISDN_TTY_FAX_CONN_OUT) {
+ idi_parse_edata(ccard, chan, buffer, len);
+
+ if (chan->fax->phase == ISDN_FAX_PHASE_A) {
+ idi_reset_fax_stat(chan);
+
+ chan->fsm_state = EICON_STATE_ACTIVE;
+ 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;
+ cmd.command = ISDN_STAT_FAXIND;
+ cmd.arg = chan->No;
+ chan->fax->r_code = ISDN_TTY_FAX_FCON;
+ ccard->interface.statcallb(&cmd);
- /* TODO , code follows */
+ cmd.driver = ccard->myid;
+ cmd.command = ISDN_STAT_FAXIND;
+ cmd.arg = chan->No;
+ chan->fax->r_code = ISDN_TTY_FAX_RID;
+ ccard->interface.statcallb(&cmd);
+
+ cmd.driver = ccard->myid;
+ cmd.command = ISDN_STAT_FAXIND;
+ cmd.arg = chan->No;
+ chan->fax->r_code = ISDN_TTY_FAX_DIS;
+ ccard->interface.statcallb(&cmd);
+ if (chan->fax->r_compression != 0) {
+ /* telling fake compression in second DIS message */
+ chan->fax->r_compression = 0;
+ cmd.driver = ccard->myid;
+ cmd.command = ISDN_STAT_FAXIND;
+ cmd.arg = chan->No;
+ chan->fax->r_code = ISDN_TTY_FAX_DIS;
+ ccard->interface.statcallb(&cmd);
+ }
+
+ cmd.driver = ccard->myid;
+ cmd.command = ISDN_STAT_FAXIND;
+ cmd.arg = chan->No;
+ chan->fax->r_code = ISDN_TTY_FAX_SENT; /* OK message */
+ ccard->interface.statcallb(&cmd);
+ } else
+ if (chan->fax->phase == ISDN_FAX_PHASE_D) {
+
+ if ((chan->fax->code == EDATA_T30_MCF) &&
+ (chan->fax->fet != 2)) {
+ cmd.driver = ccard->myid;
+ cmd.command = ISDN_STAT_FAXIND;
+ cmd.arg = chan->No;
+ chan->fax->r_code = ISDN_TTY_FAX_PTS;
+ ccard->interface.statcallb(&cmd);
+ }
+
+ switch(chan->fax->fet) {
+ case 0: /* new page */
+ /* stay in phase D , wait on cmd +FDT */
+ break;
+ case 1: /* new document */
+ /* link-level switch to phase B */
+ 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;
+ }
+ }
+ }
+
+ if (chan->fax->direction == ISDN_TTY_FAX_CONN_IN) {
+ idi_parse_edata(ccard, chan, buffer, len);
+
+ if ((chan->fax->code == EDATA_T30_DCS) &&
+ (chan->fax->phase == ISDN_FAX_PHASE_A)) {
+ idi_reset_fax_stat(chan);
+
+ 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;
+ cmd.command = ISDN_STAT_FAXIND;
+ cmd.arg = chan->No;
+ chan->fax->r_code = ISDN_TTY_FAX_FCON_I;
+ ccard->interface.statcallb(&cmd);
+ } else
+ if ((chan->fax->code == EDATA_T30_TRAIN_OK) &&
+ (chan->fax->phase == ISDN_FAX_PHASE_A)) {
+ cmd.driver = ccard->myid;
+ cmd.command = ISDN_STAT_FAXIND;
+ cmd.arg = chan->No;
+ chan->fax->r_code = ISDN_TTY_FAX_RID;
+ ccard->interface.statcallb(&cmd);
+
+ cmd.driver = ccard->myid;
+ cmd.command = ISDN_STAT_FAXIND;
+ cmd.arg = chan->No;
+ chan->fax->r_code = ISDN_TTY_FAX_TRAIN_OK;
+ ccard->interface.statcallb(&cmd);
+ } else
+ if ((chan->fax->code == EDATA_T30_TRAIN_OK) &&
+ (chan->fax->phase == ISDN_FAX_PHASE_B)) {
+ cmd.driver = ccard->myid;
+ cmd.command = ISDN_STAT_FAXIND;
+ cmd.arg = chan->No;
+ chan->fax->r_code = ISDN_TTY_FAX_TRAIN_OK;
+ ccard->interface.statcallb(&cmd);
+ } else
+ if (chan->fax->phase == ISDN_FAX_PHASE_C) {
+ switch(chan->fax->code) {
+ case EDATA_T30_TRAIN_OK:
+ idi_send_edata(ccard, chan);
+ break;
+ case EDATA_T30_MPS:
+ chan->fax->fet = 0;
+ idi_edata_rcveop(ccard, chan);
+ break;
+ case EDATA_T30_EOM:
+ chan->fax->fet = 1;
+ idi_edata_rcveop(ccard, chan);
+ break;
+ case EDATA_T30_EOP:
+ chan->fax->fet = 2;
+ idi_edata_rcveop(ccard, chan);
+ break;
+ }
+ }
+ }
}
void
fax_put_rcv(eicon_card *ccard, eicon_chan *chan, u_char *Data, int len)
{
-
- /* TODO , code follows */
-
+ struct sk_buff *skb;
+
+ skb = alloc_skb(len + MAX_HEADER_LEN, GFP_ATOMIC);
+ if (!skb) {
+ eicon_log(ccard, 1, "idi_err: Ch%d: alloc_skb failed in fax_put_rcv()\n", chan->No);
+ return;
+ }
+ skb_reserve(skb, MAX_HEADER_LEN);
+ memcpy(skb_put(skb, len), Data, len);
+ ccard->interface.rcvcallb_skb(ccard->myid, chan->No, skb);
}
void
idi_faxdata_rcv(eicon_card *ccard, eicon_chan *chan, struct sk_buff *skb)
{
+ eicon_OBJBUFFER InBuf;
+ eicon_OBJBUFFER LineBuf;
+ unsigned int Length = 0;
+ unsigned int aLength = 0;
+ unsigned int ObjectSize = 0;
+ unsigned int ObjHeadLen = 0;
+ unsigned int ObjDataLen = 0;
+ __u8 Recordtype;
+ __u8 PageHeaderLen;
+ __u8 Event;
+ eicon_sff_pagehead *ob_page;
+
+ __u16 Cl2Eol = 0x8000;
+
+# define EVENT_NONE 0
+# define EVENT_NEEDDATA 1
+
+ if (!chan->fax) {
+ eicon_log(ccard, 1, "idi_fax: rcvdata with NULL fax struct, ERROR\n");
+ return;
+ }
+
+
+
+ if (chan->fax->direction == ISDN_TTY_FAX_CONN_IN) {
+ InBuf.Data = skb->data;
+ InBuf.Size = skb->len;
+ InBuf.Len = 0;
+ InBuf.Next = InBuf.Data;
+ LineBuf.Data = chan->fax2.abLine;
+ LineBuf.Size = sizeof(chan->fax2.abLine);
+ LineBuf.Len = chan->fax2.LineLen;
+ LineBuf.Next = LineBuf.Data + LineBuf.Len;
+
+ Event = EVENT_NONE;
+ while (Event == EVENT_NONE) {
+ switch(chan->fax2.NextObject) {
+ case FAX_OBJECT_DOCU:
+ Length = LineBuf.Len + (InBuf.Size - InBuf.Len);
+ if (Length < sizeof(eicon_sff_dochead)) {
+ Event = EVENT_NEEDDATA;
+ break;
+ }
+ ObjectSize = sizeof(eicon_sff_dochead);
+ Length = ObjectSize;
+ if (LineBuf.Len < Length) {
+ Length -= LineBuf.Len;
+ LineBuf.Len = 0;
+ LineBuf.Next = LineBuf.Data;
+ InBuf.Len += Length;
+ InBuf.Next += Length;
+ } else {
+ LineBuf.Len -= Length;
+ LineBuf.Next = LineBuf.Data + LineBuf.Len;
+ memmove(LineBuf.Data, LineBuf.Data + Length, LineBuf.Len);
+ }
+ chan->fax2.PrevObject = FAX_OBJECT_DOCU;
+ chan->fax2.NextObject = FAX_OBJECT_PAGE;
+ break;
+
+ case FAX_OBJECT_PAGE:
+ Length = LineBuf.Len + (InBuf.Size - InBuf.Len);
+ if (Length < 2) {
+ Event = EVENT_NEEDDATA;
+ break;
+ }
+ if (LineBuf.Len == 0) {
+ *LineBuf.Next++ = *InBuf.Next++;
+ LineBuf.Len++;
+ InBuf.Len++;
+ }
+ if (LineBuf.Len == 1) {
+ *LineBuf.Next++ = *InBuf.Next++;
+ LineBuf.Len++;
+ InBuf.Len++;
+ }
+ PageHeaderLen = *(LineBuf.Data + 1);
+ ObjectSize = (PageHeaderLen == 0) ? 2 : sizeof(eicon_sff_pagehead);
+ if (Length < ObjectSize) {
+ Event = EVENT_NEEDDATA;
+ break;
+ }
+ Length = ObjectSize;
+ /* extract page dimensions */
+ if (LineBuf.Len < Length) {
+ aLength = Length - LineBuf.Len;
+ memcpy(LineBuf.Next, InBuf.Next, aLength);
+ LineBuf.Next += aLength;
+ InBuf.Next += aLength;
+ LineBuf.Len += aLength;
+ InBuf.Len += aLength;
+ }
+ if (Length > 2) {
+ ob_page = (eicon_sff_pagehead *)LineBuf.Data;
+ switch(ob_page->linelength) {
+ case 2048:
+ chan->fax->r_width = 1;
+ break;
+ case 2432:
+ chan->fax->r_width = 2;
+ break;
+ case 1216:
+ chan->fax->r_width = 3;
+ break;
+ case 864:
+ chan->fax->r_width = 4;
+ break;
+ case 1728:
+ default:
+ chan->fax->r_width = 0;
+ }
+ switch(ob_page->pagelength) {
+ case 1143:
+ case 2287:
+ chan->fax->r_length = 0;
+ break;
+ case 1401:
+ case 2802:
+ chan->fax->r_length = 1;
+ break;
+ default:
+ chan->fax->r_length = 2;
+ }
+ eicon_log(ccard, 128, "rSFF-Head: linelength = %d\n", ob_page->linelength);
+ eicon_log(ccard, 128, "rSFF-Head: pagelength = %d\n", ob_page->pagelength);
+ }
+ LineBuf.Len -= Length;
+ LineBuf.Next = LineBuf.Data + LineBuf.Len;
+ memmove(LineBuf.Data, LineBuf.Data + Length, LineBuf.Len);
+
+ chan->fax2.PrevObject = FAX_OBJECT_PAGE;
+ chan->fax2.NextObject = FAX_OBJECT_LINE;
+ break;
+
+ case FAX_OBJECT_LINE:
+ Length = LineBuf.Len + (InBuf.Size - InBuf.Len);
+ if (Length < 1) {
+ Event = EVENT_NEEDDATA;
+ break;
+ }
+ if (LineBuf.Len == 0) {
+ *LineBuf.Next++ = *InBuf.Next++;
+ LineBuf.Len++;
+ InBuf.Len++;
+ }
+ Recordtype = *LineBuf.Data;
+ if (Recordtype == 0) {
+ /* recordtype pixel row (2 byte length) */
+ ObjHeadLen = 3;
+ if (Length < ObjHeadLen) {
+ Event = EVENT_NEEDDATA;
+ break;
+ }
+ while (LineBuf.Len < ObjHeadLen) {
+ *LineBuf.Next++ = *InBuf.Next++;
+ LineBuf.Len++;
+ InBuf.Len++;
+ }
+ ObjDataLen = *((__u16*) (LineBuf.Data + 1));
+ ObjectSize = ObjHeadLen + ObjDataLen;
+ if (Length < ObjectSize) {
+ Event = EVENT_NEEDDATA;
+ break;
+ }
+ } else
+ if ((Recordtype >= 1) && (Recordtype <= 216)) {
+ /* recordtype pixel row (1 byte length) */
+ ObjHeadLen = 1;
+ ObjDataLen = Recordtype;
+ ObjectSize = ObjHeadLen + ObjDataLen;
+ if (Length < ObjectSize) {
+ Event = EVENT_NEEDDATA;
+ break;
+ }
+ } else
+ if ((Recordtype >= 217) && (Recordtype <= 253)) {
+ /* recordtype empty lines */
+ ObjHeadLen = 1;
+ ObjDataLen = 0;
+ ObjectSize = ObjHeadLen + ObjDataLen;
+ LineBuf.Len--;
+ LineBuf.Next = LineBuf.Data + LineBuf.Len;
+ memmove(LineBuf.Data, LineBuf.Data + 1, LineBuf.Len);
+ break;
+ } else
+ if (Recordtype == 254) {
+ /* recordtype page header */
+ chan->fax2.PrevObject = FAX_OBJECT_LINE;
+ chan->fax2.NextObject = FAX_OBJECT_PAGE;
+ break;
+ } else {
+ /* recordtype user information */
+ ObjHeadLen = 2;
+ if (Length < ObjHeadLen) {
+ Event = EVENT_NEEDDATA;
+ break;
+ }
+ while (LineBuf.Len < ObjHeadLen) {
+ *LineBuf.Next++ = *InBuf.Next++;
+ LineBuf.Len++;
+ InBuf.Len++;
+ }
+ ObjDataLen = *(LineBuf.Data + 1);
+ ObjectSize = ObjHeadLen + ObjDataLen;
+ if (ObjDataLen == 0) {
+ /* illegal line coding */
+ LineBuf.Len -= ObjHeadLen;
+ LineBuf.Next = LineBuf.Data + LineBuf.Len;
+ memmove(LineBuf.Data, LineBuf.Data + ObjHeadLen, LineBuf.Len);
+ break;
+ } else {
+ /* user information */
+ if (Length < ObjectSize) {
+ Event = EVENT_NEEDDATA;
+ break;
+ }
+ Length = ObjectSize;
+ if (LineBuf.Len < Length) {
+ Length -= LineBuf.Len;
+ LineBuf.Len = 0;
+ LineBuf.Next = LineBuf.Data;
+ InBuf.Len += Length;
+ InBuf.Next += Length;
+ } else {
+ LineBuf.Len -= Length;
+ LineBuf.Next = LineBuf.Data + LineBuf.Len;
+ memmove(LineBuf.Data, LineBuf.Data + Length, LineBuf.Len);
+ }
+ }
+ break;
+ }
+ Length = ObjectSize;
+ if (LineBuf.Len > ObjHeadLen) {
+ fax_put_rcv(ccard, chan, LineBuf.Data + ObjHeadLen,
+ (LineBuf.Len - ObjHeadLen));
+ }
+ Length -= LineBuf.Len;
+ LineBuf.Len = 0;
+ LineBuf.Next = LineBuf.Data;
+ if (Length > 0) {
+ fax_put_rcv(ccard, chan, InBuf.Next, Length);
+ InBuf.Len += Length;
+ InBuf.Next += Length;
+ }
+ fax_put_rcv(ccard, chan, (__u8 *)&Cl2Eol, sizeof(Cl2Eol));
+ break;
+ } /* end of switch (chan->fax2.NextObject) */
+ } /* end of while (Event==EVENT_NONE) */
+ if (InBuf.Len < InBuf.Size) {
+ Length = InBuf.Size - InBuf.Len;
+ if ((LineBuf.Len + Length) > LineBuf.Size) {
+ eicon_log(ccard, 1, "idi_fax: Ch%d: %d bytes dropping, small buffer\n", chan->No,
+ Length);
+ } else {
+ memcpy(LineBuf.Next, InBuf.Next, Length);
+ LineBuf.Len += Length;
+ }
+ }
+ chan->fax2.LineLen = LineBuf.Len;
+ } else { /* CONN_OUT */
+ /* On CONN_OUT we do not need incoming data, drop it */
+ /* maybe later for polling */
+ }
- /* TODO , code follows */
+# undef EVENT_NONE
+# undef EVENT_NEEDDATA
+ return;
}
int
idi_fax_send_outbuf(eicon_card *ccard, eicon_chan *chan, eicon_OBJBUFFER *OutBuf)
{
+ struct sk_buff *skb;
- /* TODO , code follows */
+ skb = alloc_skb(OutBuf->Len, GFP_ATOMIC);
+ if (!skb) {
+ eicon_log(ccard, 1, "idi_err: Ch%d: alloc_skb failed in fax_send_outbuf()\n", chan->No);
+ return(-1);
+ }
+ memcpy(skb_put(skb, OutBuf->Len), OutBuf->Data, OutBuf->Len);
- return(0);
+ OutBuf->Len = 0;
+ OutBuf->Next = OutBuf->Data;
+
+ return(idi_send_data(ccard, chan, 0, skb, 1));
}
int
idi_faxdata_send(eicon_card *ccard, eicon_chan *chan, struct sk_buff *skb)
{
+ isdn_ctrl cmd;
+ eicon_OBJBUFFER InBuf;
+ __u8 InData;
+ __u8 InMask;
+ eicon_OBJBUFFER OutBuf;
+ eicon_OBJBUFFER LineBuf;
+ __u32 LineData;
+ unsigned int LineDataLen;
+ __u8 Byte;
+ __u8 Event;
+ int ret = 1;
+
+# define EVENT_NONE 0
+# define EVENT_EOD 1
+# define EVENT_EOL 2
+# define EVENT_EOP 3
- /* TODO , code follows */
+ if ((!ccard) || (!chan))
+ return -1;
- return(0);
+ if (!chan->fax) {
+ eicon_log(ccard, 1, "idi_fax: senddata with NULL fax struct, ERROR\n");
+ return -1;
+ }
+
+ if (chan->fax->direction == ISDN_TTY_FAX_CONN_IN) {
+ /* Simply ignore any data written in data mode when receiving a fax. */
+ /* This is not completely correct because only XON's should come here. */
+ dev_kfree_skb(skb);
+ return 1;
+ }
+
+ if (chan->fax->phase != ISDN_FAX_PHASE_C) {
+ dev_kfree_skb(skb);
+ return 1;
+ }
+
+ if (chan->queued + skb->len > 1200)
+ return 0;
+
+ InBuf.Data = skb->data;
+ InBuf.Size = skb->len;
+ InBuf.Len = 0;
+ InBuf.Next = InBuf.Data;
+ InData = 0;
+ InMask = 0;
+
+ LineBuf.Data = chan->fax2.abLine;
+ LineBuf.Size = sizeof(chan->fax2.abLine);
+ LineBuf.Len = chan->fax2.LineLen;
+ LineBuf.Next = LineBuf.Data + LineBuf.Len;
+ LineData = chan->fax2.LineData;
+ LineDataLen = chan->fax2.LineDataLen;
+
+ OutBuf.Data = chan->fax2.abFrame;
+ OutBuf.Size = sizeof(chan->fax2.abFrame);
+ OutBuf.Len = 0;
+ OutBuf.Next = OutBuf.Data;
+
+ Event = EVENT_NONE;
+
+ chan->fax2.Eop = 0;
+
+ for (;;) {
+ for (;;) {
+ if (InMask == 0) {
+ if (InBuf.Len >= InBuf.Size) {
+ Event = EVENT_EOD;
+ break;
+ }
+ if ((chan->fax2.Dle != _DLE_) && *InBuf.Next == _DLE_) {
+ chan->fax2.Dle = _DLE_;
+ InBuf.Next++;
+ InBuf.Len++;
+ if (InBuf.Len >= InBuf.Size) {
+ Event = EVENT_EOD;
+ break;
+ }
+ }
+ if (chan->fax2.Dle == _DLE_) {
+ chan->fax2.Dle = 0;
+ if (*InBuf.Next == _ETX_) {
+ Event = EVENT_EOP;
+ break;
+ } else
+ if (*InBuf.Next == _DLE_) {
+ /* do nothing */
+ } else {
+ eicon_log(ccard, 1,
+ "idi_err: Ch%d: unknown DLE escape %02x found\n",
+ chan->No, *InBuf.Next);
+ InBuf.Next++;
+ InBuf.Len++;
+ if (InBuf.Len >= InBuf.Size) {
+ Event = EVENT_EOD;
+ break;
+ }
+ }
+ }
+ InBuf.Len++;
+ InData = *InBuf.Next++;
+ InMask = (chan->fax->bor) ? 0x80 : 0x01;
+ }
+ while (InMask) {
+ LineData >>= 1;
+ LineDataLen++;
+ if (InData & InMask)
+ LineData |= 0x80000000;
+ if (chan->fax->bor)
+ InMask >>= 1;
+ else
+ InMask <<= 1;
+
+ if ((LineDataLen >= T4_EOL_BITSIZE) &&
+ ((LineData & T4_EOL_MASK_DWORD) == T4_EOL_DWORD)) {
+ Event = EVENT_EOL;
+ if (LineDataLen > T4_EOL_BITSIZE) {
+ Byte = (__u8)
+ ((LineData & ~T4_EOL_MASK_DWORD) >>
+ (32 - LineDataLen));
+ if (Byte == 0) {
+ if (! chan->fax2.NullByteExist) {
+ chan->fax2.NullBytesPos = LineBuf.Len;
+ chan->fax2.NullByteExist = 1;
+ }
+ } else {
+ chan->fax2.NullByteExist = 0;
+ }
+ if (LineBuf.Len < LineBuf.Size) {
+ *LineBuf.Next++ = Byte;
+ LineBuf.Len++;
+ }
+ }
+ LineDataLen = 0;
+ break;
+ }
+ if (LineDataLen >= T4_EOL_BITSIZE + 8) {
+ Byte = (__u8)
+ ((LineData & ~T4_EOL_MASK_DWORD) >>
+ (32 - T4_EOL_BITSIZE - 8));
+ LineData &= T4_EOL_MASK_DWORD;
+ LineDataLen = T4_EOL_BITSIZE;
+ if (Byte == 0) {
+ if (! chan->fax2.NullByteExist) {
+ chan->fax2.NullBytesPos = LineBuf.Len;
+ chan->fax2.NullByteExist = 1;
+ }
+ } else {
+ chan->fax2.NullByteExist = 0;
+ }
+ if (LineBuf.Len < LineBuf.Size) {
+ *LineBuf.Next++ = Byte;
+ LineBuf.Len++;
+ }
+ }
+ }
+ if (Event != EVENT_NONE)
+ break;
+ }
+
+ if ((Event != EVENT_EOL) && (Event != EVENT_EOP))
+ break;
+
+ if ((Event == EVENT_EOP) && (LineDataLen > 0)) {
+ LineData >>= 32 - LineDataLen;
+ LineDataLen = 0;
+ while (LineData != 0) {
+ Byte = (__u8) LineData;
+ LineData >>= 8;
+ if (Byte == 0) {
+ if (! chan->fax2.NullByteExist) {
+ chan->fax2.NullBytesPos = LineBuf.Len;
+ chan->fax2.NullByteExist = 1;
+ }
+ } else {
+ chan->fax2.NullByteExist = 0;
+ }
+ if (LineBuf.Len < LineBuf.Size) {
+ *LineBuf.Next++ = Byte;
+ LineBuf.Len++;
+ }
+
+ }
+ }
+ if (chan->fax2.NullByteExist) {
+ if (chan->fax2.NullBytesPos == 0) {
+ LineBuf.Len = 0;
+ } else {
+ LineBuf.Len = chan->fax2.NullBytesPos + 1;
+ }
+ }
+ if (LineBuf.Len > 0) {
+ if (OutBuf.Len + LineBuf.Len + SFF_LEN_FLD_SIZE > OutBuf.Size) {
+ ret = idi_fax_send_outbuf(ccard, chan, &OutBuf);
+ }
+ if (LineBuf.Len <= 216) {
+ *OutBuf.Next++ = (__u8) LineBuf.Len;
+ OutBuf.Len++;
+ } else {
+ *OutBuf.Next++ = 0;
+ *((__u16 *) OutBuf.Next)++ = (__u16) LineBuf.Len;
+ OutBuf.Len += 3;
+ }
+ memcpy(OutBuf.Next, LineBuf.Data, LineBuf.Len);
+ OutBuf.Next += LineBuf.Len;
+ OutBuf.Len += LineBuf.Len;
+ }
+ LineBuf.Len = 0;
+ LineBuf.Next = LineBuf.Data;
+ chan->fax2.NullByteExist = 0;
+ if (Event == EVENT_EOP)
+ break;
+
+ Event = EVENT_NONE;
+ }
+
+ if (Event == EVENT_EOP) {
+ chan->fax2.Eop = 1;
+ chan->fax2.PageCount++;
+ cmd.driver = ccard->myid;
+ cmd.command = ISDN_STAT_FAXIND;
+ cmd.arg = chan->No;
+ chan->fax->r_code = ISDN_TTY_FAX_EOP;
+ ccard->interface.statcallb(&cmd);
+ }
+ if (OutBuf.Len > 0) {
+ ret = idi_fax_send_outbuf(ccard, chan, &OutBuf);
+ }
+
+ chan->fax2.LineLen = LineBuf.Len;
+ chan->fax2.LineData = LineData;
+ chan->fax2.LineDataLen = LineDataLen;
+
+# undef EVENT_NONE
+# undef EVENT_EOD
+# undef EVENT_EOL
+# undef EVENT_EOP
+
+ if (ret >= 0)
+ dev_kfree_skb(skb);
+ if (ret == 0)
+ ret = 1;
+ return(ret);
}
void
idi_fax_hangup(eicon_card *ccard, eicon_chan *chan)
{
+ isdn_ctrl cmd;
- /* TODO , code follows */
-
+ if (!chan->fax) {
+ eicon_log(ccard, 1, "idi_fax: hangup with NULL fax struct, ERROR\n");
+ return;
+ }
+ if ((chan->fax->direction == ISDN_TTY_FAX_CONN_OUT) &&
+ (chan->fax->code == 0)) {
+ cmd.driver = ccard->myid;
+ cmd.command = ISDN_STAT_FAXIND;
+ cmd.arg = chan->No;
+ chan->fax->r_code = ISDN_TTY_FAX_PTS;
+ ccard->interface.statcallb(&cmd);
+ }
+ if ((chan->fax->code > 1) && (chan->fax->code < 120))
+ chan->fax->code += 120;
+ chan->fax->r_code = ISDN_TTY_FAX_HNG;
+ cmd.driver = ccard->myid;
+ cmd.command = ISDN_STAT_FAXIND;
+ cmd.arg = chan->No;
+ ccard->interface.statcallb(&cmd);
}
#endif /******** FAX ********/
@@ -1084,20 +2174,17 @@
eicon_chan_ptr *chan2;
if ((chan->fsm_state == EICON_STATE_NULL) || (chan->fsm_state == EICON_STATE_LISTEN)) {
- if (DebugVar & 1)
- printk(KERN_DEBUG"idi_snd: Ch%d: send udata on state %d !\n", chan->No, chan->fsm_state);
+ eicon_log(card, 1, "idi_snd: Ch%d: send udata on state %d !\n", chan->No, chan->fsm_state);
return -ENODEV;
}
- if (DebugVar & 8)
- printk(KERN_DEBUG"idi_snd: Ch%d: udata 0x%x: %d %d %d %d\n", chan->No,
- UReq, buffer[0], buffer[1], buffer[2], buffer[3]);
+ eicon_log(card, 8, "idi_snd: Ch%d: udata 0x%x: %d %d %d %d\n", chan->No,
+ UReq, buffer[0], buffer[1], buffer[2], buffer[3]);
skb = alloc_skb(sizeof(eicon_REQ) + len + 1, GFP_ATOMIC);
skb2 = alloc_skb(sizeof(eicon_chan_ptr), GFP_ATOMIC);
if ((!skb) || (!skb2)) {
- if (DebugVar & 1)
- printk(KERN_WARNING "idi_err: Ch%d: alloc_skb failed in send_udata()\n", chan->No);
+ eicon_log(card, 1, "idi_err: Ch%d: alloc_skb failed in send_udata()\n", chan->No);
if (skb)
dev_kfree_skb(skb);
if (skb2)
@@ -1131,6 +2218,9 @@
u_char buf[6];
struct enable_dtmf_s *dtmf_buf = (struct enable_dtmf_s *)buf;
+ if ((!ccard) || (!chan))
+ return;
+
memset(buf, 0, 6);
switch(cmd) {
case ISDN_AUDIO_SETDD:
@@ -1162,14 +2252,15 @@
'1','4','7','*','2','5','8','0','3','6','9','#','A','B','C','D'
};
+ if ((!ccard) || (!chan))
+ return;
+
switch (buffer[0]) {
case DSP_UDATA_INDICATION_SYNC:
- if (DebugVar & 16)
- printk(KERN_DEBUG"idi_ind: Ch%d: UDATA_SYNC time %d\n", chan->No, p->time);
+ eicon_log(ccard, 16, "idi_ind: Ch%d: UDATA_SYNC time %d\n", chan->No, p->time);
break;
case DSP_UDATA_INDICATION_DCD_OFF:
- if (DebugVar & 8)
- printk(KERN_DEBUG"idi_ind: Ch%d: UDATA_DCD_OFF time %d\n", chan->No, p->time);
+ eicon_log(ccard, 8, "idi_ind: Ch%d: UDATA_DCD_OFF time %d\n", chan->No, p->time);
break;
case DSP_UDATA_INDICATION_DCD_ON:
if ((chan->l2prot == ISDN_PROTO_L2_MODEM) &&
@@ -1181,31 +2272,24 @@
sprintf(cmd.parm.num, "%d/%s", p->speed, connmsg[p->norm]);
ccard->interface.statcallb(&cmd);
}
- if (DebugVar & 8) {
- printk(KERN_DEBUG"idi_ind: Ch%d: UDATA_DCD_ON time %d\n", chan->No, p->time);
- printk(KERN_DEBUG"idi_ind: Ch%d: %d %d %d %d\n", chan->No,
- p->norm, p->options, p->speed, p->delay);
- }
+ eicon_log(ccard, 8, "idi_ind: Ch%d: UDATA_DCD_ON time %d\n", chan->No, p->time);
+ eicon_log(ccard, 8, "idi_ind: Ch%d: %d %d %d %d\n", chan->No,
+ p->norm, p->options, p->speed, p->delay);
break;
case DSP_UDATA_INDICATION_CTS_OFF:
- if (DebugVar & 8)
- printk(KERN_DEBUG"idi_ind: Ch%d: UDATA_CTS_OFF time %d\n", chan->No, p->time);
+ eicon_log(ccard, 8, "idi_ind: Ch%d: UDATA_CTS_OFF time %d\n", chan->No, p->time);
break;
case DSP_UDATA_INDICATION_CTS_ON:
- if (DebugVar & 8) {
- printk(KERN_DEBUG"idi_ind: Ch%d: UDATA_CTS_ON time %d\n", chan->No, p->time);
- printk(KERN_DEBUG"idi_ind: Ch%d: %d %d %d %d\n", chan->No,
- p->norm, p->options, p->speed, p->delay);
- }
+ eicon_log(ccard, 8, "idi_ind: Ch%d: UDATA_CTS_ON time %d\n", chan->No, p->time);
+ eicon_log(ccard, 8, "idi_ind: Ch%d: %d %d %d %d\n", chan->No,
+ p->norm, p->options, p->speed, p->delay);
break;
case DSP_UDATA_INDICATION_DISCONNECT:
- if (DebugVar & 8)
- printk(KERN_DEBUG"idi_ind: Ch%d: UDATA_DISCONNECT cause %d\n", chan->No, buffer[1]);
+ eicon_log(ccard, 8, "idi_ind: Ch%d: UDATA_DISCONNECT cause %d\n", chan->No, buffer[1]);
break;
case DSP_UDATA_INDICATION_DTMF_DIGITS_RECEIVED:
- if (DebugVar & 8)
- printk(KERN_DEBUG"idi_ind: Ch%d: UDATA_DTMF_REC '%c'\n", chan->No,
- dtmf_code[buffer[1]]);
+ eicon_log(ccard, 8, "idi_ind: Ch%d: UDATA_DTMF_REC '%c'\n", chan->No,
+ dtmf_code[buffer[1]]);
cmd.driver = ccard->myid;
cmd.command = ISDN_STAT_AUDIO;
cmd.parm.num[0] = ISDN_AUDIO_DTMF;
@@ -1214,8 +2298,7 @@
ccard->interface.statcallb(&cmd);
break;
default:
- if (DebugVar & 8)
- printk(KERN_WARNING "idi_ind: Ch%d: UNHANDLED UDATA Indication 0x%02x\n", chan->No, buffer[0]);
+ eicon_log(ccard, 8, "idi_ind: Ch%d: UNHANDLED UDATA Indication 0x%02x\n", chan->No, buffer[0]);
}
}
@@ -1223,23 +2306,35 @@
idi_handle_ind(eicon_card *ccard, struct sk_buff *skb)
{
int tmp;
+ char tnum[64];
+ int dlev;
int free_buff;
+ ulong flags;
struct sk_buff *skb2;
eicon_IND *ind = (eicon_IND *)skb->data;
eicon_chan *chan;
idi_ind_message message;
isdn_ctrl cmd;
+ if (!ccard) {
+ eicon_log(ccard, 1, "idi_err: Ch??: null card in handle_ind\n");
+ dev_kfree_skb(skb);
+ return;
+ }
+
if ((chan = ccard->IdTable[ind->IndId]) == NULL) {
+ eicon_log(ccard, 1, "idi_err: Ch??: null chan in handle_ind\n");
dev_kfree_skb(skb);
return;
}
- if ((DebugVar & 128) ||
- ((DebugVar & 16) && (ind->Ind != 8))) {
- printk(KERN_DEBUG "idi_hdl: Ch%d: Ind=%d Id=%x Ch=%d MInd=%d MLen=%d Len=%d\n", chan->No,
- ind->Ind,ind->IndId,ind->IndCh,ind->MInd,ind->MLength,ind->RBuffer.length);
- }
+ if (ind->Ind != 8)
+ dlev = 144;
+ 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,
+ ind->Ind,ind->IndId,ind->IndCh,ind->MInd,ind->MLength,ind->RBuffer.length);
free_buff = 1;
/* Signal Layer */
@@ -1247,15 +2342,16 @@
idi_IndParse(ccard, chan, &message, ind->RBuffer.P, ind->RBuffer.length);
switch(ind->Ind) {
case HANGUP:
- if (DebugVar & 8)
- printk(KERN_DEBUG"idi_ind: Ch%d: Hangup\n", chan->No);
+ eicon_log(ccard, 8, "idi_ind: Ch%d: Hangup\n", chan->No);
while((skb2 = skb_dequeue(&chan->e.X))) {
dev_kfree_skb(skb2);
}
- chan->e.busy = 0;
+ save_flags(flags);
+ cli();
chan->queued = 0;
chan->waitq = 0;
chan->waitpq = 0;
+ restore_flags(flags);
if (message.e_cau[0] & 0x7f) {
cmd.driver = ccard->myid;
cmd.arg = chan->No;
@@ -1269,66 +2365,92 @@
if (!chan->e.B2Id)
chan->fax = 0;
#endif
- if ((chan->fsm_state == EICON_STATE_ACTIVE) ||
- (chan->fsm_state == EICON_STATE_WMCONN)) {
+ if (((chan->fsm_state == EICON_STATE_ACTIVE) ||
+ (chan->fsm_state == EICON_STATE_WMCONN)) ||
+ ((chan->l2prot == ISDN_PROTO_L2_FAX) &&
+ (chan->fsm_state == EICON_STATE_OBWAIT))) {
chan->fsm_state = EICON_STATE_NULL;
} 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:
- if (DebugVar & 8)
- printk(KERN_DEBUG"idi_ind: Ch%d: Indicate_Ind\n", chan->No);
+ eicon_log(ccard, 8, "idi_ind: Ch%d: Indicate_Ind\n", chan->No);
+ if (chan->fsm_state != EICON_STATE_LISTEN) {
+ eicon_log(ccard, 1, "idi_err: Ch%d: Incoming call on wrong state (%d).\n",
+ chan->No, chan->fsm_state);
+ idi_do_req(ccard, chan, HANGUP, 0);
+ break;
+ }
chan->fsm_state = EICON_STATE_ICALL;
idi_bc2si(message.bc, message.hlc, &chan->si1, &chan->si2);
strcpy(chan->cpn, message.cpn + 1);
- if (strlen(message.dsa)) {
- strcat(chan->cpn, ".");
- strcat(chan->cpn, message.dsa);
- }
strcpy(chan->oad, message.oad);
- if (strlen(message.osa)) {
- strcat(chan->oad, ".");
- strcat(chan->oad, message.osa);
- }
+ strcpy(chan->dsa, message.dsa);
+ strcpy(chan->osa, message.osa);
+ chan->plan = message.plan;
+ chan->screen = message.screen;
try_stat_icall_again:
cmd.driver = ccard->myid;
cmd.command = ISDN_STAT_ICALL;
cmd.arg = chan->No;
cmd.parm.setup.si1 = chan->si1;
cmd.parm.setup.si2 = chan->si2;
- strcpy(cmd.parm.setup.eazmsn, chan->cpn);
- strcpy(cmd.parm.setup.phone, chan->oad);
- cmd.parm.setup.plan = message.plan;
- cmd.parm.setup.screen = message.screen;
+ strcpy(tnum, chan->cpn);
+ if (strlen(chan->dsa)) {
+ strcat(tnum, ".");
+ strcat(tnum, chan->dsa);
+ }
+ tnum[ISDN_MSNLEN - 1] = 0;
+ strcpy(cmd.parm.setup.eazmsn, tnum);
+ strcpy(tnum, chan->oad);
+ if (strlen(chan->osa)) {
+ strcat(tnum, ".");
+ strcat(tnum, chan->osa);
+ }
+ tnum[ISDN_MSNLEN - 1] = 0;
+ strcpy(cmd.parm.setup.phone, tnum);
+ cmd.parm.setup.plan = chan->plan;
+ cmd.parm.setup.screen = chan->screen;
tmp = ccard->interface.statcallb(&cmd);
switch(tmp) {
case 0: /* no user responding */
idi_do_req(ccard, chan, HANGUP, 0);
+ chan->fsm_state = EICON_STATE_NULL;
break;
case 1: /* alert */
- if (DebugVar & 8)
- printk(KERN_DEBUG"idi_req: Ch%d: Call Alert\n", chan->No);
+ eicon_log(ccard, 8, "idi_req: Ch%d: Call Alert\n", chan->No);
if ((chan->fsm_state == EICON_STATE_ICALL) || (chan->fsm_state == EICON_STATE_ICALLW)) {
chan->fsm_state = EICON_STATE_ICALL;
idi_do_req(ccard, chan, CALL_ALERT, 0);
}
break;
case 2: /* reject */
- if (DebugVar & 8)
- printk(KERN_DEBUG"idi_req: Ch%d: Call Reject\n", chan->No);
+ eicon_log(ccard, 8, "idi_req: Ch%d: Call Reject\n", chan->No);
idi_do_req(ccard, chan, REJECT, 0);
break;
case 3: /* incomplete number */
- if (DebugVar & 8)
- printk(KERN_DEBUG"idi_req: Ch%d: Incomplete Number\n", chan->No);
+ eicon_log(ccard, 8, "idi_req: Ch%d: Incomplete Number\n", chan->No);
switch(ccard->type) {
case EICON_CTYPE_MAESTRAP:
case EICON_CTYPE_S2M:
@@ -1342,8 +2464,7 @@
}
break;
case INFO_IND:
- if (DebugVar & 8)
- printk(KERN_DEBUG"idi_ind: Ch%d: Info_Ind\n", chan->No);
+ eicon_log(ccard, 8, "idi_ind: Ch%d: Info_Ind\n", chan->No);
if ((chan->fsm_state == EICON_STATE_ICALLW) &&
(message.cpn[0])) {
strcat(chan->cpn, message.cpn + 1);
@@ -1351,8 +2472,7 @@
}
break;
case CALL_IND:
- if (DebugVar & 8)
- printk(KERN_DEBUG"idi_ind: Ch%d: Call_Ind\n", chan->No);
+ eicon_log(ccard, 8, "idi_ind: Ch%d: Call_Ind\n", chan->No);
if ((chan->fsm_state == EICON_STATE_ICALL) || (chan->fsm_state == EICON_STATE_IWAIT)) {
chan->fsm_state = EICON_STATE_IBWAIT;
cmd.driver = ccard->myid;
@@ -1369,15 +2489,18 @@
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);
break;
case CALL_CON:
- if (DebugVar & 8)
- printk(KERN_DEBUG"idi_ind: Ch%d: Call_Con\n", chan->No);
+ eicon_log(ccard, 8, "idi_ind: Ch%d: Call_Con\n", chan->No);
if (chan->fsm_state == EICON_STATE_OCALL) {
chan->fsm_state = EICON_STATE_OBWAIT;
cmd.driver = ccard->myid;
@@ -1387,9 +2510,8 @@
/* check if old NetID has been removed */
if (chan->e.B2Id) {
- if (DebugVar & 1)
- printk(KERN_WARNING "idi_err: Ch%d: Old NetID %x was not removed.\n",
- chan->No, chan->e.B2Id);
+ eicon_log(ccard, 1, "eicon: Ch%d: old net_id %x still exist, removing.\n",
+ chan->No, chan->e.B2Id);
idi_do_req(ccard, chan, REMOVE, 1);
}
@@ -1405,12 +2527,10 @@
idi_hangup(ccard, chan);
break;
case AOC_IND:
- if (DebugVar & 8)
- printk(KERN_DEBUG"idi_ind: Ch%d: Advice of Charge\n", chan->No);
+ eicon_log(ccard, 8, "idi_ind: Ch%d: Advice of Charge\n", chan->No);
break;
default:
- if (DebugVar & 8)
- printk(KERN_WARNING "idi_ind: Ch%d: UNHANDLED SigIndication 0x%02x\n", chan->No, ind->Ind);
+ eicon_log(ccard, 8, "idi_ind: Ch%d: UNHANDLED SigIndication 0x%02x\n", chan->No, ind->Ind);
}
}
/* Network Layer */
@@ -1424,8 +2544,7 @@
else
switch(ind->Ind) {
case IDI_N_CONNECT_ACK:
- if (DebugVar & 16)
- printk(KERN_DEBUG"idi_ind: Ch%d: N_Connect_Ack\n", chan->No);
+ eicon_log(ccard, 16, "idi_ind: Ch%d: N_Connect_Ack\n", chan->No);
if (chan->l2prot == ISDN_PROTO_L2_MODEM) {
chan->fsm_state = EICON_STATE_WMCONN;
break;
@@ -1445,8 +2564,7 @@
}
}
else {
- if (DebugVar & 1)
- printk(KERN_DEBUG "idi_ind: N_CONNECT_ACK with NULL fax struct, ERROR\n");
+ eicon_log(ccard, 1, "idi_ind: N_CONNECT_ACK with NULL fax struct, ERROR\n");
}
#endif
break;
@@ -1455,11 +2573,11 @@
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:
- if (DebugVar & 16)
- printk(KERN_DEBUG"idi_ind: Ch%d: N_Connect\n", chan->No);
+ eicon_log(ccard, 16,"idi_ind: Ch%d: N_Connect\n", chan->No);
if (chan->e.B2Id) idi_do_req(ccard, chan, IDI_N_CONNECT_ACK, 1);
if (chan->l2prot == ISDN_PROTO_L2_FAX) {
break;
@@ -1472,12 +2590,15 @@
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:
- if (DebugVar & 16)
- printk(KERN_DEBUG"idi_ind: Ch%d: N_DISC\n", chan->No);
+ eicon_log(ccard, 16, "idi_ind: Ch%d: N_DISC\n", chan->No);
if (chan->e.B2Id) {
+ while((skb2 = skb_dequeue(&chan->e.X))) {
+ dev_kfree_skb(skb2);
+ }
idi_do_req(ccard, chan, IDI_N_DISC_ACK, 1);
idi_do_req(ccard, chan, REMOVE, 1);
}
@@ -1487,9 +2608,12 @@
idi_fax_hangup(ccard, chan);
}
#endif
+ save_flags(flags);
+ cli();
chan->queued = 0;
chan->waitq = 0;
chan->waitpq = 0;
+ restore_flags(flags);
idi_do_req(ccard, chan, HANGUP, 0);
if (chan->fsm_state == EICON_STATE_ACTIVE) {
cmd.driver = ccard->myid;
@@ -1497,14 +2621,14 @@
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;
#endif
break;
case IDI_N_DISC_ACK:
- if (DebugVar & 16)
- printk(KERN_DEBUG"idi_ind: Ch%d: N_DISC_ACK\n", chan->No);
+ eicon_log(ccard, 16, "idi_ind: Ch%d: N_DISC_ACK\n", chan->No);
#ifdef CONFIG_ISDN_TTY_FAX
if (chan->l2prot == ISDN_PROTO_L2_FAX) {
idi_parse_edata(ccard, chan, ind->RBuffer.P, ind->RBuffer.length);
@@ -1513,13 +2637,11 @@
#endif
break;
case IDI_N_DATA_ACK:
- if (DebugVar & 16)
- printk(KERN_DEBUG"idi_ind: Ch%d: N_DATA_ACK\n", chan->No);
+ eicon_log(ccard, 16, "idi_ind: Ch%d: N_DATA_ACK\n", chan->No);
break;
case IDI_N_DATA:
skb_pull(skb, sizeof(eicon_IND) - 1);
- if (DebugVar & 128)
- printk(KERN_DEBUG"idi_rcv: Ch%d: %d bytes\n", chan->No, skb->len);
+ eicon_log(ccard, 128, "idi_rcv: Ch%d: %d bytes\n", chan->No, skb->len);
if (chan->l2prot == ISDN_PROTO_L2_FAX) {
#ifdef CONFIG_ISDN_TTY_FAX
idi_faxdata_rcv(ccard, chan, skb);
@@ -1538,27 +2660,27 @@
break;
#endif
default:
- if (DebugVar & 8)
- printk(KERN_WARNING "idi_ind: Ch%d: UNHANDLED NetIndication 0x%02x\n", chan->No, ind->Ind);
+ eicon_log(ccard, 8, "idi_ind: Ch%d: UNHANDLED NetIndication 0x%02x\n", chan->No, ind->Ind);
}
}
else {
- if (DebugVar & 1)
- printk(KERN_ERR "idi_ind: Ch%d: Ind is neither SIG nor NET !\n", chan->No);
+ eicon_log(ccard, 1, "idi_ind: Ch%d: Ind is neither SIG nor NET !\n", chan->No);
}
- if (free_buff) dev_kfree_skb(skb);
+ if (free_buff)
+ dev_kfree_skb(skb);
}
int
idi_handle_ack_ok(eicon_card *ccard, eicon_chan *chan, eicon_RC *ack)
{
+ ulong flags;
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 */
- if (DebugVar & 16)
- printk(KERN_DEBUG "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);
+ /* 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;
}
@@ -1572,27 +2694,27 @@
/* Remove an Id */
if (chan->e.Req == REMOVE) {
if (ack->Reference != chan->e.ref) {
- if (DebugVar & 16)
- printk(KERN_DEBUG "idi_ack: Ch%d: Rc-Ref %d not equal to stored %d\n", chan->No,
- ack->Reference, chan->e.ref);
- return 0;
+ /* 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);
}
+ save_flags(flags);
+ cli();
ccard->IdTable[ack->RcId] = NULL;
- if (DebugVar & 16)
- printk(KERN_DEBUG "idi_ack: Ch%d: Removed : Id=%x Ch=%d (%s)\n", chan->No,
- ack->RcId, ack->RcCh, (chan->e.ReqCh)? "Net":"Sig");
+ eicon_log(ccard, 16, "idi_ack: Ch%d: Removed : Id=%x Ch=%d (%s)\n", chan->No,
+ ack->RcId, ack->RcCh, (chan->e.ReqCh)? "Net":"Sig");
if (!chan->e.ReqCh)
chan->e.D3Id = 0;
else
chan->e.B2Id = 0;
+ restore_flags(flags);
return 1;
}
/* Signal layer */
if (!chan->e.ReqCh) {
- if (DebugVar & 16)
- printk(KERN_DEBUG "idi_ack: Ch%d: RC OK Id=%x Ch=%d (ref:%d)\n", chan->No,
- ack->RcId, ack->RcCh, ack->Reference);
+ eicon_log(ccard, 16, "idi_ack: Ch%d: RC OK Id=%x Ch=%d (ref:%d)\n", chan->No,
+ ack->RcId, ack->RcCh, ack->Reference);
} else {
/* Network layer */
switch(chan->e.Req & 0x0f) {
@@ -1606,7 +2728,10 @@
cmd.parm.length = chan->waitpq;
ccard->interface.statcallb(&cmd);
}
+ save_flags(flags);
+ cli();
chan->waitpq = 0;
+ restore_flags(flags);
#ifdef CONFIG_ISDN_TTY_FAX
if (chan->l2prot == ISDN_PROTO_L2_FAX) {
if (((chan->queued - chan->waitq) < 1) &&
@@ -1620,20 +2745,21 @@
ccard->interface.statcallb(&cmd);
}
else {
- if (DebugVar & 1)
- printk(KERN_DEBUG "idi_ack: Sent with NULL fax struct, ERROR\n");
+ eicon_log(ccard, 1, "idi_ack: Sent with NULL fax struct, ERROR\n");
}
}
}
#endif
}
+ save_flags(flags);
+ cli();
chan->queued -= chan->waitq;
if (chan->queued < 0) chan->queued = 0;
+ restore_flags(flags);
break;
default:
- if (DebugVar & 16)
- printk(KERN_DEBUG "idi_ack: Ch%d: RC OK Id=%x Ch=%d (ref:%d)\n", chan->No,
- ack->RcId, ack->RcCh, ack->Reference);
+ eicon_log(ccard, 16, "idi_ack: Ch%d: RC OK Id=%x Ch=%d (ref:%d)\n", chan->No,
+ ack->RcId, ack->RcCh, ack->Reference);
}
}
return 1;
@@ -1643,22 +2769,30 @@
idi_handle_ack(eicon_card *ccard, struct sk_buff *skb)
{
int j;
+ ulong flags;
eicon_RC *ack = (eicon_RC *)skb->data;
eicon_chan *chan;
isdn_ctrl cmd;
int dCh = -1;
+ if (!ccard) {
+ eicon_log(ccard, 1, "idi_err: Ch??: null card in handle_ack\n");
+ dev_kfree_skb(skb);
+ return;
+ }
+
+ save_flags(flags);
+ cli();
if ((chan = ccard->IdTable[ack->RcId]) != NULL)
dCh = chan->No;
-
+ restore_flags(flags);
switch (ack->Rc) {
case OK_FC:
case N_FLOW_CONTROL:
case ASSIGN_RC:
- if (DebugVar & 1)
- printk(KERN_ERR "idi_ack: Ch%d: unhandled RC 0x%x\n",
- dCh, ack->Rc);
+ eicon_log(ccard, 1, "idi_ack: Ch%d: unhandled RC 0x%x\n",
+ dCh, ack->Rc);
break;
case READY_INT:
case TIMER_INT:
@@ -1667,8 +2801,7 @@
case OK:
if (!chan) {
- if (DebugVar & 1)
- printk(KERN_ERR "idi_ack: Ch%d: OK on chan without Id\n", dCh);
+ eicon_log(ccard, 1, "idi_ack: Ch%d: OK on chan without Id\n", dCh);
break;
}
if (!idi_handle_ack_ok(ccard, chan, ack))
@@ -1677,29 +2810,29 @@
case ASSIGN_OK:
if (chan) {
- if (DebugVar & 1)
- printk(KERN_ERR "idi_ack: Ch%d: ASSIGN-OK on chan already assigned (%x,%x)\n",
- chan->No, chan->e.D3Id, chan->e.B2Id);
+ eicon_log(ccard, 1, "idi_ack: Ch%d: ASSIGN-OK on chan already assigned (%x,%x)\n",
+ chan->No, chan->e.D3Id, chan->e.B2Id);
}
+ save_flags(flags);
+ cli();
for(j = 0; j < ccard->nchannels + 1; j++) {
- if (ccard->bch[j].e.ref == ack->Reference) {
+ if ((ccard->bch[j].e.ref == ack->Reference) &&
+ (ccard->bch[j].e.Req == ASSIGN)) {
if (!ccard->bch[j].e.ReqCh)
ccard->bch[j].e.D3Id = ack->RcId;
else
ccard->bch[j].e.B2Id = ack->RcId;
ccard->IdTable[ack->RcId] = &ccard->bch[j];
- ccard->bch[j].e.busy = 0;
- ccard->bch[j].e.ref = 0;
- if (DebugVar & 16)
- printk(KERN_DEBUG"idi_ack: Ch%d: Id %x assigned (%s)\n", j,
- ack->RcId, (ccard->bch[j].e.ReqCh)? "Net":"Sig");
+ chan = &ccard->bch[j];
+ eicon_log(ccard, 16, "idi_ack: Ch%d: Id %x assigned (%s)\n", j,
+ ack->RcId, (ccard->bch[j].e.ReqCh)? "Net":"Sig");
break;
}
}
+ restore_flags(flags);
if (j > ccard->nchannels) {
- if (DebugVar & 24)
- printk(KERN_DEBUG"idi_ack: Ch??: ref %d not found for Id %d\n",
- ack->Reference, ack->RcId);
+ eicon_log(ccard, 24, "idi_ack: Ch??: ref %d not found for Id %d\n",
+ ack->Reference, ack->RcId);
}
break;
@@ -1711,9 +2844,19 @@
case UNKNOWN_IE:
case WRONG_IE:
default:
- if (DebugVar & 1)
- printk(KERN_ERR "eicon_ack: Ch%d: Not OK !!: Rc=%d Id=%x Ch=%d\n", dCh,
- ack->Rc, ack->RcId, ack->RcCh);
+ if (!chan) {
+ eicon_log(ccard, 1, "idi_ack: Ch%d: Not OK !! on chan without Id\n", dCh);
+ break;
+ } else
+ switch (chan->e.Req) {
+ case 12: /* Alert */
+ eicon_log(ccard, 2, "eicon_err: Ch%d: Alert Not OK : Rc=%d Id=%x Ch=%d\n",
+ 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) { /* Management */
chan->fsm_state = 2;
} else if (dCh >= 0) {
@@ -1726,8 +2869,13 @@
ccard->interface.statcallb(&cmd);
}
}
- if (chan)
+ save_flags(flags);
+ cli();
+ if (chan) {
+ chan->e.ref = 0;
chan->e.busy = 0;
+ }
+ restore_flags(flags);
dev_kfree_skb(skb);
eicon_schedule_tx(ccard);
}
@@ -1742,21 +2890,25 @@
int len, plen = 0, offset = 0;
unsigned long flags;
+ if ((!card) || (!chan)) {
+ eicon_log(card, 1, "idi_err: Ch??: null card/chan in send_data\n");
+ return -1;
+ }
+
if (chan->fsm_state != EICON_STATE_ACTIVE) {
- if (DebugVar & 1)
- printk(KERN_DEBUG"idi_snd: Ch%d: send bytes on state %d !\n", chan->No, chan->fsm_state);
+ eicon_log(card, 1, "idi_snd: Ch%d: send bytes on state %d !\n", chan->No, chan->fsm_state);
return -ENODEV;
}
len = skb->len;
- if (len > 2138) /* too much for the shared memory */
+ if (len > EICON_MAX_QUEUE) /* too much for the shared memory */
return -1;
if (!len)
return 0;
- if (chan->queued + len > ((chan->l2prot == ISDN_PROTO_L2_TRANS) ? 4000 : EICON_MAX_QUEUED))
+ if (chan->queued + len > EICON_MAX_QUEUE)
return 0;
- if (DebugVar & 128)
- printk(KERN_DEBUG"idi_snd: Ch%d: %d bytes\n", chan->No, len);
+
+ eicon_log(card, 128, "idi_snd: Ch%d: %d bytes\n", chan->No, len);
save_flags(flags);
cli();
@@ -1769,8 +2921,7 @@
if ((!xmit_skb) || (!skb2)) {
restore_flags(flags);
- if (DebugVar & 1)
- printk(KERN_WARNING "idi_err: Ch%d: alloc_skb failed in send_data()\n", chan->No);
+ eicon_log(card, 1, "idi_err: Ch%d: alloc_skb failed in send_data()\n", chan->No);
if (xmit_skb)
dev_kfree_skb(skb);
if (skb2)
@@ -1824,8 +2975,7 @@
skb2 = alloc_skb(sizeof(eicon_chan_ptr), GFP_ATOMIC);
if ((!skb) || (!skb2)) {
- if (DebugVar & 1)
- printk(KERN_WARNING "idi_err: alloc_skb failed in manage_assign()\n");
+ eicon_log(card, 1, "idi_err: alloc_skb failed in manage_assign()\n");
if (skb)
dev_kfree_skb(skb);
if (skb2)
@@ -1867,8 +3017,7 @@
skb2 = alloc_skb(sizeof(eicon_chan_ptr), GFP_ATOMIC);
if ((!skb) || (!skb2)) {
- if (DebugVar & 1)
- printk(KERN_WARNING "idi_err: alloc_skb failed in manage_remove()\n");
+ eicon_log(card, 1, "idi_err: alloc_skb failed in manage_remove()\n");
if (skb)
dev_kfree_skb(skb);
if (skb2)
@@ -1934,8 +3083,7 @@
chan->fsm_state = 0;
if (!(manbuf = kmalloc(sizeof(eicon_manifbuf), GFP_KERNEL))) {
- if (DebugVar & 1)
- printk(KERN_WARNING "idi_err: alloc_manifbuf failed\n");
+ eicon_log(card, 1, "idi_err: alloc_manifbuf failed\n");
chan->e.D3Id = 0;
return -ENOMEM;
}
@@ -1949,8 +3097,7 @@
skb2 = alloc_skb(sizeof(eicon_chan_ptr), GFP_ATOMIC);
if ((!skb) || (!skb2)) {
- if (DebugVar & 1)
- printk(KERN_WARNING "idi_err_manif: alloc_skb failed in manage()\n");
+ eicon_log(card, 1, "idi_err_manif: alloc_skb failed in manage()\n");
if (skb)
dev_kfree_skb(skb);
if (skb2)
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)