patch-2.2.14 linux/drivers/isdn/hisax/hfc_pci.c

Next file: linux/drivers/isdn/hisax/hfc_pci.h
Previous file: linux/drivers/isdn/hisax/hfc_2bs0.h
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.2.13/linux/drivers/isdn/hisax/hfc_pci.c linux/drivers/isdn/hisax/hfc_pci.c
@@ -1,4 +1,4 @@
-/* $Id: hfc_pci.c,v 1.20 1999/09/07 06:18:55 werner Exp $
+/* $Id: hfc_pci.c,v 1.25 1999/12/19 13:09:42 keil Exp $
 
  * hfc_pci.c     low level driver for CCD´s hfc-pci based cards
  *
@@ -23,6 +23,25 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
  * $Log: hfc_pci.c,v $
+ * Revision 1.25  1999/12/19 13:09:42  keil
+ * changed TASK_INTERRUPTIBLE into TASK_UNINTERRUPTIBLE for
+ * signal proof delays
+ *
+ * Revision 1.24  1999/11/17 23:59:55  werner
+ *
+ * removed unneeded data
+ *
+ * Revision 1.23  1999/11/07 17:01:55  keil
+ * fix for 2.3 pci structs
+ *
+ * Revision 1.22  1999/10/10 20:14:27  werner
+ *
+ * Correct B2-chan usage in conjuntion with echo mode. First implementation of NT-leased line mode.
+ *
+ * Revision 1.21  1999/10/02 17:47:49  werner
+ *
+ * Changed init order, added correction for page alignment with shared mem
+ *
  * Revision 1.20  1999/09/07 06:18:55  werner
  *
  * Added io parameter for HFC-PCI based cards. Needed only with multiple cards
@@ -103,52 +122,40 @@
 
 extern const char *CardType[];
 
-static const char *hfcpci_revision = "$Revision: 1.20 $";
+static const char *hfcpci_revision = "$Revision: 1.25 $";
 
 /* table entry in the PCI devices list */
 typedef struct {
-  int vendor_id; 
-  int device_id;
-  char *vendor_name;
-  char *card_name;
-  } PCI_ENTRY;
-
-static const PCI_ENTRY id_list[] = {
-  {0x1397,0x2BD0,"CCD/Billion/Asuscom","2BD0"},
-  {0x1397,0xB000,"Billion","B000"},
-  {0x1397,0xB006,"Billion","B006"},
-  {0x1397,0xB007,"Billion","B007"},
-  {0x1397,0xB008,"Billion","B008"},
-  {0x1397,0xB009,"Billion","B009"},
-  {0x1397,0xB00A,"Billion","B00A"},
-  {0x1397,0xB00B,"Billion","B00B"},
-  {0x1397,0xB00C,"Billion","B00C"},
-  {0x1043,0x0675,"Asuscom/Askey","675"},
-  {0x0871,0xFFA2,"German telekom","T-Concept"},
-  {0x0871,0xFFA1,"German telekom","A1T"},
-  {0x1051,0x0100,"Motorola MC145575","MC145575"},
-  {0x1397,0xB100,"Seyeon","B100"},
-  {0x15B0,0x2BD0,"Zoltrix","2BD0"},
-  {0,0,NULL,NULL},      
+	int vendor_id;
+	int device_id;
+	char *vendor_name;
+	char *card_name;
+} PCI_ENTRY;
+
+#define NT_T1_COUNT 20		/* number of 3.125ms interrupts for G2 timeout */
+
+static const PCI_ENTRY id_list[] =
+{
+	{0x1397, 0x2BD0, "CCD/Billion/Asuscom", "2BD0"},
+	{0x1397, 0xB000, "Billion", "B000"},
+	{0x1397, 0xB006, "Billion", "B006"},
+	{0x1397, 0xB007, "Billion", "B007"},
+	{0x1397, 0xB008, "Billion", "B008"},
+	{0x1397, 0xB009, "Billion", "B009"},
+	{0x1397, 0xB00A, "Billion", "B00A"},
+	{0x1397, 0xB00B, "Billion", "B00B"},
+	{0x1397, 0xB00C, "Billion", "B00C"},
+	{0x1043, 0x0675, "Asuscom/Askey", "675"},
+	{0x0871, 0xFFA2, "German telekom", "T-Concept"},
+	{0x0871, 0xFFA1, "German telekom", "A1T"},
+	{0x1051, 0x0100, "Motorola MC145575", "MC145575"},
+	{0x1397, 0xB100, "Seyeon", "B100"},
+	{0x15B0, 0x2BD0, "Zoltrix", "2BD0"},
+	{0, 0, NULL, NULL},
 };
 
 
 #if CONFIG_PCI
-/*****************************/
-/* release D- and B-channels */
-/*****************************/
-void
-releasehfcpci(struct IsdnCardState *cs)
-{
-	if (cs->bcs[0].hw.hfc.send) {
-		kfree(cs->bcs[0].hw.hfc.send);
-		cs->bcs[0].hw.hfc.send = NULL;
-	}
-	if (cs->bcs[1].hw.hfc.send) {
-		kfree(cs->bcs[1].hw.hfc.send);
-		cs->bcs[1].hw.hfc.send = NULL;
-	}
-}
 
 /******************************************/
 /* free hardware resources used by driver */
@@ -156,10 +163,21 @@
 void
 release_io_hfcpci(struct IsdnCardState *cs)
 {
+	int flags;
+
+	save_flags(flags);
+	cli();
+	cs->hw.hfcpci.int_m2 = 0;	/* interrupt output off ! */
+	Write_hfc(cs, HFCPCI_INT_M2, cs->hw.hfcpci.int_m2);
+	restore_flags(flags);
+	Write_hfc(cs, HFCPCI_CIRM, HFCPCI_RESET);	/* Reset On */
+	sti();
+	current->state = TASK_UNINTERRUPTIBLE;
+	schedule_timeout((30 * HZ) / 1000);	/* Timeout 30ms */
+	Write_hfc(cs, HFCPCI_CIRM, 0);	/* Reset Off */
 #if CONFIG_PCI
-	pcibios_write_config_word(cs->hw.hfcpci.pci_bus, cs->hw.hfcpci.pci_device_fn, PCI_COMMAND, 0);	/* disabe memory mapped ports + busmaster */
-#endif	/* CONFIG_PCI */
-	releasehfcpci(cs);
+	pcibios_write_config_word(cs->hw.hfcpci.pci_bus, cs->hw.hfcpci.pci_device_fn, PCI_COMMAND, 0);	/* disable memory mapped ports + busmaster */
+#endif				/* CONFIG_PCI */
 	del_timer(&cs->hw.hfcpci.timer);
 	kfree(cs->hw.hfcpci.share_start);
 	cs->hw.hfcpci.share_start = NULL;
@@ -175,16 +193,20 @@
 {
 	long flags;
 
+	save_flags(flags);
+	cli();
 	pcibios_write_config_word(cs->hw.hfcpci.pci_bus, cs->hw.hfcpci.pci_device_fn, PCI_COMMAND, PCI_ENA_MEMIO);	/* enable memory mapped ports, disable busmaster */
+	cs->hw.hfcpci.int_m2 = 0;	/* interrupt output off ! */
+	Write_hfc(cs, HFCPCI_INT_M2, cs->hw.hfcpci.int_m2);
+
 	printk(KERN_INFO "HFC_PCI: resetting card\n");
 	pcibios_write_config_word(cs->hw.hfcpci.pci_bus, cs->hw.hfcpci.pci_device_fn, PCI_COMMAND, PCI_ENA_MEMIO + PCI_ENA_MASTER);	/* enable memory ports + busmaster */
 	Write_hfc(cs, HFCPCI_CIRM, HFCPCI_RESET);	/* Reset On */
-	save_flags(flags);
 	sti();
-	current->state = TASK_INTERRUPTIBLE;
+	current->state = TASK_UNINTERRUPTIBLE;
 	schedule_timeout((30 * HZ) / 1000);	/* Timeout 30ms */
 	Write_hfc(cs, HFCPCI_CIRM, 0);	/* Reset Off */
-	current->state = TASK_INTERRUPTIBLE;
+	current->state = TASK_UNINTERRUPTIBLE;
 	schedule_timeout((20 * HZ) / 1000);	/* Timeout 20ms */
 	if (Read_hfc(cs, HFCPCI_STATUS) & 2)
 		printk(KERN_WARNING "HFC-PCI init bit busy\n");
@@ -192,25 +214,23 @@
 	cs->hw.hfcpci.fifo_en = 0x30;	/* only D fifos enabled */
 	Write_hfc(cs, HFCPCI_FIFO_EN, cs->hw.hfcpci.fifo_en);
 
-	cs->hw.hfcpci.trm = 0 + HFCPCI_BTRANS_THRESMASK; /* no echo connect , threshold */
+	cs->hw.hfcpci.trm = 0 + HFCPCI_BTRANS_THRESMASK;	/* no echo connect , threshold */
 	Write_hfc(cs, HFCPCI_TRM, cs->hw.hfcpci.trm);
 
 	Write_hfc(cs, HFCPCI_CLKDEL, 0x0e);	/* ST-Bit delay for TE-Mode */
 	cs->hw.hfcpci.sctrl_e = HFCPCI_AUTO_AWAKE;
 	Write_hfc(cs, HFCPCI_SCTRL_E, cs->hw.hfcpci.sctrl_e);	/* S/T Auto awake */
-	cs->hw.hfcpci.bswapped = 0; /* no exchange */
+	cs->hw.hfcpci.bswapped = 0;	/* no exchange */
+	cs->hw.hfcpci.nt_mode = 0;	/* we are in TE mode */
 	cs->hw.hfcpci.ctmt = HFCPCI_TIM3_125 | HFCPCI_AUTO_TIMER;
 	Write_hfc(cs, HFCPCI_CTMT, cs->hw.hfcpci.ctmt);
 
-	cs->hw.hfcpci.int_m2 = HFCPCI_IRQ_ENABLE;
-	cs->hw.hfcpci.int_m1 = HFCPCI_INTS_DTRANS | HFCPCI_INTS_DREC | 
-	                       HFCPCI_INTS_L1STATE | HFCPCI_CLTIMER;
+	cs->hw.hfcpci.int_m1 = HFCPCI_INTS_DTRANS | HFCPCI_INTS_DREC |
+	    HFCPCI_INTS_L1STATE | HFCPCI_INTS_TIMER;
 	Write_hfc(cs, HFCPCI_INT_M1, cs->hw.hfcpci.int_m1);
-	Write_hfc(cs, HFCPCI_INT_M2, cs->hw.hfcpci.int_m2);
 
 	/* Clear already pending ints */
 	if (Read_hfc(cs, HFCPCI_INT_S1));
-	if (Read_hfc(cs, HFCPCI_INT_S2));
 
 	Write_hfc(cs, HFCPCI_STATES, HFCPCI_LOAD_STATE | 2);	/* HFC ST 2 */
 	udelay(10);
@@ -218,24 +238,29 @@
 	cs->hw.hfcpci.mst_m = HFCPCI_MASTER;	/* HFC Master Mode */
 
 	Write_hfc(cs, HFCPCI_MST_MODE, cs->hw.hfcpci.mst_m);
-	cs->hw.hfcpci.sctrl = 0x40; /* set tx_lo mode, error in datasheet ! */
+	cs->hw.hfcpci.sctrl = 0x40;	/* set tx_lo mode, error in datasheet ! */
 	Write_hfc(cs, HFCPCI_SCTRL, cs->hw.hfcpci.sctrl);
 	cs->hw.hfcpci.sctrl_r = 0;
 	Write_hfc(cs, HFCPCI_SCTRL_R, cs->hw.hfcpci.sctrl_r);
 
-        /* Init GCI/IOM2 in master mode */
+	/* Init GCI/IOM2 in master mode */
 	/* Slots 0 and 1 are set for B-chan 1 and 2 */
 	/* D- and monitor/CI channel are not enabled */
 	/* STIO1 is used as output for data, B1+B2 from ST->IOM+HFC */
-	/* STIO2 is used as data input, B1+B2 from IOM->ST */ 
+	/* STIO2 is used as data input, B1+B2 from IOM->ST */
 	/* ST B-channel send disabled -> continous 1s */
 	/* The IOM slots are always enabled */
-	cs->hw.hfcpci.conn = 0x36; /* set data flow directions */
+	cs->hw.hfcpci.conn = 0x36;	/* set data flow directions */
 	Write_hfc(cs, HFCPCI_CONNECT, cs->hw.hfcpci.conn);
-	Write_hfc(cs, HFCPCI_B1_SSL, 0x80); /* B1-Slot 0 STIO1 out enabled */
-	Write_hfc(cs, HFCPCI_B2_SSL, 0x81); /* B2-Slot 1 STIO1 out enabled */
-	Write_hfc(cs, HFCPCI_B1_RSL, 0x80); /* B1-Slot 0 STIO2 in enabled */
-	Write_hfc(cs, HFCPCI_B2_RSL, 0x81); /* B2-Slot 1 STIO2 in enabled */
+	Write_hfc(cs, HFCPCI_B1_SSL, 0x80);	/* B1-Slot 0 STIO1 out enabled */
+	Write_hfc(cs, HFCPCI_B2_SSL, 0x81);	/* B2-Slot 1 STIO1 out enabled */
+	Write_hfc(cs, HFCPCI_B1_RSL, 0x80);	/* B1-Slot 0 STIO2 in enabled */
+	Write_hfc(cs, HFCPCI_B2_RSL, 0x81);	/* B2-Slot 1 STIO2 in enabled */
+
+	/* Finally enable IRQ output */
+	cs->hw.hfcpci.int_m2 = HFCPCI_IRQ_ENABLE;
+	Write_hfc(cs, HFCPCI_INT_M2, cs->hw.hfcpci.int_m2);
+	if (Read_hfc(cs, HFCPCI_INT_S2));
 	restore_flags(flags);
 }
 
@@ -326,7 +351,7 @@
 		count -= 3;
 		ptr = skb_put(skb, count);
 
- 		if (zp->z2 + count <= B_FIFO_SIZE + B_SUB_VAL)
+		if (zp->z2 + count <= B_FIFO_SIZE + B_SUB_VAL)
 			maxlen = count;		/* complete transfer */
 		else
 			maxlen = B_FIFO_SIZE + B_SUB_VAL - zp->z2;	/* maximum */
@@ -418,54 +443,56 @@
 /*******************************************************************************/
 /* check for transparent receive data and read max one threshold size if avail */
 /*******************************************************************************/
-int hfcpci_empty_fifo_trans(struct BCState *bcs, bzfifo_type *bz, u_char *bdata)
-{ unsigned short *z1r, *z2r;
-  int new_z2, fcnt, maxlen;
-  struct sk_buff *skb;
-  u_char *ptr, *ptr1;
-
-  z1r = &bz->za[MAX_B_FRAMES].z1; /* pointer to z reg */
-  z2r = z1r + 1; 
-
-  if (!(fcnt = *z1r - *z2r)) 
-    return(0); /* no data avail */
-
-  if (fcnt <= 0) 
-    fcnt += B_FIFO_SIZE; /* bytes actually buffered */  
-  if (fcnt > HFCPCI_BTRANS_THRESHOLD)
-    fcnt = HFCPCI_BTRANS_THRESHOLD; /* limit size */
-
-  new_z2 = *z2r + fcnt;	/* new position in fifo */
-  if (new_z2 >= (B_FIFO_SIZE + B_SUB_VAL))
-    new_z2 -= B_FIFO_SIZE;	/* buffer wrap */
+int
+hfcpci_empty_fifo_trans(struct BCState *bcs, bzfifo_type * bz, u_char * bdata)
+{
+	unsigned short *z1r, *z2r;
+	int new_z2, fcnt, maxlen;
+	struct sk_buff *skb;
+	u_char *ptr, *ptr1;
+
+	z1r = &bz->za[MAX_B_FRAMES].z1;		/* pointer to z reg */
+	z2r = z1r + 1;
+
+	if (!(fcnt = *z1r - *z2r))
+		return (0);	/* no data avail */
+
+	if (fcnt <= 0)
+		fcnt += B_FIFO_SIZE;	/* bytes actually buffered */
+	if (fcnt > HFCPCI_BTRANS_THRESHOLD)
+		fcnt = HFCPCI_BTRANS_THRESHOLD;		/* limit size */
+
+	new_z2 = *z2r + fcnt;	/* new position in fifo */
+	if (new_z2 >= (B_FIFO_SIZE + B_SUB_VAL))
+		new_z2 -= B_FIFO_SIZE;	/* buffer wrap */
 
-  if (!(skb = dev_alloc_skb(fcnt)))
+	if (!(skb = dev_alloc_skb(fcnt)))
 		printk(KERN_WARNING "HFCPCI: receive out of memory\n");
-  else {
-    ptr = skb_put(skb, fcnt);
-    if (*z2r + fcnt <= B_FIFO_SIZE + B_SUB_VAL)
-      maxlen = fcnt; /* complete transfer */
-    else
-      maxlen = B_FIFO_SIZE + B_SUB_VAL - *z2r;	/* maximum */
-
-    ptr1 = bdata + (*z2r - B_SUB_VAL);	/* start of data */
-    memcpy(ptr, ptr1, maxlen);	/* copy data */
-    fcnt -= maxlen;
-
-    if (fcnt) {	/* rest remaining */
-      ptr += maxlen;
-      ptr1 = bdata;	/* start of buffer */
-      memcpy(ptr, ptr1, fcnt);	/* rest */
-    }
-    cli();
-    skb_queue_tail(&bcs->rqueue, skb);
-    sti();
-    hfcpci_sched_event(bcs, B_RCVBUFREADY); 
-  }
-  
-  *z2r = new_z2; /* new position */
-  return(1);
-} /* hfcpci_empty_fifo_trans */ 
+	else {
+		ptr = skb_put(skb, fcnt);
+		if (*z2r + fcnt <= B_FIFO_SIZE + B_SUB_VAL)
+			maxlen = fcnt;	/* complete transfer */
+		else
+			maxlen = B_FIFO_SIZE + B_SUB_VAL - *z2r;	/* maximum */
+
+		ptr1 = bdata + (*z2r - B_SUB_VAL);	/* start of data */
+		memcpy(ptr, ptr1, maxlen);	/* copy data */
+		fcnt -= maxlen;
+
+		if (fcnt) {	/* rest remaining */
+			ptr += maxlen;
+			ptr1 = bdata;	/* start of buffer */
+			memcpy(ptr, ptr1, fcnt);	/* rest */
+		}
+		cli();
+		skb_queue_tail(&bcs->rqueue, skb);
+		sti();
+		hfcpci_sched_event(bcs, B_RCVBUFREADY);
+	}
+
+	*z2r = new_z2;		/* new position */
+	return (1);
+}				/* hfcpci_empty_fifo_trans */
 
 /**********************************/
 /* B-channel main receive routine */
@@ -526,11 +553,10 @@
 			receive = 1;
 		else
 			receive = 0;
-	} else 
-	  if (bcs->mode == L1_MODE_TRANS)
-	    receive = hfcpci_empty_fifo_trans(bcs, bz, bdata);
-	  else
-	    receive = 0;
+	} else if (bcs->mode == L1_MODE_TRANS)
+		receive = hfcpci_empty_fifo_trans(bcs, bz, bdata);
+	else
+		receive = 0;
 	test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
 	if (count && receive)
 		goto Begin;
@@ -622,7 +648,7 @@
 	bzfifo_type *bz;
 	u_char *bdata;
 	u_char new_f1, *src, *dst;
-        unsigned short *z1t, *z2t;
+	unsigned short *z1t, *z2t;
 
 	if (!bcs->tx_skb)
 		return;
@@ -641,57 +667,53 @@
 	}
 
 	if (bcs->mode == L1_MODE_TRANS) {
-	  z1t = &bz->za[MAX_B_FRAMES].z1;
-	  z2t = z1t + 1;
-	  if (cs->debug & L1_DEB_HSCX)
-	          debugl1(cs, "hfcpci_fill_fifo_trans %d z1(%x) z2(%x)",
-		  bcs->channel, *z1t, *z2t);
-	  fcnt = *z2t - *z1t;
-	  if (fcnt <= 0)
-	          fcnt += B_FIFO_SIZE;	/* fcnt contains available bytes in fifo */
-	  fcnt = B_FIFO_SIZE - fcnt; /* remaining bytes to send */
-
-	  while ((fcnt < 2 * HFCPCI_BTRANS_THRESHOLD) && (bcs->tx_skb)) {
-	    if (bcs->tx_skb->len < B_FIFO_SIZE - fcnt) { 
-	      /* data is suitable for fifo */
-	      count = bcs->tx_skb->len;
-
-	      new_z1 = *z1t + count;	/* new buffer Position */
-	      if (new_z1 >= (B_FIFO_SIZE + B_SUB_VAL))
-		new_z1 -= B_FIFO_SIZE;	/* buffer wrap */
-	      src = bcs->tx_skb->data;	/* source pointer */
-	      dst = bdata + (*z1t - B_SUB_VAL);
-	      maxlen = (B_FIFO_SIZE + B_SUB_VAL) - *z1t; /* end of fifo */
-	      if (maxlen > count)
-		maxlen = count;	/* limit size */
-	      memcpy(dst, src, maxlen);	/* first copy */
+		z1t = &bz->za[MAX_B_FRAMES].z1;
+		z2t = z1t + 1;
+		if (cs->debug & L1_DEB_HSCX)
+			debugl1(cs, "hfcpci_fill_fifo_trans %d z1(%x) z2(%x)",
+				bcs->channel, *z1t, *z2t);
+		fcnt = *z2t - *z1t;
+		if (fcnt <= 0)
+			fcnt += B_FIFO_SIZE;	/* fcnt contains available bytes in fifo */
+		fcnt = B_FIFO_SIZE - fcnt;	/* remaining bytes to send */
+
+		while ((fcnt < 2 * HFCPCI_BTRANS_THRESHOLD) && (bcs->tx_skb)) {
+			if (bcs->tx_skb->len < B_FIFO_SIZE - fcnt) {
+				/* data is suitable for fifo */
+				count = bcs->tx_skb->len;
+
+				new_z1 = *z1t + count;	/* new buffer Position */
+				if (new_z1 >= (B_FIFO_SIZE + B_SUB_VAL))
+					new_z1 -= B_FIFO_SIZE;	/* buffer wrap */
+				src = bcs->tx_skb->data;	/* source pointer */
+				dst = bdata + (*z1t - B_SUB_VAL);
+				maxlen = (B_FIFO_SIZE + B_SUB_VAL) - *z1t;	/* end of fifo */
+				if (maxlen > count)
+					maxlen = count;		/* limit size */
+				memcpy(dst, src, maxlen);	/* first copy */
+
+				count -= maxlen;	/* remaining bytes */
+				if (count) {
+					dst = bdata;	/* start of buffer */
+					src += maxlen;	/* new position */
+					memcpy(dst, src, count);
+				}
+				bcs->tx_cnt -= bcs->tx_skb->len;
+				fcnt += bcs->tx_skb->len;
+				*z1t = new_z1;	/* now send data */
+			} else if (cs->debug & L1_DEB_HSCX)
+				debugl1(cs, "hfcpci_fill_fifo_trans %d frame length %d discarded",
+					bcs->channel, bcs->tx_skb->len);
 
-	      count -= maxlen;	/* remaining bytes */
-	      if (count) {
-		dst = bdata;	/* start of buffer */
-		src += maxlen;	/* new position */
-		memcpy(dst, src, count);
-	      }
-	      bcs->tx_cnt -= bcs->tx_skb->len;
-	      fcnt += bcs->tx_skb->len;
-	      *z1t = new_z1; /* now send data */
-	    }
-            else 
-	      if (cs->debug & L1_DEB_HSCX)
-		debugl1(cs, "hfcpci_fill_fifo_trans %d frame length %d discarded",
-			bcs->channel, bcs->tx_skb->len);
-
-	    dev_kfree_skb(bcs->tx_skb);
-            cli();
-            bcs->tx_skb = skb_dequeue(&bcs->squeue); /* fetch next data */
-            sti();
-	  }  
-	  test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
-	  restore_flags(flags);
-	  return;
+			dev_kfree_skb(bcs->tx_skb);
+			cli();
+			bcs->tx_skb = skb_dequeue(&bcs->squeue);	/* fetch next data */
+			sti();
+		}
+		test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
+		restore_flags(flags);
+		return;
 	}
-
-
 	if (cs->debug & L1_DEB_HSCX)
 		debugl1(cs, "hfcpci_fill_fifo_hdlc %d f1(%d) f2(%d) z1(f1)(%x)",
 			bcs->channel, bz->f1, bz->f2,
@@ -757,51 +779,107 @@
 	return;
 }
 
+/**********************************************/
+/* D-channel l1 state call for leased NT-mode */
+/**********************************************/
+static void
+dch_nt_l2l1(struct PStack *st, int pr, void *arg)
+{
+	struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware;
+
+	switch (pr) {
+		case (PH_DATA | REQUEST):
+		case (PH_PULL | REQUEST):
+		case (PH_PULL | INDICATION):
+			st->l1.l1hw(st, pr, arg);
+			break;
+		case (PH_ACTIVATE | REQUEST):
+			st->l1.l1l2(st, PH_ACTIVATE | CONFIRM, NULL);
+			break;
+		case (PH_TESTLOOP | REQUEST):
+			if (1 & (long) arg)
+				debugl1(cs, "PH_TEST_LOOP B1");
+			if (2 & (long) arg)
+				debugl1(cs, "PH_TEST_LOOP B2");
+			if (!(3 & (long) arg))
+				debugl1(cs, "PH_TEST_LOOP DISABLED");
+			st->l1.l1hw(st, HW_TESTLOOP | REQUEST, arg);
+			break;
+		default:
+			if (cs->debug)
+				debugl1(cs, "dch_nt_l2l1 msg %04X unhandled", pr);
+			break;
+	}
+}
+
+
+
 /***********************/
 /* set/reset echo mode */
-/***********************/ 
+/***********************/
 static int
-hfcpci_auxcmd(struct IsdnCardState *cs, isdn_ctrl *ic)
+hfcpci_auxcmd(struct IsdnCardState *cs, isdn_ctrl * ic)
 {
-  int flags;
-  int i = *(unsigned int *) ic->parm.num;
-  
-  if (cs->chanlimit > 1)
-    return(-EINVAL);
-
-  save_flags(flags);
-  cli();
-  if (i) {
-    cs->logecho = 1;
-    cs->hw.hfcpci.trm |= 0x20; /* enable echo chan */
-    cs->hw.hfcpci.int_m1 |= HFCPCI_INTS_B2REC;
-    cs->hw.hfcpci.fifo_en |= HFCPCI_FIFOEN_B2RX;
-  }
-  else {
-    cs->logecho = 0;
-    cs->hw.hfcpci.trm &= ~0x20; /* enable echo chan */
-    cs->hw.hfcpci.int_m1 &= ~HFCPCI_INTS_B2REC;
-    cs->hw.hfcpci.fifo_en &= ~HFCPCI_FIFOEN_B2RX;
-  }
-    cs->hw.hfcpci.sctrl_r &= ~SCTRL_B2_ENA;
-    cs->hw.hfcpci.sctrl &= ~SCTRL_B2_ENA;
-    cs->hw.hfcpci.conn |= 0x10; /* B2-IOM -> B2-ST */ 
-    cs->hw.hfcpci.ctmt &= ~2;
-  Write_hfc(cs, HFCPCI_CTMT, cs->hw.hfcpci.ctmt);
-  Write_hfc(cs, HFCPCI_SCTRL_R, cs->hw.hfcpci.sctrl_r);
-  Write_hfc(cs, HFCPCI_SCTRL, cs->hw.hfcpci.sctrl);
-  Write_hfc(cs, HFCPCI_CONNECT, cs->hw.hfcpci.conn);
-  Write_hfc(cs, HFCPCI_TRM, cs->hw.hfcpci.trm);
-  Write_hfc(cs, HFCPCI_FIFO_EN, cs->hw.hfcpci.fifo_en);
-  Write_hfc(cs, HFCPCI_INT_M1, cs->hw.hfcpci.int_m1);
-  restore_flags(flags);
-  return(0);
-} /* hfcpci_auxcmd */ 
+	int flags;
+	int i = *(unsigned int *) ic->parm.num;
+
+	if ((ic->arg == 98) &&
+	    (!(cs->hw.hfcpci.int_m1 & (HFCPCI_INTS_B2TRANS + HFCPCI_INTS_B2REC + HFCPCI_INTS_B1TRANS + HFCPCI_INTS_B1REC)))) {
+		save_flags(flags);
+		cli();
+		Write_hfc(cs, HFCPCI_STATES, HFCPCI_LOAD_STATE | 0);	/* HFC ST G0 */
+		udelay(10);
+		cs->hw.hfcpci.sctrl |= SCTRL_MODE_NT;
+		Write_hfc(cs, HFCPCI_SCTRL, cs->hw.hfcpci.sctrl);	/* set NT-mode */
+		udelay(10);
+		Write_hfc(cs, HFCPCI_STATES, HFCPCI_LOAD_STATE | 1);	/* HFC ST G1 */
+		udelay(10);
+		Write_hfc(cs, HFCPCI_STATES, 1 | HFCPCI_ACTIVATE | HFCPCI_DO_ACTION);
+		cs->dc.hfcpci.ph_state = 1;
+		cs->hw.hfcpci.nt_mode = 1;
+		cs->hw.hfcpci.nt_timer = 0;
+		cs->stlist->l2.l2l1 = dch_nt_l2l1;
+		restore_flags(flags);
+		debugl1(cs, "NT mode activated");
+		return (0);
+	}
+	if ((cs->chanlimit > 1) || (cs->hw.hfcpci.bswapped) ||
+	    (cs->hw.hfcpci.nt_mode) || (ic->arg != 12))
+		return (-EINVAL);
+
+	save_flags(flags);
+	cli();
+	if (i) {
+		cs->logecho = 1;
+		cs->hw.hfcpci.trm |= 0x20;	/* enable echo chan */
+		cs->hw.hfcpci.int_m1 |= HFCPCI_INTS_B2REC;
+		cs->hw.hfcpci.fifo_en |= HFCPCI_FIFOEN_B2RX;
+	} else {
+		cs->logecho = 0;
+		cs->hw.hfcpci.trm &= ~0x20;	/* disable echo chan */
+		cs->hw.hfcpci.int_m1 &= ~HFCPCI_INTS_B2REC;
+		cs->hw.hfcpci.fifo_en &= ~HFCPCI_FIFOEN_B2RX;
+	}
+	cs->hw.hfcpci.sctrl_r &= ~SCTRL_B2_ENA;
+	cs->hw.hfcpci.sctrl &= ~SCTRL_B2_ENA;
+	cs->hw.hfcpci.conn |= 0x10;	/* B2-IOM -> B2-ST */
+	cs->hw.hfcpci.ctmt &= ~2;
+	Write_hfc(cs, HFCPCI_CTMT, cs->hw.hfcpci.ctmt);
+	Write_hfc(cs, HFCPCI_SCTRL_R, cs->hw.hfcpci.sctrl_r);
+	Write_hfc(cs, HFCPCI_SCTRL, cs->hw.hfcpci.sctrl);
+	Write_hfc(cs, HFCPCI_CONNECT, cs->hw.hfcpci.conn);
+	Write_hfc(cs, HFCPCI_TRM, cs->hw.hfcpci.trm);
+	Write_hfc(cs, HFCPCI_FIFO_EN, cs->hw.hfcpci.fifo_en);
+	Write_hfc(cs, HFCPCI_INT_M1, cs->hw.hfcpci.int_m1);
+	restore_flags(flags);
+	return (0);
+}				/* hfcpci_auxcmd */
 
 /*****************************/
 /* E-channel receive routine */
 /*****************************/
-static void receive_emsg(struct IsdnCardState *cs)
+static void
+receive_emsg(struct IsdnCardState *cs)
 {
 	long flags;
 	int rcnt;
@@ -838,55 +916,54 @@
 		if (cs->debug & L1_DEB_ISAC)
 			debugl1(cs, "hfcpci e_rec z1(%x) z2(%x) cnt(%d)",
 				zp->z1, zp->z2, rcnt);
-                new_z2 = zp->z2 + rcnt; /* new position in fifo */
+		new_z2 = zp->z2 + rcnt;		/* new position in fifo */
 		if (new_z2 >= (B_FIFO_SIZE + B_SUB_VAL))
-		  new_z2 -= B_FIFO_SIZE; /* buffer wrap */
+			new_z2 -= B_FIFO_SIZE;	/* buffer wrap */
 		new_f2 = (bz->f2 + 1) & MAX_B_FRAMES;
-	        if ((rcnt > 256 + 3) || (count < 4) ||
+		if ((rcnt > 256 + 3) || (count < 4) ||
 		    (*(bdata + (zp->z1 - B_SUB_VAL)))) {
-		  if (cs->debug & L1_DEB_WARN)
-			debugl1(cs, "hfcpci_empty_echan: incoming packet invalid length %d or crc", rcnt);
-		  bz->za[new_f2].z2 = new_z2;
-		  bz->f2 = new_f2;	/* next buffer */
+			if (cs->debug & L1_DEB_WARN)
+				debugl1(cs, "hfcpci_empty_echan: incoming packet invalid length %d or crc", rcnt);
+			bz->za[new_f2].z2 = new_z2;
+			bz->f2 = new_f2;	/* next buffer */
 		} else {
-		    total = rcnt;
-		    rcnt -= 3;
-		    ptr = e_buffer;
-
-		    if (zp->z2 <= B_FIFO_SIZE + B_SUB_VAL)
-			maxlen = rcnt;		/* complete transfer */
-		    else
-			maxlen = B_FIFO_SIZE + B_SUB_VAL - zp->z2;	/* maximum */
+			total = rcnt;
+			rcnt -= 3;
+			ptr = e_buffer;
 
-		    ptr1 = bdata + (zp->z2 - B_SUB_VAL);	/* start of data */
-		    memcpy(ptr, ptr1, maxlen);	/* copy data */
-		    rcnt -= maxlen;
+			if (zp->z2 <= B_FIFO_SIZE + B_SUB_VAL)
+				maxlen = rcnt;	/* complete transfer */
+			else
+				maxlen = B_FIFO_SIZE + B_SUB_VAL - zp->z2;	/* maximum */
 
-		    if (rcnt) {	/* rest remaining */
-			ptr += maxlen;
-			ptr1 = bdata;	/* start of buffer */
-			memcpy(ptr, ptr1, rcnt);	/* rest */
-		    }
-		    bz->za[new_f2].z2 = new_z2;
-		    bz->f2 = new_f2;	/* next buffer */
-		    if (cs->debug & DEB_DLOG_HEX) {
-		      	ptr = cs->dlog;
-			if ((total - 3) < MAX_DLOG_SPACE / 3 - 10) {
-			  *ptr++ = 'E';
-			  *ptr++ = 'C';
-			  *ptr++ = 'H';
-			  *ptr++ = 'O';
-			  *ptr++ = ':';
-			  ptr += QuickHex(ptr, e_buffer, total - 3);
-			  ptr--;
-			  *ptr++ = '\n';
-			  *ptr = 0;
-			  HiSax_putstatus(cs, NULL, cs->dlog);
-			} else
-			  HiSax_putstatus(cs, "LogEcho: ", "warning Frame too big (%d)", total - 3);
-		    }
+			ptr1 = bdata + (zp->z2 - B_SUB_VAL);	/* start of data */
+			memcpy(ptr, ptr1, maxlen);	/* copy data */
+			rcnt -= maxlen;
 
-	}
+			if (rcnt) {	/* rest remaining */
+				ptr += maxlen;
+				ptr1 = bdata;	/* start of buffer */
+				memcpy(ptr, ptr1, rcnt);	/* rest */
+			}
+			bz->za[new_f2].z2 = new_z2;
+			bz->f2 = new_f2;	/* next buffer */
+			if (cs->debug & DEB_DLOG_HEX) {
+				ptr = cs->dlog;
+				if ((total - 3) < MAX_DLOG_SPACE / 3 - 10) {
+					*ptr++ = 'E';
+					*ptr++ = 'C';
+					*ptr++ = 'H';
+					*ptr++ = 'O';
+					*ptr++ = ':';
+					ptr += QuickHex(ptr, e_buffer, total - 3);
+					ptr--;
+					*ptr++ = '\n';
+					*ptr = 0;
+					HiSax_putstatus(cs, NULL, cs->dlog);
+				} else
+					HiSax_putstatus(cs, "LogEcho: ", "warning Frame too big (%d)", total - 3);
+			}
+		}
 
 		rcnt = bz->f1 - bz->f2;
 		if (rcnt < 0)
@@ -902,7 +979,7 @@
 		goto Begin;
 	restore_flags(flags);
 	return;
-} /* receive_emsg */
+}				/* receive_emsg */
 
 /*********************/
 /* Interrupt handler */
@@ -921,6 +998,9 @@
 		printk(KERN_WARNING "HFC-PCI: Spurious interrupt!\n");
 		return;
 	}
+	if (!(cs->hw.hfcpci.int_m2 & 0x08))
+		return;		/* not initialised */
+
 	if (HFCPCI_ANYINT & (stat = Read_hfc(cs, HFCPCI_STATUS))) {
 		val = Read_hfc(cs, HFCPCI_INT_S1);
 		if (cs->debug & L1_DEB_ISAC)
@@ -933,7 +1013,7 @@
 			test_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags) ?
 			"locked" : "unlocked");
 	val &= cs->hw.hfcpci.int_m1;
-	if (val & 0x40) {	/* TE state machine irq */
+	if (val & 0x40) {	/* state machine irq */
 		exval = Read_hfc(cs, HFCPCI_STATES) & 0xf;
 		if (cs->debug & L1_DEB_ISAC)
 			debugl1(cs, "ph_state chg %d->%d", cs->dc.hfcpci.ph_state,
@@ -942,6 +1022,14 @@
 		sched_event_D_pci(cs, D_L1STATECHANGE);
 		val &= ~0x40;
 	}
+	if (val & 0x80) {	/* timer irq */
+		if (cs->hw.hfcpci.nt_mode) {
+			if ((--cs->hw.hfcpci.nt_timer) < 0)
+				sched_event_D_pci(cs, D_L1STATECHANGE);
+		}
+		val &= ~0x80;
+		Write_hfc(cs, HFCPCI_CTMT, cs->hw.hfcpci.ctmt | HFCPCI_CLTIMER);
+	}
 	while (val) {
 		save_flags(flags);
 		cli();
@@ -956,24 +1044,23 @@
 			cs->hw.hfcpci.int_s1 = exval;
 		}
 		if (val & 0x08) {
-			if (!(bcs = Sel_BCS(cs, cs->hw.hfcpci.bswapped ? 1:0))) {
+			if (!(bcs = Sel_BCS(cs, cs->hw.hfcpci.bswapped ? 1 : 0))) {
 				if (cs->debug)
 					debugl1(cs, "hfcpci spurious 0x08 IRQ");
 			} else
 				main_rec_hfcpci(bcs);
 		}
-		if (val & 0x10) { 
-		        if (cs->logecho)
-			  receive_emsg(cs);
-			else    
-			if (!(bcs = Sel_BCS(cs, 1))) {
+		if (val & 0x10) {
+			if (cs->logecho)
+				receive_emsg(cs);
+			else if (!(bcs = Sel_BCS(cs, 1))) {
 				if (cs->debug)
 					debugl1(cs, "hfcpci spurious 0x10 IRQ");
 			} else
 				main_rec_hfcpci(bcs);
 		}
 		if (val & 0x01) {
-			if (!(bcs = Sel_BCS(cs, cs->hw.hfcpci.bswapped ? 1:0))) {
+			if (!(bcs = Sel_BCS(cs, cs->hw.hfcpci.bswapped ? 1 : 0))) {
 				if (cs->debug)
 					debugl1(cs, "hfcpci spurious 0x01 IRQ");
 			} else {
@@ -1082,6 +1169,7 @@
 {
 	struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware;
 	struct sk_buff *skb = arg;
+	int flags;
 
 	switch (pr) {
 		case (PH_DATA | REQUEST):
@@ -1157,13 +1245,46 @@
 			Write_hfc(cs, HFCPCI_STATES, HFCPCI_ACTIVATE | HFCPCI_DO_ACTION);
 			break;
 		case (HW_DEACTIVATE | REQUEST):
-      			cs->hw.hfcpci.mst_m &= ~HFCPCI_MASTER;
+			cs->hw.hfcpci.mst_m &= ~HFCPCI_MASTER;
 			Write_hfc(cs, HFCPCI_MST_MODE, cs->hw.hfcpci.mst_m);
 			break;
 		case (HW_INFO3 | REQUEST):
 			cs->hw.hfcpci.mst_m |= HFCPCI_MASTER;
 			Write_hfc(cs, HFCPCI_MST_MODE, cs->hw.hfcpci.mst_m);
 			break;
+		case (HW_TESTLOOP | REQUEST):
+			switch ((int) arg) {
+				case (1):
+					Write_hfc(cs, HFCPCI_B1_SSL, 0x80);	/* tx slot */
+					Write_hfc(cs, HFCPCI_B1_RSL, 0x80);	/* rx slot */
+					save_flags(flags);
+					cli();
+					cs->hw.hfcpci.conn = (cs->hw.hfcpci.conn & ~7) | 1;
+					Write_hfc(cs, HFCPCI_CONNECT, cs->hw.hfcpci.conn);
+					restore_flags(flags);
+					break;
+
+				case (2):
+					Write_hfc(cs, HFCPCI_B2_SSL, 0x81);	/* tx slot */
+					Write_hfc(cs, HFCPCI_B2_RSL, 0x81);	/* rx slot */
+					save_flags(flags);
+					cli();
+					cs->hw.hfcpci.conn = (cs->hw.hfcpci.conn & ~0x38) | 0x08;
+					Write_hfc(cs, HFCPCI_CONNECT, cs->hw.hfcpci.conn);
+					restore_flags(flags);
+					break;
+
+				default:
+					if (cs->debug & L1_DEB_WARN)
+						debugl1(cs, "hfcpci_l1hw loop invalid %4x", (int) arg);
+					return;
+			}
+			save_flags(flags);
+			cli();
+			cs->hw.hfcpci.trm |= 0x80;	/* enable IOM-loop */
+			Write_hfc(cs, HFCPCI_TRM, cs->hw.hfcpci.trm);
+			restore_flags(flags);
+			break;
 		default:
 			if (cs->debug & L1_DEB_WARN)
 				debugl1(cs, "hfcpci_l1hw unknown pr %4x", pr);
@@ -1203,113 +1324,127 @@
 {
 	struct IsdnCardState *cs = bcs->cs;
 	bzfifo_type *bzr, *bzt;
-	int flags;
+	int flags, fifo2;
 
 	if (cs->debug & L1_DEB_HSCX)
 		debugl1(cs, "HFCPCI bchannel mode %d bchan %d/%d",
 			mode, bc, bcs->channel);
 	bcs->mode = mode;
 	bcs->channel = bc;
-	if (cs->chanlimit > 1) { 
-	  cs->hw.hfcpci.bswapped = 0; /* B1 and B2 normal mode */
-	  cs->hw.hfcpci.sctrl_e &= ~0x80; 
-	}
-	else {
-	  if (bc) {
-	    cs->hw.hfcpci.bswapped = 1; /* B1 and B2 exchanged */
-	    cs->hw.hfcpci.sctrl_e |= 0x80;
-	    bc = 0; /* B1 controller used */
-	  }
-	  else {
-	    cs->hw.hfcpci.bswapped = 0; /* B1 and B2 normal mode */
-	    cs->hw.hfcpci.sctrl_e &= ~0x80; 
-	  }  
-	}  
+	fifo2 = bc;
 	save_flags(flags);
 	cli();
+	if (cs->chanlimit > 1) {
+		cs->hw.hfcpci.bswapped = 0;	/* B1 and B2 normal mode */
+		cs->hw.hfcpci.sctrl_e &= ~0x80;
+	} else {
+		if (bc) {
+			if (mode != L1_MODE_NULL) {
+				cs->hw.hfcpci.bswapped = 1;	/* B1 and B2 exchanged */
+				cs->hw.hfcpci.sctrl_e |= 0x80;
+			} else {
+				cs->hw.hfcpci.bswapped = 0;	/* B1 and B2 normal mode */
+				cs->hw.hfcpci.sctrl_e &= ~0x80;
+			}
+			fifo2 = 0;
+		} else {
+			cs->hw.hfcpci.bswapped = 0;	/* B1 and B2 normal mode */
+			cs->hw.hfcpci.sctrl_e &= ~0x80;
+		}
+	}
 	switch (mode) {
 		case (L1_MODE_NULL):
 			if (bc) {
 				cs->hw.hfcpci.sctrl &= ~SCTRL_B2_ENA;
 				cs->hw.hfcpci.sctrl_r &= ~SCTRL_B2_ENA;
-				cs->hw.hfcpci.fifo_en &= ~HFCPCI_FIFOEN_B2;
-				cs->hw.hfcpci.int_m1 &= ~(HFCPCI_INTS_B2TRANS+HFCPCI_INTS_B2REC);
 			} else {
 				cs->hw.hfcpci.sctrl &= ~SCTRL_B1_ENA;
 				cs->hw.hfcpci.sctrl_r &= ~SCTRL_B1_ENA;
+			}
+			if (fifo2) {
+				cs->hw.hfcpci.fifo_en &= ~HFCPCI_FIFOEN_B2;
+				cs->hw.hfcpci.int_m1 &= ~(HFCPCI_INTS_B2TRANS + HFCPCI_INTS_B2REC);
+			} else {
 				cs->hw.hfcpci.fifo_en &= ~HFCPCI_FIFOEN_B1;
-				cs->hw.hfcpci.int_m1 &= ~(HFCPCI_INTS_B1TRANS+HFCPCI_INTS_B1REC);
+				cs->hw.hfcpci.int_m1 &= ~(HFCPCI_INTS_B1TRANS + HFCPCI_INTS_B1REC);
 			}
 			break;
 		case (L1_MODE_TRANS):
 			if (bc) {
-				cs->hw.hfcpci.ctmt |= 2;
-				cs->hw.hfcpci.conn &= ~0x18;
 				cs->hw.hfcpci.sctrl |= SCTRL_B2_ENA;
 				cs->hw.hfcpci.sctrl_r |= SCTRL_B2_ENA;
-				cs->hw.hfcpci.fifo_en |= HFCPCI_FIFOEN_B2;
-				cs->hw.hfcpci.int_m1 |= (HFCPCI_INTS_B2TRANS+HFCPCI_INTS_B2REC);
-		                bzr = &((fifo_area *) (cs->hw.hfcpci.fifos))->b_chans.rxbz_b2;
-		                bzt = &((fifo_area *) (cs->hw.hfcpci.fifos))->b_chans.txbz_b2;
 			} else {
-				cs->hw.hfcpci.ctmt |= 1;
-				cs->hw.hfcpci.conn &= ~0x03;
 				cs->hw.hfcpci.sctrl |= SCTRL_B1_ENA;
 				cs->hw.hfcpci.sctrl_r |= SCTRL_B1_ENA;
+			}
+			if (fifo2) {
+				cs->hw.hfcpci.fifo_en |= HFCPCI_FIFOEN_B2;
+				cs->hw.hfcpci.int_m1 |= (HFCPCI_INTS_B2TRANS + HFCPCI_INTS_B2REC);
+				cs->hw.hfcpci.ctmt |= 2;
+				cs->hw.hfcpci.conn &= ~0x18;
+				bzr = &((fifo_area *) (cs->hw.hfcpci.fifos))->b_chans.rxbz_b2;
+				bzt = &((fifo_area *) (cs->hw.hfcpci.fifos))->b_chans.txbz_b2;
+			} else {
 				cs->hw.hfcpci.fifo_en |= HFCPCI_FIFOEN_B1;
-				cs->hw.hfcpci.int_m1 |= (HFCPCI_INTS_B1TRANS+HFCPCI_INTS_B1REC);
-		                bzr = &((fifo_area *) (cs->hw.hfcpci.fifos))->b_chans.rxbz_b1;
-		                bzt = &((fifo_area *) (cs->hw.hfcpci.fifos))->b_chans.txbz_b1;
+				cs->hw.hfcpci.int_m1 |= (HFCPCI_INTS_B1TRANS + HFCPCI_INTS_B1REC);
+				cs->hw.hfcpci.ctmt |= 1;
+				cs->hw.hfcpci.conn &= ~0x03;
+				bzr = &((fifo_area *) (cs->hw.hfcpci.fifos))->b_chans.rxbz_b1;
+				bzt = &((fifo_area *) (cs->hw.hfcpci.fifos))->b_chans.txbz_b1;
 			}
 			bzr->za[MAX_B_FRAMES].z1 = B_FIFO_SIZE + B_SUB_VAL - 1;
-                        bzr->za[MAX_B_FRAMES].z2 = bzr->za[MAX_B_FRAMES].z1; 
+			bzr->za[MAX_B_FRAMES].z2 = bzr->za[MAX_B_FRAMES].z1;
 			bzr->f1 = MAX_B_FRAMES;
-			bzr->f2 = bzr->f1; /* init F pointers to remain constant */
+			bzr->f2 = bzr->f1;	/* init F pointers to remain constant */
 			bzt->za[MAX_B_FRAMES].z1 = B_FIFO_SIZE + B_SUB_VAL - 1;
-                        bzt->za[MAX_B_FRAMES].z2 = bzt->za[MAX_B_FRAMES].z1; 
+			bzt->za[MAX_B_FRAMES].z2 = bzt->za[MAX_B_FRAMES].z1;
 			bzt->f1 = MAX_B_FRAMES;
-			bzt->f2 = bzt->f1; /* init F pointers to remain constant */
+			bzt->f2 = bzt->f1;	/* init F pointers to remain constant */
 			break;
 		case (L1_MODE_HDLC):
 			if (bc) {
-				cs->hw.hfcpci.ctmt &= ~2;
-				cs->hw.hfcpci.conn &= ~0x18;
 				cs->hw.hfcpci.sctrl |= SCTRL_B2_ENA;
 				cs->hw.hfcpci.sctrl_r |= SCTRL_B2_ENA;
-				cs->hw.hfcpci.fifo_en |= HFCPCI_FIFOEN_B2;
-				cs->hw.hfcpci.int_m1 |= (HFCPCI_INTS_B2TRANS+HFCPCI_INTS_B2REC);
 			} else {
-				cs->hw.hfcpci.ctmt &= ~1;
-				cs->hw.hfcpci.conn &= ~0x3;
 				cs->hw.hfcpci.sctrl |= SCTRL_B1_ENA;
 				cs->hw.hfcpci.sctrl_r |= SCTRL_B1_ENA;
+			}
+			if (fifo2) {
+				cs->hw.hfcpci.fifo_en |= HFCPCI_FIFOEN_B2;
+				cs->hw.hfcpci.int_m1 |= (HFCPCI_INTS_B2TRANS + HFCPCI_INTS_B2REC);
+				cs->hw.hfcpci.ctmt &= ~2;
+				cs->hw.hfcpci.conn &= ~0x18;
+			} else {
 				cs->hw.hfcpci.fifo_en |= HFCPCI_FIFOEN_B1;
-				cs->hw.hfcpci.int_m1 |= (HFCPCI_INTS_B1TRANS+HFCPCI_INTS_B1REC);
+				cs->hw.hfcpci.int_m1 |= (HFCPCI_INTS_B1TRANS + HFCPCI_INTS_B1REC);
+				cs->hw.hfcpci.ctmt &= ~1;
+				cs->hw.hfcpci.conn &= ~0x03;
 			}
 			break;
 		case (L1_MODE_EXTRN):
 			if (bc) {
-			        cs->hw.hfcpci.conn |= 0x10;
+				cs->hw.hfcpci.conn |= 0x10;
 				cs->hw.hfcpci.sctrl |= SCTRL_B2_ENA;
 				cs->hw.hfcpci.sctrl_r |= SCTRL_B2_ENA;
 				cs->hw.hfcpci.fifo_en &= ~HFCPCI_FIFOEN_B2;
-				cs->hw.hfcpci.int_m1 &= ~(HFCPCI_INTS_B2TRANS+HFCPCI_INTS_B2REC);
+				cs->hw.hfcpci.int_m1 &= ~(HFCPCI_INTS_B2TRANS + HFCPCI_INTS_B2REC);
 			} else {
-			        cs->hw.hfcpci.conn |= 0x02;
+				cs->hw.hfcpci.conn |= 0x02;
 				cs->hw.hfcpci.sctrl |= SCTRL_B1_ENA;
 				cs->hw.hfcpci.sctrl_r |= SCTRL_B1_ENA;
 				cs->hw.hfcpci.fifo_en &= ~HFCPCI_FIFOEN_B1;
-				cs->hw.hfcpci.int_m1 &= ~(HFCPCI_INTS_B1TRANS+HFCPCI_INTS_B1REC);
+				cs->hw.hfcpci.int_m1 &= ~(HFCPCI_INTS_B1TRANS + HFCPCI_INTS_B1REC);
 			}
 			break;
 	}
+	Write_hfc(cs, HFCPCI_SCTRL_E, cs->hw.hfcpci.sctrl_e);
 	Write_hfc(cs, HFCPCI_INT_M1, cs->hw.hfcpci.int_m1);
-	restore_flags(flags);
 	Write_hfc(cs, HFCPCI_FIFO_EN, cs->hw.hfcpci.fifo_en);
 	Write_hfc(cs, HFCPCI_SCTRL, cs->hw.hfcpci.sctrl);
 	Write_hfc(cs, HFCPCI_SCTRL_R, cs->hw.hfcpci.sctrl_r);
 	Write_hfc(cs, HFCPCI_CTMT, cs->hw.hfcpci.ctmt);
 	Write_hfc(cs, HFCPCI_CONNECT, cs->hw.hfcpci.conn);
+	restore_flags(flags);
 }
 
 /******************************/
@@ -1429,29 +1564,72 @@
 static void
 hfcpci_bh(struct IsdnCardState *cs)
 {
+	int flags;
 /*      struct PStack *stptr;
  */
 	if (!cs)
 		return;
 	if (test_and_clear_bit(D_L1STATECHANGE, &cs->event)) {
-		switch (cs->dc.hfcpci.ph_state) {
-			case (0):
-				l1_msg(cs, HW_RESET | INDICATION, NULL);
-				break;
-			case (3):
-				l1_msg(cs, HW_DEACTIVATE | INDICATION, NULL);
-				break;
-			case (8):
-				l1_msg(cs, HW_RSYNC | INDICATION, NULL);
-				break;
-			case (6):
-				l1_msg(cs, HW_INFO2 | INDICATION, NULL);
-				break;
-			case (7):
-				l1_msg(cs, HW_INFO4_P8 | INDICATION, NULL);
-				break;
-			default:
-				break;
+		if (!cs->hw.hfcpci.nt_mode)
+			switch (cs->dc.hfcpci.ph_state) {
+				case (0):
+					l1_msg(cs, HW_RESET | INDICATION, NULL);
+					break;
+				case (3):
+					l1_msg(cs, HW_DEACTIVATE | INDICATION, NULL);
+					break;
+				case (8):
+					l1_msg(cs, HW_RSYNC | INDICATION, NULL);
+					break;
+				case (6):
+					l1_msg(cs, HW_INFO2 | INDICATION, NULL);
+					break;
+				case (7):
+					l1_msg(cs, HW_INFO4_P8 | INDICATION, NULL);
+					break;
+				default:
+					break;
+		} else {
+			switch (cs->dc.hfcpci.ph_state) {
+				case (2):
+					save_flags(flags);
+					cli();
+					if (cs->hw.hfcpci.nt_timer < 0) {
+						cs->hw.hfcpci.nt_timer = 0;
+						cs->hw.hfcpci.int_m1 &= ~HFCPCI_INTS_TIMER;
+						Write_hfc(cs, HFCPCI_INT_M1, cs->hw.hfcpci.int_m1);
+						/* Clear already pending ints */
+						if (Read_hfc(cs, HFCPCI_INT_S1));
+
+						Write_hfc(cs, HFCPCI_STATES, 4 | HFCPCI_LOAD_STATE);
+						udelay(10);
+						Write_hfc(cs, HFCPCI_STATES, 4);
+						cs->dc.hfcpci.ph_state = 4;
+					} else {
+						cs->hw.hfcpci.int_m1 |= HFCPCI_INTS_TIMER;
+						Write_hfc(cs, HFCPCI_INT_M1, cs->hw.hfcpci.int_m1);
+						cs->hw.hfcpci.ctmt &= ~HFCPCI_AUTO_TIMER;
+						cs->hw.hfcpci.ctmt |= HFCPCI_TIM3_125;
+						Write_hfc(cs, HFCPCI_CTMT, cs->hw.hfcpci.ctmt | HFCPCI_CLTIMER);
+						Write_hfc(cs, HFCPCI_CTMT, cs->hw.hfcpci.ctmt | HFCPCI_CLTIMER);
+						cs->hw.hfcpci.nt_timer = NT_T1_COUNT;
+						Write_hfc(cs, HFCPCI_STATES, 2 | HFCPCI_NT_G2_G3);	/* allow G2 -> G3 transition */
+					}
+					restore_flags(flags);
+					break;
+				case (1):
+				case (3):
+				case (4):
+					save_flags(flags);
+					cli();
+					cs->hw.hfcpci.nt_timer = 0;
+					cs->hw.hfcpci.int_m1 &= ~HFCPCI_INTS_TIMER;
+					Write_hfc(cs, HFCPCI_INT_M1, cs->hw.hfcpci.int_m1);
+					restore_flags(flags);
+					break;
+				default:
+					break;
+			}
 		}
 	}
 	if (test_and_clear_bit(D_RCVBUFREADY, &cs->event))
@@ -1461,24 +1639,6 @@
 }
 
 
-/*************************************/
-/* Alloc memory send data for queues */
-/*************************************/
-__initfunc(unsigned int
-	   *init_send_hfcpci(int cnt))
-{
-	int i, *send;
-
-	if (!(send = kmalloc(cnt * sizeof(unsigned int), GFP_ATOMIC))) {
-		printk(KERN_WARNING
-		       "HiSax: No memory for hfcpci.send\n");
-		return (NULL);
-	}
-	for (i = 0; i < cnt; i++)
-		send[i] = 0x1fff;
-	return (send);
-}
-
 /********************************/
 /* called for card init message */
 /********************************/
@@ -1490,10 +1650,6 @@
 	cs->dbusytimer.data = (long) cs;
 	init_timer(&cs->dbusytimer);
 	cs->tqueue.routine = (void *) (void *) hfcpci_bh;
-	if (!cs->bcs[0].hw.hfc.send)
-		cs->bcs[0].hw.hfc.send = init_send_hfcpci(32);
-	if (!cs->bcs[1].hw.hfc.send)
-		cs->bcs[1].hw.hfc.send = init_send_hfcpci(32);
 	cs->BC_Send_Data = &hfcpci_send_data;
 	cs->bcs[0].BC_SetStack = setstack_2b;
 	cs->bcs[1].BC_SetStack = setstack_2b;
@@ -1526,7 +1682,7 @@
 			inithfcpci(cs);
 			save_flags(flags);
 			sti();
-			current->state = TASK_INTERRUPTIBLE;
+			current->state = TASK_UNINTERRUPTIBLE;
 			schedule_timeout((80 * HZ) / 1000);	/* Timeout 80ms */
 			/* now switch timer interrupt off */
 			cs->hw.hfcpci.int_m1 &= ~HFCPCI_INTS_TIMER;
@@ -1551,16 +1707,15 @@
 	   setup_hfcpci(struct IsdnCard *card))
 {
 	struct IsdnCardState *cs = card->cs;
+	unsigned short cmd;
 	char tmp[64];
 	int i;
-        struct pci_dev *tmp_hfcpci = NULL;
+	struct pci_dev *tmp_hfcpci = NULL;
 
 	strcpy(tmp, hfcpci_revision);
 	printk(KERN_INFO "HiSax: HFC-PCI driver Rev. %s\n", HiSax_getrev(tmp));
 #if CONFIG_PCI
 	cs->hw.hfcpci.int_s1 = 0;
-	cs->bcs[0].hw.hfc.send = NULL;
-	cs->bcs[1].hw.hfc.send = NULL;
 	cs->dc.hfcpci.ph_state = 0;
 	cs->hw.hfcpci.fifo = 255;
 	if (cs->typ == ISDN_CTYPE_HFC_PCI) {
@@ -1569,22 +1724,22 @@
 			return (0);
 		}
 		i = 0;
-                while (id_list[i].vendor_id) {
-		  tmp_hfcpci = pci_find_device(id_list[i].vendor_id,
-					       id_list[i].device_id,
-					       dev_hfcpci);
-		  i++;
-		  if (tmp_hfcpci) {
-		    if ((card->para[0]) && (card->para[0] != (tmp_hfcpci->base_address[0] & PCI_BASE_ADDRESS_IO_MASK)))
-		      continue;
-		    else
-		      break;
-		  }  
-		}  
-					      
+		while (id_list[i].vendor_id) {
+			tmp_hfcpci = pci_find_device(id_list[i].vendor_id,
+						     id_list[i].device_id,
+						     dev_hfcpci);
+			i++;
+			if (tmp_hfcpci) {
+				if ((card->para[0]) && (card->para[0] != (tmp_hfcpci->base_address[ 0] & PCI_BASE_ADDRESS_IO_MASK)))
+					continue;
+				else
+					break;
+			}
+		}
+
 		if (tmp_hfcpci) {
-		        i--;
-		        dev_hfcpci = tmp_hfcpci; /* old device */
+			i--;
+			dev_hfcpci = tmp_hfcpci;	/* old device */
 			cs->hw.hfcpci.pci_bus = dev_hfcpci->bus->number;
 			cs->hw.hfcpci.pci_device_fn = dev_hfcpci->devfn;
 			cs->irq = dev_hfcpci->irq;
@@ -1593,11 +1748,44 @@
 				return (0);
 			}
 			cs->hw.hfcpci.pci_io = (char *) dev_hfcpci->base_address[ 1];
-			printk(KERN_INFO "HiSax: HFC-PCI card manufacturer: %s card name: %s\n",id_list[i].vendor_name,id_list[i].card_name);
+			printk(KERN_INFO "HiSax: HFC-PCI card manufacturer: %s card name: %s\n", id_list[i].vendor_name, id_list[i].card_name);
 		} else {
 			printk(KERN_WARNING "HFC-PCI: No PCI card found\n");
 			return (0);
 		}
+		if (((int) cs->hw.hfcpci.pci_io & (PAGE_SIZE - 1))) {
+			printk(KERN_WARNING "HFC-PCI shared mem address will be corrected\n");
+			pcibios_write_config_word(cs->hw.hfcpci.pci_bus,
+					     cs->hw.hfcpci.pci_device_fn,
+						  PCI_COMMAND,
+						  0x0103);	/* set SERR */
+			pcibios_read_config_word(cs->hw.hfcpci.pci_bus,
+					     cs->hw.hfcpci.pci_device_fn,
+						 PCI_COMMAND,
+						 &cmd);
+			pcibios_write_config_word(cs->hw.hfcpci.pci_bus,
+					     cs->hw.hfcpci.pci_device_fn,
+						  PCI_COMMAND,
+						  cmd & ~2);
+			(int) cs->hw.hfcpci.pci_io &= ~(PAGE_SIZE - 1);
+			pcibios_write_config_dword(cs->hw.hfcpci.pci_bus,
+					     cs->hw.hfcpci.pci_device_fn,
+						   PCI_BASE_ADDRESS_1,
+					     (int) cs->hw.hfcpci.pci_io);
+			pcibios_write_config_word(cs->hw.hfcpci.pci_bus,
+					     cs->hw.hfcpci.pci_device_fn,
+						  PCI_COMMAND,
+						  cmd);
+			pcibios_read_config_dword(cs->hw.hfcpci.pci_bus,
+					     cs->hw.hfcpci.pci_device_fn,
+						  PCI_BASE_ADDRESS_1,
+					 (void *) &cs->hw.hfcpci.pci_io);
+			if (((int) cs->hw.hfcpci.pci_io & (PAGE_SIZE - 1))) {
+				printk(KERN_WARNING "HFC-PCI unable to align address %x\n", (unsigned) cs->hw.hfcpci.pci_io);
+				return (0);
+			}
+			dev_hfcpci->base_address[1] = (int) cs->hw.hfcpci.pci_io;
+		}
 		if (!cs->hw.hfcpci.pci_io) {
 			printk(KERN_WARNING "HFC-PCI: No IO-Mem for PCI card found\n");
 			return (0);
@@ -1613,16 +1801,16 @@
 		    (((ulong) cs->hw.hfcpci.share_start) & ~0x7FFF) + 0x8000;
 		pcibios_write_config_dword(cs->hw.hfcpci.pci_bus,
 				       cs->hw.hfcpci.pci_device_fn, 0x80,
-					   (u_int) virt_to_bus(cs->hw.hfcpci.fifos));
+			       (u_int) virt_to_bus(cs->hw.hfcpci.fifos));
 		cs->hw.hfcpci.pci_io = ioremap((ulong) cs->hw.hfcpci.pci_io, 256);
 		printk(KERN_INFO
-		 "HFC-PCI: defined at mem %#x fifo %#x(%#x) IRQ %d HZ %d\n",
+		       "HFC-PCI: defined at mem %#x fifo %#x(%#x) IRQ %d HZ %d\n",
 		       (u_int) cs->hw.hfcpci.pci_io,
 		       (u_int) cs->hw.hfcpci.fifos,
 		       (u_int) virt_to_bus(cs->hw.hfcpci.fifos),
 		       cs->irq, HZ);
 		pcibios_write_config_word(cs->hw.hfcpci.pci_bus, cs->hw.hfcpci.pci_device_fn, PCI_COMMAND, PCI_ENA_MEMIO);	/* enable memory mapped ports, disable busmaster */
-		cs->hw.hfcpci.int_m2 = 0; /* disable alle interrupts */
+		cs->hw.hfcpci.int_m2 = 0;	/* disable alle interrupts */
 		cs->hw.hfcpci.int_m1 = 0;
 		Write_hfc(cs, HFCPCI_INT_M1, cs->hw.hfcpci.int_m1);
 		Write_hfc(cs, HFCPCI_INT_M2, cs->hw.hfcpci.int_m2);
@@ -1647,7 +1835,7 @@
 
 	reset_hfcpci(cs);
 	cs->cardmsg = &hfcpci_card_msg;
-	cs->auxcmd  = &hfcpci_auxcmd;
+	cs->auxcmd = &hfcpci_auxcmd;
 	return (1);
 #else
 	printk(KERN_WARNING "HFC-PCI: NO_PCI_BIOS\n");

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