[Pkg-voip-commits] [dahdi-linux] 02/12: Refresh dahdi_linux_extra, also fix opvxa1200 with 4.11

tzafrir at debian.org tzafrir at debian.org
Wed Jan 10 22:42:26 UTC 2018


This is an automated email from the git hooks/post-receive script.

tzafrir pushed a commit to branch master
in repository dahdi-linux.

commit 630221ed6e944c7d49323bbae531e74ea021e26b
Author: Tzafrir Cohen <tzafrir at debian.org>
Date:   Mon Jan 8 03:13:22 2018 +0200

    Refresh dahdi_linux_extra, also fix opvxa1200 with 4.11
---
 debian/patches/dahdi_linux_extra | 2660 +++++++++++++++++++++++++++++++++++++-
 1 file changed, 2650 insertions(+), 10 deletions(-)

diff --git a/debian/patches/dahdi_linux_extra b/debian/patches/dahdi_linux_extra
index 7db0f13..1aa5506 100644
--- a/debian/patches/dahdi_linux_extra
+++ b/debian/patches/dahdi_linux_extra
@@ -1,37 +1,39 @@
 Subject: dahdi-extra: out-of-tree DAHDI drivers
+From: Tzafrir Cohen <tzafrir.cohen at xorcom.com>
 Origin: https://notabug.org/tzafrir/dahdi-linux-extra
 Forwarded: No
-Last-Update: 2015-08-12
+Last-Update: 2018-01-02
  
 This patch includes a number of out-of-tree DAHDI drivers from the
 dahdi-extra repository. They are all out-of-tree and are highly likely
 not to be included in DAHDI-linux in the forseeable future.
 
-Currently only includes OSLEC and opvxa1200.
+Currently only includes OSLEC, ZapHFC and opvxa1200.
  
-Git-Commit: 3b5e1e0b2f6a449144282ef640efd16e2d6d7c87
-Dahdi: v2.10.2
+Git-Commit: d14f6de62b8eeff1eabc74b08a15bdbe3777b1ec
+Dahdi: d4e232a776ee27eb04aed3cbd72a203118dbe9f1
 ---
 diff --git a/drivers/dahdi/Kbuild b/drivers/dahdi/Kbuild
-index ee2cd59..45686de 100644
+index ee2cd59..ebcc200 100644
 --- a/drivers/dahdi/Kbuild
 +++ b/drivers/dahdi/Kbuild
-@@ -56,6 +56,10 @@ obj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_ECHOCAN_STEVE2)	+= dahdi_echocan_sec2.o
+@@ -56,6 +56,11 @@ obj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_ECHOCAN_STEVE2)	+= dahdi_echocan_sec2.o
  obj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_ECHOCAN_KB1)	+= dahdi_echocan_kb1.o
  obj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_ECHOCAN_MG2)	+= dahdi_echocan_mg2.o
  
 +ifdef CONFIG_PCI
 +obj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_OPVXA1200)		+= opvxa1200/
++obj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_ZAPHFC)		+= zaphfc/
 +endif
 +
  obj-m += $(DAHDI_MODULES_EXTRA)
  
  # If you want to build OSLEC, include the code in the standard location:
 diff --git a/drivers/dahdi/Kconfig b/drivers/dahdi/Kconfig
-index 6952c6a..444b7c2 100644
+index 6952c6a..68f79d3 100644
 --- a/drivers/dahdi/Kconfig
 +++ b/drivers/dahdi/Kconfig
-@@ -292,3 +292,34 @@ config DAHDI_WCTE11XP
+@@ -292,3 +292,47 @@ config DAHDI_WCTE11XP
  	  If unsure, say Y.
  
  source "drivers/dahdi/xpp/Kconfig"
@@ -54,6 +56,19 @@ index 6952c6a..444b7c2 100644
 +
 +	  If unsure, say Y.
 +
++config DAHDI_ZAPHFC
++	tristate "HFC-S DAHDI Driver"
++	depends on DAHDI && PCI
++	default DAHDI
++	---help---
++	  This driver provides DAHDI support for various HFC-S single-port
++          ISDN (BRI) cards.
++
++	  To compile this driver as a module, choose M here: the
++	  module will be called zaphfc.
++
++	  If unsure, say Y.
++
 +config ECHO
 +	tristate "Line Echo Canceller support"
 +	default DAHDI
@@ -107,10 +122,10 @@ index 0000000..baaab35
 +endif
 diff --git a/drivers/dahdi/opvxa1200/base.c b/drivers/dahdi/opvxa1200/base.c
 new file mode 100644
-index 0000000..8b69c94
+index 0000000..c318773
 --- /dev/null
 +++ b/drivers/dahdi/opvxa1200/base.c
-@@ -0,0 +1,3052 @@
+@@ -0,0 +1,3053 @@
 +/*
 + * OpenVox A1200P FXS/FXO Interface Driver for DAHDI Telephony interface
 + *
@@ -215,6 +230,7 @@ index 0000000..8b69c94
 +#include <linux/moduleparam.h>
 +#include <asm/io.h>
 +#include <linux/sched.h>
++#include <linux/nmi.h>
 +#include "proslic.h"
 +   
 +/* MiaoLin debug start */
@@ -3163,6 +3179,2630 @@ index 0000000..8b69c94
 +
 +module_init(wctdm_init);
 +module_exit(wctdm_cleanup);
+diff --git a/drivers/dahdi/zaphfc/Kbuild b/drivers/dahdi/zaphfc/Kbuild
+new file mode 100644
+index 0000000..960fb3a
+--- /dev/null
++++ b/drivers/dahdi/zaphfc/Kbuild
+@@ -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 --git a/drivers/dahdi/zaphfc/base.c b/drivers/dahdi/zaphfc/base.c
+new file mode 100644
+index 0000000..a2045e5
+--- /dev/null
++++ b/drivers/dahdi/zaphfc/base.c
+@@ -0,0 +1,1657 @@
++/*
++ * zaphfc.c - Dahdi driver for HFC-S PCI A based ISDN BRI cards
++ *
++ * Dahdi rewrite in hardhdlc mode
++ * Jose A. Deniz <odicha at 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 at headissue.com>
++ *
++ * Original author of this code is
++ * Daniele "Vihai" Orlandi <daniele at orlandi.com>
++ *
++ * Major rewrite of the driver made by
++ * Klaus-Peter Junghanns <kpj at junghanns.net>
++ *
++ * This program is free software and may be modified and
++ * distributed under the terms of the GNU General 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>
++#include <linux/sched.h>
++#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;
++
++#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 file *file, 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 file *file, 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 file *file, 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;
++
++	hfccard->ddev = dahdi_create_device();
++	hfccard->ddev->manufacturer = "Cologne Chips";
++	hfccard->ddev->devicetype = "HFC-S PCI-A ISDN";
++	hfccard->ddev->location = kasprintf(GFP_KERNEL,
++			"PCI Bus %02d Slot %02d",
++			hfctmp->pcidev->bus->number,
++			PCI_SLOT(hfctmp->pcidev->devfn) + 1);
++	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 ? SPANTYPE_DIGITAL_BRI_NT : 
++		SPANTYPE_DIGITAL_BRI_TE;
++	hfccard->span.flags = 0;
++	hfccard->span.ops = &hfc_zap_span_ops;
++	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;
++
++	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];
++
++	list_add_tail(&hfccard->span.device_node, &hfccard->ddev->spans);
++	if (dahdi_register_device(hfccard->ddev, &hfctmp->pcidev->dev)) {
++		printk(KERN_ERR "unable to register DAHDI device %s!\n",
++				hfccard->span.name);
++		return -1; /* FIXME: release resources? */
++	}
++
++	return 0;
++}
++
++static void hfc_dahdi_free(struct dahdi_hfc *hfccard)
++{
++	kfree(hfccard->ddev->location);
++	dahdi_free_device(hfccard->ddev);
++}
++
++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;
++
++	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) {
++			if (card->chans[D].rx.ugly_framebuf_size) {
++				/*
++				 * We have to wait for Dahdi to transmit the
++				 * frame... wait for next time
++				 */
++
++				 break;
++			} else {
++				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) {
++					continue;
++				}
++			}
++		} else {
++			hfc_fifo_drop_frame(&chan->rx);
++		}
++	}
++
++	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;
++
++	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_device(card->ztdev->ddev);
++	hfc_dahdi_free(card->ztdev);
++
++
++	/*
++	 * disable memio and busmaster
++	 */
++	pci_write_config_word(pci_dev, PCI_COMMAND, 0);
++
++	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");
++
++	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);
++	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 at headissue.com>, "
++		"Daniele (Vihai) Orlandi <daniele at orlandi.com>, "
++		"Jose A. Deniz <odicha at 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 --git a/drivers/dahdi/zaphfc/fifo.c b/drivers/dahdi/zaphfc/fifo.c
+new file mode 100644
+index 0000000..aab46c0
+--- /dev/null
++++ b/drivers/dahdi/zaphfc/fifo.c
+@@ -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 at orlandi.com>
++ *
++ * This program is free software and may be modified and
++ * distributed under the terms of the GNU General 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 --git a/drivers/dahdi/zaphfc/fifo.h b/drivers/dahdi/zaphfc/fifo.h
+new file mode 100644
+index 0000000..e2ae524
+--- /dev/null
++++ b/drivers/dahdi/zaphfc/fifo.h
+@@ -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 at orlandi.com>
++ *
++ * Major rewrite of the driver made by
++ * Klaus-Peter Junghanns <kpj at junghanns.net>
++ *
++ * This program is free software and may be modified and
++ * distributed under the terms of the GNU General 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 --git a/drivers/dahdi/zaphfc/zaphfc.h b/drivers/dahdi/zaphfc/zaphfc.h
+new file mode 100644
+index 0000000..f56a47e
+--- /dev/null
++++ b/drivers/dahdi/zaphfc/zaphfc.h
+@@ -0,0 +1,413 @@
++/*
++ * zaphfc.h - Dahdi driver for HFC-S PCI A based ISDN BRI cards
++ *
++ * Dahdi port by Jose A. Deniz <odicha at 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 at headissue.com>
++ *
++ * Orginal author of this code is
++ * Daniele "Vihai" Orlandi <daniele at orlandi.com>
++ *
++ * Major rewrite of the driver made by
++ * Klaus-Peter Junghanns <kpj at junghanns.net>
++ *
++ * This program is free software and may be modified and
++ * distributed under the terms of the GNU General 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;
++
++	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_device *ddev;
++	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 --git a/drivers/staging/echo/Kbuild b/drivers/staging/echo/Kbuild
 new file mode 100644
 index 0000000..f813006

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-voip/dahdi-linux.git



More information about the Pkg-voip-commits mailing list