Index: dahdi-linux-2.1.0.4/drivers/dahdi/zaphfc.h
===================================================================
--- dahdi-linux-2.1.0.4.orig/drivers/dahdi/zaphfc.h	2009-03-17 18:13:54.000000000 +0200
+++ dahdi-linux-2.1.0.4/drivers/dahdi/zaphfc.h	2009-03-17 18:14:44.000000000 +0200
@@ -135,8 +135,12 @@
 /* bits in HFCD_MST_MODE */
 #define hfc_MST_MODE_MASTER	     0x01
 #define hfc_MST_MODE_SLAVE         0x00
+#define hfc_MST_MODE_F0_LONG_DURATION         0x08
 /* remaining bits are for codecs control */
 
+/* bits in HFCD_MST_EMOD */
+#define hfc_MST_EMOD_SLOW_CLOCK_ADJ	0x01
+
 /* bits in HFCD_SCTRL */
 #define hfc_SCTRL_B1_ENA	     0x01
 #define hfc_SCTRL_B2_ENA	     0x02
@@ -236,6 +240,9 @@
 #define hfc_BTRANS_THRESHOLD 128
 #define hfc_BTRANS_THRESMASK 0x00
 
+#define hfc_FIFO_MEM_SIZE_BYTES (32*1024)
+#define hfc_FIFO_MEM_SIZE_PAGES ((hfc_FIFO_MEM_SIZE_BYTES+PAGE_SIZE-1)/PAGE_SIZE)
+
 /* Structures */
 
 typedef struct hfc_regs {
@@ -249,20 +256,67 @@
     unsigned char connect;
     unsigned char trm;
     unsigned char mst_mode;
+    unsigned char mst_emod;
     unsigned char bswapped;
     unsigned char nt_mode;
     unsigned char int_drec;
 } hfc_regs;
 
+struct bch {
+    int fill_fifo,checkcnt,initialized;
+    struct {
+	u16 z2;
+	struct {
+	    volatile u16 *z1p;
+	    volatile u8 *fifo_base;
+	    int filled;
+	} c[2];
+	int diff;
+    } rx;
+    struct {
+	u16 z1;
+	struct {
+	    volatile u16 *z1p,*z2p;
+	    volatile u8 *fifo_base;
+	    int filled;
+	} c[2];
+	int diff;
+    } tx;
+};
+
+struct dch {
+    struct {
+	struct {
+	    volatile u8 *p;
+	} f1;
+	struct {
+	    u8 v;
+	    struct {
+		u16 v;
+	    } z2;
+	} f2;
+    } rx;
+    struct {
+	struct {
+	    u8 v;
+	    volatile u8 *p;
+	    struct {
+		u16 v;
+	    } z1;
+	} f1;
+	struct {
+	    volatile u8 *p;
+	} f2;
+    } tx;
+};
+
 typedef struct hfc_card {
     spinlock_t lock;
     unsigned int irq;
     unsigned int iomem;
     int ticks;		
-    int clicks;		
     unsigned char *pci_io;
-    void *fifomem;		// start of the shared mem
-    volatile void *fifos;	// 32k aligned mem for the fifos
+    void *fifos;		// 32k aligned mem for the fifos
     struct hfc_regs regs;
     unsigned int pcibus;
     unsigned int pcidevfn;
@@ -274,6 +328,9 @@
     unsigned char brecbuf[2][DAHDI_CHUNKSIZE];
     unsigned char btransbuf[2][DAHDI_CHUNKSIZE];
     unsigned char cardno;
+    int active;
+    struct bch bch;
+    struct dch dch;
     struct hfc_card *next;
 } hfc_card;
 
@@ -285,6 +342,3 @@
     struct hfc_card *card;
 } dahdi_hfc;
 
-/* tune this */
-#define hfc_BCHAN_BUFFER	8
-#define hfc_MAX_CARDS		8
Index: dahdi-linux-2.1.0.4/drivers/dahdi/zaphfc.c
===================================================================
--- dahdi-linux-2.1.0.4.orig/drivers/dahdi/zaphfc.c	2009-03-17 18:52:47.000000000 +0200
+++ dahdi-linux-2.1.0.4/drivers/dahdi/zaphfc.c	2009-03-17 18:53:43.000000000 +0200
@@ -7,19 +7,21 @@
  *
  * Klaus-Peter Junghanns <kpj@junghanns.net>
  *
+ * Copyright (C) 2004, 2005, 2006  Florian Zumbiehl <florz@gmx.de>
+ *  - support for slave mode of the HFC-S chip which allows it to
+ *    sync its sample clock to an external source/another HFC chip
+ *  - support for "interrupt bundling" (let only one card generate
+ *    8 kHz timing interrupt no matter how many cards there are
+ *    in the system)
+ *  - interrupt loss tolerant b channel handling
+ *
  * This program is free software and may be modified and
- * distributed under the terms of the GNU Public License.
+ * distributed under the terms of the GNU General Public License.
  *
  */
 
 #include <linux/kernel.h>
 #include <linux/module.h>
-#ifdef RTAITIMING
-#include <asm/io.h>
-#include <rtai.h>
-#include <rtai_sched.h>
-#include <rtai_fifos.h>
-#endif
 #include <linux/pci.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
@@ -29,6 +31,8 @@
 
 #include <linux/moduleparam.h>
 
+#define log2(n) ffz(~(n))
+
 #if CONFIG_PCI
 
 #define CLKDEL_TE	0x0f	/* CLKDEL in TE mode */
@@ -70,42 +74,31 @@
 static struct hfc_card *hfc_dev_list = NULL;
 static int hfc_dev_count = 0;
 static int modes = 0; // all TE
+static int sync_slave = 0; // all master
+static int timer_card = 0;
+static int jitterbuffer = 1;
 static int debug = 0;
 static struct pci_dev *multi_hfc = NULL;
 static DEFINE_SPINLOCK(registerlock);
 
-void hfc_shutdownCard(struct hfc_card *hfctmp) {
-    unsigned long flags;
-
-    if (hfctmp == NULL) {
-	return;
-    }
-
-    if (hfctmp->pci_io == NULL) {
-	return;
-    }
-    
-    spin_lock_irqsave(&hfctmp->lock,flags);
-
+void hfc_shutdownCard1(struct hfc_card *hfctmp) {
     printk(KERN_INFO "zaphfc: shutting down card at %p.\n",hfctmp->pci_io);
 
     /* Clear interrupt mask */
     hfctmp->regs.int_m2 = 0;
     hfc_outb(hfctmp, hfc_INT_M2, hfctmp->regs.int_m2);
 
-    /* Reset pending interrupts */
-    hfc_inb(hfctmp, hfc_INT_S1);
+    /* Remove interrupt handler */
+    free_irq(hfctmp->irq,hfctmp);
+}
+
+void hfc_shutdownCard2(struct hfc_card *hfctmp) {
+    unsigned long flags;
 
-    /* Wait for interrupts that might still be pending */
-    spin_unlock_irqrestore(&hfctmp->lock, flags);
-    set_current_state(TASK_UNINTERRUPTIBLE);
-    schedule_timeout((30 * HZ) / 1000);	// wait 30 ms
     spin_lock_irqsave(&hfctmp->lock,flags);
 
-    /* Remove interrupt handler */
-    if (hfctmp->irq) {
-	free_irq(hfctmp->irq, hfctmp);
-    }
+    /* Reset pending interrupts */
+    hfc_inb(hfctmp, hfc_INT_S1);
 
     /* Soft-reset the card */
     hfc_outb(hfctmp, hfc_CIRM, hfc_CIRM_RESET); // softreset on
@@ -119,8 +112,8 @@
 
     pci_write_config_word(hfctmp->pcidev, PCI_COMMAND, 0);	// disable memio and bustmaster
 
-    if (hfctmp->fifomem != NULL) {
-        kfree(hfctmp->fifomem);
+    if (hfctmp->fifos != NULL) {
+	free_pages((unsigned long)hfctmp->fifos,log2(hfc_FIFO_MEM_SIZE_PAGES));
     }
     iounmap((void *) hfctmp->pci_io);
     hfctmp->pci_io = NULL;
@@ -130,11 +123,24 @@
     spin_unlock_irqrestore(&hfctmp->lock,flags);
     if (hfctmp->ztdev != NULL) {
 	dahdi_unregister(&hfctmp->ztdev->span);
-	kfree(hfctmp->ztdev);
+	vfree(hfctmp->ztdev);
 	printk(KERN_INFO "unregistered from DAHDI.\n");
     }
 }
 
+void hfc_shutdownCard(struct hfc_card *hfctmp) {
+    if (hfctmp == NULL) {
+	return;
+    }
+
+    if (hfctmp->pci_io == NULL) {
+	return;
+    }
+
+    hfc_shutdownCard1(hfctmp);
+    hfc_shutdownCard2(hfctmp);
+}
+
 void hfc_resetCard(struct hfc_card *hfctmp) {
     unsigned long flags;
 
@@ -178,14 +184,14 @@
     hfctmp->regs.ctmt = hfc_CTMT_TRANSB1 | hfc_CTMT_TRANSB2; // all bchans are transparent , no freaking hdlc
     hfc_outb(hfctmp, hfc_CTMT, hfctmp->regs.ctmt);
 
-    hfctmp->regs.int_m1 = 0;
+    hfctmp->regs.int_m1=hfc_INTS_L1STATE;
+    if(hfctmp->cardno==timer_card){
+	hfctmp->regs.int_m2=hfc_M2_PROC_TRANS;
+    }else{
+	hfctmp->regs.int_m1|=hfc_INTS_DREC;
+	hfctmp->regs.int_m2=0;
+    }
     hfc_outb(hfctmp, hfc_INT_M1, hfctmp->regs.int_m1);
-
-#ifdef RTAITIMING
-    hfctmp->regs.int_m2 = 0;
-#else
-    hfctmp->regs.int_m2 = hfc_M2_PROC_TRANS;
-#endif
     hfc_outb(hfctmp, hfc_INT_M2, hfctmp->regs.int_m2);
 
     /* Clear already pending ints */
@@ -197,8 +203,8 @@
 	hfctmp->regs.sctrl = 3 | hfc_SCTRL_NONE_CAP | hfc_SCTRL_MODE_TE;	/* set tx_lo mode, error in datasheet ! */
     }
 
-    hfctmp->regs.mst_mode = hfc_MST_MODE_MASTER;	/* HFC Master Mode */
     hfc_outb(hfctmp, hfc_MST_MODE, hfctmp->regs.mst_mode);
+    hfc_outb(hfctmp, hfc_MST_EMOD, hfctmp->regs.mst_emod);
 
     hfc_outb(hfctmp, hfc_SCTRL, hfctmp->regs.sctrl);
     hfctmp->regs.sctrl_r = 3;
@@ -210,10 +216,8 @@
     hfc_outb(hfctmp, hfc_CIRM, 0x80 | 0x40);	// bit order
 
     /* Finally enable IRQ output */
-#ifndef RTAITIMING
     hfctmp->regs.int_m2 |= hfc_M2_IRQ_ENABLE;
     hfc_outb(hfctmp, hfc_INT_M2, hfctmp->regs.int_m2);
-#endif
 
     /* clear pending ints */
     hfc_inb(hfctmp, hfc_INT_S1); 
@@ -230,368 +234,210 @@
     spin_unlock(&registerlock);
 }
 
-static void hfc_btrans(struct hfc_card *hfctmp, char whichB) {
-    // we are called with irqs disabled from the irq handler
-    int count, maxlen, total;
-    unsigned char *f1, *f2;
-    unsigned short *z1, *z2, newz1;
-    int freebytes;
-
-    if (whichB == 1) {
-	f1 = (char *)(hfctmp->fifos + hfc_FIFO_B1TX_F1);
-        f2 = (char *)(hfctmp->fifos + hfc_FIFO_B1TX_F2);
-	z1 = (unsigned short *)(hfctmp->fifos + hfc_FIFO_B1TX_Z1 + (*f1 * 4));
-	z2 = (unsigned short *)(hfctmp->fifos + hfc_FIFO_B1TX_Z2 + (*f1 * 4));
-    } else {
-	f1 = (char *)(hfctmp->fifos + hfc_FIFO_B2TX_F1);
-        f2 = (char *)(hfctmp->fifos + hfc_FIFO_B2TX_F2);
-	z1 = (unsigned short *)(hfctmp->fifos + hfc_FIFO_B2TX_Z1 + (*f1 * 4));
-	z2 = (unsigned short *)(hfctmp->fifos + hfc_FIFO_B2TX_Z2 + (*f1 * 4));
-    }
-
-    freebytes = *z2 - *z1;
-    if (freebytes <= 0) {
-	freebytes += hfc_B_FIFO_SIZE;
-    }
-    count = DAHDI_CHUNKSIZE;
-
-    total = count;
-    if (freebytes < count) {
-	hfctmp->clicks++;
-	/* only spit out this warning once per second to not make things worse! */
-	if (hfctmp->clicks > 100) {
-	    printk(KERN_CRIT "zaphfc: bchan tx fifo full, dropping audio! (z1=%d, z2=%d)\n",*z1,*z2);
-	    hfctmp->clicks = 0;
-	}
-	return;
-    }
-    
-    maxlen = (hfc_B_FIFO_SIZE + hfc_B_SUB_VAL) - *z1;
-    if (maxlen > count) {
-        maxlen = count;
-    }
-    newz1 = *z1 + total;
-    if (newz1 >= (hfc_B_FIFO_SIZE + hfc_B_SUB_VAL)) { newz1 -= hfc_B_FIFO_SIZE; }
+/*===========================================================================*/
 
-	if (whichB == 1) {
-	    memcpy((char *)(hfctmp->fifos + hfc_FIFO_B1TX_ZOFF + *z1),hfctmp->ztdev->chans[0].writechunk, maxlen);
-	} else {
-	    memcpy((char *)(hfctmp->fifos + hfc_FIFO_B2TX_ZOFF + *z1),hfctmp->ztdev->chans[1].writechunk, maxlen);
-	}
-	
-	count -= maxlen;
-	if (count > 0) {
-	// Buffer wrap
-	    if (whichB == 1) {
-	        memcpy((char *)(hfctmp->fifos + hfc_FIFO_B1TX_ZOFF + hfc_B_SUB_VAL),hfctmp->ztdev->chans[0].writechunk+maxlen, count);
-	    } else {
-	        memcpy((char *)(hfctmp->fifos + hfc_FIFO_B2TX_ZOFF + hfc_B_SUB_VAL),hfctmp->ztdev->chans[1].writechunk+maxlen, count);
-	    }
-	}
+#if hfc_B_FIFO_SIZE%DAHDI_CHUNKSIZE
+#error hfc_B_FIFO_SIZE is not a multiple of DAHDI_CHUNKSIZE even though the code assumes this
+#endif
+
+static void hfc_dch_init(struct hfc_card *hfctmp){
+    struct dch *chtmp=&hfctmp->dch;
 
-    *z1 = newz1;	/* send it now */
+    chtmp->rx.f1.p=(u8 *)(hfctmp->fifos+hfc_FIFO_DRX_F1);
+    chtmp->rx.f2.v=0x1f;
+    chtmp->rx.f2.z2.v=0x1ff;
 
-//    if (count > 0) printk(KERN_CRIT "zaphfc: bchan tx fifo (f1=%d, f2=%d, z1=%d, z2=%d)\n",(*f1) & hfc_FMASK,(*f2) & hfc_FMASK, *z1, *z2);
-    return;    
+    chtmp->tx.f1.p=(u8 *)(hfctmp->fifos+hfc_FIFO_DTX_F1);
+    chtmp->tx.f1.v=0x1f;
+    chtmp->tx.f1.z1.v=0x1ff;
+    chtmp->tx.f2.p=(u8 *)(hfctmp->fifos+hfc_FIFO_DTX_F2);
 }
 
-static void hfc_brec(struct hfc_card *hfctmp, char whichB) {
-    // we are called with irqs disabled from the irq handler
-    int count, maxlen, drop;
-    volatile unsigned char *f1, *f2;
-    volatile unsigned short *z1, *z2, newz2;
-    int bytes = 0;
-
-    if (whichB == 1) {
-	f1 = (char *)(hfctmp->fifos + hfc_FIFO_B1RX_F1);
-        f2 = (char *)(hfctmp->fifos + hfc_FIFO_B1RX_F2);
-	z1 = (unsigned short *)(hfctmp->fifos + hfc_FIFO_B1RX_Z1 + (*f1 * 4));
-	z2 = (unsigned short *)(hfctmp->fifos + hfc_FIFO_B1RX_Z2 + (*f1 * 4));
-    } else {
-	f1 = (char *)(hfctmp->fifos + hfc_FIFO_B2RX_F1);
-        f2 = (char *)(hfctmp->fifos + hfc_FIFO_B2RX_F2);
-	z1 = (unsigned short *)(hfctmp->fifos + hfc_FIFO_B2RX_Z1 + (*f1 * 4));
-	z2 = (unsigned short *)(hfctmp->fifos + hfc_FIFO_B2RX_Z2 + (*f1 * 4));
-    }
+static void hfc_bch_init(struct hfc_card *hfctmp){
+    struct bch *chtmp=&hfctmp->bch;
 
-    bytes = *z1 - *z2;
-    if (bytes < 0) {
-	bytes += hfc_B_FIFO_SIZE;
-    }
-    count = DAHDI_CHUNKSIZE;
-    
-    if (bytes < DAHDI_CHUNKSIZE) {
-#ifndef RTAITIMING
-	printk(KERN_CRIT "zaphfc: bchan rx fifo not enough bytes to receive! (z1=%d, z2=%d, wanted %d got %d), probably a buffer overrun.\n",*z1,*z2,DAHDI_CHUNKSIZE,bytes);
-#endif
-	return;
-    }
+    chtmp->checkcnt=0;
+    chtmp->fill_fifo=0;
 
-    /* allowing the buffering of hfc_BCHAN_BUFFER bytes of audio data works around irq jitter */
-    if (bytes > hfc_BCHAN_BUFFER + DAHDI_CHUNKSIZE) {
-	/* if the system is too slow to handle it, we will have to drop it all (except 1 DAHDI chunk) */
-	drop = bytes - DAHDI_CHUNKSIZE;
-	hfctmp->clicks++;
-	/* only spit out this warning once per second to not make things worse! */
-	if (hfctmp->clicks > 100) {
-	    printk(KERN_CRIT "zaphfc: dropped audio (z1=%d, z2=%d, wanted %d got %d, dropped %d).\n",*z1,*z2,count,bytes,drop);
-	    hfctmp->clicks = 0;
-	}
-	/* hm, we are processing the b chan data tooooo slowly... let's drop the lost audio */
-	newz2 = *z2 + drop;
-	if (newz2 >= (hfc_B_FIFO_SIZE + hfc_B_SUB_VAL)) { 
-	    newz2 -= hfc_B_FIFO_SIZE; 
-	}
-	*z2 = newz2;
-    }
+    chtmp->rx.c[0].z1p=(unsigned short *)(hfctmp->fifos+hfc_FIFO_B1RX_Z1+0x1f*4);
+    chtmp->rx.c[0].fifo_base=(char *)(hfctmp->fifos+hfc_FIFO_B1RX_ZOFF);
+    chtmp->rx.c[1].z1p=(unsigned short *)(hfctmp->fifos+hfc_FIFO_B2RX_Z1+0x1f*4);
+    chtmp->rx.c[1].fifo_base=(char *)(hfctmp->fifos+hfc_FIFO_B2RX_ZOFF);
+    chtmp->rx.z2=hfc_B_SUB_VAL;
+    chtmp->rx.diff=0;
 
-    
-    maxlen = (hfc_B_FIFO_SIZE + hfc_B_SUB_VAL) - *z2;
-    if (maxlen > count) {
-        maxlen = count;
-    }
-    if (whichB == 1) {
-        memcpy(hfctmp->ztdev->chans[0].readchunk,(char *)(hfctmp->fifos + hfc_FIFO_B1RX_ZOFF + *z2), maxlen);
-    } else {
-        memcpy(hfctmp->ztdev->chans[1].readchunk,(char *)(hfctmp->fifos + hfc_FIFO_B2RX_ZOFF + *z2), maxlen);
-    }
-    newz2 = *z2 + count;
-    if (newz2 >= (hfc_B_FIFO_SIZE + hfc_B_SUB_VAL)) { 
-        newz2 -= hfc_B_FIFO_SIZE; 
+    chtmp->tx.c[0].z1p=(unsigned short *)(hfctmp->fifos+hfc_FIFO_B1TX_Z1+0x1f*4);
+    chtmp->tx.c[0].z2p=(unsigned short *)(hfctmp->fifos+hfc_FIFO_B1TX_Z2+0x1f*4);
+    chtmp->tx.c[0].fifo_base=(char *)(hfctmp->fifos+hfc_FIFO_B1TX_ZOFF);
+    chtmp->tx.c[0].filled=0;
+    chtmp->tx.c[1].z1p=(unsigned short *)(hfctmp->fifos+hfc_FIFO_B2TX_Z1+0x1f*4);
+    chtmp->tx.c[1].z2p=(unsigned short *)(hfctmp->fifos+hfc_FIFO_B2TX_Z2+0x1f*4);
+    chtmp->tx.c[1].fifo_base=(char *)(hfctmp->fifos+hfc_FIFO_B2TX_ZOFF);
+    chtmp->tx.c[1].filled=0;
+    chtmp->tx.z1=hfc_B_SUB_VAL;
+    chtmp->tx.diff=0;
+
+    hfc_dch_init(hfctmp);
+
+    chtmp->initialized=0;
+}
+
+static int hfc_bch_check(struct hfc_card *hfctmp){
+    struct bch *chtmp=&hfctmp->bch;
+    int x,r;
+
+    for(x=0;x<2;x++){
+	chtmp->tx.c[x].filled=(chtmp->tx.z1-*chtmp->tx.c[x].z2p+hfc_B_FIFO_SIZE)%hfc_B_FIFO_SIZE;
+	chtmp->rx.c[x].filled=(*chtmp->rx.c[x].z1p-chtmp->rx.z2+hfc_B_FIFO_SIZE)%hfc_B_FIFO_SIZE;
     }
-    *z2 = newz2;
-	
-    count -= maxlen;
-    if (count > 0) {
-    // Buffer wrap
-        if (whichB == 1) {
-	    z2 = (unsigned short *)(hfctmp->fifos + hfc_FIFO_B1RX_Z2 + (*f1 * 4));
-    	    memcpy(hfctmp->ztdev->chans[0].readchunk + maxlen,(char *)(hfctmp->fifos + hfc_FIFO_B1RX_ZOFF + hfc_B_SUB_VAL), count);
-	} else {
-	    z2 = (unsigned short *)(hfctmp->fifos + hfc_FIFO_B2RX_Z2 + (*f1 * 4));
-	    memcpy(hfctmp->ztdev->chans[1].readchunk + maxlen,(char *)(hfctmp->fifos + hfc_FIFO_B2RX_ZOFF + hfc_B_SUB_VAL), count);
-	}
-	newz2 = *z2 + count;
-	if (newz2 >= (hfc_B_FIFO_SIZE + hfc_B_SUB_VAL)) { 
-	    newz2 -= hfc_B_FIFO_SIZE; 
+    if(chtmp->fill_fifo){
+	chtmp->checkcnt++;
+	chtmp->checkcnt%=DAHDI_CHUNKSIZE;
+	r=!chtmp->checkcnt;
+    }else{
+	x=chtmp->tx.c[0].filled-chtmp->tx.c[1].filled;
+	if(abs(x-chtmp->tx.diff)>1){
+	    printk(KERN_CRIT "zaphfc[%d]: tx sync changed: %d, %d\n",hfctmp->cardno,chtmp->tx.c[0].filled,chtmp->tx.c[1].filled);
+	    chtmp->tx.diff=x;
 	}
+	r=chtmp->tx.c[0].filled<=DAHDI_CHUNKSIZE*jitterbuffer&&chtmp->tx.c[1].filled<=DAHDI_CHUNKSIZE*jitterbuffer;
     }
+    return(r);
+}
 
+#define hfc_bch_inc_z(a,b) (a)=((a)-hfc_B_SUB_VAL+(b))%hfc_B_FIFO_SIZE+hfc_B_SUB_VAL
 
-    if (whichB == 1) {
-	dahdi_ec_chunk(&hfctmp->ztdev->chans[0], hfctmp->ztdev->chans[0].readchunk, hfctmp->ztdev->chans[0].writechunk);
-    } else {
-	dahdi_ec_chunk(&hfctmp->ztdev->chans[1], hfctmp->ztdev->chans[1].readchunk, hfctmp->ztdev->chans[1].writechunk);
+static void hfc_bch_tx(struct hfc_card *hfctmp){
+    struct bch *chtmp=&hfctmp->bch;
+    int x;
+
+    for(x=0;x<2;x++)
+	memcpy((void *)(chtmp->tx.c[x].fifo_base+chtmp->tx.z1),hfctmp->ztdev->chans[x].writechunk,DAHDI_CHUNKSIZE);
+    hfc_bch_inc_z(chtmp->tx.z1,DAHDI_CHUNKSIZE);
+    if(chtmp->fill_fifo){
+	chtmp->fill_fifo--;
+    }else if(chtmp->tx.c[0].filled<=1||chtmp->tx.c[1].filled<=1){
+	chtmp->fill_fifo=jitterbuffer;
+	if(chtmp->initialized)
+	    printk(KERN_CRIT "zaphfc[%d]: b channel buffer underrun: %d, %d\n",hfctmp->cardno,chtmp->tx.c[0].filled,chtmp->tx.c[1].filled);
     }
-    return;    
+    if(!chtmp->fill_fifo)
+	for(x=0;x<2;x++)*chtmp->tx.c[x].z1p=chtmp->tx.z1;
 }
 
-
-static void hfc_dtrans(struct hfc_card *hfctmp) {
-    // we are called with irqs disabled from the irq handler
+static void hfc_bch_rx(struct hfc_card *hfctmp){
+    struct bch *chtmp=&hfctmp->bch;
     int x;
-    int count, maxlen, total;
-    unsigned char *f1, *f2, newf1;
-    unsigned short *z1, *z2, newz1;
-    int frames, freebytes;
 
-    if (hfctmp->ztdev->chans[2].bytes2transmit == 0) {
-	return;
+    x=chtmp->rx.c[0].filled-chtmp->rx.c[1].filled;
+    if(abs(x-chtmp->rx.diff)>1){
+	printk(KERN_CRIT "zaphfc[%d]: rx sync changed: %d, %d\n",hfctmp->cardno,chtmp->rx.c[0].filled,chtmp->rx.c[1].filled);
+	chtmp->rx.diff=x;
     }
-
-    f1 = (char *)(hfctmp->fifos + hfc_FIFO_DTX_F1);
-    f2 = (char *)(hfctmp->fifos + hfc_FIFO_DTX_F2);
-    z1 = (unsigned short *)(hfctmp->fifos + hfc_FIFO_DTX_Z1 + (*f1 * 4));
-    z2 = (unsigned short *)(hfctmp->fifos + hfc_FIFO_DTX_Z2 + (*f1 * 4));
-
-    frames = (*f1 - *f2) & hfc_FMASK;
-    if (frames < 0) {
-	frames += hfc_MAX_DFRAMES + 1;
+    if(chtmp->rx.c[0].filled>=DAHDI_CHUNKSIZE&&chtmp->rx.c[1].filled>=DAHDI_CHUNKSIZE){
+	if((chtmp->rx.c[0].filled>=DAHDI_CHUNKSIZE*(jitterbuffer+2)&&chtmp->rx.c[1].filled>=DAHDI_CHUNKSIZE*(jitterbuffer+2))||!chtmp->initialized){
+	    if(chtmp->initialized)
+		printk(KERN_CRIT "zaphfc[%d]: b channel buffer overflow: %d, %d\n",hfctmp->cardno,chtmp->rx.c[0].filled,chtmp->rx.c[1].filled);
+	    hfc_bch_inc_z(chtmp->rx.z2,chtmp->rx.c[0].filled-chtmp->rx.c[0].filled%DAHDI_CHUNKSIZE-DAHDI_CHUNKSIZE);
+	    chtmp->initialized=1;
+	}
+	for(x=0;x<2;x++){
+	    memcpy(hfctmp->ztdev->chans[x].readchunk,(void *)(chtmp->rx.c[x].fifo_base+chtmp->rx.z2),DAHDI_CHUNKSIZE);
+	    dahdi_ec_chunk(&hfctmp->ztdev->chans[x],hfctmp->ztdev->chans[x].readchunk,hfctmp->ztdev->chans[x].writechunk);
+	}
+	hfc_bch_inc_z(chtmp->rx.z2,DAHDI_CHUNKSIZE);
     }
+}
 
-    if (frames >= hfc_MAX_DFRAMES) {
-	printk(KERN_CRIT "zaphfc: dchan tx fifo total number of frames exceeded!\n");
-	return;
-    }
+/*===========================================================================*/
 
-    freebytes = *z2 - *z1;
-    if (freebytes <= 0) {
-	freebytes += hfc_D_FIFO_SIZE;
-    }
-    count = hfctmp->ztdev->chans[2].bytes2transmit;
-
-    total = count;
-    if (freebytes < count) {
-	printk(KERN_CRIT "zaphfc: dchan tx fifo not enough free bytes! (z1=%d, z2=%d)\n",*z1,*z2);
-	return;
-    }
-    
-    newz1 = (*z1 + count) & hfc_ZMASK;
-    newf1 = ((*f1 + 1) & hfc_MAX_DFRAMES) | (hfc_MAX_DFRAMES + 1);	// next frame
-    
-    if (count > 0) {
-	if (debug) {
-    	    printk(KERN_CRIT "zaphfc: card %d TX [ ", hfctmp->cardno);
-	    for (x=0; x<count; x++) {
+static void hfc_dch_tx(struct hfc_card *hfctmp){
+    struct dch *chtmp=&hfctmp->dch;
+    u8 tx_f2_v;
+    u16 x;
+
+    if(hfctmp->ztdev->chans[2].bytes2transmit){
+	if(debug){
+	    printk(KERN_CRIT "zaphfc[%d]: card TX [ ",hfctmp->cardno);
+	    for(x=0;x<hfctmp->ztdev->chans[2].bytes2transmit;x++){
 		printk("%#2x ",hfctmp->dtransbuf[x]);
 	    }
-	    if (hfctmp->ztdev->chans[2].eoftx == 1) {
-		printk("] %d bytes\n", count);
-	    } else {
-		printk("..] %d bytes\n", count);
-	    }
-	}
-	maxlen = hfc_D_FIFO_SIZE - *z1;
-	if (maxlen > count) {
-	    maxlen = count;
+	    printk("] %d bytes\n",hfctmp->ztdev->chans[2].bytes2transmit);
 	}
-	memcpy((char *)(hfctmp->fifos + hfc_FIFO_DTX_ZOFF + *z1),hfctmp->ztdev->chans[2].writechunk, maxlen);
-	count -= maxlen;
-	if (count > 0) {
-	    memcpy((char *)(hfctmp->fifos + hfc_FIFO_DTX_ZOFF),(char *)(hfctmp->ztdev->chans[2].writechunk + maxlen), count);
+	tx_f2_v=*chtmp->tx.f2.p;
+	if(!(tx_f2_v-chtmp->tx.f1.v+hfc_MAX_DFRAMES+1-1)&(hfc_MAX_DFRAMES+1-1)){
+	    printk(KERN_CRIT "zaphfc[%d]: dchan tx fifo total number of frames exceeded!\n",hfctmp->cardno);
+	}else{
+	    if(((*(volatile u16 *)(hfctmp->fifos+hfc_FIFO_DTX_Z2+tx_f2_v*4)-chtmp->tx.f1.z1.v+hfc_D_FIFO_SIZE-1)&(hfc_D_FIFO_SIZE-1))<hfctmp->ztdev->chans[2].bytes2transmit){
+		printk(KERN_CRIT "zaphfc[%d]: dchan tx fifo not enough space for frame!\n",hfctmp->cardno);
+	    }else{
+		chtmp->tx.f1.v=((chtmp->tx.f1.v+1)&hfc_MAX_DFRAMES)|(hfc_MAX_DFRAMES+1);
+		x=min(hfctmp->ztdev->chans[2].bytes2transmit,hfc_D_FIFO_SIZE-chtmp->tx.f1.z1.v);
+		memcpy(hfctmp->fifos+hfc_FIFO_DTX_ZOFF+chtmp->tx.f1.z1.v,hfctmp->ztdev->chans[2].writechunk,x);
+		memcpy(hfctmp->fifos+hfc_FIFO_DTX_ZOFF,hfctmp->ztdev->chans[2].writechunk+x,hfctmp->ztdev->chans[2].bytes2transmit-x);
+		*(volatile u16 *)(hfctmp->fifos+hfc_FIFO_DTX_Z2+chtmp->tx.f1.v*4)=chtmp->tx.f1.z1.v;
+		chtmp->tx.f1.z1.v=(chtmp->tx.f1.z1.v+hfctmp->ztdev->chans[2].bytes2transmit+hfc_D_FIFO_SIZE)&(hfc_D_FIFO_SIZE-1);
+		*(volatile u16 *)(hfctmp->fifos+hfc_FIFO_DTX_Z1+chtmp->tx.f1.v*4)=chtmp->tx.f1.z1.v;
+		*chtmp->tx.f1.p=chtmp->tx.f1.v;
+	    }
 	}
     }
-
-    *z1 = newz1;
-
-    if (hfctmp->ztdev->chans[2].eoftx == 1) {
-	*f1 = newf1;
-	z1 = (unsigned short *)(hfctmp->fifos + hfc_FIFO_DTX_Z1 + (*f1 * 4));
-	*z1 = newz1;
-	hfctmp->ztdev->chans[2].eoftx = 0;
-    }
-//    printk(KERN_CRIT "zaphfc: dchan tx fifo (f1=%d, f2=%d, z1=%d, z2=%d)\n",(*f1) & hfc_FMASK,(*f2) & hfc_FMASK, *z1, *z2);
-    return;    
 }
 
-/* receive a complete hdlc frame, skip broken or short frames */
-static void hfc_drec(struct hfc_card *hfctmp) {
-    int count=0, maxlen=0, framelen=0;
-    unsigned char *f1, *f2, *crcstat;
-    unsigned short *z1, *z2, oldz2, newz2;
+static void hfc_dch_rx(struct hfc_card *hfctmp){
+    struct dch *chtmp=&hfctmp->dch;
+    u16 size;
 
     hfctmp->ztdev->chans[2].bytes2receive=0;
-    hfctmp->ztdev->chans[2].eofrx = 0;
-
-    /* put the received data into the DAHDI buffer
-       we'll call dahdi_receive() later when the timer fires. */
-    f1 = (char *)(hfctmp->fifos + hfc_FIFO_DRX_F1);
-    f2 = (char *)(hfctmp->fifos + hfc_FIFO_DRX_F2);
-
-    if (*f1 == *f2) return; /* nothing received, strange eh? */
-
-    z1 = (unsigned short *)(hfctmp->fifos + hfc_FIFO_DRX_Z1 + (*f2 * 4));
-    z2 = (unsigned short *)(hfctmp->fifos + hfc_FIFO_DRX_Z2 + (*f2 * 4));
-    
-    /* calculate length of frame, including 2 bytes CRC and 1 byte STAT */
-    count = *z1 - *z2;
-    
-    if (count < 0) { 
-	count += hfc_D_FIFO_SIZE; /* ring buffer wrapped */
-    }
-    count++;
-    framelen = count;
-
-    crcstat = (char *)(hfctmp->fifos + hfc_FIFO_DRX_ZOFF + *z1);
-
-    if ((framelen < 4) || (*crcstat != 0x0)) {
-	/* the frame is too short for a valid HDLC frame or the CRC is borked */
-	printk(KERN_CRIT "zaphfc: empty HDLC frame or bad CRC received (framelen = %d, stat = %#x, card = %d).\n", framelen, *crcstat, hfctmp->cardno);
-	oldz2 = *z2;
-	*f2 = ((*f2 + 1) & hfc_MAX_DFRAMES) | (hfc_MAX_DFRAMES + 1);	/* NEXT!!! */
-        // recalculate z2, because Z2 is a function of F2 Z2(F2) and we INCed F2!!!
-	z2 = (unsigned short *)(hfctmp->fifos + hfc_FIFO_DRX_Z2 + (*f2 * 4));
-	*z2 = (oldz2 + framelen) & hfc_ZMASK;
-	hfctmp->drecinframe = 0;
-	hfctmp->regs.int_drec--;
-	/* skip short or broken frames */
-        hfctmp->ztdev->chans[2].bytes2receive = 0; 
-	return;
-    }
-
-    count -= 1;	/* strip STAT */
-    hfctmp->ztdev->chans[2].eofrx = 1;
-
-    if (count + *z2 <= hfc_D_FIFO_SIZE) {
-	maxlen = count;
-    } else {
-	maxlen = hfc_D_FIFO_SIZE - *z2;
+    hfctmp->ztdev->chans[2].eofrx=0;
+    if(*chtmp->rx.f1.p==chtmp->rx.f2.v){
+	hfctmp->regs.int_drec=0;
+    }else{
+	size=((*(volatile u16 *)(hfctmp->fifos+hfc_FIFO_DRX_Z1+chtmp->rx.f2.v*4)-chtmp->rx.f2.z2.v+hfc_D_FIFO_SIZE)&(hfc_D_FIFO_SIZE-1))+1;
+	if(size<4){
+	    printk(KERN_CRIT "zaphfc[%d]: empty HDLC frame received.\n",hfctmp->cardno);
+	}else{
+	    u16 x=min(size,(u16)(hfc_D_FIFO_SIZE-chtmp->rx.f2.z2.v));
+	    memcpy(hfctmp->drecbuf,hfctmp->fifos+hfc_FIFO_DRX_ZOFF+chtmp->rx.f2.z2.v,x);
+	    memcpy(hfctmp->drecbuf+x,hfctmp->fifos+hfc_FIFO_DRX_ZOFF,size-x);
+	    if(hfctmp->drecbuf[size-1]){
+		printk(KERN_CRIT "zaphfc[%d]: received d channel frame with bad CRC.\n",hfctmp->cardno);
+	    }else{
+		hfctmp->ztdev->chans[2].bytes2receive=size-1;
+		hfctmp->ztdev->chans[2].eofrx=1;
+	    }
+	}
+	chtmp->rx.f2.z2.v=(chtmp->rx.f2.z2.v+size)&(hfc_D_FIFO_SIZE-1);
+	chtmp->rx.f2.v=((chtmp->rx.f2.v+1)&hfc_MAX_DFRAMES)|(hfc_MAX_DFRAMES+1);
     }
-
-    /* copy first part */
-    memcpy(hfctmp->drecbuf, (char *)(hfctmp->fifos + hfc_FIFO_DRX_ZOFF + *z2), maxlen);
-    hfctmp->ztdev->chans[2].bytes2receive += maxlen; 
-    
-    count -= maxlen;
-    if (count > 0) {
-	/* ring buffer wrapped, copy rest from start of d fifo */
-	memcpy(hfctmp->drecbuf + maxlen, (char *)(hfctmp->fifos + hfc_FIFO_DRX_ZOFF), count);
-	hfctmp->ztdev->chans[2].bytes2receive += count; 
-    }
-
-    /* frame read */
-    oldz2 = *z2;
-    newz2 = (oldz2 + framelen) & hfc_ZMASK;
-    *f2 = ((*f2 + 1) & hfc_MAX_DFRAMES) | (hfc_MAX_DFRAMES + 1);	/* NEXT!!! */
-    /* recalculate z2, because Z2 is a function of F2 Z2(F2) and we INCed F2!!! */
-    z2 = (unsigned short *)(hfctmp->fifos + hfc_FIFO_DRX_Z2 + (*f2 * 4));
-    *z2 = newz2;
-    hfctmp->drecinframe = 0;
-    hfctmp->regs.int_drec--; 
 }
 
-#ifndef RTAITIMING
 DAHDI_IRQ_HANDLER(hfc_interrupt) {
     struct hfc_card *hfctmp = dev_id;
-    unsigned long flags = 0;
-    unsigned char stat;
-#else
-static void hfc_service(struct hfc_card *hfctmp) {
-#endif
+    struct hfc_card *hfctmp2;
     struct dahdi_hfc *zthfc;
-    unsigned char s1, s2, l1state;
+    unsigned char stat, s1, s2, l1state;
+    unsigned long flags = 0;
+    unsigned long flags2 = 0;
     int x;
 
     if (!hfctmp) {
-#ifndef RTAITIMING
-		return IRQ_NONE;
-#else
-	/* rtai */
-	return;
-#endif
+	    return IRQ_NONE;
     }
 
     if (!hfctmp->pci_io) {
 	    printk(KERN_WARNING "%s: IO-mem disabled, cannot handle interrupt\n",
 		   __FUNCTION__);
-#ifndef RTAITIMING
 	    return IRQ_NONE;
-#else
-	/* rtai */
-	return;
-#endif
     }
     
-    /*	we assume a few things in this irq handler:
-	- the hfc-pci will only generate "timer" irqs (proc/non-proc)
-	- we need to use every 8th IRQ (to generate 1khz timing)
-	OR
-	- if we use rtai for timing the hfc-pci will not generate ANY irq,
-	  instead rtai will call this "fake" irq with a 1khz realtime timer. :)
-	- rtai will directly service the card, not like it used to by triggering
-	  the linux irq
-    */
-
-#ifndef RTAITIMING
     spin_lock_irqsave(&hfctmp->lock, flags);
     stat = hfc_inb(hfctmp, hfc_STATUS);
-
     if ((stat & hfc_STATUS_ANYINT) == 0) {
         // maybe we are sharing the irq
 	spin_unlock_irqrestore(&hfctmp->lock,flags);
 	return IRQ_NONE;
     }
-#endif
 
     s1 = hfc_inb(hfctmp, hfc_INT_S1);
     s2 = hfc_inb(hfctmp, hfc_INT_S2); 
@@ -611,18 +457,10 @@
 		}
 		switch (l1state) {
 		    case 3:
-#ifdef RTAITIMING
-			sprintf(zthfc->span.desc, "HFC-S PCI A ISDN card %d [NT] layer 1 ACTIVATED (G%d) [realtime]", hfctmp->cardno, l1state);
-#else
 			sprintf(zthfc->span.desc, "HFC-S PCI A ISDN card %d [NT] layer 1 ACTIVATED (G%d)", hfctmp->cardno, l1state);
-#endif
 			break;
 		    default:
-#ifdef RTAITIMING
-			sprintf(zthfc->span.desc, "HFC-S PCI A ISDN card %d [NT] layer 1 DEACTIVATED (G%d) [realtime]", hfctmp->cardno, l1state);
-#else
 			sprintf(zthfc->span.desc, "HFC-S PCI A ISDN card %d [NT] layer 1 DEACTIVATED (G%d)", hfctmp->cardno, l1state);
-#endif
 		}
 		if (l1state == 2) {
 		    hfc_outb(hfctmp, hfc_STATES, hfc_STATES_ACTIVATE | hfc_STATES_DO_ACTION | hfc_STATES_NT_G2_G3);
@@ -636,18 +474,10 @@
 		}
 		switch (l1state) {
 		    case 7:
-#ifdef RTAITIMING
-			sprintf(zthfc->span.desc, "HFC-S PCI A ISDN card %d [TE] layer 1 ACTIVATED (F%d) [realtime]", hfctmp->cardno, l1state);
-#else
 			sprintf(zthfc->span.desc, "HFC-S PCI A ISDN card %d [TE] layer 1 ACTIVATED (F%d)", hfctmp->cardno, l1state);
-#endif
 			break;
 		    default:
-#ifdef RTAITIMING
-			sprintf(zthfc->span.desc, "HFC-S PCI A ISDN card %d [TE] layer 1 DEACTIVATED (F%d) [realtime]", hfctmp->cardno, l1state);
-#else
 			sprintf(zthfc->span.desc, "HFC-S PCI A ISDN card %d [TE] layer 1 DEACTIVATED (F%d)", hfctmp->cardno, l1state);
-#endif
 		}
 		if (l1state == 3) {
 		    hfc_outb(hfctmp, hfc_STATES, hfc_STATES_DO_ACTION | hfc_STATES_ACTIVATE);
@@ -657,7 +487,7 @@
 	}
 	if (s1 & hfc_INTS_DREC) {
 	    // D chan RX (bit 5)
-	    hfctmp->regs.int_drec++;
+	    hfctmp->regs.int_drec = 1;
 	    // mr. zapata there is something for you!
 	//    printk(KERN_CRIT "d chan rx\n");		    
 	}
@@ -678,14 +508,10 @@
 	    // B1 chan TX (bit 0)
 	}
     }
-#ifdef RTAITIMING
-    /* fake an irq */
-    s2 |= hfc_M2_PROC_TRANS;
-#endif
     if (s2 != 0) {
 	if (s2 & hfc_M2_PMESEL) {
 	    // kaboom irq (bit 7)
-	    printk(KERN_CRIT "zaphfc: sync lost, pci performance too low. you might have some cpu throtteling enabled.\n");
+	    //printk(KERN_CRIT "zaphfc: sync lost, pci performance too low. you might have some cpu throtteling enabled.\n");
 	}
 	if (s2 & hfc_M2_GCI_MON_REC) {
 	    // RxR monitor channel (bit 2)
@@ -693,32 +519,31 @@
 	if (s2 & hfc_M2_GCI_I_CHG) {
 	    // GCI I-change  (bit 1)
 	}
-	if (s2 & hfc_M2_PROC_TRANS) {
+	if((s2&hfc_M2_PROC_TRANS)&&(hfctmp->cardno==timer_card)){
 	    // processing/non-processing transition  (bit 0)
-	    hfctmp->ticks++;
-#ifndef RTAITIMING
-	    if (hfctmp->ticks > 7) {
-		// welcome to DAHDI timing :)
-#endif
-	    	hfctmp->ticks = 0;
-
-		if (hfctmp->ztdev->span.flags & DAHDI_FLAG_RUNNING) {
+	hfctmp2=hfctmp;
+	hfctmp=hfc_dev_list;
+	while(hfctmp){
+	    if(hfctmp->active){
+	    if(hfctmp!=hfctmp2)spin_lock_irqsave(&hfctmp->lock, flags2);
+	    if(hfc_bch_check(hfctmp)){
+    if (hfctmp->ztdev->span.flags & DAHDI_FLAG_RUNNING) {
 		    // clear dchan buffer
+	//	    memset(hfctmp->drecbuf, 0x0, sizeof(hfctmp->drecbuf));
+
 		    hfctmp->ztdev->chans[2].bytes2transmit = 0;
 		    hfctmp->ztdev->chans[2].maxbytes2transmit = hfc_D_FIFO_SIZE;
 
 		    dahdi_transmit(&(hfctmp->ztdev->span));
 
-		    hfc_btrans(hfctmp,1);
-		    hfc_btrans(hfctmp,2);
-		    hfc_dtrans(hfctmp);
+		    hfc_bch_tx(hfctmp);
+		    hfc_dch_tx(hfctmp);
 		}
 
-		hfc_brec(hfctmp,1);
-		hfc_brec(hfctmp,2);
-		if (hfctmp->regs.int_drec > 0) {
+		hfc_bch_rx(hfctmp);
+		if (hfctmp->regs.int_drec) {
 		    // dchan data to read
-		    hfc_drec(hfctmp);
+		    hfc_dch_rx(hfctmp);
 		    if (hfctmp->ztdev->chans[2].bytes2receive > 0) {
 			    if (debug) {
     				printk(KERN_CRIT "zaphfc: card %d RX [ ", hfctmp->cardno);
@@ -743,17 +568,16 @@
 		if (hfctmp->ztdev->span.flags & DAHDI_FLAG_RUNNING) {
 		    dahdi_receive(&(hfctmp->ztdev->span));
 		}
-		
-#ifndef RTAITIMING
 	    }
-#endif
+	    if(hfctmp!=hfctmp2)spin_unlock_irqrestore(&hfctmp->lock,flags2);
+	    }
+	    hfctmp=hfctmp->next;
+	}
+	hfctmp=hfctmp2;
 	}
-
     }
-#ifndef RTAITIMING
     spin_unlock_irqrestore(&hfctmp->lock,flags);
-	return IRQ_RETVAL(1);
-#endif
+    return IRQ_RETVAL(1);
 }
 
 
@@ -802,22 +626,22 @@
     }
     alreadyrunning = span->flags & DAHDI_FLAG_RUNNING;
     
-    if (!alreadyrunning) {
-	span->chans[2]->flags &= ~DAHDI_FLAG_HDLC;
-	span->chans[2]->flags |= DAHDI_FLAG_BRIDCHAN;
-	
-	span->flags |= DAHDI_FLAG_RUNNING;
+    if (alreadyrunning) return 0;
 
-	hfctmp->ticks = -2;
-	hfctmp->clicks = 0;
-	hfctmp->regs.fifo_en = hfc_FIFOEN_D | hfc_FIFOEN_B1 | hfc_FIFOEN_B2;
-        hfc_outb(hfctmp, hfc_FIFO_EN, hfctmp->regs.fifo_en);
-    } else {
-	return 0;
-    }
+    span->chans[2]->flags &= ~DAHDI_FLAG_HDLC;
+    span->chans[2]->flags |= DAHDI_FLAG_BRIDCHAN;
+
+    span->flags |= DAHDI_FLAG_RUNNING;
+
+    hfctmp->ticks = -2;
+    hfctmp->regs.fifo_en = hfc_FIFOEN_D | hfc_FIFOEN_B1 | hfc_FIFOEN_B2;
+    hfc_outb(hfctmp, hfc_FIFO_EN, hfctmp->regs.fifo_en);
+
+    hfc_bch_init(hfctmp);
 
     // drivers, start engines!
     hfc_outb(hfctmp, hfc_STATES, hfc_STATES_DO_ACTION | hfc_STATES_ACTIVATE);
+    hfctmp->active=1;
     return 0;
 }
 
@@ -847,17 +671,9 @@
 
     sprintf(zthfc->span.name, "ZTHFC%d", hfc_dev_count + 1);
     if (hfctmp->regs.nt_mode == 1) {
-#ifdef RTAITIMING
-	sprintf(zthfc->span.desc, "HFC-S PCI A ISDN card %d [NT] [realtime]", hfc_dev_count + 1);
-#else
 	sprintf(zthfc->span.desc, "HFC-S PCI A ISDN card %d [NT]", hfc_dev_count + 1);
-#endif
     } else {
-#ifdef RTAITIMING
-	sprintf(zthfc->span.desc, "HFC-S PCI A ISDN card %d [TE] [realtime]", hfc_dev_count + 1);
-#else
 	sprintf(zthfc->span.desc, "HFC-S PCI A ISDN card %d [TE]", hfc_dev_count + 1);
-#endif
     }
 
     zthfc->span.spanconfig = zthfc_spanconfig;
@@ -897,32 +713,6 @@
     return 0;
 }
 
-#ifdef RTAITIMING
-#define TICK_PERIOD  1000000
-#define TICK_PERIOD2 1000000000
-#define TASK_PRIORITY 1
-#define STACK_SIZE 10000
-
-static RT_TASK rt_task;
-static struct hfc_card *rtai_hfc_list[hfc_MAX_CARDS];
-static unsigned char rtai_hfc_counter = 0;
-
-static void rtai_register_hfc(struct hfc_card *hfctmp) {
-    rtai_hfc_list[rtai_hfc_counter++] = hfctmp;
-}
-
-static void rtai_loop(int t) {
-    int i=0;
-    for (;;) {
-	for (i=0; i < rtai_hfc_counter; i++) {
-	    if (rtai_hfc_list[i] != NULL)
-		hfc_service(rtai_hfc_list[i]);
-	}
-        rt_task_wait_period();
-    }
-}
-#endif
-
 int hfc_findCards(int pcivendor, int pcidevice, char *vendor_name, char *card_name) {
     struct pci_dev *tmp;
     struct hfc_card *hfctmp = NULL;
@@ -938,9 +728,9 @@
 	}
 	pci_set_master(tmp);
 
-	hfctmp = kmalloc(sizeof(struct hfc_card), GFP_KERNEL);
+	hfctmp = vmalloc(sizeof(struct hfc_card));
 	if (!hfctmp) {
-	    printk(KERN_WARNING "zaphfc: unable to kmalloc!\n");
+	    printk(KERN_WARNING "zaphfc: unable to vmalloc!\n");
 	    pci_disable_device(tmp);
 	    multi_hfc = NULL;
 	    return -ENOMEM;
@@ -948,6 +738,7 @@
 	memset(hfctmp, 0x0, sizeof(struct hfc_card));
 	spin_lock_init(&hfctmp->lock);
 	
+	hfctmp->active=0;
 	hfctmp->pcidev = tmp;
 	hfctmp->pcibus = tmp->bus->number;
 	hfctmp->pcidevfn = tmp->devfn; 
@@ -961,49 +752,39 @@
 	hfctmp->pci_io = (char *) tmp->resource[1].start;
 	if (!hfctmp->pci_io) {
 	    printk(KERN_WARNING "zaphfc: no iomem!\n");
-	    kfree(hfctmp);
+	    vfree(hfctmp);
 	    pci_disable_device(tmp);
 	    multi_hfc = NULL;
 	    return -1;
 	}
-	
-	hfctmp->fifomem = kmalloc(65536, GFP_KERNEL);
-	if (!hfctmp->fifomem) {
-	    printk(KERN_WARNING "zaphfc: unable to kmalloc fifomem!\n");
-	    kfree(hfctmp);
+
+	hfctmp->fifos=(void *)__get_free_pages(GFP_KERNEL,log2(hfc_FIFO_MEM_SIZE_PAGES));
+	if (!hfctmp->fifos) {
+	    printk(KERN_WARNING "zaphfc: unable to __get_free_pages fifomem!\n");
+	    vfree(hfctmp);
 	    pci_disable_device(tmp);
 	    multi_hfc = NULL;
 	    return -ENOMEM;
 	} else {
-	    memset(hfctmp->fifomem, 0x0, 65536);
-	    hfctmp->fifos = (void *)(((ulong) hfctmp->fifomem) & ~0x7FFF) + 0x8000;
 	    pci_write_config_dword(hfctmp->pcidev, 0x80, (u_int) virt_to_bus(hfctmp->fifos));
 	    hfctmp->pci_io = ioremap((ulong) hfctmp->pci_io, 256);
 	}
 
-#ifdef RTAITIMING
-	/* we need no stinking irq */
-	hfctmp->irq = 0;
-#else
 	if (request_irq(hfctmp->irq, &hfc_interrupt, IRQF_SHARED, "zaphfc", hfctmp)) {
 	    printk(KERN_WARNING "zaphfc: unable to register irq\n");
-	    kfree(hfctmp->fifomem);
-	    kfree(hfctmp);
+	    free_pages((unsigned long)hfctmp->fifos,log2(hfc_FIFO_MEM_SIZE_PAGES));
+	    vfree(hfctmp);
 	    iounmap((void *) hfctmp->pci_io);
 	    pci_disable_device(tmp);
 	    multi_hfc = NULL;
 	    return -EIO;
 	}
-#endif
 
-#ifdef RTAITIMING
-	rtai_register_hfc(hfctmp);
-#endif
 	printk(KERN_INFO
-		       "zaphfc: %s %s configured at mem %lx fifo %lx(%#x) IRQ %d HZ %d\n",
+		       "zaphfc: %s %s configured at mem %#x fifo %#x(%#x) IRQ %d HZ %d\n",
 			vendor_name, card_name,
-		       (unsigned long) hfctmp->pci_io,
-		       (unsigned long) hfctmp->fifos,
+		       (u_int) hfctmp->pci_io,
+		       (u_int) hfctmp->fifos,
 		       (u_int) virt_to_bus(hfctmp->fifos),
 		       hfctmp->irq, HZ); 
 	pci_write_config_word(hfctmp->pcidev, PCI_COMMAND, PCI_COMMAND_MEMORY);	// enable memio
@@ -1020,11 +801,21 @@
 	    hfctmp->regs.nt_mode = 0;
 	}
 
-	zthfc = kmalloc(sizeof(struct dahdi_hfc),GFP_KERNEL);
+	if(sync_slave&(1<<hfc_dev_count)){
+	    printk(KERN_INFO "zaphfc: Card %d configured for slave mode\n",hfc_dev_count);
+	    hfctmp->regs.mst_mode=hfc_MST_MODE_SLAVE|hfc_MST_MODE_F0_LONG_DURATION;
+	    hfctmp->regs.mst_emod=hfc_MST_EMOD_SLOW_CLOCK_ADJ;
+	}else{
+	    printk(KERN_INFO "zaphfc: Card %d configured for master mode\n",hfc_dev_count);
+	    hfctmp->regs.mst_mode=hfc_MST_MODE_MASTER|hfc_MST_MODE_F0_LONG_DURATION;
+	    hfctmp->regs.mst_emod=0;
+	}
+
+	zthfc = vmalloc(sizeof(struct dahdi_hfc));
 	if (!zthfc) {
-	    printk(KERN_CRIT "zaphfc: unable to kmalloc!\n");
+	    printk(KERN_CRIT "zaphfc: unable to vmalloc!\n");
 	    hfc_shutdownCard(hfctmp);
-	    kfree(hfctmp);
+	    vfree(hfctmp);
 	    multi_hfc = NULL;
 	    return -ENOMEM;
 	}
@@ -1050,7 +841,6 @@
 	memset(hfctmp->btransbuf[1], 0x0, sizeof(hfctmp->btransbuf[1]));
 	hfctmp->ztdev->chans[1].writechunk = hfctmp->btransbuf[1];
 
-
 	hfc_registerCard(hfctmp);
 	hfc_resetCard(hfctmp);
 	tmp = pci_get_device(pcivendor, pcidevice, multi_hfc);
@@ -1058,58 +848,42 @@
     return 0;
 }
 
-
-
 int init_module(void) {
     int i = 0;
-#ifdef RTAITIMING
-    RTIME tick_period;
-    for (i=0; i < hfc_MAX_CARDS; i++) {
-	rtai_hfc_list[i] = NULL;
+    if(jitterbuffer<1){
+	printk(KERN_INFO "zaphfc: invalid jitterbuffer size specified: %d - changing to minimum of 1\n",jitterbuffer);
+	jitterbuffer=1;
+    }else if(jitterbuffer>500){
+	printk(KERN_INFO "zaphfc: invalid jitterbuffer size specified: %d - changing to maximum of 500\n",jitterbuffer);
+	jitterbuffer=500;
     }
-    rt_set_periodic_mode();
-#endif
-    i = 0;
+    printk(KERN_INFO "zaphfc: jitterbuffer size: %d\n",jitterbuffer);
     while (id_list[i].vendor_id) {
 	multi_hfc = NULL;
 	hfc_findCards(id_list[i].vendor_id, id_list[i].device_id, id_list[i].vendor_name, id_list[i].card_name);
 	i++;
     }
-#ifdef RTAITIMING
-    for (i=0; i < hfc_MAX_CARDS; i++) {
-        if (rtai_hfc_list[i]) {
-	    printk(KERN_INFO
-		       "zaphfc: configured %d at mem %#x fifo %#x(%#x) for realtime servicing\n",
-			rtai_hfc_list[i]->cardno,
-		       (u_int) rtai_hfc_list[i]->pci_io,
-		       (u_int) rtai_hfc_list[i]->fifos,
-		       (u_int) virt_to_bus(rtai_hfc_list[i]->fifos));
-
-	}
-    }
-    rt_task_init(&rt_task, rtai_loop, 1, STACK_SIZE, TASK_PRIORITY, 0, 0);
-    tick_period = start_rt_timer(nano2count(TICK_PERIOD));
-    rt_task_make_periodic(&rt_task, rt_get_time() + tick_period, tick_period);
-#endif
     printk(KERN_INFO "zaphfc: %d hfc-pci card(s) in this box.\n", hfc_dev_count);
     return 0;
 }
 
 void cleanup_module(void) {
     struct hfc_card *tmpcard;
-#ifdef RTAITIMING
-    stop_rt_timer();
-    rt_task_delete(&rt_task);
-#endif
+
     printk(KERN_INFO "zaphfc: stop\n");
 //    spin_lock(&registerlock);
+    tmpcard=hfc_dev_list;
+    while(tmpcard){
+	hfc_shutdownCard1(tmpcard);
+	tmpcard=tmpcard->next;
+    }
     while (hfc_dev_list != NULL) {
 	if (hfc_dev_list == NULL) break;
-	hfc_shutdownCard(hfc_dev_list);
+	hfc_shutdownCard2(hfc_dev_list);
 	tmpcard = hfc_dev_list;
 	hfc_dev_list = hfc_dev_list->next;
 	if (tmpcard != NULL) {
-	    kfree(tmpcard);
+	    vfree(tmpcard);
 	    tmpcard = NULL;
 	    printk(KERN_INFO "zaphfc: freed one card.\n");
 	}
@@ -1119,8 +893,11 @@
 #endif
 
 
-module_param(modes, int, 0600);
+module_param(modes, int, 0400);
 module_param(debug, int, 0600);
+module_param(sync_slave, int, 0400);
+module_param(timer_card, int, 0400);
+module_param(jitterbuffer, int, 0400);
 
 MODULE_DESCRIPTION("HFC-S PCI A Zaptel Driver");
 MODULE_AUTHOR("Klaus-Peter Junghanns <kpj@junghanns.net>");
