[Pkg-voip-commits] r7496 - in /dahdi-linux/trunk/debian: changelog copyright patches/series patches/zaphfc rules

tzafrir-guest at alioth.debian.org tzafrir-guest at alioth.debian.org
Tue Aug 11 12:43:22 UTC 2009


Author: tzafrir-guest
Date: Tue Aug 11 12:43:22 2009
New Revision: 7496

URL: http://svn.debian.org/wsvn/pkg-voip/?sc=1&rev=7496
Log:
Use new zaphfc drivers from http://code.google.com/p/zaphfc/ .
Note that those use hrdhdlc in system.conf . 

Added:
    dahdi-linux/trunk/debian/patches/zaphfc
Modified:
    dahdi-linux/trunk/debian/changelog
    dahdi-linux/trunk/debian/copyright
    dahdi-linux/trunk/debian/patches/series
    dahdi-linux/trunk/debian/rules

Modified: dahdi-linux/trunk/debian/changelog
URL: http://svn.debian.org/wsvn/pkg-voip/dahdi-linux/trunk/debian/changelog?rev=7496&op=diff
==============================================================================
--- dahdi-linux/trunk/debian/changelog (original)
+++ dahdi-linux/trunk/debian/changelog Tue Aug 11 12:43:22 2009
@@ -3,8 +3,10 @@
   * New upstream release
   * New openvox drivers: r113 from their SVN.
   * Fix copyright file for origin of OpenVox drivers.
-
- -- Tzafrir Cohen <tzafrir.cohen at xorcom.com>  Wed, 24 Jun 2009 20:20:44 +0300
+  * Use new zaphfc drivers from http://code.google.com/p/zaphfc/ .
+    Note that those use hrdhdlc in system.conf . 
+
+ -- Tzafrir Cohen <tzafrir.cohen at xorcom.com>  Tue, 11 Aug 2009 15:11:53 +0300
 
 dahdi-linux (1:2.2.0~dfsg~rc5-1) unstable; urgency=low
 

Modified: dahdi-linux/trunk/debian/copyright
URL: http://svn.debian.org/wsvn/pkg-voip/dahdi-linux/trunk/debian/copyright?rev=7496&op=diff
==============================================================================
--- dahdi-linux/trunk/debian/copyright (original)
+++ dahdi-linux/trunk/debian/copyright Tue Aug 11 12:43:22 2009
@@ -5,8 +5,8 @@
   http://www.asterisk.org/
 bristuff patch was downloaded from
   http://www.junghanns.net/download/
-florz' patch for the zaphfc driver was downloaded from
-  http://zaphfc.florz.dyndns.org/
+zaphfc driver was downloaded from
+  http://zaphfc.googlecode.com/
 OpenVox drivers were downloaded from
   http://www.openvox.cn/viewvc/dahdi/trunk/opvxa1200.c?view=co
 
@@ -59,6 +59,9 @@
  * Copyright (C) 2004-2006, Daniele "Vihai" Orlandi <daniele at orlandi.com>
  * Copyright (C) 2006, headissue GmbH; Jens Wilke <jw_vzaphfc at headissue.com>
 
+zaphfc is derived from bristuff and vzaphfc and has been enhanced by:
+  * Copyright (C) 2009, Jose A. Deniz <odicha at hotmail.com>
+
 Files in the xpp/ subdirectory:
 
 * Written by Oron Peled <oron at actcom.co.il>

Modified: dahdi-linux/trunk/debian/patches/series
URL: http://svn.debian.org/wsvn/pkg-voip/dahdi-linux/trunk/debian/patches/series?rev=7496&op=diff
==============================================================================
--- dahdi-linux/trunk/debian/patches/series (original)
+++ dahdi-linux/trunk/debian/patches/series Tue Aug 11 12:43:22 2009
@@ -5,6 +5,8 @@
 #zaphfc-florz
 #florz-vmalloc
 
+zaphfc
+
 # OSLEC:
 oslec_kernelorg
 

Added: dahdi-linux/trunk/debian/patches/zaphfc
URL: http://svn.debian.org/wsvn/pkg-voip/dahdi-linux/trunk/debian/patches/zaphfc?rev=7496&op=file
==============================================================================
--- dahdi-linux/trunk/debian/patches/zaphfc (added)
+++ dahdi-linux/trunk/debian/patches/zaphfc Tue Aug 11 12:43:22 2009
@@ -1,0 +1,2672 @@
+zaphfc r3
+
+diff -Npur old/drivers/dahdi/zaphfc/base.c new/drivers/dahdi/zaphfc/base.c
+--- old/drivers/dahdi/zaphfc/base.c	1970-01-01 02:00:00.000000000 +0200
++++ new/drivers/dahdi/zaphfc/base.c	2009-08-07 08:08:57.000000000 +0300
+@@ -0,0 +1,1701 @@
++/*
++ * 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 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/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
++
++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 = span->pvt;
++    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->sigchan = (sigtype == DAHDI_SIG_HARDHDLC)
++			? d_chan : NULL;
++
++		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 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.spanconfig = hfc_zap_spanconfig;
++	hfccard->span.chanconfig = hfc_zap_chanconfig;
++	hfccard->span.startup = hfc_zap_startup;
++	hfccard->span.shutdown = hfc_zap_shutdown;
++	hfccard->span.maint = hfc_zap_maint;
++	hfccard->span.rbsbits = hfc_zap_rbsbits;
++	hfccard->span.open = hfc_zap_open;
++	hfccard->span.close = hfc_zap_close;
++	hfccard->span.ioctl = hfc_zap_ioctl;
++	hfccard->span.hdlc_hard_xmit = hfc_hdlc_hard_xmit;
++	hfccard->span.flags = 0;
++	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);
++	hfccard->span.pvt = hfccard;
++
++	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[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);
++	card->proc_dir->owner = THIS_MODULE;
++
++	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 at headissue.com>, "
++		"Daniele (Vihai) Orlandi <daniele at orlandi.com>, "
++		"Jose A. Deniz <odicha at hotmail.com>");
++#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 -Npur old/drivers/dahdi/zaphfc/fifo.c new/drivers/dahdi/zaphfc/fifo.c
+--- old/drivers/dahdi/zaphfc/fifo.c	1970-01-01 02:00:00.000000000 +0200
++++ new/drivers/dahdi/zaphfc/fifo.c	2009-08-07 08:08:57.000000000 +0300
+@@ -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 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 -Npur old/drivers/dahdi/zaphfc/fifo.h new/drivers/dahdi/zaphfc/fifo.h
+--- old/drivers/dahdi/zaphfc/fifo.h	1970-01-01 02:00:00.000000000 +0200
++++ new/drivers/dahdi/zaphfc/fifo.h	2009-08-07 08:08:57.000000000 +0300
+@@ -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 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 -Npur old/drivers/dahdi/zaphfc/Kbuild new/drivers/dahdi/zaphfc/Kbuild
+--- old/drivers/dahdi/zaphfc/Kbuild	1970-01-01 02:00:00.000000000 +0200
++++ new/drivers/dahdi/zaphfc/Kbuild	2009-08-07 08:08:57.000000000 +0300
+@@ -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 -Npur old/drivers/dahdi/zaphfc/Makefile new/drivers/dahdi/zaphfc/Makefile
+--- old/drivers/dahdi/zaphfc/Makefile	1970-01-01 02:00:00.000000000 +0200
++++ new/drivers/dahdi/zaphfc/Makefile	2009-08-07 02:35:42.000000000 +0300
+@@ -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 -Npur old/drivers/dahdi/zaphfc/zaphfc.h new/drivers/dahdi/zaphfc/zaphfc.h
+--- old/drivers/dahdi/zaphfc/zaphfc.h	1970-01-01 02:00:00.000000000 +0200
++++ new/drivers/dahdi/zaphfc/zaphfc.h	2009-08-07 08:08:57.000000000 +0300
+@@ -0,0 +1,414 @@
++/*
++ * 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 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 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

Modified: dahdi-linux/trunk/debian/rules
URL: http://svn.debian.org/wsvn/pkg-voip/dahdi-linux/trunk/debian/rules?rev=7496&op=diff
==============================================================================
--- dahdi-linux/trunk/debian/rules (original)
+++ dahdi-linux/trunk/debian/rules Tue Aug 11 12:43:22 2009
@@ -46,7 +46,7 @@
 EXTRA_MODS=opvxa1200
 
 ifneq (,$(filter-out powerpc m68k armeb mips,$(shell dpkg-architecture -qDEB_HOST_ARCH)))
-EXTRA_MODS += wcopenpci zaphfc
+EXTRA_MODS += wcopenpci
 endif
 
 #BRISTUFF_MODULES=cwain qozap zaphfc ztgsm
@@ -59,7 +59,7 @@
   EXTRA_SUBDIRS += vzaphfc
 endif
 
-EXTRA_SUBDIRS += ../staging/echo
+EXTRA_SUBDIRS += zaphfc ../staging/echo
 EXTRA_MODS += dahdi_echocan_oslec
 
 MOD_ARGS=MODULES_EXTRA="$(EXTRA_MODS)" SUBDIRS_EXTRA="$(EXTRA_SUBDIRS)"
@@ -180,6 +180,13 @@
 # For the record: updating openvox drivers:
 # wget 'http://www.openvox.cn/viewvc/dahdi/trunk/opvxa1200.c?view=co' \
 #  | sed -e '\r$//' >drivers/dahdi/opvxa1200.c
+#
+# Updating the zaphfc drivers:
+#   rm -rf old new
+#   mkdir -p old new/drivers/dahdi
+#   svn export http://zaphfc.googlecode.com/svn/branches/2.2/zaphfc/ new/drivers/dahdi/zaphfc
+#   diff -Npur old new >debian/patches/zaphfc
+#   rm -rf old new
 
 TARBALL_DIR=../tarballs/$(PACKAGE_SRC)-$(UPVERSION).tmp
 get-orig-source:




More information about the Pkg-voip-commits mailing list