diff -urN dahdi-linux-complete-2.4.1.2+2.4.1/linux/drivers/dahdi/Kbuild dahdi-linux-complete-2.4.1.2+2.4.1-new/linux/drivers/dahdi/Kbuild
--- dahdi-linux-complete-2.4.1.2+2.4.1/linux/drivers/dahdi/Kbuild	2011-08-08 18:29:11.000000000 -0500
+++ dahdi-linux-complete-2.4.1.2+2.4.1-new/linux/drivers/dahdi/Kbuild	2011-08-08 18:31:46.000000000 -0500
@@ -13,6 +13,7 @@
 obj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_WCTDM)		+= wctdm.o
 obj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_VOICEBUS)		+= voicebus/
 obj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_WCB4XXP)		+= wcb4xxp/
+obj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_ZAPHFC)		+= zaphfc/
 
 obj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_OPVXD115)		+= opvxd115/
 obj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_OPVXA1200)		+= opvxa1200/
diff -urN dahdi-linux-complete-2.4.1.2+2.4.1/linux/drivers/dahdi/zaphfc/base.c dahdi-linux-complete-2.4.1.2+2.4.1-new/linux/drivers/dahdi/zaphfc/base.c
--- dahdi-linux-complete-2.4.1.2+2.4.1/linux/drivers/dahdi/zaphfc/base.c	1969-12-31 19:00:00.000000000 -0500
+++ dahdi-linux-complete-2.4.1.2+2.4.1-new/linux/drivers/dahdi/zaphfc/base.c	2011-08-08 18:31:46.000000000 -0500
@@ -0,0 +1,1712 @@
+/*
+ * zaphfc.c - Dahdi driver for HFC-S PCI A based ISDN BRI cards
+ *
+ * Dahdi rewrite in hardhdlc mode
+ * Jose A. Deniz <odicha@hotmail.com>
+ *
+ * Copyright (C) 2009, Jose A. Deniz
+ * Copyright (C) 2006, headiisue GmbH; Jens Wilke
+ * Copyright (C) 2004 Daniele Orlandi
+ * Copyright (C) 2002, 2003, 2004, Junghanns.NET GmbH
+ *
+ * Jens Wilke <jw_vzaphfc@headissue.com>
+ *
+ * Original author of this code is
+ * Daniele "Vihai" Orlandi <daniele@orlandi.com>
+ *
+ * Major rewrite of the driver made by
+ * Klaus-Peter Junghanns <kpj@junghanns.net>
+ *
+ * This program is free software and may be modified and
+ * distributed under the terms of the GNU Public License.
+ *
+ * Please read the README file for important infos.
+ */
+
+#include <linux/spinlock.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32))
+#include <linux/sched.h>
+#endif
+#include <linux/proc_fs.h>
+#include <linux/if_arp.h>
+
+#include <dahdi/kernel.h>
+
+#include "zaphfc.h"
+#include "fifo.h"
+
+#if CONFIG_PCI
+
+#define DAHDI_B1 0
+#define DAHDI_B2 1
+#define DAHDI_D 2
+
+#define D 0
+#define B1 1
+#define B2 2
+
+/*
+ * Mode Te for all
+ */
+static int modes;
+static int nt_modes[hfc_MAX_BOARDS];
+static int nt_modes_count;
+static int force_l1_up;
+static struct proc_dir_entry *hfc_proc_zaphfc_dir;
+
+#ifdef DEBUG
+int debug_level;
+#endif
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+#ifndef TRUE
+#define TRUE (!FALSE)
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30)
+#define	SET_PROC_DIRENTRY_OWNER(p)	do { (p)->owner = THIS_MODULE; } while(0);
+#else
+#define	SET_PROC_DIRENTRY_OWNER(p)	do { } while(0);
+#endif
+
+static struct pci_device_id hfc_pci_ids[] = {
+	{PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_2BD0,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B000,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B006,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B007,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B008,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B009,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B00A,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B00B,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B00C,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B100,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_ABOCOM, PCI_DEVICE_ID_ABOCOM_2BD1,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_ASUSTEK, PCI_DEVICE_ID_ASUSTEK_0675,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_BERKOM, PCI_DEVICE_ID_BERKOM_T_CONCEPT,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_BERKOM, PCI_DEVICE_ID_BERKOM_A1T,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_ANIGMA, PCI_DEVICE_ID_ANIGMA_MC145575,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_ZOLTRIX, PCI_DEVICE_ID_ZOLTRIX_2BD0,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_DIGI_DF_M_IOM2_E,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_DIGI_DF_M_E,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_DIGI_DF_M_IOM2_A,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_DIGI_DF_M_A,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_SITECOM, PCI_DEVICE_ID_SITECOM_3069,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{0,}
+};
+
+MODULE_DEVICE_TABLE(pci, hfc_pci_ids);
+
+static int __devinit hfc_probe(struct pci_dev *dev
+			, const struct pci_device_id *ent);
+static void __devexit hfc_remove(struct pci_dev *dev);
+
+static struct pci_driver hfc_driver = {
+	.name     = hfc_DRIVER_NAME,
+	.id_table = hfc_pci_ids,
+	.probe    = hfc_probe,
+	.remove   = hfc_remove,
+};
+
+/******************************************
+ * HW routines
+ ******************************************/
+
+static void hfc_softreset(struct hfc_card *card)
+{
+	printk(KERN_INFO hfc_DRIVER_PREFIX
+		"card %d: "
+		"resetting\n",
+		card->cardnum);
+
+/*
+ * Softreset procedure. Put it on, wait and off again
+ */
+	hfc_outb(card, hfc_CIRM, hfc_CIRM_RESET);
+	udelay(6);
+	hfc_outb(card, hfc_CIRM, 0);
+
+	set_current_state(TASK_UNINTERRUPTIBLE);
+	schedule_timeout((hfc_RESET_DELAY * HZ) / 1000);
+}
+
+static void hfc_resetCard(struct hfc_card *card)
+{
+	card->regs.m1 = 0;
+	hfc_outb(card, hfc_INT_M1, card->regs.m1);
+
+	card->regs.m2 = 0;
+	hfc_outb(card, hfc_INT_M2, card->regs.m2);
+
+	hfc_softreset(card);
+
+	card->regs.trm = 0;
+	hfc_outb(card, hfc_TRM, card->regs.trm);
+
+	/*
+	 * Select the non-capacitive line mode for the S/T interface
+	 */
+	card->regs.sctrl = hfc_SCTRL_NONE_CAP;
+
+	if (card->nt_mode) {
+		/*
+		 * ST-Bit delay for NT-Mode
+		 */
+		hfc_outb(card, hfc_CLKDEL, hfc_CLKDEL_NT);
+
+		card->regs.sctrl |= hfc_SCTRL_MODE_NT;
+	} else {
+		/*
+		 * ST-Bit delay for TE-Mode
+		 */
+		hfc_outb(card, hfc_CLKDEL, hfc_CLKDEL_TE);
+
+		card->regs.sctrl |= hfc_SCTRL_MODE_TE;
+	}
+
+	hfc_outb(card, hfc_SCTRL, card->regs.sctrl);
+
+	/*
+	 * S/T Auto awake
+	 */
+	card->regs.sctrl_e = hfc_SCTRL_E_AUTO_AWAKE;
+	hfc_outb(card, hfc_SCTRL_E, card->regs.sctrl_e);
+
+	/*
+	 * No B-channel enabled at startup
+	 */
+	card->regs.sctrl_r = 0;
+	hfc_outb(card, hfc_SCTRL_R, card->regs.sctrl_r);
+
+	/*
+	 * HFC Master Mode
+	 */
+	hfc_outb(card, hfc_MST_MODE, hfc_MST_MODE_MASTER);
+
+	/*
+	 * Connect internal blocks
+	 */
+	card->regs.connect =
+		hfc_CONNECT_B1_HFC_from_ST |
+		hfc_CONNECT_B1_ST_from_HFC |
+		hfc_CONNECT_B1_GCI_from_HFC |
+		hfc_CONNECT_B2_HFC_from_ST |
+		hfc_CONNECT_B2_ST_from_HFC |
+		hfc_CONNECT_B2_GCI_from_HFC;
+	hfc_outb(card, hfc_CONNECT, card->regs.connect);
+
+	/*
+	 * All bchans are HDLC by default, not useful, actually
+	 * since mode is set during open()
+	 */
+	hfc_outb(card, hfc_CTMT, 0);
+
+	/*
+	 * bit order
+	 */
+	hfc_outb(card, hfc_CIRM, 0);
+
+	/*
+	 * Enable D-rx FIFO. At least one FIFO must be enabled (by specs)
+	 */
+	card->regs.fifo_en = hfc_FIFOEN_DRX;
+	hfc_outb(card, hfc_FIFO_EN, card->regs.fifo_en);
+
+	card->late_irqs = 0;
+
+	/*
+	 * Clear already pending ints
+	 */
+	hfc_inb(card, hfc_INT_S1);
+	hfc_inb(card, hfc_INT_S2);
+
+	/*
+	 * Enable IRQ output
+	 */
+	card->regs.m1 = hfc_INTS_DREC | hfc_INTS_L1STATE | hfc_INTS_TIMER;
+	hfc_outb(card, hfc_INT_M1, card->regs.m1);
+
+	card->regs.m2 = hfc_M2_IRQ_ENABLE;
+	hfc_outb(card, hfc_INT_M2, card->regs.m2);
+
+	/*
+	 * Unlocks the states machine
+	 */
+	hfc_outb(card, hfc_STATES, 0);
+
+	/*
+	 * There's no need to explicitly activate L1 now.
+	 * Activation is managed inside the interrupt routine.
+	 */
+}
+
+static void hfc_update_fifo_state(struct hfc_card *card)
+{
+	/*
+	 * I'm not sure if irqsave is needed but there could be a race
+	 * condition since hfc_update_fifo_state could be called from
+	 * both the IRQ handler and the *_(open|close) functions
+	 */
+
+	unsigned long flags;
+	spin_lock_irqsave(&card->chans[B1].lock, flags);
+	if (!card->fifo_suspended &&
+		(card->chans[B1].status == open_framed ||
+		card->chans[B1].status == open_voice)) {
+
+		if (!(card->regs.fifo_en & hfc_FIFOEN_B1RX)) {
+			card->regs.fifo_en |= hfc_FIFOEN_B1RX;
+			hfc_clear_fifo_rx(&card->chans[B1].rx);
+		}
+
+		if (!(card->regs.fifo_en & hfc_FIFOEN_B1TX)) {
+			card->regs.fifo_en |= hfc_FIFOEN_B1TX;
+			hfc_clear_fifo_tx(&card->chans[B1].tx);
+		}
+	} else {
+		if (card->regs.fifo_en & hfc_FIFOEN_B1RX)
+			card->regs.fifo_en &= ~hfc_FIFOEN_B1RX;
+		if (card->regs.fifo_en & hfc_FIFOEN_B1TX)
+			card->regs.fifo_en &= ~hfc_FIFOEN_B1TX;
+	}
+	spin_unlock_irqrestore(&card->chans[B1].lock, flags);
+
+	spin_lock_irqsave(&card->chans[B2].lock, flags);
+	if (!card->fifo_suspended &&
+		(card->chans[B2].status == open_framed ||
+		card->chans[B2].status == open_voice ||
+		card->chans[B2].status == sniff_aux)) {
+
+		if (!(card->regs.fifo_en & hfc_FIFOEN_B2RX)) {
+			card->regs.fifo_en |= hfc_FIFOEN_B2RX;
+			hfc_clear_fifo_rx(&card->chans[B2].rx);
+		}
+
+		if (!(card->regs.fifo_en & hfc_FIFOEN_B2TX)) {
+			card->regs.fifo_en |= hfc_FIFOEN_B2TX;
+			hfc_clear_fifo_tx(&card->chans[B2].tx);
+		}
+	} else {
+		if (card->regs.fifo_en & hfc_FIFOEN_B2RX)
+			card->regs.fifo_en &= ~hfc_FIFOEN_B2RX;
+		if (card->regs.fifo_en & hfc_FIFOEN_B2TX)
+			card->regs.fifo_en &= ~hfc_FIFOEN_B2TX;
+	}
+	spin_unlock_irqrestore(&card->chans[B2].lock, flags);
+
+	spin_lock_irqsave(&card->chans[D].lock, flags);
+	if (!card->fifo_suspended &&
+		card->chans[D].status == open_framed) {
+
+		if (!(card->regs.fifo_en & hfc_FIFOEN_DTX)) {
+			card->regs.fifo_en |= hfc_FIFOEN_DTX;
+
+			card->chans[D].tx.ugly_framebuf_size = 0;
+			card->chans[D].tx.ugly_framebuf_off = 0;
+		}
+	} else {
+		if (card->regs.fifo_en & hfc_FIFOEN_DTX)
+			card->regs.fifo_en &= ~hfc_FIFOEN_DTX;
+	}
+	spin_unlock_irqrestore(&card->chans[D].lock, flags);
+
+	hfc_outb(card, hfc_FIFO_EN, card->regs.fifo_en);
+}
+
+static inline void hfc_suspend_fifo(struct hfc_card *card)
+{
+	card->fifo_suspended = TRUE;
+
+	hfc_update_fifo_state(card);
+
+	/*
+	 * When L1 goes down D rx receives garbage; it is nice to
+	 * clear it to avoid a CRC error on reactivation
+	 * udelay is needed because the FIFO deactivation happens
+	 * in 250us
+	 */
+	udelay(250);
+	hfc_clear_fifo_rx(&card->chans[D].rx);
+
+#ifdef DEBUG
+	if (debug_level >= 3) {
+		printk(KERN_DEBUG hfc_DRIVER_PREFIX
+			"card %d: "
+			"FIFOs suspended\n",
+			card->cardnum);
+	}
+#endif
+}
+
+static inline void hfc_resume_fifo(struct hfc_card *card)
+{
+	card->fifo_suspended = FALSE;
+
+	hfc_update_fifo_state(card);
+
+#ifdef DEBUG
+	if (debug_level >= 3) {
+		printk(KERN_DEBUG hfc_DRIVER_PREFIX
+			"card %d: "
+			"FIFOs resumed\n",
+			card->cardnum);
+	}
+#endif
+}
+
+static void hfc_check_l1_up(struct hfc_card *card)
+{
+	if ((!card->nt_mode && card->l1_state != 7)
+		|| (card->nt_mode && card->l1_state != 3)) {
+
+		hfc_outb(card, hfc_STATES, hfc_STATES_DO_ACTION |
+			hfc_STATES_ACTIVATE|
+				hfc_STATES_NT_G2_G3);
+
+	/*
+	 * 0 because this is quite verbose when an inferface is unconnected, jaw
+	 */
+#if 0
+		if (debug_level >= 1) {
+			printk(KERN_DEBUG hfc_DRIVER_PREFIX
+				"card %d: "
+				"L1 is down, bringing up L1.\n",
+				card->cardnum);
+		}
+#endif
+	}
+}
+
+
+/*******************
+ * Dahdi interface *
+ *******************/
+
+static int hfc_zap_open(struct dahdi_chan *zaptel_chan)
+{
+	struct hfc_chan_duplex *chan = zaptel_chan->pvt;
+	struct hfc_card *card = chan->card;
+
+	spin_lock(&chan->lock);
+
+	switch (chan->number) {
+	case D:
+		if (chan->status != free &&
+			chan->status != open_framed) {
+			spin_unlock(&chan->lock);
+			return -EBUSY;
+		}
+		chan->status = open_framed;
+	break;
+
+	case B1:
+	case B2:
+		if (chan->status != free) {
+			spin_unlock(&chan->lock);
+			return -EBUSY;
+		}
+		chan->status = open_voice;
+	break;
+	}
+
+	chan->open_by_zaptel = TRUE;
+	try_module_get(THIS_MODULE);
+	spin_unlock(&chan->lock);
+
+	switch (chan->number) {
+	case D:
+	break;
+
+	case B1:
+		card->regs.m2 |= hfc_M2_PROC_TRANS;
+		/*
+		 * Enable transparent mode
+		 */
+		card->regs.ctmt |= hfc_CTMT_TRANSB1;
+		/*
+		* Reversed bit order
+		*/
+		card->regs.cirm |= hfc_CIRM_B1_REV;
+		/*
+		 * Enable transmission
+		 */
+		card->regs.sctrl |= hfc_SCTRL_B1_ENA;
+		/*
+		 * Enable reception
+		 */
+		card->regs.sctrl_r |= hfc_SCTRL_R_B1_ENA;
+	break;
+
+	case B2:
+		card->regs.m2 |= hfc_M2_PROC_TRANS;
+		card->regs.ctmt |= hfc_CTMT_TRANSB2;
+		card->regs.cirm |= hfc_CIRM_B2_REV;
+		card->regs.sctrl |= hfc_SCTRL_B2_ENA;
+		card->regs.sctrl_r |= hfc_SCTRL_R_B2_ENA;
+	break;
+
+	}
+
+	/*
+	 * If not already enabled, enable processing transition (8KHz)
+	 * interrupt
+	 */
+	hfc_outb(card, hfc_INT_M2, card->regs.m2);
+	hfc_outb(card, hfc_CTMT, card->regs.ctmt);
+	hfc_outb(card, hfc_CIRM, card->regs.cirm);
+	hfc_outb(card, hfc_SCTRL, card->regs.sctrl);
+	hfc_outb(card, hfc_SCTRL_R, card->regs.sctrl_r);
+
+	hfc_update_fifo_state(card);
+
+	printk(KERN_INFO hfc_DRIVER_PREFIX
+		"card %d: "
+		"chan %s opened as %s.\n",
+		card->cardnum,
+		chan->name,
+		zaptel_chan->name);
+
+	return 0;
+}
+
+static int hfc_zap_close(struct dahdi_chan *zaptel_chan)
+{
+	struct hfc_chan_duplex *chan = zaptel_chan->pvt;
+	struct hfc_card *card = chan->card;
+
+	if (!card) {
+		printk(KERN_CRIT hfc_DRIVER_PREFIX
+			"hfc_zap_close called with NULL card\n");
+		return -1;
+	}
+
+	spin_lock(&chan->lock);
+
+	if (chan->status == free) {
+		spin_unlock(&chan->lock);
+		return -EINVAL;
+	}
+
+	chan->status = free;
+	chan->open_by_zaptel = FALSE;
+
+	spin_unlock(&chan->lock);
+
+	switch (chan->number) {
+	case D:
+	break;
+
+	case B1:
+		card->regs.ctmt &= ~hfc_CTMT_TRANSB1;
+		card->regs.cirm &= ~hfc_CIRM_B1_REV;
+		card->regs.sctrl &= ~hfc_SCTRL_B1_ENA;
+		card->regs.sctrl_r &= ~hfc_SCTRL_R_B1_ENA;
+	break;
+
+	case B2:
+		card->regs.ctmt &= ~hfc_CTMT_TRANSB2;
+		card->regs.cirm &= ~hfc_CIRM_B2_REV;
+		card->regs.sctrl &= ~hfc_SCTRL_B2_ENA;
+		card->regs.sctrl_r &= ~hfc_SCTRL_R_B2_ENA;
+	break;
+	}
+
+	if (card->chans[B1].status == free &&
+		card->chans[B2].status == free)
+		card->regs.m2 &= ~hfc_M2_PROC_TRANS;
+
+	hfc_outb(card, hfc_INT_M2, card->regs.m2);
+	hfc_outb(card, hfc_CTMT, card->regs.ctmt);
+	hfc_outb(card, hfc_CIRM, card->regs.cirm);
+	hfc_outb(card, hfc_SCTRL, card->regs.sctrl);
+	hfc_outb(card, hfc_SCTRL_R, card->regs.sctrl_r);
+
+	hfc_update_fifo_state(card);
+
+	module_put(THIS_MODULE);
+
+	printk(KERN_INFO hfc_DRIVER_PREFIX
+		"card %d: "
+		"chan %s closed as %s.\n",
+		card->cardnum,
+		chan->name,
+		zaptel_chan->name);
+
+	return 0;
+}
+
+static int hfc_zap_rbsbits(struct dahdi_chan *chan, int bits)
+{
+	return 0;
+}
+
+static int hfc_zap_ioctl(struct dahdi_chan *chan,
+		unsigned int cmd, unsigned long data)
+{
+	switch (cmd) {
+
+	default:
+		return -ENOTTY;
+	}
+
+	return 0;
+}
+
+static void hfc_hdlc_hard_xmit(struct dahdi_chan *d_chan)
+{
+	struct hfc_chan_duplex *chan = d_chan->pvt;
+	struct hfc_card *card = chan->card;
+	struct dahdi_hfc *hfccard = card->ztdev;
+
+	atomic_inc(&hfccard->hdlc_pending);
+
+}
+
+static int hfc_zap_startup(struct dahdi_span *span)
+{
+    struct dahdi_hfc *zthfc = dahdi_hfc_from_span(span);
+    struct hfc_card *hfctmp = zthfc->card;
+    int alreadyrunning;
+
+	if (!hfctmp) {
+		printk(KERN_INFO hfc_DRIVER_PREFIX
+			"card %d: "
+			"no card for span at startup!\n",
+			hfctmp->cardnum);
+	}
+
+	alreadyrunning = span->flags & DAHDI_FLAG_RUNNING;
+
+	if (!alreadyrunning)
+		span->flags |= DAHDI_FLAG_RUNNING;
+
+	return 0;
+}
+
+static int hfc_zap_shutdown(struct dahdi_span *span)
+{
+	return 0;
+}
+
+static int hfc_zap_maint(struct dahdi_span *span, int cmd)
+{
+	return 0;
+}
+
+static int hfc_zap_chanconfig(struct dahdi_chan *d_chan, int sigtype)
+{
+	struct hfc_chan_duplex *chan = d_chan->pvt;
+	struct hfc_card *card = chan->card;
+	struct dahdi_hfc *hfccard = card->ztdev;
+
+	if ((sigtype == DAHDI_SIG_HARDHDLC) && (hfccard->sigchan == d_chan)) {
+		hfccard->sigactive = 0;
+		atomic_set(&hfccard->hdlc_pending, 0);
+	}
+
+	return 0;
+}
+
+static int hfc_zap_spanconfig(struct dahdi_span *span,
+		struct dahdi_lineconfig *lc)
+{
+	span->lineconfig = lc->lineconfig;
+
+	return 0;
+}
+
+static const struct dahdi_span_ops hfc_zap_span_ops = {
+       .owner = THIS_MODULE,
+       .chanconfig = hfc_zap_chanconfig,
+       .spanconfig = hfc_zap_spanconfig,
+       .startup = hfc_zap_startup,
+       .shutdown = hfc_zap_shutdown,
+       .maint = hfc_zap_maint,
+       .rbsbits = hfc_zap_rbsbits,
+       .open = hfc_zap_open,
+       .close = hfc_zap_close,
+       .ioctl = hfc_zap_ioctl,
+       .hdlc_hard_xmit = hfc_hdlc_hard_xmit
+};
+
+static int hfc_zap_initialize(struct dahdi_hfc *hfccard)
+{
+	 struct hfc_card *hfctmp = hfccard->card;
+	int i;
+
+	memset(&hfccard->span, 0x0, sizeof(struct dahdi_span));
+	sprintf(hfccard->span.name, "ZTHFC%d", hfctmp->cardnum + 1);
+	sprintf(hfccard->span.desc,
+			"HFC-S PCI A ISDN card %d [%s] ",
+			hfctmp->cardnum,
+			hfctmp->nt_mode ? "NT" : "TE");
+	hfccard->span.spantype = hfctmp->nt_mode ? "NT" : "TE";
+	hfccard->span.manufacturer = "Cologne Chips";
+	hfccard->span.flags = 0;
+	hfccard->span.ops = &hfc_zap_span_ops;
+	hfccard->span.irq = hfctmp->pcidev->irq;
+	dahdi_copy_string(hfccard->span.devicetype, "HFC-S PCI-A ISDN",
+			sizeof(hfccard->span.devicetype));
+	sprintf(hfccard->span.location, "PCI Bus %02d Slot %02d",
+			hfctmp->pcidev->bus->number,
+			PCI_SLOT(hfctmp->pcidev->devfn) + 1);
+	hfccard->span.chans = hfccard->_chans;
+	hfccard->span.channels = 3;
+	for (i = 0; i < hfccard->span.channels; i++)
+		hfccard->_chans[i] = &hfccard->chans[i];
+	hfccard->span.deflaw = DAHDI_LAW_ALAW;
+	hfccard->span.linecompat = DAHDI_CONFIG_AMI | DAHDI_CONFIG_CCS;
+	hfccard->span.offset = 0;
+	init_waitqueue_head(&hfccard->span.maintq);
+
+	for (i = 0; i < hfccard->span.channels; i++) {
+		memset(&hfccard->chans[i], 0x0, sizeof(struct dahdi_chan));
+
+		sprintf(hfccard->chans[i].name,
+				"ZTHFC%d/%d/%d",
+				hfctmp->cardnum + 1, 0, i + 1);
+
+		printk(KERN_INFO hfc_DRIVER_PREFIX
+			"card %d: "
+			"registered %s\n",
+			hfctmp->cardnum,
+			hfccard->chans[i].name);
+
+		if (i == hfccard->span.channels - 1) {
+			hfccard->chans[i].sigcap = DAHDI_SIG_HARDHDLC;
+			hfccard->sigchan = &hfccard->chans[DAHDI_D];
+			hfccard->sigactive = 0;
+			atomic_set(&hfccard->hdlc_pending, 0);
+		} else {
+			hfccard->chans[i].sigcap =
+				DAHDI_SIG_CLEAR | DAHDI_SIG_DACS;
+		}
+
+		hfccard->chans[i].chanpos = i + 1;
+	}
+
+	hfccard->chans[DAHDI_D].readchunk  =
+		hfctmp->chans[D].rx.zaptel_buffer;
+
+	hfccard->chans[DAHDI_D].writechunk =
+		hfctmp->chans[D].tx.zaptel_buffer;
+
+	hfccard->chans[DAHDI_D].pvt = &hfctmp->chans[D];
+
+	hfccard->chans[DAHDI_B1].readchunk  =
+		hfctmp->chans[B1].rx.zaptel_buffer;
+
+	hfccard->chans[DAHDI_B1].writechunk =
+		hfctmp->chans[B1].tx.zaptel_buffer;
+
+	hfccard->chans[DAHDI_B1].pvt = &hfctmp->chans[B1];
+
+	hfccard->chans[DAHDI_B2].readchunk  =
+		hfctmp->chans[B2].rx.zaptel_buffer;
+
+	hfccard->chans[DAHDI_B2].writechunk =
+		hfctmp->chans[B2].tx.zaptel_buffer;
+
+	hfccard->chans[DAHDI_B2].pvt = &hfctmp->chans[B2];
+
+	if (dahdi_register(&hfccard->span, 0)) {
+		printk(KERN_CRIT "unable to register zaptel device!\n");
+		return -1;
+	}
+
+	return 0;
+}
+
+static void hfc_zap_transmit(struct hfc_chan_simplex *chan)
+{
+	hfc_fifo_put(chan, chan->zaptel_buffer, DAHDI_CHUNKSIZE);
+}
+
+static void hfc_zap_receive(struct hfc_chan_simplex *chan)
+{
+	hfc_fifo_get(chan, chan->zaptel_buffer, DAHDI_CHUNKSIZE);
+}
+
+/******************************************
+ * Interrupt Handler
+ ******************************************/
+
+static void hfc_handle_timer_interrupt(struct hfc_card *card);
+static void hfc_handle_state_interrupt(struct hfc_card *card);
+static void hfc_handle_processing_interrupt(struct hfc_card *card);
+static void hfc_frame_arrived(struct hfc_chan_duplex *chan);
+static void hfc_handle_voice(struct hfc_card *card);
+
+#if (KERNEL_VERSION(2, 6, 24) < LINUX_VERSION_CODE)
+static irqreturn_t hfc_interrupt(int irq, void *dev_id)
+#else
+static irqreturn_t hfc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+#endif
+{
+	struct hfc_card *card = dev_id;
+	unsigned long flags;
+	u8 status, s1, s2;
+
+	if (!card) {
+		printk(KERN_CRIT hfc_DRIVER_PREFIX
+			"spurious interrupt (IRQ %d)\n",
+			irq);
+		return IRQ_NONE;
+	}
+
+	spin_lock_irqsave(&card->lock, flags);
+	status = hfc_inb(card, hfc_STATUS);
+	if (!(status & hfc_STATUS_ANYINT)) {
+		/*
+		 * maybe we are sharing the irq
+		 */
+		spin_unlock_irqrestore(&card->lock, flags);
+		return IRQ_NONE;
+	}
+
+	/* We used to ingore the IRQ when the card was in processing
+	 * state but apparently there is no restriction to access the
+	 * card in such state:
+	 *
+	 * Joerg Ciesielski wrote:
+	 * > There is no restriction for the IRQ handler to access
+	 * > HFC-S PCI during processing phase. A IRQ latency of 375 us
+	 * > is also no problem since there are no interrupt sources in
+	 * > HFC-S PCI which must be handled very fast.
+	 * > Due to its deep fifos the IRQ latency can be several ms with
+	 * > out the risk of loosing data. Even the S/T state interrupts
+	 * > must not be handled with a latency less than <5ms.
+	 * >
+	 * > The processing phase only indicates that HFC-S PCI is
+	 * > processing the Fifos as PCI master so that data is read and
+	 * > written in the 32k memory window. But there is no restriction
+	 * > to access data in the memory window during this time.
+	 *
+	 * // if (status & hfc_STATUS_PCI_PROC) {
+	 * // return IRQ_HANDLED;
+	 * // }
+	 */
+
+	s1 = hfc_inb(card, hfc_INT_S1);
+	s2 = hfc_inb(card, hfc_INT_S2);
+
+	if (s1 != 0) {
+		if (s1 & hfc_INTS_TIMER) {
+			/*
+			 * timer (bit 7)
+			 */
+			hfc_handle_timer_interrupt(card);
+		}
+
+		if (s1 & hfc_INTS_L1STATE) {
+			/*
+			 * state machine (bit 6)
+			 */
+			hfc_handle_state_interrupt(card);
+		}
+
+		if (s1 & hfc_INTS_DREC) {
+			/*
+			 * D chan RX (bit 5)
+			 */
+			hfc_frame_arrived(&card->chans[D]);
+		}
+
+		if (s1 & hfc_INTS_B1REC) {
+			/*
+			 * B1 chan RX (bit 3)
+			 */
+			hfc_frame_arrived(&card->chans[B1]);
+		}
+
+		if (s1 & hfc_INTS_B2REC) {
+			/*
+			 * B2 chan RX (bit 4)
+			 */
+			hfc_frame_arrived(&card->chans[B2]);
+		}
+
+		if (s1 & hfc_INTS_DTRANS) {
+			/*
+			 * D chan TX (bit 2)
+			 */
+		}
+
+		if (s1 & hfc_INTS_B1TRANS) {
+			/*
+			 * B1 chan TX (bit 0)
+			 */
+		}
+
+		if (s1 & hfc_INTS_B2TRANS) {
+			/*
+			 * B2 chan TX (bit 1)
+			 */
+		}
+
+	}
+
+	if (s2 != 0) {
+		if (s2 & hfc_M2_PMESEL) {
+			/*
+			 * kaboom irq (bit 7)
+			 *
+			 * CologneChip says:
+			 *
+			 * the meaning of this fatal error bit is that HFC-S
+			 * PCI as PCI master could not access the PCI bus
+			 * within 125us to finish its data processing. If this
+			 * happens only very seldom it does not cause big
+			 * problems but of course some B-channel or D-channel
+			 * data will be corrupted due to this event.
+			 *
+			 * Unfortunately this bit is only set once after the
+			 * problem occurs and can only be reseted by a
+			 * software reset. That means it is not easily
+			 * possible to check how often this fatal error
+			 * happens.
+			 *
+			 */
+
+			if (!card->sync_loss_reported) {
+				printk(KERN_CRIT hfc_DRIVER_PREFIX
+					"card %d: "
+					"sync lost, pci performance too low!\n",
+					card->cardnum);
+
+				card->sync_loss_reported = TRUE;
+			}
+		}
+
+		if (s2 & hfc_M2_GCI_MON_REC) {
+			/*
+			 * RxR monitor channel (bit 2)
+			 */
+		}
+
+		if (s2 & hfc_M2_GCI_I_CHG) {
+			/*
+			 * GCI I-change  (bit 1)
+			 */
+		}
+
+		if (s2 & hfc_M2_PROC_TRANS) {
+			/*
+			 * processing/non-processing transition  (bit 0)
+			 */
+			hfc_handle_processing_interrupt(card);
+		}
+
+	}
+
+	spin_unlock_irqrestore(&card->lock, flags);
+
+	return IRQ_HANDLED;
+}
+
+static void hfc_handle_timer_interrupt(struct hfc_card *card)
+{
+	if (card->ignore_first_timer_interrupt) {
+		card->ignore_first_timer_interrupt = FALSE;
+		return;
+	}
+
+	if ((card->nt_mode && card->l1_state == 3) ||
+		(!card->nt_mode && card->l1_state == 7)) {
+
+		card->regs.ctmt &= ~hfc_CTMT_TIMER_MASK;
+		hfc_outb(card, hfc_CTMT, card->regs.ctmt);
+
+		hfc_resume_fifo(card);
+	}
+}
+
+static void hfc_handle_state_interrupt(struct hfc_card *card)
+{
+	u8 new_state = hfc_inb(card, hfc_STATES)  & hfc_STATES_STATE_MASK;
+
+#ifdef DEBUG
+	if (debug_level >= 1) {
+		printk(KERN_DEBUG hfc_DRIVER_PREFIX
+			"card %d: "
+			"layer 1 state = %c%d\n",
+			card->cardnum,
+			card->nt_mode ? 'G' : 'F',
+			new_state);
+	}
+#endif
+
+	if (card->nt_mode) {
+		/*
+		 * NT mode
+		 */
+
+		if (new_state == 3) {
+			/*
+			 * fix to G3 state (see specs)
+			 */
+			hfc_outb(card, hfc_STATES, hfc_STATES_LOAD_STATE | 3);
+		}
+
+		if (new_state == 3 && card->l1_state != 3)
+			hfc_resume_fifo(card);
+
+		if (new_state != 3 && card->l1_state == 3)
+			hfc_suspend_fifo(card);
+
+	} else {
+		if (new_state == 3) {
+			/*
+			 * Keep L1 up... zaptel & libpri expects
+			 * a always up L1...
+			 * Enable only  when using an unpatched libpri
+			 */
+
+			if (force_l1_up) {
+				hfc_outb(card, hfc_STATES,
+					hfc_STATES_DO_ACTION |
+					hfc_STATES_ACTIVATE|
+					hfc_STATES_NT_G2_G3);
+			}
+		}
+
+		if (new_state == 7 && card->l1_state != 7) {
+			/*
+			 * TE is now active, schedule FIFO activation after
+			 * some time, otherwise the first frames are lost
+			 */
+
+			card->regs.ctmt |= hfc_CTMT_TIMER_50 |
+				hfc_CTMT_TIMER_CLEAR;
+			hfc_outb(card, hfc_CTMT, card->regs.ctmt);
+
+			/*
+			 * Activating the timer firest an
+			 * interrupt immediately, we
+			 * obviously need to ignore it
+			 */
+			card->ignore_first_timer_interrupt = TRUE;
+		}
+
+		if (new_state != 7 && card->l1_state == 7) {
+			/*
+			 * TE has become inactive, disable FIFO
+			 */
+			hfc_suspend_fifo(card);
+		}
+	}
+
+	card->l1_state = new_state;
+}
+
+static void hfc_handle_processing_interrupt(struct hfc_card *card)
+{
+	int available_bytes = 0;
+
+	/*
+	 * Synchronize with the first enabled channel
+	 */
+	if (card->regs.fifo_en & hfc_FIFOEN_B1RX)
+		available_bytes = hfc_fifo_used_rx(&card->chans[B1].rx);
+	if (card->regs.fifo_en & hfc_FIFOEN_B2RX)
+		available_bytes = hfc_fifo_used_rx(&card->chans[B2].rx);
+	else
+		available_bytes = -1;
+
+	if ((available_bytes == -1 && card->ticks == 8) ||
+		available_bytes >= DAHDI_CHUNKSIZE + hfc_RX_FIFO_PRELOAD) {
+		card->ticks = 0;
+
+		if (available_bytes > DAHDI_CHUNKSIZE*2 + hfc_RX_FIFO_PRELOAD) {
+			card->late_irqs++;
+			/*
+			 * we are out of sync, clear fifos, jaw
+			 */
+			hfc_clear_fifo_rx(&card->chans[B1].rx);
+			hfc_clear_fifo_tx(&card->chans[B1].tx);
+			hfc_clear_fifo_rx(&card->chans[B2].rx);
+			hfc_clear_fifo_tx(&card->chans[B2].tx);
+
+#ifdef DEBUG
+			if (debug_level >= 4) {
+				printk(KERN_DEBUG hfc_DRIVER_PREFIX
+					"card %d: "
+					"late IRQ, %d bytes late\n",
+					card->cardnum,
+					available_bytes -
+						(DAHDI_CHUNKSIZE +
+						 hfc_RX_FIFO_PRELOAD));
+			}
+#endif
+		} else {
+			hfc_handle_voice(card);
+		}
+	}
+
+	card->ticks++;
+}
+
+
+static void hfc_handle_voice(struct hfc_card *card)
+{
+	struct dahdi_hfc *hfccard = card->ztdev;
+	int frame_left, res;
+	unsigned char buf[hfc_HDLC_BUF_LEN];
+	unsigned int size = sizeof(buf) / sizeof(buf[0]);
+
+
+	if (card->chans[B1].status != open_voice &&
+		card->chans[B2].status != open_voice)
+		return;
+
+	dahdi_transmit(&hfccard->span);
+
+	if (card->regs.fifo_en & hfc_FIFOEN_B1TX)
+		hfc_zap_transmit(&card->chans[B1].tx);
+	if (card->regs.fifo_en & hfc_FIFOEN_B2TX)
+		hfc_zap_transmit(&card->chans[B2].tx);
+
+	/*
+	 * dahdi hdlc frame tx
+	 */
+
+	if (atomic_read(&hfccard->hdlc_pending)) {
+		hfc_check_l1_up(card);
+		res = dahdi_hdlc_getbuf(hfccard->sigchan, buf, &size);
+			if (size > 0) {
+				hfccard->sigactive = 1;
+				memcpy(card->chans[D].tx.ugly_framebuf +
+				card->chans[D].tx.ugly_framebuf_size,
+				buf, size);
+				card->chans[D].tx.ugly_framebuf_size += size;
+			if (res != 0) {
+					hfc_fifo_put_frame(&card->chans[D].tx,
+					card->chans[D].tx.ugly_framebuf,
+					card->chans[D].tx.ugly_framebuf_size);
+					++hfccard->frames_out;
+					hfccard->sigactive = 0;
+					card->chans[D].tx.ugly_framebuf_size
+						= 0;
+					atomic_dec(&hfccard->hdlc_pending);
+				}
+			}
+	}
+	/*
+	 * dahdi hdlc frame tx done
+	 */
+
+	if (card->regs.fifo_en & hfc_FIFOEN_B1RX)
+		hfc_zap_receive(&card->chans[B1].rx);
+	else
+		memset(&card->chans[B1].rx.zaptel_buffer, 0x7f,
+			sizeof(card->chans[B1].rx.zaptel_buffer));
+
+	if (card->regs.fifo_en & hfc_FIFOEN_B2RX)
+		hfc_zap_receive(&card->chans[B2].rx);
+	else
+		memset(&card->chans[B2].rx.zaptel_buffer, 0x7f,
+			sizeof(card->chans[B1].rx.zaptel_buffer));
+
+	/*
+	 * Echo cancellation
+	 */
+	dahdi_ec_chunk(&hfccard->chans[DAHDI_B1],
+			card->chans[B1].rx.zaptel_buffer,
+			card->chans[B1].tx.zaptel_buffer);
+	dahdi_ec_chunk(&hfccard->chans[DAHDI_B2],
+			card->chans[B2].rx.zaptel_buffer,
+			card->chans[B2].tx.zaptel_buffer);
+
+	/*
+	 * dahdi hdlc frame rx
+	 */
+	if (hfc_fifo_has_frames(&card->chans[D].rx))
+		hfc_frame_arrived(&card->chans[D]);
+
+	if (card->chans[D].rx.ugly_framebuf_size) {
+		frame_left = card->chans[D].rx.ugly_framebuf_size -
+			card->chans[D].rx.ugly_framebuf_off ;
+		if (frame_left > hfc_HDLC_BUF_LEN) {
+			dahdi_hdlc_putbuf(hfccard->sigchan,
+					card->chans[D].rx.ugly_framebuf +
+					card->chans[D].rx.ugly_framebuf_off,
+					hfc_HDLC_BUF_LEN);
+			card->chans[D].rx.ugly_framebuf_off +=
+				hfc_HDLC_BUF_LEN;
+		} else {
+			dahdi_hdlc_putbuf(hfccard->sigchan,
+					card->chans[D].rx.ugly_framebuf +
+					card->chans[D].rx.ugly_framebuf_off,
+					frame_left);
+			dahdi_hdlc_finish(hfccard->sigchan);
+			card->chans[D].rx.ugly_framebuf_size = 0;
+			card->chans[D].rx.ugly_framebuf_off = 0;
+		}
+	}
+	/*
+	 * dahdi hdlc frame rx done
+	 */
+
+	if (hfccard->span.flags & DAHDI_FLAG_RUNNING)
+		dahdi_receive(&hfccard->span);
+
+}
+
+static void hfc_frame_arrived(struct hfc_chan_duplex *chan)
+{
+	struct hfc_card *card = chan->card;
+	int antiloop = 16;
+	struct sk_buff *skb;
+
+	while (hfc_fifo_has_frames(&chan->rx) && --antiloop) {
+		int frame_size = hfc_fifo_get_frame_size(&chan->rx);
+
+		if (frame_size < 3) {
+#ifdef DEBUG
+			if (debug_level >= 2)
+				printk(KERN_DEBUG hfc_DRIVER_PREFIX
+					"card %d: "
+					"chan %s: "
+					"invalid frame received, "
+					"just %d bytes\n",
+					card->cardnum,
+					chan->name,
+					frame_size);
+#endif
+
+			hfc_fifo_drop_frame(&chan->rx);
+
+
+			continue;
+		} else if (frame_size == 3) {
+#ifdef DEBUG
+			if (debug_level >= 2)
+				printk(KERN_DEBUG hfc_DRIVER_PREFIX
+					"card %d: "
+					"chan %s: "
+					"empty frame received\n",
+					card->cardnum,
+					chan->name);
+#endif
+
+			hfc_fifo_drop_frame(&chan->rx);
+
+
+			continue;
+		}
+
+		if (chan->open_by_zaptel &&
+			card->chans[D].rx.ugly_framebuf_size) {
+
+				/*
+				 * We have to wait for Dahdi to transmit the
+				 * frame... wait for next time
+				 */
+
+				 break;
+		}
+
+		skb = dev_alloc_skb(frame_size - 3);
+
+		if (!skb) {
+			printk(KERN_ERR hfc_DRIVER_PREFIX
+				"card %d: "
+				"chan %s: "
+				"cannot allocate skb: frame dropped\n",
+				card->cardnum,
+				chan->name);
+
+			hfc_fifo_drop_frame(&chan->rx);
+
+
+			continue;
+		}
+
+
+		/*
+		* HFC does the checksum
+		*/
+#ifndef CHECKSUM_HW
+		skb->ip_summed = CHECKSUM_COMPLETE;
+#else
+		skb->ip_summed = CHECKSUM_HW;
+#endif
+
+		if (chan->open_by_zaptel) {
+			card->chans[D].rx.ugly_framebuf_size = frame_size - 1;
+
+			if (hfc_fifo_get_frame(&card->chans[D].rx,
+				card->chans[D].rx.ugly_framebuf,
+				frame_size - 1) == -1) {
+				dev_kfree_skb(skb);
+				continue;
+			}
+
+			memcpy(skb_put(skb, frame_size - 3),
+				card->chans[D].rx.ugly_framebuf,
+				frame_size - 3);
+		} else {
+			if (hfc_fifo_get_frame(&chan->rx,
+				skb_put(skb, frame_size - 3),
+				frame_size - 3) == -1) {
+				dev_kfree_skb(skb);
+				continue;
+			}
+		}
+	}
+
+	if (!antiloop)
+		printk(KERN_CRIT hfc_DRIVER_PREFIX
+			"card %d: "
+			"Infinite loop detected\n",
+			card->cardnum);
+}
+
+/******************************************
+ * Module initialization and cleanup
+ ******************************************/
+
+static int __devinit hfc_probe(struct pci_dev *pci_dev,
+	const struct pci_device_id *ent)
+{
+	static int cardnum;
+	int err;
+	int i;
+
+	struct hfc_card *card = NULL;
+	struct dahdi_hfc *zthfc = NULL;
+	card = kmalloc(sizeof(struct hfc_card), GFP_KERNEL);
+	if (!card) {
+		printk(KERN_CRIT hfc_DRIVER_PREFIX
+			"unable to kmalloc!\n");
+		err = -ENOMEM;
+		goto err_alloc_hfccard;
+	}
+
+	memset(card, 0x00, sizeof(struct hfc_card));
+	card->cardnum = cardnum;
+	card->pcidev = pci_dev;
+	spin_lock_init(&card->lock);
+
+	pci_set_drvdata(pci_dev, card);
+
+	err = pci_enable_device(pci_dev);
+	if (err)
+		goto err_pci_enable_device;
+
+	err = pci_set_dma_mask(pci_dev, PCI_DMA_32BIT);
+	if (err) {
+		printk(KERN_ERR hfc_DRIVER_PREFIX
+			"card %d: "
+			"No suitable DMA configuration available.\n",
+			card->cardnum);
+		goto err_pci_set_dma_mask;
+	}
+
+	pci_write_config_word(pci_dev, PCI_COMMAND, PCI_COMMAND_MEMORY);
+	err = pci_request_regions(pci_dev, hfc_DRIVER_NAME);
+	if (err) {
+		printk(KERN_CRIT hfc_DRIVER_PREFIX
+			"card %d: "
+			"cannot request I/O memory region\n",
+			card->cardnum);
+		goto err_pci_request_regions;
+	}
+
+	pci_set_master(pci_dev);
+
+	if (!pci_dev->irq) {
+		printk(KERN_CRIT hfc_DRIVER_PREFIX
+			"card %d: "
+			"no irq!\n",
+			card->cardnum);
+		err = -ENODEV;
+		goto err_noirq;
+	}
+
+	card->io_bus_mem = pci_resource_start(pci_dev, 1);
+	if (!card->io_bus_mem) {
+		printk(KERN_CRIT hfc_DRIVER_PREFIX
+			"card %d: "
+			"no iomem!\n",
+			card->cardnum);
+		err = -ENODEV;
+		goto err_noiobase;
+	}
+
+	card->io_mem = ioremap(card->io_bus_mem, hfc_PCI_MEM_SIZE);
+	if (!(card->io_mem)) {
+		printk(KERN_CRIT hfc_DRIVER_PREFIX
+			"card %d: "
+			"cannot ioremap I/O memory\n",
+			card->cardnum);
+		err = -ENODEV;
+		goto err_ioremap;
+	}
+
+	/*
+	 * pci_alloc_consistent guarantees alignment
+	 * (Documentation/DMA-mapping.txt)
+	 */
+	card->fifo_mem = pci_alloc_consistent(pci_dev,
+			hfc_FIFO_SIZE, &card->fifo_bus_mem);
+	if (!card->fifo_mem) {
+		printk(KERN_CRIT hfc_DRIVER_PREFIX
+			"card %d: "
+			"unable to allocate FIFO DMA memory!\n",
+			card->cardnum);
+		err = -ENOMEM;
+		goto err_alloc_fifo;
+	}
+
+	memset(card->fifo_mem, 0x00, hfc_FIFO_SIZE);
+
+	card->fifos = card->fifo_mem;
+
+	pci_write_config_dword(card->pcidev, hfc_PCI_MWBA, card->fifo_bus_mem);
+
+	err = request_irq(card->pcidev->irq, &hfc_interrupt,
+
+#if (KERNEL_VERSION(2, 6, 23) < LINUX_VERSION_CODE)
+		IRQF_SHARED, hfc_DRIVER_NAME, card);
+#else
+		SA_SHIRQ, hfc_DRIVER_NAME, card);
+#endif
+
+	if (err) {
+		printk(KERN_CRIT hfc_DRIVER_PREFIX
+			"card %d: "
+			"unable to register irq\n",
+			card->cardnum);
+		goto err_request_irq;
+	}
+
+	card->nt_mode = FALSE;
+
+	if (modes & (1 << card->cardnum))
+		card->nt_mode = TRUE;
+
+	for (i = 0; i < nt_modes_count; i++) {
+		if (nt_modes[i] == card->cardnum)
+			card->nt_mode = TRUE;
+	}
+
+	/*
+	 * D Channel
+	 */
+	card->chans[D].card = card;
+	card->chans[D].name = "D";
+	card->chans[D].status = free;
+	card->chans[D].number = D;
+	spin_lock_init(&card->chans[D].lock);
+
+	card->chans[D].rx.chan      = &card->chans[D];
+	card->chans[D].rx.fifo_base = card->fifos + 0x4000;
+	card->chans[D].rx.z_base    = card->fifos + 0x4000;
+	card->chans[D].rx.z1_base   = card->fifos + 0x6080;
+	card->chans[D].rx.z2_base   = card->fifos + 0x6082;
+	card->chans[D].rx.z_min     = 0x0000;
+	card->chans[D].rx.z_max     = 0x01FF;
+	card->chans[D].rx.f_min     = 0x10;
+	card->chans[D].rx.f_max     = 0x1F;
+	card->chans[D].rx.f1        = card->fifos + 0x60a0;
+	card->chans[D].rx.f2        = card->fifos + 0x60a1;
+	card->chans[D].rx.fifo_size = card->chans[D].rx.z_max
+		- card->chans[D].rx.z_min + 1;
+	card->chans[D].rx.f_num     = card->chans[D].rx.f_max
+		- card->chans[D].rx.f_min + 1;
+
+	card->chans[D].tx.chan      = &card->chans[D];
+	card->chans[D].tx.fifo_base = card->fifos + 0x0000;
+	card->chans[D].tx.z_base    = card->fifos + 0x0000;
+	card->chans[D].tx.z1_base   = card->fifos + 0x2080;
+	card->chans[D].tx.z2_base   = card->fifos + 0x2082;
+	card->chans[D].tx.z_min     = 0x0000;
+	card->chans[D].tx.z_max     = 0x01FF;
+	card->chans[D].tx.f_min     = 0x10;
+	card->chans[D].tx.f_max     = 0x1F;
+	card->chans[D].tx.f1        = card->fifos + 0x20a0;
+	card->chans[D].tx.f2        = card->fifos + 0x20a1;
+	card->chans[D].tx.fifo_size = card->chans[D].tx.z_max -
+		card->chans[D].tx.z_min + 1;
+	card->chans[D].tx.f_num     = card->chans[D].tx.f_max -
+		card->chans[D].tx.f_min + 1;
+
+	/*
+	 * B1 Channel
+	 */
+	card->chans[B1].card = card;
+	card->chans[B1].name = "B1";
+	card->chans[B1].status = free;
+	card->chans[B1].number = B1;
+	card->chans[B1].protocol = 0;
+	spin_lock_init(&card->chans[B1].lock);
+
+	card->chans[B1].rx.chan      = &card->chans[B1];
+	card->chans[B1].rx.fifo_base = card->fifos + 0x4200;
+	card->chans[B1].rx.z_base    = card->fifos + 0x4000;
+	card->chans[B1].rx.z1_base   = card->fifos + 0x6000;
+	card->chans[B1].rx.z2_base   = card->fifos + 0x6002;
+	card->chans[B1].rx.z_min     = 0x0200;
+	card->chans[B1].rx.z_max     = 0x1FFF;
+	card->chans[B1].rx.f_min     = 0x00;
+	card->chans[B1].rx.f_max     = 0x1F;
+	card->chans[B1].rx.f1        = card->fifos + 0x6080;
+	card->chans[B1].rx.f2        = card->fifos + 0x6081;
+	card->chans[B1].rx.fifo_size = card->chans[B1].rx.z_max -
+		card->chans[B1].rx.z_min + 1;
+	card->chans[B1].rx.f_num     = card->chans[B1].rx.f_max -
+		card->chans[B1].rx.f_min + 1;
+
+	card->chans[B1].tx.chan      = &card->chans[B1];
+	card->chans[B1].tx.fifo_base = card->fifos + 0x0200;
+	card->chans[B1].tx.z_base    = card->fifos + 0x0000;
+	card->chans[B1].tx.z1_base   = card->fifos + 0x2000;
+	card->chans[B1].tx.z2_base   = card->fifos + 0x2002;
+	card->chans[B1].tx.z_min     = 0x0200;
+	card->chans[B1].tx.z_max     = 0x1FFF;
+	card->chans[B1].tx.f_min     = 0x00;
+	card->chans[B1].tx.f_max     = 0x1F;
+	card->chans[B1].tx.f1        = card->fifos + 0x2080;
+	card->chans[B1].tx.f2        = card->fifos + 0x2081;
+	card->chans[B1].tx.fifo_size = card->chans[B1].tx.z_max -
+		card->chans[B1].tx.z_min + 1;
+	card->chans[B1].tx.f_num     = card->chans[B1].tx.f_max -
+		card->chans[B1].tx.f_min + 1;
+
+	/*
+	 * B2 Channel
+	 */
+	card->chans[B2].card = card;
+	card->chans[B2].name = "B2";
+	card->chans[B2].status = free;
+	card->chans[B2].number = B2;
+	card->chans[B2].protocol = 0;
+	spin_lock_init(&card->chans[B2].lock);
+
+	card->chans[B2].rx.chan      = &card->chans[B2];
+	card->chans[B2].rx.fifo_base = card->fifos + 0x6200,
+	card->chans[B2].rx.z_base    = card->fifos + 0x6000;
+	card->chans[B2].rx.z1_base   = card->fifos + 0x6100;
+	card->chans[B2].rx.z2_base   = card->fifos + 0x6102;
+	card->chans[B2].rx.z_min     = 0x0200;
+	card->chans[B2].rx.z_max     = 0x1FFF;
+	card->chans[B2].rx.f_min     = 0x00;
+	card->chans[B2].rx.f_max     = 0x1F;
+	card->chans[B2].rx.f1        = card->fifos + 0x6180;
+	card->chans[B2].rx.f2        = card->fifos + 0x6181;
+	card->chans[B2].rx.fifo_size = card->chans[B2].rx.z_max -
+		card->chans[B2].rx.z_min + 1;
+	card->chans[B2].rx.f_num     = card->chans[B2].rx.f_max -
+		card->chans[B2].rx.f_min + 1;
+
+	card->chans[B2].tx.chan      = &card->chans[B2];
+	card->chans[B2].tx.fifo_base = card->fifos + 0x2200;
+	card->chans[B2].tx.z_base    = card->fifos + 0x2000;
+	card->chans[B2].tx.z1_base   = card->fifos + 0x2100;
+	card->chans[B2].tx.z2_base   = card->fifos + 0x2102;
+	card->chans[B2].tx.z_min     = 0x0200;
+	card->chans[B2].tx.z_max     = 0x1FFF;
+	card->chans[B2].tx.f_min     = 0x00;
+	card->chans[B2].tx.f_max     = 0x1F;
+	card->chans[B2].tx.f1        = card->fifos + 0x2180;
+	card->chans[B2].tx.f2        = card->fifos + 0x2181;
+	card->chans[B2].tx.fifo_size = card->chans[B2].tx.z_max -
+		card->chans[B2].tx.z_min + 1;
+	card->chans[B2].tx.f_num     = card->chans[B2].tx.f_max -
+		card->chans[B2].tx.f_min + 1;
+
+	/*
+	 * All done
+	 */
+
+	zthfc = kmalloc(sizeof(struct dahdi_hfc), GFP_KERNEL);
+	if (!zthfc) {
+		printk(KERN_CRIT hfc_DRIVER_PREFIX
+			"unable to kmalloc!\n");
+		goto err_request_irq;
+	}
+	memset(zthfc, 0x0, sizeof(struct dahdi_hfc));
+
+	zthfc->card = card;
+	hfc_zap_initialize(zthfc);
+	card->ztdev = zthfc;
+
+	snprintf(card->proc_dir_name,
+			sizeof(card->proc_dir_name),
+			"%d", card->cardnum);
+	card->proc_dir = proc_mkdir(card->proc_dir_name, hfc_proc_zaphfc_dir);
+	SET_PROC_DIRENTRY_OWNER(card->proc_dir);
+
+	hfc_resetCard(card);
+
+	printk(KERN_INFO hfc_DRIVER_PREFIX
+		"card %d configured for %s mode at mem %#lx (0x%p) IRQ %u\n",
+		card->cardnum,
+		card->nt_mode ? "NT" : "TE",
+		card->io_bus_mem,
+		card->io_mem,
+		card->pcidev->irq);
+
+	cardnum++;
+
+	return 0;
+
+err_request_irq:
+	pci_free_consistent(pci_dev, hfc_FIFO_SIZE,
+		card->fifo_mem, card->fifo_bus_mem);
+err_alloc_fifo:
+	iounmap(card->io_mem);
+err_ioremap:
+err_noiobase:
+err_noirq:
+	pci_release_regions(pci_dev);
+err_pci_request_regions:
+err_pci_set_dma_mask:
+err_pci_enable_device:
+	kfree(card);
+err_alloc_hfccard:
+	return err;
+}
+
+static void __devexit hfc_remove(struct pci_dev *pci_dev)
+{
+	struct hfc_card *card = pci_get_drvdata(pci_dev);
+
+
+	printk(KERN_INFO hfc_DRIVER_PREFIX
+		"card %d: "
+		"shutting down card at %p.\n",
+		card->cardnum,
+		card->io_mem);
+
+	hfc_softreset(card);
+
+	dahdi_unregister(&card->ztdev->span);
+
+
+	/*
+	 * disable memio and bustmaster
+	 */
+	pci_write_config_word(pci_dev, PCI_COMMAND, 0);
+
+	remove_proc_entry("bufs", card->proc_dir);
+	remove_proc_entry("fifos", card->proc_dir);
+	remove_proc_entry("info", card->proc_dir);
+	remove_proc_entry(card->proc_dir_name, hfc_proc_zaphfc_dir);
+
+	free_irq(pci_dev->irq, card);
+
+	pci_free_consistent(pci_dev, hfc_FIFO_SIZE,
+		card->fifo_mem, card->fifo_bus_mem);
+
+	iounmap(card->io_mem);
+
+	pci_release_regions(pci_dev);
+
+	pci_disable_device(pci_dev);
+
+	kfree(card);
+}
+
+/******************************************
+ * Module stuff
+ ******************************************/
+
+static int __init hfc_init_module(void)
+{
+	int ret;
+
+	printk(KERN_INFO hfc_DRIVER_PREFIX
+		hfc_DRIVER_STRING " loading\n");
+
+#if (KERNEL_VERSION(2, 6, 26) <= LINUX_VERSION_CODE)
+	hfc_proc_zaphfc_dir = proc_mkdir(hfc_DRIVER_NAME, NULL);
+#else
+	hfc_proc_zaphfc_dir = proc_mkdir(hfc_DRIVER_NAME, proc_root_driver);
+#endif
+
+	ret = dahdi_pci_module(&hfc_driver);
+	return ret;
+}
+
+module_init(hfc_init_module);
+
+static void __exit hfc_module_exit(void)
+{
+	pci_unregister_driver(&hfc_driver);
+
+#if (KERNEL_VERSION(2, 6, 26) <= LINUX_VERSION_CODE)
+	remove_proc_entry(hfc_DRIVER_NAME, NULL);
+#else
+	remove_proc_entry(hfc_DRIVER_NAME, proc_root_driver);
+#endif
+
+	printk(KERN_INFO hfc_DRIVER_PREFIX
+		hfc_DRIVER_STRING " unloaded\n");
+}
+
+module_exit(hfc_module_exit);
+
+#endif
+
+MODULE_DESCRIPTION(hfc_DRIVER_DESCR);
+MODULE_AUTHOR("Jens Wilke <jw_vzaphfc@headissue.com>, "
+		"Daniele (Vihai) Orlandi <daniele@orlandi.com>, "
+		"Jose A. Deniz <odicha@hotmail.com>");
+MODULE_ALIAS("vzaphfc");
+#ifdef MODULE_LICENSE
+MODULE_LICENSE("GPL");
+#endif
+
+
+module_param(modes, int, 0444);
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 10)
+module_param_array(nt_modes, int, &nt_modes_count, 0444);
+#else
+module_param_array(nt_modes, int, nt_modes_count, 0444);
+#endif
+
+module_param(force_l1_up, int, 0444);
+#ifdef DEBUG
+module_param(debug_level, int, 0444);
+#endif
+
+MODULE_PARM_DESC(modes, "[Deprecated] bit-mask to configure NT mode");
+MODULE_PARM_DESC(nt_modes,
+		"Comma-separated list of card IDs to configure in NT mode");
+MODULE_PARM_DESC(force_l1_up, "Don't allow L1 to go down");
+#ifdef DEBUG
+MODULE_PARM_DESC(debug_level, "Debug verbosity level");
+#endif
diff -urN dahdi-linux-complete-2.4.1.2+2.4.1/linux/drivers/dahdi/zaphfc/fifo.c dahdi-linux-complete-2.4.1.2+2.4.1-new/linux/drivers/dahdi/zaphfc/fifo.c
--- dahdi-linux-complete-2.4.1.2+2.4.1/linux/drivers/dahdi/zaphfc/fifo.c	1969-12-31 19:00:00.000000000 -0500
+++ dahdi-linux-complete-2.4.1.2+2.4.1-new/linux/drivers/dahdi/zaphfc/fifo.c	2011-08-08 18:31:46.000000000 -0500
@@ -0,0 +1,375 @@
+/*
+ * fifo.c - HFC FIFO management routines
+ *
+ * Copyright (C) 2006 headissue GmbH; Jens Wilke
+ * Copyright (C) 2004 Daniele Orlandi
+ * Copyright (C) 2002, 2003, 2004, Junghanns.NET GmbH
+ *
+ * Original author of this code is
+ * Daniele "Vihai" Orlandi <daniele@orlandi.com>
+ *
+ * This program is free software and may be modified and
+ * distributed under the terms of the GNU Public License.
+ *
+ */
+
+#include <linux/kernel.h>
+
+#include <dahdi/kernel.h>
+
+#include "fifo.h"
+
+static void hfc_fifo_mem_read(struct hfc_chan_simplex *chan,
+	int z_start,
+	void *data, int size)
+{
+	int bytes_to_boundary = chan->z_max - z_start + 1;
+	if (bytes_to_boundary >= size) {
+		memcpy(data,
+			chan->z_base + z_start,
+			size);
+	} else {
+		/*
+		 * Buffer wrap
+		 */
+		memcpy(data,
+			chan->z_base + z_start,
+			bytes_to_boundary);
+
+		memcpy(data + bytes_to_boundary,
+			chan->fifo_base,
+			size - bytes_to_boundary);
+	}
+}
+
+static void hfc_fifo_mem_write(struct hfc_chan_simplex *chan,
+	void *data, int size)
+{
+	int bytes_to_boundary = chan->z_max - *Z1_F1(chan) + 1;
+	if (bytes_to_boundary >= size) {
+		memcpy(chan->z_base + *Z1_F1(chan),
+			data,
+			size);
+	} else {
+		/*
+		 * FIFO wrap
+		 */
+
+		memcpy(chan->z_base + *Z1_F1(chan),
+			data,
+			bytes_to_boundary);
+
+		memcpy(chan->fifo_base,
+			data + bytes_to_boundary,
+			size - bytes_to_boundary);
+	}
+}
+
+int hfc_fifo_get(struct hfc_chan_simplex *chan,
+		void *data, int size)
+{
+	int available_bytes;
+
+	/*
+	 * Some useless statistic
+	 */
+	chan->bytes += size;
+
+	available_bytes = hfc_fifo_used_rx(chan);
+
+	if (available_bytes < size && !chan->fifo_underrun++) {
+		/*
+		 * print the warning only once
+		 */
+		printk(KERN_WARNING hfc_DRIVER_PREFIX
+			"card %d: "
+			"chan %s: "
+			"RX FIFO not enough (%d) bytes to receive!\n",
+			chan->chan->card->cardnum,
+			chan->chan->name,
+			available_bytes);
+		return -1;
+	}
+
+	hfc_fifo_mem_read(chan, *Z2_F2(chan), data, size);
+	*Z2_F2(chan) = Z_inc(chan, *Z2_F2(chan), size);
+	return available_bytes - size;
+}
+
+void hfc_fifo_put(struct hfc_chan_simplex *chan,
+			void *data, int size)
+{
+	struct hfc_card *card = chan->chan->card;
+	int used_bytes = hfc_fifo_used_tx(chan);
+	int free_bytes = hfc_fifo_free_tx(chan);
+
+	if (!used_bytes && !chan->fifo_underrun++) {
+		/*
+		 * print warning only once, to make timing not worse
+		 */
+		printk(KERN_WARNING hfc_DRIVER_PREFIX
+			"card %d: "
+			"chan %s: "
+			"TX FIFO has become empty\n",
+			card->cardnum,
+			chan->chan->name);
+	}
+	if (free_bytes < size) {
+		printk(KERN_CRIT hfc_DRIVER_PREFIX
+			"card %d: "
+			"chan %s: "
+			"TX FIFO full!\n",
+			chan->chan->card->cardnum,
+			chan->chan->name);
+		chan->fifo_full++;
+		hfc_clear_fifo_tx(chan);
+	}
+
+	hfc_fifo_mem_write(chan, data, size);
+	chan->bytes += size;
+	*Z1_F1(chan) = Z_inc(chan, *Z1_F1(chan), size);
+}
+
+int hfc_fifo_get_frame(struct hfc_chan_simplex *chan, void *data, int max_size)
+{
+	int frame_size;
+	u16 newz2 ;
+
+	if (*chan->f1 == *chan->f2) {
+		/*
+		 * nothing received, strange uh?
+		 */
+		printk(KERN_WARNING hfc_DRIVER_PREFIX
+			"card %d: "
+			"chan %s: "
+			"get_frame called with no frame in FIFO.\n",
+			chan->chan->card->cardnum,
+			chan->chan->name);
+
+		return -1;
+	}
+
+	/*
+	 * frame_size includes CRC+CRC+STAT
+	 */
+	frame_size = hfc_fifo_get_frame_size(chan);
+
+#ifdef DEBUG
+	if (debug_level == 3) {
+		printk(KERN_DEBUG hfc_DRIVER_PREFIX
+			"card %d: "
+			"chan %s: "
+			"RX len %2d: ",
+			chan->chan->card->cardnum,
+			chan->chan->name,
+			frame_size);
+	} else if (debug_level >= 4) {
+		printk(KERN_DEBUG hfc_DRIVER_PREFIX
+			"card %d: "
+			"chan %s: "
+			"RX (f1=%02x, f2=%02x, z1=%04x, z2=%04x) len %2d: ",
+			chan->chan->card->cardnum,
+			chan->chan->name,
+			*chan->f1, *chan->f2, *Z1_F2(chan), *Z2_F2(chan),
+			frame_size);
+	}
+
+	if (debug_level >= 3) {
+		int i;
+		for (i = 0; i < frame_size; i++) {
+			printk("%02x", hfc_fifo_u8(chan,
+				Z_inc(chan, *Z2_F2(chan), i)));
+		}
+
+		printk("\n");
+	}
+#endif
+
+	if (frame_size <= 0) {
+#ifdef DEBUG
+		if (debug_level >= 2) {
+			printk(KERN_DEBUG hfc_DRIVER_PREFIX
+				"card %d: "
+				"chan %s: "
+				"invalid (empty) frame received.\n",
+				chan->chan->card->cardnum,
+				chan->chan->name);
+		}
+#endif
+
+		hfc_fifo_drop_frame(chan);
+		return -1;
+	}
+
+	/*
+	 * STAT is not really received
+	 */
+	chan->bytes += frame_size - 1;
+
+	/*
+	 * Calculate beginning of the next frame
+	 */
+	newz2 = Z_inc(chan, *Z2_F2(chan), frame_size);
+
+	/*
+	 * We cannot use hfc_fifo_get because of different semantic of
+	 * "available bytes" and to avoid useless increment of Z2
+	 */
+	hfc_fifo_mem_read(chan, *Z2_F2(chan), data,
+		frame_size < max_size ? frame_size : max_size);
+
+	if (hfc_fifo_u8(chan, Z_inc(chan, *Z2_F2(chan),
+		frame_size - 1)) != 0x00) {
+		/*
+		 * CRC not ok, frame broken, skipping
+		 */
+#ifdef DEBUG
+		if (debug_level >= 2) {
+			printk(KERN_WARNING hfc_DRIVER_PREFIX
+				"card %d: "
+				"chan %s: "
+				"Received frame with wrong CRC\n",
+				chan->chan->card->cardnum,
+				chan->chan->name);
+		}
+#endif
+
+		chan->crc++;
+
+		hfc_fifo_drop_frame(chan);
+		return -1;
+	}
+
+	chan->frames++;
+
+	*chan->f2 = F_inc(chan, *chan->f2, 1);
+
+	/*
+	 * Set Z2 for the next frame we're going to receive
+	 */
+	*Z2_F2(chan) = newz2;
+
+	return frame_size;
+}
+
+void hfc_fifo_drop_frame(struct hfc_chan_simplex *chan)
+{
+	int available_bytes;
+	u16 newz2;
+
+	if (*chan->f1 == *chan->f2) {
+		/*
+		 * nothing received, strange eh?
+		 */
+		printk(KERN_WARNING hfc_DRIVER_PREFIX
+			"card %d: "
+			"chan %s: "
+			"skip_frame called with no frame in FIFO.\n",
+			chan->chan->card->cardnum,
+			chan->chan->name);
+
+		return;
+	}
+
+	available_bytes = hfc_fifo_used_rx(chan) + 1;
+
+	/*
+	 * Calculate beginning of the next frame
+	 */
+	newz2 = Z_inc(chan, *Z2_F2(chan), available_bytes);
+
+	*chan->f2 = F_inc(chan, *chan->f2, 1);
+
+	/*
+	 * Set Z2 for the next frame we're going to receive
+	 */
+	*Z2_F2(chan) = newz2;
+}
+
+void hfc_fifo_put_frame(struct hfc_chan_simplex *chan,
+		 void *data, int size)
+{
+	u16 newz1;
+	int available_frames;
+
+#ifdef DEBUG
+	if (debug_level == 3) {
+		printk(KERN_DEBUG hfc_DRIVER_PREFIX
+			"card %d: "
+			"chan %s: "
+			"TX len %2d: ",
+			chan->chan->card->cardnum,
+			chan->chan->name,
+			size);
+	} else if (debug_level >= 4) {
+		printk(KERN_DEBUG hfc_DRIVER_PREFIX
+			"card %d: "
+			"chan %s: "
+			"TX (f1=%02x, f2=%02x, z1=%04x, z2=%04x) len %2d: ",
+			chan->chan->card->cardnum,
+			chan->chan->name,
+			*chan->f1, *chan->f2, *Z1_F1(chan), *Z2_F1(chan),
+			size);
+	}
+
+	if (debug_level >= 3) {
+		int i;
+		for (i = 0; i < size; i++)
+			printk("%02x", ((u8 *)data)[i]);
+
+		printk("\n");
+	}
+#endif
+
+	available_frames = hfc_fifo_free_frames(chan);
+
+	if (available_frames >= chan->f_num) {
+		printk(KERN_CRIT hfc_DRIVER_PREFIX
+			"card %d: "
+			"chan %s: "
+			"TX FIFO total number of frames exceeded!\n",
+			chan->chan->card->cardnum,
+			chan->chan->name);
+
+		chan->fifo_full++;
+
+		return;
+	}
+
+	hfc_fifo_put(chan, data, size);
+
+	newz1 = *Z1_F1(chan);
+
+	*chan->f1 = F_inc(chan, *chan->f1, 1);
+
+	*Z1_F1(chan) = newz1;
+
+	chan->frames++;
+}
+
+void hfc_clear_fifo_rx(struct hfc_chan_simplex *chan)
+{
+	*chan->f2 = *chan->f1;
+	*Z2_F2(chan) = *Z1_F2(chan);
+}
+
+void hfc_clear_fifo_tx(struct hfc_chan_simplex *chan)
+{
+	*chan->f1 = *chan->f2;
+	*Z1_F1(chan) = *Z2_F1(chan);
+
+	if (chan->chan->status == open_voice) {
+		/*
+		 * Make sure that at least hfc_TX_FIFO_PRELOAD bytes are
+		 * present in the TX FIFOs
+		 * Create hfc_TX_FIFO_PRELOAD bytes of empty data
+		 * (0x7f is mute audio)
+		 */
+		u8 empty_fifo[hfc_TX_FIFO_PRELOAD +
+			DAHDI_CHUNKSIZE + hfc_RX_FIFO_PRELOAD];
+		memset(empty_fifo, 0x7f, sizeof(empty_fifo));
+
+		hfc_fifo_put(chan, empty_fifo, sizeof(empty_fifo));
+	}
+}
+
diff -urN dahdi-linux-complete-2.4.1.2+2.4.1/linux/drivers/dahdi/zaphfc/fifo.h dahdi-linux-complete-2.4.1.2+2.4.1-new/linux/drivers/dahdi/zaphfc/fifo.h
--- dahdi-linux-complete-2.4.1.2+2.4.1/linux/drivers/dahdi/zaphfc/fifo.h	1969-12-31 19:00:00.000000000 -0500
+++ dahdi-linux-complete-2.4.1.2+2.4.1-new/linux/drivers/dahdi/zaphfc/fifo.h	2011-08-08 18:31:46.000000000 -0500
@@ -0,0 +1,139 @@
+/*
+ * fifo.h - Dahdi driver for HFC-S PCI A based ISDN BRI cards
+ *
+ * Copyright (C) 2004 Daniele Orlandi
+ * Copyright (C) 2002, 2003, 2004, Junghanns.NET GmbH
+ *
+ * Daniele "Vihai" Orlandi <daniele@orlandi.com>
+ *
+ * Major rewrite of the driver made by
+ * Klaus-Peter Junghanns <kpj@junghanns.net>
+ *
+ * This program is free software and may be modified and
+ * distributed under the terms of the GNU Public License.
+ *
+ */
+
+#ifndef _HFC_FIFO_H
+#define _HFC_FIFO_H
+
+#include "zaphfc.h"
+
+static inline u16 *Z1_F1(struct hfc_chan_simplex *chan)
+{
+	return chan->z1_base + (*chan->f1 * 4);
+}
+
+static inline u16 *Z2_F1(struct hfc_chan_simplex *chan)
+{
+	return chan->z2_base + (*chan->f1 * 4);
+}
+
+static inline u16 *Z1_F2(struct hfc_chan_simplex *chan)
+{
+	return chan->z1_base + (*chan->f2 * 4);
+}
+
+static inline u16 *Z2_F2(struct hfc_chan_simplex *chan)
+{
+	return chan->z2_base + (*chan->f2 * 4);
+}
+
+static inline u16 Z_inc(struct hfc_chan_simplex *chan, u16 z, u16 inc)
+{
+	/*
+	 * declared as u32 in order to manage overflows
+	 */
+	u32 newz = z + inc;
+	if (newz > chan->z_max)
+		newz -= chan->fifo_size;
+
+	return newz;
+}
+
+static inline u8 F_inc(struct hfc_chan_simplex *chan, u8 f, u8 inc)
+{
+	/*
+	 * declared as u16 in order to manage overflows
+	 */
+	u16 newf = f + inc;
+	if (newf > chan->f_max)
+		newf -= chan->f_num;
+
+	return newf;
+}
+
+static inline u16 hfc_fifo_used_rx(struct hfc_chan_simplex *chan)
+{
+	return (*Z1_F2(chan) - *Z2_F2(chan) +
+			chan->fifo_size) % chan->fifo_size;
+}
+
+static inline u16 hfc_fifo_get_frame_size(struct hfc_chan_simplex *chan)
+{
+ /*
+  * This +1 is needed because in frame mode the available bytes are Z2-Z1+1
+  * while in transparent mode I wouldn't consider the byte pointed by Z2 to
+  * be available, otherwise, the FIFO would always contain one byte, even
+  * when Z1==Z2
+  */
+
+	return hfc_fifo_used_rx(chan) + 1;
+}
+
+static inline u8 hfc_fifo_u8(struct hfc_chan_simplex *chan, u16 z)
+{
+	return *((u8 *)(chan->z_base + z));
+}
+
+static inline u16 hfc_fifo_used_tx(struct hfc_chan_simplex *chan)
+{
+	return (*Z1_F1(chan) - *Z2_F1(chan) +
+			chan->fifo_size) % chan->fifo_size;
+}
+
+static inline u16 hfc_fifo_free_rx(struct hfc_chan_simplex *chan)
+{
+	u16 free_bytes = *Z2_F1(chan) - *Z1_F1(chan);
+
+	if (free_bytes > 0)
+		return free_bytes;
+	else
+		return free_bytes + chan->fifo_size;
+}
+
+static inline u16 hfc_fifo_free_tx(struct hfc_chan_simplex *chan)
+{
+	u16 free_bytes = *Z2_F1(chan) - *Z1_F1(chan);
+
+	if (free_bytes > 0)
+		return free_bytes;
+	else
+		return free_bytes + chan->fifo_size;
+}
+
+static inline int hfc_fifo_has_frames(struct hfc_chan_simplex *chan)
+{
+	return *chan->f1 != *chan->f2;
+}
+
+static inline u8 hfc_fifo_used_frames(struct hfc_chan_simplex *chan)
+{
+	return (*chan->f1 - *chan->f2 + chan->f_num) % chan->f_num;
+}
+
+static inline u8 hfc_fifo_free_frames(struct hfc_chan_simplex *chan)
+{
+	return (*chan->f2 - *chan->f1 + chan->f_num) % chan->f_num;
+}
+
+int hfc_fifo_get(struct hfc_chan_simplex *chan, void *data, int size);
+void hfc_fifo_put(struct hfc_chan_simplex *chan, void *data, int size);
+void hfc_fifo_drop(struct hfc_chan_simplex *chan, int size);
+int hfc_fifo_get_frame(struct hfc_chan_simplex *chan, void *data, int max_size);
+void hfc_fifo_drop_frame(struct hfc_chan_simplex *chan);
+void hfc_fifo_put_frame(struct hfc_chan_simplex *chan, void *data, int size);
+void hfc_clear_fifo_rx(struct hfc_chan_simplex *chan);
+void hfc_clear_fifo_tx(struct hfc_chan_simplex *chan);
+
+#endif
diff -urN dahdi-linux-complete-2.4.1.2+2.4.1/linux/drivers/dahdi/zaphfc/Kbuild dahdi-linux-complete-2.4.1.2+2.4.1-new/linux/drivers/dahdi/zaphfc/Kbuild
--- dahdi-linux-complete-2.4.1.2+2.4.1/linux/drivers/dahdi/zaphfc/Kbuild	1969-12-31 19:00:00.000000000 -0500
+++ dahdi-linux-complete-2.4.1.2+2.4.1-new/linux/drivers/dahdi/zaphfc/Kbuild	2011-08-08 18:31:46.000000000 -0500
@@ -0,0 +1,10 @@
+obj-m += zaphfc.o
+
+EXTRA_CFLAGS := -I$(src)/.. -Wno-undef
+
+zaphfc-objs := base.o fifo.o
+
+$(obj)/base.o: $(src)/zaphfc.h
+$(obj)/fifo.o: $(src)/fifo.h
+
+
diff -urN dahdi-linux-complete-2.4.1.2+2.4.1/linux/drivers/dahdi/zaphfc/Makefile dahdi-linux-complete-2.4.1.2+2.4.1-new/linux/drivers/dahdi/zaphfc/Makefile
--- dahdi-linux-complete-2.4.1.2+2.4.1/linux/drivers/dahdi/zaphfc/Makefile	1969-12-31 19:00:00.000000000 -0500
+++ dahdi-linux-complete-2.4.1.2+2.4.1-new/linux/drivers/dahdi/zaphfc/Makefile	2011-08-08 18:31:46.000000000 -0500
@@ -0,0 +1,7 @@
+ifdef KBUILD_EXTMOD
+# We only get here on kernels 2.6.0-2.6.9 .
+# For newer kernels, Kbuild will be included directly by the kernel
+# build system.
+include $(src)/Kbuild
+else
+endif
diff -urN dahdi-linux-complete-2.4.1.2+2.4.1/linux/drivers/dahdi/zaphfc/zaphfc.h dahdi-linux-complete-2.4.1.2+2.4.1-new/linux/drivers/dahdi/zaphfc/zaphfc.h
--- dahdi-linux-complete-2.4.1.2+2.4.1/linux/drivers/dahdi/zaphfc/zaphfc.h	1969-12-31 19:00:00.000000000 -0500
+++ dahdi-linux-complete-2.4.1.2+2.4.1-new/linux/drivers/dahdi/zaphfc/zaphfc.h	2011-08-08 18:31:46.000000000 -0500
@@ -0,0 +1,418 @@
+/*
+ * zaphfc.h - Dahdi driver for HFC-S PCI A based ISDN BRI cards
+ *
+ * Dahdi port by Jose A. Deniz <odicha@hotmail.com>
+ *
+ * Copyright (C) 2009 Jose A. Deniz
+ * Copyright (C) 2006 headissue GmbH; Jens Wilke
+ * Copyright (C) 2004 Daniele Orlandi
+ * Copyright (C) 2002, 2003, 2004, Junghanns.NET GmbH
+ *
+ * Jens Wilke <jw_vzaphfc@headissue.com>
+ *
+ * Orginal author of this code is
+ * Daniele "Vihai" Orlandi <daniele@orlandi.com>
+ *
+ * Major rewrite of the driver made by
+ * Klaus-Peter Junghanns <kpj@junghanns.net>
+ *
+ * This program is free software and may be modified and
+ * distributed under the terms of the GNU Public License.
+ *
+ */
+
+#ifndef _HFC_ZAPHFC_H
+#define _HFC_ZAPHFC_H
+
+#include <asm/io.h>
+
+#define hfc_DRIVER_NAME "vzaphfc"
+#define hfc_DRIVER_PREFIX hfc_DRIVER_NAME ": "
+#define hfc_DRIVER_DESCR "HFC-S PCI A ISDN"
+#define hfc_DRIVER_VERSION "1.42"
+#define hfc_DRIVER_STRING hfc_DRIVER_DESCR " (V" hfc_DRIVER_VERSION ")"
+
+#define hfc_MAX_BOARDS 32
+
+#ifndef PCI_DMA_32BIT
+#define PCI_DMA_32BIT	0x00000000ffffffffULL
+#endif
+
+#ifndef PCI_VENDOR_ID_SITECOM
+#define PCI_VENDOR_ID_SITECOM 0x182D
+#endif
+
+#ifndef PCI_DEVICE_ID_SITECOM_3069
+#define PCI_DEVICE_ID_SITECOM_3069 0x3069
+#endif
+
+#define hfc_RESET_DELAY 20
+
+#define hfc_CLKDEL_TE	0x0f	/* CLKDEL in TE mode */
+#define hfc_CLKDEL_NT	0x6c	/* CLKDEL in NT mode */
+
+/* PCI memory mapped I/O */
+
+#define hfc_PCI_MEM_SIZE	0x0100
+#define hfc_PCI_MWBA		0x80
+
+/* GCI/IOM bus monitor registers */
+
+#define hfc_C_I       0x08
+#define hfc_TRxR      0x0C
+#define hfc_MON1_D    0x28
+#define hfc_MON2_D    0x2C
+
+
+/* GCI/IOM bus timeslot registers */
+
+#define hfc_B1_SSL    0x80
+#define hfc_B2_SSL    0x84
+#define hfc_AUX1_SSL  0x88
+#define hfc_AUX2_SSL  0x8C
+#define hfc_B1_RSL    0x90
+#define hfc_B2_RSL    0x94
+#define hfc_AUX1_RSL  0x98
+#define hfc_AUX2_RSL  0x9C
+
+/* GCI/IOM bus data registers */
+
+#define hfc_B1_D      0xA0
+#define hfc_B2_D      0xA4
+#define hfc_AUX1_D    0xA8
+#define hfc_AUX2_D    0xAC
+
+/* GCI/IOM bus configuration registers */
+
+#define hfc_MST_EMOD  0xB4
+#define hfc_MST_MODE	 0xB8
+#define hfc_CONNECT 	 0xBC
+
+
+/* Interrupt and status registers */
+
+#define hfc_FIFO_EN   0x44
+#define hfc_TRM       0x48
+#define hfc_B_MODE    0x4C
+#define hfc_CHIP_ID   0x58
+#define hfc_CIRM  	 0x60
+#define hfc_CTMT	 0x64
+#define hfc_INT_M1  	 0x68
+#define hfc_INT_M2  	 0x6C
+#define hfc_INT_S1  	 0x78
+#define hfc_INT_S2  	 0x7C
+#define hfc_STATUS  	 0x70
+
+/* S/T section registers */
+
+#define hfc_STATES  	 0xC0
+#define hfc_SCTRL  	 0xC4
+#define hfc_SCTRL_E   0xC8
+#define hfc_SCTRL_R   0xCC
+#define hfc_SQ  	 0xD0
+#define hfc_CLKDEL  	 0xDC
+#define hfc_B1_REC    0xF0
+#define hfc_B1_SEND   0xF0
+#define hfc_B2_REC    0xF4
+#define hfc_B2_SEND   0xF4
+#define hfc_D_REC     0xF8
+#define hfc_D_SEND    0xF8
+#define hfc_E_REC     0xFC
+
+/* Bits and values in various HFC PCI registers */
+
+/* bits in status register (READ) */
+#define hfc_STATUS_PCI_PROC   0x02
+#define hfc_STATUS_NBUSY	0x04
+#define hfc_STATUS_TIMER_ELAP 0x10
+#define hfc_STATUS_STATINT	  0x20
+#define hfc_STATUS_FRAMEINT	  0x40
+#define hfc_STATUS_ANYINT	  0x80
+
+/* bits in CTMT (Write) */
+#define hfc_CTMT_TRANSB1	0x01
+#define hfc_CTMT_TRANSB2	0x02
+#define hfc_CTMT_TIMER_CLEAR	0x80
+#define hfc_CTMT_TIMER_MASK	0x1C
+#define hfc_CTMT_TIMER_3_125	(0x01 << 2)
+#define hfc_CTMT_TIMER_6_25	(0x02 << 2)
+#define hfc_CTMT_TIMER_12_5	(0x03 << 2)
+#define hfc_CTMT_TIMER_25	(0x04 << 2)
+#define hfc_CTMT_TIMER_50	(0x05 << 2)
+#define hfc_CTMT_TIMER_400	(0x06 << 2)
+#define hfc_CTMT_TIMER_800	(0x07 << 2)
+#define hfc_CTMT_AUTO_TIMER	0x20
+
+/* bits in CIRM (Write) */
+#define hfc_CIRM_AUX_MSK    0x07
+#define hfc_CIRM_RESET  	  0x08
+#define hfc_CIRM_B1_REV     0x40
+#define hfc_CIRM_B2_REV     0x80
+
+/* bits in INT_M1 and INT_S1 */
+#define hfc_INTS_B1TRANS  0x01
+#define hfc_INTS_B2TRANS  0x02
+#define hfc_INTS_DTRANS   0x04
+#define hfc_INTS_B1REC    0x08
+#define hfc_INTS_B2REC    0x10
+#define hfc_INTS_DREC     0x20
+#define hfc_INTS_L1STATE  0x40
+#define hfc_INTS_TIMER    0x80
+
+/* bits in INT_M2 */
+#define hfc_M2_PROC_TRANS    0x01
+#define hfc_M2_GCI_I_CHG     0x02
+#define hfc_M2_GCI_MON_REC   0x04
+#define hfc_M2_IRQ_ENABLE    0x08
+#define hfc_M2_PMESEL        0x80
+
+/* bits in STATES */
+#define hfc_STATES_STATE_MASK     0x0F
+#define hfc_STATES_LOAD_STATE    0x10
+#define hfc_STATES_ACTIVATE	     0x20
+#define hfc_STATES_DO_ACTION     0x40
+#define hfc_STATES_NT_G2_G3      0x80
+
+/* bits in HFCD_MST_MODE */
+#define hfc_MST_MODE_MASTER	     0x01
+#define hfc_MST_MODE_SLAVE         0x00
+/* remaining bits are for codecs control */
+
+/* bits in HFCD_SCTRL */
+#define hfc_SCTRL_B1_ENA	     0x01
+#define hfc_SCTRL_B2_ENA	     0x02
+#define hfc_SCTRL_MODE_TE        0x00
+#define hfc_SCTRL_MODE_NT        0x04
+#define hfc_SCTRL_LOW_PRIO	     0x08
+#define hfc_SCTRL_SQ_ENA	     0x10
+#define hfc_SCTRL_TEST	     0x20
+#define hfc_SCTRL_NONE_CAP	     0x40
+#define hfc_SCTRL_PWR_DOWN	     0x80
+
+/* bits in SCTRL_E  */
+#define hfc_SCTRL_E_AUTO_AWAKE    0x01
+#define hfc_SCTRL_E_DBIT_1        0x04
+#define hfc_SCTRL_E_IGNORE_COL    0x08
+#define hfc_SCTRL_E_CHG_B1_B2     0x80
+
+/* bits in SCTRL_R  */
+#define hfc_SCTRL_R_B1_ENA	     0x01
+#define hfc_SCTRL_R_B2_ENA	     0x02
+
+/* bits in FIFO_EN register */
+#define hfc_FIFOEN_B1TX   0x01
+#define hfc_FIFOEN_B1RX   0x02
+#define hfc_FIFOEN_B2TX   0x04
+#define hfc_FIFOEN_B2RX   0x08
+#define hfc_FIFOEN_DTX    0x10
+#define hfc_FIFOEN_DRX    0x20
+
+#define hfc_FIFOEN_B1     (hfc_FIFOEN_B1TX|hfc_FIFOEN_B1RX)
+#define hfc_FIFOEN_B2     (hfc_FIFOEN_B2TX|hfc_FIFOEN_B2RX)
+#define hfc_FIFOEN_D      (hfc_FIFOEN_DTX|hfc_FIFOEN_DRX)
+
+/* bits in the CONNECT register */
+#define	hfc_CONNECT_B1_HFC_from_ST		0x00
+#define	hfc_CONNECT_B1_HFC_from_GCI		0x01
+#define hfc_CONNECT_B1_ST_from_HFC		0x00
+#define hfc_CONNECT_B1_ST_from_GCI		0x02
+#define hfc_CONNECT_B1_GCI_from_HFC		0x00
+#define hfc_CONNECT_B1_GCI_from_ST		0x04
+
+#define	hfc_CONNECT_B2_HFC_from_ST		0x00
+#define	hfc_CONNECT_B2_HFC_from_GCI		0x08
+#define hfc_CONNECT_B2_ST_from_HFC		0x00
+#define hfc_CONNECT_B2_ST_from_GCI		0x10
+#define hfc_CONNECT_B2_GCI_from_HFC		0x00
+#define hfc_CONNECT_B2_GCI_from_ST		0x20
+
+/* bits in the TRM register */
+#define hfc_TRM_TRANS_INT_00	0x00
+#define hfc_TRM_TRANS_INT_01	0x01
+#define hfc_TRM_TRANS_INT_10	0x02
+#define hfc_TRM_TRANS_INT_11	0x04
+#define hfc_TRM_ECHO		0x20
+#define hfc_TRM_B1_PLUS_B2	0x40
+#define hfc_TRM_IOM_TEST_LOOP	0x80
+
+/* bits in the __SSL and __RSL registers */
+#define	hfc_SRSL_STIO		0x40
+#define hfc_SRSL_ENABLE		0x80
+#define hfc_SRCL_SLOT_MASK	0x1f
+
+/* FIFO memory definitions */
+
+#define hfc_FIFO_SIZE   0x8000
+
+#define hfc_UGLY_FRAMEBUF 0x2000
+
+#define hfc_TX_FIFO_PRELOAD (DAHDI_CHUNKSIZE + 2)
+#define hfc_RX_FIFO_PRELOAD 4
+
+/* HDLC STUFF */
+#define hfc_HDLC_BUF_LEN	32
+/* arbitrary, just the max # of byts we will send to DAHDI per call */
+
+
+/* NOTE: FIFO pointers are not declared volatile because accesses to the
+ *       FIFOs are inherently safe.
+ */
+
+#ifdef DEBUG
+extern int debug_level;
+#endif
+
+struct hfc_chan;
+
+struct hfc_chan_simplex {
+	struct hfc_chan_duplex *chan;
+
+	u8 zaptel_buffer[DAHDI_CHUNKSIZE];
+
+	u8 ugly_framebuf[hfc_UGLY_FRAMEBUF];
+	int ugly_framebuf_size;
+	u16 ugly_framebuf_off;
+
+	void *z1_base, *z2_base;
+	void *fifo_base;
+	void *z_base;
+	u16 z_min;
+	u16 z_max;
+	u16 fifo_size;
+
+	u8 *f1, *f2;
+	u8 f_min;
+	u8 f_max;
+	u8 f_num;
+
+	unsigned long long frames;
+	unsigned long long bytes;
+	unsigned long long fifo_full;
+	unsigned long long crc;
+	unsigned long long fifo_underrun;
+};
+
+enum hfc_chan_status {
+	free,
+	open_framed,
+	open_voice,
+	sniff_aux,
+	loopback,
+};
+
+struct hfc_chan_duplex {
+	struct hfc_card *card;
+
+	char *name;
+	int number;
+
+	enum hfc_chan_status status;
+	int open_by_netdev;
+	int open_by_zaptel;
+
+	unsigned short protocol;
+
+	spinlock_t lock;
+
+	struct hfc_chan_simplex rx;
+	struct hfc_chan_simplex tx;
+
+};
+
+typedef struct hfc_card {
+	int cardnum;
+	struct pci_dev *pcidev;
+	struct dahdi_hfc *ztdev;
+	struct proc_dir_entry *proc_dir;
+	char proc_dir_name[32];
+
+	struct proc_dir_entry *proc_info;
+	struct proc_dir_entry *proc_fifos;
+	struct proc_dir_entry *proc_bufs;
+
+	unsigned long io_bus_mem;
+	void __iomem *io_mem;
+
+	dma_addr_t fifo_bus_mem;
+	void *fifo_mem;
+	void *fifos;
+
+	int nt_mode;
+	int sync_loss_reported;
+	int late_irqs;
+
+	u8 l1_state;
+	int fifo_suspended;
+	int ignore_first_timer_interrupt;
+
+	struct {
+		u8 m1;
+		u8 m2;
+		u8 fifo_en;
+		u8 trm;
+		u8 connect;
+		u8 sctrl;
+		u8 sctrl_r;
+		u8 sctrl_e;
+		u8 ctmt;
+		u8 cirm;
+	} regs;
+
+	struct hfc_chan_duplex chans[3];
+	int echo_enabled;
+
+
+
+	int debug_event;
+
+    spinlock_t lock;
+    unsigned int irq;
+    unsigned int iomem;
+    int ticks;
+    int clicks;
+    unsigned char *pci_io;
+    void *fifomem;		/* start of the shared mem */
+
+    unsigned int pcibus;
+    unsigned int pcidevfn;
+
+    int	drecinframe;
+
+    unsigned char cardno;
+    struct hfc_card *next;
+
+} hfc_card;
+
+typedef struct dahdi_hfc {
+    unsigned int usecount;
+    struct dahdi_span span;
+    struct dahdi_chan chans[3];
+    struct dahdi_chan *_chans[3];
+    struct hfc_card *card;
+
+    /* pointer to the signalling channel for this span */
+    struct dahdi_chan *sigchan;
+    /* nonzero means we're in the middle of sending an HDLC frame */
+    int sigactive;
+    /* hdlc_hard_xmit() increments, hdlc_tx_frame() decrements */
+    atomic_t hdlc_pending;
+    int frames_out;
+    int frames_in;
+
+} dahdi_hfc;
+
+static inline struct dahdi_hfc* dahdi_hfc_from_span(struct dahdi_span *span) {
+	return container_of(span, struct dahdi_hfc, span);
+}
+
+static inline u8 hfc_inb(struct hfc_card *card, int offset)
+{
+ return readb(card->io_mem + offset);
+}
+
+static inline void hfc_outb(struct hfc_card *card, int offset, u8 value)
+{
+ writeb(value, card->io_mem + offset);
+}
+
+#endif
diff -urN dahdi-linux-complete-2.4.1.2+2.4.1/tools/blacklist.sample dahdi-linux-complete-2.4.1.2+2.4.1-new/tools/blacklist.sample
--- dahdi-linux-complete-2.4.1.2+2.4.1/tools/blacklist.sample	2011-08-08 18:29:11.000000000 -0500
+++ dahdi-linux-complete-2.4.1.2+2.4.1-new/tools/blacklist.sample	2011-08-08 18:31:46.000000000 -0500
@@ -19,3 +19,4 @@
 blacklist ystdm16xx
 blacklist ap400
 blacklist ax1600p
+blacklist zaphfc
diff -urN dahdi-linux-complete-2.4.1.2+2.4.1/tools/modules.sample dahdi-linux-complete-2.4.1.2+2.4.1-new/tools/modules.sample
--- dahdi-linux-complete-2.4.1.2+2.4.1/tools/modules.sample	2011-08-08 18:29:11.000000000 -0500
+++ dahdi-linux-complete-2.4.1.2+2.4.1-new/tools/modules.sample	2011-08-08 18:34:21.000000000 -0500
@@ -69,3 +69,6 @@
 
 # ATCOM AX1600P/800P
 ax1600p
+
+# Dahdi driver for HFC-S PCI A based ISDN BRI cards
+zaphfc
diff -urN dahdi-linux-complete-2.4.1.2+2.4.1/tools/xpp/perl_modules/Dahdi/Hardware/PCI.pm dahdi-linux-complete-2.4.1.2+2.4.1-new/tools/xpp/perl_modules/Dahdi/Hardware/PCI.pm
--- dahdi-linux-complete-2.4.1.2+2.4.1/tools/xpp/perl_modules/Dahdi/Hardware/PCI.pm	2011-08-08 18:29:11.000000000 -0500
+++ dahdi-linux-complete-2.4.1.2+2.4.1-new/tools/xpp/perl_modules/Dahdi/Hardware/PCI.pm	2011-08-08 18:37:56.000000000 -0500
@@ -153,11 +153,31 @@
 	'1397:08b4'		=> { DRIVER => 'qozap', DESCRIPTION => 'Generic Cologne ISDN card' },
 	'1397:16b8'		=> { DRIVER => 'qozap', DESCRIPTION => 'Generic OctoBRI ISDN card' },
 	'1397:30b1'		=> { DRIVER => 'cwain', DESCRIPTION => 'HFC-E1 ISDN E1 card' },
-	'1397:2bd0'		=> { DRIVER => 'zaphfc', DESCRIPTION => 'HFC-S ISDN BRI card' },
-	# Has three submodels. Tested with 0675:1704:
-	'1043:0675'		=> { DRIVER => 'zaphfc', DESCRIPTION => 'ASUSTeK Computer Inc. ISDNLink P-IN100-ST-D' },
 	'1397:f001'		=> { DRIVER => 'ztgsm', DESCRIPTION => 'HFC-GSM Cologne Chips GSM' },
 
+	'1397:2bd0'             => { DRIVER => 'zaphfc', DESCRIPTION => 'HFC-S ISDN BRI card' },
+	'1397:b000'             => { DRIVER => 'zaphfc', DESCRIPTION => 'HFC-S ISDN BRI card' },
+	'1397:b006'             => { DRIVER => 'zaphfc', DESCRIPTION => 'HFC-S ISDN BRI card' },
+	'1397:b007'             => { DRIVER => 'zaphfc', DESCRIPTION => 'HFC-S ISDN BRI card' },
+	'1397:b008'             => { DRIVER => 'zaphfc', DESCRIPTION => 'HFC-S ISDN BRI card' },
+	'1397:b009'             => { DRIVER => 'zaphfc', DESCRIPTION => 'HFC-S ISDN BRI card' },
+	'1397:b00a'             => { DRIVER => 'zaphfc', DESCRIPTION => 'HFC-S ISDN BRI card' },
+	'1397:b00b'             => { DRIVER => 'zaphfc', DESCRIPTION => 'HFC-S ISDN BRI card' },
+	'1397:b00c'             => { DRIVER => 'zaphfc', DESCRIPTION => 'HFC-S ISDN BRI card' },
+	'1397:b100'             => { DRIVER => 'zaphfc', DESCRIPTION => 'HFC-S ISDN BRI card' },
+	'13d1:2bd1'             => { DRIVER => 'zaphfc', DESCRIPTION => 'HFC-S ISDN BRI card' },
+	'1043:0675'             => { DRIVER => 'zaphfc', DESCRIPTION => 'ASUSTeK Computer Inc. ISDNLink P-IN100-ST-D' },
+	'0871:ffa2'             => { DRIVER => 'zaphfc', DESCRIPTION => 'HFC-S ISDN BRI card' },
+	'0871:ffa1'             => { DRIVER => 'zaphfc', DESCRIPTION => 'HFC-S ISDN BRI card' },
+	'1051:0100'             => { DRIVER => 'zaphfc', DESCRIPTION => 'HFC-S ISDN BRI card' },
+	'15b0:2bd0'             => { DRIVER => 'zaphfc', DESCRIPTION => 'HFC-S ISDN BRI card' },
+	'114f:0070'             => { DRIVER => 'zaphfc', DESCRIPTION => 'HFC-S ISDN BRI card' },
+	'114f:0071'             => { DRIVER => 'zaphfc', DESCRIPTION => 'HFC-S ISDN BRI card' },
+	'114f:0072'             => { DRIVER => 'zaphfc', DESCRIPTION => 'HFC-S ISDN BRI card' },
+	'114f:0073'             => { DRIVER => 'zaphfc', DESCRIPTION => 'HFC-S ISDN BRI card' },
+	'182d:3069'             => { DRIVER => 'zaphfc', DESCRIPTION => 'HFC-S ISDN BRI card' },
+
+
 	# Rhino cards (based on pci.ids)
 	'0b0b:0105'	=> { DRIVER => 'r1t1', DESCRIPTION => 'Rhino R1T1' },
 	'0b0b:0205'	=> { DRIVER => 'r4fxo', DESCRIPTION => 'Rhino R14FXO' },
