diff options
author | Natanael Copa <ncopa@alpinelinux.org> | 2009-10-22 11:38:05 +0000 |
---|---|---|
committer | Natanael Copa <ncopa@alpinelinux.org> | 2009-10-22 11:38:05 +0000 |
commit | f9bfcced75a5d1ed64c0c33c1f9de65bdbd5ff91 (patch) | |
tree | ba5f07aae157a08aa2328a951517ad32820899cb | |
parent | a4bf05c589fc12c3a0655447944c53fa83684a30 (diff) | |
download | aports-f9bfcced75a5d1ed64c0c33c1f9de65bdbd5ff91.tar.bz2 aports-f9bfcced75a5d1ed64c0c33c1f9de65bdbd5ff91.tar.xz |
testing/dahdi-linux-vserver: new aport
dahdi drivers for vserver kernel
-rw-r--r-- | testing/dahdi-linux-vserver/APKBUILD | 69 | ||||
-rw-r--r-- | testing/dahdi-linux-vserver/dahdi-2.6.31.patch | 44 | ||||
-rw-r--r-- | testing/dahdi-linux-vserver/dahdi-bri_dchan.patch | 161 | ||||
-rw-r--r-- | testing/dahdi-linux-vserver/dahdi-depmod.patch | 22 | ||||
-rw-r--r-- | testing/dahdi-linux-vserver/dahdi-linux-2.2.0-hfc-4s.patch | 553 | ||||
-rw-r--r-- | testing/dahdi-linux-vserver/dahdi-zaphfc.patch | 1429 | ||||
-rw-r--r-- | testing/dahdi-linux-vserver/zaphfc-dahdi-flortz.diff | 1232 |
7 files changed, 3510 insertions, 0 deletions
diff --git a/testing/dahdi-linux-vserver/APKBUILD b/testing/dahdi-linux-vserver/APKBUILD new file mode 100644 index 0000000000..1638b5f117 --- /dev/null +++ b/testing/dahdi-linux-vserver/APKBUILD @@ -0,0 +1,69 @@ +# Contributor: Timo Teras <timo.teras@iki.fi> +# Maintainer: Timo Teras <timo.teras@iki.fi> + +_flavor=vserver + +# source the kernel version +if [ -f ../linux-${_flavor}/APKBUILD ]; then + . ../linux-${_flavor}/APKBUILD +fi + +_kernelver="$pkgver-r$pkgrel" +_abi_release=${pkgver}-${_flavor} +_realname=dahdi-linux + +pkgname=${_realname}-${_flavor} +pkgver=$pkgver +_dahdiver=2.2.0.2 +pkgrel=0 +pkgdesc="Digium Asterisk Hardware Device Interface drivers $_dahdiver" +url="http://www.asterisk.org" +license="GPL" +depends="dahdi-linux linux-${_flavor}=${_kernelver}" +# we need wget and tar because make install downloads firmware and uses fancy +# options for tar and wget. +makedepends="linux-${_flavor}-dev=${_kernelver} wget tar perl" +install= +subpackages="$pkgname-dev" +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 + dahdi-linux-2.2.0-hfc-4s.patch + dahdi-2.6.31.patch + " + +build() { + cd "$srcdir/$_realname-$_dahdiver" + for i in ../*.patch ../*.diff; do + msg "Applying $i" + patch -p1 < $i || return 1; + done + + make KVERS="${_abi_release}" DYNFS="yes" MODULES_EXTRA="zaphfc" \ + || return 1 + make KVERS="${_abi_release}" DYNFS="yes" MODULES_EXTRA="zaphfc" \ + DESTDIR="$pkgdir" install + 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-$pkgver/drivers/dahdi/Module.symvers \ + "$dir"/drivers/dahdi/Module.symvers + ln -s /usr/include "$dir"/include +} + +md5sums="1f932729ad28f2f028afcf2cc5ccf7ba dahdi-linux-2.2.0.2.tar.gz +c78fb8d80f9efdffd950297c88ff9273 dahdi-depmod.patch +4b41a82ff390ac64c08092c5a3eab6a8 dahdi-bri_dchan.patch +a822c092f0548cd13f5e8d8cba053af6 dahdi-zaphfc.patch +291c5c44c86ab02443a742415461ddca zaphfc-dahdi-flortz.diff +68dfe17a49cca15ae439fd83f4ccfbc5 dahdi-linux-2.2.0-hfc-4s.patch +bd5e7457ee8f37c10ed7ec383995e4fa dahdi-2.6.31.patch" diff --git a/testing/dahdi-linux-vserver/dahdi-2.6.31.patch b/testing/dahdi-linux-vserver/dahdi-2.6.31.patch new file mode 100644 index 0000000000..35fe4383e2 --- /dev/null +++ b/testing/dahdi-linux-vserver/dahdi-2.6.31.patch @@ -0,0 +1,44 @@ +Index: drivers/dahdi/wctc4xxp/base.c +=================================================================== +--- a/drivers/dahdi/wctc4xxp/base.c (revision 6716) ++++ b/drivers/dahdi/wctc4xxp/base.c (revision 6717) +@@ -742,6 +742,17 @@ + return 0; + } + ++#ifdef HAVE_NET_DEVICE_OPS ++const struct net_device_ops wctc4xxp_netdev_ops = { ++ .ndo_set_multicast_list = &wctc4xxp_net_set_multi, ++ .ndo_open = &wctc4xxp_net_up, ++ .ndo_stop = &wctc4xxp_net_down, ++ .ndo_start_xmit = &wctc4xxp_net_hard_start_xmit, ++ .ndo_get_stats = &wctc4xxp_net_get_stats, ++ .ndo_do_ioctl = &wctc4xxp_net_ioctl, ++}; ++#endif ++ + /** + * wctc4xxp_net_register - Register a new network interface. + * @wc: transcoder card to register the interface for. +@@ -773,14 +784,21 @@ + netdev->priv = wc; + # endif + memcpy(netdev->dev_addr, our_mac, sizeof(our_mac)); ++ ++# ifdef HAVE_NET_DEVICE_OPS ++ netdev->netdev_ops = &wctc4xxp_netdev_ops; ++# else + netdev->set_multicast_list = &wctc4xxp_net_set_multi; + netdev->open = &wctc4xxp_net_up; + netdev->stop = &wctc4xxp_net_down; + netdev->hard_start_xmit = &wctc4xxp_net_hard_start_xmit; + netdev->get_stats = &wctc4xxp_net_get_stats; + netdev->do_ioctl = &wctc4xxp_net_ioctl; ++# endif ++ + netdev->promiscuity = 0; + netdev->flags |= IFF_NOARP; ++ + # if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24) + netdev->poll = &wctc4xxp_poll; + netdev->weight = 64; diff --git a/testing/dahdi-linux-vserver/dahdi-bri_dchan.patch b/testing/dahdi-linux-vserver/dahdi-bri_dchan.patch new file mode 100644 index 0000000000..d7a3fe859b --- /dev/null +++ b/testing/dahdi-linux-vserver/dahdi-bri_dchan.patch @@ -0,0 +1,161 @@ +# 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. + +--- a/include/dahdi/kernel.h ++++ b/include/dahdi/kernel.h +@@ -132,6 +132,13 @@ struct dahdi_chan { + int do_ppp_error; + struct sk_buff_head ppp_rq; + #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 */ +@@ -462,6 +469,9 @@ enum { + DAHDI_FLAGBIT_LOOPED = 18, /*!< Loopback the receive data from the channel to the transmit */ + DAHDI_FLAGBIT_MTP2 = 19, /*!< Repeats last message in buffer and also discards repeating messages sent to us */ + DAHDI_FLAGBIT_HDLC56 = 20, /*!< Sets the given channel (if in HDLC mode) to use 56K HDLC instead of 64K */ ++#if defined(CONFIG_DAHDI_BRI_DCHANS) ++ DAHDI_FLAGBIT_BRIDCHAN = 21, /*!< hardhdlc-like handling of the D channel */ ++#endif + }; + + /* map flagbits to flag masks */ +@@ -500,6 +510,7 @@ enum { + #define DAHDI_FLAG_LOOPED DAHDI_FLAG(LOOPED) + #define DAHDI_FLAG_MTP2 DAHDI_FLAG(MTP2) + #define DAHDI_FLAG_HDLC56 DAHDI_FLAG(HDLC56) ++#define DAHDI_FLAG_BRIDCHAN DAHDI_FLAG(BRIDCHAN) + + struct dahdi_span { + spinlock_t lock; +--- a/include/dahdi/dahdi_config.h ++++ b/include/dahdi/dahdi_config.h +@@ -174,4 +174,10 @@ + */ + /* #define OPTIMIZE_CHANMUTE */ + ++/* ++ * Uncomment the following for BRI D channels ++ * ++ */ ++#define CONFIG_DAHDI_BRI_DCHANS ++ + #endif +--- a/drivers/dahdi/dahdi-base.c ++++ b/drivers/dahdi/dahdi-base.c +@@ -5907,11 +5907,40 @@ static inline void __dahdi_getbuf_chunk( + *(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]) { +@@ -5968,6 +5997,17 @@ out in the later versions, and is put ba + /* 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 (ms->flags & DAHDI_FLAG_NETDEV) + netif_wake_queue(ztchan_to_dev(ms)); +@@ -6028,6 +6068,12 @@ out in the later versions, and is put ba + memset(txb, 0xFF, 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 */ + bytes = 0; +@@ -6840,6 +6886,14 @@ static inline void __putbuf_chunk(struct + 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; +@@ -6897,6 +6951,19 @@ static inline void __putbuf_chunk(struct + } + } + } ++#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/testing/dahdi-linux-vserver/dahdi-depmod.patch b/testing/dahdi-linux-vserver/dahdi-depmod.patch new file mode 100644 index 0000000000..289aad403b --- /dev/null +++ b/testing/dahdi-linux-vserver/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/testing/dahdi-linux-vserver/dahdi-linux-2.2.0-hfc-4s.patch b/testing/dahdi-linux-vserver/dahdi-linux-2.2.0-hfc-4s.patch new file mode 100644 index 0000000000..67857e2f7d --- /dev/null +++ b/testing/dahdi-linux-vserver/dahdi-linux-2.2.0-hfc-4s.patch @@ -0,0 +1,553 @@ +--- a/drivers/dahdi/wcb4xxp/base.c 2009-06-24 13:17:03.000000000 +0000 ++++ b/drivers/dahdi/wcb4xxp/base.c 2009-06-24 13:40:15.000000000 +0000 +@@ -75,7 +75,7 @@ + #define DBG_SPANFILTER ((1 << bspan->port) & spanfilter) + + static int debug = 0; +-static int spanfilter = 15; ++static int spanfilter = 255; /* Bitmap .. 1, 2, 4, 8, 16, 32, 64, 128 for ports 1-8 */ + #ifdef LOOPBACK_SUPPORTED + static int loopback = 0; + #endif +@@ -114,9 +114,21 @@ + struct devtype { + char *desc; + unsigned int flags; ++ int ports; /* Number of ports the card has */ ++ int has_ec; /* Does the card have an Echo Canceller */ ++ enum cards_ids card_type; /* Card type - Digium B410P, ... */ + }; + +-static struct devtype wcb4xxp = { "Wildcard B410P", 0 }; ++static struct devtype wcb4xxp = { "Wildcard B410P", .ports = 4, .has_ec = 1, .card_type = B410P }; ++static struct devtype hfc2s = { "HFC-2S Junghanns.NET duoBRI PCI", .ports = 2, .has_ec = 0, .card_type = DUOBRI }; ++static struct devtype hfc4s = { "HFC-4S Junghanns.NET quadBRI PCI", .ports = 4, .has_ec = 0, .card_type = QUADBRI }; ++static struct devtype hfc8s = { "HFC-4S Junghanns.NET octoBRI PCI", .ports = 8, .has_ec = 0, .card_type = OCTOBRI }; ++static struct devtype hfc2s_OV ={ "OpenVox B200P", .ports = 2, .has_ec = 0, .card_type = B200P_OV }; ++static struct devtype hfc4s_OV ={ "OpenVox B400P", .ports = 4, .has_ec = 0, .card_type = B400P_OV }; ++static struct devtype hfc8s_OV ={ "OpenVox B800P", .ports = 8, .has_ec = 0, .card_type = B800P_OV }; ++static struct devtype hfc2s_BN ={ "BeroNet BN2S0", .ports = 2, .has_ec = 0, .card_type = BN2S0 }; ++static struct devtype hfc4s_BN ={ "BeroNet BN4S0", .ports = 4, .has_ec = 0, .card_type = BN4S0 }; ++static struct devtype hfc8s_BN ={ "BeroNet BN8S0", .ports = 8, .has_ec = 0, .card_type = BN8S0 }; + + static int echocan_create(struct dahdi_chan *chan, struct dahdi_echocanparams *ecp, + struct dahdi_echocanparam *p, struct dahdi_echocan_state **ec); +@@ -403,7 +415,14 @@ + + mb(); + +- b4xxp_setreg8(b4, R_GPIO_SEL, 0xf0); /* GPIO0..7 S/T, 8..15 GPIO */ ++ if ((b4->card_type == OCTOBRI) || (b4->card_type == B800P_OV) || (b4->card_type == BN8S0)) ++ { ++ b4xxp_setreg8(b4, R_GPIO_SEL, 0x00); /* GPIO0..15 S/T - HFC-8S uses GPIO8-15 for S/T ports 5-8 */ ++ } ++ else ++ { ++ b4xxp_setreg8(b4, R_GPIO_SEL, 0xf0); /* GPIO0..7 S/T, 8..15 GPIO */ ++ } + + mb(); + +@@ -618,13 +637,16 @@ + unsigned char b; + unsigned int i, j, mask; + ++ if (! b4->has_ec) /* Avoid Echo Cancelling for non hardware echo canceller cards */ ++ return; ++ + /* Setup GPIO */ + for (i=0; i < NUM_EC; i++) { + b = ec_read(b4, i, 0x1a0); + + dev_info(b4->dev, "VPM %d/%d init: chip ver %02x\n", i, NUM_EC - 1, b); + +- for (j=0; j < 4; j++) { ++ for (j=0; j < b4->numspans; j++) { + ec_write(b4, i, 0x1a8 + j, 0x00); /* GPIO out */ + ec_write(b4, i, 0x1ac + j, 0x00); /* GPIO dir */ + ec_write(b4, i, 0x1b0 + j, 0x00); /* GPIO sel */ +@@ -1008,7 +1030,15 @@ + int fifo, hfc_chan; + unsigned long irq_flags; + +- fifo = port + 8; ++ if ((b4->card_type == B800P_OV) || (b4->card_type == OCTOBRI) || (b4->card_type == BN8S0)) ++ { ++ fifo = port + 16; /* In HFC-8S cards we can't use ports 8-11 for dchan FIFOs */ ++ } ++ else ++ { ++ fifo = port + 8; ++ } ++ + hfc_chan = (port * 4) + 2; + + /* record the host's FIFO # in the span fifo array */ +@@ -1210,7 +1240,7 @@ + int i, j; + struct b4xxp_span *s; + +- for (i=0; i < 4; i++) { ++ for (i=0; i < b4->numspans; i++) { + s = &b4->spans[i]; + + for (j=HFC_T1; j <= HFC_T3; j++) { +@@ -1413,12 +1443,21 @@ + + gpio = b4xxp_getreg8(b4, R_GPI_IN3); + +- for (i=0; i < 4; i++) { ++ for (i=0; i < b4->numspans; i++) { + s = &b4->spans[i]; + s->parent = b4; + s->port = i; + +- nt = ((gpio & (1 << (i + 4))) == 0); /* GPIO=0 = NT mode */ ++ /* The way the Digium B410P card reads the NT/TE mode ++ * jumper is the oposite of how other HFC-4S cards do: ++ * - In B410P: GPIO=0: NT ++ * - In Junghanns: GPIO=0: TE ++ */ ++ if (b4->card_type == B410P) ++ nt = ((gpio & (1 << (i + 4))) == 0); ++ else ++ nt = ((gpio & (1 << (i + 4))) != 0); ++ + s->te_mode = !nt; + + dev_info(b4->dev, "Port %d: %s mode\n", i + 1, (nt ? "NT" : "TE")); +@@ -1774,9 +1813,15 @@ + + /* + * set up the clock controller +- * we have a 24.576MHz crystal, so the PCM clock is 2x the incoming clock. ++ * B410P has a 24.576MHz crystal, so the PCM clock is 2x the incoming clock. ++ * Other cards have a 49.152Mhz crystal, so the PCM clock equals incoming clock. + */ +- b4xxp_setreg8(b4, R_BRG_PCM_CFG, 0x02); ++ ++ if (b4->card_type == B410P) ++ b4xxp_setreg8(b4, R_BRG_PCM_CFG,0x02); ++ else ++ b4xxp_setreg8(b4, R_BRG_PCM_CFG, V_PCM_CLK); ++ + flush_pci(); + + udelay(100); /* wait a bit for clock to settle */ +@@ -1807,7 +1852,7 @@ + + /* + * set up the flow controller. +- * B channel map: ++ * B channel map: (4 ports cards with Hardware Echo Cancel present & active) + * FIFO 0 connects Port 1 B0 using HFC channel 16 and PCM timeslots 0/1. + * FIFO 1 connects Port 1 B1 using HFC channel 17 and PCM timeslots 4/5. + * FIFO 2 connects Port 2 B0 using HFC channel 20 and PCM timeslots 8/9. +@@ -1822,14 +1867,35 @@ + * + * D channels are handled by FIFOs 8-11. + * FIFO 8 connects Port 1 D using HFC channel 3 +- * FIFO 9 connects Port 1 D using HFC channel 7 +- * FIFO 10 connects Port 1 D using HFC channel 11 +- * FIFO 11 connects Port 1 D using HFC channel 15 ++ * FIFO 9 connects Port 2 D using HFC channel 7 ++ * FIFO 10 connects Port 3 D using HFC channel 11 ++ * FIFO 11 connects Port 4 D using HFC channel 15 ++ * ++ * D channel FIFOs are operated in HDLC mode and interrupt on end of frame. ++ * ++ * B channel map: (8 ports cards without Hardware Echo Cancel) ++ * FIFO 0 connects Port 1 B0 using HFC channel 0 ++ * FIFO 1 connects Port 1 B1 using HFC channel 1 ++ * FIFO 2 connects Port 2 B0 using HFC channel 4 ++ * FIFO 3 connects Port 2 B1 using HFC channel 5 ++ * ......................... ++ * FIFO 14 connects Port 8 B0 using HFC channel 28 ++ * FIFO 15 connects Port 8 B1 using HFC channel 29 ++ * ++ * All B channel FIFOs have their HDLC controller in transparent mode, ++ * and only the FIFO for B0 on each port has its interrupt operational. + * ++ * D channels are handled by FIFOs 16-23. ++ * FIFO 16 connects Port 1 D using HFC channel 3 ++ * FIFO 17 connects Port 2 D using HFC channel 7 ++ * FIFO 18 connects Port 3 D using HFC channel 11 ++ * FIFO 19 connects Port 4 D using HFC channel 15 ++ * ................ ++ * FIFO 23 connects Port 8 D using HFC channel 31 + * D channel FIFOs are operated in HDLC mode and interrupt on end of frame. + */ + for (span=0; span < b4->numspans; span++) { +- if (vpmsupport) { ++ if ((vpmsupport) && (b4->has_ec)) { + hfc_assign_bchan_fifo_ec(b4, span, 0); + hfc_assign_bchan_fifo_ec(b4, span, 1); + } else { +@@ -1854,6 +1920,145 @@ + ec_write(b4, 0, 0x1a8 + 3, val); + } + ++static void b4xxp_update_leds_hfc_8s(struct b4xxp *b4) ++{ ++ unsigned long lled; ++ unsigned long leddw; ++ int i,j; ++ struct b4xxp_span *bspan; ++ lled = 0; ++ j=8; ++ ++ b4->blinktimer++; ++ for (i=0; i < 8; i++) { ++ bspan = &b4->spans[i]; ++ j = j -1 ; /* Leds are in reverse order - Led 7 => Port 0 */ ++ if (bspan->span.flags & DAHDI_FLAG_RUNNING) { ++ if (bspan->span.alarms) { ++ lled |= 1 << j; /* Led OFF in alarm state */ ++ } else if (bspan->span.mainttimer || bspan->span.maintstat) { ++ if (b4->blinktimer >= 0x7f) /* Led Blinking in maint state */ ++ { ++ lled |= 1 << j; ++ } ++ else ++ { ++ lled |= 0 << j; ++ } ++ } else { ++ ++ lled |= 0 << j; /* Led ON - No alarms */ ++ } ++ } ++ else ++ lled |= 1 << j; /* Led OFF - Not running */ ++ } ++ /* Write Leds...*/ ++ leddw = lled << 24 | lled << 16 | lled << 8 | lled; ++ b4xxp_setreg8(b4, R_BRG_PCM_CFG, 0x21); ++ iowrite16(0x4000, b4->ioaddr + 4); ++ iowrite32(leddw, b4->ioaddr); ++ b4xxp_setreg8(b4, R_BRG_PCM_CFG, 0x20); ++ ++ if (b4->blinktimer == 0xff) { ++ b4->blinktimer = -1; ++ } ++} ++ ++static void b4xxp_update_leds_hfc(struct b4xxp *b4) ++{ ++ int i, leds; ++ int led[4]; ++ struct b4xxp_span *bspan; ++ ++ b4->blinktimer++; ++ for (i=0; i < b4->numspans; i++) { ++ bspan = &b4->spans[i]; ++ ++ if (bspan->span.flags & DAHDI_FLAG_RUNNING) { ++ if (bspan->span.alarms) { ++ if (b4->blinktimer >= 0x7f) /* Red blinking -> Alarm */ ++ { ++ led[i] = 2; ++ } ++ else ++ { ++ led[i] = 0; ++ } ++ } else if (bspan->span.mainttimer || bspan->span.maintstat) { ++ if (b4->blinktimer >= 0x7f) /* Green blinking -> Maint status */ ++ { ++ led[i] = 1; ++ } ++ else ++ { ++ led[i] = 0; ++ } ++ } else { ++ /* No Alarm - Green */ ++ led[i] = 1; ++ } ++ } ++ else ++ led[i] = 0; /* OFF - Not running */ ++ } ++ ++ /* Each card manage leds in a different way. So one section per card type */ ++ ++ if (b4->card_type == B400P_OV) { ++ leds = ((led[0] > 0) << 0) | ((led[1] > 0) << 1) | ++ ((led[2] > 0) << 2) | ((led[3] > 0) << 3) | ++ ((led[0] & 1) << 4) | ((led[1] & 1) << 5) | ++ ((led[2] & 1) << 6) | ((led[3] & 1) << 7); /* Tested OK */ ++ b4xxp_setreg8(b4, R_GPIO_EN1, leds & 0x0f); ++ b4xxp_setreg8(b4, R_GPIO_OUT1, leds >> 4); ++ } ++ ++ else if (b4->card_type == QUADBRI) { ++ leds = ((led[0] > 0) << 0) | ((led[1] > 0) << 1) | ++ ((led[2] > 0) << 2) | ((led[3] > 0) << 3) | ++ ((led[0] & 1) << 4) | ((led[1] & 1) << 5) | ++ ((led[2] & 1) << 6) | ((led[3] & 1) << 7); /* UNTESTED */ ++ b4xxp_setreg8(b4, R_GPIO_EN1, leds & 0x0f); ++ b4xxp_setreg8(b4, R_GPIO_OUT1, leds >> 4); ++ } ++ ++ else if (b4->card_type == BN4S0) { ++ leds = ((led[0] > 0) << 0) | ((led[1] > 0) << 1) | ++ ((led[2] > 0) << 2) | ((led[3] > 0) << 3) | ++ ((led[0] & 1) << 4) | ((led[1] & 1) << 5) | ++ ((led[2] & 1) << 6) | ((led[3] & 1) << 7); /* UNTESTED */ ++ b4xxp_setreg8(b4, R_GPIO_EN1, leds & 0x0f); ++ b4xxp_setreg8(b4, R_GPIO_OUT1, leds >> 4); ++ } ++ ++ else if (b4->card_type == B200P_OV) { ++ leds = ((led[0] > 0) << 0) | ((led[1] > 0) << 1) | ++ ((led[0] & 1) << 4) | ((led[1] & 1) << 5); ++ b4xxp_setreg8(b4, R_GPIO_EN1, leds & 0x0f); ++ b4xxp_setreg8(b4, R_GPIO_OUT1, leds >> 4); /* Tested OK */ ++ } ++ ++ else if (b4->card_type == DUOBRI) { ++ leds = ((led[0] > 0) << 0) | ((led[1] > 0) << 1) | ++ ((led[0] & 1) << 4) | ((led[1] & 1) << 5); ++ b4xxp_setreg8(b4, R_GPIO_EN1, leds & 0x0f); ++ b4xxp_setreg8(b4, R_GPIO_OUT1, leds >> 4); /* UNTESTED */ ++ } ++ ++ else if (b4->card_type == BN2S0) { ++ leds = ((led[0] > 0) << 0) | ((led[1] > 0) << 1) | ++ ((led[0] & 1) << 4) | ((led[1] & 1) << 5); ++ b4xxp_setreg8(b4, R_GPIO_EN1, leds & 0x0f); ++ b4xxp_setreg8(b4, R_GPIO_OUT1, leds >> 4); /* UNTESTED */ ++ } ++ ++ if (b4->blinktimer == 0xff) { ++ b4->blinktimer = -1; ++ } ++ ++} ++ + static void b4xxp_set_span_led(struct b4xxp *b4, int span, unsigned char val) + { + int shift, spanmask; +@@ -1871,6 +2076,18 @@ + int i; + struct b4xxp_span *bspan; + ++ if (b4->numspans == 8) { ++ /* Use the alternative function for non-Digium HFC-8S cards */ ++ b4xxp_update_leds_hfc_8s(b4); ++ return; ++ } ++ ++ if (b4->card_type != B410P) { ++ /* Use the alternative function for non-Digium HFC-4S cards */ ++ b4xxp_update_leds_hfc(b4); ++ return; ++ } ++ + b4->blinktimer++; + for (i=0; i < b4->numspans; i++) { + bspan = &b4->spans[i]; +@@ -2174,7 +2391,7 @@ + bspan->span.close = b4xxp_close; + bspan->span.ioctl = b4xxp_ioctl; + bspan->span.hdlc_hard_xmit = b4xxp_hdlc_hard_xmit; +- if (vpmsupport) ++ if (vpmsupport && b4->has_ec) + bspan->span.echocan_create = echocan_create; + + /* HDLC stuff */ +@@ -2281,13 +2498,24 @@ + static void b4xxp_bottom_half(unsigned long data) + { + struct b4xxp *b4 = (struct b4xxp *)data; +- int i, j, k, gotrxfifo, fifo; ++ int i, j, k, gotrxfifo, fifo, fifo_low, fifo_high; + unsigned char b, b2; + + if (b4->shutdown) + return; + + gotrxfifo = 0; ++ if ( b4->numspans == 8 ) /* HFC-4S d-chan fifos 8-11 *** HFC-8S d-chan fifos 16-23 */ ++ { ++ fifo_low = 16; ++ fifo_high = 23; ++ } ++ else ++ { ++ fifo_low = 8; ++ fifo_high = 11; ++ } ++ + + for (i=0; i < 8; i++) { + b = b2 = b4->fifo_irqstatus[i]; +@@ -2296,7 +2524,7 @@ + fifo = i*4 + j; + + if (b & V_IRQ_FIFOx_TX) { +- if (fifo >=8 && fifo <= 11) { /* d-chan fifo */ ++ if (fifo >= fifo_low && fifo <= fifo_high) { /* d-chan fifos */ + /* + * WOW I don't like this. + * It's bad enough that I have to send a fake frame to get an HDLC TX FIFO interrupt, +@@ -2305,7 +2533,7 @@ + * Yuck. It works well, but yuck. + */ + do { +- k = hdlc_tx_frame(&b4->spans[fifo - 8]); ++ k = hdlc_tx_frame(&b4->spans[fifo - fifo_low]); + } while (k); + } else { + if (printk_ratelimit()) +@@ -2314,7 +2542,7 @@ + } + + if (b & V_IRQ_FIFOx_RX) { +- if (fifo >=8 && fifo <= 11) { ++ if (fifo >= fifo_low && fifo <= fifo_high) { /* dchan fifos */ + /* + * I have to loop here until hdlc_rx_frame says there are no more frames waiting. + * for whatever reason, the HFC will not generate another interrupt if there are +@@ -2322,7 +2550,7 @@ + * i.e. I get an int when F1 changes, not when F1 != F2. + */ + do { +- k = hdlc_rx_frame(&b4->spans[fifo - 8]); ++ k = hdlc_rx_frame(&b4->spans[fifo - fifo_low]); + } while (k); + } else { + if (printk_ratelimit()) +@@ -2404,8 +2632,8 @@ + sprintf(sBuf, "Card %d, PCI identifier %s, IRQ %d\n", b4->cardno + 1, b4->dev->bus_id, b4->irq); + + strcat(sBuf,"Tx:\n"); +- for (j=0; j<8; j++) { +- for (i=0; i<12; i++) { ++ for (j=0; j<(b4->numspans * 2) ; j++) { /* B Channels */ ++ for (i=0; i<(b4->numspans * 3) ; i++) { /* All Channels */ + chan = b4->spans[i/3].chans[i%3]; + sprintf(str, "%02x ", chan->writechunk[j]); + strcat(sBuf, str); +@@ -2415,8 +2643,8 @@ + } + + strcat(sBuf, "\nRx:\n"); +- for (j=0; j < 8; j++) { +- for (i=0; i < 12; i++) { ++ for (j=0; j < (b4->numspans * 2); j++) { /* B Channels */ ++ for (i=0; i < (b4->numspans * 3); i++) { /* All Channels */ + chan = b4->spans[i / 3].chans[i % 3]; + sprintf(str, "%02x%c", chan->readchunk[j], (i == 11) ? '\n' : ' '); + strcat(sBuf, str); +@@ -2424,7 +2652,7 @@ + } + + strcat(sBuf, "\nPort states:\n"); +- for (i=0; i < 4; i++) { ++ for (i=0; i < b4->numspans; i++) { + int state; + char *x; + struct b4xxp_span *s = &b4->spans[i]; +@@ -2519,7 +2747,8 @@ + /* card found, enabled and main struct allocated. Fill it out. */ + b4->magic = WCB4XXP_MAGIC; + b4->variety = dt->desc; +- ++ b4->has_ec = dt->has_ec; ++ b4->card_type = dt->card_type; + b4->pdev = pdev; + b4->dev = &pdev->dev; + pci_set_drvdata(pdev, b4); +@@ -2533,7 +2762,7 @@ + spin_lock_init(&b4->fifolock); + + x = b4xxp_getreg8(b4, R_CHIP_ID); +- if (x != 0xc0) { /* wrong chip? */ ++ if ((x != 0xc0) && ( x != 0x80)) { /* wrong chip? */ + dev_err(&pdev->dev, "Unknown/unsupported controller detected (R_CHIP_ID = 0x%02x)\n", x); + goto err_out_free_mem; + } +@@ -2548,7 +2777,7 @@ + */ + + /* TODO: determine whether this is a 2, 4 or 8 port card */ +- b4->numspans = 4; ++ b4->numspans = dt->ports; + b4->syncspan = -1; /* sync span is unknown */ + if (b4->numspans > MAX_SPANS_PER_CARD) { + dev_err(b4->dev, "Driver does not know how to handle a %d span card!\n", b4->numspans); +@@ -2696,7 +2925,17 @@ + static struct pci_device_id b4xx_ids[] __devinitdata = + { + { 0xd161, 0xb410, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long)&wcb4xxp }, +- { 0, } ++ { 0x1397, 0x16b8, 0x1397, 0xe552, 0, 0, (unsigned long)&hfc8s }, ++ { 0x1397, 0x08b4, 0x1397, 0xb520, 0, 0, (unsigned long)&hfc4s }, ++ { 0x1397, 0x08b4, 0x1397, 0xb556, 0, 0, (unsigned long)&hfc2s }, ++ { 0x1397, 0x08b4, 0x1397, 0xe884, 0, 0, (unsigned long)&hfc2s_OV }, ++ { 0x1397, 0x08b4, 0x1397, 0xe888, 0, 0, (unsigned long)&hfc4s_OV }, ++ { 0x1397, 0x16b8, 0x1397, 0xe998, 0, 0, (unsigned long)&hfc8s_OV }, ++ { 0x1397, 0x08b4, 0x1397, 0xb566, 0, 0, (unsigned long)&hfc2s_BN }, ++ { 0x1397, 0x08b4, 0x1397, 0xb560, 0, 0, (unsigned long)&hfc4s_BN }, ++ { 0x1397, 0x16b8, 0x1397, 0xb562, 0, 0, (unsigned long)&hfc8s_BN }, ++ {0, } ++ + }; + + static struct pci_driver b4xx_driver = { +@@ -2756,7 +2995,7 @@ + MODULE_PARM_DESC(timer_3_ms, "TE: msec to wait for link activation, NT: unused."); + + MODULE_AUTHOR("Digium Incorporated <support@digium.com>"); +-MODULE_DESCRIPTION("B410P quad-port BRI module driver."); ++MODULE_DESCRIPTION("B410P & Similars multi-port BRI module driver."); + MODULE_LICENSE("GPL"); + + MODULE_DEVICE_TABLE(pci, b4xx_ids); +--- a/drivers/dahdi/wcb4xxp/wcb4xxp.h 2009-06-24 13:17:03.000000000 +0000 ++++ b/drivers/dahdi/wcb4xxp/wcb4xxp.h 2009-06-24 13:18:07.000000000 +0000 +@@ -378,7 +378,7 @@ + #define HFC_T3 2 + + #define WCB4XXP_MAGIC 0xb410c0de +-#define MAX_SPANS_PER_CARD 4 ++#define MAX_SPANS_PER_CARD 8 + + #define WCB4XXP_CHANNELS_PER_SPAN 3 /* 2 B-channels and 1 D-Channel for each BRI span */ + #define WCB4XXP_HDLC_BUF_LEN 32 /* arbitrary, just the max # of byts we will send to DAHDI per call */ +@@ -415,6 +415,19 @@ + struct dahdi_chan _chans[WCB4XXP_CHANNELS_PER_SPAN]; /* Backing memory */ + }; + ++enum cards_ids { /* Cards ==> Brand & Model */ ++ B410P = 0, /* Digium B410P */ ++ B200P_OV, /* OpenVox B200P */ ++ B400P_OV, /* OpenVox B400P */ ++ B800P_OV, /* OpenVox B800P */ ++ DUOBRI, /* HFC-2S Junghanns.NET duoBRI PCI */ ++ QUADBRI, /* HFC-4S Junghanns.NET quadBRI PCI */ ++ OCTOBRI, /* HFC-8S Junghanns.NET octoBRI PCI */ ++ BN2S0, /* BeroNet BN2S0 */ ++ BN4S0, /* Beronet BN4S0 */ ++ BN8S0 /* BeroNet BN8S0 */ ++ }; ++ + /* This structure exists one per card */ + struct b4xxp { + unsigned magic; /* magic value to make sure we're looking at our struct */ +@@ -449,10 +462,12 @@ + int globalconfig; /* Whether global setup has been done */ + int syncspan; /* span that HFC uses for sync on this card */ + int running; /* interrupts are enabled */ +- ++ + struct b4xxp_span spans[MAX_SPANS_PER_CARD]; /* Individual spans */ + int order; /* Order */ + int flags; /* Device flags */ ++ int has_ec; /* Has ECHO Cancel */ ++ enum cards_ids card_type; /* Card Identifier (using ids_cards enum)*/ + int master; /* Are we master */ + int ledreg; /* copy of the LED Register */ + unsigned int gpio; diff --git a/testing/dahdi-linux-vserver/dahdi-zaphfc.patch b/testing/dahdi-linux-vserver/dahdi-zaphfc.patch new file mode 100644 index 0000000000..b711c07ff9 --- /dev/null +++ b/testing/dahdi-linux-vserver/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 spinlock_t registerlock = SPIN_LOCK_UNLOCKED; ++ ++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(®isterlock); ++ if (hfccard != NULL) { ++ hfccard->cardno = hfc_dev_count++; ++ hfccard->next = hfc_dev_list; ++ hfc_dev_list = hfccard; ++ } ++ spin_unlock(®isterlock); ++} ++ ++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, DAHDI_IRQ_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(®isterlock); ++ 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(®isterlock); ++} ++#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/testing/dahdi-linux-vserver/zaphfc-dahdi-flortz.diff b/testing/dahdi-linux-vserver/zaphfc-dahdi-flortz.diff new file mode 100644 index 0000000000..719accdc69 --- /dev/null +++ b/testing/dahdi-linux-vserver/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 spinlock_t registerlock = SPIN_LOCK_UNLOCKED; + +-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(®isterlock); + } + +-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, DAHDI_IRQ_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(®isterlock); ++ 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>"); |