[Pkg-voip-commits] r5129 - in /zaptel/trunk: cwain/cwain.c cwain/cwain.h cwain/zaptel.conf.hdlcnet.doubleE1 debian/changelog

tzafrir-guest at alioth.debian.org tzafrir-guest at alioth.debian.org
Fri Dec 28 00:20:29 UTC 2007


Author: tzafrir-guest
Date: Fri Dec 28 00:20:29 2007
New Revision: 5129

URL: http://svn.debian.org/wsvn/pkg-voip/?sc=1&rev=5129
Log:
Update cwain from recent bristuff.

Modified:
    zaptel/trunk/cwain/cwain.c
    zaptel/trunk/cwain/cwain.h
    zaptel/trunk/cwain/zaptel.conf.hdlcnet.doubleE1
    zaptel/trunk/debian/changelog

Modified: zaptel/trunk/cwain/cwain.c
URL: http://svn.debian.org/wsvn/pkg-voip/zaptel/trunk/cwain/cwain.c?rev=5129&op=diff
==============================================================================
--- zaptel/trunk/cwain/cwain.c (original)
+++ zaptel/trunk/cwain/cwain.c Fri Dec 28 00:20:29 2007
@@ -5,7 +5,7 @@
  *
  * single/double E1 board
  *
- * Copyright (C) 2004, 2005 Junghanns.NET GmbH
+ * Copyright (C) 2004, 2005, 2006, 2007 Junghanns.NET GmbH
  *
  * Klaus-Peter Junghanns <kpj at junghanns.net>
  *
@@ -21,10 +21,20 @@
 #include <zaptel.h>
 #include "cwain.h"
 
+#ifdef LINUX26
+#include <linux/moduleparam.h>
+#endif
+
 #if CONFIG_PCI
 
 static int ports=-1; /* autodetect */
 static int debug=0;
+static int hw_hdlc=1;
+static int hdlcnet=0;
+static int pwm0 = 0x50;	/* TX level */
+static int pwm1 = 0x50; /* RX level */
+static int dacs = 1; /* 0 = no dacs, 1 = oncard dacs */
+static int require_ext_clock = 0;
 static struct zt_cwain *cwain_span_list = NULL;
 static int cwain_span_count = 0;
 static struct zt_cwain_card *cwain_card_list = NULL;
@@ -97,8 +107,6 @@
 	cwainspan->pcidev = NULL;
     }
 
-//    iounmap((void *) cwainspan->pci_io);
-//    cwainspan->pci_io = NULL;
 }
 
 void cwain_shutdown_card(struct zt_cwain_card *cwaintmp) {
@@ -110,20 +118,18 @@
 	return;
     }
 
-    for (i=0;i<cwaintmp->spans;i++) {
-	cwain_unregister_zap_span(cwaintmp->span[i]);
-    }
-
     spin_lock_irqsave(&cwaintmp->lock,flags);
 
     // turn off irqs
     cwain_outb(cwaintmp->span[0],cwain_R_IRQ_CTRL, 0); 
     cwain_outb(cwaintmp->span[0],cwain_R_IRQMSK_MISC, 0); 
 
+    spin_unlock_irqrestore(&cwaintmp->lock,flags);
+
     for (i=0;i<cwaintmp->spans;i++) {
-	cwain_shutdown_span(cwaintmp->span[i]);
-    }
-    spin_unlock_irqrestore(&cwaintmp->lock,flags);
+	cwain_unregister_zap_span(cwaintmp->span[i]);
+    }
+
 
     for (i=0;i<cwaintmp->spans;i++) {
 	release_region(cwaintmp->span[i]->ioport, 8);
@@ -175,32 +181,52 @@
     }
 }
 
-void cwain_reset_span(struct zt_cwain *cwaintmp) {
-    int i = 0;
-    pci_write_config_word(cwaintmp->pcidev, PCI_COMMAND, PCI_COMMAND_MEMORY | PCI_COMMAND_IO);	// enable memio
-
-    /* FIFO, HDLC reset */
-    cwain_outb(cwaintmp,cwain_R_CIRM,0x10);
-    cwain_outb(cwaintmp,cwain_R_CIRM,0x0); 
-    cwain_waitbusy(cwaintmp);
-
+void cwain_reset_pcm(struct zt_cwain *cwaintmp, int master, int int_clock) {
     /* PCM reset */
     cwain_outb(cwaintmp,cwain_R_CIRM,0x20);
     cwain_outb(cwaintmp,cwain_R_CIRM,0x0); 
     cwain_waitbusy(cwaintmp);
-
-    for (i=0; i<128; i++) {
-	cwain_outb(cwaintmp,cwain_R_SLOT, i);
-	cwain_outb(cwaintmp,cwain_A_SL_CFG, 0x0);
-    }
+    
+    if (master) {
+	cwain_outb(cwaintmp,cwain_R_PCM_MD0, 0x91);
+        cwain_outb(cwaintmp,cwain_R_PCM_MD1, 0x20);
+	if (int_clock) {
+	    cwain_outb(cwaintmp,cwain_R_PCM_MD0, 0xA1);
+    	    cwain_outb(cwaintmp,cwain_R_PCM_MD2, 0x04);
+	} else {
+	    cwain_outb(cwaintmp,cwain_R_PCM_MD0, 0xA1);
+    	    cwain_outb(cwaintmp,cwain_R_PCM_MD2, 0x00);
+	}
+    } else {
+    	cwain_outb(cwaintmp,cwain_R_PCM_MD0, 0x90);
+	cwain_outb(cwaintmp,cwain_R_PCM_MD1, 0x20);
+    }
+}
+
+void cwain_reset_span(struct zt_cwain *cwaintmp) {
+
+    pci_write_config_word(cwaintmp->pcidev, PCI_COMMAND, PCI_COMMAND_MEMORY | PCI_COMMAND_IO);	// enable memio
+
+    cwain_reset_pcm(cwaintmp,0,0);
     
     /* E1 reset */
     cwain_outb(cwaintmp,cwain_R_CIRM,0x40);
     cwain_outb(cwaintmp,cwain_R_CIRM,0x0); 
     cwain_waitbusy(cwaintmp);
 
+    /* soft reset */
+    cwain_outb(cwaintmp,cwain_R_CIRM,0x10);
+    cwain_outb(cwaintmp,cwain_R_CIRM,0x0); 
+    cwain_waitbusy(cwaintmp);
+
     /* 128 byte B chans, 4096 byte D chans */
-    cwain_outb(cwaintmp,cwain_R_FIFO_MD,0x36);
+    if (hdlcnet) {
+	cwain_outb(cwaintmp,cwain_R_FIFO_MD,0x3E);
+    } else {
+	cwain_outb(cwaintmp,cwain_R_FIFO_MD,0x36);
+    }
+
+
     cwain_outb(cwaintmp,cwain_R_BRG_PCM_CFG,0x0); 
     cwain_outb(cwaintmp,cwain_R_CTRL,0x0); 
 
@@ -324,74 +350,32 @@
     return 0;
 }
 
-static int cwain_dfifo_tx(struct zt_cwain *cwaintmp) {
-    int chan = 15;
-    int x=0;
-    char fifo = 0;
-
-    fifo = 0x1F;
-
-    if (cwaintmp->chans[chan].bytes2transmit < 1) {
-	return 0;
-    } else {
-	/* select fifo */
-	cwain_outb(cwaintmp,cwain_R_FIFO,fifo << 1);    
-	cwain_waitbusy(cwaintmp);
-    
-	if (debug)
-	    printk(KERN_INFO "cwain: card %d TX [ ", cwaintmp->cardno);
-	/* copy frame to fifo */
-    	for (x=0;x<cwaintmp->chans[chan].bytes2transmit;x++) {
-	    if (debug)
-	        printk("%#x ",cwaintmp->dtxbuf[x]);
-    	    cwain_outb(cwaintmp,cwain_A_FIFO_DATA0,cwaintmp->dtxbuf[x]);
-	}
-	if (debug)
-	    printk("]\n");
-	if (debug)
-    	    printk(KERN_INFO "ztx %d bytes\n",cwaintmp->chans[chan].bytes2transmit);
-
-	if (cwaintmp->chans[chan].eoftx == 1) {
-	    /* transmit HDLC frame */
-    	    cwain_outb(cwaintmp,cwain_R_INC_RES_FIFO,0x1);    
-    	    cwain_waitbusy(cwaintmp);
-	}
-    }
-    return 0;
-}
-
-static int cwain_fifo_tx(struct zt_cwain *cwaintmp, char fifo) {
-    int chan,f;
-    if (fifo >= 15) {
-	chan = fifo;
-    } else {
-	chan = fifo;
-    }
-    /* select fifo */
-    cwain_outb(cwaintmp,cwain_R_FIFO,0x80 | (fifo << 1));    
-    cwain_waitbusy(cwaintmp);
-    
-    for (f=0; f < (cwain_FRAME_SIZE/4); f++) {
-	cwain_outdw(cwaintmp,cwain_A_FIFO_DATA0,*((unsigned int *) &cwaintmp->ftxbuf[chan][f * 4]));
-    }
-    return 0;
-}
-
-static int cwain_dfifo_rx(struct zt_cwain *cwaintmp) {
-    int chan = 15;
-    unsigned char f1=1,f2=1,data,stat;
-    unsigned char of1=0,of2=0;
-    int len,i;
+static void cwain_dfifo_check(struct zt_cwain *cwaintmp) {
     unsigned short z1=1,z2=1;
     unsigned short oz1=0,oz2=0;
-    char fifo = 0;
-
-    fifo = 0x1F;
-    
-    /* select fifo */
-    cwain_outb(cwaintmp,cwain_R_FIFO,(fifo << 1) | 1);    
+    unsigned char f1=1,f2=1;
+    unsigned char of1=0,of2=0;
+    int space = 0;
+    int len;
+    int chan;
+    int fifo = 0x1f;
+    unsigned long flags;
+    int frames = 0;
+
+    if (hdlcnet) {
+	chan = 0;
+    } else {
+	chan = 15;
+    }
+    
+
+    /* calculate how much data we can allow zaptel to transmit */
+    spin_lock_irqsave(&cwaintmp->lock,flags);
+    /* select tx fifo */
+
+    cwain_outb(cwaintmp,cwain_R_FIFO, fifo << 1);    
     cwain_waitbusy(cwaintmp);
-    
+
     while ((oz1 != z1) && (oz2 != z2)) {
         oz1 = z1;
         oz2 = z2;
@@ -403,6 +387,19 @@
     if (len < 0) {
         len += cwain_DFIFO_SIZE;
     }
+    space = cwain_DFIFO_SIZE - len;
+
+    if (((debug > 2) && (space < cwain_DFIFO_SIZE)) || (space == 0)) {
+        printk(KERN_INFO "cwain: card %d TX fifo %d space now %d\n", cwaintmp->cardno, fifo, space);
+    }    
+    cwaintmp->chans[chan].maxbytes2transmit = space;
+
+
+    /* calculate how many frames are in the receive fifo */
+
+    /* select rx fifo */
+    cwain_outb(cwaintmp,cwain_R_FIFO,(fifo << 1) | 1);    
+    cwain_waitbusy(cwaintmp);
 
     while ((of1 != f1) && (of2 != f2)) {
         of1 = f1;
@@ -411,18 +408,144 @@
         f2 = cwain_inb(cwaintmp,cwain_A_F2) & 0xf;
     }
 
+    frames = f1 - f2;
+    if (frames < 0) {
+	frames += cwain_DFIFO_FRAMES;
+    }
+    cwaintmp->drx = frames;
+
+    spin_unlock_irqrestore(&cwaintmp->lock,flags);
+
+    if ((frames > 0) && (debug > 3))
+	printk(KERN_INFO "\ncwain: %d frames in RX fifo\n", frames);
+}
+
+static int cwain_dfifo_tx(struct zt_cwain *cwaintmp) {
+    int chan;
+    int x=0;
+    char fifo = 0;
+    unsigned long flags = 0;
+    
+    fifo = 0x1F;
+
+    if (hdlcnet) {
+	chan = 0;
+    } else {
+	chan = 15;
+    }
+
+    if (cwaintmp->chans[chan].bytes2transmit < 1) {
+	return 0;
+    } else {
+	spin_lock_irqsave(&cwaintmp->lock,flags);
+	/* select fifo */
+	cwain_outb(cwaintmp,cwain_R_FIFO,fifo << 1);    
+	cwain_waitbusy(cwaintmp);
+
+	if (((debug > 3 ) && hdlcnet) || ((!hdlcnet) && (debug > 3)))
+	    printk(KERN_INFO "cwain: card %d TX [ ", cwaintmp->cardno);
+	/* copy frame to fifo */
+    	for (x=0;x<cwaintmp->chans[chan].bytes2transmit;x++) {
+	    if (((debug > 3 ) && hdlcnet) || ((!hdlcnet) && (debug > 3)))
+	        printk("%#x ",cwaintmp->dtxbuf[x]);
+    	    cwain_outb(cwaintmp,cwain_A_FIFO_DATA0,cwaintmp->dtxbuf[x]);
+	}
+	if (((debug > 3 ) && hdlcnet) || ((!hdlcnet) && (debug > 3)))
+	    printk("]\n");
+	if (((debug > 2 ) && hdlcnet) || ((!hdlcnet) && (debug > 3)))
+    	    printk(KERN_INFO "ztx %d bytes\n",cwaintmp->chans[chan].bytes2transmit);
+
+	if (cwaintmp->chans[chan].eoftx == 1) {
+	    /* transmit HDLC frame */
+    	    cwain_outb(cwaintmp,cwain_R_INC_RES_FIFO,0x1);    
+    	    cwain_waitbusy(cwaintmp);
+	    if ((debug > 3 ) && hdlcnet)
+    		printk(KERN_INFO "cwain: TX flag\n");
+	}
+	spin_unlock_irqrestore(&cwaintmp->lock,flags);
+    }
+    return 0;
+}
+
+static int cwain_fifo_tx(struct zt_cwain *cwaintmp, char fifo) {
+    int chan,f;
+    unsigned long flags = 0;
+
+    if (hw_hdlc) {
+	if (fifo <= 14) {
+	    chan = fifo;
+	} else {
+	    chan = fifo + 1;
+	}
+    } else {
+	chan = fifo;
+    }
+
+    if (dacs && (cwaintmp->ts_rx[chan] > -1)) {
+	/* dont transmit when we receive from the pcm bus */
+	return 0;
+    }
+
+    spin_lock_irqsave(&cwaintmp->lock,flags);
+	/* select fifo */
+	cwain_outb(cwaintmp,cwain_R_FIFO,0x80 | (fifo << 1));    
+	cwain_waitbusy(cwaintmp);
+    
+	for (f=0; f < (cwain_FRAME_SIZE/4); f++) {
+	    cwain_outdw(cwaintmp,cwain_A_FIFO_DATA0,*((unsigned int *) &cwaintmp->ftxbuf[chan][f * 4]));
+	}
+    spin_unlock_irqrestore(&cwaintmp->lock,flags);
+    return 0;
+}
+
+static int cwain_dfifo_rx(struct zt_cwain *cwaintmp) {
+    int chan;
+    unsigned char data,stat;
+    int len,i = 0;
+    unsigned short z1=1,z2=1;
+    unsigned short oz1=0,oz2=0;
+    char fifo = 0;
+    unsigned long flags = 0;
+
+    fifo = 0x1F;
+    if (hdlcnet) {
+	chan = 0;
+    } else {
+	chan = 15;
+    }
+    
+    spin_lock_irqsave(&cwaintmp->lock,flags);
+    /* select fifo */
+    cwain_outb(cwaintmp,cwain_R_FIFO,(fifo << 1) | 1);    
+    cwain_waitbusy(cwaintmp);
+    
+    while ((oz1 != z1) && (oz2 != z2)) {
+        oz1 = z1;
+        oz2 = z2;
+    	z1 = cwain_inw(cwaintmp,cwain_A_Z1) & 0xfff;
+	z2 = cwain_inw(cwaintmp,cwain_A_Z2) & 0xfff;
+    }
+    
+    len = z1-(z2 & 0xfff);
+    if (len < 0) {
+        len += cwain_DFIFO_SIZE;
+    }
+
     if (len > cwain_DFIFO_SIZE) {
 	printk(KERN_INFO "\ncwain: buffer overflow in D channel RX!\n");
 	cwaintmp->chans[chan].bytes2receive = 0;
 	cwaintmp->chans[chan].eofrx = 0;
     } else {
-	if (debug) printk(KERN_INFO "cwain: card %d RX [ ", cwaintmp->cardno);
+	if ((((debug > 3 ) && hdlcnet) || ((!hdlcnet) && (debug > 3))) && (cwaintmp->sync))
+	    printk(KERN_INFO "cwain: card %d RX [ ", cwaintmp->cardno);
 	for (i=0; i<len; i++) {
     	    data = cwain_inb(cwaintmp,cwain_A_FIFO_DATA0);
 	    cwaintmp->drxbuf[i] = data;
-	    if (debug) printk("%#x ",data);
-	}
-	if (debug) printk("] %d bytes\n", i);
+	    if ((((debug > 3 ) && hdlcnet) || ((!hdlcnet) && (debug > 3))) && (cwaintmp->sync))
+		printk("%#x ",data);
+	}
+	if ((((debug > 3 ) && hdlcnet) || ((!hdlcnet) && (debug > 3))) && (cwaintmp->sync))
+	    printk("] %d bytes\n", i);
 	cwaintmp->chans[chan].bytes2receive = i;
 	cwaintmp->chans[chan].eofrx = 1;
     }
@@ -431,34 +554,52 @@
     if (stat != 0x0) {
 	// bad CRC, skip it
 	if (cwaintmp->sync) {
-	    printk(KERN_INFO "cwain: BAD CRC for hdlc frame on card %d (cardID %d) stat %#x\n",cwaintmp->cardno, cwaintmp->cardID, stat);
+	    printk(KERN_INFO "cwain: BAD CRC for hdlc frame on card %d (cardID %d) stat %#x len %d\n",cwaintmp->cardno, cwaintmp->cardID, stat, i);
 	}
 	cwaintmp->chans[chan].bytes2receive = 0;
 	cwaintmp->chans[chan].eofrx = 0;
-//	    zt_qevent_nolock(&cwaintmp->spans[stport].chans[chan], ZT_EVENT_BADFCS);
+//	zt_qevent_nolock(&cwaintmp->chans[chan], ZT_EVENT_BADFCS);
     }
     cwain_outb(cwaintmp,cwain_R_INC_RES_FIFO,0x1);    
     cwain_waitbusy(cwaintmp);
 
     /* frame received */
     cwaintmp->drx--;
-    return 0;
-}
-
+    if (!cwaintmp->sync) {
+	cwaintmp->chans[chan].bytes2receive = 0;
+	cwaintmp->chans[chan].eofrx = 0;
+	stat = 0xff;
+    }
+    spin_unlock_irqrestore(&cwaintmp->lock,flags);
+    if (stat == 0) {
+	return 1;
+    } else {
+	return 0;
+    }
+}
 
 static int cwain_fifo_rx(struct zt_cwain *cwaintmp, char fifo) {
     int chan;
     unsigned int data;
-    int len,i,f,flen = 0;
+    int len = 0,i,f,flen = 0;
     unsigned short z1=1,z2=1;
     unsigned short oz1=0,oz2=0;
     int mumbojumbo=0;
+    unsigned long flags = 0;
     int x = 1000;
 
-    chan = fifo;
+    if (hw_hdlc) {
+	if (fifo <= 14) {
+	    chan = fifo;
+	} else {
+	    chan = fifo + 1;
+	}
+    } else {
+	chan = fifo;
+    }
 
     // select rx fifo
-    
+    spin_lock_irqsave(&cwaintmp->lock,flags);
 	// no hdlc, transparent data
 	cwain_outb(cwaintmp,cwain_R_FIFO,0x80 | (fifo << 1) | 1);    
         cwain_waitbusy(cwaintmp);
@@ -491,8 +632,9 @@
 	if (len < cwain_FRAME_SIZE) {
 	    /* dont get nervous here */
 	    if ((cwaintmp->clicks > 600) && (cwaintmp->span.alarms == ZT_ALARM_NONE)) {
-		printk(KERN_INFO "cwain: not enough to receive (%d bytes)\n",len);
-	    }
+		printk(KERN_INFO "cwain: cardID %d not enough to receive (%d bytes), fifo %d\n",cwaintmp->cardID, len, fifo);
+	    }
+	    spin_unlock_irqrestore(&cwaintmp->lock,flags);
 	    return 0;
 	} else {
 	    for (f=0;f<(cwain_FRAME_SIZE / 4);f++) {
@@ -502,61 +644,59 @@
 
 
 	/* dont get nervous here */
-	if ((cwaintmp->clicks > 500) && (cwaintmp->span.alarms == ZT_ALARM_NONE)) {
+	if (((cwaintmp->clicks > 50) || (debug > 3)) && ((cwaintmp->span.alarms == ZT_ALARM_NONE) && (mumbojumbo > 0))) {
 	    printk(KERN_INFO "cwain: span %d dropped audio fifo %d mj %d flen %d z1 %d z2 %d\n", cwaintmp->cardID, fifo, mumbojumbo, flen, z1, z2);
 	    cwaintmp->clicks = 0;
 	}
 //    printk(KERN_INFO "s/t port %d, channel %d, dbufi=%d, f1=%d, f2=%d, z1=%d, z2=%d  => len = %d stat=%#x, hdlc=%d\n",stport,chan,cwaintmp->st[stport].dbufi,f1,f2,z1,z2,len,stat,hdlc);    
+    spin_unlock_irqrestore(&cwaintmp->lock,flags);
     return 0;
 }
 
 void cwain_set_master(struct zt_cwain_card *cwaintmp, int span) {
     int i=0;
+    unsigned long flags = 0;
 
     if (cwaintmp->syncsrc == span) return;
     
+    spin_lock_irqsave(&cwaintmp->lock,flags);
+    /* disable the old master */
+    for (i=0; i < cwaintmp->spans; i++) {
+	if (cwaintmp->master[i]) {
+	    /* enable PCM slave mode, PCM128 */
+	    cwain_reset_pcm(cwaintmp->span[i],0,0);
+	    cwaintmp->master[i] = 0;
+	}
+    }
+
+    /* enable the new master */
+    if (cwaintmp->syncs[span] > 0) {
+        /* enable PCM master mode, PCM128, synced to E1 receive */
+	cwain_reset_pcm(cwaintmp->span[span],1,0);
+	if (debug)
+	    printk(KERN_INFO "cwain: cardID %d span %d, PCM master E1 sync\n", cwaintmp->cardID, span);
+    } else {
+        /* enable PCM master mode, PCM128, free running */
+	cwain_reset_pcm(cwaintmp->span[span],1,1);
+	if (debug)
+	    printk(KERN_INFO "cwain: cardID %d span %d, PCM master internal clock\n", cwaintmp->cardID, span);
+    }
+
+    /* reset the slaves */
     for (i=0; i < cwaintmp->spans; i++) {
 	if (i != span) {
-	    if (cwaintmp->syncs[i] > 0) {
-		/* enable PCM slave mode, PCM32, synced to E1 receive */
-    		cwain_outb(cwaintmp->span[i],cwain_R_PCM_MD0, 0x90);
-		cwain_outb(cwaintmp->span[i],cwain_R_PCM_MD1, 0x0);
-		cwain_outb(cwaintmp->span[span],cwain_R_PCM_MD0, 0xA0);
-		cwain_outb(cwaintmp->span[i],cwain_R_PCM_MD2, 0x00);
-	    } else {
-		/* enable PCM slave mode, PCM32 */
-    		cwain_outb(cwaintmp->span[i],cwain_R_PCM_MD0, 0x90);
-		cwain_outb(cwaintmp->span[i],cwain_R_PCM_MD1, 0x0);
-		cwain_outb(cwaintmp->span[span],cwain_R_PCM_MD0, 0xA0);
-		cwain_outb(cwaintmp->span[i],cwain_R_PCM_MD2, 0x00);
-	    }
+	    /* enable PCM slave mode, PCM128 */
+	    cwain_reset_pcm(cwaintmp->span[i],0,0);
 	    cwaintmp->master[i] = 0;
-	    cwaintmp->span[i]->span.syncsrc = 0;
-	}
-    }
-
-    if (cwaintmp->syncs[span] > 0) {
-        /* enable PCM master mode, PCM32, synced to E1 receive */
-	if (debug)
-	    printk(KERN_INFO "cwain: cardID %d span %d, PCM master E1 sync\n", cwaintmp->cardID, span);
-	cwain_outb(cwaintmp->span[span],cwain_R_PCM_MD0, 0x91);
-        cwain_outb(cwaintmp->span[span],cwain_R_PCM_MD1, 0x0);
-	cwain_outb(cwaintmp->span[span],cwain_R_PCM_MD0, 0xA1);
-        cwain_outb(cwaintmp->span[span],cwain_R_PCM_MD2, 0x00);
-	cwaintmp->span[span]->span.syncsrc = 1;
-    } else {
-        /* enable PCM master mode, PCM32, free running */
-	if (debug)
-	    printk(KERN_INFO "cwain: cardID %d span %d, PCM master\n", cwaintmp->cardID, span);
-	cwain_outb(cwaintmp->span[span],cwain_R_PCM_MD0, 0x91);
-        cwain_outb(cwaintmp->span[span],cwain_R_PCM_MD1, 0x0);
-	cwain_outb(cwaintmp->span[span],cwain_R_PCM_MD0, 0xA1);
-        cwain_outb(cwaintmp->span[span],cwain_R_PCM_MD2, 0x04);
-	cwaintmp->span[span]->span.syncsrc = 0;
+	}
     }
     
     cwaintmp->master[span] = 1;
     cwaintmp->syncsrc = span;
+
+    /* restore pcm assignments !!! */
+
+    spin_unlock_irqrestore(&cwaintmp->lock,flags);
 }
 
 void cwain_check_timing(struct zt_cwain_card *cwaintmp) {
@@ -602,8 +742,8 @@
 	}
     }
 
-    /* if reelection failed, find internal sync source */
-    if (cwaintmp->syncsrc == -1) {
+    /* if reelection failed, find internal sync source, if not forbidden! */
+    if ((cwaintmp->syncsrc == -1) && !require_ext_clock) {
 	/* no master yet */
 	if (debug > 3)
 	    printk(KERN_INFO "cwain: no clocksource found cardID %d\n", cwaintmp->cardID);
@@ -634,42 +774,294 @@
     }
 }
 
+
+static void cwain_assign(struct zt_cwain_card *cwaincard, int src_span, int src_chan, int dst_span, int dst_chan, int timeslot, int use_pcm_bus) {
+    int dst_fifo = dst_chan - 1; 
+    int src_fifo = src_chan - 1; 
+    int src_hfc_chan = src_chan;
+    int dst_hfc_chan = dst_chan;
+    struct zt_cwain *cwain_src = NULL, *cwain_dst = NULL;
+    unsigned long flags = 0;
+    /*  hw_hdlc == 1
+	fifo    00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 >< 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
+	time 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
+	chan    00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
+
+	 hw_hdlc == 0
+	fifo    00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
+	time 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
+	chan    00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
+    */
+
+    if (hw_hdlc) {
+	if (dst_chan > 0x10) {
+	    dst_fifo--; 
+	}
+	if (src_chan > 0x10) {
+	    src_fifo--; 
+	}
+    }
+
+    if (cwaincard) {
+	cwain_src = cwaincard->span[src_span];
+	cwain_dst = cwaincard->span[dst_span];
+    } else {
+	return;
+    }
+    
+    if (debug)
+	printk(KERN_INFO "cwain: assign(src_span %d (ID %d), src_chan %d, dst_span %d (ID %d), dst_chan %d, use_pcm_bus %d, timeslot %d\n", src_span, cwain_src->cardID, src_chan, dst_span, cwain_dst->cardID, dst_chan, use_pcm_bus, timeslot);
+    
+    spin_lock_irqsave(&cwaincard->lock,flags);
+
+	/* assign the data received from the hfc-channel "src_hfc_chan" to transmit pcm slot "timeslot" on pin STIO1 */
+	/* TX up */
+	cwain_outb(cwain_src,cwain_R_FIFO, src_fifo << 1); 
+        cwain_waitbusy(cwain_src);
+	cwain_outb(cwain_src,cwain_R_INC_RES_FIFO,0x2);
+        cwain_waitbusy(cwain_src);
+        cwain_outb(cwain_src,cwain_A_CON_HDLC,0xC2);
+        cwain_outb(cwain_src,cwain_A_CHANNEL,src_hfc_chan << 1); 
+
+        cwain_outb(cwain_src,cwain_R_SLOT,timeslot << 1);
+	if (use_pcm_bus) {
+	    cwain_outb(cwain_src,cwain_A_SL_CFG, (src_hfc_chan << 1) | 0 | 0x80);
+	} else {
+	    cwain_outb(cwain_src,cwain_A_SL_CFG, (src_hfc_chan << 1) | 0 | 0x40);
+	}
+        cwain_src->ts_tx[src_chan - 1] = timeslot;
+
+	/* assign the data received from the receive pcm slot "timeslot" on pin STIO1 to the hfc-channel "dst_hfc_chan"*/
+	/* RX down */ 
+	cwain_outb(cwain_dst,cwain_R_FIFO, (dst_fifo << 1) | 1);
+        cwain_waitbusy(cwain_dst);
+	cwain_outb(cwain_dst,cwain_R_INC_RES_FIFO,0x2);
+        cwain_waitbusy(cwain_dst);
+        cwain_outb(cwain_dst,cwain_A_CHANNEL,(dst_hfc_chan << 1) | 1);
+        cwain_outb(cwain_dst,cwain_A_CON_HDLC,0xC2);
+    
+        cwain_outb(cwain_dst,cwain_R_SLOT,(timeslot << 1) | 1); 
+        if (use_pcm_bus) {
+    	    cwain_outb(cwain_dst,cwain_A_SL_CFG, (dst_hfc_chan << 1) | 1 | 0xC0);
+	} else {
+	    cwain_outb(cwain_dst,cwain_A_SL_CFG, (dst_hfc_chan << 1) | 1 | 0x40);
+	}
+        cwain_dst->ts_rx[dst_chan - 1] = timeslot;
+// printk(KERN_INFO "cwain: span %d ts_tx[%d] = %d\n", src_span, src_chan - 1, timeslot);
+// printk(KERN_INFO "cwain: span %d ts_rx[%d] = %d\n", dst_span, dst_chan - 1, timeslot);
+
+    spin_unlock_irqrestore(&cwaincard->lock,flags);
+}
+
+static void cwain_unassign(struct zt_cwain *cwaintmp, int chan, int timeslot, int lock) {
+    int fifo = chan - 1;
+    int hfc_chan = chan;
+    unsigned long flags = 0;
+
+    if (hw_hdlc && (chan > 0x10)) {
+	fifo--; 
+    }
+
+    if (lock) spin_lock_irqsave(&cwaintmp->lock,flags);
+
+	/* unassign from_where we receive and to_where we transmit */
+	
+
+	/* we were transmitting on cwaintmp->ts_tx[chan - 1] */
+        cwain_outb(cwaintmp,cwain_R_SLOT, cwaintmp->ts_tx[chan - 1] << 1); 
+	cwain_outb(cwaintmp,cwain_A_SL_CFG, 0x0);
+        cwaintmp->ts_tx[chan - 1] = -1;
+
+	/* we were receiving on cwaintmp->ts_rx[chan - 1] */
+        cwain_outb(cwaintmp,cwain_R_SLOT, (cwaintmp->ts_rx[chan - 1] << 1) | 1); 
+	cwain_outb(cwaintmp,cwain_A_SL_CFG, 0x0);
+        cwaintmp->ts_rx[chan - 1] = -1;
+
+	/* restore our tx fifo */
+	cwain_outb(cwaintmp,cwain_R_FIFO,fifo << 1);
+	cwain_waitbusy(cwaintmp);
+	cwain_outb(cwaintmp,cwain_R_INC_RES_FIFO,0x2);
+	cwain_waitbusy(cwaintmp);
+	cwain_outb(cwaintmp,cwain_A_CON_HDLC,0x2);
+	cwain_outb(cwaintmp,cwain_A_CHANNEL,hfc_chan  << 1);
+	cwain_outb(cwaintmp,cwain_A_IRQ_MSK,0x0);
+
+	/* restore our rx fifo */
+	cwain_outb(cwaintmp,cwain_R_FIFO,(fifo << 1) | 1);
+	cwain_waitbusy(cwaintmp);
+	cwain_outb(cwaintmp,cwain_R_INC_RES_FIFO,0x2);
+	cwain_waitbusy(cwaintmp);
+	cwain_outb(cwaintmp,cwain_A_CON_HDLC,0x2);
+	cwain_outb(cwaintmp,cwain_A_CHANNEL,(hfc_chan << 1) | 1);
+	cwain_outb(cwaintmp,cwain_A_IRQ_MSK,0x0);
+	
+//  printk(KERN_INFO "cwain: ts_tx[%d] = %d\n", chan - 1, -1);
+// printk(KERN_INFO "cwain: ts_rx[%d] = %d\n", chan - 1, -1);
+    if (lock) spin_unlock_irqrestore(&cwaintmp->lock,flags);
+}
+
+
+static int ztcwain_dacs(struct zt_chan *dst, struct zt_chan *src) {
+	struct zt_cwain *cwaintmp = NULL;
+	int use_pcm_bus = 0;
+	int timeslot = 0;
+	if (hdlcnet) return -1;
+	if (!dacs) return -1;
+
+	if (src) {
+		cwaintmp = src->pvt;
+
+		if ((src->pvt != dst->pvt) && (src->span->pvt != dst->span->pvt)) {
+		    if (dacs == 2) {
+			if (debug)
+			    printk("cwain: Assigning %d/%d -> %d/%d, different cards!\n", src->span->offset, src->chanpos, dst->span->offset, dst->chanpos);
+			timeslot = src->channo;
+			use_pcm_bus = 1;
+		    } else {
+			if (debug)
+			    printk("cwain: Not Assigning %d/%d -> %d/%d, different cards!\n", src->span->offset, src->chanpos, dst->span->offset, dst->chanpos);
+			return -1;
+		    }
+		} else {
+		    if (debug)
+			printk("cwain: Assigning %d/%d -> %d/%d, same cwain card!\n", src->span->offset, src->chanpos, dst->span->offset, dst->chanpos);
+			timeslot = src->channo;
+/*		    if (dacs == 2) {
+			timeslot = src->channo;
+		    } else {
+			timeslot = (src->span->offset * 30) + (src->chanpos - 1);
+		    } */
+		    if (src->span == dst->span) {
+			use_pcm_bus = 0;
+		    } else {
+			use_pcm_bus = 1;
+		    }
+		}
+	
+		if (hw_hdlc && ((src->chanpos == 16) || (dst->chanpos == 16))) {
+		    if (debug)
+			printk("cwain: Not Assigning D-channel %d/%d -> %d/%d!\n", src->span->offset, src->chanpos, dst->span->offset, dst->chanpos);
+		} else {
+		    cwain_assign(src->span->pvt, src->span->offset, src->chanpos, dst->span->offset, dst->chanpos, timeslot, use_pcm_bus);
+		    if (debug)
+			printk("cwain: Assigning channel %d/%d -> %d/%d!\n", src->span->offset, src->chanpos, dst->span->offset, dst->chanpos);
+		}
+	} else {
+		cwaintmp = dst->pvt;
+		if (hw_hdlc && (dst->chanpos == 16)) {
+		    if (debug)
+			printk("cwain: Not Unassigning D-channel %d/%d!\n", dst->span->offset, dst->chanpos);
+		} else {
+			timeslot = dst->channo;
+/*		    if (dacs == 2) {
+			timeslot = dst->channo;
+		    } else {
+			timeslot = (dst->span->offset * 30) + (dst->chanpos - 1);
+		    } */
+//	    printk(KERN_INFO "cwain: unassing chan %d ts_rx %d ts_tx %d ?\n", dst->chanpos - 1, cwaintmp->ts_rx[dst->chanpos - 1], cwaintmp->ts_tx[dst->chanpos - 1]);
+		    if ((cwaintmp->ts_rx[dst->chanpos - 1] > -1) || (cwaintmp->ts_tx[dst->chanpos - 1] > -1)) {
+		        cwain_unassign(cwaintmp, dst->chanpos, timeslot, 1);
+			if (debug)
+			    printk("cwain: Unassigning channel %d/%d!\n", dst->span->offset, dst->chanpos);
+		    }
+		}
+	}
+	return 0;
+}
+
 static inline void cwain_isr_run(struct zt_cwain *cwaintmp, int ticks) {
-    int fifo=0;
+    int dchan;
+    int chan = 0;
+
     if (cwaintmp->span.flags & ZT_FLAG_RUNNING) {
+
+	if (hdlcnet) {
+	    dchan = 0;
+	} else {
+	    dchan = 15;
+	}
+	cwaintmp->chans[dchan].bytes2transmit = 0;
+	cwaintmp->chans[dchan].eoftx = 0;
+	if (hw_hdlc) {
+	    cwain_dfifo_check(cwaintmp);
+	}
+
         /* oh zaptel! tell us what to transmit... */
         zt_transmit(&cwaintmp->span);
-	/* B chans 1-15 mapped to fifos 0-14 */
-	/* B chans 17-31 mapped to fifos 15-29 */
-	for (fifo=0; fifo < 30; fifo++) {
-	    /* copy to fbuffer */
-	    if ((ticks < 1) || (ticks > 8)) {
-		printk(KERN_INFO "cwain: whicked ticks make whicked tricks (%d)\n",cwaintmp->ticks);
+
+	if (hdlcnet) {
+
+	        if (cwaintmp->sync) {
+		    cwain_dfifo_tx(cwaintmp);
+		}
+
+		/* d-chan data */
+		while (cwaintmp->drx > 0) {
+		    cwaintmp->chans[dchan].bytes2receive = 0;
+		    cwaintmp->chans[dchan].eofrx = 0;
+		    if (debug > 3)
+		        printk(KERN_CRIT "drx = %d\n", cwaintmp->drx);
+		    if (cwain_dfifo_rx(cwaintmp)) {
+			zt_receive(&(cwaintmp->span)); // XXX
+		    }
+		}
+		cwaintmp->chans[dchan].bytes2receive = 0;
+		cwaintmp->chans[dchan].eofrx = 0;
+	} else {
+	    if (hw_hdlc) {
+		/* B chans 1-15 mapped to fifos 0-14 */
+	        /* B chans 17-31 mapped to fifos 15-29 */
+		for (chan=0; chan < 31; chan++) {
+		    /* copy to fbuffer */
+	    	    if ((ticks < 1) || (ticks > 8)) {
+			printk(KERN_INFO "cwain: whicked ticks make whicked tricks (%d)\n",cwaintmp->ticks);
+		    } else {
+			if (chan != dchan) {
+			    memcpy(&cwaintmp->ftxbuf[chan][(ticks-1)*8], cwaintmp->txbuf[chan], ZT_CHUNKSIZE);
+			}
+		    }
+		}
+	
+	        if (cwaintmp->sync) {
+		    cwain_dfifo_tx(cwaintmp);
+		}
+
+    		cwaintmp->chans[dchan].bytes2receive = 0;
+		cwaintmp->chans[dchan].bytes2transmit = 0;
+		cwaintmp->chans[dchan].eofrx = 0;
+		cwaintmp->chans[dchan].eoftx = 0;
+
+		for (chan=0; chan < 31; chan++) {
+		    /* copy from fbuffer */
+		    if (chan != dchan) {
+			memcpy(cwaintmp->rxbuf[chan], &cwaintmp->frxbuf[chan][(ticks-1)*8], ZT_CHUNKSIZE);
+		        zt_ec_chunk(&cwaintmp->span.chans[chan], cwaintmp->span.chans[chan].readchunk, cwaintmp->span.chans[chan].writechunk);
+		    }
+		}
+
+		/* d-chan data */
+		if (cwaintmp->drx > 0) {
+		    if (debug > 3)
+			printk(KERN_CRIT "drx = %d\n", cwaintmp->drx);
+		    cwain_dfifo_rx(cwaintmp);
+		}
 	    } else {
-		memcpy(&cwaintmp->ftxbuf[fifo][(ticks-1)*8], cwaintmp->txbuf[fifo], ZT_CHUNKSIZE);
-	    }
-
-	}
-	if (cwaintmp->sync) {
-	    cwain_dfifo_tx(cwaintmp);
-	}
-
-        cwaintmp->chans[15].bytes2receive = 0;
-	cwaintmp->chans[15].bytes2transmit = 0;
-	cwaintmp->chans[15].eofrx = 0;
-	cwaintmp->chans[15].eoftx = 0;
-
-	for (fifo=0; fifo < 30; fifo++) {
-	    /* copy from fbuffer */
-	    memcpy(cwaintmp->rxbuf[fifo], &cwaintmp->frxbuf[fifo][(ticks-1)*8], ZT_CHUNKSIZE);
-	    zt_ec_chunk(&cwaintmp->span.chans[fifo], cwaintmp->span.chans[fifo].readchunk, cwaintmp->span.chans[fifo].writechunk);
-	}
-
-	/* d-chan data */
-	if ((cwaintmp->drx > 0) && cwaintmp->sync){
-	    if (debug > 2)
-	    	printk(KERN_CRIT "drx = %d\n", cwaintmp->drx);
-	    cwain_dfifo_rx(cwaintmp);
+		/* software HDLC */
+        	for (chan=0; chan < 31; chan++) {
+        	    /* copy to fbuffer */
+            	    if ((ticks < 1) || (ticks > 8)) {
+                	printk(KERN_INFO "cwain: whicked ticks make whicked tricks (%d)\n",cwaintmp->ticks);
+            	    } else {
+                	memcpy(&cwaintmp->ftxbuf[chan][(ticks-1)*8], cwaintmp->txbuf[chan], ZT_CHUNKSIZE);
+            	    }
+        	}
+
+        	for (chan=0; chan < 31; chan++) {
+            	    /* copy from fbuffer */
+            	    memcpy(cwaintmp->rxbuf[chan], &cwaintmp->frxbuf[chan][(ticks-1)*8], ZT_CHUNKSIZE);
+            	    zt_ec_chunk(&cwaintmp->span.chans[chan], cwaintmp->span.chans[chan].readchunk, cwaintmp->span.chans[chan].writechunk);
+        	}
+	    }
 	}
 	/* oh zaptel! thou shall receive! */
 	zt_receive(&(cwaintmp->span));
@@ -677,27 +1069,48 @@
 }
 
 static inline void cwain_isr_err(struct zt_cwain *cwaintmp) {
+    unsigned long flags = 0;
     unsigned short crc, vio, ebit, fas;
-
+    unsigned short rx_slip, tx_slip;
+
+    spin_lock_irqsave(&cwaintmp->lock,flags);
     crc = (cwain_inb(cwaintmp, cwain_R_CRC_ECH) << 8) | cwain_inb(cwaintmp, cwain_R_CRC_ECL);
     vio = (cwain_inb(cwaintmp, cwain_R_VIO_ECH) << 8) | cwain_inb(cwaintmp, cwain_R_VIO_ECL);
     ebit = (cwain_inb(cwaintmp, cwain_R_E_ECH) << 8) | cwain_inb(cwaintmp, cwain_R_E_ECL);
     fas = (cwain_inb(cwaintmp, cwain_R_FAS_ECH) << 8) | cwain_inb(cwaintmp, cwain_R_FAS_ECL);
-			
+    rx_slip = cwain_inb(cwaintmp, cwain_R_SLIP) & 0x01;
+    tx_slip = (cwain_inb(cwaintmp, cwain_R_SLIP) >> 4) & 0x01;
+    if (cwaintmp->sync) {
+        if (rx_slip) {
+	    cwain_outb(cwaintmp,cwain_R_RX_OFFS,0x06);
+	    if (debug)
+		printk(KERN_INFO "cwain: cardID %d detected RX slip\n", cwaintmp->cardID);
+	}
+	if (tx_slip) {
+	    cwain_outb(cwaintmp,cwain_R_TX_OFFS,0x06);
+	    if (debug)
+    		printk(KERN_INFO "cwain: cardID %d detected TX slip\n", cwaintmp->cardID);
+	}
+    }
+
     cwaintmp->span.crc4count += crc;
     cwaintmp->span.bpvcount += vio;
     cwaintmp->span.ebitcount += ebit;
     cwaintmp->span.fascount += fas;
 			
-    if (debug > 2)
-        printk("cwain: CRC4 %d BPVIOL %d EBIT %d FAS %d\n", crc, vio, ebit, fas);
+    if ((debug > 3) && (crc || vio || ebit || fas)) 
+        printk(KERN_INFO "cwain: CRC4 %d BPVIOL %d EBIT %d FAS %d\n", cwaintmp->span.crc4count, cwaintmp->span.bpvcount, cwaintmp->span.ebitcount, cwaintmp->span.fascount);
+    spin_unlock_irqrestore(&cwaintmp->lock,flags);
 }
 						    		    
 
 static inline void cwain_audio_run(struct zt_cwain *cwaintmp) {
     int fifo=0;
+    if (hdlcnet) return;
+    
+    if (hw_hdlc) {
 	for (fifo=0; fifo < 30; fifo++) {
-	    /* B xmit */
+	    /* B tx */
 	    cwain_fifo_tx(cwaintmp, fifo);
 	}
 
@@ -705,18 +1118,33 @@
 	    /* B rx */
 	    cwain_fifo_rx(cwaintmp, fifo);
 	}
+    } else {
+	/* software HDLC */
+	for (fifo=0; fifo < 31; fifo++) {
+	    /* B tx */
+	    cwain_fifo_tx(cwaintmp, fifo);
+	}
+
+	for (fifo=0; fifo < 31; fifo++) {
+	    /* B rx */
+	    cwain_fifo_rx(cwaintmp, fifo);
+	}
+    }
 }
 
 int cwain_isr_sync(struct zt_cwain *cwainspan) {
     unsigned char sync_sta;
     unsigned char sync_ok = 0;
     unsigned char jatt_sta = 0;
+    unsigned long flags = 0;
+//    int chan = 0;
     int res = 0; /* assume no l1event */
 
     if (!cwainspan->span.flags & ZT_FLAG_RUNNING) {
 	return res;
     }
 
+    spin_lock_irqsave(&cwainspan->lock,flags);
     sync_sta = cwain_inb(cwainspan, cwain_R_SYNC_STA);
 
     if ((!cwainspan->sync) || (sync_sta != cwainspan->sync_sta)) {
@@ -729,11 +1157,11 @@
 		/* reset MFA detection */
 		cwain_outb(cwainspan ,cwain_R_RX_SL0_CFG1,0x41);
 	    } else if ((sync_sta & 0x27) == 0x27) {
-		if ((cwainspan->sync_sta & 0x27) != 0x27) {
+		if (((cwainspan->sync_sta & 0x27) != 0x27) && cwainspan->span.syncsrc) {
 		    /* sync achieved, restart JATT */
-		    if (debug)
-			printk(KERN_INFO "cwain: %d starting jitter attenuator\n", cwainspan->cardID);
-		    cwain_outb(cwainspan, cwain_R_JATT_CFG,0x9c);
+/*		    if (debug)
+			printk(KERN_INFO "cwain: %d starting jitter attenuator\n", cwainspan->cardID); */
+//		    cwain_outb(cwainspan, cwain_R_JATT_CFG,0x9c);
 		}
 		sync_ok = 0x27;
 	    } else {
@@ -741,11 +1169,11 @@
 	    }
 	} else {
 	    if ((sync_sta & 0x07) == 0x07) {
-		if ((cwainspan->sync_sta & 0x7) != 0x7) {
+		if (((cwainspan->sync_sta & 0x7) != 0x7) && cwainspan->span.syncsrc) {
 		    /* sync achieved, restart JATT */
-		    if (debug)
-			printk(KERN_INFO "cwain: %d starting jitter attenuator\n", cwainspan->cardID);
-		    cwain_outb(cwainspan, cwain_R_JATT_CFG,0x9c);
+	/*	    if (debug)
+			printk(KERN_INFO "cwain: %d starting jitter attenuator\n", cwainspan->cardID); */
+//		    cwain_outb(cwainspan, cwain_R_JATT_CFG,0x9c);
 		}
 		sync_ok = 0x07;
 	    } else {
@@ -755,32 +1183,24 @@
 
 	cwainspan->sync_sta = sync_sta;
 
-	jatt_sta = cwain_inb(cwainspan, cwain_R_JATT_STA);
-	if ((jatt_sta & 0x60) != 0x60) {
-	    if (debug > 2)
-		printk(KERN_INFO "cwain: %d jitter attenuator %#x\n", cwainspan->cardID, (jatt_sta & 0x60) >> 5);
-	    sync_ok = 0x00;
-	} else if (!cwainspan->sync && sync_ok) {
+	if (cwainspan->span.syncsrc) {
+	    jatt_sta = cwain_inb(cwainspan, cwain_R_JATT_STA);
+	    if ((jatt_sta & 0x60) != 0x60) {
+		if (debug > 2)
+		    printk(KERN_INFO "cwain: %d jitter attenuator %#x\n", cwainspan->cardID, (jatt_sta & 0x60) >> 5);
+		sync_ok = 0x00;
+	    } else if (!cwainspan->sync && sync_ok) {
+		if (debug)
+		    printk(KERN_CRIT "cwain: %d jitter attenuator %#x ok!\n", cwainspan->cardID, (jatt_sta & 0x60) >> 5);
+	    }
+	}
+
+	if (sync_ok && (!cwainspan->sync)) {
 	    if (debug)
-		printk(KERN_CRIT "cwain: %d jitter attenuator %#x ok!\n", cwainspan->cardID, (jatt_sta & 0x60) >> 5);
-	}
-
-	if (sync_ok && (!cwainspan->sync)) {
-	    /* elastic buffer offsets */
+	        printk(KERN_INFO "cwain: cardID %d link up\n", cwainspan->cardID);
+
 	    cwain_outb(cwainspan,cwain_R_RX_OFFS,0x06);
 	    cwain_outb(cwainspan,cwain_R_TX_OFFS,0x06);
-
-	    if (debug > 2)
-		printk(KERN_INFO "cwain: enabling D channel fifos\n");
-	    cwain_outb(cwainspan,cwain_R_FIFO,0x1F << 1);
-	    cwain_waitbusy(cwainspan);
-	    cwain_outb(cwainspan,cwain_A_CON_HDLC,0xd);
-	    cwain_outb(cwainspan,cwain_A_IRQ_MSK,0x1);
-	
-	    cwain_outb(cwainspan,cwain_R_FIFO,(0x1F << 1) | 1);
-	    cwain_waitbusy(cwainspan);
-	    cwain_outb(cwainspan,cwain_A_CON_HDLC,0xd);
-	    cwain_outb(cwainspan,cwain_A_IRQ_MSK,0x1);
 
 	    cwainspan->span.crc4count = 0;
     	    cwainspan->span.bpvcount = 0;
@@ -791,16 +1211,13 @@
 	    res = 1;
 	}
 	if (!sync_ok && cwainspan->sync) {
-	    if (debug > 2)
-		printk(KERN_INFO "cwain: disabling D channel fifos\n");
-	    cwain_outb(cwainspan,cwain_R_FIFO,0x1F << 1);
-	    cwain_waitbusy(cwainspan);
-	    cwain_outb(cwainspan,cwain_A_CON_HDLC,0x1);
-	    cwain_outb(cwainspan,cwain_A_IRQ_MSK,0x0);
-	    cwain_outb(cwainspan,cwain_R_FIFO,(0x1F << 1) | 1);
-	    cwain_waitbusy(cwainspan);
-	    cwain_outb(cwainspan,cwain_A_CON_HDLC,0x1);
-	    cwain_outb(cwainspan,cwain_A_IRQ_MSK,0x0);
+	    if (debug)
+	        printk(KERN_INFO "cwain: cardID %d link down\n", cwainspan->cardID);
+	    
+	    cwainspan->span.crc4count = 0;
+    	    cwainspan->span.bpvcount = 0;
+	    cwainspan->span.ebitcount = 0;
+    	    cwainspan->span.fascount = 0;
 	    cwainspan->span.alarms = ZT_ALARM_RED;
 	    zt_alarm_notify(&cwainspan->span);
 	    res = 1;
@@ -828,9 +1245,33 @@
 	}
 	cwain_doLEDs(cwainspan);
     }
+    spin_unlock_irqrestore(&cwainspan->lock,flags);
     return res;
 }
 
+static int ztcwain_proc_read(struct zt_span *span, char *output) {
+    struct zt_cwain_card *cwaincard = span->pvt;
+    struct zt_cwain *cwaintmp;
+    unsigned long flags;
+    unsigned char fstate;
+
+    if (cwaincard == NULL) {
+	printk(KERN_CRIT "cwain: cwaincard == NULL!\n");
+	return 0;
+    }
+    cwaintmp = cwaincard->span[span->offset];
+    if (cwaintmp == NULL) {
+	printk(KERN_CRIT "cwain: cwaintmp == NULL!\n");
+	return 0;
+    }
+
+    spin_lock_irqsave(&cwaintmp->lock,flags);
+	fstate = cwain_inb(cwaintmp, cwain_R_E1_RD_STA);
+    spin_unlock_irqrestore(&cwaintmp->lock,flags);
+    return sprintf(output, "cwain: span state = F%d.", fstate & 0x7);
+}
+
+/* called locked */
 int cwain_isr_fifo(struct zt_cwain *cwainspan, unsigned char status) {
     unsigned char irq_foview,fi;
 
@@ -840,9 +1281,12 @@
 	if (irq_foview & 0x80) {
 	    fi = cwain_inb(cwainspan,cwain_R_IRQ_FIFO_BL7);
 	    if (fi & 0x80) {
-		if (debug > 2)
+		if (debug > 4)
 		    printk(KERN_CRIT "cwain: fifo 31 RX irq for D channel cardID %d\n", cwainspan->cardID);
-		cwainspan->drx += 1;		
+	    }
+	    if (fi & 0x40) {
+		if (debug > 4)
+		    printk(KERN_CRIT "cwain: fifo 31 TX irq for D channel cardID %d\n", cwainspan->cardID);
 	    }
 	}
 	return 1;
@@ -870,9 +1314,7 @@
 ZAP_IRQ_HANDLER(cwain_interrupt) {
     struct zt_cwain_card *cwaintmp = dev_id;
     unsigned char status, status2, status_tmp, irq_misc, irq_misc2 = 0;
-#ifndef RELAXED_LOCKING    
     unsigned long flags;
-#endif
     int i = 0;
     int l1event = 0;
     
@@ -884,32 +1326,23 @@
 #endif		
     }
     
-#ifdef RELAXED_LOCKING    
-    spin_lock(&(cwaintmp->lock));
-#else
     spin_lock_irqsave(&(cwaintmp->lock),flags);
-#endif
-    status = cwain_inb(cwaintmp->span[0],cwain_R_STATUS);
-
-    status2 = 0;
-
-    for (i=0;i<cwaintmp->spans;i++) {
-	if (i == 0) {
-	    status_tmp = status;
-	} else {
-	    status_tmp = cwain_inb(cwaintmp->span[i],cwain_R_STATUS);
-	    status2 = status_tmp;
-	}
-	cwain_isr_fifo(cwaintmp->span[i], status_tmp);
-    }
+	status = cwain_inb(cwaintmp->span[0],cwain_R_STATUS);
+	status2 = 0;
+
+	for (i=0;i<cwaintmp->spans;i++) {
+	    if (i == 0) {
+		status_tmp = status;
+	    } else {
+		status_tmp = cwain_inb(cwaintmp->span[i],cwain_R_STATUS);
+		status2 = status_tmp;
+	    }
+	    cwain_isr_fifo(cwaintmp->span[i], status_tmp);
+	}
+    spin_unlock_irqrestore(&(cwaintmp->lock),flags);
 
     if (!(status & 0x80) && !(status & 0x40)) {
 	// it's not us!
-#ifdef RELAXED_LOCKING    
-	spin_unlock(&(cwaintmp->lock));
-#else 
-	spin_unlock_irqrestore(&(cwaintmp->lock),flags);
-#endif
 #ifdef LINUX26
 		return IRQ_NONE;
 #else
@@ -919,7 +1352,9 @@
 
     // misc irq
     if (status & 0x40) {
-	irq_misc = cwain_inb(cwaintmp->span[0],cwain_R_IRQ_MISC);
+	spin_lock_irqsave(&(cwaintmp->lock),flags);
+	    irq_misc = cwain_inb(cwaintmp->span[0],cwain_R_IRQ_MISC);
+	spin_unlock_irqrestore(&(cwaintmp->lock),flags);
 	if (irq_misc & 0x2)  {
 	    /* cwain timer */
 	    cwaintmp->ticks++;
@@ -931,7 +1366,7 @@
 	    for (i=0;i<cwaintmp->spans;i++) {
 		cwain_isr_run(cwaintmp->span[i], cwaintmp->ticks);
 	    }
-	    if (cwaintmp->ticks == (cwain_FRAME_SIZE / 8)) {
+	    if (cwaintmp->ticks == (cwain_FRAME_SIZE / ZT_CHUNKSIZE)) {
 		cwaintmp->ticks = 0;
 	    }
 	} 
@@ -942,6 +1377,9 @@
 	    l1event++;
 	}
 	if (irq_misc & 0x10) {
+	    for (i=0;i<cwaintmp->spans;i++) {
+	        cwain_isr_err(cwaintmp->span[i]);
+	    }
     	    if (l1event == 0) {
 		/* just in case we missed it */
 		for (i=0;i<cwaintmp->spans;i++) {
@@ -954,7 +1392,9 @@
     // misc irq
     if (status2 & 0x40) {
 	if (cwaintmp->spans == 2) {
-	    irq_misc2 = cwain_inb(cwaintmp->span[1],cwain_R_IRQ_MISC);
+	    spin_lock_irqsave(&(cwaintmp->lock),flags);
+		irq_misc2 = cwain_inb(cwaintmp->span[1],cwain_R_IRQ_MISC);
+	    spin_unlock_irqrestore(&(cwaintmp->lock),flags);
 	}
 	if (irq_misc2 & 0x1) {
 	    /* state machine 2 */
@@ -974,11 +1414,6 @@
         }
     }
 
-#ifdef RELAXED_LOCKING    
-    spin_unlock(&(cwaintmp->lock));
-#else
-    spin_unlock_irqrestore(&(cwaintmp->lock),flags);
-#endif
 #ifdef LINUX26
 	return IRQ_RETVAL(1);
 #endif		
@@ -1022,6 +1457,7 @@
     unsigned long flags;
     int alreadyrunning;
     int i=0;
+    int idx = 0;
 
 //    printk(KERN_INFO "cwain: startup spanno %d offset %d\n", span->spanno, span->offset);
 
@@ -1041,31 +1477,55 @@
 //    printk(KERN_CRIT "already running %d flags %d\n", alreadyrunning, span->flags);
 
     if (!alreadyrunning) {
-	span->chans[15].flags &= ~ZT_FLAG_HDLC;
-	span->chans[15].flags |= ZT_FLAG_BRIDCHAN; /* yes! */
-    
-	/* setup B channel buffers (8 bytes each) */
-	for (i=0; i<15 ; i++) {
-	    memset(cwaintmp->rxbuf[i],0x0,sizeof(cwaintmp->rxbuf[i]));
-    	    memset(cwaintmp->txbuf[i],0x0,sizeof(cwaintmp->txbuf[i]));
-
-    	    span->chans[i].readchunk = cwaintmp->rxbuf[i];
-	    span->chans[i].writechunk = cwaintmp->txbuf[i];
-	}
-	for (i=16; i<31 ; i++) {
-	    memset(cwaintmp->rxbuf[i-1],0x0,sizeof(cwaintmp->rxbuf[i-1]));
-    	    memset(cwaintmp->txbuf[i-1],0x0,sizeof(cwaintmp->txbuf[i-1]));
-    	    span->chans[i].readchunk = cwaintmp->rxbuf[i-1];
-	    span->chans[i].writechunk = cwaintmp->txbuf[i-1];
-	}
-	/* setup D channel buffer */
-    	memset(cwaintmp->dtxbuf,0x0,sizeof(cwaintmp->dtxbuf));
-	span->chans[15].writechunk = cwaintmp->dtxbuf;
-	cwaintmp->chans[15].maxbytes2transmit = sizeof(cwaintmp->dtxbuf);
-
-	memset(cwaintmp->drxbuf,0x0,sizeof(cwaintmp->drxbuf));
-    	span->chans[15].readchunk = cwaintmp->drxbuf;
-
+	for (i=0; i<31 ; i++) {
+	    cwaintmp->ts_rx[i] = -1;
+	    cwaintmp->ts_tx[i] = -1;
+	}
+
+	if (hdlcnet) {
+		span->chans[0].flags &= ~ZT_FLAG_HDLC;
+		span->chans[0].flags |= ZT_FLAG_BRIDCHAN; /* yes! */
+
+    		memset(cwaintmp->dtxbuf,0x0,sizeof(cwaintmp->dtxbuf));
+		span->chans[0].writechunk = cwaintmp->dtxbuf;
+
+		cwaintmp->chans[0].maxbytes2transmit = 248;
+//		cwaintmp->chans[0].maxbytes2transmit = 64;
+
+		memset(cwaintmp->drxbuf,0x0,sizeof(cwaintmp->drxbuf));
+    		span->chans[0].readchunk = cwaintmp->drxbuf;
+	} else {
+	    if (hw_hdlc) {
+		span->chans[15].flags &= ~ZT_FLAG_HDLC;
+		span->chans[15].flags |= ZT_FLAG_BRIDCHAN; /* yes! */
+    
+		/* setup B channel buffers (8 bytes each) */
+		for (i=0; i<31 ; i++) {
+		    if (i != 15) {
+		        memset(cwaintmp->rxbuf[i],0x0,sizeof(cwaintmp->rxbuf[i]));
+    			memset(cwaintmp->txbuf[i],0x0,sizeof(cwaintmp->txbuf[i]));
+    		        span->chans[i].readchunk = cwaintmp->rxbuf[i];
+			span->chans[i].writechunk = cwaintmp->txbuf[i];
+		    }
+		}
+		/* setup D channel buffer */
+    		memset(cwaintmp->dtxbuf,0x0,sizeof(cwaintmp->dtxbuf));
+		span->chans[15].writechunk = cwaintmp->dtxbuf;
+		cwaintmp->chans[15].maxbytes2transmit = sizeof(cwaintmp->dtxbuf) / 2;
+
+		memset(cwaintmp->drxbuf,0x0,sizeof(cwaintmp->drxbuf));
+    		span->chans[15].readchunk = cwaintmp->drxbuf;
+	    } else {
+		/* software HDLC */
+    		/* setup B channel buffers (8 bytes each) */
+    	        for (i=0; i<31 ; i++) {
+        	    memset(cwaintmp->rxbuf[i],0x0,sizeof(cwaintmp->rxbuf[i]));
+    		    memset(cwaintmp->txbuf[i],0x0,sizeof(cwaintmp->txbuf[i]));
+        	    span->chans[i].readchunk = cwaintmp->rxbuf[i];
+        	    span->chans[i].writechunk = cwaintmp->txbuf[i];
+    		}	    
+	    }
+	}
 	span->flags |= ZT_FLAG_RUNNING;
     } else {
 	printk(KERN_CRIT "already running\n");
@@ -1073,71 +1533,149 @@
     }
 
     spin_lock_irqsave(&cwaintmp->lock,flags);
-    // irqs off
+    /* irqs off */
     cwain_outb(cwaintmp,cwain_R_IRQ_CTRL, 0); 
 
-    /* setup D-FIFO TX */
-    cwain_outb(cwaintmp,cwain_R_FIFO,0x1F << 1);
-    cwain_waitbusy(cwaintmp);
-    cwain_outb(cwaintmp,cwain_R_INC_RES_FIFO,0x2);
-    cwain_waitbusy(cwaintmp);
-    cwain_outb(cwaintmp,cwain_A_CON_HDLC,0x1);
-    cwain_outb(cwaintmp,cwain_A_SUBCH_CFG,0x0);
-    cwain_outb(cwaintmp,cwain_A_CHANNEL,0x10 << 1);
-    cwain_outb(cwaintmp,cwain_A_IRQ_MSK,0x0);
-
-    /* setup D-FIFO RX */
-    cwain_outb(cwaintmp,cwain_R_FIFO,(0x1F << 1) | 1);
-    cwain_waitbusy(cwaintmp);
-    cwain_outb(cwaintmp,cwain_R_INC_RES_FIFO,0x2);
-    cwain_waitbusy(cwaintmp);
-    cwain_outb(cwaintmp,cwain_A_CON_HDLC,0x1);
-    cwain_outb(cwaintmp,cwain_A_SUBCH_CFG,0x0);
-    cwain_outb(cwaintmp,cwain_A_CHANNEL,(0x10 << 1) | 1);
-    cwain_outb(cwaintmp,cwain_A_IRQ_MSK,0x0);
-
-    /* setup B-FIFOs TX */
-    /* map ts 1 to 15 to fifos 0 to 14 */
-    for (i=1; i<16 ; i++) {
-	cwain_outb(cwaintmp,cwain_R_FIFO,(i - 1) << 1);
+    if (hdlcnet) {
+	    /* map ts 1 to 31 to fifo 31 */
+	    /* TX fifo */
+//	cwain_outb(cwaintmp,cwain_R_FIFO_MD,0x3E);
+	    cwain_outb(cwaintmp,cwain_R_FIRST_FIFO,0x1F << 1);
+	    cwain_waitbusy(cwaintmp);
+	    
+	    idx = 0;
+	    for (i=1; i<=31; i++) {
+		cwain_outb(cwaintmp,cwain_R_FSM_IDX, idx++);
+		cwain_waitbusy(cwaintmp);
+    		cwain_outb(cwaintmp,cwain_A_CHANNEL,i << 1);
+		if (i == 31) {
+		    cwain_outb(cwaintmp,cwain_A_FIFO_SEQ, (0x1F << 1) | 1);
+//		    if (debug) printk(KERN_INFO "cwain: cardID %d fsm_idx %d channel %d fifo_seq %#x\n", cwaintmp->cardID, idx - 1, i , (0x1f << 1) | 1);
+		} else {
+		    cwain_outb(cwaintmp,cwain_A_FIFO_SEQ, 0x1F << 1);
+//		    if (debug) printk(KERN_INFO "cwain: cardID %d fsm_idx %d channel %d fifo_seq %#x\n", cwaintmp->cardID, idx - 1, i  ,0x1f << 1);
+		}
+	    }
+
+	    /* map ts 1 to 31 to fifo 31 */
+	    /* RX fifo */
+	    
+	    for (i=1; i<=31; i++) {
+		cwain_outb(cwaintmp,cwain_R_FSM_IDX, idx++);
+		cwain_waitbusy(cwaintmp);
+    		cwain_outb(cwaintmp,cwain_A_CHANNEL,(i << 1) | 1);
+		if (i == 31) {
+		    cwain_outb(cwaintmp,cwain_A_FIFO_SEQ, 0x40);
+//		    if (debug) printk(KERN_INFO "cwain: cardID %d fsm_idx %d channel %d fifo_seq %#x\n", cwaintmp->cardID, idx - 1, i,  0x40);
+		} else {
+		    cwain_outb(cwaintmp,cwain_A_FIFO_SEQ, (0x1F << 1) | 1);
+//		    if (debug) printk(KERN_INFO "cwain: cardID %d fsm_idx %d channel %d fifo_seq %#x\n", cwaintmp->cardID, idx - 1, i,  (0x1f << 1) | 1);
+		}
+	    }
+
+//	cwain_outb(cwaintmp,cwain_R_FIFO_MD,0x36);
+
+	cwain_outb(cwaintmp,cwain_R_FIFO,0x1F << 1);
 	cwain_waitbusy(cwaintmp);
-    	cwain_outb(cwaintmp,cwain_R_INC_RES_FIFO,0x2);
+	cwain_outb(cwaintmp,cwain_A_CON_HDLC,0xc);
+	cwain_outb(cwaintmp,cwain_A_IRQ_MSK, 0x1);
+
+	cwain_outb(cwaintmp,cwain_R_FIFO,(0x1F << 1) | 1);
 	cwain_waitbusy(cwaintmp);
-	cwain_outb(cwaintmp,cwain_A_CON_HDLC,0x2);
-	cwain_outb(cwaintmp,cwain_A_CHANNEL,i << 1);
-	cwain_outb(cwaintmp,cwain_A_IRQ_MSK,0x1);
-    }
-    /* map ts 17 to 31 to fifos 15 to 29 */
-    for (i=17; i<32 ; i++) {
-	cwain_outb(cwaintmp,cwain_R_FIFO,(i - 2) << 1);
-	cwain_waitbusy(cwaintmp);
-    	cwain_outb(cwaintmp,cwain_R_INC_RES_FIFO,0x2);
-	cwain_waitbusy(cwaintmp);
-	cwain_outb(cwaintmp,cwain_A_CON_HDLC,0x2);
-	cwain_outb(cwaintmp,cwain_A_CHANNEL,i << 1);
-	cwain_outb(cwaintmp,cwain_A_IRQ_MSK,0x1);
-    }
-
-    /* setup B-FIFOs RX */
-    /* map ts 1 to 15 to fifos 0 to 14 */
-    for (i=1; i<16 ; i++) {
-	cwain_outb(cwaintmp,cwain_R_FIFO,((i-1) << 1) | 1);
-    	cwain_waitbusy(cwaintmp);
-    	cwain_outb(cwaintmp,cwain_R_INC_RES_FIFO,0x2);
-    	cwain_waitbusy(cwaintmp);
-    	cwain_outb(cwaintmp,cwain_A_CON_HDLC,0x2);
-    	cwain_outb(cwaintmp,cwain_A_CHANNEL,(i << 1) | 1);
-    	cwain_outb(cwaintmp,cwain_A_IRQ_MSK,0x1);
-    }
-    /* map ts 17 to 31 to fifos 15 to 29 */
-    for (i=17; i<32 ; i++) {
-	cwain_outb(cwaintmp,cwain_R_FIFO,((i-2) << 1) | 1);
-    	cwain_waitbusy(cwaintmp);
-    	cwain_outb(cwaintmp,cwain_R_INC_RES_FIFO,0x2);
-    	cwain_waitbusy(cwaintmp);
-    	cwain_outb(cwaintmp,cwain_A_CON_HDLC,0x2);
-    	cwain_outb(cwaintmp,cwain_A_CHANNEL,(i << 1) | 1);
-    	cwain_outb(cwaintmp,cwain_A_IRQ_MSK,0x1);
+	cwain_outb(cwaintmp,cwain_A_CON_HDLC,0xc);
+	cwain_outb(cwaintmp,cwain_A_IRQ_MSK, 0x1);
+
+//	cwain_outb(cwaintmp,cwain_R_FIFO_MD,0x3E);
+
+    } else {
+	if (hw_hdlc) {
+	    /* setup D-FIFO TX */
+	    cwain_outb(cwaintmp,cwain_R_FIFO,0x1F << 1);
+	    cwain_waitbusy(cwaintmp);
+    	    cwain_outb(cwaintmp,cwain_R_INC_RES_FIFO,0x2);
+    	    cwain_waitbusy(cwaintmp);
+    	    cwain_outb(cwaintmp,cwain_A_CON_HDLC,0xd);
+	    cwain_outb(cwaintmp,cwain_A_SUBCH_CFG,0x0);
+    	    cwain_outb(cwaintmp,cwain_A_CHANNEL,0x10 << 1);
+	    cwain_outb(cwaintmp,cwain_A_IRQ_MSK,0x1);
+
+            /* setup D-FIFO RX */
+	    cwain_outb(cwaintmp,cwain_R_FIFO,(0x1F << 1) | 1);
+    	    cwain_waitbusy(cwaintmp);
+	    cwain_outb(cwaintmp,cwain_R_INC_RES_FIFO,0x2);
+    	    cwain_waitbusy(cwaintmp);
+    	    cwain_outb(cwaintmp,cwain_A_CON_HDLC,0xd);
+    	    cwain_outb(cwaintmp,cwain_A_SUBCH_CFG,0x0);
+    	    cwain_outb(cwaintmp,cwain_A_CHANNEL,(0x10 << 1) | 1);
+    	    cwain_outb(cwaintmp,cwain_A_IRQ_MSK,0x1);
+
+    	    /* setup B-FIFOs TX */
+    	    /* map ts 1 to 15 to fifos 0 to 14 */
+	    for (i=1; i<16 ; i++) {
+		cwain_outb(cwaintmp,cwain_R_FIFO,(i - 1) << 1);
+		cwain_waitbusy(cwaintmp);
+    		cwain_outb(cwaintmp,cwain_R_INC_RES_FIFO,0x2);
+		cwain_waitbusy(cwaintmp);
+		cwain_outb(cwaintmp,cwain_A_CON_HDLC,0x2);
+		cwain_outb(cwaintmp,cwain_A_CHANNEL,i << 1);
+		cwain_outb(cwaintmp,cwain_A_IRQ_MSK,0x0);
+    	    }
+	    /* map ts 17 to 31 to fifos 15 to 29 */
+    	    for (i=17; i<32 ; i++) {
+		cwain_outb(cwaintmp,cwain_R_FIFO,(i - 2) << 1);
+		cwain_waitbusy(cwaintmp);
+    	        cwain_outb(cwaintmp,cwain_R_INC_RES_FIFO,0x2);
+	        cwain_waitbusy(cwaintmp);
+    	        cwain_outb(cwaintmp,cwain_A_CON_HDLC,0x2);
+	        cwain_outb(cwaintmp,cwain_A_CHANNEL,i << 1);
+	        cwain_outb(cwaintmp,cwain_A_IRQ_MSK,0x0);
+	    }
+
+	    /* setup B-FIFOs RX */
+	    /* map ts 1 to 15 to fifos 0 to 14 */
+	    for (i=1; i<16 ; i++) {
+		cwain_outb(cwaintmp,cwain_R_FIFO,((i-1) << 1) | 1);
+    	        cwain_waitbusy(cwaintmp);
+    		cwain_outb(cwaintmp,cwain_R_INC_RES_FIFO,0x2);
+    	        cwain_waitbusy(cwaintmp);
+    		cwain_outb(cwaintmp,cwain_A_CON_HDLC,0x2);
+    	        cwain_outb(cwaintmp,cwain_A_CHANNEL,(i << 1) | 1);
+    		cwain_outb(cwaintmp,cwain_A_IRQ_MSK,0x0);
+	    }
+    	    /* map ts 17 to 31 to fifos 15 to 29 */
+	    for (i=17; i<32 ; i++) {
+		cwain_outb(cwaintmp,cwain_R_FIFO,((i-2) << 1) | 1);
+    	        cwain_waitbusy(cwaintmp);
+    		cwain_outb(cwaintmp,cwain_R_INC_RES_FIFO,0x2);
+    		cwain_waitbusy(cwaintmp);
+    		cwain_outb(cwaintmp,cwain_A_CON_HDLC,0x2);
+    		cwain_outb(cwaintmp,cwain_A_CHANNEL,(i << 1) | 1);
+	        cwain_outb(cwaintmp,cwain_A_IRQ_MSK,0x0);
+	    }
+	} else {
+	    /* software HDLC */
+    	    /* setup B-FIFOs TX */
+    	    for (i=1; i<32 ; i++) {
+        	cwain_outb(cwaintmp,cwain_R_FIFO,(i - 1) << 1);
+        	cwain_waitbusy(cwaintmp);
+        	cwain_outb(cwaintmp,cwain_R_INC_RES_FIFO,0x2);
+        	cwain_waitbusy(cwaintmp);
+        	cwain_outb(cwaintmp,cwain_A_CON_HDLC,0x2);
+        	cwain_outb(cwaintmp,cwain_A_CHANNEL,i << 1);
+        	cwain_outb(cwaintmp,cwain_A_IRQ_MSK,0x0);
+    	    }
+    	    /* setup B-FIFOs RX */
+    	    for (i=1; i<32 ; i++) {
+        	cwain_outb(cwaintmp,cwain_R_FIFO,((i-1) << 1) | 1);
+        	cwain_waitbusy(cwaintmp);
+        	cwain_outb(cwaintmp,cwain_R_INC_RES_FIFO,0x2);
+        	cwain_waitbusy(cwaintmp);
+		cwain_outb(cwaintmp,cwain_A_CON_HDLC,0x2);
+        	cwain_outb(cwaintmp,cwain_A_CHANNEL,(i << 1) | 1);
+        	cwain_outb(cwaintmp,cwain_A_IRQ_MSK,0x0);
+    	    }
+
+	}
     }
 
     if (debug)
@@ -1149,14 +1687,14 @@
     
     /* setup E1 amplitude */
     cwain_outb(cwaintmp,cwain_R_PWM_MD,0x20);
-    cwain_outb(cwaintmp,cwain_R_PWM0,0x50);
-    cwain_outb(cwaintmp,cwain_R_PWM1,0xff);
+    cwain_outb(cwaintmp,cwain_R_PWM0,pwm0);
+    cwain_outb(cwaintmp,cwain_R_PWM1,pwm1);
 
     /* setup E1 transceiver */
-    cwain_outb(cwaintmp,cwain_R_TX_SL0,0xf8);  // R_TX_FR1
+    cwain_outb(cwaintmp,cwain_R_TX_SL0,0xf8);
     cwain_outb(cwaintmp,cwain_R_TX_SL0_CFG0,0x00); /* semiautomatic mode */
 
-    cwain_outb(cwaintmp,cwain_R_RX_SL0_CFG0,0x6); /* 0x26 */
+    cwain_outb(cwaintmp,cwain_R_RX_SL0_CFG0,0x6); 
 
     if (cwaintmp->span.lineconfig & ZT_CONFIG_AMI) {
 	cwain_outb(cwaintmp,cwain_R_TX0,0x82);
@@ -1165,38 +1703,41 @@
 	cwain_outb(cwaintmp,cwain_R_TX0,0x81);
 	cwain_outb(cwaintmp,cwain_R_RX0,0x01);
     }
-
-    /* transmitter mode */
-    cwain_outb(cwaintmp,cwain_R_TX1,0x60); 
-
-    cwain_outb(cwaintmp,cwain_R_LOS0,0x10);
-    cwain_outb(cwaintmp,cwain_R_LOS1,0x10);
+    cwain_outb(cwaintmp,cwain_R_TX1,0x60); /* transmitter mode */
+
+    cwain_outb(cwaintmp,cwain_R_LOS0,0x0f);
+    cwain_outb(cwaintmp,cwain_R_LOS1,0x0f);
 
     if (cwaintmp->span.lineconfig & ZT_CONFIG_CRC4) {
 	/* crc4 multiframe */
 	cwain_outb(cwaintmp,cwain_R_TX_SL0_CFG1,0x31);
-//	cwain_outb(cwaintmp,cwain_R_RX_SL0_CFG1,0x41);
 	cwain_outb(cwaintmp,cwain_R_RX_SL0_CFG1,0x03);
     } else {
 	/* doubleframe */
 	cwain_outb(cwaintmp,cwain_R_TX_SL0_CFG1,0x0);
-//	cwain_outb(cwaintmp,cwain_R_RX_SL0_CFG1,0x40);
-	cwain_outb(cwaintmp,cwain_R_RX_SL0_CFG1,0x02);
-    }
-
+	cwain_outb(cwaintmp,cwain_R_RX_SL0_CFG1,0x0);
+    }
+
+
+    /* automatic JATT */
+    cwain_outb(cwaintmp, cwain_R_JATT_CFG,0x9c);
     
     /* setup sync mode */    
     if (cwaincard->syncs[span->offset] > 0) {
-	cwain_outb(cwaintmp,cwain_R_SYNC_CTRL,0x2);
-	cwain_outb(cwaintmp,cwain_R_SYNC_OUT,0xe0);
+	cwain_outb(cwaintmp,cwain_R_SYNC_CTRL,0x2); // phase offset arb.
+	cwain_outb(cwaintmp,cwain_R_SYNC_OUT,0x00); // sync from e1 tx
 	/* layer 1, here we go! */
 	cwain_outb(cwaintmp,cwain_R_E1_WR_STA,0x00);
     } else {
-	cwain_outb(cwaintmp,cwain_R_SYNC_CTRL,0x5);
-	cwain_outb(cwaintmp,cwain_R_SYNC_OUT,0xe0);
+	cwain_outb(cwaintmp,cwain_R_SYNC_CTRL,0x5); // pcm_f0IO
+	cwain_outb(cwaintmp,cwain_R_SYNC_OUT,0x00); // sync from e1 tx
 	/* layer 1, up! */
 	cwain_outb(cwaintmp,cwain_R_E1_WR_STA,0x11);
     }
+
+    /* elastic buffer offsets */
+    cwain_outb(cwaintmp,cwain_R_RX_OFFS,0x06);
+    cwain_outb(cwaintmp,cwain_R_TX_OFFS,0x06);
     
     cwaintmp->sync = 0;
     cwaintmp->sync_sta = 0;
@@ -1239,27 +1780,37 @@
 //    printk(KERN_CRIT "cwain: stopping card %d span %d/%d.\n",cwaintmp->cardno,span->spanno,span->offset);
 
     // turn off irqs for all fifos
-
-    /* disable FIFO TX */
-    for (i=0; i<0x20 ; i++) {
-	cwain_outb(cwaintmp,cwain_R_FIFO,i << 1);
-	cwain_waitbusy(cwaintmp);
-	cwain_outb(cwaintmp,cwain_A_IRQ_MSK,0x0);
-    }
-
-    /* disable FIFO RX */
-    for (i=0; i<0x20 ; i++) {
-	cwain_outb(cwaintmp,cwain_R_FIFO,(i << 1) | 1);
-    	cwain_waitbusy(cwaintmp);
-    	cwain_outb(cwaintmp,cwain_A_IRQ_MSK,0x0);
-    }
-
+    if (hdlcnet) {
+	    cwain_outb(cwaintmp,cwain_R_FIFO,(0x1F << 1) | 1);
+	    cwain_waitbusy(cwaintmp);
+	    cwain_outb(cwaintmp,cwain_A_IRQ_MSK,0x0);
+    } else {
+	/* disable FIFO TX */
+	for (i=0; i<0x20 ; i++) {
+	    cwain_outb(cwaintmp,cwain_R_FIFO,i << 1);
+	    cwain_waitbusy(cwaintmp);
+	    cwain_outb(cwaintmp,cwain_A_IRQ_MSK,0x0);
+	}
+
+	/* disable FIFO RX */
+        for (i=0; i<0x20 ; i++) {
+	    cwain_outb(cwaintmp,cwain_R_FIFO,(i << 1) | 1);
+    	    cwain_waitbusy(cwaintmp);
+    	    cwain_outb(cwaintmp,cwain_A_IRQ_MSK,0x0);
+	}
+    }
 
     /* Deactivate Layer 1 */
     cwain_outb(cwaintmp,cwain_R_E1_WR_STA,0x10);
 
+    /* Disable transmit */
+    if (cwaintmp->span.lineconfig & ZT_CONFIG_AMI) {
+	cwain_outb(cwaintmp,cwain_R_TX0,0x02);
+    } else if (cwaintmp->span.lineconfig & ZT_CONFIG_HDB3) {
+	cwain_outb(cwaintmp,cwain_R_TX0,0x01);
+    }
+
     cwain_outb(cwaintmp,cwain_R_IRQ_CTRL, 0); 
-//    cwain_outb(cwaintmp,cwain_R_IRQMSK_MISC, 0); 
     cwain_inb(cwaintmp,cwain_R_STATUS);
 
 
@@ -1283,11 +1834,17 @@
 
 static int ztcwain_spanconfig(struct zt_span *span,struct zt_lineconfig *lc) {
     struct zt_cwain_card *cwaincard = span->pvt;
-    span->lineconfig = lc->lineconfig;
-    span->syncsrc = lc->sync;
-
-    cwaincard->syncs[span->offset] = lc->sync;
-    cwaincard->syncsrc = -1;
+    int alreadyrunning;
+
+    alreadyrunning = span->flags & ZT_FLAG_RUNNING;
+
+    if (!alreadyrunning) {
+	span->lineconfig = lc->lineconfig;
+	span->syncsrc = lc->sync;
+
+	cwaincard->syncs[span->offset] = lc->sync;
+	cwaincard->syncsrc = -1;
+    }
 //    printk(KERN_INFO "span_config %d lineconfig=%d syncsrc=%d\n", span->spanno, lc->lineconfig, lc->sync);
 //    cwain_check_timing(cwaincard);
     return 0;
@@ -1317,9 +1874,15 @@
         cwaintmp->span.open = ztcwain_open;
         cwaintmp->span.close = ztcwain_close;
         cwaintmp->span.ioctl = ztcwain_ioctl;
+        cwaintmp->span.proc_read = ztcwain_proc_read;
+	cwaintmp->span.dacs = ztcwain_dacs;
 
         cwaintmp->span.chans = cwaintmp->chans;
-        cwaintmp->span.channels = 31;
+	if (hdlcnet) {
+	    cwaintmp->span.channels = 1;
+	} else {
+	    cwaintmp->span.channels = 31;
+	}
         cwaintmp->span.deflaw = ZT_LAW_ALAW;
         cwaintmp->span.linecompat = ZT_CONFIG_AMI | ZT_CONFIG_HDB3 | ZT_CONFIG_CCS; 
         init_waitqueue_head(&cwaintmp->span.maintq);
@@ -1330,7 +1893,7 @@
 	    memset(&(cwaintmp->chans[i]),0x0,sizeof(struct zt_chan));
 	    sprintf(cwaintmp->chans[i].name,"cwain%d/%d",cwain_span_count + 1,i + 1);
 	    cwaintmp->chans[i].pvt = cwaintmp;
-	    cwaintmp->chans[i].sigcap =  ZT_SIG_CLEAR;
+	    cwaintmp->chans[i].sigcap =  ZT_SIG_CLEAR | ZT_SIG_DACS;
 	    cwaintmp->chans[i].chanpos = i + 1; 
 	}
 
@@ -1374,8 +1937,14 @@
     /* no master yet, force reelection */
     cwaintmp->syncsrc = -1;
     
+#if (ZT_CHUNKSIZE == 32)
+    /* set up the timer 250 Hz, zaptel timing */
+    cwain_outb(cwaintmp->span[0],cwain_R_TI_WD, 0x4);
+#endif
+#if (ZT_CHUNKSIZE == 8)
     /* set up the timer 1 khz, zaptel timing */
     cwain_outb(cwaintmp->span[0],cwain_R_TI_WD, 0x2);
+#endif
 
     if (cwaintmp->spans == 2) {
 //	cwain_outb(cwaintmp->span[1],cwain_R_IRQMSK_MISC, 0x1); 
@@ -1564,6 +2133,10 @@
 
 
 int init_module(void) {
+    if (hdlcnet) {
+	hw_hdlc = 1; /* otherwise it makes no sense at all... */
+	dacs = 0;
+    }
     multi_cwain = NULL;
     cwain_find_spans(PCI_DEVICE_ID_CCD_E);
     cwain_sort_cards();
@@ -1571,7 +2144,7 @@
     if (cwain_card_count == 0) {
 	printk(KERN_INFO "cwain: no cwain cards found.\n");
     } else {
-	printk(KERN_INFO "cwain: %d cwain card(s) in this box, %d E1 ports total.\n", cwain_card_count, cwain_span_count);
+	printk(KERN_INFO "cwain: %d cwain card(s) in this box, %d E1 ports total, hw_hdcl = %d, dacs =%d, require_ext_clock = %d, ZT_CHUNKSIZE = %d, timer = %d.\n", cwain_card_count, cwain_span_count, hw_hdlc, dacs, require_ext_clock, ZT_CHUNKSIZE, cwain_TIMER_INT);
     }
     return 0;
 }
@@ -1609,9 +2182,21 @@
 #ifdef LINUX26
 module_param(ports, int, 0600);
 module_param(debug, int, 0600);
+module_param(hw_hdlc, int, 0600);
+module_param(hdlcnet, int, 0600);
+module_param(pwm0, int, 0600);
+module_param(pwm1, int, 0600);
+module_param(dacs, int, 0600);
+module_param(require_ext_clock, int, 0600);
 #else
 MODULE_PARM(ports,"i");
 MODULE_PARM(debug,"i");
+MODULE_PARM(hw_hdlc,"i");
+MODULE_PARM(hdlcnet,"i");
+MODULE_PARM(pwm0,"i");
+MODULE_PARM(pwm1,"i");
+MODULE_PARM(dacs,"i");
+MODULE_PARM(require_ext_clock,"i");
 #endif
 
 MODULE_DESCRIPTION("cwain zaptel driver");

Modified: zaptel/trunk/cwain/cwain.h
URL: http://svn.debian.org/wsvn/pkg-voip/zaptel/trunk/cwain/cwain.h?rev=5129&op=diff
==============================================================================
--- zaptel/trunk/cwain/cwain.h (original)
+++ zaptel/trunk/cwain/cwain.h Fri Dec 28 00:20:29 2007
@@ -1,7 +1,10 @@
 #define cwain_FIFO_SIZE	128
 #define cwain_DFIFO_SIZE	4096
+#define cwain_DFIFO_FRAMES	0x10
 #define cwain_FRAME_SIZE 16	/* has to be %4==0 */
 #define cwain_FIFO_HW cwain_FRAME_SIZE * 2 + ZT_CHUNKSIZE
+#define cwain_TIMER_INT	(8000 / ZT_CHUNKSIZE)
+
 
 typedef struct zt_cwain {
     /* pci resources */
@@ -32,12 +35,15 @@
     unsigned char leds[4];
 
     /* B chan buffers */
-    unsigned char rxbuf[30][ZT_CHUNKSIZE];
-    unsigned char txbuf[30][ZT_CHUNKSIZE];
+    unsigned char rxbuf[31][ZT_CHUNKSIZE];
+    unsigned char txbuf[31][ZT_CHUNKSIZE];
+
+    signed short ts_rx[31];
+    signed short ts_tx[31];
 
     /* buffers */
-    unsigned char frxbuf[30][cwain_FRAME_SIZE];
-    unsigned char ftxbuf[30][cwain_FRAME_SIZE];
+    unsigned char frxbuf[31][cwain_FRAME_SIZE];
+    unsigned char ftxbuf[31][cwain_FRAME_SIZE];
     
     /* number of RXed dchan frames */
     unsigned char drx;

Modified: zaptel/trunk/cwain/zaptel.conf.hdlcnet.doubleE1
URL: http://svn.debian.org/wsvn/pkg-voip/zaptel/trunk/cwain/zaptel.conf.hdlcnet.doubleE1?rev=5129&op=diff
==============================================================================
--- zaptel/trunk/cwain/zaptel.conf.hdlcnet.doubleE1 (original)
+++ zaptel/trunk/cwain/zaptel.conf.hdlcnet.doubleE1 Fri Dec 28 00:20:29 2007
@@ -7,5 +7,4 @@
 hdlcnet = 1
 
 ; hdlc 1
-hdlcnet = 2
-
+hdlcnet = 2

Modified: zaptel/trunk/debian/changelog
URL: http://svn.debian.org/wsvn/pkg-voip/zaptel/trunk/debian/changelog?rev=5129&op=diff
==============================================================================
--- zaptel/trunk/debian/changelog (original)
+++ zaptel/trunk/debian/changelog Fri Dec 28 00:20:29 2007
@@ -19,7 +19,10 @@
     (Closes: #407996).
   * Don't build wcopenpci on big endian platforms (Module gives #error there).
   * Actually fix building xpp with M instead of SUBDIRS.
-  * Updates to bristuff zap modules from bristuff-0.3.0-1y-l .
+  * Updates to bristuff zap modules from bristuff-0.3.0-1y-l: 
+    - Fix build warnings.
+    - Allow sharing interrupts.
+  * Update cwain from recent bristuff.
 
   [ Faidon Liambotis ]
   * Don't delete old device nodes on installations since it's needed only for




More information about the Pkg-voip-commits mailing list