aboutsummaryrefslogtreecommitdiffstats
path: root/main
diff options
context:
space:
mode:
authorWilliam Pitcock <nenolod@dereferenced.org>2018-02-01 20:55:22 +0000
committerWilliam Pitcock <nenolod@dereferenced.org>2018-02-01 20:55:22 +0000
commita89bb38a6765a19ffc5d6ae4397d2af2cbe6f221 (patch)
tree2d7ce7f3eeeacbe1ae10459a7adacc5742858019 /main
parent4815c17138e1cbc9593e8d630c6d1d71c14e69ae (diff)
downloadaports-a89bb38a6765a19ffc5d6ae4397d2af2cbe6f221.tar.bz2
aports-a89bb38a6765a19ffc5d6ae4397d2af2cbe6f221.tar.xz
main/dahdi-linux-vanilla: new aport (replacing dahdi-linux-hardened)
Diffstat (limited to 'main')
-rw-r--r--main/dahdi-linux-vanilla/APKBUILD108
-rw-r--r--main/dahdi-linux-vanilla/constify.patch22
-rw-r--r--main/dahdi-linux-vanilla/dahdi-2.5.0-bri-fixes.patch327
-rw-r--r--main/dahdi-linux-vanilla/dahdi-bri_dchan.patch167
-rw-r--r--main/dahdi-linux-vanilla/dahdi-depmod.patch22
-rw-r--r--main/dahdi-linux-vanilla/dahdi-zaphfc.patch1429
-rw-r--r--main/dahdi-linux-vanilla/linux-3.13.patch12
-rw-r--r--main/dahdi-linux-vanilla/linux-4.11.patch141
-rw-r--r--main/dahdi-linux-vanilla/linux-4.13.patch299
-rw-r--r--main/dahdi-linux-vanilla/linux-4.4.patch10
-rw-r--r--main/dahdi-linux-vanilla/zaphfc-dahdi-2.4.0.patch58
-rw-r--r--main/dahdi-linux-vanilla/zaphfc-dahdi-2.5.0.patch36
-rw-r--r--main/dahdi-linux-vanilla/zaphfc-dahdi-2.6.0.patch58
-rw-r--r--main/dahdi-linux-vanilla/zaphfc-dahdi-2.7.0.patch32
-rw-r--r--main/dahdi-linux-vanilla/zaphfc-dahdi-flortz.diff1232
15 files changed, 3953 insertions, 0 deletions
diff --git a/main/dahdi-linux-vanilla/APKBUILD b/main/dahdi-linux-vanilla/APKBUILD
new file mode 100644
index 0000000000..04d6242978
--- /dev/null
+++ b/main/dahdi-linux-vanilla/APKBUILD
@@ -0,0 +1,108 @@
+# Contributor: Timo Teras <timo.teras@iki.fi>
+# Maintainer: Timo Teras <timo.teras@iki.fi>
+
+_flavor=vanilla
+_kpkg=linux-$_flavor
+_kver=4.14.16
+_kpkgrel=0
+_mypkgrel=0
+
+_kpkgver="$_kver-r$_kpkgrel"
+_abi_release=${_kver}-${_kpkgrel}-${_flavor}
+_realname=dahdi-linux
+
+pkgname=${_realname}-${_flavor}
+pkgver=$_kver
+# when chaning _dahdiver we *must* bump _mypkgrel
+_dahdiver=2.11.1
+pkgrel=$(( $_kpkgrel + $_mypkgrel ))
+pkgdesc="Digium Asterisk Hardware Device Interface drivers $_dahdiver"
+url="http://www.asterisk.org"
+arch="x86 x86_64"
+license="GPL"
+depends="dahdi-linux linux-${_flavor}=${_kpkgver}"
+# we need wget and tar because make install downloads firmware and uses fancy
+# options for tar and wget.
+makedepends="linux-${_flavor}-dev=${_kpkgver} wget tar perl"
+install=
+subpackages="$pkgname-dev"
+provides="${_realname}-grsec=${pkgver}-r${pkgrel}"
+source="http://downloads.digium.com/pub/telephony/dahdi-linux/releases/${_realname}-$_dahdiver.tar.gz
+ dahdi-depmod.patch
+ dahdi-bri_dchan.patch
+ dahdi-zaphfc.patch
+ zaphfc-dahdi-flortz.diff
+ zaphfc-dahdi-2.4.0.patch
+ zaphfc-dahdi-2.5.0.patch
+ zaphfc-dahdi-2.6.0.patch
+ zaphfc-dahdi-2.7.0.patch
+ linux-3.13.patch
+ linux-4.4.patch
+ linux-4.11.patch
+ linux-4.13.patch
+ "
+
+prepare() {
+ cd "$srcdir/$_realname-$_dahdiver"
+ # verify the kernel version
+ (
+
+ if [ -f "$startdir"/../linux-${_flavor}/APKBUILD ]; then
+ . "$startdir"/../linux-${_flavor}/APKBUILD
+ if [ "$_kver" != "$pkgver" ]; then
+ die "dahdi-linux-grsec: please update _kver to $pkgver"
+ fi
+ if [ "$_kpkgrel" != "$pkgrel" ]; then
+ die "dahdi-linux-grsec: please update _kpkgrel to $pkgrel"
+ fi
+ fi
+ ) || return 1
+
+ for i in $source; do
+ case $i in
+ *.patch|*.diff)
+ msg "Applying $i"
+ patch -p1 -i "$srcdir"/$i || return 1
+ ;;
+ esac
+ done
+}
+
+build() {
+ cd "$srcdir/$_realname-$_dahdiver"
+ make KVERS="${_abi_release}" DYNFS="yes" MODULES_EXTRA="zaphfc" \
+ || return 1
+}
+
+package() {
+ cd "$srcdir/$_realname-$_dahdiver"
+ make KVERS="${_abi_release}" DYNFS="yes" MODULES_EXTRA="zaphfc" \
+ DESTDIR="$pkgdir" install-modules || return 1
+ rm -rf "$pkgdir"/lib/firmware "$pkgdir"/usr/lib/hotplug/firmware \
+ "$pkgdir"/usr/include
+}
+
+# since we sourced the APKBUILD above we got the dev() function there to
+# so we override it again.
+depends_dev="dahdi-linux-dev"
+dev() {
+ default_dev
+ local dir="$subpkgdir"/usr/src/dahdi-headers-${_abi_release}
+ install -D "$srcdir"/$_realname-$_dahdiver/drivers/dahdi/Module.symvers \
+ "$dir"/drivers/dahdi/Module.symvers
+ ln -s /usr/include "$dir"/include
+}
+
+sha512sums="db15d9237f157b5349de8f4cdb45573ed42e1dd25c83f900835c7e15637a19e1e95c7c990dc786c1e3f37f32419f3d009e179d27b5d16421789ff9bc76f54224 dahdi-linux-2.11.1.tar.gz
+aba01eb90d9db1c595ff22078c76aadb20900486b5794d38b7ee61fa30d2fb51be318a4d059246017640447aee03fb09bb5514c818e3caa1cd98e331ec065173 dahdi-depmod.patch
+fa2fa9e96eefc0f31a1a4a8f8f44e77936f6da0d7b74fe3c3d1f0de085621744ae4367932ac97a10b7f96b7d0954843b0bfe07a251b85434079cc6da29e243ba dahdi-bri_dchan.patch
+8ef31c9723237da83954832df5aee1f5daa23f8fefe07a1a191a2c5da2c2308001d68cee83500f7ef43166bfc0d65552b0ca5362789c5c82a7217e09362fd5fe dahdi-zaphfc.patch
+f18043fd18a05be7e49daa9d8c96c8a8c45936b14e82e30523e4d88b1620a73147f765d24d2038c4ec0855901e36e8e2b188d596f94437dfb80f6d76ab699d9d zaphfc-dahdi-flortz.diff
+8068fcbba81b819bbd14a1a324457d0febd5350d16c6443be035c50f7759010376bd92d3c7ea69b47309e02603e587387b643f64663652e162853515371a6da5 zaphfc-dahdi-2.4.0.patch
+95811d56f5567bbab1e6fac89fdc7a4d78252a54a416e884903ae2709f8922f5cd02c492de0bad5c35fdfd52250ec231ed11457e36ba33f8747c3226491882de zaphfc-dahdi-2.5.0.patch
+7533c640817f71789c922bb9a5a3b6132b5b47958770929b1c9a50a1e2e6de914e278f466a85ef99759e291e5907c56d60926c74075f4e731a9910a46c1be3ea zaphfc-dahdi-2.6.0.patch
+daca74da31c655265164a854987d45ca5ee3af1defbe2d49a9f1a70a48a43dc2bc3ceba724781ae29e3a9078b827f641d2e29809fb25101986f2f69c767d1382 zaphfc-dahdi-2.7.0.patch
+dfc2b0357dc3d2a37c45f1fcc503009cf35e99c8b174d0dd7c91ac4c2c9bb3428f9a19a3f264446069fd751441833f43e11b3b55a060865c6daca9bef74008be linux-3.13.patch
+18cc299c9b9ab05b93769c0aa68595d3b3b640b97c6ee546b9cbe551f08679557c7e2a5a8255577ab6ae7036c2210550b45066b03d04ebbe7adad1a59aba5866 linux-4.4.patch
+1ce44a927607e04013f03af7655687098397b68c0e857beb5b4d6ae09e92cac59974fd69b5be6bf6d2e4d8e5643f2ce54d9e05661da656d943b5f30c4696ef41 linux-4.11.patch
+ded7386794abad54fb9f7106e4dc0cc62da1a6b32baaed35a15820f935fe65128e9639bf27eaca392fec0750fd0ee13dbb0cbbf95b8d749085d491361a2b3da2 linux-4.13.patch"
diff --git a/main/dahdi-linux-vanilla/constify.patch b/main/dahdi-linux-vanilla/constify.patch
new file mode 100644
index 0000000000..6741522f23
--- /dev/null
+++ b/main/dahdi-linux-vanilla/constify.patch
@@ -0,0 +1,22 @@
+--- ./drivers/dahdi/voicebus/voicebus.h.orig
++++ ./drivers/dahdi/voicebus/voicebus.h
+@@ -89,7 +89,7 @@
+ void (*handle_receive)(struct voicebus *vb, struct list_head *buffers);
+ void (*handle_transmit)(struct voicebus *vb, struct list_head *buffers);
+ void (*handle_error)(struct voicebus *vb);
+-};
++} __no_const;
+
+ /**
+ * struct voicebus_descriptor_list - A single descriptor list.
+--- ./drivers/dahdi/wctc4xxp/base.c.orig
++++ ./drivers/dahdi/wctc4xxp/base.c
+@@ -3193,7 +3193,7 @@
+ return ret;
+ }
+
+-static void wctc4xxp_setup_file_operations(struct file_operations *fops)
++static void wctc4xxp_setup_file_operations(file_operations_no_const *fops)
+ {
+ fops->owner = THIS_MODULE;
+ fops->read = wctc4xxp_read;
diff --git a/main/dahdi-linux-vanilla/dahdi-2.5.0-bri-fixes.patch b/main/dahdi-linux-vanilla/dahdi-2.5.0-bri-fixes.patch
new file mode 100644
index 0000000000..01dcf646fb
--- /dev/null
+++ b/main/dahdi-linux-vanilla/dahdi-2.5.0-bri-fixes.patch
@@ -0,0 +1,327 @@
+Index: dahdi-linux-2.5.0/drivers/dahdi/xpp/card_bri.c
+===================================================================
+--- dahdi-linux-2.5.0.orig/drivers/dahdi/xpp/card_bri.c 2011-08-15 14:42:29.000000000 +0300
++++ dahdi-linux-2.5.0/drivers/dahdi/xpp/card_bri.c 2011-08-15 14:51:37.000000000 +0300
+@@ -274,7 +274,6 @@
+ int frame_begin;
+
+ priv = xpd->priv;
+- BUG_ON(!priv);
+ if(transmit) {
+ direction = "TX";
+ frame_begin = priv->txframe_begin;
+@@ -312,9 +311,7 @@
+ {
+ struct BRI_priv_data *priv;
+
+- BUG_ON(!xpd);
+ priv = xpd->priv;
+- BUG_ON(!priv);
+ if(priv->dchan_alive == up)
+ return;
+ if(up) {
+@@ -332,9 +329,7 @@
+ {
+ struct BRI_priv_data *priv;
+
+- BUG_ON(!xpd);
+ priv = xpd->priv;
+- BUG_ON(!priv);
+ if(priv->layer1_up == up)
+ return;
+ priv->layer1_up = up;
+@@ -348,9 +343,7 @@
+ struct BRI_priv_data *priv;
+ byte curr_state;
+
+- BUG_ON(!xpd);
+ priv = xpd->priv;
+- BUG_ON(!priv);
+ curr_state = priv->state_register.bits.v_su_sta;
+ XPD_DBG(SIGNAL, xpd, "%s\n", (on)?"ON":"OFF");
+ if(on) {
+@@ -391,9 +384,7 @@
+ struct BRI_priv_data *priv;
+ byte curr_state;
+
+- BUG_ON(!xpd);
+ priv = xpd->priv;
+- BUG_ON(!priv);
+ curr_state = priv->state_register.bits.v_su_sta;
+ XPD_DBG(SIGNAL, xpd, "%s\n", (on)?"ON":"OFF");
+ if(on) {
+@@ -443,7 +434,6 @@
+ struct BRI_priv_data *priv;
+
+ priv = xpd->priv;
+- BUG_ON(!priv);
+ #ifdef CONFIG_DAHDI_BRI_DCHANS
+ if(debug & DBG_COMMANDS)
+ dump_hex_buf(xpd, "D-Chan(abort) RX: dchan_rbuf",
+@@ -460,7 +450,6 @@
+ byte status;
+
+ priv = xpd->priv;
+- BUG_ON(!priv);
+ #ifdef CONFIG_DAHDI_BRI_DCHANS
+ if(priv->dchan_r_idx < 4) {
+ XPD_NOTICE(xpd, "D-Chan RX short frame (dchan_r_idx=%d)\n",
+@@ -503,7 +492,6 @@
+ int idx;
+
+ priv = xpd->priv;
+- BUG_ON(!priv);
+ dchan_buf = dchan->readchunk;
+ idx = priv->dchan_r_idx;
+ if(idx + len >= DCHAN_BUFSIZE) {
+@@ -527,7 +515,6 @@
+ struct BRI_priv_data *priv;
+
+ priv = xpd->priv;
+- BUG_ON(!priv);
+ #ifdef CONFIG_DAHDI_BRI_DCHANS
+ dchan->bytes2receive = priv->dchan_r_idx - 1;
+ dchan->eofrx = 1;
+@@ -556,10 +543,7 @@
+ return 0;
+ if(!SPAN_REGISTERED(xpd)) /* Nowhere to copy data */
+ return 0;
+- BUG_ON(!xpd);
+ priv = xpd->priv;
+- BUG_ON(!priv);
+- xbus = xpd->xbus;
+ dchan = XPD_CHAN(xpd, 2);
+ if(!IS_OFFHOOK(xpd, 2)) { /* D-chan is used? */
+ static int rate_limit;
+@@ -629,9 +613,7 @@
+ return 0;
+ if(!SPAN_REGISTERED(xpd)) /* Nowhere to copy data */
+ return 0;
+- BUG_ON(!xpd);
+ priv = xpd->priv;
+- BUG_ON(!priv);
+ dchan = XPD_CHAN(xpd, 2);
+ if(!IS_OFFHOOK(xpd, 2)) { /* D-chan is used? */
+ static int rate_limit;
+@@ -677,7 +659,6 @@
+ struct BRI_priv_data *priv;
+
+ priv = xpd->priv;
+- BUG_ON(!priv);
+ dchan = XPD_CHAN(xpd, 2);
+ if (dchan == chan) {
+ atomic_inc(&priv->hdlc_pending);
+@@ -716,7 +697,6 @@
+ int ret;
+
+ priv = xpd->priv;
+- BUG_ON(!priv);
+ #ifndef CONFIG_DAHDI_BRI_DCHANS
+ if(atomic_read(&priv->hdlc_pending) == 0)
+ return 0;
+@@ -769,7 +749,6 @@
+ {
+ struct BRI_priv_data *priv;
+
+- BUG_ON(!xpd);
+ priv = xpd->priv;
+ XPD_DBG(PROC, xpd, "\n");
+ #ifdef CONFIG_PROC_FS
+@@ -784,7 +763,6 @@
+ {
+ struct BRI_priv_data *priv;
+
+- BUG_ON(!xpd);
+ priv = xpd->priv;
+ XPD_DBG(PROC, xpd, "\n");
+ #ifdef CONFIG_PROC_FS
+@@ -828,7 +806,6 @@
+ {
+ struct BRI_priv_data *priv;
+
+- BUG_ON(!xpd);
+ XPD_DBG(GENERAL, xpd, "\n");
+ priv = xpd->priv;
+ DO_LED(xpd, GREEN_LED, BRI_LED_OFF);
+@@ -841,7 +818,6 @@
+
+ static int BRI_card_remove(xbus_t *xbus, xpd_t *xpd)
+ {
+- BUG_ON(!xpd);
+ XPD_DBG(GENERAL, xpd, "\n");
+ bri_proc_remove(xbus, xpd);
+ return 0;
+@@ -877,10 +853,8 @@
+ struct BRI_priv_data *priv;
+ int i;
+
+- BUG_ON(!xpd);
+ xbus = xpd->xbus;
+ priv = xpd->priv;
+- BUG_ON(!xbus);
+ XPD_DBG(GENERAL, xpd, "%s\n", (on)?"on":"off");
+ if(!on) {
+ /* Nothing to do yet */
+@@ -927,11 +901,6 @@
+
+ static int BRI_card_dahdi_postregistration(xpd_t *xpd, bool on)
+ {
+- xbus_t *xbus;
+-
+- BUG_ON(!xpd);
+- xbus = xpd->xbus;
+- BUG_ON(!xbus);
+ XPD_DBG(GENERAL, xpd, "%s\n", (on)?"on":"off");
+ return(0);
+ }
+@@ -956,7 +925,6 @@
+ int other_led;
+ int mod;
+
+- BUG_ON(!xpd);
+ if(IS_NT(xpd)) {
+ which_led = RED_LED;
+ other_led = GREEN_LED;
+@@ -965,7 +933,6 @@
+ other_led = RED_LED;
+ }
+ priv = xpd->priv;
+- BUG_ON(!priv);
+ timer_count = xpd->timer_count;
+ if(xpd->blink_mode) {
+ if((timer_count % DEFAULT_LED_PERIOD) == 0) {
+@@ -1014,9 +981,7 @@
+ {
+ struct BRI_priv_data *priv;
+
+- BUG_ON(!xpd);
+ priv = xpd->priv;
+- BUG_ON(!priv);
+ if(IS_NT(xpd)) {
+ if (priv->t1 > HFC_TIMER_OFF) {
+ if (--priv->t1 == 0) {
+@@ -1053,9 +1018,7 @@
+ {
+ struct BRI_priv_data *priv;
+
+- BUG_ON(!xpd);
+ priv = xpd->priv;
+- BUG_ON(!priv);
+ if(!priv->initialized || !xbus->self_ticking)
+ return 0;
+ if(poll_interval != 0 && (priv->tick_counter % poll_interval) == 0) {
+@@ -1111,7 +1074,6 @@
+
+ static int BRI_card_ioctl(xpd_t *xpd, int pos, unsigned int cmd, unsigned long arg)
+ {
+- BUG_ON(!xpd);
+ if(!XBUS_IS(xpd->xbus, READY))
+ return -ENODEV;
+ switch (cmd) {
+@@ -1131,7 +1093,6 @@
+
+ static int BRI_card_open(xpd_t *xpd, lineno_t pos)
+ {
+- BUG_ON(!xpd);
+ if(pos == 2) {
+ LINE_DBG(SIGNAL, xpd, pos, "OFFHOOK the whole span\n");
+ BIT_SET(PHONEDEV(xpd).offhook_state, 0);
+@@ -1230,12 +1191,8 @@
+ {
+ struct phonedev *phonedev = container_of(span, struct phonedev, span);
+ xpd_t *xpd = container_of(phonedev, struct xpd, phonedev);
+- struct BRI_priv_data *priv;
+ struct dahdi_chan *dchan;
+
+- BUG_ON(!xpd);
+- priv = xpd->priv;
+- BUG_ON(!priv);
+ if(!XBUS_IS(xpd->xbus, READY)) {
+ XPD_DBG(GENERAL, xpd, "Startup called by dahdi. No Hardware. Ignored\n");
+ return -ENODEV;
+@@ -1267,11 +1224,7 @@
+ {
+ struct phonedev *phonedev = container_of(span, struct phonedev, span);
+ xpd_t *xpd = container_of(phonedev, struct xpd, phonedev);
+- struct BRI_priv_data *priv;
+
+- BUG_ON(!xpd);
+- priv = xpd->priv;
+- BUG_ON(!priv);
+ if(!XBUS_IS(xpd->xbus, READY)) {
+ XPD_DBG(GENERAL, xpd, "Shutdown called by dahdi. No Hardware. Ignored\n");
+ return -ENODEV;
+@@ -1292,7 +1245,6 @@
+ xpd_t *main_xpd;
+ unsigned long flags;
+
+- BUG_ON(!xpd);
+ main_xpd = xpd_byaddr(xpd->xbus, xpd->addr.unit, 0);
+ if(!main_xpd) {
+ XPD_DBG(DEVICES, xpd, "Unit 0 is already gone. Ignore request\n");
+@@ -1350,8 +1302,6 @@
+ xpp_line_t wanted_lines;
+
+
+- BUG_ON(!xpd);
+- BUG_ON(!pack);
+ pcm = RPACKET_FIELD(pack, GLOBAL, PCM_WRITE, pcm);
+ for(subunit = 0; subunit < MAX_SUBUNIT; subunit++) {
+ xpd_t *tmp_xpd;
+@@ -1435,12 +1385,8 @@
+
+ static int BRI_echocancel_setmask(xpd_t *xpd, xpp_line_t ec_mask)
+ {
+- struct BRI_priv_data *priv;
+ int i;
+
+- BUG_ON(!xpd);
+- priv = xpd->priv;
+- BUG_ON(!priv);
+ XPD_DBG(GENERAL, xpd, "0x%8X\n", ec_mask);
+ if (!ECHOOPS(xpd->xbus)) {
+ XPD_DBG(GENERAL, xpd,
+@@ -1466,9 +1412,7 @@
+ struct bri_leds *bri_leds;
+ struct BRI_priv_data *priv;
+
+- BUG_ON(!xbus);
+ priv = xpd->priv;
+- BUG_ON(!priv);
+ XPD_DBG(LEDS, xpd, "%s -> %d\n",
+ (which_led)?"RED":"GREEN",
+ to_led_state);
+@@ -1507,9 +1451,7 @@
+ struct BRI_priv_data *priv;
+ su_rd_sta_t new_state;
+
+- BUG_ON(!xpd);
+ priv = xpd->priv;
+- BUG_ON(!priv);
+ if(!priv->initialized) {
+ XPD_ERR(xpd, "%s called on uninitialized AB\n", __FUNCTION__);
+ return;
+@@ -1621,7 +1563,6 @@
+ }
+ spin_lock_irqsave(&xpd->lock, flags);
+ priv = xpd->priv;
+- BUG_ON(!priv);
+ if(REG_FIELD(info, do_subreg)) {
+ XPD_DBG(REGS, xpd, "RI %02X %02X %02X\n",
+ REG_FIELD(info, regnum), REG_FIELD(info, subreg), REG_FIELD(info, data_low));
+@@ -1665,7 +1606,6 @@
+ {
+ struct BRI_priv_data *priv;
+
+- BUG_ON(!xpd);
+ priv = xpd->priv;
+ XPD_DBG(GENERAL, xpd, "%s\n", (on)?"ON":"OFF");
+ if(on) {
+@@ -1745,7 +1685,6 @@
+ return -ENODEV;
+ spin_lock_irqsave(&xpd->lock, flags);
+ priv = xpd->priv;
+- BUG_ON(!priv);
+ len += sprintf(page + len, "%05d Layer 1: ", priv->poll_counter);
+ if(priv->reg30_good) {
+ len += sprintf(page + len, "%-5s ", (priv->layer1_up) ? "UP" : "DOWN");
diff --git a/main/dahdi-linux-vanilla/dahdi-bri_dchan.patch b/main/dahdi-linux-vanilla/dahdi-bri_dchan.patch
new file mode 100644
index 0000000000..8d2ba97fd1
--- /dev/null
+++ b/main/dahdi-linux-vanilla/dahdi-bri_dchan.patch
@@ -0,0 +1,167 @@
+# Translate the D channels to a standard channel data.
+# The HFC chipset provides us the D channel as data, but
+# Zaptel expects it as a standard channel with 1000 samples
+# per second.
+
+Index: dahdi-linux-2.5.0/include/dahdi/kernel.h
+===================================================================
+--- dahdi-linux-2.5.0.orig/include/dahdi/kernel.h 2011-06-29 18:32:40.000000000 +0300
++++ dahdi-linux-2.5.0/include/dahdi/kernel.h 2011-08-15 14:14:26.000000000 +0300
+@@ -413,6 +413,13 @@
+ int statcount;
+ int lastnumbufs;
+ #endif
++#ifdef CONFIG_DAHDI_BRI_DCHANS
++ int bytes2receive;
++ int maxbytes2transmit; /* size of the tx buffer in the card driver */
++ int bytes2transmit;
++ int eofrx;
++ int eoftx;
++#endif
+ spinlock_t lock;
+ char name[40];
+ /* Specified by DAHDI */
+@@ -723,6 +730,9 @@
+ DAHDI_FLAGBIT_TXUNDERRUN = 22, /*!< Transmit underrun condition */
+ DAHDI_FLAGBIT_RXOVERRUN = 23, /*!< Receive overrun condition */
+ DAHDI_FLAGBIT_DEVFILE = 25, /*!< Channel has a sysfs dev file */
++#if defined(CONFIG_DAHDI_BRI_DCHANS)
++ DAHDI_FLAGBIT_BRIDCHAN = 26, /*!< hardhdlc-like handling of the D channel */
++#endif
+ };
+
+ #ifdef CONFIG_DAHDI_NET
+@@ -789,6 +799,7 @@
+ #define DAHDI_FLAG_BUFEVENTS DAHDI_FLAG(BUFEVENTS)
+ #define DAHDI_FLAG_TXUNDERRUN DAHDI_FLAG(TXUNDERRUN)
+ #define DAHDI_FLAG_RXOVERRUN DAHDI_FLAG(RXOVERRUN)
++#define DAHDI_FLAG_BRIDCHAN DAHDI_FLAG(BRIDCHAN)
+
+ struct file;
+
+Index: dahdi-linux-2.5.0/include/dahdi/dahdi_config.h
+===================================================================
+--- dahdi-linux-2.5.0.orig/include/dahdi/dahdi_config.h 2011-01-05 17:52:03.000000000 +0200
++++ dahdi-linux-2.5.0/include/dahdi/dahdi_config.h 2011-08-15 14:13:01.000000000 +0300
+@@ -195,4 +195,10 @@
+ */
+ /* #define CONFIG_DAHDI_MIRROR */
+
++/*
++ * Uncomment the following for BRI D channels
++ *
++ */
++#define CONFIG_DAHDI_BRI_DCHANS
++
+ #endif
+Index: dahdi-linux-2.5.0/drivers/dahdi/dahdi-base.c
+===================================================================
+--- dahdi-linux-2.5.0.orig/drivers/dahdi/dahdi-base.c 2011-07-21 19:26:31.000000000 +0300
++++ dahdi-linux-2.5.0/drivers/dahdi/dahdi-base.c 2011-08-15 14:13:01.000000000 +0300
+@@ -7224,11 +7224,40 @@
+ *(txb++) = fasthdlc_tx_run_nocheck(&ms->txhdlc);
+ }
+ bytes -= left;
++#ifdef CONFIG_DAHDI_BRI_DCHANS
++ } else if (test_bit(DAHDI_FLAGBIT_BRIDCHAN, &ms->flags)) {
++ /*
++ * Let's get this right, we want to transmit complete frames only.
++ * The card driver will do the dirty HDLC work for us.
++ * txb (transmit buffer) is supposed to be big enough to store one frame
++ * we will make this as big as the D fifo (1KB or 2KB)
++ */
++
++ /* there are 'left' bytes in the user buffer left to transmit */
++ left = ms->writen[ms->outwritebuf] - ms->writeidx[ms->outwritebuf] - 2;
++ if (left > ms->maxbytes2transmit) {
++ memcpy(txb, buf + ms->writeidx[ms->outwritebuf], ms->maxbytes2transmit);
++ ms->writeidx[ms->outwritebuf] += ms->maxbytes2transmit;
++ txb += ms->maxbytes2transmit;
++ ms->bytes2transmit = ms->maxbytes2transmit;
++ ms->eoftx = 0;
++ } else {
++ memcpy(txb, buf + ms->writeidx[ms->outwritebuf], left);
++ ms->writeidx[ms->outwritebuf] += left + 2;
++ txb += left + 2;
++ ms->bytes2transmit = left;
++ ms->eoftx = 1;
++ }
++ bytes = 0;
++#endif
+ } else {
+ memcpy(txb, buf + ms->writeidx[ms->outwritebuf], left);
+ ms->writeidx[ms->outwritebuf]+=left;
+ txb += left;
+ bytes -= left;
++#if defined(CONFIG_DAHDI_BRI_DCHANS)
++ ms->bytes2transmit=DAHDI_CHUNKSIZE;
++#endif
+ }
+ /* Check buffer status */
+ if (ms->writeidx[ms->outwritebuf] >= ms->writen[ms->outwritebuf]) {
+@@ -7285,6 +7314,17 @@
+ /* Transmit a flag if this is an HDLC channel */
+ if (ms->flags & DAHDI_FLAG_HDLC)
+ fasthdlc_tx_frame_nocheck(&ms->txhdlc);
++#if defined(CONFIG_DAHDI_BRI_DCHANS)
++ if (test_bit(DAHDI_FLAGBIT_BRIDCHAN, &ms->flags)) {
++ // if (ms->bytes2transmit > 0) {
++ // txb += 2;
++ // ms->bytes2transmit -= 2;
++ bytes=0;
++ ms->eoftx = 1;
++// printk(KERN_CRIT "zaptel EOF(%d) bytes2transmit %d\n",ms->eoftx,ms->bytes2transmit);
++ // }
++ }
++#endif
+ #ifdef CONFIG_DAHDI_NET
+ if (dahdi_have_netdev(ms))
+ netif_wake_queue(chan_to_netdev(ms));
+@@ -7346,6 +7386,12 @@
+ }
+ needtxunderrun += bytes;
+ bytes = 0;
++#if defined(CONFIG_DAHDI_BRI_DCHANS)
++ } else if (test_bit(DAHDI_FLAGBIT_BRIDCHAN, &ms->flags)) {
++ ms->bytes2transmit = 0;
++ ms->eoftx = 0;
++ bytes = 0;
++#endif
+ } else {
+ memset(txb, DAHDI_LIN2X(0, ms), bytes); /* Lastly we use silence on telephony channels */
+ needtxunderrun += bytes;
+@@ -8267,6 +8313,14 @@
+ int res;
+ int left, x;
+
++#if defined(CONFIG_DAHDI_BRI_DCHANS)
++ if (test_bit(DAHDI_FLAGBIT_BRIDCHAN, &ms->flags)) {
++ bytes = ms->bytes2receive;
++ if (bytes < 1) return;
++// printk(KERN_CRIT "bytes2receive %d\n",ms->bytes2receive);
++ }
++#endif
++
+ while(bytes) {
+ #if defined(CONFIG_DAHDI_NET) || defined(CONFIG_DAHDI_PPP)
+ skb = NULL;
+@@ -8324,6 +8378,19 @@
+ }
+ }
+ }
++#ifdef CONFIG_DAHDI_BRI_DCHANS
++ } else if (test_bit(DAHDI_FLAGBIT_BRIDCHAN, &ms->flags)) {
++ memcpy(buf + ms->readidx[ms->inreadbuf], rxb, left);
++ rxb += left;
++ ms->readidx[ms->inreadbuf] += left;
++ bytes -= left;
++ if (ms->eofrx == 1) {
++ eof=1;
++ }
++// printk(KERN_CRIT "receiving %d bytes\n",ms->bytes2receive);
++ ms->bytes2receive = 0;
++ ms->eofrx = 0;
++#endif
+ } else {
+ /* Not HDLC */
+ memcpy(buf + ms->readidx[ms->inreadbuf], rxb, left);
diff --git a/main/dahdi-linux-vanilla/dahdi-depmod.patch b/main/dahdi-linux-vanilla/dahdi-depmod.patch
new file mode 100644
index 0000000000..289aad403b
--- /dev/null
+++ b/main/dahdi-linux-vanilla/dahdi-depmod.patch
@@ -0,0 +1,22 @@
+Index: dahdi-linux-2.0.0-rc4/Makefile
+===================================================================
+--- dahdi-linux-2.0.0-rc4.orig/Makefile 2008-09-09 14:07:23.000000000 +0300
++++ dahdi-linux-2.0.0-rc4/Makefile 2008-09-09 14:12:31.000000000 +0300
+@@ -190,7 +190,7 @@
+ build_tools/uninstall-modules dahdi $(KVERS)
+ endif
+ $(KMAKE) INSTALL_MOD_PATH=$(DESTDIR) INSTALL_MOD_DIR=dahdi modules_install
+- [ `id -u` = 0 ] && /sbin/depmod -a $(KVERS) || :
++ [ -z "$(DESTDIR)" -a `id -u` = 0 ] && /sbin/depmod -a $(KVERS) || :
+
+ uninstall-modules:
+ ifdef DESTDIR
+@@ -203,7 +203,7 @@
+ rm -rf /lib/modules/$(KVERS)/dahdi; \
+ echo "done."; \
+ fi
+- [ `id -u` = 0 ] && /sbin/depmod -a $(KVERS) || :
++ [ -z "$(DESTDIR)" -a `id -u` = 0 ] && /sbin/depmod -a $(KVERS) || :
+ endif
+
+ update:
diff --git a/main/dahdi-linux-vanilla/dahdi-zaphfc.patch b/main/dahdi-linux-vanilla/dahdi-zaphfc.patch
new file mode 100644
index 0000000000..931c5b5cf6
--- /dev/null
+++ b/main/dahdi-linux-vanilla/dahdi-zaphfc.patch
@@ -0,0 +1,1429 @@
+Index: dahdi-linux-2.1.0/drivers/dahdi/zaphfc.c
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ dahdi-linux-2.1.0/drivers/dahdi/zaphfc.c 2008-12-10 12:46:14.000000000 +0200
+@@ -0,0 +1,1129 @@
++/*
++ * zaphfc.c - Zaptel driver for HFC-S PCI A based ISDN BRI cards
++ *
++ * kernel module inspired by HFC PCI ISDN4Linux and Zaptel drivers
++ *
++ * Copyright (C) 2002, 2003, 2004, 2005 Junghanns.NET GmbH
++ *
++ * Klaus-Peter Junghanns <kpj@junghanns.net>
++ *
++ * This program is free software and may be modified and
++ * distributed under the terms of the GNU Public License.
++ *
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#ifdef RTAITIMING
++#include <asm/io.h>
++#include <rtai.h>
++#include <rtai_sched.h>
++#include <rtai_fifos.h>
++#endif
++#include <linux/pci.h>
++#include <linux/init.h>
++#include <linux/interrupt.h>
++#include <linux/delay.h>
++#include <dahdi/kernel.h>
++#include "zaphfc.h"
++
++#include <linux/moduleparam.h>
++
++#if CONFIG_PCI
++
++#define CLKDEL_TE 0x0f /* CLKDEL in TE mode */
++#define CLKDEL_NT 0x6c /* CLKDEL in NT mode */
++
++typedef struct {
++ int vendor_id;
++ int device_id;
++ char *vendor_name;
++ char *card_name;
++} PCI_ENTRY;
++
++static const PCI_ENTRY id_list[] =
++{
++ {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_2BD0, "CCD/Billion/Asuscom", "2BD0"},
++ {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B000, "Billion", "B000"},
++ {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B006, "Billion", "B006"},
++ {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B007, "Billion", "B007"},
++ {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B008, "Billion", "B008"},
++ {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B009, "Billion", "B009"},
++ {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B00A, "Billion", "B00A"},
++ {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B00B, "Billion", "B00B"},
++ {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B00C, "Billion", "B00C"},
++ {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B100, "Seyeon", "B100"},
++ {PCI_VENDOR_ID_ABOCOM, PCI_DEVICE_ID_ABOCOM_2BD1, "Abocom/Magitek", "2BD1"},
++ {PCI_VENDOR_ID_ASUSTEK, PCI_DEVICE_ID_ASUSTEK_0675, "Asuscom/Askey", "675"},
++ {PCI_VENDOR_ID_BERKOM, PCI_DEVICE_ID_BERKOM_T_CONCEPT, "German telekom", "T-Concept"},
++ {PCI_VENDOR_ID_BERKOM, PCI_DEVICE_ID_BERKOM_A1T, "German telekom", "A1T"},
++ {PCI_VENDOR_ID_ANIGMA, PCI_DEVICE_ID_ANIGMA_MC145575, "Motorola MC145575", "MC145575"},
++ {PCI_VENDOR_ID_ZOLTRIX, PCI_DEVICE_ID_ZOLTRIX_2BD0, "Zoltrix", "2BD0"},
++ {PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_DIGI_DF_M_IOM2_E,"Digi International", "Digi DataFire Micro V IOM2 (Europe)"},
++ {PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_DIGI_DF_M_E,"Digi International", "Digi DataFire Micro V (Europe)"},
++ {PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_DIGI_DF_M_IOM2_A,"Digi International", "Digi DataFire Micro V IOM2 (North America)"},
++ {PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_DIGI_DF_M_A,"Digi International", "Digi DataFire Micro V (North America)"},
++ {0x182d, 0x3069,"Sitecom","Isdn 128 PCI"},
++ {0, 0, NULL, NULL},
++};
++
++static struct hfc_card *hfc_dev_list = NULL;
++static int hfc_dev_count = 0;
++static int modes = 0; // all TE
++static int debug = 0;
++static struct pci_dev *multi_hfc = NULL;
++static DEFINE_SPINLOCK(registerlock);
++
++void hfc_shutdownCard(struct hfc_card *hfctmp) {
++ unsigned long flags;
++
++ if (hfctmp == NULL) {
++ return;
++ }
++
++ if (hfctmp->pci_io == NULL) {
++ return;
++ }
++
++ spin_lock_irqsave(&hfctmp->lock,flags);
++
++ printk(KERN_INFO "zaphfc: shutting down card at %p.\n",hfctmp->pci_io);
++
++ /* Clear interrupt mask */
++ hfctmp->regs.int_m2 = 0;
++ hfc_outb(hfctmp, hfc_INT_M2, hfctmp->regs.int_m2);
++
++ /* Reset pending interrupts */
++ hfc_inb(hfctmp, hfc_INT_S1);
++
++ /* Wait for interrupts that might still be pending */
++ spin_unlock_irqrestore(&hfctmp->lock, flags);
++ set_current_state(TASK_UNINTERRUPTIBLE);
++ schedule_timeout((30 * HZ) / 1000); // wait 30 ms
++ spin_lock_irqsave(&hfctmp->lock,flags);
++
++ /* Remove interrupt handler */
++ if (hfctmp->irq) {
++ free_irq(hfctmp->irq, hfctmp);
++ }
++
++ /* Soft-reset the card */
++ hfc_outb(hfctmp, hfc_CIRM, hfc_CIRM_RESET); // softreset on
++
++ spin_unlock_irqrestore(&hfctmp->lock, flags);
++ set_current_state(TASK_UNINTERRUPTIBLE);
++ schedule_timeout((30 * HZ) / 1000); // wait 30 ms
++ spin_lock_irqsave(&hfctmp->lock,flags);
++
++ hfc_outb(hfctmp,hfc_CIRM,0); // softreset off
++
++ pci_write_config_word(hfctmp->pcidev, PCI_COMMAND, 0); // disable memio and bustmaster
++
++ if (hfctmp->fifomem != NULL) {
++ kfree(hfctmp->fifomem);
++ }
++ iounmap((void *) hfctmp->pci_io);
++ hfctmp->pci_io = NULL;
++ if (hfctmp->pcidev != NULL) {
++ pci_disable_device(hfctmp->pcidev);
++ }
++ spin_unlock_irqrestore(&hfctmp->lock,flags);
++ if (hfctmp->ztdev != NULL) {
++ dahdi_unregister(&hfctmp->ztdev->span);
++ kfree(hfctmp->ztdev);
++ printk(KERN_INFO "unregistered from DAHDI.\n");
++ }
++}
++
++void hfc_resetCard(struct hfc_card *hfctmp) {
++ unsigned long flags;
++
++ spin_lock_irqsave(&hfctmp->lock,flags);
++ pci_write_config_word(hfctmp->pcidev, PCI_COMMAND, PCI_COMMAND_MEMORY); // enable memio
++ hfctmp->regs.int_m2 = 0;
++ hfc_outb(hfctmp, hfc_INT_M2, hfctmp->regs.int_m2);
++
++// printk(KERN_INFO "zaphfc: resetting card.\n");
++ pci_set_master(hfctmp->pcidev);
++ hfc_outb(hfctmp, hfc_CIRM, hfc_CIRM_RESET); // softreset on
++ spin_unlock_irqrestore(&hfctmp->lock, flags);
++
++ set_current_state(TASK_UNINTERRUPTIBLE);
++ schedule_timeout((30 * HZ) / 1000); // wait 30 ms
++ hfc_outb(hfctmp, hfc_CIRM, 0); // softreset off
++
++ set_current_state(TASK_UNINTERRUPTIBLE);
++ schedule_timeout((20 * HZ) / 1000); // wait 20 ms
++ if (hfc_inb(hfctmp,hfc_STATUS) & hfc_STATUS_PCI_PROC) {
++ printk(KERN_WARNING "zaphfc: hfc busy.\n");
++ }
++
++// hfctmp->regs.fifo_en = hfc_FIFOEN_D | hfc_FIFOEN_B1 | hfc_FIFOEN_B2;
++// hfctmp->regs.fifo_en = hfc_FIFOEN_D; /* only D fifos enabled */
++ hfctmp->regs.fifo_en = 0; /* no fifos enabled */
++ hfc_outb(hfctmp, hfc_FIFO_EN, hfctmp->regs.fifo_en);
++
++ hfctmp->regs.trm = 2;
++ hfc_outb(hfctmp, hfc_TRM, hfctmp->regs.trm);
++
++ if (hfctmp->regs.nt_mode == 1) {
++ hfc_outb(hfctmp, hfc_CLKDEL, CLKDEL_NT); /* ST-Bit delay for NT-Mode */
++ } else {
++ hfc_outb(hfctmp, hfc_CLKDEL, CLKDEL_TE); /* ST-Bit delay for TE-Mode */
++ }
++ hfctmp->regs.sctrl_e = hfc_SCTRL_E_AUTO_AWAKE;
++ hfc_outb(hfctmp, hfc_SCTRL_E, hfctmp->regs.sctrl_e); /* S/T Auto awake */
++ hfctmp->regs.bswapped = 0; /* no exchange */
++
++ hfctmp->regs.ctmt = hfc_CTMT_TRANSB1 | hfc_CTMT_TRANSB2; // all bchans are transparent , no freaking hdlc
++ hfc_outb(hfctmp, hfc_CTMT, hfctmp->regs.ctmt);
++
++ hfctmp->regs.int_m1 = 0;
++ hfc_outb(hfctmp, hfc_INT_M1, hfctmp->regs.int_m1);
++
++#ifdef RTAITIMING
++ hfctmp->regs.int_m2 = 0;
++#else
++ hfctmp->regs.int_m2 = hfc_M2_PROC_TRANS;
++#endif
++ hfc_outb(hfctmp, hfc_INT_M2, hfctmp->regs.int_m2);
++
++ /* Clear already pending ints */
++ hfc_inb(hfctmp, hfc_INT_S1);
++
++ if (hfctmp->regs.nt_mode == 1) {
++ hfctmp->regs.sctrl = 3 | hfc_SCTRL_NONE_CAP | hfc_SCTRL_MODE_NT; /* set tx_lo mode, error in datasheet ! */
++ } else {
++ hfctmp->regs.sctrl = 3 | hfc_SCTRL_NONE_CAP | hfc_SCTRL_MODE_TE; /* set tx_lo mode, error in datasheet ! */
++ }
++
++ hfctmp->regs.mst_mode = hfc_MST_MODE_MASTER; /* HFC Master Mode */
++ hfc_outb(hfctmp, hfc_MST_MODE, hfctmp->regs.mst_mode);
++
++ hfc_outb(hfctmp, hfc_SCTRL, hfctmp->regs.sctrl);
++ hfctmp->regs.sctrl_r = 3;
++ hfc_outb(hfctmp, hfc_SCTRL_R, hfctmp->regs.sctrl_r);
++
++ hfctmp->regs.connect = 0;
++ hfc_outb(hfctmp, hfc_CONNECT, hfctmp->regs.connect);
++
++ hfc_outb(hfctmp, hfc_CIRM, 0x80 | 0x40); // bit order
++
++ /* Finally enable IRQ output */
++#ifndef RTAITIMING
++ hfctmp->regs.int_m2 |= hfc_M2_IRQ_ENABLE;
++ hfc_outb(hfctmp, hfc_INT_M2, hfctmp->regs.int_m2);
++#endif
++
++ /* clear pending ints */
++ hfc_inb(hfctmp, hfc_INT_S1);
++ hfc_inb(hfctmp, hfc_INT_S2);
++}
++
++void hfc_registerCard(struct hfc_card *hfccard) {
++ spin_lock(&registerlock);
++ if (hfccard != NULL) {
++ hfccard->cardno = hfc_dev_count++;
++ hfccard->next = hfc_dev_list;
++ hfc_dev_list = hfccard;
++ }
++ spin_unlock(&registerlock);
++}
++
++static void hfc_btrans(struct hfc_card *hfctmp, char whichB) {
++ // we are called with irqs disabled from the irq handler
++ int count, maxlen, total;
++ unsigned char *f1, *f2;
++ unsigned short *z1, *z2, newz1;
++ int freebytes;
++
++ if (whichB == 1) {
++ f1 = (char *)(hfctmp->fifos + hfc_FIFO_B1TX_F1);
++ f2 = (char *)(hfctmp->fifos + hfc_FIFO_B1TX_F2);
++ z1 = (unsigned short *)(hfctmp->fifos + hfc_FIFO_B1TX_Z1 + (*f1 * 4));
++ z2 = (unsigned short *)(hfctmp->fifos + hfc_FIFO_B1TX_Z2 + (*f1 * 4));
++ } else {
++ f1 = (char *)(hfctmp->fifos + hfc_FIFO_B2TX_F1);
++ f2 = (char *)(hfctmp->fifos + hfc_FIFO_B2TX_F2);
++ z1 = (unsigned short *)(hfctmp->fifos + hfc_FIFO_B2TX_Z1 + (*f1 * 4));
++ z2 = (unsigned short *)(hfctmp->fifos + hfc_FIFO_B2TX_Z2 + (*f1 * 4));
++ }
++
++ freebytes = *z2 - *z1;
++ if (freebytes <= 0) {
++ freebytes += hfc_B_FIFO_SIZE;
++ }
++ count = DAHDI_CHUNKSIZE;
++
++ total = count;
++ if (freebytes < count) {
++ hfctmp->clicks++;
++ /* only spit out this warning once per second to not make things worse! */
++ if (hfctmp->clicks > 100) {
++ printk(KERN_CRIT "zaphfc: bchan tx fifo full, dropping audio! (z1=%d, z2=%d)\n",*z1,*z2);
++ hfctmp->clicks = 0;
++ }
++ return;
++ }
++
++ maxlen = (hfc_B_FIFO_SIZE + hfc_B_SUB_VAL) - *z1;
++ if (maxlen > count) {
++ maxlen = count;
++ }
++ newz1 = *z1 + total;
++ if (newz1 >= (hfc_B_FIFO_SIZE + hfc_B_SUB_VAL)) { newz1 -= hfc_B_FIFO_SIZE; }
++
++ if (whichB == 1) {
++ memcpy((char *)(hfctmp->fifos + hfc_FIFO_B1TX_ZOFF + *z1),hfctmp->ztdev->chans[0].writechunk, maxlen);
++ } else {
++ memcpy((char *)(hfctmp->fifos + hfc_FIFO_B2TX_ZOFF + *z1),hfctmp->ztdev->chans[1].writechunk, maxlen);
++ }
++
++ count -= maxlen;
++ if (count > 0) {
++ // Buffer wrap
++ if (whichB == 1) {
++ memcpy((char *)(hfctmp->fifos + hfc_FIFO_B1TX_ZOFF + hfc_B_SUB_VAL),hfctmp->ztdev->chans[0].writechunk+maxlen, count);
++ } else {
++ memcpy((char *)(hfctmp->fifos + hfc_FIFO_B2TX_ZOFF + hfc_B_SUB_VAL),hfctmp->ztdev->chans[1].writechunk+maxlen, count);
++ }
++ }
++
++ *z1 = newz1; /* send it now */
++
++// if (count > 0) printk(KERN_CRIT "zaphfc: bchan tx fifo (f1=%d, f2=%d, z1=%d, z2=%d)\n",(*f1) & hfc_FMASK,(*f2) & hfc_FMASK, *z1, *z2);
++ return;
++}
++
++static void hfc_brec(struct hfc_card *hfctmp, char whichB) {
++ // we are called with irqs disabled from the irq handler
++ int count, maxlen, drop;
++ volatile unsigned char *f1, *f2;
++ volatile unsigned short *z1, *z2, newz2;
++ int bytes = 0;
++
++ if (whichB == 1) {
++ f1 = (char *)(hfctmp->fifos + hfc_FIFO_B1RX_F1);
++ f2 = (char *)(hfctmp->fifos + hfc_FIFO_B1RX_F2);
++ z1 = (unsigned short *)(hfctmp->fifos + hfc_FIFO_B1RX_Z1 + (*f1 * 4));
++ z2 = (unsigned short *)(hfctmp->fifos + hfc_FIFO_B1RX_Z2 + (*f1 * 4));
++ } else {
++ f1 = (char *)(hfctmp->fifos + hfc_FIFO_B2RX_F1);
++ f2 = (char *)(hfctmp->fifos + hfc_FIFO_B2RX_F2);
++ z1 = (unsigned short *)(hfctmp->fifos + hfc_FIFO_B2RX_Z1 + (*f1 * 4));
++ z2 = (unsigned short *)(hfctmp->fifos + hfc_FIFO_B2RX_Z2 + (*f1 * 4));
++ }
++
++ bytes = *z1 - *z2;
++ if (bytes < 0) {
++ bytes += hfc_B_FIFO_SIZE;
++ }
++ count = DAHDI_CHUNKSIZE;
++
++ if (bytes < DAHDI_CHUNKSIZE) {
++#ifndef RTAITIMING
++ printk(KERN_CRIT "zaphfc: bchan rx fifo not enough bytes to receive! (z1=%d, z2=%d, wanted %d got %d), probably a buffer overrun.\n",*z1,*z2,DAHDI_CHUNKSIZE,bytes);
++#endif
++ return;
++ }
++
++ /* allowing the buffering of hfc_BCHAN_BUFFER bytes of audio data works around irq jitter */
++ if (bytes > hfc_BCHAN_BUFFER + DAHDI_CHUNKSIZE) {
++ /* if the system is too slow to handle it, we will have to drop it all (except 1 DAHDI chunk) */
++ drop = bytes - DAHDI_CHUNKSIZE;
++ hfctmp->clicks++;
++ /* only spit out this warning once per second to not make things worse! */
++ if (hfctmp->clicks > 100) {
++ printk(KERN_CRIT "zaphfc: dropped audio (z1=%d, z2=%d, wanted %d got %d, dropped %d).\n",*z1,*z2,count,bytes,drop);
++ hfctmp->clicks = 0;
++ }
++ /* hm, we are processing the b chan data tooooo slowly... let's drop the lost audio */
++ newz2 = *z2 + drop;
++ if (newz2 >= (hfc_B_FIFO_SIZE + hfc_B_SUB_VAL)) {
++ newz2 -= hfc_B_FIFO_SIZE;
++ }
++ *z2 = newz2;
++ }
++
++
++ maxlen = (hfc_B_FIFO_SIZE + hfc_B_SUB_VAL) - *z2;
++ if (maxlen > count) {
++ maxlen = count;
++ }
++ if (whichB == 1) {
++ memcpy(hfctmp->ztdev->chans[0].readchunk,(char *)(hfctmp->fifos + hfc_FIFO_B1RX_ZOFF + *z2), maxlen);
++ } else {
++ memcpy(hfctmp->ztdev->chans[1].readchunk,(char *)(hfctmp->fifos + hfc_FIFO_B2RX_ZOFF + *z2), maxlen);
++ }
++ newz2 = *z2 + count;
++ if (newz2 >= (hfc_B_FIFO_SIZE + hfc_B_SUB_VAL)) {
++ newz2 -= hfc_B_FIFO_SIZE;
++ }
++ *z2 = newz2;
++
++ count -= maxlen;
++ if (count > 0) {
++ // Buffer wrap
++ if (whichB == 1) {
++ z2 = (unsigned short *)(hfctmp->fifos + hfc_FIFO_B1RX_Z2 + (*f1 * 4));
++ memcpy(hfctmp->ztdev->chans[0].readchunk + maxlen,(char *)(hfctmp->fifos + hfc_FIFO_B1RX_ZOFF + hfc_B_SUB_VAL), count);
++ } else {
++ z2 = (unsigned short *)(hfctmp->fifos + hfc_FIFO_B2RX_Z2 + (*f1 * 4));
++ memcpy(hfctmp->ztdev->chans[1].readchunk + maxlen,(char *)(hfctmp->fifos + hfc_FIFO_B2RX_ZOFF + hfc_B_SUB_VAL), count);
++ }
++ newz2 = *z2 + count;
++ if (newz2 >= (hfc_B_FIFO_SIZE + hfc_B_SUB_VAL)) {
++ newz2 -= hfc_B_FIFO_SIZE;
++ }
++ }
++
++
++ if (whichB == 1) {
++ dahdi_ec_chunk(&hfctmp->ztdev->chans[0], hfctmp->ztdev->chans[0].readchunk, hfctmp->ztdev->chans[0].writechunk);
++ } else {
++ dahdi_ec_chunk(&hfctmp->ztdev->chans[1], hfctmp->ztdev->chans[1].readchunk, hfctmp->ztdev->chans[1].writechunk);
++ }
++ return;
++}
++
++
++static void hfc_dtrans(struct hfc_card *hfctmp) {
++ // we are called with irqs disabled from the irq handler
++ int x;
++ int count, maxlen, total;
++ unsigned char *f1, *f2, newf1;
++ unsigned short *z1, *z2, newz1;
++ int frames, freebytes;
++
++ if (hfctmp->ztdev->chans[2].bytes2transmit == 0) {
++ return;
++ }
++
++ f1 = (char *)(hfctmp->fifos + hfc_FIFO_DTX_F1);
++ f2 = (char *)(hfctmp->fifos + hfc_FIFO_DTX_F2);
++ z1 = (unsigned short *)(hfctmp->fifos + hfc_FIFO_DTX_Z1 + (*f1 * 4));
++ z2 = (unsigned short *)(hfctmp->fifos + hfc_FIFO_DTX_Z2 + (*f1 * 4));
++
++ frames = (*f1 - *f2) & hfc_FMASK;
++ if (frames < 0) {
++ frames += hfc_MAX_DFRAMES + 1;
++ }
++
++ if (frames >= hfc_MAX_DFRAMES) {
++ printk(KERN_CRIT "zaphfc: dchan tx fifo total number of frames exceeded!\n");
++ return;
++ }
++
++ freebytes = *z2 - *z1;
++ if (freebytes <= 0) {
++ freebytes += hfc_D_FIFO_SIZE;
++ }
++ count = hfctmp->ztdev->chans[2].bytes2transmit;
++
++ total = count;
++ if (freebytes < count) {
++ printk(KERN_CRIT "zaphfc: dchan tx fifo not enough free bytes! (z1=%d, z2=%d)\n",*z1,*z2);
++ return;
++ }
++
++ newz1 = (*z1 + count) & hfc_ZMASK;
++ newf1 = ((*f1 + 1) & hfc_MAX_DFRAMES) | (hfc_MAX_DFRAMES + 1); // next frame
++
++ if (count > 0) {
++ if (debug) {
++ printk(KERN_CRIT "zaphfc: card %d TX [ ", hfctmp->cardno);
++ for (x=0; x<count; x++) {
++ printk("%#2x ",hfctmp->dtransbuf[x]);
++ }
++ if (hfctmp->ztdev->chans[2].eoftx == 1) {
++ printk("] %d bytes\n", count);
++ } else {
++ printk("..] %d bytes\n", count);
++ }
++ }
++ maxlen = hfc_D_FIFO_SIZE - *z1;
++ if (maxlen > count) {
++ maxlen = count;
++ }
++ memcpy((char *)(hfctmp->fifos + hfc_FIFO_DTX_ZOFF + *z1),hfctmp->ztdev->chans[2].writechunk, maxlen);
++ count -= maxlen;
++ if (count > 0) {
++ memcpy((char *)(hfctmp->fifos + hfc_FIFO_DTX_ZOFF),(char *)(hfctmp->ztdev->chans[2].writechunk + maxlen), count);
++ }
++ }
++
++ *z1 = newz1;
++
++ if (hfctmp->ztdev->chans[2].eoftx == 1) {
++ *f1 = newf1;
++ z1 = (unsigned short *)(hfctmp->fifos + hfc_FIFO_DTX_Z1 + (*f1 * 4));
++ *z1 = newz1;
++ hfctmp->ztdev->chans[2].eoftx = 0;
++ }
++// printk(KERN_CRIT "zaphfc: dchan tx fifo (f1=%d, f2=%d, z1=%d, z2=%d)\n",(*f1) & hfc_FMASK,(*f2) & hfc_FMASK, *z1, *z2);
++ return;
++}
++
++/* receive a complete hdlc frame, skip broken or short frames */
++static void hfc_drec(struct hfc_card *hfctmp) {
++ int count=0, maxlen=0, framelen=0;
++ unsigned char *f1, *f2, *crcstat;
++ unsigned short *z1, *z2, oldz2, newz2;
++
++ hfctmp->ztdev->chans[2].bytes2receive=0;
++ hfctmp->ztdev->chans[2].eofrx = 0;
++
++ /* put the received data into the DAHDI buffer
++ we'll call dahdi_receive() later when the timer fires. */
++ f1 = (char *)(hfctmp->fifos + hfc_FIFO_DRX_F1);
++ f2 = (char *)(hfctmp->fifos + hfc_FIFO_DRX_F2);
++
++ if (*f1 == *f2) return; /* nothing received, strange eh? */
++
++ z1 = (unsigned short *)(hfctmp->fifos + hfc_FIFO_DRX_Z1 + (*f2 * 4));
++ z2 = (unsigned short *)(hfctmp->fifos + hfc_FIFO_DRX_Z2 + (*f2 * 4));
++
++ /* calculate length of frame, including 2 bytes CRC and 1 byte STAT */
++ count = *z1 - *z2;
++
++ if (count < 0) {
++ count += hfc_D_FIFO_SIZE; /* ring buffer wrapped */
++ }
++ count++;
++ framelen = count;
++
++ crcstat = (char *)(hfctmp->fifos + hfc_FIFO_DRX_ZOFF + *z1);
++
++ if ((framelen < 4) || (*crcstat != 0x0)) {
++ /* the frame is too short for a valid HDLC frame or the CRC is borked */
++ printk(KERN_CRIT "zaphfc: empty HDLC frame or bad CRC received (framelen = %d, stat = %#x, card = %d).\n", framelen, *crcstat, hfctmp->cardno);
++ oldz2 = *z2;
++ *f2 = ((*f2 + 1) & hfc_MAX_DFRAMES) | (hfc_MAX_DFRAMES + 1); /* NEXT!!! */
++ // recalculate z2, because Z2 is a function of F2 Z2(F2) and we INCed F2!!!
++ z2 = (unsigned short *)(hfctmp->fifos + hfc_FIFO_DRX_Z2 + (*f2 * 4));
++ *z2 = (oldz2 + framelen) & hfc_ZMASK;
++ hfctmp->drecinframe = 0;
++ hfctmp->regs.int_drec--;
++ /* skip short or broken frames */
++ hfctmp->ztdev->chans[2].bytes2receive = 0;
++ return;
++ }
++
++ count -= 1; /* strip STAT */
++ hfctmp->ztdev->chans[2].eofrx = 1;
++
++ if (count + *z2 <= hfc_D_FIFO_SIZE) {
++ maxlen = count;
++ } else {
++ maxlen = hfc_D_FIFO_SIZE - *z2;
++ }
++
++ /* copy first part */
++ memcpy(hfctmp->drecbuf, (char *)(hfctmp->fifos + hfc_FIFO_DRX_ZOFF + *z2), maxlen);
++ hfctmp->ztdev->chans[2].bytes2receive += maxlen;
++
++ count -= maxlen;
++ if (count > 0) {
++ /* ring buffer wrapped, copy rest from start of d fifo */
++ memcpy(hfctmp->drecbuf + maxlen, (char *)(hfctmp->fifos + hfc_FIFO_DRX_ZOFF), count);
++ hfctmp->ztdev->chans[2].bytes2receive += count;
++ }
++
++ /* frame read */
++ oldz2 = *z2;
++ newz2 = (oldz2 + framelen) & hfc_ZMASK;
++ *f2 = ((*f2 + 1) & hfc_MAX_DFRAMES) | (hfc_MAX_DFRAMES + 1); /* NEXT!!! */
++ /* recalculate z2, because Z2 is a function of F2 Z2(F2) and we INCed F2!!! */
++ z2 = (unsigned short *)(hfctmp->fifos + hfc_FIFO_DRX_Z2 + (*f2 * 4));
++ *z2 = newz2;
++ hfctmp->drecinframe = 0;
++ hfctmp->regs.int_drec--;
++}
++
++#ifndef RTAITIMING
++DAHDI_IRQ_HANDLER(hfc_interrupt) {
++ struct hfc_card *hfctmp = dev_id;
++ unsigned long flags = 0;
++ unsigned char stat;
++#else
++static void hfc_service(struct hfc_card *hfctmp) {
++#endif
++ struct dahdi_hfc *zthfc;
++ unsigned char s1, s2, l1state;
++ int x;
++
++ if (!hfctmp) {
++#ifndef RTAITIMING
++ return IRQ_NONE;
++#else
++ /* rtai */
++ return;
++#endif
++ }
++
++ if (!hfctmp->pci_io) {
++ printk(KERN_WARNING "%s: IO-mem disabled, cannot handle interrupt\n",
++ __FUNCTION__);
++#ifndef RTAITIMING
++ return IRQ_NONE;
++#else
++ /* rtai */
++ return;
++#endif
++ }
++
++ /* we assume a few things in this irq handler:
++ - the hfc-pci will only generate "timer" irqs (proc/non-proc)
++ - we need to use every 8th IRQ (to generate 1khz timing)
++ OR
++ - if we use rtai for timing the hfc-pci will not generate ANY irq,
++ instead rtai will call this "fake" irq with a 1khz realtime timer. :)
++ - rtai will directly service the card, not like it used to by triggering
++ the linux irq
++ */
++
++#ifndef RTAITIMING
++ spin_lock_irqsave(&hfctmp->lock, flags);
++ stat = hfc_inb(hfctmp, hfc_STATUS);
++
++ if ((stat & hfc_STATUS_ANYINT) == 0) {
++ // maybe we are sharing the irq
++ spin_unlock_irqrestore(&hfctmp->lock,flags);
++ return IRQ_NONE;
++ }
++#endif
++
++ s1 = hfc_inb(hfctmp, hfc_INT_S1);
++ s2 = hfc_inb(hfctmp, hfc_INT_S2);
++ if (s1 != 0) {
++ if (s1 & hfc_INTS_TIMER) {
++ // timer (bit 7)
++ // printk(KERN_CRIT "timer %d %d %d.\n", stat, s1, s2);
++ }
++ if (s1 & hfc_INTS_L1STATE) {
++ // state machine (bit 6)
++ // printk(KERN_CRIT "zaphfc: layer 1 state machine interrupt\n");
++ zthfc = hfctmp->ztdev;
++ l1state = hfc_inb(hfctmp,hfc_STATES) & hfc_STATES_STATE_MASK;
++ if (hfctmp->regs.nt_mode == 1) {
++ if (debug) {
++ printk(KERN_CRIT "zaphfc: card %d layer 1 state = G%d\n", hfctmp->cardno, l1state);
++ }
++ switch (l1state) {
++ case 3:
++#ifdef RTAITIMING
++ sprintf(zthfc->span.desc, "HFC-S PCI A ISDN card %d [NT] layer 1 ACTIVATED (G%d) [realtime]", hfctmp->cardno, l1state);
++#else
++ sprintf(zthfc->span.desc, "HFC-S PCI A ISDN card %d [NT] layer 1 ACTIVATED (G%d)", hfctmp->cardno, l1state);
++#endif
++ break;
++ default:
++#ifdef RTAITIMING
++ sprintf(zthfc->span.desc, "HFC-S PCI A ISDN card %d [NT] layer 1 DEACTIVATED (G%d) [realtime]", hfctmp->cardno, l1state);
++#else
++ sprintf(zthfc->span.desc, "HFC-S PCI A ISDN card %d [NT] layer 1 DEACTIVATED (G%d)", hfctmp->cardno, l1state);
++#endif
++ }
++ if (l1state == 2) {
++ hfc_outb(hfctmp, hfc_STATES, hfc_STATES_ACTIVATE | hfc_STATES_DO_ACTION | hfc_STATES_NT_G2_G3);
++ } else if (l1state == 3) {
++ // fix to G3 state (see specs)
++ hfc_outb(hfctmp, hfc_STATES, hfc_STATES_LOAD_STATE | 3);
++ }
++ } else {
++ if (debug) {
++ printk(KERN_CRIT "zaphfc: card %d layer 1 state = F%d\n", hfctmp->cardno, l1state);
++ }
++ switch (l1state) {
++ case 7:
++#ifdef RTAITIMING
++ sprintf(zthfc->span.desc, "HFC-S PCI A ISDN card %d [TE] layer 1 ACTIVATED (F%d) [realtime]", hfctmp->cardno, l1state);
++#else
++ sprintf(zthfc->span.desc, "HFC-S PCI A ISDN card %d [TE] layer 1 ACTIVATED (F%d)", hfctmp->cardno, l1state);
++#endif
++ break;
++ default:
++#ifdef RTAITIMING
++ sprintf(zthfc->span.desc, "HFC-S PCI A ISDN card %d [TE] layer 1 DEACTIVATED (F%d) [realtime]", hfctmp->cardno, l1state);
++#else
++ sprintf(zthfc->span.desc, "HFC-S PCI A ISDN card %d [TE] layer 1 DEACTIVATED (F%d)", hfctmp->cardno, l1state);
++#endif
++ }
++ if (l1state == 3) {
++ hfc_outb(hfctmp, hfc_STATES, hfc_STATES_DO_ACTION | hfc_STATES_ACTIVATE);
++ }
++ }
++
++ }
++ if (s1 & hfc_INTS_DREC) {
++ // D chan RX (bit 5)
++ hfctmp->regs.int_drec++;
++ // mr. zapata there is something for you!
++ // printk(KERN_CRIT "d chan rx\n");
++ }
++ if (s1 & hfc_INTS_B2REC) {
++ // B2 chan RX (bit 4)
++ }
++ if (s1 & hfc_INTS_B1REC) {
++ // B1 chan RX (bit 3)
++ }
++ if (s1 & hfc_INTS_DTRANS) {
++ // D chan TX (bit 2)
++// printk(KERN_CRIT "zaphfc: dchan frame transmitted.\n");
++ }
++ if (s1 & hfc_INTS_B2TRANS) {
++ // B2 chan TX (bit 1)
++ }
++ if (s1 & hfc_INTS_B1TRANS) {
++ // B1 chan TX (bit 0)
++ }
++ }
++#ifdef RTAITIMING
++ /* fake an irq */
++ s2 |= hfc_M2_PROC_TRANS;
++#endif
++ if (s2 != 0) {
++ if (s2 & hfc_M2_PMESEL) {
++ // kaboom irq (bit 7)
++ printk(KERN_CRIT "zaphfc: sync lost, pci performance too low. you might have some cpu throtteling enabled.\n");
++ }
++ 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)
++ hfctmp->ticks++;
++#ifndef RTAITIMING
++ if (hfctmp->ticks > 7) {
++ // welcome to DAHDI timing :)
++#endif
++ hfctmp->ticks = 0;
++
++ if (hfctmp->ztdev->span.flags & DAHDI_FLAG_RUNNING) {
++ // clear dchan buffer
++ hfctmp->ztdev->chans[2].bytes2transmit = 0;
++ hfctmp->ztdev->chans[2].maxbytes2transmit = hfc_D_FIFO_SIZE;
++
++ dahdi_transmit(&(hfctmp->ztdev->span));
++
++ hfc_btrans(hfctmp,1);
++ hfc_btrans(hfctmp,2);
++ hfc_dtrans(hfctmp);
++ }
++
++ hfc_brec(hfctmp,1);
++ hfc_brec(hfctmp,2);
++ if (hfctmp->regs.int_drec > 0) {
++ // dchan data to read
++ hfc_drec(hfctmp);
++ if (hfctmp->ztdev->chans[2].bytes2receive > 0) {
++ if (debug) {
++ printk(KERN_CRIT "zaphfc: card %d RX [ ", hfctmp->cardno);
++ if (hfctmp->ztdev->chans[2].eofrx) {
++ /* dont output CRC == less user confusion */
++ for (x=0; x < hfctmp->ztdev->chans[2].bytes2receive - 2; x++) {
++ printk("%#2x ", hfctmp->drecbuf[x]);
++ }
++ printk("] %d bytes\n", hfctmp->ztdev->chans[2].bytes2receive - 2);
++ } else {
++ for (x=0; x < hfctmp->ztdev->chans[2].bytes2receive; x++) {
++ printk("%#2x ", hfctmp->drecbuf[x]);
++ }
++ printk("..] %d bytes\n", hfctmp->ztdev->chans[2].bytes2receive);
++ }
++ }
++ }
++ } else {
++ // hmm....ok, let DAHDI receive nothing
++ hfctmp->ztdev->chans[2].bytes2receive = 0;
++ }
++ if (hfctmp->ztdev->span.flags & DAHDI_FLAG_RUNNING) {
++ dahdi_receive(&(hfctmp->ztdev->span));
++ }
++
++#ifndef RTAITIMING
++ }
++#endif
++ }
++
++ }
++#ifndef RTAITIMING
++ spin_unlock_irqrestore(&hfctmp->lock,flags);
++ return IRQ_RETVAL(1);
++#endif
++}
++
++
++static int zthfc_open(struct dahdi_chan *chan) {
++ struct dahdi_hfc *zthfc = chan->pvt;
++ struct hfc_card *hfctmp = zthfc->card;
++
++ if (!hfctmp) {
++ return 0;
++ }
++ try_module_get(THIS_MODULE);
++ return 0;
++}
++
++static int zthfc_close(struct dahdi_chan *chan) {
++ struct dahdi_hfc *zthfc = chan->pvt;
++ struct hfc_card *hfctmp = zthfc->card;
++
++ if (!hfctmp) {
++ return 0;
++ }
++
++ module_put(THIS_MODULE);
++ return 0;
++}
++
++static int zthfc_rbsbits(struct dahdi_chan *chan, int bits) {
++ return 0;
++}
++
++static int zthfc_ioctl(struct dahdi_chan *chan, unsigned int cmd, unsigned long data) {
++ switch(cmd) {
++ default:
++ return -ENOTTY;
++ }
++ return 0;
++}
++
++static int zthfc_startup(struct dahdi_span *span) {
++ struct dahdi_hfc *zthfc = span->pvt;
++ struct hfc_card *hfctmp = zthfc->card;
++ int alreadyrunning;
++
++ if (hfctmp == NULL) {
++ printk(KERN_INFO "zaphfc: no card for span at startup!\n");
++ }
++ alreadyrunning = span->flags & DAHDI_FLAG_RUNNING;
++
++ if (!alreadyrunning) {
++ span->chans[2]->flags &= ~DAHDI_FLAG_HDLC;
++ span->chans[2]->flags |= DAHDI_FLAG_BRIDCHAN;
++
++ span->flags |= DAHDI_FLAG_RUNNING;
++
++ hfctmp->ticks = -2;
++ hfctmp->clicks = 0;
++ hfctmp->regs.fifo_en = hfc_FIFOEN_D | hfc_FIFOEN_B1 | hfc_FIFOEN_B2;
++ hfc_outb(hfctmp, hfc_FIFO_EN, hfctmp->regs.fifo_en);
++ } else {
++ return 0;
++ }
++
++ // drivers, start engines!
++ hfc_outb(hfctmp, hfc_STATES, hfc_STATES_DO_ACTION | hfc_STATES_ACTIVATE);
++ return 0;
++}
++
++static int zthfc_shutdown(struct dahdi_span *span) {
++ return 0;
++}
++
++static int zthfc_maint(struct dahdi_span *span, int cmd) {
++ return 0;
++}
++
++static int zthfc_chanconfig(struct dahdi_chan *chan, int sigtype) {
++// printk(KERN_CRIT "chan_config sigtype=%d\n", sigtype);
++ return 0;
++}
++
++static int zthfc_spanconfig(struct dahdi_span *span, struct dahdi_lineconfig *lc) {
++ span->lineconfig = lc->lineconfig;
++ return 0;
++}
++
++static int zthfc_initialize(struct dahdi_hfc *zthfc) {
++ struct hfc_card *hfctmp = zthfc->card;
++ int i;
++
++ memset(&zthfc->span, 0x0, sizeof(struct dahdi_span)); // you never can tell...
++
++ sprintf(zthfc->span.name, "ZTHFC%d", hfc_dev_count + 1);
++ if (hfctmp->regs.nt_mode == 1) {
++#ifdef RTAITIMING
++ sprintf(zthfc->span.desc, "HFC-S PCI A ISDN card %d [NT] [realtime]", hfc_dev_count + 1);
++#else
++ sprintf(zthfc->span.desc, "HFC-S PCI A ISDN card %d [NT]", hfc_dev_count + 1);
++#endif
++ } else {
++#ifdef RTAITIMING
++ sprintf(zthfc->span.desc, "HFC-S PCI A ISDN card %d [TE] [realtime]", hfc_dev_count + 1);
++#else
++ sprintf(zthfc->span.desc, "HFC-S PCI A ISDN card %d [TE]", hfc_dev_count + 1);
++#endif
++ }
++
++ zthfc->span.spanconfig = zthfc_spanconfig;
++ zthfc->span.chanconfig = zthfc_chanconfig;
++ zthfc->span.startup = zthfc_startup;
++ zthfc->span.shutdown = zthfc_shutdown;
++ zthfc->span.maint = zthfc_maint;
++ zthfc->span.rbsbits = zthfc_rbsbits;
++ zthfc->span.open = zthfc_open;
++ zthfc->span.close = zthfc_close;
++ zthfc->span.ioctl = zthfc_ioctl;
++
++ zthfc->span.channels = 3;
++ zthfc->span.chans = zthfc->_chans;
++ for (i = 0; i < zthfc->span.channels; i++)
++ zthfc->_chans[i] = &zthfc->chans[i];
++
++ zthfc->span.deflaw = DAHDI_LAW_ALAW;
++ zthfc->span.linecompat = DAHDI_CONFIG_AMI | DAHDI_CONFIG_CCS; // <--- this is really BS
++ zthfc->span.offset = 0;
++ init_waitqueue_head(&zthfc->span.maintq);
++ zthfc->span.pvt = zthfc;
++
++ for (i = 0; i < zthfc->span.channels; i++) {
++ memset(&(zthfc->chans[i]), 0x0, sizeof(struct dahdi_chan));
++ sprintf(zthfc->chans[i].name, "ZTHFC%d/%d/%d", hfc_dev_count + 1,0,i + 1);
++ zthfc->chans[i].pvt = zthfc;
++ zthfc->chans[i].sigcap = DAHDI_SIG_EM | DAHDI_SIG_CLEAR | DAHDI_SIG_FXSLS | DAHDI_SIG_FXSGS | DAHDI_SIG_FXSKS | DAHDI_SIG_FXOLS | DAHDI_SIG_FXOGS | DAHDI_SIG_FXOKS | DAHDI_SIG_CAS | DAHDI_SIG_SF;
++ zthfc->chans[i].chanpos = i + 1;
++ }
++
++ if (dahdi_register(&zthfc->span,0)) {
++ printk(KERN_CRIT "unable to register DAHDI device!\n");
++ return -1;
++ }
++// printk(KERN_CRIT "zaphfc: registered DAHDI device!\n");
++ return 0;
++}
++
++#ifdef RTAITIMING
++#define TICK_PERIOD 1000000
++#define TICK_PERIOD2 1000000000
++#define TASK_PRIORITY 1
++#define STACK_SIZE 10000
++
++static RT_TASK rt_task;
++static struct hfc_card *rtai_hfc_list[hfc_MAX_CARDS];
++static unsigned char rtai_hfc_counter = 0;
++
++static void rtai_register_hfc(struct hfc_card *hfctmp) {
++ rtai_hfc_list[rtai_hfc_counter++] = hfctmp;
++}
++
++static void rtai_loop(int t) {
++ int i=0;
++ for (;;) {
++ for (i=0; i < rtai_hfc_counter; i++) {
++ if (rtai_hfc_list[i] != NULL)
++ hfc_service(rtai_hfc_list[i]);
++ }
++ rt_task_wait_period();
++ }
++}
++#endif
++
++int hfc_findCards(int pcivendor, int pcidevice, char *vendor_name, char *card_name) {
++ struct pci_dev *tmp;
++ struct hfc_card *hfctmp = NULL;
++ struct dahdi_hfc *zthfc = NULL;
++
++ tmp = pci_get_device(pcivendor, pcidevice, multi_hfc);
++ while (tmp != NULL) {
++ multi_hfc = tmp; // skip this next time.
++
++ if (pci_enable_device(tmp)) {
++ multi_hfc = NULL;
++ return -1;
++ }
++ pci_set_master(tmp);
++
++ hfctmp = kmalloc(sizeof(struct hfc_card), GFP_KERNEL);
++ if (!hfctmp) {
++ printk(KERN_WARNING "zaphfc: unable to kmalloc!\n");
++ pci_disable_device(tmp);
++ multi_hfc = NULL;
++ return -ENOMEM;
++ }
++ memset(hfctmp, 0x0, sizeof(struct hfc_card));
++ spin_lock_init(&hfctmp->lock);
++
++ hfctmp->pcidev = tmp;
++ hfctmp->pcibus = tmp->bus->number;
++ hfctmp->pcidevfn = tmp->devfn;
++
++ if (!tmp->irq) {
++ printk(KERN_WARNING "zaphfc: no irq!\n");
++ } else {
++ hfctmp->irq = tmp->irq;
++ }
++
++ hfctmp->pci_io = (char *) tmp->resource[1].start;
++ if (!hfctmp->pci_io) {
++ printk(KERN_WARNING "zaphfc: no iomem!\n");
++ kfree(hfctmp);
++ pci_disable_device(tmp);
++ multi_hfc = NULL;
++ return -1;
++ }
++
++ hfctmp->fifomem = kmalloc(65536, GFP_KERNEL);
++ if (!hfctmp->fifomem) {
++ printk(KERN_WARNING "zaphfc: unable to kmalloc fifomem!\n");
++ kfree(hfctmp);
++ pci_disable_device(tmp);
++ multi_hfc = NULL;
++ return -ENOMEM;
++ } else {
++ memset(hfctmp->fifomem, 0x0, 65536);
++ hfctmp->fifos = (void *)(((ulong) hfctmp->fifomem) & ~0x7FFF) + 0x8000;
++ pci_write_config_dword(hfctmp->pcidev, 0x80, (u_int) virt_to_bus(hfctmp->fifos));
++ hfctmp->pci_io = ioremap((ulong) hfctmp->pci_io, 256);
++ }
++
++#ifdef RTAITIMING
++ /* we need no stinking irq */
++ hfctmp->irq = 0;
++#else
++ if (request_irq(hfctmp->irq, &hfc_interrupt, IRQF_SHARED, "zaphfc", hfctmp)) {
++ printk(KERN_WARNING "zaphfc: unable to register irq\n");
++ kfree(hfctmp->fifomem);
++ kfree(hfctmp);
++ iounmap((void *) hfctmp->pci_io);
++ pci_disable_device(tmp);
++ multi_hfc = NULL;
++ return -EIO;
++ }
++#endif
++
++#ifdef RTAITIMING
++ rtai_register_hfc(hfctmp);
++#endif
++ printk(KERN_INFO
++ "zaphfc: %s %s configured at mem %lx fifo %lx(%#x) IRQ %d HZ %d\n",
++ vendor_name, card_name,
++ (unsigned long) hfctmp->pci_io,
++ (unsigned long) hfctmp->fifos,
++ (u_int) virt_to_bus(hfctmp->fifos),
++ hfctmp->irq, HZ);
++ pci_write_config_word(hfctmp->pcidev, PCI_COMMAND, PCI_COMMAND_MEMORY); // enable memio
++ hfctmp->regs.int_m1 = 0; // no ints
++ hfctmp->regs.int_m2 = 0; // not at all
++ hfc_outb(hfctmp,hfc_INT_M1,hfctmp->regs.int_m1);
++ hfc_outb(hfctmp,hfc_INT_M2,hfctmp->regs.int_m2);
++
++ if ((modes & (1 << hfc_dev_count)) != 0) {
++ printk(KERN_INFO "zaphfc: Card %d configured for NT mode\n",hfc_dev_count);
++ hfctmp->regs.nt_mode = 1;
++ } else {
++ printk(KERN_INFO "zaphfc: Card %d configured for TE mode\n",hfc_dev_count);
++ hfctmp->regs.nt_mode = 0;
++ }
++
++ zthfc = kmalloc(sizeof(struct dahdi_hfc),GFP_KERNEL);
++ if (!zthfc) {
++ printk(KERN_CRIT "zaphfc: unable to kmalloc!\n");
++ hfc_shutdownCard(hfctmp);
++ kfree(hfctmp);
++ multi_hfc = NULL;
++ return -ENOMEM;
++ }
++ memset(zthfc, 0x0, sizeof(struct dahdi_hfc));
++
++ zthfc->card = hfctmp;
++ zthfc_initialize(zthfc);
++ hfctmp->ztdev = zthfc;
++
++ memset(hfctmp->drecbuf, 0x0, sizeof(hfctmp->drecbuf));
++ hfctmp->ztdev->chans[2].readchunk = hfctmp->drecbuf;
++
++ memset(hfctmp->dtransbuf, 0x0, sizeof(hfctmp->dtransbuf));
++ hfctmp->ztdev->chans[2].writechunk = hfctmp->dtransbuf;
++
++ memset(hfctmp->brecbuf[0], 0x0, sizeof(hfctmp->brecbuf[0]));
++ hfctmp->ztdev->chans[0].readchunk = hfctmp->brecbuf[0];
++ memset(hfctmp->btransbuf[0], 0x0, sizeof(hfctmp->btransbuf[0]));
++ hfctmp->ztdev->chans[0].writechunk = hfctmp->btransbuf[0];
++
++ memset(hfctmp->brecbuf[1], 0x0, sizeof(hfctmp->brecbuf[1]));
++ hfctmp->ztdev->chans[1].readchunk = hfctmp->brecbuf[1];
++ memset(hfctmp->btransbuf[1], 0x0, sizeof(hfctmp->btransbuf[1]));
++ hfctmp->ztdev->chans[1].writechunk = hfctmp->btransbuf[1];
++
++
++ hfc_registerCard(hfctmp);
++ hfc_resetCard(hfctmp);
++ tmp = pci_get_device(pcivendor, pcidevice, multi_hfc);
++ }
++ return 0;
++}
++
++
++
++int init_module(void) {
++ int i = 0;
++#ifdef RTAITIMING
++ RTIME tick_period;
++ for (i=0; i < hfc_MAX_CARDS; i++) {
++ rtai_hfc_list[i] = NULL;
++ }
++ rt_set_periodic_mode();
++#endif
++ i = 0;
++ while (id_list[i].vendor_id) {
++ multi_hfc = NULL;
++ hfc_findCards(id_list[i].vendor_id, id_list[i].device_id, id_list[i].vendor_name, id_list[i].card_name);
++ i++;
++ }
++#ifdef RTAITIMING
++ for (i=0; i < hfc_MAX_CARDS; i++) {
++ if (rtai_hfc_list[i]) {
++ printk(KERN_INFO
++ "zaphfc: configured %d at mem %#x fifo %#x(%#x) for realtime servicing\n",
++ rtai_hfc_list[i]->cardno,
++ (u_int) rtai_hfc_list[i]->pci_io,
++ (u_int) rtai_hfc_list[i]->fifos,
++ (u_int) virt_to_bus(rtai_hfc_list[i]->fifos));
++
++ }
++ }
++ rt_task_init(&rt_task, rtai_loop, 1, STACK_SIZE, TASK_PRIORITY, 0, 0);
++ tick_period = start_rt_timer(nano2count(TICK_PERIOD));
++ rt_task_make_periodic(&rt_task, rt_get_time() + tick_period, tick_period);
++#endif
++ printk(KERN_INFO "zaphfc: %d hfc-pci card(s) in this box.\n", hfc_dev_count);
++ return 0;
++}
++
++void cleanup_module(void) {
++ struct hfc_card *tmpcard;
++#ifdef RTAITIMING
++ stop_rt_timer();
++ rt_task_delete(&rt_task);
++#endif
++ printk(KERN_INFO "zaphfc: stop\n");
++// spin_lock(&registerlock);
++ while (hfc_dev_list != NULL) {
++ if (hfc_dev_list == NULL) break;
++ hfc_shutdownCard(hfc_dev_list);
++ tmpcard = hfc_dev_list;
++ hfc_dev_list = hfc_dev_list->next;
++ if (tmpcard != NULL) {
++ kfree(tmpcard);
++ tmpcard = NULL;
++ printk(KERN_INFO "zaphfc: freed one card.\n");
++ }
++ }
++// spin_unlock(&registerlock);
++}
++#endif
++
++
++module_param(modes, int, 0600);
++module_param(debug, int, 0600);
++
++MODULE_DESCRIPTION("HFC-S PCI A Zaptel Driver");
++MODULE_AUTHOR("Klaus-Peter Junghanns <kpj@junghanns.net>");
++#ifdef MODULE_LICENSE
++MODULE_LICENSE("GPL");
++#endif
+Index: dahdi-linux-2.1.0/drivers/dahdi/zaphfc.h
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ dahdi-linux-2.1.0/drivers/dahdi/zaphfc.h 2008-12-10 12:46:14.000000000 +0200
+@@ -0,0 +1,290 @@
++/*
++ * zaphfc.h - Zaptel driver for HFC-S PCI A based ISDN BRI cards
++ *
++ * kernel module based on HFC PCI ISDN4Linux and Zaptel drivers
++ *
++ * Copyright (C) 2002, 2003, 2004, 2005 Junghanns.NET GmbH
++ *
++ * Klaus-Peter Junghanns <kpj@junghanns.net>
++ *
++ * This program is free software and may be modified and
++ * distributed under the terms of the GNU Public License.
++ *
++ */
++
++/* HFC register addresses - accessed using memory mapped I/O */
++/* For a list, see datasheet section 3.2.1 at page 21 */
++
++#define hfc_outb(a,b,c) (writeb((c),(a)->pci_io+(b)))
++#define hfc_inb(a,b) (readb((a)->pci_io+(b)))
++
++/* 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_CLTIMER 0x80
++#define hfc_CTMT_TIM3_125 0x04
++#define hfc_CTMT_TIM25 0x10
++#define hfc_CTMT_TIM50 0x14
++#define hfc_CTMT_TIM400 0x18
++#define hfc_CTMT_TIM800 0x1C
++#define hfc_CTMT_AUTO_TIMER 0x20
++#define hfc_CTMT_TRANSB2 0x02
++#define hfc_CTMT_TRANSB1 0x01
++
++/* 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 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_shift 0
++#define hfc_CONNECT_B2_shift 3
++
++#define hfc_CONNECT_HFC_from_ST 0x0
++#define hfc_CONNECT_HFC_from_GCI 0x1
++#define hfc_CONNECT_ST_from_HFC 0x0
++#define hfc_CONNECT_ST_from_GCI 0x2
++#define hfc_CONNECT_GCI_from_HFC 0x0
++#define hfc_CONNECT_GCI_from_ST 0x4
++
++/* 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_FMASK 0x000f
++#define hfc_ZMASK 0x01ff
++#define hfc_ZMASKB 0x1fff
++
++#define hfc_D_FIFO_SIZE 0x0200
++#define hfc_B_SUB_VAL 0x0200
++#define hfc_B_FIFO_SIZE 0x1E00
++#define hfc_MAX_DFRAMES 0x000f
++
++#define hfc_FIFO_DTX_Z1 0x2080
++#define hfc_FIFO_DTX_Z2 0x2082
++#define hfc_FIFO_DTX_F1 0x20a0
++#define hfc_FIFO_DTX_F2 0x20a1
++#define hfc_FIFO_DTX 0x0000
++#define hfc_FIFO_DTX_ZOFF 0x000
++
++#define hfc_FIFO_DRX_Z1 0x6080
++#define hfc_FIFO_DRX_Z2 0x6082
++#define hfc_FIFO_DRX_F1 0x60a0
++#define hfc_FIFO_DRX_F2 0x60a1
++#define hfc_FIFO_DRX 0x4000
++#define hfc_FIFO_DRX_ZOFF 0x4000
++
++#define hfc_FIFO_B1TX_Z1 0x2000
++#define hfc_FIFO_B1TX_Z2 0x2002
++#define hfc_FIFO_B1RX_Z1 0x6000
++#define hfc_FIFO_B1RX_Z2 0x6002
++
++#define hfc_FIFO_B1TX_F1 0x2080
++#define hfc_FIFO_B1TX_F2 0x2081
++#define hfc_FIFO_B1RX_F1 0x6080
++#define hfc_FIFO_B1RX_F2 0x6081
++
++#define hfc_FIFO_B1RX_ZOFF 0x4000
++#define hfc_FIFO_B1TX_ZOFF 0x0000
++
++#define hfc_FIFO_B2TX_Z1 0x2100
++#define hfc_FIFO_B2TX_Z2 0x2102
++#define hfc_FIFO_B2RX_Z1 0x6100
++#define hfc_FIFO_B2RX_Z2 0x6102
++
++#define hfc_FIFO_B2TX_F1 0x2180
++#define hfc_FIFO_B2TX_F2 0x2181
++#define hfc_FIFO_B2RX_F1 0x6180
++#define hfc_FIFO_B2RX_F2 0x6181
++
++#define hfc_FIFO_B2RX_ZOFF 0x6000
++#define hfc_FIFO_B2TX_ZOFF 0x2000
++
++#define hfc_BTRANS_THRESHOLD 128
++#define hfc_BTRANS_THRESMASK 0x00
++
++/* Structures */
++
++typedef struct hfc_regs {
++ unsigned char fifo_en;
++ unsigned char ctmt;
++ unsigned char int_m1;
++ unsigned char int_m2;
++ unsigned char sctrl;
++ unsigned char sctrl_e;
++ unsigned char sctrl_r;
++ unsigned char connect;
++ unsigned char trm;
++ unsigned char mst_mode;
++ unsigned char bswapped;
++ unsigned char nt_mode;
++ unsigned char int_drec;
++} hfc_regs;
++
++typedef struct hfc_card {
++ spinlock_t lock;
++ unsigned int irq;
++ unsigned int iomem;
++ int ticks;
++ int clicks;
++ unsigned char *pci_io;
++ void *fifomem; // start of the shared mem
++ volatile void *fifos; // 32k aligned mem for the fifos
++ struct hfc_regs regs;
++ unsigned int pcibus;
++ unsigned int pcidevfn;
++ struct pci_dev *pcidev;
++ struct dahdi_hfc *ztdev;
++ int drecinframe;
++ unsigned char drecbuf[hfc_D_FIFO_SIZE];
++ unsigned char dtransbuf[hfc_D_FIFO_SIZE];
++ unsigned char brecbuf[2][DAHDI_CHUNKSIZE];
++ unsigned char btransbuf[2][DAHDI_CHUNKSIZE];
++ 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;
++} dahdi_hfc;
++
++/* tune this */
++#define hfc_BCHAN_BUFFER 8
++#define hfc_MAX_CARDS 8
diff --git a/main/dahdi-linux-vanilla/linux-3.13.patch b/main/dahdi-linux-vanilla/linux-3.13.patch
new file mode 100644
index 0000000000..220568995f
--- /dev/null
+++ b/main/dahdi-linux-vanilla/linux-3.13.patch
@@ -0,0 +1,12 @@
+diff --git a/drivers/dahdi/zaphfc.c b/drivers/dahdi/zaphfc.c
+index 0402b90..eb56f88 100644
+--- a/drivers/dahdi/zaphfc.c
++++ b/drivers/dahdi/zaphfc.c
+@@ -26,6 +26,7 @@
+ #include <linux/init.h>
+ #include <linux/interrupt.h>
+ #include <linux/delay.h>
++#include <linux/sched.h>
+ #include <dahdi/kernel.h>
+ #include "zaphfc.h"
+
diff --git a/main/dahdi-linux-vanilla/linux-4.11.patch b/main/dahdi-linux-vanilla/linux-4.11.patch
new file mode 100644
index 0000000000..2a8cb60ced
--- /dev/null
+++ b/main/dahdi-linux-vanilla/linux-4.11.patch
@@ -0,0 +1,141 @@
+diff -ur dahdi-linux-2.11.1/drivers/dahdi/dahdi-base.c dahdi-linux-2.11.1-4.11/drivers/dahdi/dahdi-base.c
+--- dahdi-linux-2.11.1/drivers/dahdi/dahdi-base.c 2016-03-01 23:03:59.000000000 +0100
++++ dahdi-linux-2.11.1-4.11/drivers/dahdi/dahdi-base.c 2017-05-09 20:34:45.170079849 +0200
+@@ -47,6 +47,9 @@
+ #include <linux/kmod.h>
+ #include <linux/moduleparam.h>
+ #include <linux/sched.h>
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,11,0)
++#include <linux/sched/signal.h>
++#endif
+ #include <linux/list.h>
+ #include <linux/delay.h>
+ #include <linux/mutex.h>
+diff -ur dahdi-linux-2.11.1/drivers/dahdi/dahdi_dynamic.c dahdi-linux-2.11.1-4.11/drivers/dahdi/dahdi_dynamic.c
+--- dahdi-linux-2.11.1/drivers/dahdi/dahdi_dynamic.c 2016-03-01 23:03:59.000000000 +0100
++++ dahdi-linux-2.11.1-4.11/drivers/dahdi/dahdi_dynamic.c 2017-05-09 20:38:03.809649973 +0200
+@@ -467,7 +467,11 @@
+
+ /* We shouldn't have more than the two references at this point. If
+ * we do, there are probably channels that are still opened. */
++#if LINUX_VERSION_CODE < KERNEL_VERSION(4,11,0)
+ if (atomic_read(&d->kref.refcount) > 2) {
++#else
++ if (kref_read(&d->kref) > 2) {
++#endif
+ dynamic_put(d);
+ return -EBUSY;
+ }
+diff -ur dahdi-linux-2.11.1/drivers/dahdi/wcaxx-base.c dahdi-linux-2.11.1-4.11/drivers/dahdi/wcaxx-base.c
+--- dahdi-linux-2.11.1/drivers/dahdi/wcaxx-base.c 2016-03-01 23:03:59.000000000 +0100
++++ dahdi-linux-2.11.1-4.11/drivers/dahdi/wcaxx-base.c 2017-05-09 20:39:05.690553708 +0200
+@@ -28,6 +28,9 @@
+ #include <linux/init.h>
+ #include <linux/pci.h>
+ #include <linux/sched.h>
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,11,0)
++#include <linux/sched/signal.h>
++#endif
+ #include <linux/workqueue.h>
+ #include <linux/delay.h>
+ #include <linux/moduleparam.h>
+diff -ur dahdi-linux-2.11.1/drivers/dahdi/wctc4xxp/base.c dahdi-linux-2.11.1-4.11/drivers/dahdi/wctc4xxp/base.c
+--- dahdi-linux-2.11.1/drivers/dahdi/wctc4xxp/base.c 2016-03-01 23:03:59.000000000 +0100
++++ dahdi-linux-2.11.1-4.11/drivers/dahdi/wctc4xxp/base.c 2017-05-09 20:40:14.041864392 +0200
+@@ -26,6 +26,10 @@
+ #include <linux/slab.h>
+ #include <linux/kmod.h>
+ #include <linux/sched.h>
++#include <linux/version.h>
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,11,0)
++#include <linux/sched/signal.h>
++#endif
+ #include <linux/pci.h>
+ #include <linux/interrupt.h>
+ #include <linux/delay.h>
+diff -ur dahdi-linux-2.11.1/drivers/dahdi/wctdm24xxp/base.c dahdi-linux-2.11.1-4.11/drivers/dahdi/wctdm24xxp/base.c
+--- dahdi-linux-2.11.1/drivers/dahdi/wctdm24xxp/base.c 2016-03-01 23:03:59.000000000 +0100
++++ dahdi-linux-2.11.1-4.11/drivers/dahdi/wctdm24xxp/base.c 2017-05-09 20:39:47.343067209 +0200
+@@ -44,6 +44,9 @@
+ #include <linux/init.h>
+ #include <linux/pci.h>
+ #include <linux/sched.h>
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,11,0)
++#include <linux/sched/signal.h>
++#endif
+ #include <linux/interrupt.h>
+ #include <linux/workqueue.h>
+ #include <linux/delay.h>
+diff -ur dahdi-linux-2.11.1/drivers/dahdi/wcte12xp/base.c dahdi-linux-2.11.1-4.11/drivers/dahdi/wcte12xp/base.c
+--- dahdi-linux-2.11.1/drivers/dahdi/wcte12xp/base.c 2016-03-01 23:03:59.000000000 +0100
++++ dahdi-linux-2.11.1-4.11/drivers/dahdi/wcte12xp/base.c 2017-05-09 20:40:31.216160114 +0200
+@@ -40,6 +40,10 @@
+ #include <linux/workqueue.h>
+ #include <linux/delay.h>
+ #include <linux/sched.h>
++#include <linux/version.h>
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,11,0)
++#include <linux/sched/signal.h>
++#endif
+ #include <linux/slab.h>
+
+ #include <stdbool.h>
+diff -ur dahdi-linux-2.11.1/drivers/dahdi/wcte43x-base.c dahdi-linux-2.11.1-4.11/drivers/dahdi/wcte43x-base.c
+--- dahdi-linux-2.11.1/drivers/dahdi/wcte43x-base.c 2016-03-01 23:03:59.000000000 +0100
++++ dahdi-linux-2.11.1-4.11/drivers/dahdi/wcte43x-base.c 2017-05-09 20:38:38.996830549 +0200
+@@ -33,6 +33,10 @@
+ #include <linux/workqueue.h>
+ #include <linux/delay.h>
+ #include <linux/sched.h>
++#include <linux/version.h>
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,11,0)
++#include <linux/sched/signal.h>
++#endif
+ #include <linux/crc32.h>
+ #include <linux/slab.h>
+
+diff -ur dahdi-linux-2.11.1/drivers/dahdi/xpp/xbus-core.c dahdi-linux-2.11.1-4.11/drivers/dahdi/xpp/xbus-core.c
+--- dahdi-linux-2.11.1/drivers/dahdi/xpp/xbus-core.c 2016-03-01 23:03:59.000000000 +0100
++++ dahdi-linux-2.11.1-4.11/drivers/dahdi/xpp/xbus-core.c 2017-05-09 20:41:27.973007253 +0200
+@@ -244,7 +244,11 @@
+ {
+ struct kref *kref = &xbus->kref;
+
++#if LINUX_VERSION_CODE < KERNEL_VERSION(4,11,0)
+ return atomic_read(&kref->refcount);
++#else
++ return kref_read(kref);
++#endif
+ }
+
+ /*------------------------- Frame Handling ------------------------*/
+diff -ur dahdi-linux-2.11.1/drivers/dahdi/xpp/xbus-sysfs.c dahdi-linux-2.11.1-4.11/drivers/dahdi/xpp/xbus-sysfs.c
+--- dahdi-linux-2.11.1/drivers/dahdi/xpp/xbus-sysfs.c 2016-03-01 23:03:59.000000000 +0100
++++ dahdi-linux-2.11.1-4.11/drivers/dahdi/xpp/xbus-sysfs.c 2017-05-09 20:42:09.972886067 +0200
+@@ -974,7 +974,11 @@
+ return;
+ }
+ XBUS_DBG(DEVICES, xbus, "going to unregister: refcount=%d\n",
++#if LINUX_VERSION_CODE < KERNEL_VERSION(4,11,0)
+ atomic_read(&astribank->kobj.kref.refcount));
++#else
++ kref_read(&astribank->kobj.kref));
++#endif
+ BUG_ON(dev_get_drvdata(astribank) != xbus);
+ device_unregister(astribank);
+ dev_set_drvdata(astribank, NULL);
+diff -ur dahdi-linux-2.11.1/drivers/dahdi/xpp/xpp_dahdi.c dahdi-linux-2.11.1-4.11/drivers/dahdi/xpp/xpp_dahdi.c
+--- dahdi-linux-2.11.1/drivers/dahdi/xpp/xpp_dahdi.c 2016-03-01 23:03:59.000000000 +0100
++++ dahdi-linux-2.11.1-4.11/drivers/dahdi/xpp/xpp_dahdi.c 2017-05-09 20:42:55.336485638 +0200
+@@ -124,7 +124,11 @@
+ {
+ struct kref *kref = &xpd->kref;
+
++#if LINUX_VERSION_CODE < KERNEL_VERSION(4,11,0)
+ return atomic_read(&kref->refcount);
++#else
++ return kref_read(kref);
++#endif
+ }
+
+ xpd_t *get_xpd(const char *msg, xpd_t *xpd)
diff --git a/main/dahdi-linux-vanilla/linux-4.13.patch b/main/dahdi-linux-vanilla/linux-4.13.patch
new file mode 100644
index 0000000000..824e880a3e
--- /dev/null
+++ b/main/dahdi-linux-vanilla/linux-4.13.patch
@@ -0,0 +1,299 @@
+Index: dahdi-linux-2.11.1~dfsg/drivers/dahdi/dahdi-sysfs.c
+===================================================================
+--- dahdi-linux-2.11.1~dfsg.orig/drivers/dahdi/dahdi-sysfs.c
++++ dahdi-linux-2.11.1~dfsg/drivers/dahdi/dahdi-sysfs.c
+@@ -214,6 +214,7 @@ static BUS_ATTR_READER(linecompat_show,
+ return len;
+ }
+
++#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0)
+ static struct device_attribute span_dev_attrs[] = {
+ __ATTR_RO(name),
+ __ATTR_RO(desc),
+@@ -230,6 +231,39 @@ static struct device_attribute span_dev_
+ __ATTR_RO(linecompat),
+ __ATTR_NULL,
+ };
++#else
++static DEVICE_ATTR_RO(name);
++static DEVICE_ATTR_RO(desc);
++static DEVICE_ATTR_RO(spantype);
++static DEVICE_ATTR_RO(local_spanno);
++static DEVICE_ATTR_RO(alarms);
++static DEVICE_ATTR_RO(lbo);
++static DEVICE_ATTR_RO(syncsrc);
++static DEVICE_ATTR_RO(is_digital);
++static DEVICE_ATTR_RO(is_sync_master);
++static DEVICE_ATTR_RO(basechan);
++static DEVICE_ATTR_RO(channels);
++static DEVICE_ATTR_RO(lineconfig);
++static DEVICE_ATTR_RO(linecompat);
++
++static struct attribute *span_dev_attrs[] = {
++ &dev_attr_name.attr,
++ &dev_attr_desc.attr,
++ &dev_attr_spantype.attr,
++ &dev_attr_local_spanno.attr,
++ &dev_attr_alarms.attr,
++ &dev_attr_lbo.attr,
++ &dev_attr_syncsrc.attr,
++ &dev_attr_is_digital.attr,
++ &dev_attr_is_sync_master.attr,
++ &dev_attr_basechan.attr,
++ &dev_attr_channels.attr,
++ &dev_attr_lineconfig.attr,
++ &dev_attr_linecompat.attr,
++ NULL,
++};
++ATTRIBUTE_GROUPS(span_dev);
++#endif
+
+ static ssize_t master_span_show(struct device_driver *driver, char *buf)
+ {
+@@ -270,10 +304,11 @@ static struct bus_type spans_bus_type =
+ .name = "dahdi_spans",
+ .match = span_match,
+ .uevent = span_uevent,
+- .dev_attrs = span_dev_attrs,
+ #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0)
++ .dev_attrs = span_dev_attrs,
+ .drv_attrs = dahdi_attrs,
+ #else
++ .dev_groups = span_dev_groups,
+ .drv_groups = dahdi_groups,
+ #endif
+ };
+@@ -690,6 +725,7 @@ dahdi_registration_time_show(struct devi
+ return count;
+ }
+
++#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0)
+ static struct device_attribute dahdi_device_attrs[] = {
+ __ATTR(manufacturer, S_IRUGO, dahdi_device_manufacturer_show, NULL),
+ __ATTR(type, S_IRUGO, dahdi_device_type_show, NULL),
+@@ -704,11 +740,48 @@ static struct device_attribute dahdi_dev
+ __ATTR(registration_time, S_IRUGO, dahdi_registration_time_show, NULL),
+ __ATTR_NULL,
+ };
++#else
++static DEVICE_ATTR(manufacturer, S_IRUGO, dahdi_device_manufacturer_show, NULL);
++static DEVICE_ATTR(type, S_IRUGO, dahdi_device_type_show, NULL);
++static DEVICE_ATTR(span_count, S_IRUGO, dahdi_device_span_count_show, NULL);
++static DEVICE_ATTR(hardware_id, S_IRUGO, dahdi_device_hardware_id_show, NULL);
++static DEVICE_ATTR(location, S_IRUGO, dahdi_device_location_show, NULL);
++static DEVICE_ATTR(auto_assign, S_IWUSR, NULL, dahdi_device_auto_assign);
++static DEVICE_ATTR(assign_span, S_IWUSR, NULL, dahdi_device_assign_span);
++static DEVICE_ATTR(unassign_span, S_IWUSR, NULL, dahdi_device_unassign_span);
++/*
++ * Using DEVICE_ATTR for spantype attribute here will conflict with the
++ * span device attribute definition above. Define it somewhat more
++ * manually to give it a unique name.
++ */
++static struct device_attribute dahdi_dev_attr_spantype =
++ __ATTR(spantype, S_IWUSR | S_IRUGO, dahdi_spantype_show, dahdi_spantype_store);
++static DEVICE_ATTR(registration_time, S_IRUGO, dahdi_registration_time_show, NULL);
++
++static struct attribute *dahdi_device_attrs[] = {
++ &dev_attr_manufacturer.attr,
++ &dev_attr_type.attr,
++ &dev_attr_span_count.attr,
++ &dev_attr_hardware_id.attr,
++ &dev_attr_location.attr,
++ &dev_attr_auto_assign.attr,
++ &dev_attr_assign_span.attr,
++ &dev_attr_unassign_span.attr,
++ &dahdi_dev_attr_spantype.attr,
++ &dev_attr_registration_time.attr,
++ NULL,
++};
++ATTRIBUTE_GROUPS(dahdi_device);
++#endif
+
+ static struct bus_type dahdi_device_bus = {
+ .name = "dahdi_devices",
+ .uevent = device_uevent,
++#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0)
+ .dev_attrs = dahdi_device_attrs,
++#else
++ .dev_groups = dahdi_device_groups,
++#endif
+ };
+
+ static void dahdi_sysfs_cleanup(void)
+Index: dahdi-linux-2.11.1~dfsg/drivers/dahdi/dahdi-sysfs-chan.c
+===================================================================
+--- dahdi-linux-2.11.1~dfsg.orig/drivers/dahdi/dahdi-sysfs-chan.c
++++ dahdi-linux-2.11.1~dfsg/drivers/dahdi/dahdi-sysfs-chan.c
+@@ -158,6 +158,7 @@ static BUS_ATTR_READER(ec_state_show, de
+ return len;
+ }
+
++#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0)
+ static struct device_attribute chan_dev_attrs[] = {
+ __ATTR_RO(name),
+ __ATTR_RO(channo),
+@@ -174,6 +175,39 @@ static struct device_attribute chan_dev_
+ __ATTR_RO(in_use),
+ __ATTR_NULL,
+ };
++#else
++static DEVICE_ATTR_RO(name);
++static DEVICE_ATTR_RO(channo);
++static DEVICE_ATTR_RO(chanpos);
++static DEVICE_ATTR_RO(sig);
++static DEVICE_ATTR_RO(sigcap);
++static DEVICE_ATTR_RO(alarms);
++static DEVICE_ATTR_RO(ec_factory);
++static DEVICE_ATTR_RO(ec_state);
++static DEVICE_ATTR_RO(blocksize);
++#ifdef OPTIMIZE_CHANMUTE
++static DEVICE_ATTR_RO(chanmute);
++#endif
++static DEVICE_ATTR_RO(in_use);
++
++static struct attribute *chan_dev_attrs[] = {
++ &dev_attr_name.attr,
++ &dev_attr_channo.attr,
++ &dev_attr_chanpos.attr,
++ &dev_attr_sig.attr,
++ &dev_attr_sigcap.attr,
++ &dev_attr_alarms.attr,
++ &dev_attr_ec_factory.attr,
++ &dev_attr_ec_state.attr,
++ &dev_attr_blocksize.attr,
++#ifdef OPTIMIZE_CHANMUTE
++ &dev_attr_chanmute.attr,
++#endif
++ &dev_attr_in_use.attr,
++ NULL,
++};
++ATTRIBUTE_GROUPS(chan_dev);
++#endif
+
+ static void chan_release(struct device *dev)
+ {
+@@ -196,7 +230,11 @@ static int chan_match(struct device *dev
+ static struct bus_type chan_bus_type = {
+ .name = "dahdi_channels",
+ .match = chan_match,
++#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0)
+ .dev_attrs = chan_dev_attrs,
++#else
++ .dev_groups = chan_dev_groups,
++#endif
+ };
+
+ static int chan_probe(struct device *dev)
+Index: dahdi-linux-2.11.1~dfsg/drivers/dahdi/xpp/xbus-sysfs.c
+===================================================================
+--- dahdi-linux-2.11.1~dfsg.orig/drivers/dahdi/xpp/xbus-sysfs.c
++++ dahdi-linux-2.11.1~dfsg/drivers/dahdi/xpp/xbus-sysfs.c
+@@ -339,6 +339,7 @@ static DEVICE_ATTR_READER(dahdi_registra
+ return len;
+ }
+
++#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0)
+ static struct device_attribute xbus_dev_attrs[] = {
+ __ATTR_RO(connector),
+ __ATTR_RO(label),
+@@ -358,6 +359,42 @@ static struct device_attribute xbus_dev_
+ dahdi_registration_store),
+ __ATTR_NULL,
+ };
++#else
++static DEVICE_ATTR_RO(connector);
++static DEVICE_ATTR_RO(label);
++static DEVICE_ATTR_RO(status);
++static DEVICE_ATTR_RO(timing);
++static DEVICE_ATTR_RO(refcount_xbus);
++static DEVICE_ATTR_RO(waitfor_xpds);
++static DEVICE_ATTR_RO(driftinfo);
++static DEVICE_ATTR(cls, S_IWUSR, NULL, cls_store);
++static DEVICE_ATTR(xbus_state, S_IRUGO | S_IWUSR, xbus_state_show,
++ xbus_state_store);
++#ifdef SAMPLE_TICKS
++static DEVICE_ATTR(samples, S_IWUSR | S_IRUGO, samples_show, samples_store);
++#endif
++static DEVICE_ATTR(dahdi_registration, S_IRUGO | S_IWUSR,
++ dahdi_registration_show,
++ dahdi_registration_store);
++
++static struct attribute *xbus_dev_attrs[] = {
++ &dev_attr_connector.attr,
++ &dev_attr_label.attr,
++ &dev_attr_status.attr,
++ &dev_attr_timing.attr,
++ &dev_attr_refcount_xbus.attr,
++ &dev_attr_waitfor_xpds.attr,
++ &dev_attr_driftinfo.attr,
++ &dev_attr_cls.attr,
++ &dev_attr_xbus_state.attr,
++#ifdef SAMPLE_TICKS
++ &dev_attr_samples.attr,
++#endif
++ &dev_attr_dahdi_registration.attr,
++ NULL,
++};
++ATTRIBUTE_GROUPS(xbus_dev);
++#endif
+
+ static int astribank_match(struct device *dev, struct device_driver *driver)
+ {
+@@ -457,10 +494,11 @@ static struct bus_type toplevel_bus_type
+ .name = "astribanks",
+ .match = astribank_match,
+ .uevent = astribank_uevent,
+- .dev_attrs = xbus_dev_attrs,
+ #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0)
++ .dev_attrs = xbus_dev_attrs,
+ .drv_attrs = xpp_attrs,
+ #else
++ .dev_groups = xbus_dev_groups,
+ .drv_groups = xpp_groups,
+ #endif
+ };
+@@ -744,6 +782,7 @@ static int xpd_match(struct device *dev,
+ return 1;
+ }
+
++#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0)
+ static struct device_attribute xpd_dev_attrs[] = {
+ __ATTR(chipregs, S_IRUGO | S_IWUSR, chipregs_show, chipregs_store),
+ __ATTR(blink, S_IRUGO | S_IWUSR, blink_show, blink_store),
+@@ -754,11 +793,36 @@ static struct device_attribute xpd_dev_a
+ __ATTR_RO(refcount_xpd),
+ __ATTR_NULL,
+ };
++#else
++DEVICE_ATTR(chipregs, S_IRUGO | S_IWUSR, chipregs_show, chipregs_store);
++DEVICE_ATTR(blink, S_IRUGO | S_IWUSR, blink_show, blink_store);
++DEVICE_ATTR(span, S_IRUGO | S_IWUSR, span_show, span_store);
++DEVICE_ATTR_RO(type);
++DEVICE_ATTR_RO(offhook);
++DEVICE_ATTR_RO(timing_priority);
++DEVICE_ATTR_RO(refcount_xpd);
++
++static struct attribute *xpd_dev_attrs[] = {
++ &dev_attr_chipregs.attr,
++ &dev_attr_blink.attr,
++ &dev_attr_span.attr,
++ &dev_attr_type.attr,
++ &dev_attr_offhook.attr,
++ &dev_attr_timing_priority.attr,
++ &dev_attr_refcount_xpd.attr,
++ NULL,
++};
++ATTRIBUTE_GROUPS(xpd_dev);
++#endif
+
+ static struct bus_type xpd_type = {
+ .name = "xpds",
+ .match = xpd_match,
++#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0)
+ .dev_attrs = xpd_dev_attrs,
++#else
++ .dev_groups = xpd_dev_groups,
++#endif
+ };
+
+ int xpd_driver_register(struct device_driver *driver)
diff --git a/main/dahdi-linux-vanilla/linux-4.4.patch b/main/dahdi-linux-vanilla/linux-4.4.patch
new file mode 100644
index 0000000000..fe6105319d
--- /dev/null
+++ b/main/dahdi-linux-vanilla/linux-4.4.patch
@@ -0,0 +1,10 @@
+--- ./drivers/dahdi/zaphfc.c.orig
++++ ./drivers/dahdi/zaphfc.c
+@@ -27,6 +27,7 @@
+ #include <linux/interrupt.h>
+ #include <linux/delay.h>
+ #include <linux/sched.h>
++#include <linux/vmalloc.h>
+ #include <dahdi/kernel.h>
+ #include "zaphfc.h"
+
diff --git a/main/dahdi-linux-vanilla/zaphfc-dahdi-2.4.0.patch b/main/dahdi-linux-vanilla/zaphfc-dahdi-2.4.0.patch
new file mode 100644
index 0000000000..80500a574a
--- /dev/null
+++ b/main/dahdi-linux-vanilla/zaphfc-dahdi-2.4.0.patch
@@ -0,0 +1,58 @@
+Index: dahdi-linux-2.4.0/drivers/dahdi/zaphfc.c
+===================================================================
+--- dahdi-linux-2.4.0.orig/drivers/dahdi/zaphfc.c 2010-10-26 14:41:21.000000000 +0300
++++ dahdi-linux-2.4.0/drivers/dahdi/zaphfc.c 2010-10-26 14:50:14.000000000 +0300
+@@ -617,7 +617,7 @@
+ }
+
+ static int zthfc_startup(struct dahdi_span *span) {
+- struct dahdi_hfc *zthfc = span->pvt;
++ struct dahdi_hfc *zthfc = container_of(span, struct dahdi_hfc, span);
+ struct hfc_card *hfctmp = zthfc->card;
+ int alreadyrunning;
+
+@@ -663,6 +663,19 @@
+ return 0;
+ }
+
++static const struct dahdi_span_ops zaphfc_span_ops = {
++ .owner = THIS_MODULE,
++ .spanconfig = zthfc_spanconfig,
++ .chanconfig = zthfc_chanconfig,
++ .startup = zthfc_startup,
++ .shutdown = zthfc_shutdown,
++ .maint = zthfc_maint,
++ .rbsbits = zthfc_rbsbits,
++ .open = zthfc_open,
++ .close = zthfc_close,
++ .ioctl = zthfc_ioctl,
++};
++
+ static int zthfc_initialize(struct dahdi_hfc *zthfc) {
+ struct hfc_card *hfctmp = zthfc->card;
+ int i;
+@@ -676,15 +689,7 @@
+ sprintf(zthfc->span.desc, "HFC-S PCI A ISDN card %d [TE]", hfc_dev_count + 1);
+ }
+
+- zthfc->span.spanconfig = zthfc_spanconfig;
+- zthfc->span.chanconfig = zthfc_chanconfig;
+- zthfc->span.startup = zthfc_startup;
+- zthfc->span.shutdown = zthfc_shutdown;
+- zthfc->span.maint = zthfc_maint;
+- zthfc->span.rbsbits = zthfc_rbsbits;
+- zthfc->span.open = zthfc_open;
+- zthfc->span.close = zthfc_close;
+- zthfc->span.ioctl = zthfc_ioctl;
++ zthfc->span.ops = &zaphfc_span_ops;
+
+ zthfc->span.channels = 3;
+ zthfc->span.chans = zthfc->_chans;
+@@ -695,7 +700,6 @@
+ zthfc->span.linecompat = DAHDI_CONFIG_AMI | DAHDI_CONFIG_CCS; // <--- this is really BS
+ zthfc->span.offset = 0;
+ init_waitqueue_head(&zthfc->span.maintq);
+- zthfc->span.pvt = zthfc;
+
+ for (i = 0; i < zthfc->span.channels; i++) {
+ memset(&(zthfc->chans[i]), 0x0, sizeof(struct dahdi_chan));
diff --git a/main/dahdi-linux-vanilla/zaphfc-dahdi-2.5.0.patch b/main/dahdi-linux-vanilla/zaphfc-dahdi-2.5.0.patch
new file mode 100644
index 0000000000..37a1e76ba8
--- /dev/null
+++ b/main/dahdi-linux-vanilla/zaphfc-dahdi-2.5.0.patch
@@ -0,0 +1,36 @@
+Index: dahdi-linux-2.5.0/drivers/dahdi/zaphfc.c
+===================================================================
+--- dahdi-linux-2.5.0.orig/drivers/dahdi/zaphfc.c 2011-08-15 14:29:51.000000000 +0300
++++ dahdi-linux-2.5.0/drivers/dahdi/zaphfc.c 2011-08-15 14:30:11.000000000 +0300
+@@ -616,7 +616,7 @@
+ return 0;
+ }
+
+-static int zthfc_startup(struct dahdi_span *span) {
++static int zthfc_startup(struct file *file, struct dahdi_span *span) {
+ struct dahdi_hfc *zthfc = container_of(span, struct dahdi_hfc, span);
+ struct hfc_card *hfctmp = zthfc->card;
+ int alreadyrunning;
+@@ -653,12 +653,12 @@
+ return 0;
+ }
+
+-static int zthfc_chanconfig(struct dahdi_chan *chan, int sigtype) {
++static int zthfc_chanconfig(struct file *file, struct dahdi_chan *chan, int sigtype) {
+ // printk(KERN_CRIT "chan_config sigtype=%d\n", sigtype);
+ return 0;
+ }
+
+-static int zthfc_spanconfig(struct dahdi_span *span, struct dahdi_lineconfig *lc) {
++static int zthfc_spanconfig(struct file *file, struct dahdi_span *span, struct dahdi_lineconfig *lc) {
+ span->lineconfig = lc->lineconfig;
+ return 0;
+ }
+@@ -699,7 +699,6 @@
+ zthfc->span.deflaw = DAHDI_LAW_ALAW;
+ zthfc->span.linecompat = DAHDI_CONFIG_AMI | DAHDI_CONFIG_CCS; // <--- this is really BS
+ zthfc->span.offset = 0;
+- init_waitqueue_head(&zthfc->span.maintq);
+
+ for (i = 0; i < zthfc->span.channels; i++) {
+ memset(&(zthfc->chans[i]), 0x0, sizeof(struct dahdi_chan));
diff --git a/main/dahdi-linux-vanilla/zaphfc-dahdi-2.6.0.patch b/main/dahdi-linux-vanilla/zaphfc-dahdi-2.6.0.patch
new file mode 100644
index 0000000000..5a77438462
--- /dev/null
+++ b/main/dahdi-linux-vanilla/zaphfc-dahdi-2.6.0.patch
@@ -0,0 +1,58 @@
+--- dahdi-linux-2.6.0/drivers/dahdi/zaphfc.c.orig 2012-01-25 14:08:58.000000000 +0200
++++ dahdi-linux-2.6.0/drivers/dahdi/zaphfc.c 2012-01-25 14:29:26.000000000 +0200
+@@ -122,7 +122,10 @@
+ }
+ spin_unlock_irqrestore(&hfctmp->lock,flags);
+ if (hfctmp->ztdev != NULL) {
+- dahdi_unregister(&hfctmp->ztdev->span);
++ if (hfctmp->ztdev->ddev) {
++ dahdi_unregister_device(hfctmp->ztdev->ddev);
++ dahdi_free_device(hfctmp->ztdev->ddev);
++ }
+ vfree(hfctmp->ztdev);
+ printk(KERN_INFO "unregistered from DAHDI.\n");
+ }
+@@ -680,9 +683,15 @@
+ struct hfc_card *hfctmp = zthfc->card;
+ int i;
+
++ zthfc->ddev = dahdi_create_device();
++ if (!zthfc->ddev)
++ return -ENOMEM;
++
++ zthfc->ddev->manufacturer = "HFC";
++
+ memset(&zthfc->span, 0x0, sizeof(struct dahdi_span)); // you never can tell...
+
+- sprintf(zthfc->span.name, "ZTHFC%d", hfc_dev_count + 1);
++ sprintf(zthfc->span.name, "ZTHFC/%d", hfc_dev_count + 1);
+ if (hfctmp->regs.nt_mode == 1) {
+ sprintf(zthfc->span.desc, "HFC-S PCI A ISDN card %d [NT]", hfc_dev_count + 1);
+ } else {
+@@ -702,13 +711,14 @@
+
+ for (i = 0; i < zthfc->span.channels; i++) {
+ memset(&(zthfc->chans[i]), 0x0, sizeof(struct dahdi_chan));
+- sprintf(zthfc->chans[i].name, "ZTHFC%d/%d/%d", hfc_dev_count + 1,0,i + 1);
++ sprintf(zthfc->chans[i].name, "ZTHFC/%d/%d/%d", hfc_dev_count + 1,0,i + 1);
+ zthfc->chans[i].pvt = zthfc;
+ zthfc->chans[i].sigcap = DAHDI_SIG_EM | DAHDI_SIG_CLEAR | DAHDI_SIG_FXSLS | DAHDI_SIG_FXSGS | DAHDI_SIG_FXSKS | DAHDI_SIG_FXOLS | DAHDI_SIG_FXOGS | DAHDI_SIG_FXOKS | DAHDI_SIG_CAS | DAHDI_SIG_SF;
+ zthfc->chans[i].chanpos = i + 1;
+ }
+
+- if (dahdi_register(&zthfc->span,0)) {
++ list_add_tail(&zthfc->span.device_node, &zthfc->ddev->spans);
++ if (dahdi_register_device(zthfc->ddev, &zthfc->card->pcidev->dev)) {
+ printk(KERN_CRIT "unable to register DAHDI device!\n");
+ return -1;
+ }
+--- dahdi-linux-2.6.0/drivers/dahdi/zaphfc.h.orig 2012-01-25 14:23:37.000000000 +0200
++++ dahdi-linux-2.6.0/drivers/dahdi/zaphfc.h 2012-01-25 14:24:33.000000000 +0200
+@@ -339,6 +339,7 @@
+ struct dahdi_span span;
+ struct dahdi_chan chans[3];
+ struct dahdi_chan *_chans[3];
++ struct dahdi_device *ddev;
+ struct hfc_card *card;
+ } dahdi_hfc;
+
diff --git a/main/dahdi-linux-vanilla/zaphfc-dahdi-2.7.0.patch b/main/dahdi-linux-vanilla/zaphfc-dahdi-2.7.0.patch
new file mode 100644
index 0000000000..624cfe7b9a
--- /dev/null
+++ b/main/dahdi-linux-vanilla/zaphfc-dahdi-2.7.0.patch
@@ -0,0 +1,32 @@
+--- dahdi-linux-2.7.0/drivers/dahdi/zaphfc.c.orig 2013-11-13 14:47:31.772140792 +0200
++++ dahdi-linux-2.7.0/drivers/dahdi/zaphfc.c 2013-11-13 14:55:20.136270113 +0200
+@@ -687,19 +687,18 @@
+ if (!zthfc->ddev)
+ return -ENOMEM;
+
+- zthfc->ddev->manufacturer = "HFC";
+-
++ zthfc->ddev->manufacturer = "Cologne Chips";
++ zthfc->ddev->devicetype = "HFC-S PCI-A ISDN";
++ zthfc->ddev->location = kasprintf(GFP_KERNEL,
++ "PCI Bus %02d Slot %02d",
++ hfctmp->pcidev->bus->number,
++ PCI_SLOT(hfctmp->pcidev->devfn) + 1);
+ memset(&zthfc->span, 0x0, sizeof(struct dahdi_span)); // you never can tell...
+-
+ sprintf(zthfc->span.name, "ZTHFC/%d", hfc_dev_count + 1);
+- if (hfctmp->regs.nt_mode == 1) {
+- sprintf(zthfc->span.desc, "HFC-S PCI A ISDN card %d [NT]", hfc_dev_count + 1);
+- } else {
+- sprintf(zthfc->span.desc, "HFC-S PCI A ISDN card %d [TE]", hfc_dev_count + 1);
+- }
+-
++ sprintf(zthfc->span.desc, "HFC-S PCI A ISDN card %d [%s]",
++ hfc_dev_count + 1, hfctmp->regs.nt_mode ? "NT" : "TE");
++ zthfc->span.spantype = hfctmp->regs.nt_mode ? SPANTYPE_DIGITAL_BRI_NT : SPANTYPE_DIGITAL_BRI_TE;
+ zthfc->span.ops = &zaphfc_span_ops;
+-
+ zthfc->span.channels = 3;
+ zthfc->span.chans = zthfc->_chans;
+ for (i = 0; i < zthfc->span.channels; i++)
+
diff --git a/main/dahdi-linux-vanilla/zaphfc-dahdi-flortz.diff b/main/dahdi-linux-vanilla/zaphfc-dahdi-flortz.diff
new file mode 100644
index 0000000000..dc856c97c7
--- /dev/null
+++ b/main/dahdi-linux-vanilla/zaphfc-dahdi-flortz.diff
@@ -0,0 +1,1232 @@
+Index: dahdi-linux-2.1.0.4/drivers/dahdi/zaphfc.h
+===================================================================
+--- dahdi-linux-2.1.0.4.orig/drivers/dahdi/zaphfc.h 2009-03-17 18:13:54.000000000 +0200
++++ dahdi-linux-2.1.0.4/drivers/dahdi/zaphfc.h 2009-03-17 18:14:44.000000000 +0200
+@@ -135,8 +135,12 @@
+ /* bits in HFCD_MST_MODE */
+ #define hfc_MST_MODE_MASTER 0x01
+ #define hfc_MST_MODE_SLAVE 0x00
++#define hfc_MST_MODE_F0_LONG_DURATION 0x08
+ /* remaining bits are for codecs control */
+
++/* bits in HFCD_MST_EMOD */
++#define hfc_MST_EMOD_SLOW_CLOCK_ADJ 0x01
++
+ /* bits in HFCD_SCTRL */
+ #define hfc_SCTRL_B1_ENA 0x01
+ #define hfc_SCTRL_B2_ENA 0x02
+@@ -236,6 +240,9 @@
+ #define hfc_BTRANS_THRESHOLD 128
+ #define hfc_BTRANS_THRESMASK 0x00
+
++#define hfc_FIFO_MEM_SIZE_BYTES (32*1024)
++#define hfc_FIFO_MEM_SIZE_PAGES ((hfc_FIFO_MEM_SIZE_BYTES+PAGE_SIZE-1)/PAGE_SIZE)
++
+ /* Structures */
+
+ typedef struct hfc_regs {
+@@ -249,20 +256,67 @@
+ unsigned char connect;
+ unsigned char trm;
+ unsigned char mst_mode;
++ unsigned char mst_emod;
+ unsigned char bswapped;
+ unsigned char nt_mode;
+ unsigned char int_drec;
+ } hfc_regs;
+
++struct bch {
++ int fill_fifo,checkcnt,initialized;
++ struct {
++ u16 z2;
++ struct {
++ volatile u16 *z1p;
++ volatile u8 *fifo_base;
++ int filled;
++ } c[2];
++ int diff;
++ } rx;
++ struct {
++ u16 z1;
++ struct {
++ volatile u16 *z1p,*z2p;
++ volatile u8 *fifo_base;
++ int filled;
++ } c[2];
++ int diff;
++ } tx;
++};
++
++struct dch {
++ struct {
++ struct {
++ volatile u8 *p;
++ } f1;
++ struct {
++ u8 v;
++ struct {
++ u16 v;
++ } z2;
++ } f2;
++ } rx;
++ struct {
++ struct {
++ u8 v;
++ volatile u8 *p;
++ struct {
++ u16 v;
++ } z1;
++ } f1;
++ struct {
++ volatile u8 *p;
++ } f2;
++ } tx;
++};
++
+ typedef struct hfc_card {
+ spinlock_t lock;
+ unsigned int irq;
+ unsigned int iomem;
+ int ticks;
+- int clicks;
+ unsigned char *pci_io;
+- void *fifomem; // start of the shared mem
+- volatile void *fifos; // 32k aligned mem for the fifos
++ void *fifos; // 32k aligned mem for the fifos
+ struct hfc_regs regs;
+ unsigned int pcibus;
+ unsigned int pcidevfn;
+@@ -274,6 +328,9 @@
+ unsigned char brecbuf[2][DAHDI_CHUNKSIZE];
+ unsigned char btransbuf[2][DAHDI_CHUNKSIZE];
+ unsigned char cardno;
++ int active;
++ struct bch bch;
++ struct dch dch;
+ struct hfc_card *next;
+ } hfc_card;
+
+@@ -285,6 +342,3 @@
+ struct hfc_card *card;
+ } dahdi_hfc;
+
+-/* tune this */
+-#define hfc_BCHAN_BUFFER 8
+-#define hfc_MAX_CARDS 8
+Index: dahdi-linux-2.1.0.4/drivers/dahdi/zaphfc.c
+===================================================================
+--- dahdi-linux-2.1.0.4.orig/drivers/dahdi/zaphfc.c 2009-03-17 18:52:47.000000000 +0200
++++ dahdi-linux-2.1.0.4/drivers/dahdi/zaphfc.c 2009-03-17 18:53:43.000000000 +0200
+@@ -7,19 +7,21 @@
+ *
+ * Klaus-Peter Junghanns <kpj@junghanns.net>
+ *
++ * Copyright (C) 2004, 2005, 2006 Florian Zumbiehl <florz@gmx.de>
++ * - support for slave mode of the HFC-S chip which allows it to
++ * sync its sample clock to an external source/another HFC chip
++ * - support for "interrupt bundling" (let only one card generate
++ * 8 kHz timing interrupt no matter how many cards there are
++ * in the system)
++ * - interrupt loss tolerant b channel handling
++ *
+ * This program is free software and may be modified and
+- * distributed under the terms of the GNU Public License.
++ * distributed under the terms of the GNU General Public License.
+ *
+ */
+
+ #include <linux/kernel.h>
+ #include <linux/module.h>
+-#ifdef RTAITIMING
+-#include <asm/io.h>
+-#include <rtai.h>
+-#include <rtai_sched.h>
+-#include <rtai_fifos.h>
+-#endif
+ #include <linux/pci.h>
+ #include <linux/init.h>
+ #include <linux/interrupt.h>
+@@ -29,6 +31,8 @@
+
+ #include <linux/moduleparam.h>
+
++#define log2(n) ffz(~(n))
++
+ #if CONFIG_PCI
+
+ #define CLKDEL_TE 0x0f /* CLKDEL in TE mode */
+@@ -70,42 +74,31 @@
+ static struct hfc_card *hfc_dev_list = NULL;
+ static int hfc_dev_count = 0;
+ static int modes = 0; // all TE
++static int sync_slave = 0; // all master
++static int timer_card = 0;
++static int jitterbuffer = 1;
+ static int debug = 0;
+ static struct pci_dev *multi_hfc = NULL;
+ static DEFINE_SPINLOCK(registerlock);
+
+-void hfc_shutdownCard(struct hfc_card *hfctmp) {
+- unsigned long flags;
+-
+- if (hfctmp == NULL) {
+- return;
+- }
+-
+- if (hfctmp->pci_io == NULL) {
+- return;
+- }
+-
+- spin_lock_irqsave(&hfctmp->lock,flags);
+-
++void hfc_shutdownCard1(struct hfc_card *hfctmp) {
+ printk(KERN_INFO "zaphfc: shutting down card at %p.\n",hfctmp->pci_io);
+
+ /* Clear interrupt mask */
+ hfctmp->regs.int_m2 = 0;
+ hfc_outb(hfctmp, hfc_INT_M2, hfctmp->regs.int_m2);
+
+- /* Reset pending interrupts */
+- hfc_inb(hfctmp, hfc_INT_S1);
++ /* Remove interrupt handler */
++ free_irq(hfctmp->irq,hfctmp);
++}
++
++void hfc_shutdownCard2(struct hfc_card *hfctmp) {
++ unsigned long flags;
+
+- /* Wait for interrupts that might still be pending */
+- spin_unlock_irqrestore(&hfctmp->lock, flags);
+- set_current_state(TASK_UNINTERRUPTIBLE);
+- schedule_timeout((30 * HZ) / 1000); // wait 30 ms
+ spin_lock_irqsave(&hfctmp->lock,flags);
+
+- /* Remove interrupt handler */
+- if (hfctmp->irq) {
+- free_irq(hfctmp->irq, hfctmp);
+- }
++ /* Reset pending interrupts */
++ hfc_inb(hfctmp, hfc_INT_S1);
+
+ /* Soft-reset the card */
+ hfc_outb(hfctmp, hfc_CIRM, hfc_CIRM_RESET); // softreset on
+@@ -119,8 +112,8 @@
+
+ pci_write_config_word(hfctmp->pcidev, PCI_COMMAND, 0); // disable memio and bustmaster
+
+- if (hfctmp->fifomem != NULL) {
+- kfree(hfctmp->fifomem);
++ if (hfctmp->fifos != NULL) {
++ free_pages((unsigned long)hfctmp->fifos,log2(hfc_FIFO_MEM_SIZE_PAGES));
+ }
+ iounmap((void *) hfctmp->pci_io);
+ hfctmp->pci_io = NULL;
+@@ -130,11 +123,24 @@
+ spin_unlock_irqrestore(&hfctmp->lock,flags);
+ if (hfctmp->ztdev != NULL) {
+ dahdi_unregister(&hfctmp->ztdev->span);
+- kfree(hfctmp->ztdev);
++ vfree(hfctmp->ztdev);
+ printk(KERN_INFO "unregistered from DAHDI.\n");
+ }
+ }
+
++void hfc_shutdownCard(struct hfc_card *hfctmp) {
++ if (hfctmp == NULL) {
++ return;
++ }
++
++ if (hfctmp->pci_io == NULL) {
++ return;
++ }
++
++ hfc_shutdownCard1(hfctmp);
++ hfc_shutdownCard2(hfctmp);
++}
++
+ void hfc_resetCard(struct hfc_card *hfctmp) {
+ unsigned long flags;
+
+@@ -178,14 +184,14 @@
+ hfctmp->regs.ctmt = hfc_CTMT_TRANSB1 | hfc_CTMT_TRANSB2; // all bchans are transparent , no freaking hdlc
+ hfc_outb(hfctmp, hfc_CTMT, hfctmp->regs.ctmt);
+
+- hfctmp->regs.int_m1 = 0;
++ hfctmp->regs.int_m1=hfc_INTS_L1STATE;
++ if(hfctmp->cardno==timer_card){
++ hfctmp->regs.int_m2=hfc_M2_PROC_TRANS;
++ }else{
++ hfctmp->regs.int_m1|=hfc_INTS_DREC;
++ hfctmp->regs.int_m2=0;
++ }
+ hfc_outb(hfctmp, hfc_INT_M1, hfctmp->regs.int_m1);
+-
+-#ifdef RTAITIMING
+- hfctmp->regs.int_m2 = 0;
+-#else
+- hfctmp->regs.int_m2 = hfc_M2_PROC_TRANS;
+-#endif
+ hfc_outb(hfctmp, hfc_INT_M2, hfctmp->regs.int_m2);
+
+ /* Clear already pending ints */
+@@ -197,8 +203,8 @@
+ hfctmp->regs.sctrl = 3 | hfc_SCTRL_NONE_CAP | hfc_SCTRL_MODE_TE; /* set tx_lo mode, error in datasheet ! */
+ }
+
+- hfctmp->regs.mst_mode = hfc_MST_MODE_MASTER; /* HFC Master Mode */
+ hfc_outb(hfctmp, hfc_MST_MODE, hfctmp->regs.mst_mode);
++ hfc_outb(hfctmp, hfc_MST_EMOD, hfctmp->regs.mst_emod);
+
+ hfc_outb(hfctmp, hfc_SCTRL, hfctmp->regs.sctrl);
+ hfctmp->regs.sctrl_r = 3;
+@@ -210,10 +216,8 @@
+ hfc_outb(hfctmp, hfc_CIRM, 0x80 | 0x40); // bit order
+
+ /* Finally enable IRQ output */
+-#ifndef RTAITIMING
+ hfctmp->regs.int_m2 |= hfc_M2_IRQ_ENABLE;
+ hfc_outb(hfctmp, hfc_INT_M2, hfctmp->regs.int_m2);
+-#endif
+
+ /* clear pending ints */
+ hfc_inb(hfctmp, hfc_INT_S1);
+@@ -230,368 +234,210 @@
+ spin_unlock(&registerlock);
+ }
+
+-static void hfc_btrans(struct hfc_card *hfctmp, char whichB) {
+- // we are called with irqs disabled from the irq handler
+- int count, maxlen, total;
+- unsigned char *f1, *f2;
+- unsigned short *z1, *z2, newz1;
+- int freebytes;
+-
+- if (whichB == 1) {
+- f1 = (char *)(hfctmp->fifos + hfc_FIFO_B1TX_F1);
+- f2 = (char *)(hfctmp->fifos + hfc_FIFO_B1TX_F2);
+- z1 = (unsigned short *)(hfctmp->fifos + hfc_FIFO_B1TX_Z1 + (*f1 * 4));
+- z2 = (unsigned short *)(hfctmp->fifos + hfc_FIFO_B1TX_Z2 + (*f1 * 4));
+- } else {
+- f1 = (char *)(hfctmp->fifos + hfc_FIFO_B2TX_F1);
+- f2 = (char *)(hfctmp->fifos + hfc_FIFO_B2TX_F2);
+- z1 = (unsigned short *)(hfctmp->fifos + hfc_FIFO_B2TX_Z1 + (*f1 * 4));
+- z2 = (unsigned short *)(hfctmp->fifos + hfc_FIFO_B2TX_Z2 + (*f1 * 4));
+- }
+-
+- freebytes = *z2 - *z1;
+- if (freebytes <= 0) {
+- freebytes += hfc_B_FIFO_SIZE;
+- }
+- count = DAHDI_CHUNKSIZE;
+-
+- total = count;
+- if (freebytes < count) {
+- hfctmp->clicks++;
+- /* only spit out this warning once per second to not make things worse! */
+- if (hfctmp->clicks > 100) {
+- printk(KERN_CRIT "zaphfc: bchan tx fifo full, dropping audio! (z1=%d, z2=%d)\n",*z1,*z2);
+- hfctmp->clicks = 0;
+- }
+- return;
+- }
+-
+- maxlen = (hfc_B_FIFO_SIZE + hfc_B_SUB_VAL) - *z1;
+- if (maxlen > count) {
+- maxlen = count;
+- }
+- newz1 = *z1 + total;
+- if (newz1 >= (hfc_B_FIFO_SIZE + hfc_B_SUB_VAL)) { newz1 -= hfc_B_FIFO_SIZE; }
++/*===========================================================================*/
+
+- if (whichB == 1) {
+- memcpy((char *)(hfctmp->fifos + hfc_FIFO_B1TX_ZOFF + *z1),hfctmp->ztdev->chans[0].writechunk, maxlen);
+- } else {
+- memcpy((char *)(hfctmp->fifos + hfc_FIFO_B2TX_ZOFF + *z1),hfctmp->ztdev->chans[1].writechunk, maxlen);
+- }
+-
+- count -= maxlen;
+- if (count > 0) {
+- // Buffer wrap
+- if (whichB == 1) {
+- memcpy((char *)(hfctmp->fifos + hfc_FIFO_B1TX_ZOFF + hfc_B_SUB_VAL),hfctmp->ztdev->chans[0].writechunk+maxlen, count);
+- } else {
+- memcpy((char *)(hfctmp->fifos + hfc_FIFO_B2TX_ZOFF + hfc_B_SUB_VAL),hfctmp->ztdev->chans[1].writechunk+maxlen, count);
+- }
+- }
++#if hfc_B_FIFO_SIZE%DAHDI_CHUNKSIZE
++#error hfc_B_FIFO_SIZE is not a multiple of DAHDI_CHUNKSIZE even though the code assumes this
++#endif
++
++static void hfc_dch_init(struct hfc_card *hfctmp){
++ struct dch *chtmp=&hfctmp->dch;
+
+- *z1 = newz1; /* send it now */
++ chtmp->rx.f1.p=(u8 *)(hfctmp->fifos+hfc_FIFO_DRX_F1);
++ chtmp->rx.f2.v=0x1f;
++ chtmp->rx.f2.z2.v=0x1ff;
+
+-// if (count > 0) printk(KERN_CRIT "zaphfc: bchan tx fifo (f1=%d, f2=%d, z1=%d, z2=%d)\n",(*f1) & hfc_FMASK,(*f2) & hfc_FMASK, *z1, *z2);
+- return;
++ chtmp->tx.f1.p=(u8 *)(hfctmp->fifos+hfc_FIFO_DTX_F1);
++ chtmp->tx.f1.v=0x1f;
++ chtmp->tx.f1.z1.v=0x1ff;
++ chtmp->tx.f2.p=(u8 *)(hfctmp->fifos+hfc_FIFO_DTX_F2);
+ }
+
+-static void hfc_brec(struct hfc_card *hfctmp, char whichB) {
+- // we are called with irqs disabled from the irq handler
+- int count, maxlen, drop;
+- volatile unsigned char *f1, *f2;
+- volatile unsigned short *z1, *z2, newz2;
+- int bytes = 0;
+-
+- if (whichB == 1) {
+- f1 = (char *)(hfctmp->fifos + hfc_FIFO_B1RX_F1);
+- f2 = (char *)(hfctmp->fifos + hfc_FIFO_B1RX_F2);
+- z1 = (unsigned short *)(hfctmp->fifos + hfc_FIFO_B1RX_Z1 + (*f1 * 4));
+- z2 = (unsigned short *)(hfctmp->fifos + hfc_FIFO_B1RX_Z2 + (*f1 * 4));
+- } else {
+- f1 = (char *)(hfctmp->fifos + hfc_FIFO_B2RX_F1);
+- f2 = (char *)(hfctmp->fifos + hfc_FIFO_B2RX_F2);
+- z1 = (unsigned short *)(hfctmp->fifos + hfc_FIFO_B2RX_Z1 + (*f1 * 4));
+- z2 = (unsigned short *)(hfctmp->fifos + hfc_FIFO_B2RX_Z2 + (*f1 * 4));
+- }
++static void hfc_bch_init(struct hfc_card *hfctmp){
++ struct bch *chtmp=&hfctmp->bch;
+
+- bytes = *z1 - *z2;
+- if (bytes < 0) {
+- bytes += hfc_B_FIFO_SIZE;
+- }
+- count = DAHDI_CHUNKSIZE;
+-
+- if (bytes < DAHDI_CHUNKSIZE) {
+-#ifndef RTAITIMING
+- printk(KERN_CRIT "zaphfc: bchan rx fifo not enough bytes to receive! (z1=%d, z2=%d, wanted %d got %d), probably a buffer overrun.\n",*z1,*z2,DAHDI_CHUNKSIZE,bytes);
+-#endif
+- return;
+- }
++ chtmp->checkcnt=0;
++ chtmp->fill_fifo=0;
+
+- /* allowing the buffering of hfc_BCHAN_BUFFER bytes of audio data works around irq jitter */
+- if (bytes > hfc_BCHAN_BUFFER + DAHDI_CHUNKSIZE) {
+- /* if the system is too slow to handle it, we will have to drop it all (except 1 DAHDI chunk) */
+- drop = bytes - DAHDI_CHUNKSIZE;
+- hfctmp->clicks++;
+- /* only spit out this warning once per second to not make things worse! */
+- if (hfctmp->clicks > 100) {
+- printk(KERN_CRIT "zaphfc: dropped audio (z1=%d, z2=%d, wanted %d got %d, dropped %d).\n",*z1,*z2,count,bytes,drop);
+- hfctmp->clicks = 0;
+- }
+- /* hm, we are processing the b chan data tooooo slowly... let's drop the lost audio */
+- newz2 = *z2 + drop;
+- if (newz2 >= (hfc_B_FIFO_SIZE + hfc_B_SUB_VAL)) {
+- newz2 -= hfc_B_FIFO_SIZE;
+- }
+- *z2 = newz2;
+- }
++ chtmp->rx.c[0].z1p=(unsigned short *)(hfctmp->fifos+hfc_FIFO_B1RX_Z1+0x1f*4);
++ chtmp->rx.c[0].fifo_base=(char *)(hfctmp->fifos+hfc_FIFO_B1RX_ZOFF);
++ chtmp->rx.c[1].z1p=(unsigned short *)(hfctmp->fifos+hfc_FIFO_B2RX_Z1+0x1f*4);
++ chtmp->rx.c[1].fifo_base=(char *)(hfctmp->fifos+hfc_FIFO_B2RX_ZOFF);
++ chtmp->rx.z2=hfc_B_SUB_VAL;
++ chtmp->rx.diff=0;
+
+-
+- maxlen = (hfc_B_FIFO_SIZE + hfc_B_SUB_VAL) - *z2;
+- if (maxlen > count) {
+- maxlen = count;
+- }
+- if (whichB == 1) {
+- memcpy(hfctmp->ztdev->chans[0].readchunk,(char *)(hfctmp->fifos + hfc_FIFO_B1RX_ZOFF + *z2), maxlen);
+- } else {
+- memcpy(hfctmp->ztdev->chans[1].readchunk,(char *)(hfctmp->fifos + hfc_FIFO_B2RX_ZOFF + *z2), maxlen);
+- }
+- newz2 = *z2 + count;
+- if (newz2 >= (hfc_B_FIFO_SIZE + hfc_B_SUB_VAL)) {
+- newz2 -= hfc_B_FIFO_SIZE;
++ chtmp->tx.c[0].z1p=(unsigned short *)(hfctmp->fifos+hfc_FIFO_B1TX_Z1+0x1f*4);
++ chtmp->tx.c[0].z2p=(unsigned short *)(hfctmp->fifos+hfc_FIFO_B1TX_Z2+0x1f*4);
++ chtmp->tx.c[0].fifo_base=(char *)(hfctmp->fifos+hfc_FIFO_B1TX_ZOFF);
++ chtmp->tx.c[0].filled=0;
++ chtmp->tx.c[1].z1p=(unsigned short *)(hfctmp->fifos+hfc_FIFO_B2TX_Z1+0x1f*4);
++ chtmp->tx.c[1].z2p=(unsigned short *)(hfctmp->fifos+hfc_FIFO_B2TX_Z2+0x1f*4);
++ chtmp->tx.c[1].fifo_base=(char *)(hfctmp->fifos+hfc_FIFO_B2TX_ZOFF);
++ chtmp->tx.c[1].filled=0;
++ chtmp->tx.z1=hfc_B_SUB_VAL;
++ chtmp->tx.diff=0;
++
++ hfc_dch_init(hfctmp);
++
++ chtmp->initialized=0;
++}
++
++static int hfc_bch_check(struct hfc_card *hfctmp){
++ struct bch *chtmp=&hfctmp->bch;
++ int x,r;
++
++ for(x=0;x<2;x++){
++ chtmp->tx.c[x].filled=(chtmp->tx.z1-*chtmp->tx.c[x].z2p+hfc_B_FIFO_SIZE)%hfc_B_FIFO_SIZE;
++ chtmp->rx.c[x].filled=(*chtmp->rx.c[x].z1p-chtmp->rx.z2+hfc_B_FIFO_SIZE)%hfc_B_FIFO_SIZE;
+ }
+- *z2 = newz2;
+-
+- count -= maxlen;
+- if (count > 0) {
+- // Buffer wrap
+- if (whichB == 1) {
+- z2 = (unsigned short *)(hfctmp->fifos + hfc_FIFO_B1RX_Z2 + (*f1 * 4));
+- memcpy(hfctmp->ztdev->chans[0].readchunk + maxlen,(char *)(hfctmp->fifos + hfc_FIFO_B1RX_ZOFF + hfc_B_SUB_VAL), count);
+- } else {
+- z2 = (unsigned short *)(hfctmp->fifos + hfc_FIFO_B2RX_Z2 + (*f1 * 4));
+- memcpy(hfctmp->ztdev->chans[1].readchunk + maxlen,(char *)(hfctmp->fifos + hfc_FIFO_B2RX_ZOFF + hfc_B_SUB_VAL), count);
+- }
+- newz2 = *z2 + count;
+- if (newz2 >= (hfc_B_FIFO_SIZE + hfc_B_SUB_VAL)) {
+- newz2 -= hfc_B_FIFO_SIZE;
++ if(chtmp->fill_fifo){
++ chtmp->checkcnt++;
++ chtmp->checkcnt%=DAHDI_CHUNKSIZE;
++ r=!chtmp->checkcnt;
++ }else{
++ x=chtmp->tx.c[0].filled-chtmp->tx.c[1].filled;
++ if(abs(x-chtmp->tx.diff)>1){
++ printk(KERN_CRIT "zaphfc[%d]: tx sync changed: %d, %d\n",hfctmp->cardno,chtmp->tx.c[0].filled,chtmp->tx.c[1].filled);
++ chtmp->tx.diff=x;
+ }
++ r=chtmp->tx.c[0].filled<=DAHDI_CHUNKSIZE*jitterbuffer&&chtmp->tx.c[1].filled<=DAHDI_CHUNKSIZE*jitterbuffer;
+ }
++ return(r);
++}
+
++#define hfc_bch_inc_z(a,b) (a)=((a)-hfc_B_SUB_VAL+(b))%hfc_B_FIFO_SIZE+hfc_B_SUB_VAL
+
+- if (whichB == 1) {
+- dahdi_ec_chunk(&hfctmp->ztdev->chans[0], hfctmp->ztdev->chans[0].readchunk, hfctmp->ztdev->chans[0].writechunk);
+- } else {
+- dahdi_ec_chunk(&hfctmp->ztdev->chans[1], hfctmp->ztdev->chans[1].readchunk, hfctmp->ztdev->chans[1].writechunk);
++static void hfc_bch_tx(struct hfc_card *hfctmp){
++ struct bch *chtmp=&hfctmp->bch;
++ int x;
++
++ for(x=0;x<2;x++)
++ memcpy((void *)(chtmp->tx.c[x].fifo_base+chtmp->tx.z1),hfctmp->ztdev->chans[x].writechunk,DAHDI_CHUNKSIZE);
++ hfc_bch_inc_z(chtmp->tx.z1,DAHDI_CHUNKSIZE);
++ if(chtmp->fill_fifo){
++ chtmp->fill_fifo--;
++ }else if(chtmp->tx.c[0].filled<=1||chtmp->tx.c[1].filled<=1){
++ chtmp->fill_fifo=jitterbuffer;
++ if(chtmp->initialized)
++ printk(KERN_CRIT "zaphfc[%d]: b channel buffer underrun: %d, %d\n",hfctmp->cardno,chtmp->tx.c[0].filled,chtmp->tx.c[1].filled);
+ }
+- return;
++ if(!chtmp->fill_fifo)
++ for(x=0;x<2;x++)*chtmp->tx.c[x].z1p=chtmp->tx.z1;
+ }
+
+-
+-static void hfc_dtrans(struct hfc_card *hfctmp) {
+- // we are called with irqs disabled from the irq handler
++static void hfc_bch_rx(struct hfc_card *hfctmp){
++ struct bch *chtmp=&hfctmp->bch;
+ int x;
+- int count, maxlen, total;
+- unsigned char *f1, *f2, newf1;
+- unsigned short *z1, *z2, newz1;
+- int frames, freebytes;
+
+- if (hfctmp->ztdev->chans[2].bytes2transmit == 0) {
+- return;
++ x=chtmp->rx.c[0].filled-chtmp->rx.c[1].filled;
++ if(abs(x-chtmp->rx.diff)>1){
++ printk(KERN_CRIT "zaphfc[%d]: rx sync changed: %d, %d\n",hfctmp->cardno,chtmp->rx.c[0].filled,chtmp->rx.c[1].filled);
++ chtmp->rx.diff=x;
+ }
+-
+- f1 = (char *)(hfctmp->fifos + hfc_FIFO_DTX_F1);
+- f2 = (char *)(hfctmp->fifos + hfc_FIFO_DTX_F2);
+- z1 = (unsigned short *)(hfctmp->fifos + hfc_FIFO_DTX_Z1 + (*f1 * 4));
+- z2 = (unsigned short *)(hfctmp->fifos + hfc_FIFO_DTX_Z2 + (*f1 * 4));
+-
+- frames = (*f1 - *f2) & hfc_FMASK;
+- if (frames < 0) {
+- frames += hfc_MAX_DFRAMES + 1;
++ if(chtmp->rx.c[0].filled>=DAHDI_CHUNKSIZE&&chtmp->rx.c[1].filled>=DAHDI_CHUNKSIZE){
++ if((chtmp->rx.c[0].filled>=DAHDI_CHUNKSIZE*(jitterbuffer+2)&&chtmp->rx.c[1].filled>=DAHDI_CHUNKSIZE*(jitterbuffer+2))||!chtmp->initialized){
++ if(chtmp->initialized)
++ printk(KERN_CRIT "zaphfc[%d]: b channel buffer overflow: %d, %d\n",hfctmp->cardno,chtmp->rx.c[0].filled,chtmp->rx.c[1].filled);
++ hfc_bch_inc_z(chtmp->rx.z2,chtmp->rx.c[0].filled-chtmp->rx.c[0].filled%DAHDI_CHUNKSIZE-DAHDI_CHUNKSIZE);
++ chtmp->initialized=1;
++ }
++ for(x=0;x<2;x++){
++ memcpy(hfctmp->ztdev->chans[x].readchunk,(void *)(chtmp->rx.c[x].fifo_base+chtmp->rx.z2),DAHDI_CHUNKSIZE);
++ dahdi_ec_chunk(&hfctmp->ztdev->chans[x],hfctmp->ztdev->chans[x].readchunk,hfctmp->ztdev->chans[x].writechunk);
++ }
++ hfc_bch_inc_z(chtmp->rx.z2,DAHDI_CHUNKSIZE);
+ }
++}
+
+- if (frames >= hfc_MAX_DFRAMES) {
+- printk(KERN_CRIT "zaphfc: dchan tx fifo total number of frames exceeded!\n");
+- return;
+- }
++/*===========================================================================*/
+
+- freebytes = *z2 - *z1;
+- if (freebytes <= 0) {
+- freebytes += hfc_D_FIFO_SIZE;
+- }
+- count = hfctmp->ztdev->chans[2].bytes2transmit;
+-
+- total = count;
+- if (freebytes < count) {
+- printk(KERN_CRIT "zaphfc: dchan tx fifo not enough free bytes! (z1=%d, z2=%d)\n",*z1,*z2);
+- return;
+- }
+-
+- newz1 = (*z1 + count) & hfc_ZMASK;
+- newf1 = ((*f1 + 1) & hfc_MAX_DFRAMES) | (hfc_MAX_DFRAMES + 1); // next frame
+-
+- if (count > 0) {
+- if (debug) {
+- printk(KERN_CRIT "zaphfc: card %d TX [ ", hfctmp->cardno);
+- for (x=0; x<count; x++) {
++static void hfc_dch_tx(struct hfc_card *hfctmp){
++ struct dch *chtmp=&hfctmp->dch;
++ u8 tx_f2_v;
++ u16 x;
++
++ if(hfctmp->ztdev->chans[2].bytes2transmit){
++ if(debug){
++ printk(KERN_CRIT "zaphfc[%d]: card TX [ ",hfctmp->cardno);
++ for(x=0;x<hfctmp->ztdev->chans[2].bytes2transmit;x++){
+ printk("%#2x ",hfctmp->dtransbuf[x]);
+ }
+- if (hfctmp->ztdev->chans[2].eoftx == 1) {
+- printk("] %d bytes\n", count);
+- } else {
+- printk("..] %d bytes\n", count);
+- }
+- }
+- maxlen = hfc_D_FIFO_SIZE - *z1;
+- if (maxlen > count) {
+- maxlen = count;
++ printk("] %d bytes\n",hfctmp->ztdev->chans[2].bytes2transmit);
+ }
+- memcpy((char *)(hfctmp->fifos + hfc_FIFO_DTX_ZOFF + *z1),hfctmp->ztdev->chans[2].writechunk, maxlen);
+- count -= maxlen;
+- if (count > 0) {
+- memcpy((char *)(hfctmp->fifos + hfc_FIFO_DTX_ZOFF),(char *)(hfctmp->ztdev->chans[2].writechunk + maxlen), count);
++ tx_f2_v=*chtmp->tx.f2.p;
++ if(!(tx_f2_v-chtmp->tx.f1.v+hfc_MAX_DFRAMES+1-1)&(hfc_MAX_DFRAMES+1-1)){
++ printk(KERN_CRIT "zaphfc[%d]: dchan tx fifo total number of frames exceeded!\n",hfctmp->cardno);
++ }else{
++ if(((*(volatile u16 *)(hfctmp->fifos+hfc_FIFO_DTX_Z2+tx_f2_v*4)-chtmp->tx.f1.z1.v+hfc_D_FIFO_SIZE-1)&(hfc_D_FIFO_SIZE-1))<hfctmp->ztdev->chans[2].bytes2transmit){
++ printk(KERN_CRIT "zaphfc[%d]: dchan tx fifo not enough space for frame!\n",hfctmp->cardno);
++ }else{
++ chtmp->tx.f1.v=((chtmp->tx.f1.v+1)&hfc_MAX_DFRAMES)|(hfc_MAX_DFRAMES+1);
++ x=min(hfctmp->ztdev->chans[2].bytes2transmit,hfc_D_FIFO_SIZE-chtmp->tx.f1.z1.v);
++ memcpy(hfctmp->fifos+hfc_FIFO_DTX_ZOFF+chtmp->tx.f1.z1.v,hfctmp->ztdev->chans[2].writechunk,x);
++ memcpy(hfctmp->fifos+hfc_FIFO_DTX_ZOFF,hfctmp->ztdev->chans[2].writechunk+x,hfctmp->ztdev->chans[2].bytes2transmit-x);
++ *(volatile u16 *)(hfctmp->fifos+hfc_FIFO_DTX_Z2+chtmp->tx.f1.v*4)=chtmp->tx.f1.z1.v;
++ chtmp->tx.f1.z1.v=(chtmp->tx.f1.z1.v+hfctmp->ztdev->chans[2].bytes2transmit+hfc_D_FIFO_SIZE)&(hfc_D_FIFO_SIZE-1);
++ *(volatile u16 *)(hfctmp->fifos+hfc_FIFO_DTX_Z1+chtmp->tx.f1.v*4)=chtmp->tx.f1.z1.v;
++ *chtmp->tx.f1.p=chtmp->tx.f1.v;
++ }
+ }
+ }
+-
+- *z1 = newz1;
+-
+- if (hfctmp->ztdev->chans[2].eoftx == 1) {
+- *f1 = newf1;
+- z1 = (unsigned short *)(hfctmp->fifos + hfc_FIFO_DTX_Z1 + (*f1 * 4));
+- *z1 = newz1;
+- hfctmp->ztdev->chans[2].eoftx = 0;
+- }
+-// printk(KERN_CRIT "zaphfc: dchan tx fifo (f1=%d, f2=%d, z1=%d, z2=%d)\n",(*f1) & hfc_FMASK,(*f2) & hfc_FMASK, *z1, *z2);
+- return;
+ }
+
+-/* receive a complete hdlc frame, skip broken or short frames */
+-static void hfc_drec(struct hfc_card *hfctmp) {
+- int count=0, maxlen=0, framelen=0;
+- unsigned char *f1, *f2, *crcstat;
+- unsigned short *z1, *z2, oldz2, newz2;
++static void hfc_dch_rx(struct hfc_card *hfctmp){
++ struct dch *chtmp=&hfctmp->dch;
++ u16 size;
+
+ hfctmp->ztdev->chans[2].bytes2receive=0;
+- hfctmp->ztdev->chans[2].eofrx = 0;
+-
+- /* put the received data into the DAHDI buffer
+- we'll call dahdi_receive() later when the timer fires. */
+- f1 = (char *)(hfctmp->fifos + hfc_FIFO_DRX_F1);
+- f2 = (char *)(hfctmp->fifos + hfc_FIFO_DRX_F2);
+-
+- if (*f1 == *f2) return; /* nothing received, strange eh? */
+-
+- z1 = (unsigned short *)(hfctmp->fifos + hfc_FIFO_DRX_Z1 + (*f2 * 4));
+- z2 = (unsigned short *)(hfctmp->fifos + hfc_FIFO_DRX_Z2 + (*f2 * 4));
+-
+- /* calculate length of frame, including 2 bytes CRC and 1 byte STAT */
+- count = *z1 - *z2;
+-
+- if (count < 0) {
+- count += hfc_D_FIFO_SIZE; /* ring buffer wrapped */
+- }
+- count++;
+- framelen = count;
+-
+- crcstat = (char *)(hfctmp->fifos + hfc_FIFO_DRX_ZOFF + *z1);
+-
+- if ((framelen < 4) || (*crcstat != 0x0)) {
+- /* the frame is too short for a valid HDLC frame or the CRC is borked */
+- printk(KERN_CRIT "zaphfc: empty HDLC frame or bad CRC received (framelen = %d, stat = %#x, card = %d).\n", framelen, *crcstat, hfctmp->cardno);
+- oldz2 = *z2;
+- *f2 = ((*f2 + 1) & hfc_MAX_DFRAMES) | (hfc_MAX_DFRAMES + 1); /* NEXT!!! */
+- // recalculate z2, because Z2 is a function of F2 Z2(F2) and we INCed F2!!!
+- z2 = (unsigned short *)(hfctmp->fifos + hfc_FIFO_DRX_Z2 + (*f2 * 4));
+- *z2 = (oldz2 + framelen) & hfc_ZMASK;
+- hfctmp->drecinframe = 0;
+- hfctmp->regs.int_drec--;
+- /* skip short or broken frames */
+- hfctmp->ztdev->chans[2].bytes2receive = 0;
+- return;
+- }
+-
+- count -= 1; /* strip STAT */
+- hfctmp->ztdev->chans[2].eofrx = 1;
+-
+- if (count + *z2 <= hfc_D_FIFO_SIZE) {
+- maxlen = count;
+- } else {
+- maxlen = hfc_D_FIFO_SIZE - *z2;
++ hfctmp->ztdev->chans[2].eofrx=0;
++ if(*chtmp->rx.f1.p==chtmp->rx.f2.v){
++ hfctmp->regs.int_drec=0;
++ }else{
++ size=((*(volatile u16 *)(hfctmp->fifos+hfc_FIFO_DRX_Z1+chtmp->rx.f2.v*4)-chtmp->rx.f2.z2.v+hfc_D_FIFO_SIZE)&(hfc_D_FIFO_SIZE-1))+1;
++ if(size<4){
++ printk(KERN_CRIT "zaphfc[%d]: empty HDLC frame received.\n",hfctmp->cardno);
++ }else{
++ u16 x=min(size,(u16)(hfc_D_FIFO_SIZE-chtmp->rx.f2.z2.v));
++ memcpy(hfctmp->drecbuf,hfctmp->fifos+hfc_FIFO_DRX_ZOFF+chtmp->rx.f2.z2.v,x);
++ memcpy(hfctmp->drecbuf+x,hfctmp->fifos+hfc_FIFO_DRX_ZOFF,size-x);
++ if(hfctmp->drecbuf[size-1]){
++ printk(KERN_CRIT "zaphfc[%d]: received d channel frame with bad CRC.\n",hfctmp->cardno);
++ }else{
++ hfctmp->ztdev->chans[2].bytes2receive=size-1;
++ hfctmp->ztdev->chans[2].eofrx=1;
++ }
++ }
++ chtmp->rx.f2.z2.v=(chtmp->rx.f2.z2.v+size)&(hfc_D_FIFO_SIZE-1);
++ chtmp->rx.f2.v=((chtmp->rx.f2.v+1)&hfc_MAX_DFRAMES)|(hfc_MAX_DFRAMES+1);
+ }
+-
+- /* copy first part */
+- memcpy(hfctmp->drecbuf, (char *)(hfctmp->fifos + hfc_FIFO_DRX_ZOFF + *z2), maxlen);
+- hfctmp->ztdev->chans[2].bytes2receive += maxlen;
+-
+- count -= maxlen;
+- if (count > 0) {
+- /* ring buffer wrapped, copy rest from start of d fifo */
+- memcpy(hfctmp->drecbuf + maxlen, (char *)(hfctmp->fifos + hfc_FIFO_DRX_ZOFF), count);
+- hfctmp->ztdev->chans[2].bytes2receive += count;
+- }
+-
+- /* frame read */
+- oldz2 = *z2;
+- newz2 = (oldz2 + framelen) & hfc_ZMASK;
+- *f2 = ((*f2 + 1) & hfc_MAX_DFRAMES) | (hfc_MAX_DFRAMES + 1); /* NEXT!!! */
+- /* recalculate z2, because Z2 is a function of F2 Z2(F2) and we INCed F2!!! */
+- z2 = (unsigned short *)(hfctmp->fifos + hfc_FIFO_DRX_Z2 + (*f2 * 4));
+- *z2 = newz2;
+- hfctmp->drecinframe = 0;
+- hfctmp->regs.int_drec--;
+ }
+
+-#ifndef RTAITIMING
+ DAHDI_IRQ_HANDLER(hfc_interrupt) {
+ struct hfc_card *hfctmp = dev_id;
+- unsigned long flags = 0;
+- unsigned char stat;
+-#else
+-static void hfc_service(struct hfc_card *hfctmp) {
+-#endif
++ struct hfc_card *hfctmp2;
+ struct dahdi_hfc *zthfc;
+- unsigned char s1, s2, l1state;
++ unsigned char stat, s1, s2, l1state;
++ unsigned long flags = 0;
++ unsigned long flags2 = 0;
+ int x;
+
+ if (!hfctmp) {
+-#ifndef RTAITIMING
+- return IRQ_NONE;
+-#else
+- /* rtai */
+- return;
+-#endif
++ return IRQ_NONE;
+ }
+
+ if (!hfctmp->pci_io) {
+ printk(KERN_WARNING "%s: IO-mem disabled, cannot handle interrupt\n",
+ __FUNCTION__);
+-#ifndef RTAITIMING
+ return IRQ_NONE;
+-#else
+- /* rtai */
+- return;
+-#endif
+ }
+
+- /* we assume a few things in this irq handler:
+- - the hfc-pci will only generate "timer" irqs (proc/non-proc)
+- - we need to use every 8th IRQ (to generate 1khz timing)
+- OR
+- - if we use rtai for timing the hfc-pci will not generate ANY irq,
+- instead rtai will call this "fake" irq with a 1khz realtime timer. :)
+- - rtai will directly service the card, not like it used to by triggering
+- the linux irq
+- */
+-
+-#ifndef RTAITIMING
+ spin_lock_irqsave(&hfctmp->lock, flags);
+ stat = hfc_inb(hfctmp, hfc_STATUS);
+-
+ if ((stat & hfc_STATUS_ANYINT) == 0) {
+ // maybe we are sharing the irq
+ spin_unlock_irqrestore(&hfctmp->lock,flags);
+ return IRQ_NONE;
+ }
+-#endif
+
+ s1 = hfc_inb(hfctmp, hfc_INT_S1);
+ s2 = hfc_inb(hfctmp, hfc_INT_S2);
+@@ -611,18 +457,10 @@
+ }
+ switch (l1state) {
+ case 3:
+-#ifdef RTAITIMING
+- sprintf(zthfc->span.desc, "HFC-S PCI A ISDN card %d [NT] layer 1 ACTIVATED (G%d) [realtime]", hfctmp->cardno, l1state);
+-#else
+ sprintf(zthfc->span.desc, "HFC-S PCI A ISDN card %d [NT] layer 1 ACTIVATED (G%d)", hfctmp->cardno, l1state);
+-#endif
+ break;
+ default:
+-#ifdef RTAITIMING
+- sprintf(zthfc->span.desc, "HFC-S PCI A ISDN card %d [NT] layer 1 DEACTIVATED (G%d) [realtime]", hfctmp->cardno, l1state);
+-#else
+ sprintf(zthfc->span.desc, "HFC-S PCI A ISDN card %d [NT] layer 1 DEACTIVATED (G%d)", hfctmp->cardno, l1state);
+-#endif
+ }
+ if (l1state == 2) {
+ hfc_outb(hfctmp, hfc_STATES, hfc_STATES_ACTIVATE | hfc_STATES_DO_ACTION | hfc_STATES_NT_G2_G3);
+@@ -636,18 +474,10 @@
+ }
+ switch (l1state) {
+ case 7:
+-#ifdef RTAITIMING
+- sprintf(zthfc->span.desc, "HFC-S PCI A ISDN card %d [TE] layer 1 ACTIVATED (F%d) [realtime]", hfctmp->cardno, l1state);
+-#else
+ sprintf(zthfc->span.desc, "HFC-S PCI A ISDN card %d [TE] layer 1 ACTIVATED (F%d)", hfctmp->cardno, l1state);
+-#endif
+ break;
+ default:
+-#ifdef RTAITIMING
+- sprintf(zthfc->span.desc, "HFC-S PCI A ISDN card %d [TE] layer 1 DEACTIVATED (F%d) [realtime]", hfctmp->cardno, l1state);
+-#else
+ sprintf(zthfc->span.desc, "HFC-S PCI A ISDN card %d [TE] layer 1 DEACTIVATED (F%d)", hfctmp->cardno, l1state);
+-#endif
+ }
+ if (l1state == 3) {
+ hfc_outb(hfctmp, hfc_STATES, hfc_STATES_DO_ACTION | hfc_STATES_ACTIVATE);
+@@ -657,7 +487,7 @@
+ }
+ if (s1 & hfc_INTS_DREC) {
+ // D chan RX (bit 5)
+- hfctmp->regs.int_drec++;
++ hfctmp->regs.int_drec = 1;
+ // mr. zapata there is something for you!
+ // printk(KERN_CRIT "d chan rx\n");
+ }
+@@ -678,14 +508,10 @@
+ // B1 chan TX (bit 0)
+ }
+ }
+-#ifdef RTAITIMING
+- /* fake an irq */
+- s2 |= hfc_M2_PROC_TRANS;
+-#endif
+ if (s2 != 0) {
+ if (s2 & hfc_M2_PMESEL) {
+ // kaboom irq (bit 7)
+- printk(KERN_CRIT "zaphfc: sync lost, pci performance too low. you might have some cpu throtteling enabled.\n");
++ //printk(KERN_CRIT "zaphfc: sync lost, pci performance too low. you might have some cpu throtteling enabled.\n");
+ }
+ if (s2 & hfc_M2_GCI_MON_REC) {
+ // RxR monitor channel (bit 2)
+@@ -693,32 +519,31 @@
+ if (s2 & hfc_M2_GCI_I_CHG) {
+ // GCI I-change (bit 1)
+ }
+- if (s2 & hfc_M2_PROC_TRANS) {
++ if((s2&hfc_M2_PROC_TRANS)&&(hfctmp->cardno==timer_card)){
+ // processing/non-processing transition (bit 0)
+- hfctmp->ticks++;
+-#ifndef RTAITIMING
+- if (hfctmp->ticks > 7) {
+- // welcome to DAHDI timing :)
+-#endif
+- hfctmp->ticks = 0;
+-
+- if (hfctmp->ztdev->span.flags & DAHDI_FLAG_RUNNING) {
++ hfctmp2=hfctmp;
++ hfctmp=hfc_dev_list;
++ while(hfctmp){
++ if(hfctmp->active){
++ if(hfctmp!=hfctmp2)spin_lock_irqsave(&hfctmp->lock, flags2);
++ if(hfc_bch_check(hfctmp)){
++ if (hfctmp->ztdev->span.flags & DAHDI_FLAG_RUNNING) {
+ // clear dchan buffer
++ // memset(hfctmp->drecbuf, 0x0, sizeof(hfctmp->drecbuf));
++
+ hfctmp->ztdev->chans[2].bytes2transmit = 0;
+ hfctmp->ztdev->chans[2].maxbytes2transmit = hfc_D_FIFO_SIZE;
+
+ dahdi_transmit(&(hfctmp->ztdev->span));
+
+- hfc_btrans(hfctmp,1);
+- hfc_btrans(hfctmp,2);
+- hfc_dtrans(hfctmp);
++ hfc_bch_tx(hfctmp);
++ hfc_dch_tx(hfctmp);
+ }
+
+- hfc_brec(hfctmp,1);
+- hfc_brec(hfctmp,2);
+- if (hfctmp->regs.int_drec > 0) {
++ hfc_bch_rx(hfctmp);
++ if (hfctmp->regs.int_drec) {
+ // dchan data to read
+- hfc_drec(hfctmp);
++ hfc_dch_rx(hfctmp);
+ if (hfctmp->ztdev->chans[2].bytes2receive > 0) {
+ if (debug) {
+ printk(KERN_CRIT "zaphfc: card %d RX [ ", hfctmp->cardno);
+@@ -743,17 +568,16 @@
+ if (hfctmp->ztdev->span.flags & DAHDI_FLAG_RUNNING) {
+ dahdi_receive(&(hfctmp->ztdev->span));
+ }
+-
+-#ifndef RTAITIMING
+ }
+-#endif
++ if(hfctmp!=hfctmp2)spin_unlock_irqrestore(&hfctmp->lock,flags2);
++ }
++ hfctmp=hfctmp->next;
++ }
++ hfctmp=hfctmp2;
+ }
+-
+ }
+-#ifndef RTAITIMING
+ spin_unlock_irqrestore(&hfctmp->lock,flags);
+- return IRQ_RETVAL(1);
+-#endif
++ return IRQ_RETVAL(1);
+ }
+
+
+@@ -802,22 +626,22 @@
+ }
+ alreadyrunning = span->flags & DAHDI_FLAG_RUNNING;
+
+- if (!alreadyrunning) {
+- span->chans[2]->flags &= ~DAHDI_FLAG_HDLC;
+- span->chans[2]->flags |= DAHDI_FLAG_BRIDCHAN;
+-
+- span->flags |= DAHDI_FLAG_RUNNING;
++ if (alreadyrunning) return 0;
+
+- hfctmp->ticks = -2;
+- hfctmp->clicks = 0;
+- hfctmp->regs.fifo_en = hfc_FIFOEN_D | hfc_FIFOEN_B1 | hfc_FIFOEN_B2;
+- hfc_outb(hfctmp, hfc_FIFO_EN, hfctmp->regs.fifo_en);
+- } else {
+- return 0;
+- }
++ span->chans[2]->flags &= ~DAHDI_FLAG_HDLC;
++ span->chans[2]->flags |= DAHDI_FLAG_BRIDCHAN;
++
++ span->flags |= DAHDI_FLAG_RUNNING;
++
++ hfctmp->ticks = -2;
++ hfctmp->regs.fifo_en = hfc_FIFOEN_D | hfc_FIFOEN_B1 | hfc_FIFOEN_B2;
++ hfc_outb(hfctmp, hfc_FIFO_EN, hfctmp->regs.fifo_en);
++
++ hfc_bch_init(hfctmp);
+
+ // drivers, start engines!
+ hfc_outb(hfctmp, hfc_STATES, hfc_STATES_DO_ACTION | hfc_STATES_ACTIVATE);
++ hfctmp->active=1;
+ return 0;
+ }
+
+@@ -847,17 +671,9 @@
+
+ sprintf(zthfc->span.name, "ZTHFC%d", hfc_dev_count + 1);
+ if (hfctmp->regs.nt_mode == 1) {
+-#ifdef RTAITIMING
+- sprintf(zthfc->span.desc, "HFC-S PCI A ISDN card %d [NT] [realtime]", hfc_dev_count + 1);
+-#else
+ sprintf(zthfc->span.desc, "HFC-S PCI A ISDN card %d [NT]", hfc_dev_count + 1);
+-#endif
+ } else {
+-#ifdef RTAITIMING
+- sprintf(zthfc->span.desc, "HFC-S PCI A ISDN card %d [TE] [realtime]", hfc_dev_count + 1);
+-#else
+ sprintf(zthfc->span.desc, "HFC-S PCI A ISDN card %d [TE]", hfc_dev_count + 1);
+-#endif
+ }
+
+ zthfc->span.spanconfig = zthfc_spanconfig;
+@@ -897,32 +713,6 @@
+ return 0;
+ }
+
+-#ifdef RTAITIMING
+-#define TICK_PERIOD 1000000
+-#define TICK_PERIOD2 1000000000
+-#define TASK_PRIORITY 1
+-#define STACK_SIZE 10000
+-
+-static RT_TASK rt_task;
+-static struct hfc_card *rtai_hfc_list[hfc_MAX_CARDS];
+-static unsigned char rtai_hfc_counter = 0;
+-
+-static void rtai_register_hfc(struct hfc_card *hfctmp) {
+- rtai_hfc_list[rtai_hfc_counter++] = hfctmp;
+-}
+-
+-static void rtai_loop(int t) {
+- int i=0;
+- for (;;) {
+- for (i=0; i < rtai_hfc_counter; i++) {
+- if (rtai_hfc_list[i] != NULL)
+- hfc_service(rtai_hfc_list[i]);
+- }
+- rt_task_wait_period();
+- }
+-}
+-#endif
+-
+ int hfc_findCards(int pcivendor, int pcidevice, char *vendor_name, char *card_name) {
+ struct pci_dev *tmp;
+ struct hfc_card *hfctmp = NULL;
+@@ -938,9 +728,9 @@
+ }
+ pci_set_master(tmp);
+
+- hfctmp = kmalloc(sizeof(struct hfc_card), GFP_KERNEL);
++ hfctmp = vmalloc(sizeof(struct hfc_card));
+ if (!hfctmp) {
+- printk(KERN_WARNING "zaphfc: unable to kmalloc!\n");
++ printk(KERN_WARNING "zaphfc: unable to vmalloc!\n");
+ pci_disable_device(tmp);
+ multi_hfc = NULL;
+ return -ENOMEM;
+@@ -948,6 +738,7 @@
+ memset(hfctmp, 0x0, sizeof(struct hfc_card));
+ spin_lock_init(&hfctmp->lock);
+
++ hfctmp->active=0;
+ hfctmp->pcidev = tmp;
+ hfctmp->pcibus = tmp->bus->number;
+ hfctmp->pcidevfn = tmp->devfn;
+@@ -961,49 +752,39 @@
+ hfctmp->pci_io = (char *) tmp->resource[1].start;
+ if (!hfctmp->pci_io) {
+ printk(KERN_WARNING "zaphfc: no iomem!\n");
+- kfree(hfctmp);
++ vfree(hfctmp);
+ pci_disable_device(tmp);
+ multi_hfc = NULL;
+ return -1;
+ }
+-
+- hfctmp->fifomem = kmalloc(65536, GFP_KERNEL);
+- if (!hfctmp->fifomem) {
+- printk(KERN_WARNING "zaphfc: unable to kmalloc fifomem!\n");
+- kfree(hfctmp);
++
++ hfctmp->fifos=(void *)__get_free_pages(GFP_KERNEL,log2(hfc_FIFO_MEM_SIZE_PAGES));
++ if (!hfctmp->fifos) {
++ printk(KERN_WARNING "zaphfc: unable to __get_free_pages fifomem!\n");
++ vfree(hfctmp);
+ pci_disable_device(tmp);
+ multi_hfc = NULL;
+ return -ENOMEM;
+ } else {
+- memset(hfctmp->fifomem, 0x0, 65536);
+- hfctmp->fifos = (void *)(((ulong) hfctmp->fifomem) & ~0x7FFF) + 0x8000;
+ pci_write_config_dword(hfctmp->pcidev, 0x80, (u_int) virt_to_bus(hfctmp->fifos));
+ hfctmp->pci_io = ioremap((ulong) hfctmp->pci_io, 256);
+ }
+
+-#ifdef RTAITIMING
+- /* we need no stinking irq */
+- hfctmp->irq = 0;
+-#else
+ if (request_irq(hfctmp->irq, &hfc_interrupt, IRQF_SHARED, "zaphfc", hfctmp)) {
+ printk(KERN_WARNING "zaphfc: unable to register irq\n");
+- kfree(hfctmp->fifomem);
+- kfree(hfctmp);
++ free_pages((unsigned long)hfctmp->fifos,log2(hfc_FIFO_MEM_SIZE_PAGES));
++ vfree(hfctmp);
+ iounmap((void *) hfctmp->pci_io);
+ pci_disable_device(tmp);
+ multi_hfc = NULL;
+ return -EIO;
+ }
+-#endif
+
+-#ifdef RTAITIMING
+- rtai_register_hfc(hfctmp);
+-#endif
+ printk(KERN_INFO
+- "zaphfc: %s %s configured at mem %lx fifo %lx(%#x) IRQ %d HZ %d\n",
++ "zaphfc: %s %s configured at mem %#x fifo %#x(%#x) IRQ %d HZ %d\n",
+ vendor_name, card_name,
+- (unsigned long) hfctmp->pci_io,
+- (unsigned long) hfctmp->fifos,
++ (u_int) hfctmp->pci_io,
++ (u_int) hfctmp->fifos,
+ (u_int) virt_to_bus(hfctmp->fifos),
+ hfctmp->irq, HZ);
+ pci_write_config_word(hfctmp->pcidev, PCI_COMMAND, PCI_COMMAND_MEMORY); // enable memio
+@@ -1020,11 +801,21 @@
+ hfctmp->regs.nt_mode = 0;
+ }
+
+- zthfc = kmalloc(sizeof(struct dahdi_hfc),GFP_KERNEL);
++ if(sync_slave&(1<<hfc_dev_count)){
++ printk(KERN_INFO "zaphfc: Card %d configured for slave mode\n",hfc_dev_count);
++ hfctmp->regs.mst_mode=hfc_MST_MODE_SLAVE|hfc_MST_MODE_F0_LONG_DURATION;
++ hfctmp->regs.mst_emod=hfc_MST_EMOD_SLOW_CLOCK_ADJ;
++ }else{
++ printk(KERN_INFO "zaphfc: Card %d configured for master mode\n",hfc_dev_count);
++ hfctmp->regs.mst_mode=hfc_MST_MODE_MASTER|hfc_MST_MODE_F0_LONG_DURATION;
++ hfctmp->regs.mst_emod=0;
++ }
++
++ zthfc = vmalloc(sizeof(struct dahdi_hfc));
+ if (!zthfc) {
+- printk(KERN_CRIT "zaphfc: unable to kmalloc!\n");
++ printk(KERN_CRIT "zaphfc: unable to vmalloc!\n");
+ hfc_shutdownCard(hfctmp);
+- kfree(hfctmp);
++ vfree(hfctmp);
+ multi_hfc = NULL;
+ return -ENOMEM;
+ }
+@@ -1050,7 +841,6 @@
+ memset(hfctmp->btransbuf[1], 0x0, sizeof(hfctmp->btransbuf[1]));
+ hfctmp->ztdev->chans[1].writechunk = hfctmp->btransbuf[1];
+
+-
+ hfc_registerCard(hfctmp);
+ hfc_resetCard(hfctmp);
+ tmp = pci_get_device(pcivendor, pcidevice, multi_hfc);
+@@ -1058,58 +848,42 @@
+ return 0;
+ }
+
+-
+-
+ int init_module(void) {
+ int i = 0;
+-#ifdef RTAITIMING
+- RTIME tick_period;
+- for (i=0; i < hfc_MAX_CARDS; i++) {
+- rtai_hfc_list[i] = NULL;
++ if(jitterbuffer<1){
++ printk(KERN_INFO "zaphfc: invalid jitterbuffer size specified: %d - changing to minimum of 1\n",jitterbuffer);
++ jitterbuffer=1;
++ }else if(jitterbuffer>500){
++ printk(KERN_INFO "zaphfc: invalid jitterbuffer size specified: %d - changing to maximum of 500\n",jitterbuffer);
++ jitterbuffer=500;
+ }
+- rt_set_periodic_mode();
+-#endif
+- i = 0;
++ printk(KERN_INFO "zaphfc: jitterbuffer size: %d\n",jitterbuffer);
+ while (id_list[i].vendor_id) {
+ multi_hfc = NULL;
+ hfc_findCards(id_list[i].vendor_id, id_list[i].device_id, id_list[i].vendor_name, id_list[i].card_name);
+ i++;
+ }
+-#ifdef RTAITIMING
+- for (i=0; i < hfc_MAX_CARDS; i++) {
+- if (rtai_hfc_list[i]) {
+- printk(KERN_INFO
+- "zaphfc: configured %d at mem %#x fifo %#x(%#x) for realtime servicing\n",
+- rtai_hfc_list[i]->cardno,
+- (u_int) rtai_hfc_list[i]->pci_io,
+- (u_int) rtai_hfc_list[i]->fifos,
+- (u_int) virt_to_bus(rtai_hfc_list[i]->fifos));
+-
+- }
+- }
+- rt_task_init(&rt_task, rtai_loop, 1, STACK_SIZE, TASK_PRIORITY, 0, 0);
+- tick_period = start_rt_timer(nano2count(TICK_PERIOD));
+- rt_task_make_periodic(&rt_task, rt_get_time() + tick_period, tick_period);
+-#endif
+ printk(KERN_INFO "zaphfc: %d hfc-pci card(s) in this box.\n", hfc_dev_count);
+ return 0;
+ }
+
+ void cleanup_module(void) {
+ struct hfc_card *tmpcard;
+-#ifdef RTAITIMING
+- stop_rt_timer();
+- rt_task_delete(&rt_task);
+-#endif
++
+ printk(KERN_INFO "zaphfc: stop\n");
+ // spin_lock(&registerlock);
++ tmpcard=hfc_dev_list;
++ while(tmpcard){
++ hfc_shutdownCard1(tmpcard);
++ tmpcard=tmpcard->next;
++ }
+ while (hfc_dev_list != NULL) {
+ if (hfc_dev_list == NULL) break;
+- hfc_shutdownCard(hfc_dev_list);
++ hfc_shutdownCard2(hfc_dev_list);
+ tmpcard = hfc_dev_list;
+ hfc_dev_list = hfc_dev_list->next;
+ if (tmpcard != NULL) {
+- kfree(tmpcard);
++ vfree(tmpcard);
+ tmpcard = NULL;
+ printk(KERN_INFO "zaphfc: freed one card.\n");
+ }
+@@ -1119,8 +893,11 @@
+ #endif
+
+
+-module_param(modes, int, 0600);
++module_param(modes, int, 0400);
+ module_param(debug, int, 0600);
++module_param(sync_slave, int, 0400);
++module_param(timer_card, int, 0400);
++module_param(jitterbuffer, int, 0400);
+
+ MODULE_DESCRIPTION("HFC-S PCI A Zaptel Driver");
+ MODULE_AUTHOR("Klaus-Peter Junghanns <kpj@junghanns.net>");