patch-2.3.46 linux/drivers/isdn/eicon/eicon_idi.c

Next file: linux/drivers/isdn/eicon/eicon_idi.h
Previous file: linux/drivers/isdn/eicon/eicon_dsp.h
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.3.45/linux/drivers/isdn/eicon/eicon_idi.c linux/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 @@
 	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 @@
 			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 @@
 		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 @@
 	}
 	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 @@
 		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_do_req(card, chan, ASSIGN, 1);
+	idi_do_req(card, chan, CALL_RES, 0);
 	return(0);
 }
 
@@ -656,9 +676,18 @@
 	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 @@
 			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 @@
 					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 @@
 			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 @@
 }
 
 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 @@
 	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 @@
 				} 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 @@
 						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 @@
 
 		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 @@
 				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 @@
 				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 @@
 					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 @@
 	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 @@
 	/* 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 @@
 						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 @@
 
         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 @@
 		if (skb2) 
 			dev_kfree_skb(skb2);
 		kfree(manbuf);
-		chan->e.D3Id = 0;
                 return -ENOMEM;
         }
 
@@ -3093,25 +3196,14 @@
                 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);
 }

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)