Go to:
Gentoo Home
Documentation
Forums
Lists
Bugs
Planet
Store
Wiki
Get Gentoo!
Gentoo's Bugzilla – Attachment 196465 Details for
Bug 275635
dahdi 2.2.0 released - version bump request
Home
|
New
–
[Ex]
|
Browse
|
Search
|
Privacy Policy
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
dahdi-2.2.0_zaphfc.patch
dahdi-2.2.0_zaphfc.patch (text/plain), 424.70 KB, created by
Norbert Marx
on 2009-07-03 01:33:30 UTC
(
hide
)
Description:
dahdi-2.2.0_zaphfc.patch
Filename:
MIME Type:
Creator:
Norbert Marx
Created:
2009-07-03 01:33:30 UTC
Size:
424.70 KB
patch
obsolete
>diff -Naur dahdi-linux-2.2.0/.version dahdi-linux-2.2.0_zaphfc/.version >--- dahdi-linux-2.2.0/.version 2009-06-23 18:34:11.000000000 +0200 >+++ dahdi-linux-2.2.0_zaphfc/.version 1970-01-01 01:00:00.000000000 +0100 >@@ -1 +0,0 @@ >-2.2.0 >diff -Naur dahdi-linux-2.2.0/Makefile dahdi-linux-2.2.0_zaphfc/Makefile >--- dahdi-linux-2.2.0/Makefile 2009-07-03 02:32:33.112129593 +0200 >+++ dahdi-linux-2.2.0_zaphfc/Makefile 2009-05-12 23:57:44.000000000 +0200 >@@ -197,7 +197,7 @@ > rm -rf /lib/modules/$(KVERS)/dahdi; \ > echo "done."; \ > fi >-# [ `id -u` = 0 ] && /sbin/depmod -a $(KVERS) || : >+ [ `id -u` = 0 ] && /sbin/depmod -a $(KVERS) || : > endif > > update: >diff -Naur dahdi-linux-2.2.0/drivers/dahdi/Kbuild dahdi-linux-2.2.0_zaphfc/drivers/dahdi/Kbuild >--- dahdi-linux-2.2.0/drivers/dahdi/Kbuild 2009-06-13 00:30:02.000000000 +0200 >+++ dahdi-linux-2.2.0_zaphfc/drivers/dahdi/Kbuild 2009-07-03 02:16:06.241129929 +0200 >@@ -16,6 +16,8 @@ > obj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_WCT1XXP) += wct1xxp.o > obj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_WCTE11XP) += wcte11xp.o > >+obj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_ZAPHFC) += zaphfc/ >+ > obj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_WCFXO) += wcfxo.o > obj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_TOR2) += tor2.o > obj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_PCIRADIO) += pciradio.o >diff -Naur dahdi-linux-2.2.0/drivers/dahdi/dahdi-base.c dahdi-linux-2.2.0_zaphfc/drivers/dahdi/dahdi-base.c >--- dahdi-linux-2.2.0/drivers/dahdi/dahdi-base.c 2009-06-04 23:14:53.000000000 +0200 >+++ dahdi-linux-2.2.0_zaphfc/drivers/dahdi/dahdi-base.c 2009-07-03 02:15:47.964129301 +0200 >@@ -6026,11 +6026,40 @@ > *(txb++) = fasthdlc_tx_run_nocheck(&ms->txhdlc); > } > bytes -= left; >+#ifdef CONFIG_DAHDI_BRI_DCHANS >+ } else if (test_bit(DAHDI_FLAGBIT_BRIDCHAN, &ms->flags)) { >+ /* >+ * Let's get this right, we want to transmit complete frames only. >+ * The card driver will do the dirty HDLC work for us. >+ * txb (transmit buffer) is supposed to be big enough to store one frame >+ * we will make this as big as the D fifo (1KB or 2KB) >+ */ >+ >+ /* there are 'left' bytes in the user buffer left to transmit */ >+ left = ms->writen[ms->outwritebuf] - ms->writeidx[ms->outwritebuf] - 2; >+ if (left > ms->maxbytes2transmit) { >+ memcpy(txb, buf + ms->writeidx[ms->outwritebuf], ms->maxbytes2transmit); >+ ms->writeidx[ms->outwritebuf] += ms->maxbytes2transmit; >+ txb += ms->maxbytes2transmit; >+ ms->bytes2transmit = ms->maxbytes2transmit; >+ ms->eoftx = 0; >+ } else { >+ memcpy(txb, buf + ms->writeidx[ms->outwritebuf], left); >+ ms->writeidx[ms->outwritebuf] += left + 2; >+ txb += left + 2; >+ ms->bytes2transmit = left; >+ ms->eoftx = 1; >+ } >+ bytes = 0; >+#endif > } else { > memcpy(txb, buf + ms->writeidx[ms->outwritebuf], left); > ms->writeidx[ms->outwritebuf]+=left; > txb += left; > bytes -= left; >+#if defined(CONFIG_DAHDI_BRI_DCHANS) >+ ms->bytes2transmit=DAHDI_CHUNKSIZE; >+#endif > } > /* Check buffer status */ > if (ms->writeidx[ms->outwritebuf] >= ms->writen[ms->outwritebuf]) { >@@ -6089,6 +6118,17 @@ > /* Transmit a flag if this is an HDLC channel */ > if (ms->flags & DAHDI_FLAG_HDLC) > fasthdlc_tx_frame_nocheck(&ms->txhdlc); >+#if defined(CONFIG_DAHDI_BRI_DCHANS) >+ if (test_bit(DAHDI_FLAGBIT_BRIDCHAN, &ms->flags)) { >+ // if (ms->bytes2transmit > 0) { >+ // txb += 2; >+ // ms->bytes2transmit -= 2; >+ bytes=0; >+ ms->eoftx = 1; >+// printk(KERN_CRIT "zaptel EOF(%d) bytes2transmit %d\n",ms->eoftx,ms->bytes2transmit); >+ // } >+ } >+#endif > #ifdef CONFIG_DAHDI_NET > if (ms->flags & DAHDI_FLAG_NETDEV) > netif_wake_queue(ztchan_to_dev(ms)); >@@ -6149,6 +6189,12 @@ > 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; >@@ -7005,6 +7051,14 @@ > int res; > int left, x; > >+#if defined(CONFIG_DAHDI_BRI_DCHANS) >+ if (test_bit(DAHDI_FLAGBIT_BRIDCHAN, &ms->flags)) { >+ bytes = ms->bytes2receive; >+ if (bytes < 1) return; >+// printk(KERN_CRIT "bytes2receive %d\n",ms->bytes2receive); >+ } >+#endif >+ > while(bytes) { > #if defined(CONFIG_DAHDI_NET) || defined(CONFIG_DAHDI_PPP) > skb = NULL; >@@ -7062,6 +7116,19 @@ > } > } > } >+#ifdef CONFIG_DAHDI_BRI_DCHANS >+ } else if (test_bit(DAHDI_FLAGBIT_BRIDCHAN, &ms->flags)) { >+ memcpy(buf + ms->readidx[ms->inreadbuf], rxb, left); >+ rxb += left; >+ ms->readidx[ms->inreadbuf] += left; >+ bytes -= left; >+ if (ms->eofrx == 1) { >+ eof=1; >+ } >+// printk(KERN_CRIT "receiving %d bytes\n",ms->bytes2receive); >+ ms->bytes2receive = 0; >+ ms->eofrx = 0; >+#endif > } else { > /* Not HDLC */ > memcpy(buf + ms->readidx[ms->inreadbuf], rxb, left); >diff -Naur dahdi-linux-2.2.0/drivers/dahdi/dahdi-base.c.orig dahdi-linux-2.2.0_zaphfc/drivers/dahdi/dahdi-base.c.orig >--- dahdi-linux-2.2.0/drivers/dahdi/dahdi-base.c.orig 1970-01-01 01:00:00.000000000 +0100 >+++ dahdi-linux-2.2.0_zaphfc/drivers/dahdi/dahdi-base.c.orig 2009-06-04 23:14:53.000000000 +0200 >@@ -0,0 +1,8074 @@ >+/* >+ * DAHDI Telephony Interface Driver >+ * >+ * Written by Mark Spencer <markster@digium.com> >+ * Based on previous works, designs, and architectures conceived and >+ * written by Jim Dixon <jim@lambdatel.com>. >+ * >+ * Special thanks to Steve Underwood <steve@coppice.org> >+ * for substantial contributions to signal processing functions >+ * in DAHDI and the Zapata library. >+ * >+ * Yury Bokhoncovich <byg@cf1.ru> >+ * Adaptation for 2.4.20+ kernels (HDLC API was changed) >+ * The work has been performed as a part of our move >+ * from Cisco 3620 to IBM x305 here in F1 Group >+ * >+ * Copyright (C) 2001 Jim Dixon / Zapata Telephony. >+ * Copyright (C) 2001 - 2008 Digium, Inc. >+ * >+ * All rights reserved. >+ * >+ */ >+ >+/* >+ * See http://www.asterisk.org for more information about >+ * the Asterisk project. Please do not directly contact >+ * any of the maintainers of this project for assistance; >+ * the project provides a web site, mailing lists and IRC >+ * channels for your use. >+ * >+ * This program is free software, distributed under the terms of >+ * the GNU General Public License Version 2 as published by the >+ * Free Software Foundation. See the LICENSE file included with >+ * this program for more details. >+ */ >+ >+ >+#include <linux/kernel.h> >+#include <linux/errno.h> >+#include <linux/module.h> >+#include <linux/proc_fs.h> >+#include <linux/pci.h> >+#include <linux/init.h> >+#include <linux/version.h> >+#include <linux/ctype.h> >+#include <linux/kmod.h> >+#include <linux/moduleparam.h> >+#include <linux/list.h> >+ >+#include <linux/ppp_defs.h> >+ >+#include <asm/atomic.h> >+ >+#define module_printk(level, fmt, args...) printk(level "%s: " fmt, THIS_MODULE->name, ## args) >+ >+/* #define BUF_MUNGE */ >+ >+#include <dahdi/version.h> >+/* Grab fasthdlc with tables */ >+#define FAST_HDLC_NEED_TABLES >+#include <dahdi/kernel.h> >+#include "ecdis.h" >+ >+#ifndef CONFIG_OLD_HDLC_API >+#define NEW_HDLC_INTERFACE >+#endif >+ >+#ifdef CONFIG_DAHDI_PPP >+#include <linux/netdevice.h> >+#include <linux/if.h> >+#include <linux/if_ppp.h> >+#endif >+ >+#ifdef CONFIG_DAHDI_NET >+#include <linux/netdevice.h> >+#endif >+ >+#include "hpec/hpec_user.h" >+ >+/* Get helper arithmetic */ >+#include "arith.h" >+#if defined(CONFIG_DAHDI_MMX) || defined(ECHO_CAN_FP) >+#include <asm/i387.h> >+#endif >+ >+#define hdlc_to_ztchan(h) (((struct dahdi_hdlc *)(h))->chan) >+#define dev_to_ztchan(h) (((struct dahdi_hdlc *)(dev_to_hdlc(h)->priv))->chan) >+#define ztchan_to_dev(h) ((h)->hdlcnetdev->netdev) >+ >+/* macro-oni for determining a unit (channel) number */ >+#define UNIT(file) MINOR(file->f_dentry->d_inode->i_rdev) >+ >+/* names of tx level settings */ >+static char *dahdi_txlevelnames[] = { >+"0 db (CSU)/0-133 feet (DSX-1)", >+"133-266 feet (DSX-1)", >+"266-399 feet (DSX-1)", >+"399-533 feet (DSX-1)", >+"533-655 feet (DSX-1)", >+"-7.5db (CSU)", >+"-15db (CSU)", >+"-22.5db (CSU)" >+} ; >+ >+EXPORT_SYMBOL(dahdi_transcode_fops); >+EXPORT_SYMBOL(dahdi_init_tone_state); >+EXPORT_SYMBOL(dahdi_mf_tone); >+EXPORT_SYMBOL(dahdi_register); >+EXPORT_SYMBOL(dahdi_unregister); >+EXPORT_SYMBOL(__dahdi_mulaw); >+EXPORT_SYMBOL(__dahdi_alaw); >+#ifdef CONFIG_CALC_XLAW >+EXPORT_SYMBOL(__dahdi_lineartoulaw); >+EXPORT_SYMBOL(__dahdi_lineartoalaw); >+#else >+EXPORT_SYMBOL(__dahdi_lin2mu); >+EXPORT_SYMBOL(__dahdi_lin2a); >+#endif >+EXPORT_SYMBOL(dahdi_lboname); >+EXPORT_SYMBOL(dahdi_transmit); >+EXPORT_SYMBOL(dahdi_receive); >+EXPORT_SYMBOL(dahdi_rbsbits); >+EXPORT_SYMBOL(dahdi_qevent_nolock); >+EXPORT_SYMBOL(dahdi_qevent_lock); >+EXPORT_SYMBOL(dahdi_hooksig); >+EXPORT_SYMBOL(dahdi_alarm_notify); >+EXPORT_SYMBOL(dahdi_set_dynamic_ioctl); >+EXPORT_SYMBOL(dahdi_ec_chunk); >+EXPORT_SYMBOL(dahdi_ec_span); >+EXPORT_SYMBOL(dahdi_hdlc_abort); >+EXPORT_SYMBOL(dahdi_hdlc_finish); >+EXPORT_SYMBOL(dahdi_hdlc_getbuf); >+EXPORT_SYMBOL(dahdi_hdlc_putbuf); >+EXPORT_SYMBOL(dahdi_alarm_channel); >+EXPORT_SYMBOL(dahdi_register_chardev); >+EXPORT_SYMBOL(dahdi_unregister_chardev); >+ >+EXPORT_SYMBOL(dahdi_register_echocan_factory); >+EXPORT_SYMBOL(dahdi_unregister_echocan_factory); >+ >+EXPORT_SYMBOL(dahdi_set_hpec_ioctl); >+ >+#ifdef CONFIG_PROC_FS >+static struct proc_dir_entry *proc_entries[DAHDI_MAX_SPANS]; >+#endif >+ >+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27) >+#define CLASS_DEV_CREATE(class, devt, device, name) \ >+ device_create(class, device, devt, NULL, "%s", name) >+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26) >+#define CLASS_DEV_CREATE(class, devt, device, name) \ >+ device_create(class, device, devt, name) >+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,15) >+#define CLASS_DEV_CREATE(class, devt, device, name) \ >+ class_device_create(class, NULL, devt, device, name) >+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,13) >+#define CLASS_DEV_CREATE(class, devt, device, name) \ >+ class_device_create(class, devt, device, name) >+#else >+#define CLASS_DEV_CREATE(class, devt, device, name) \ >+ class_simple_device_add(class, devt, device, name) >+#endif >+ >+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26) >+#define CLASS_DEV_DESTROY(class, devt) \ >+ device_destroy(class, devt) >+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,13) >+#define CLASS_DEV_DESTROY(class, devt) \ >+ class_device_destroy(class, devt) >+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,9) >+#define CLASS_DEV_DESTROY(class, devt) \ >+ class_simple_device_remove(devt) >+#else >+#define CLASS_DEV_DESTROY(class, devt) \ >+ class_simple_device_remove(class, devt) >+#endif >+ >+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,13) >+static struct class *dahdi_class = NULL; >+#else >+static struct class_simple *dahdi_class = NULL; >+#define class_create class_simple_create >+#define class_destroy class_simple_destroy >+#endif >+ >+/* >+ * See issue http://bugs.digium.com/view.php?id=13504 for more information. >+ * on why reference counting on the echo canceller modules is disabled >+ * currently. >+ */ >+#undef USE_ECHOCAN_REFCOUNT >+ >+static int deftaps = 64; >+ >+static int debug; >+ >+/*! >+ * \brief states for transmit signalling >+ */ >+enum dahdi_txstate { >+ DAHDI_TXSTATE_ONHOOK, >+ DAHDI_TXSTATE_OFFHOOK, >+ DAHDI_TXSTATE_START, >+ DAHDI_TXSTATE_PREWINK, >+ DAHDI_TXSTATE_WINK, >+ DAHDI_TXSTATE_PREFLASH, >+ DAHDI_TXSTATE_FLASH, >+ DAHDI_TXSTATE_DEBOUNCE, >+ DAHDI_TXSTATE_AFTERSTART, >+ DAHDI_TXSTATE_RINGON, >+ DAHDI_TXSTATE_RINGOFF, >+ DAHDI_TXSTATE_KEWL, >+ DAHDI_TXSTATE_AFTERKEWL, >+ DAHDI_TXSTATE_PULSEBREAK, >+ DAHDI_TXSTATE_PULSEMAKE, >+ DAHDI_TXSTATE_PULSEAFTER, >+}; >+ >+typedef short sumtype[DAHDI_MAX_CHUNKSIZE]; >+ >+static sumtype sums[(DAHDI_MAX_CONF + 1) * 3]; >+ >+/* Translate conference aliases into actual conferences >+ and vice-versa */ >+static short confalias[DAHDI_MAX_CONF + 1]; >+static short confrev[DAHDI_MAX_CONF + 1]; >+ >+static sumtype *conf_sums_next; >+static sumtype *conf_sums; >+static sumtype *conf_sums_prev; >+ >+static struct dahdi_span *master; >+static struct file_operations dahdi_fops; >+struct file_operations *dahdi_transcode_fops = NULL; >+ >+static struct { >+ int src; /* source conf number */ >+ int dst; /* dst conf number */ >+} conf_links[DAHDI_MAX_CONF + 1]; >+ >+ >+/* There are three sets of conference sum accumulators. One for the current >+sample chunk (conf_sums), one for the next sample chunk (conf_sums_next), and >+one for the previous sample chunk (conf_sums_prev). The following routine >+(rotate_sums) "rotates" the pointers to these accululator arrays as part >+of the events of sample chink processing as follows: >+ >+The following sequence is designed to be looked at from the reference point >+of the receive routine of the master span. >+ >+1. All (real span) receive chunks are processed (with putbuf). The last one >+to be processed is the master span. The data received is loaded into the >+accumulators for the next chunk (conf_sums_next), to be in alignment with >+current data after rotate_sums() is called (which immediately follows). >+Keep in mind that putbuf is *also* a transmit routine for the pseudo parts >+of channels that are in the REALANDPSEUDO conference mode. These channels >+are processed from data in the current sample chunk (conf_sums), being >+that this is a "transmit" function (for the pseudo part). >+ >+2. rotate_sums() is called. >+ >+3. All pseudo channel receive chunks are processed. This data is loaded into >+the current sample chunk accumulators (conf_sums). >+ >+4. All conference links are processed (being that all receive data for this >+chunk has already been processed by now). >+ >+5. All pseudo channel transmit chunks are processed. This data is loaded from >+the current sample chunk accumulators (conf_sums). >+ >+6. All (real span) transmit chunks are processed (with getbuf). This data is >+loaded from the current sample chunk accumulators (conf_sums). Keep in mind >+that getbuf is *also* a receive routine for the pseudo part of channels that >+are in the REALANDPSEUDO conference mode. These samples are loaded into >+the next sample chunk accumulators (conf_sums_next) to be processed as part >+of the next sample chunk's data (next time around the world). >+ >+*/ >+ >+enum dahdi_digit_mode { >+ DIGIT_MODE_DTMF, >+ DIGIT_MODE_MFR1, >+ DIGIT_MODE_PULSE, >+ DIGIT_MODE_MFR2_FWD, >+ DIGIT_MODE_MFR2_REV, >+}; >+ >+#include "digits.h" >+ >+static struct dahdi_dialparams global_dialparams = { >+ .dtmf_tonelen = DEFAULT_DTMF_LENGTH, >+ .mfv1_tonelen = DEFAULT_MFR1_LENGTH, >+ .mfr2_tonelen = DEFAULT_MFR2_LENGTH, >+}; >+ >+static int dahdi_chan_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long data, int unit); >+ >+#if defined(CONFIG_DAHDI_MMX) || defined(ECHO_CAN_FP) >+#define dahdi_kernel_fpu_begin kernel_fpu_begin >+#endif >+ >+struct dahdi_timer { >+ int ms; /* Countdown */ >+ int pos; /* Position */ >+ int ping; /* Whether we've been ping'd */ >+ int tripped; /* Whether we're tripped */ >+ struct list_head list; >+ wait_queue_head_t sel; >+}; >+ >+static LIST_HEAD(zaptimers); >+ >+#ifdef DEFINE_SPINLOCK >+static DEFINE_SPINLOCK(zaptimerlock); >+static DEFINE_SPINLOCK(bigzaplock); >+#else >+static spinlock_t zaptimerlock = SPIN_LOCK_UNLOCKED; >+static spinlock_t bigzaplock = SPIN_LOCK_UNLOCKED; >+#endif >+ >+struct dahdi_zone { >+ atomic_t refcount; >+ char name[40]; /* Informational, only */ >+ int ringcadence[DAHDI_MAX_CADENCE]; >+ struct dahdi_tone *tones[DAHDI_TONE_MAX]; >+ /* Each of these is a circular list >+ of dahdi_tones to generate what we >+ want. Use NULL if the tone is >+ unavailable */ >+ struct dahdi_tone dtmf[16]; /* DTMF tones for this zone, with desired length */ >+ struct dahdi_tone dtmf_continuous[16]; /* DTMF tones for this zone, continuous play */ >+ struct dahdi_tone mfr1[15]; /* MFR1 tones for this zone, with desired length */ >+ struct dahdi_tone mfr2_fwd[15]; /* MFR2 FWD tones for this zone, with desired length */ >+ struct dahdi_tone mfr2_rev[15]; /* MFR2 REV tones for this zone, with desired length */ >+ struct dahdi_tone mfr2_fwd_continuous[16]; /* MFR2 FWD tones for this zone, continuous play */ >+ struct dahdi_tone mfr2_rev_continuous[16]; /* MFR2 REV tones for this zone, continuous play */ >+}; >+ >+static struct dahdi_span *spans[DAHDI_MAX_SPANS]; >+static struct dahdi_chan *chans[DAHDI_MAX_CHANNELS]; >+ >+static int maxspans = 0; >+static int maxchans = 0; >+static int maxconfs = 0; >+static int maxlinks = 0; >+ >+static int default_zone = -1; >+ >+short __dahdi_mulaw[256]; >+short __dahdi_alaw[256]; >+ >+#ifndef CONFIG_CALC_XLAW >+u_char __dahdi_lin2mu[16384]; >+ >+u_char __dahdi_lin2a[16384]; >+#endif >+ >+static u_char defgain[256]; >+ >+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 10) >+#define __RW_LOCK_UNLOCKED() RW_LOCK_UNLOCKED >+#endif >+ >+#ifdef DEFINE_RWLOCK >+static DEFINE_RWLOCK(zone_lock); >+static DEFINE_RWLOCK(chan_lock); >+#else >+static rwlock_t zone_lock = RW_LOCK_UNLOCKED; >+static rwlock_t chan_lock = RW_LOCK_UNLOCKED; >+#endif >+ >+static struct dahdi_zone *tone_zones[DAHDI_TONE_ZONE_MAX]; >+ >+#define NUM_SIGS 10 >+ >+#ifdef DEFINE_RWLOCK >+static DEFINE_RWLOCK(ecfactory_list_lock); >+#else >+static rwlock_t ecfactory_list_lock = __RW_LOCK_UNLOCKED(); >+#endif >+ >+static LIST_HEAD(ecfactory_list); >+ >+struct ecfactory { >+ const struct dahdi_echocan_factory *ec; >+ struct module *owner; >+ struct list_head list; >+}; >+ >+int dahdi_register_echocan_factory(const struct dahdi_echocan_factory *ec) >+{ >+ struct ecfactory *cur; >+ >+ write_lock(&ecfactory_list_lock); >+ >+ /* make sure it isn't already registered */ >+ list_for_each_entry(cur, &ecfactory_list, list) { >+ if (cur->ec == ec) { >+ write_unlock(&ecfactory_list_lock); >+ return -EPERM; >+ } >+ } >+ >+ if (!(cur = kzalloc(sizeof(*cur), GFP_KERNEL))) { >+ write_unlock(&ecfactory_list_lock); >+ return -ENOMEM; >+ } >+ >+ cur->ec = ec; >+ INIT_LIST_HEAD(&cur->list); >+ >+ list_add_tail(&cur->list, &ecfactory_list); >+ >+ write_unlock(&ecfactory_list_lock); >+ >+ return 0; >+} >+ >+void dahdi_unregister_echocan_factory(const struct dahdi_echocan_factory *ec) >+{ >+ struct ecfactory *cur, *next; >+ >+ write_lock(&ecfactory_list_lock); >+ >+ list_for_each_entry_safe(cur, next, &ecfactory_list, list) { >+ if (cur->ec == ec) { >+ list_del(&cur->list); >+ break; >+ } >+ } >+ >+ write_unlock(&ecfactory_list_lock); >+} >+ >+static inline void rotate_sums(void) >+{ >+ /* Rotate where we sum and so forth */ >+ static int pos = 0; >+ conf_sums_prev = sums + (DAHDI_MAX_CONF + 1) * pos; >+ conf_sums = sums + (DAHDI_MAX_CONF + 1) * ((pos + 1) % 3); >+ conf_sums_next = sums + (DAHDI_MAX_CONF + 1) * ((pos + 2) % 3); >+ pos = (pos + 1) % 3; >+ memset(conf_sums_next, 0, maxconfs * sizeof(sumtype)); >+} >+ >+/*! >+ * \return quiescent (idle) signalling states, for the various signalling types >+ */ >+static int dahdi_q_sig(struct dahdi_chan *chan) >+{ >+ int x; >+ static const unsigned int in_sig[NUM_SIGS][2] = { >+ { DAHDI_SIG_NONE, 0 }, >+ { DAHDI_SIG_EM, (DAHDI_ABIT << 8) }, >+ { DAHDI_SIG_FXSLS, DAHDI_BBIT | (DAHDI_BBIT << 8) }, >+ { DAHDI_SIG_FXSGS, DAHDI_ABIT | DAHDI_BBIT | ((DAHDI_ABIT | DAHDI_BBIT) << 8) }, >+ { DAHDI_SIG_FXSKS, DAHDI_BBIT | DAHDI_BBIT | ((DAHDI_ABIT | DAHDI_BBIT) << 8) }, >+ { DAHDI_SIG_FXOLS, (DAHDI_ABIT << 8) }, >+ { DAHDI_SIG_FXOGS, DAHDI_BBIT | ((DAHDI_ABIT | DAHDI_BBIT) << 8) }, >+ { DAHDI_SIG_FXOKS, (DAHDI_ABIT << 8) }, >+ { DAHDI_SIG_SF, 0 }, >+ { DAHDI_SIG_EM_E1, DAHDI_DBIT | ((DAHDI_ABIT | DAHDI_DBIT) << 8) }, >+ }; >+ >+ /* must have span to begin with */ >+ if (!chan->span) >+ return -1; >+ >+ /* if RBS does not apply, return error */ >+ if (!(chan->span->flags & DAHDI_FLAG_RBS) || !chan->span->rbsbits) >+ return -1; >+ >+ if (chan->sig == DAHDI_SIG_CAS) >+ return chan->idlebits; >+ >+ for (x = 0; x < NUM_SIGS; x++) { >+ if (in_sig[x][0] == chan->sig) >+ return in_sig[x][1]; >+ } >+ >+ return -1; /* not found -- error */ >+} >+ >+#ifdef CONFIG_PROC_FS >+static const char *sigstr(int sig) >+{ >+ switch (sig) { >+ case DAHDI_SIG_FXSLS: >+ return "FXSLS"; >+ case DAHDI_SIG_FXSKS: >+ return "FXSKS"; >+ case DAHDI_SIG_FXSGS: >+ return "FXSGS"; >+ case DAHDI_SIG_FXOLS: >+ return "FXOLS"; >+ case DAHDI_SIG_FXOKS: >+ return "FXOKS"; >+ case DAHDI_SIG_FXOGS: >+ return "FXOGS"; >+ case DAHDI_SIG_EM: >+ return "E&M"; >+ case DAHDI_SIG_EM_E1: >+ return "E&M-E1"; >+ case DAHDI_SIG_CLEAR: >+ return "Clear"; >+ case DAHDI_SIG_HDLCRAW: >+ return "HDLCRAW"; >+ case DAHDI_SIG_HDLCFCS: >+ return "HDLCFCS"; >+ case DAHDI_SIG_HDLCNET: >+ return "HDLCNET"; >+ case DAHDI_SIG_HARDHDLC: >+ return "Hardware-assisted HDLC"; >+ case DAHDI_SIG_MTP2: >+ return "MTP2"; >+ case DAHDI_SIG_SLAVE: >+ return "Slave"; >+ case DAHDI_SIG_CAS: >+ return "CAS"; >+ case DAHDI_SIG_DACS: >+ return "DACS"; >+ case DAHDI_SIG_DACS_RBS: >+ return "DACS+RBS"; >+ case DAHDI_SIG_SF: >+ return "SF (ToneOnly)"; >+ case DAHDI_SIG_NONE: >+ default: >+ return "Unconfigured"; >+ } >+} >+ >+static int fill_alarm_string(char *buf, int count, int alarms) >+{ >+ int len; >+ >+ if (alarms <= 0) >+ return 0; >+ >+ len = snprintf(buf, count, "%s%s%s%s%s%s", >+ (alarms & DAHDI_ALARM_BLUE) ? "BLUE " : "", >+ (alarms & DAHDI_ALARM_YELLOW) ? "YELLOW " : "", >+ (alarms & DAHDI_ALARM_RED) ? "RED " : "", >+ (alarms & DAHDI_ALARM_LOOPBACK) ? "LOOP " : "", >+ (alarms & DAHDI_ALARM_RECOVER) ? "RECOVERING " : "", >+ (alarms & DAHDI_ALARM_NOTOPEN) ? "NOTOPEN " : ""); >+ >+ if (len > 0) >+ buf[--len] = '\0'; /* strip last space */ >+ >+ return len; >+} >+ >+static int dahdi_proc_read(char *page, char **start, off_t off, int count, int *eof, void *data) >+{ >+ int x, len = 0, real_count; >+ long span; >+ >+ /* In Linux 2.6, page is always PROC_BLOCK_SIZE=(PAGE_SIZE-1024) bytes. >+ * 0<count<=PROC_BLOCK_SIZE . count=1 will produce an error in >+ * vsnprintf ('head -c 1 /proc/dahdi/1', 'dd bs=1'). >+ * An ugly hack. Good way: seq_printf (seq_file.c). */ >+ real_count = count; >+ count = PAGE_SIZE-1024; >+ span = (long)data; >+ if (!span) >+ return 0; >+ >+ if (spans[span]->name) >+ len += snprintf(page + len, count - len, "Span %ld: %s ", >+ span, spans[span]->name); >+ if (spans[span]->desc) >+ len += snprintf(page + len, count - len, "\"%s\"", >+ spans[span]->desc); >+ else >+ len += snprintf(page + len, count - len, "\"\""); >+ >+ if (spans[span] == master) >+ len += snprintf(page + len, count - len, " (MASTER)"); >+ >+ if (spans[span]->lineconfig) { >+ /* framing first */ >+ if (spans[span]->lineconfig & DAHDI_CONFIG_B8ZS) >+ len += snprintf(page + len, count - len, " B8ZS/"); >+ else if (spans[span]->lineconfig & DAHDI_CONFIG_AMI) >+ len += snprintf(page + len, count - len, " AMI/"); >+ else if (spans[span]->lineconfig & DAHDI_CONFIG_HDB3) >+ len += snprintf(page + len, count - len, " HDB3/"); >+ /* then coding */ >+ if (spans[span]->lineconfig & DAHDI_CONFIG_ESF) >+ len += snprintf(page + len, count - len, "ESF"); >+ else if (spans[span]->lineconfig & DAHDI_CONFIG_D4) >+ len += snprintf(page + len, count - len, "D4"); >+ else if (spans[span]->lineconfig & DAHDI_CONFIG_CCS) >+ len += snprintf(page + len, count - len, "CCS"); >+ /* E1's can enable CRC checking */ >+ if (spans[span]->lineconfig & DAHDI_CONFIG_CRC4) >+ len += snprintf(page + len, count - len, "/CRC4"); >+ } >+ >+ len += snprintf(page + len, count - len, " "); >+ >+ /* list alarms */ >+ len += fill_alarm_string(page + len, count - len, spans[span]->alarms); >+ if (spans[span]->syncsrc && >+ (spans[span]->syncsrc == spans[span]->spanno)) >+ len += snprintf(page + len, count - len, "ClockSource "); >+ len += snprintf(page + len, count - len, "\n"); >+ if (spans[span]->bpvcount) >+ len += snprintf(page + len, count - len, "\tBPV count: %d\n", >+ spans[span]->bpvcount); >+ if (spans[span]->crc4count) >+ len += snprintf(page + len, count - len, >+ "\tCRC4 error count: %d\n", >+ spans[span]->crc4count); >+ if (spans[span]->ebitcount) >+ len += snprintf(page + len, count - len, >+ "\tE-bit error count: %d\n", >+ spans[span]->ebitcount); >+ if (spans[span]->fascount) >+ len += snprintf(page + len, count - len, >+ "\tFAS error count: %d\n", >+ spans[span]->fascount); >+ if (spans[span]->irqmisses) >+ len += snprintf(page + len, count - len, >+ "\tIRQ misses: %d\n", >+ spans[span]->irqmisses); >+ if (spans[span]->timingslips) >+ len += snprintf(page + len, count - len, >+ "\tTiming slips: %d\n", >+ spans[span]->timingslips); >+ len += snprintf(page + len, count - len, "\n"); >+ >+ for (x = 0; x < spans[span]->channels; x++) { >+ struct dahdi_chan *chan = spans[span]->chans[x]; >+ >+ if (chan->name) >+ len += snprintf(page + len, count - len, >+ "\t%4d %s ", chan->channo, chan->name); >+ >+ if (chan->sig) { >+ if (chan->sig == DAHDI_SIG_SLAVE) >+ len += snprintf(page+len, count-len, "%s ", >+ sigstr(chan->master->sig)); >+ else { >+ len += snprintf(page+len, count-len, "%s ", >+ sigstr(chan->sig)); >+ if (chan->nextslave && >+ (chan->master->channo == chan->channo)) >+ len += snprintf(page+len, count-len, >+ "Master "); >+ } >+ } >+ >+ if (test_bit(DAHDI_FLAGBIT_OPEN, &chan->flags)) >+ len += snprintf(page + len, count - len, "(In use) "); >+ >+#ifdef OPTIMIZE_CHANMUTE >+ if (chan->chanmute) >+ len += snprintf(page+len, count-len, "(no pcm) "); >+#endif >+ >+ len += fill_alarm_string(page+len, count-len, >+ chan->chan_alarms); >+ >+ if (chan->ec_factory) >+ len += snprintf(page+len, count-len, "(SWEC: %s) ", >+ chan->ec_factory->name); >+ >+ if (chan->ec_state) >+ len += snprintf(page+len, count-len, "(EC: %s) ", >+ chan->ec_state->ops->name); >+ >+ len += snprintf(page+len, count-len, "\n"); >+ >+ /* If everything printed so far is before beginning >+ * of request */ >+ if (len <= off) { >+ off -= len; >+ len = 0; >+ } >+ >+ /* stop if we've already generated enough */ >+ if (len > off + count) >+ break; >+ /* stop if we're NEAR danger limit. let it be -128 bytes. */ >+ if (len > count-128) >+ break; >+ } >+ count = real_count; >+ /* If everything printed so far is before beginning of request */ >+ if (len <= off) { >+ off = 0; >+ len = 0; >+ } >+ *start = page + off; >+ len -= off; /* un-count any remaining offset */ >+ *eof = 1; >+ if (len > count) >+ len = count; /* don't return bytes not asked for */ >+ return len; >+} >+#endif >+ >+static int dahdi_first_empty_alias(void) >+{ >+ /* Find the first conference which has no alias pointing to it */ >+ int x; >+ for (x=1;x<DAHDI_MAX_CONF;x++) { >+ if (!confrev[x]) >+ return x; >+ } >+ return -1; >+} >+ >+static void recalc_maxconfs(void) >+{ >+ int x; >+ >+ for (x = DAHDI_MAX_CONF - 1; x > 0; x--) { >+ if (confrev[x]) { >+ maxconfs = x + 1; >+ return; >+ } >+ } >+ >+ maxconfs = 0; >+} >+ >+static void recalc_maxlinks(void) >+{ >+ int x; >+ >+ for (x = DAHDI_MAX_CONF - 1; x > 0; x--) { >+ if (conf_links[x].src || conf_links[x].dst) { >+ maxlinks = x + 1; >+ return; >+ } >+ } >+ >+ maxlinks = 0; >+} >+ >+static int dahdi_first_empty_conference(void) >+{ >+ /* Find the first conference which has no alias */ >+ int x; >+ >+ for (x = DAHDI_MAX_CONF - 1; x > 0; x--) { >+ if (!confalias[x]) >+ return x; >+ } >+ >+ return -1; >+} >+ >+static int dahdi_get_conf_alias(int x) >+{ >+ int a; >+ >+ if (confalias[x]) >+ return confalias[x]; >+ >+ /* Allocate an alias */ >+ a = dahdi_first_empty_alias(); >+ confalias[x] = a; >+ confrev[a] = x; >+ >+ /* Highest conference may have changed */ >+ recalc_maxconfs(); >+ >+ return a; >+} >+ >+static void dahdi_check_conf(int x) >+{ >+ int y; >+ >+ /* return if no valid conf number */ >+ if (x <= 0) >+ return; >+ >+ /* Return if there is no alias */ >+ if (!confalias[x]) >+ return; >+ >+ for (y = 0; y < maxchans; y++) { >+ if (chans[y] && (chans[y]->confna == x) && >+ ((chans[y]->confmode & DAHDI_CONF_MODE_MASK) == DAHDI_CONF_CONF || >+ (chans[y]->confmode & DAHDI_CONF_MODE_MASK) == DAHDI_CONF_CONFANN || >+ (chans[y]->confmode & DAHDI_CONF_MODE_MASK) == DAHDI_CONF_CONFMON || >+ (chans[y]->confmode & DAHDI_CONF_MODE_MASK) == DAHDI_CONF_CONFANNMON || >+ (chans[y]->confmode & DAHDI_CONF_MODE_MASK) == DAHDI_CONF_REALANDPSEUDO)) { >+ return; >+ } >+ } >+ >+ /* If we get here, nobody is in the conference anymore. Clear it out >+ both forward and reverse */ >+ confrev[confalias[x]] = 0; >+ confalias[x] = 0; >+ >+ /* Highest conference may have changed */ >+ recalc_maxconfs(); >+} >+ >+/* enqueue an event on a channel */ >+static void __qevent(struct dahdi_chan *chan, int event) >+{ >+ /* if full, ignore */ >+ if ((chan->eventoutidx == 0) && (chan->eventinidx == (DAHDI_MAX_EVENTSIZE - 1))) >+ return; >+ >+ /* if full, ignore */ >+ if (chan->eventinidx == (chan->eventoutidx - 1)) >+ return; >+ >+ /* save the event */ >+ chan->eventbuf[chan->eventinidx++] = event; >+ >+ /* wrap the index, if necessary */ >+ if (chan->eventinidx >= DAHDI_MAX_EVENTSIZE) >+ chan->eventinidx = 0; >+ >+ /* wake em all up */ >+ if (chan->iomask & DAHDI_IOMUX_SIGEVENT) >+ wake_up_interruptible(&chan->eventbufq); >+ >+ wake_up_interruptible(&chan->readbufq); >+ wake_up_interruptible(&chan->writebufq); >+ wake_up_interruptible(&chan->sel); >+ >+ return; >+} >+ >+void dahdi_qevent_nolock(struct dahdi_chan *chan, int event) >+{ >+ __qevent(chan, event); >+} >+ >+void dahdi_qevent_lock(struct dahdi_chan *chan, int event) >+{ >+ unsigned long flags; >+ spin_lock_irqsave(&chan->lock, flags); >+ __qevent(chan, event); >+ spin_unlock_irqrestore(&chan->lock, flags); >+} >+ >+/* sleep in user space until woken up. Equivilant of tsleep() in BSD */ >+static int schluffen(wait_queue_head_t *q) >+{ >+ DECLARE_WAITQUEUE(wait, current); >+ >+ add_wait_queue(q, &wait); >+ current->state = TASK_INTERRUPTIBLE; >+ >+ if (!signal_pending(current)) >+ schedule(); >+ >+ current->state = TASK_RUNNING; >+ remove_wait_queue(q, &wait); >+ >+ if (signal_pending(current)) >+ return -ERESTARTSYS; >+ >+ return 0; >+} >+ >+static inline void calc_fcs(struct dahdi_chan *ss, int inwritebuf) >+{ >+ int x; >+ unsigned int fcs = PPP_INITFCS; >+ unsigned char *data = ss->writebuf[inwritebuf]; >+ int len = ss->writen[inwritebuf]; >+ >+ /* Not enough space to do FCS calculation */ >+ if (len < 2) >+ return; >+ >+ for (x = 0; x < len - 2; x++) >+ fcs = PPP_FCS(fcs, data[x]); >+ >+ fcs ^= 0xffff; >+ /* Send out the FCS */ >+ data[len - 2] = (fcs & 0xff); >+ data[len - 1] = (fcs >> 8) & 0xff; >+} >+ >+static int dahdi_reallocbufs(struct dahdi_chan *ss, int j, int numbufs) >+{ >+ unsigned char *newbuf, *oldbuf; >+ unsigned long flags; >+ int x; >+ >+ /* Check numbufs */ >+ if (numbufs < 2) >+ numbufs = 2; >+ >+ if (numbufs > DAHDI_MAX_NUM_BUFS) >+ numbufs = DAHDI_MAX_NUM_BUFS; >+ >+ /* We need to allocate our buffers now */ >+ if (j) { >+ if (!(newbuf = kcalloc(j * 2, numbufs, GFP_KERNEL))) >+ return -ENOMEM; >+ } else >+ newbuf = NULL; >+ >+ /* Now that we've allocated our new buffer, we can safely >+ move things around... */ >+ >+ spin_lock_irqsave(&ss->lock, flags); >+ >+ ss->blocksize = j; /* set the blocksize */ >+ oldbuf = ss->readbuf[0]; /* Keep track of the old buffer */ >+ ss->readbuf[0] = NULL; >+ >+ if (newbuf) { >+ for (x = 0; x < numbufs; x++) { >+ ss->readbuf[x] = newbuf + x * j; >+ ss->writebuf[x] = newbuf + (numbufs + x) * j; >+ } >+ } else { >+ for (x = 0; x < numbufs; x++) { >+ ss->readbuf[x] = NULL; >+ ss->writebuf[x] = NULL; >+ } >+ } >+ >+ /* Mark all buffers as empty */ >+ for (x = 0; x < numbufs; x++) { >+ ss->writen[x] = >+ ss->writeidx[x]= >+ ss->readn[x]= >+ ss->readidx[x] = 0; >+ } >+ >+ /* Keep track of where our data goes (if it goes >+ anywhere at all) */ >+ if (newbuf) { >+ ss->inreadbuf = 0; >+ ss->inwritebuf = 0; >+ } else { >+ ss->inreadbuf = -1; >+ ss->inwritebuf = -1; >+ } >+ >+ ss->outreadbuf = -1; >+ ss->outwritebuf = -1; >+ ss->numbufs = numbufs; >+ >+ if ((ss->txbufpolicy == DAHDI_POLICY_WHEN_FULL) || (ss->txbufpolicy == DAHDI_POLICY_HALF_FULL)) >+ ss->txdisable = 1; >+ else >+ ss->txdisable = 0; >+ >+ if (ss->rxbufpolicy == DAHDI_POLICY_WHEN_FULL) >+ ss->rxdisable = 1; >+ else >+ ss->rxdisable = 0; >+ >+ spin_unlock_irqrestore(&ss->lock, flags); >+ >+ if (oldbuf) >+ kfree(oldbuf); >+ >+ return 0; >+} >+ >+static int dahdi_hangup(struct dahdi_chan *chan); >+static void dahdi_set_law(struct dahdi_chan *chan, int law); >+ >+/* Pull a DAHDI_CHUNKSIZE piece off the queue. Returns >+ 0 on success or -1 on failure. If failed, provides >+ silence */ >+static int __buf_pull(struct confq *q, u_char *data, struct dahdi_chan *c, char *label) >+{ >+ int oldoutbuf = q->outbuf; >+ /* Ain't nuffin to read */ >+ if (q->outbuf < 0) { >+ if (data) >+ memset(data, DAHDI_LIN2X(0,c), DAHDI_CHUNKSIZE); >+ return -1; >+ } >+ if (data) >+ memcpy(data, q->buf[q->outbuf], DAHDI_CHUNKSIZE); >+ q->outbuf = (q->outbuf + 1) % DAHDI_CB_SIZE; >+ >+ /* Won't be nuffin next time */ >+ if (q->outbuf == q->inbuf) { >+ q->outbuf = -1; >+ } >+ >+ /* If they thought there was no space then >+ there is now where we just read */ >+ if (q->inbuf < 0) >+ q->inbuf = oldoutbuf; >+ return 0; >+} >+ >+/* Returns a place to put stuff, or NULL if there is >+ no room */ >+ >+static u_char *__buf_pushpeek(struct confq *q) >+{ >+ if (q->inbuf < 0) >+ return NULL; >+ return q->buf[q->inbuf]; >+} >+ >+static u_char *__buf_peek(struct confq *q) >+{ >+ if (q->outbuf < 0) >+ return NULL; >+ return q->buf[q->outbuf]; >+} >+ >+#ifdef BUF_MUNGE >+static u_char *__buf_cpush(struct confq *q) >+{ >+ int pos; >+ /* If we have no space, return where the >+ last space that we *did* have was */ >+ if (q->inbuf > -1) >+ return NULL; >+ pos = q->outbuf - 1; >+ if (pos < 0) >+ pos += DAHDI_CB_SIZE; >+ return q->buf[pos]; >+} >+ >+static void __buf_munge(struct dahdi_chan *chan, u_char *old, u_char *new) >+{ >+ /* Run a weighted average of the old and new, in order to >+ mask a missing sample */ >+ int x; >+ int val; >+ for (x=0;x<DAHDI_CHUNKSIZE;x++) { >+ val = x * DAHDI_XLAW(new[x], chan) + (DAHDI_CHUNKSIZE - x - 1) * DAHDI_XLAW(old[x], chan); >+ val = val / (DAHDI_CHUNKSIZE - 1); >+ old[x] = DAHDI_LIN2X(val, chan); >+ } >+} >+#endif >+/* Push something onto the queue, or assume what >+ is there is valid if data is NULL */ >+static int __buf_push(struct confq *q, u_char *data, char *label) >+{ >+ int oldinbuf = q->inbuf; >+ if (q->inbuf < 0) { >+ return -1; >+ } >+ if (data) >+ /* Copy in the data */ >+ memcpy(q->buf[q->inbuf], data, DAHDI_CHUNKSIZE); >+ >+ /* Advance the inbuf pointer */ >+ q->inbuf = (q->inbuf + 1) % DAHDI_CB_SIZE; >+ >+ if (q->inbuf == q->outbuf) { >+ /* No space anymore... */ >+ q->inbuf = -1; >+ } >+ /* If they don't think data is ready, let >+ them know it is now */ >+ if (q->outbuf < 0) { >+ q->outbuf = oldinbuf; >+ } >+ return 0; >+} >+ >+static void reset_conf(struct dahdi_chan *chan) >+{ >+ int x; >+ >+ /* Empty out buffers and reset to initialization */ >+ >+ for (x = 0; x < DAHDI_CB_SIZE; x++) >+ chan->confin.buf[x] = chan->confin.buffer + DAHDI_CHUNKSIZE * x; >+ >+ chan->confin.inbuf = 0; >+ chan->confin.outbuf = -1; >+ >+ for (x = 0; x < DAHDI_CB_SIZE; x++) >+ chan->confout.buf[x] = chan->confout.buffer + DAHDI_CHUNKSIZE * x; >+ >+ chan->confout.inbuf = 0; >+ chan->confout.outbuf = -1; >+} >+ >+ >+static const struct dahdi_echocan_factory *find_echocan(const char *name) >+{ >+ struct ecfactory *cur; >+ char name_upper[strlen(name) + 1]; >+ char *c; >+ const char *d; >+ char modname_buf[128] = "dahdi_echocan_"; >+ unsigned int tried_once = 0; >+ >+ for (c = name_upper, d = name; *d; c++, d++) { >+ *c = toupper(*d); >+ } >+ >+ *c = '\0'; >+ >+retry: >+ read_lock(&ecfactory_list_lock); >+ >+ list_for_each_entry(cur, &ecfactory_list, list) { >+ if (!strcmp(name_upper, cur->ec->name)) { >+#ifdef USE_ECHOCAN_REFCOUNT >+ if (try_module_get(cur->owner)) { >+ read_unlock(&ecfactory_list_lock); >+ return cur->ec; >+ } else { >+ read_unlock(&ecfactory_list_lock); >+ return NULL; >+ } >+#else >+ read_unlock(&ecfactory_list_lock); >+ return cur->ec; >+#endif >+ } >+ } >+ >+ read_unlock(&ecfactory_list_lock); >+ >+ if (tried_once) { >+ return NULL; >+ } >+ >+ /* couldn't find it, let's try to load it */ >+ >+ for (c = &modname_buf[strlen(modname_buf)], d = name; *d; c++, d++) { >+ *c = tolower(*d); >+ } >+ >+ request_module("%s", modname_buf); >+ >+ tried_once = 1; >+ >+ /* and try one more time */ >+ goto retry; >+} >+ >+static void release_echocan(const struct dahdi_echocan_factory *ec) >+{ >+#ifdef USE_ECHOCAN_REFCOUNT >+ if (ec) >+ module_put(ec->owner); >+#endif >+} >+ >+/** >+ * close_channel - close the channel, resetting any channel variables >+ * @chan: the dahdi_chan to close >+ * >+ * This function might be called before the channel is placed on the global >+ * array of channels, (chans), and therefore, neither this function nor it's >+ * children should depend on the dahdi_chan.channo member which is not set yet. >+ */ >+static void close_channel(struct dahdi_chan *chan) >+{ >+ unsigned long flags; >+ void *rxgain = NULL; >+ struct dahdi_echocan_state *ec_state; >+ const struct dahdi_echocan_factory *ec_current; >+ int oldconf; >+ short *readchunkpreec; >+#ifdef CONFIG_DAHDI_PPP >+ struct ppp_channel *ppp; >+#endif >+ >+ might_sleep(); >+ >+ /* XXX Buffers should be send out before reallocation!!! XXX */ >+ if (!(chan->flags & DAHDI_FLAG_NOSTDTXRX)) >+ dahdi_reallocbufs(chan, 0, 0); >+ spin_lock_irqsave(&chan->lock, flags); >+#ifdef CONFIG_DAHDI_PPP >+ ppp = chan->ppp; >+ chan->ppp = NULL; >+#endif >+ ec_state = chan->ec_state; >+ chan->ec_state = NULL; >+ ec_current = chan->ec_current; >+ chan->ec_current = NULL; >+ readchunkpreec = chan->readchunkpreec; >+ chan->readchunkpreec = NULL; >+ chan->curtone = NULL; >+ if (chan->curzone) >+ atomic_dec(&chan->curzone->refcount); >+ chan->curzone = NULL; >+ chan->cadencepos = 0; >+ chan->pdialcount = 0; >+ dahdi_hangup(chan); >+ chan->itimerset = chan->itimer = 0; >+ chan->pulsecount = 0; >+ chan->pulsetimer = 0; >+ chan->ringdebtimer = 0; >+ init_waitqueue_head(&chan->sel); >+ init_waitqueue_head(&chan->readbufq); >+ init_waitqueue_head(&chan->writebufq); >+ init_waitqueue_head(&chan->eventbufq); >+ init_waitqueue_head(&chan->txstateq); >+ chan->txdialbuf[0] = '\0'; >+ chan->digitmode = DIGIT_MODE_DTMF; >+ chan->dialing = 0; >+ chan->afterdialingtimer = 0; >+ /* initialize IO MUX mask */ >+ chan->iomask = 0; >+ /* save old conf number, if any */ >+ oldconf = chan->confna; >+ /* initialize conference variables */ >+ chan->_confn = 0; >+ if ((chan->sig & __DAHDI_SIG_DACS) != __DAHDI_SIG_DACS) { >+ chan->confna = 0; >+ chan->confmode = 0; >+ } >+ chan->confmute = 0; >+ /* release conference resource, if any to release */ >+ if (oldconf) dahdi_check_conf(oldconf); >+ chan->gotgs = 0; >+ reset_conf(chan); >+ >+ if (chan->gainalloc && chan->rxgain) >+ rxgain = chan->rxgain; >+ >+ chan->rxgain = defgain; >+ chan->txgain = defgain; >+ chan->gainalloc = 0; >+ chan->eventinidx = chan->eventoutidx = 0; >+ chan->flags &= ~(DAHDI_FLAG_LOOPED | DAHDI_FLAG_LINEAR | DAHDI_FLAG_PPP | DAHDI_FLAG_SIGFREEZE); >+ >+ dahdi_set_law(chan,0); >+ >+ memset(chan->conflast, 0, sizeof(chan->conflast)); >+ memset(chan->conflast1, 0, sizeof(chan->conflast1)); >+ memset(chan->conflast2, 0, sizeof(chan->conflast2)); >+ >+ if (chan->span && chan->span->dacs && oldconf) >+ chan->span->dacs(chan, NULL); >+ >+ if (ec_state) { >+ ec_state->ops->echocan_free(chan, ec_state); >+ release_echocan(ec_current); >+ } >+ >+ spin_unlock_irqrestore(&chan->lock, flags); >+ >+ if (rxgain) >+ kfree(rxgain); >+ if (readchunkpreec) >+ kfree(readchunkpreec); >+ >+#ifdef CONFIG_DAHDI_PPP >+ if (ppp) { >+ tasklet_kill(&chan->ppp_calls); >+ skb_queue_purge(&chan->ppp_rq); >+ ppp_unregister_channel(ppp); >+ kfree(ppp); >+ } >+#endif >+ >+} >+ >+static int free_tone_zone(int num) >+{ >+ struct dahdi_zone *z = NULL; >+ int res = 0; >+ >+ if ((num >= DAHDI_TONE_ZONE_MAX) || (num < 0)) >+ return -EINVAL; >+ >+ write_lock(&zone_lock); >+ if (tone_zones[num]) { >+ if (!atomic_read(&tone_zones[num]->refcount)) { >+ z = tone_zones[num]; >+ tone_zones[num] = NULL; >+ } else { >+ res = -EBUSY; >+ } >+ } >+ write_unlock(&zone_lock); >+ >+ if (z) >+ kfree(z); >+ >+ return res; >+} >+ >+static int dahdi_register_tone_zone(int num, struct dahdi_zone *zone) >+{ >+ int res = 0; >+ >+ if ((num >= DAHDI_TONE_ZONE_MAX) || (num < 0)) >+ return -EINVAL; >+ >+ write_lock(&zone_lock); >+ if (tone_zones[num]) { >+ res = -EINVAL; >+ } else { >+ res = 0; >+ tone_zones[num] = zone; >+ } >+ write_unlock(&zone_lock); >+ >+ if (!res) >+ module_printk(KERN_INFO, "Registered tone zone %d (%s)\n", num, zone->name); >+ >+ return res; >+} >+ >+static int start_tone_digit(struct dahdi_chan *chan, int tone) >+{ >+ struct dahdi_tone *playtone = NULL; >+ int base, max; >+ >+ if (!chan->curzone) >+ return -ENODATA; >+ >+ switch (chan->digitmode) { >+ case DIGIT_MODE_DTMF: >+ /* Set dialing so that a dial operation doesn't interrupt this tone */ >+ chan->dialing = 1; >+ base = DAHDI_TONE_DTMF_BASE; >+ max = DAHDI_TONE_DTMF_MAX; >+ break; >+ case DIGIT_MODE_MFR2_FWD: >+ base = DAHDI_TONE_MFR2_FWD_BASE; >+ max = DAHDI_TONE_MFR2_FWD_MAX; >+ break; >+ case DIGIT_MODE_MFR2_REV: >+ base = DAHDI_TONE_MFR2_REV_BASE; >+ max = DAHDI_TONE_MFR2_REV_MAX; >+ break; >+ default: >+ return -EINVAL; >+ } >+ >+ if ((tone < base) || (tone > max)) >+ return -EINVAL; >+ >+ switch (chan->digitmode) { >+ case DIGIT_MODE_DTMF: >+ playtone = &chan->curzone->dtmf_continuous[tone - base]; >+ break; >+ case DIGIT_MODE_MFR2_FWD: >+ playtone = &chan->curzone->mfr2_fwd_continuous[tone - base]; >+ break; >+ case DIGIT_MODE_MFR2_REV: >+ playtone = &chan->curzone->mfr2_rev_continuous[tone - base]; >+ break; >+ } >+ >+ if (!playtone || !playtone->tonesamples) >+ return -ENOSYS; >+ >+ chan->curtone = playtone; >+ >+ return 0; >+} >+ >+static int start_tone(struct dahdi_chan *chan, int tone) >+{ >+ int res = -EINVAL; >+ >+ /* Stop the current tone, no matter what */ >+ chan->tonep = 0; >+ chan->curtone = NULL; >+ chan->pdialcount = 0; >+ chan->txdialbuf[0] = '\0'; >+ chan->dialing = 0; >+ >+ if (tone == -1) { >+ /* Just stop the current tone */ >+ res = 0; >+ } else if (!chan->curzone) { >+ static int __warnonce = 1; >+ if (__warnonce) { >+ __warnonce = 0; >+ /* The tonezones are loaded by dahdi_cfg based on /etc/dahdi/system.conf. */ >+ module_printk(KERN_WARNING, "DAHDI: Cannot start tones until tone zone is loaded.\n"); >+ } >+ /* Note that no tone zone exists at the moment */ >+ res = -ENODATA; >+ } else if ((tone >= 0 && tone <= DAHDI_TONE_MAX)) { >+ /* Have a tone zone */ >+ if (chan->curzone->tones[tone]) { >+ chan->curtone = chan->curzone->tones[tone]; >+ res = 0; >+ } else { /* Indicate that zone is loaded but no such tone exists */ >+ res = -ENOSYS; >+ } >+ } else if (chan->digitmode == DIGIT_MODE_DTMF || >+ chan->digitmode == DIGIT_MODE_MFR2_FWD || >+ chan->digitmode == DIGIT_MODE_MFR2_REV) { >+ res = start_tone_digit(chan, tone); >+ } else { >+ chan->dialing = 0; >+ res = -EINVAL; >+ } >+ >+ if (chan->curtone) >+ dahdi_init_tone_state(&chan->ts, chan->curtone); >+ >+ return res; >+} >+ >+static int set_tone_zone(struct dahdi_chan *chan, int zone) >+{ >+ int res = 0; >+ struct dahdi_zone *z; >+ >+ /* Do not call with the channel locked. */ >+ >+ if (zone == -1) >+ zone = default_zone; >+ >+ if ((zone >= DAHDI_TONE_ZONE_MAX) || (zone < 0)) >+ return -EINVAL; >+ >+ read_lock(&zone_lock); >+ >+ if ((z = tone_zones[zone])) { >+ unsigned long flags; >+ >+ spin_lock_irqsave(&chan->lock, flags); >+ >+ if (chan->curzone) >+ atomic_dec(&chan->curzone->refcount); >+ >+ atomic_inc(&z->refcount); >+ chan->curzone = z; >+ chan->tonezone = zone; >+ memcpy(chan->ringcadence, z->ringcadence, sizeof(chan->ringcadence)); >+ >+ spin_unlock_irqrestore(&chan->lock, flags); >+ } else { >+ res = -ENODATA; >+ } >+ >+ read_unlock(&zone_lock); >+ >+ return res; >+} >+ >+static void dahdi_set_law(struct dahdi_chan *chan, int law) >+{ >+ if (!law) { >+ if (chan->deflaw) >+ law = chan->deflaw; >+ else >+ if (chan->span) law = chan->span->deflaw; >+ else law = DAHDI_LAW_MULAW; >+ } >+ if (law == DAHDI_LAW_ALAW) { >+ chan->xlaw = __dahdi_alaw; >+#ifdef CONFIG_CALC_XLAW >+ chan->lineartoxlaw = __dahdi_lineartoalaw; >+#else >+ chan->lin2x = __dahdi_lin2a; >+#endif >+ } else { >+ chan->xlaw = __dahdi_mulaw; >+#ifdef CONFIG_CALC_XLAW >+ chan->lineartoxlaw = __dahdi_lineartoulaw; >+#else >+ chan->lin2x = __dahdi_lin2mu; >+#endif >+ } >+} >+ >+static int dahdi_chan_reg(struct dahdi_chan *chan) >+{ >+ int x; >+ unsigned long flags; >+ >+ might_sleep(); >+ >+ spin_lock_init(&chan->lock); >+ if (!chan->master) >+ chan->master = chan; >+ if (!chan->readchunk) >+ chan->readchunk = chan->sreadchunk; >+ if (!chan->writechunk) >+ chan->writechunk = chan->swritechunk; >+ dahdi_set_law(chan, 0); >+ close_channel(chan); >+ >+ write_lock_irqsave(&chan_lock, flags); >+ for (x = 1; x < DAHDI_MAX_CHANNELS; x++) { >+ if (chans[x]) >+ continue; >+ >+ chans[x] = chan; >+ if (maxchans < x + 1) >+ maxchans = x + 1; >+ chan->channo = x; >+ write_unlock_irqrestore(&chan_lock, flags); >+ /* set this AFTER running close_channel() so that >+ HDLC channels wont cause hangage */ >+ set_bit(DAHDI_FLAGBIT_REGISTERED, &chan->flags); >+ break; >+ } >+ >+ if (DAHDI_MAX_CHANNELS == x) { >+ write_unlock_irqrestore(&chan_lock, flags); >+ module_printk(KERN_ERR, "No more channels available\n"); >+ return -ENOMEM; >+ } >+ >+ return 0; >+} >+ >+char *dahdi_lboname(int x) >+{ >+ if ((x < 0) || (x > 7)) >+ return "Unknown"; >+ return dahdi_txlevelnames[x]; >+} >+ >+#if defined(CONFIG_DAHDI_NET) || defined(CONFIG_DAHDI_PPP) >+static inline void print_debug_writebuf(struct dahdi_chan* ss, struct sk_buff *skb, int oldbuf) >+{ >+#ifdef CONFIG_DAHDI_DEBUG >+ int x; >+ >+ module_printk(KERN_NOTICE, "Buffered %d bytes to go out in buffer %d\n", ss->writen[oldbuf], oldbuf); >+ module_printk(KERN_DEBUG ""); >+ for (x=0;x<ss->writen[oldbuf];x++) >+ printk("%02x ", ss->writebuf[oldbuf][x]); >+ printk("\n"); >+#endif >+} >+#endif >+ >+#ifdef CONFIG_DAHDI_NET >+#ifdef NEW_HDLC_INTERFACE >+static int dahdi_net_open(struct net_device *dev) >+{ >+ int res = hdlc_open(dev); >+ struct dahdi_chan *ms = dev_to_ztchan(dev); >+ >+/* if (!dev->hard_start_xmit) return res; is this really necessary? --byg */ >+ if (res) /* this is necessary to avoid kernel panic when UNSPEC link encap, proven --byg */ >+ return res; >+#else >+static int dahdi_net_open(hdlc_device *hdlc) >+{ >+ struct dahdi_chan *ms = hdlc_to_ztchan(hdlc); >+ int res; >+#endif >+ if (!ms) { >+ module_printk(KERN_NOTICE, "dahdi_net_open: nothing??\n"); >+ return -EINVAL; >+ } >+ if (test_bit(DAHDI_FLAGBIT_OPEN, &ms->flags)) { >+ module_printk(KERN_NOTICE, "%s is already open!\n", ms->name); >+ return -EBUSY; >+ } >+ if (!(ms->flags & DAHDI_FLAG_NETDEV)) { >+ module_printk(KERN_NOTICE, "%s is not a net device!\n", ms->name); >+ return -EINVAL; >+ } >+ ms->txbufpolicy = DAHDI_POLICY_IMMEDIATE; >+ ms->rxbufpolicy = DAHDI_POLICY_IMMEDIATE; >+ >+ res = dahdi_reallocbufs(ms, DAHDI_DEFAULT_MTU_MRU, DAHDI_DEFAULT_NUM_BUFS); >+ if (res) >+ return res; >+ >+ fasthdlc_init(&ms->rxhdlc, (ms->flags & DAHDI_FLAG_HDLC56) ? FASTHDLC_MODE_56 : FASTHDLC_MODE_64); >+ fasthdlc_init(&ms->txhdlc, (ms->flags & DAHDI_FLAG_HDLC56) ? FASTHDLC_MODE_56 : FASTHDLC_MODE_64); >+ ms->infcs = PPP_INITFCS; >+ >+ netif_start_queue(ztchan_to_dev(ms)); >+ >+#ifdef CONFIG_DAHDI_DEBUG >+ module_printk(KERN_NOTICE, "DAHDINET: Opened channel %d name %s\n", ms->channo, ms->name); >+#endif >+ return 0; >+} >+ >+static int dahdi_register_hdlc_device(struct net_device *dev, const char *dev_name) >+{ >+ int result; >+ >+ if (dev_name && *dev_name) { >+ if ((result = dev_alloc_name(dev, dev_name)) < 0) >+ return result; >+ } >+ result = register_netdev(dev); >+ if (result != 0) >+ return -EIO; >+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,14) >+ if (netif_carrier_ok(dev)) >+ netif_carrier_off(dev); /* no carrier until DCD goes up */ >+#endif >+ return 0; >+} >+ >+#ifdef NEW_HDLC_INTERFACE >+static int dahdi_net_stop(struct net_device *dev) >+{ >+ hdlc_device *h = dev_to_hdlc(dev); >+ struct dahdi_hdlc *hdlc = h->priv; >+ >+#else >+static void dahdi_net_close(hdlc_device *hdlc) >+{ >+#endif >+ struct dahdi_chan *ms = hdlc_to_ztchan(hdlc); >+ if (!ms) { >+#ifdef NEW_HDLC_INTERFACE >+ module_printk(KERN_NOTICE, "dahdi_net_stop: nothing??\n"); >+ return 0; >+#else >+ module_printk(KERN_NOTICE, "dahdi_net_close: nothing??\n"); >+ return; >+#endif >+ } >+ if (!(ms->flags & DAHDI_FLAG_NETDEV)) { >+#ifdef NEW_HDLC_INTERFACE >+ module_printk(KERN_NOTICE, "dahdi_net_stop: %s is not a net device!\n", ms->name); >+ return 0; >+#else >+ module_printk(KERN_NOTICE, "dahdi_net_close: %s is not a net device!\n", ms->name); >+ return; >+#endif >+ } >+ /* Not much to do here. Just deallocate the buffers */ >+ netif_stop_queue(ztchan_to_dev(ms)); >+ dahdi_reallocbufs(ms, 0, 0); >+ hdlc_close(dev); >+#ifdef NEW_HDLC_INTERFACE >+ return 0; >+#else >+ return; >+#endif >+} >+ >+#ifdef NEW_HDLC_INTERFACE >+/* kernel 2.4.20+ has introduced attach function, dunno what to do, >+ just copy sources from dscc4 to be sure and ready for further mastering, >+ NOOP right now (i.e. really a stub) --byg */ >+static int dahdi_net_attach(struct net_device *dev, unsigned short encoding, >+ unsigned short parity) >+{ >+/* struct net_device *dev = hdlc_to_dev(hdlc); >+ struct dscc4_dev_priv *dpriv = dscc4_priv(dev); >+ >+ if (encoding != ENCODING_NRZ && >+ encoding != ENCODING_NRZI && >+ encoding != ENCODING_FM_MARK && >+ encoding != ENCODING_FM_SPACE && >+ encoding != ENCODING_MANCHESTER) >+ return -EINVAL; >+ >+ if (parity != PARITY_NONE && >+ parity != PARITY_CRC16_PR0_CCITT && >+ parity != PARITY_CRC16_PR1_CCITT && >+ parity != PARITY_CRC32_PR0_CCITT && >+ parity != PARITY_CRC32_PR1_CCITT) >+ return -EINVAL; >+ >+ dpriv->encoding = encoding; >+ dpriv->parity = parity;*/ >+ return 0; >+} >+#endif >+ >+static struct dahdi_hdlc *dahdi_hdlc_alloc(void) >+{ >+ return kzalloc(sizeof(struct dahdi_hdlc), GFP_KERNEL); >+} >+ >+#ifdef NEW_HDLC_INTERFACE >+static int dahdi_xmit(struct sk_buff *skb, struct net_device *dev) >+{ >+ /* FIXME: this construction seems to be not very optimal for me but I could find nothing better at the moment (Friday, 10PM :( ) --byg */ >+/* struct dahdi_chan *ss = hdlc_to_ztchan(list_entry(dev, struct dahdi_hdlc, netdev.netdev));*/ >+ struct dahdi_chan *ss = dev_to_ztchan(dev); >+ struct net_device_stats *stats = hdlc_stats(dev); >+ >+#else >+static int dahdi_xmit(hdlc_device *hdlc, struct sk_buff *skb) >+{ >+ struct dahdi_chan *ss = hdlc_to_ztchan(hdlc); >+ struct net_device *dev = &ss->hdlcnetdev->netdev.netdev; >+ struct net_device_stats *stats = &ss->hdlcnetdev->netdev.stats; >+#endif >+ int retval = 1; >+ int x,oldbuf; >+ unsigned int fcs; >+ unsigned char *data; >+ unsigned long flags; >+ /* See if we have any buffers */ >+ spin_lock_irqsave(&ss->lock, flags); >+ if (skb->len > ss->blocksize - 2) { >+ module_printk(KERN_ERR, "dahdi_xmit(%s): skb is too large (%d > %d)\n", dev->name, skb->len, ss->blocksize -2); >+ stats->tx_dropped++; >+ retval = 0; >+ } else if (ss->inwritebuf >= 0) { >+ /* We have a place to put this packet */ >+ /* XXX We should keep the SKB and avoid the memcpy XXX */ >+ data = ss->writebuf[ss->inwritebuf]; >+ memcpy(data, skb->data, skb->len); >+ ss->writen[ss->inwritebuf] = skb->len; >+ ss->writeidx[ss->inwritebuf] = 0; >+ /* Calculate the FCS */ >+ fcs = PPP_INITFCS; >+ for (x=0;x<skb->len;x++) >+ fcs = PPP_FCS(fcs, data[x]); >+ /* Invert it */ >+ fcs ^= 0xffff; >+ /* Send it out LSB first */ >+ data[ss->writen[ss->inwritebuf]++] = (fcs & 0xff); >+ data[ss->writen[ss->inwritebuf]++] = (fcs >> 8) & 0xff; >+ /* Advance to next window */ >+ oldbuf = ss->inwritebuf; >+ ss->inwritebuf = (ss->inwritebuf + 1) % ss->numbufs; >+ >+ if (ss->inwritebuf == ss->outwritebuf) { >+ /* Whoops, no more space. */ >+ ss->inwritebuf = -1; >+ >+ netif_stop_queue(ztchan_to_dev(ss)); >+ } >+ if (ss->outwritebuf < 0) { >+ /* Let the interrupt handler know there's >+ some space for us */ >+ ss->outwritebuf = oldbuf; >+ } >+ dev->trans_start = jiffies; >+ stats->tx_packets++; >+ stats->tx_bytes += ss->writen[oldbuf]; >+ print_debug_writebuf(ss, skb, oldbuf); >+ retval = 0; >+ /* Free the SKB */ >+ dev_kfree_skb_any(skb); >+ } >+ spin_unlock_irqrestore(&ss->lock, flags); >+ return retval; >+} >+ >+#ifdef NEW_HDLC_INTERFACE >+static int dahdi_net_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) >+{ >+ return hdlc_ioctl(dev, ifr, cmd); >+} >+#else >+static int dahdi_net_ioctl(hdlc_device *hdlc, struct ifreq *ifr, int cmd) >+{ >+ return -EIO; >+} >+#endif >+ >+#endif >+ >+#ifdef CONFIG_DAHDI_PPP >+ >+static int dahdi_ppp_xmit(struct ppp_channel *ppp, struct sk_buff *skb) >+{ >+ >+ /* >+ * If we can't handle the packet right now, return 0. If we >+ * we handle or drop it, return 1. Always free if we return >+ * 1 and never if we return 0 >+ */ >+ struct dahdi_chan *ss = ppp->private; >+ int x,oldbuf; >+ unsigned int fcs; >+ unsigned char *data; >+ unsigned long flags; >+ int retval = 0; >+ >+ /* See if we have any buffers */ >+ spin_lock_irqsave(&ss->lock, flags); >+ if (!(test_bit(DAHDI_FLAGBIT_OPEN, &ss->flags))) { >+ module_printk(KERN_ERR, "Can't transmit on closed channel\n"); >+ retval = 1; >+ } else if (skb->len > ss->blocksize - 4) { >+ module_printk(KERN_ERR, "dahdi_ppp_xmit(%s): skb is too large (%d > %d)\n", ss->name, skb->len, ss->blocksize -2); >+ retval = 1; >+ } else if (ss->inwritebuf >= 0) { >+ /* We have a place to put this packet */ >+ /* XXX We should keep the SKB and avoid the memcpy XXX */ >+ data = ss->writebuf[ss->inwritebuf]; >+ /* Start with header of two bytes */ >+ /* Add "ALL STATIONS" and "UNNUMBERED" */ >+ data[0] = 0xff; >+ data[1] = 0x03; >+ ss->writen[ss->inwritebuf] = 2; >+ >+ /* Copy real data and increment amount written */ >+ memcpy(data + 2, skb->data, skb->len); >+ >+ ss->writen[ss->inwritebuf] += skb->len; >+ >+ /* Re-set index back to zero */ >+ ss->writeidx[ss->inwritebuf] = 0; >+ >+ /* Calculate the FCS */ >+ fcs = PPP_INITFCS; >+ for (x=0;x<skb->len + 2;x++) >+ fcs = PPP_FCS(fcs, data[x]); >+ /* Invert it */ >+ fcs ^= 0xffff; >+ >+ /* Point past the real data now */ >+ data += (skb->len + 2); >+ >+ /* Send FCS out LSB first */ >+ data[0] = (fcs & 0xff); >+ data[1] = (fcs >> 8) & 0xff; >+ >+ /* Account for FCS length */ >+ ss->writen[ss->inwritebuf]+=2; >+ >+ /* Advance to next window */ >+ oldbuf = ss->inwritebuf; >+ ss->inwritebuf = (ss->inwritebuf + 1) % ss->numbufs; >+ >+ if (ss->inwritebuf == ss->outwritebuf) { >+ /* Whoops, no more space. */ >+ ss->inwritebuf = -1; >+ } >+ if (ss->outwritebuf < 0) { >+ /* Let the interrupt handler know there's >+ some space for us */ >+ ss->outwritebuf = oldbuf; >+ } >+ print_debug_writebuf(ss, skb, oldbuf); >+ retval = 1; >+ } >+ spin_unlock_irqrestore(&ss->lock, flags); >+ if (retval) { >+ /* Get rid of the SKB if we're returning non-zero */ >+ /* N.B. this is called in process or BH context so >+ dev_kfree_skb is OK. */ >+ dev_kfree_skb(skb); >+ } >+ return retval; >+} >+ >+static int dahdi_ppp_ioctl(struct ppp_channel *ppp, unsigned int cmd, unsigned long flags) >+{ >+ return -EIO; >+} >+ >+static struct ppp_channel_ops ztppp_ops = >+{ >+ .start_xmit = dahdi_ppp_xmit, >+ .ioctl = dahdi_ppp_ioctl, >+}; >+ >+#endif >+ >+static void dahdi_chan_unreg(struct dahdi_chan *chan) >+{ >+ int x; >+ unsigned long flags; >+ >+ might_sleep(); >+ >+#ifdef CONFIG_DAHDI_NET >+ if (chan->flags & DAHDI_FLAG_NETDEV) { >+ unregister_hdlc_device(chan->hdlcnetdev->netdev); >+ free_netdev(chan->hdlcnetdev->netdev); >+ kfree(chan->hdlcnetdev); >+ chan->hdlcnetdev = NULL; >+ } >+#endif >+ write_lock_irqsave(&chan_lock, flags); >+ if (test_bit(DAHDI_FLAGBIT_REGISTERED, &chan->flags)) { >+ chans[chan->channo] = NULL; >+ clear_bit(DAHDI_FLAGBIT_REGISTERED, &chan->flags); >+ } >+#ifdef CONFIG_DAHDI_PPP >+ if (chan->ppp) { >+ module_printk(KERN_NOTICE, "HUH??? PPP still attached??\n"); >+ } >+#endif >+ maxchans = 0; >+ for (x=1;x<DAHDI_MAX_CHANNELS;x++) >+ if (chans[x]) { >+ maxchans = x + 1; >+ /* Remove anyone pointing to us as master >+ and make them their own thing */ >+ if (chans[x]->master == chan) { >+ chans[x]->master = chans[x]; >+ } >+ if ((chans[x]->confna == chan->channo) && >+ ((chans[x]->confmode & DAHDI_CONF_MODE_MASK) == DAHDI_CONF_MONITOR || >+ (chans[x]->confmode & DAHDI_CONF_MODE_MASK) == DAHDI_CONF_MONITORTX || >+ (chans[x]->confmode & DAHDI_CONF_MODE_MASK) == DAHDI_CONF_MONITORBOTH || >+ (chans[x]->confmode & DAHDI_CONF_MODE_MASK) == DAHDI_CONF_MONITOR_RX_PREECHO || >+ (chans[x]->confmode & DAHDI_CONF_MODE_MASK) == DAHDI_CONF_MONITOR_TX_PREECHO || >+ (chans[x]->confmode & DAHDI_CONF_MODE_MASK) == DAHDI_CONF_MONITORBOTH_PREECHO || >+ (chans[x]->confmode & DAHDI_CONF_MODE_MASK) == DAHDI_CONF_DIGITALMON)) { >+ /* Take them out of conference with us */ >+ /* release conference resource if any */ >+ if (chans[x]->confna) { >+ dahdi_check_conf(chans[x]->confna); >+ if (chans[x]->span && chans[x]->span->dacs) >+ chans[x]->span->dacs(chans[x], NULL); >+ } >+ chans[x]->confna = 0; >+ chans[x]->_confn = 0; >+ chans[x]->confmode = 0; >+ } >+ } >+ chan->channo = -1; >+ write_unlock_irqrestore(&chan_lock, flags); >+} >+ >+static ssize_t dahdi_chan_read(struct file *file, char *usrbuf, size_t count, int unit) >+{ >+ struct dahdi_chan *chan = chans[unit]; >+ int amnt; >+ int res, rv; >+ int oldbuf,x; >+ unsigned long flags; >+ >+ /* Make sure count never exceeds 65k, and make sure it's unsigned */ >+ count &= 0xffff; >+ >+ if (!chan) >+ return -EINVAL; >+ >+ if (count < 1) >+ return -EINVAL; >+ >+ for (;;) { >+ spin_lock_irqsave(&chan->lock, flags); >+ if (chan->eventinidx != chan->eventoutidx) { >+ spin_unlock_irqrestore(&chan->lock, flags); >+ return -ELAST /* - chan->eventbuf[chan->eventoutidx]*/; >+ } >+ res = chan->outreadbuf; >+ if (chan->rxdisable) >+ res = -1; >+ spin_unlock_irqrestore(&chan->lock, flags); >+ if (res >= 0) >+ break; >+ if (file->f_flags & O_NONBLOCK) >+ return -EAGAIN; >+ rv = schluffen(&chan->readbufq); >+ if (rv) >+ return rv; >+ } >+ amnt = count; >+/* added */ >+#if 0 >+ if ((unit == 24) || (unit == 48) || (unit == 16) || (unit == 47)) { >+ int myamnt = amnt; >+ int x; >+ if (amnt > chan->readn[res]) >+ myamnt = chan->readn[res]; >+ module_printk(KERN_NOTICE, "dahdi_chan_read(unit: %d, inwritebuf: %d, outwritebuf: %d amnt: %d\n", >+ unit, chan->inwritebuf, chan->outwritebuf, myamnt); >+ >+ module_printk(KERN_DEBUG, "\t("); >+ for (x = 0; x < myamnt; x++) >+ printk((x ? " %02x" : "%02x"), (unsigned char)usrbuf[x]); >+ printk(")\n"); >+ } >+#endif >+/* end addition */ >+ if (chan->flags & DAHDI_FLAG_LINEAR) { >+ if (amnt > (chan->readn[res] << 1)) >+ amnt = chan->readn[res] << 1; >+ if (amnt) { >+ /* There seems to be a max stack size, so we have >+ to do this in smaller pieces */ >+ short lindata[128]; >+ int left = amnt >> 1; /* amnt is in bytes */ >+ int pos = 0; >+ int pass; >+ while (left) { >+ pass = left; >+ if (pass > 128) >+ pass = 128; >+ for (x = 0; x < pass; x++) >+ lindata[x] = DAHDI_XLAW(chan->readbuf[res][x + pos], chan); >+ if (copy_to_user(usrbuf + (pos << 1), lindata, pass << 1)) >+ return -EFAULT; >+ left -= pass; >+ pos += pass; >+ } >+ } >+ } else { >+ if (amnt > chan->readn[res]) >+ amnt = chan->readn[res]; >+ if (amnt) { >+ if (copy_to_user(usrbuf, chan->readbuf[res], amnt)) >+ return -EFAULT; >+ } >+ } >+ spin_lock_irqsave(&chan->lock, flags); >+ chan->readidx[res] = 0; >+ chan->readn[res] = 0; >+ oldbuf = res; >+ chan->outreadbuf = (res + 1) % chan->numbufs; >+ if (chan->outreadbuf == chan->inreadbuf) { >+ /* Out of stuff */ >+ chan->outreadbuf = -1; >+ if (chan->rxbufpolicy == DAHDI_POLICY_WHEN_FULL) >+ chan->rxdisable = 1; >+ } >+ if (chan->inreadbuf < 0) { >+ /* Notify interrupt handler that we have some space now */ >+ chan->inreadbuf = oldbuf; >+ } >+ spin_unlock_irqrestore(&chan->lock, flags); >+ >+ return amnt; >+} >+ >+static int num_filled_bufs(struct dahdi_chan *chan) >+{ >+ int range1, range2; >+ >+ if (chan->inwritebuf < 0) { >+ return chan->numbufs; >+ } >+ >+ if (chan->outwritebuf < 0) { >+ return 0; >+ } >+ >+ if (chan->outwritebuf <= chan->inwritebuf) { >+ return chan->inwritebuf - chan->outwritebuf; >+ } >+ >+ /* This means (in > out) and we have wrap around */ >+ range1 = chan->numbufs - chan->outwritebuf; >+ range2 = chan->inwritebuf; >+ >+ return range1 + range2; >+} >+ >+static ssize_t dahdi_chan_write(struct file *file, const char *usrbuf, size_t count, int unit) >+{ >+ unsigned long flags; >+ struct dahdi_chan *chan = chans[unit]; >+ int res, amnt, oldbuf, rv, x; >+ >+ /* Make sure count never exceeds 65k, and make sure it's unsigned */ >+ count &= 0xffff; >+ >+ if (!chan) >+ return -EINVAL; >+ >+ if (count < 1) { >+ return -EINVAL; >+ } >+ >+ for (;;) { >+ spin_lock_irqsave(&chan->lock, flags); >+ if ((chan->curtone || chan->pdialcount) && !(chan->flags & DAHDI_FLAG_PSEUDO)) { >+ chan->curtone = NULL; >+ chan->tonep = 0; >+ chan->dialing = 0; >+ chan->txdialbuf[0] = '\0'; >+ chan->pdialcount = 0; >+ } >+ if (chan->eventinidx != chan->eventoutidx) { >+ spin_unlock_irqrestore(&chan->lock, flags); >+ return -ELAST; >+ } >+ res = chan->inwritebuf; >+ spin_unlock_irqrestore(&chan->lock, flags); >+ if (res >= 0) >+ break; >+ if (file->f_flags & O_NONBLOCK) { >+#ifdef BUFFER_DEBUG >+ printk("Error: Nonblock\n"); >+#endif >+ return -EAGAIN; >+ } >+ /* Wait for something to be available */ >+ rv = schluffen(&chan->writebufq); >+ if (rv) { >+ return rv; >+ } >+ } >+ >+ amnt = count; >+ if (chan->flags & DAHDI_FLAG_LINEAR) { >+ if (amnt > (chan->blocksize << 1)) >+ amnt = chan->blocksize << 1; >+ } else { >+ if (amnt > chan->blocksize) >+ amnt = chan->blocksize; >+ } >+ >+#ifdef CONFIG_DAHDI_DEBUG >+ module_printk(KERN_NOTICE, "dahdi_chan_write(unit: %d, res: %d, outwritebuf: %d amnt: %d\n", >+ unit, res, chan->outwritebuf, amnt); >+#endif >+#if 0 >+ if ((unit == 24) || (unit == 48) || (unit == 16) || (unit == 47)) { >+ int x; >+ module_printk(KERN_NOTICE, "dahdi_chan_write/in(unit: %d, res: %d, outwritebuf: %d amnt: %d, txdisable: %d)\n", >+ unit, res, chan->outwritebuf, amnt, chan->txdisable); >+ module_printk(KERN_DEBUG, "\t("); for (x = 0; x < amnt; x++) module_printk(KERN_DEBUG, (x ? " %02x" : "%02x"), (unsigned char)usrbuf[x]); >+ module_printk(KERN_DEBUG, ")\n"); >+ } >+#endif >+ >+ if (amnt) { >+ if (chan->flags & DAHDI_FLAG_LINEAR) { >+ /* There seems to be a max stack size, so we have >+ to do this in smaller pieces */ >+ short lindata[128]; >+ int left = amnt >> 1; /* amnt is in bytes */ >+ int pos = 0; >+ int pass; >+ while (left) { >+ pass = left; >+ if (pass > 128) >+ pass = 128; >+ if (copy_from_user(lindata, usrbuf + (pos << 1), pass << 1)) { >+ return -EFAULT; >+ } >+ left -= pass; >+ for (x = 0; x < pass; x++) >+ chan->writebuf[res][x + pos] = DAHDI_LIN2X(lindata[x], chan); >+ pos += pass; >+ } >+ chan->writen[res] = amnt >> 1; >+ } else { >+ if (copy_from_user(chan->writebuf[res], usrbuf, amnt)) { >+ return -EFAULT; >+ } >+ chan->writen[res] = amnt; >+ } >+ chan->writeidx[res] = 0; >+ if (chan->flags & DAHDI_FLAG_FCS) >+ calc_fcs(chan, res); >+ oldbuf = res; >+ spin_lock_irqsave(&chan->lock, flags); >+ chan->inwritebuf = (res + 1) % chan->numbufs; >+ >+ if (chan->inwritebuf == chan->outwritebuf) { >+ /* Don't stomp on the transmitter, just wait for them to >+ wake us up */ >+ chan->inwritebuf = -1; >+ /* Make sure the transmitter is transmitting in case of POLICY_WHEN_FULL */ >+ chan->txdisable = 0; >+ } >+ >+ if (chan->outwritebuf < 0) { >+ /* Okay, the interrupt handler has been waiting for us. Give them a buffer */ >+ chan->outwritebuf = oldbuf; >+ } >+ >+ if ((chan->txbufpolicy == DAHDI_POLICY_HALF_FULL) && (chan->txdisable)) { >+ if (num_filled_bufs(chan) >= (chan->numbufs >> 1)) { >+#ifdef BUFFER_DEBUG >+ printk("Reached buffer fill mark of %d\n", num_filled_bufs(chan)); >+#endif >+ chan->txdisable = 0; >+ } >+ } >+ >+#ifdef BUFFER_DEBUG >+ if ((chan->statcount <= 0) || (amnt != 128) || (num_filled_bufs(chan) != chan->lastnumbufs)) { >+ printk("amnt: %d Number of filled buffers: %d\n", amnt, num_filled_bufs(chan)); >+ chan->statcount = 32000; >+ chan->lastnumbufs = num_filled_bufs(chan); >+ } >+#endif >+ >+ spin_unlock_irqrestore(&chan->lock, flags); >+ >+ if (chan->flags & DAHDI_FLAG_NOSTDTXRX && chan->span->hdlc_hard_xmit) >+ chan->span->hdlc_hard_xmit(chan); >+ } >+ return amnt; >+} >+ >+static int dahdi_ctl_open(struct inode *inode, struct file *file) >+{ >+ /* Nothing to do, really */ >+ return 0; >+} >+ >+static int dahdi_chan_open(struct inode *inode, struct file *file) >+{ >+ /* Nothing to do here for now either */ >+ return 0; >+} >+ >+static int dahdi_ctl_release(struct inode *inode, struct file *file) >+{ >+ /* Nothing to do */ >+ return 0; >+} >+ >+static int dahdi_chan_release(struct inode *inode, struct file *file) >+{ >+ /* Nothing to do for now */ >+ return 0; >+} >+ >+static void set_txtone(struct dahdi_chan *ss, int fac, int init_v2, int init_v3) >+{ >+ if (fac == 0) { >+ ss->v2_1 = 0; >+ ss->v3_1 = 0; >+ return; >+ } >+ ss->txtone = fac; >+ ss->v1_1 = 0; >+ ss->v2_1 = init_v2; >+ ss->v3_1 = init_v3; >+ return; >+} >+ >+static void dahdi_rbs_sethook(struct dahdi_chan *chan, int txsig, int txstate, >+ int timeout) >+{ >+ static const struct { >+ unsigned int sig_type; >+ /* Index is dahdi_txsig enum */ >+ unsigned int bits[DAHDI_TXSIG_TOTAL]; >+ } outs[NUM_SIGS] = { >+ { >+ /* >+ * We set the idle case of the DAHDI_SIG_NONE to this pattern to make idle E1 CAS >+ * channels happy. Should not matter with T1, since on an un-configured channel, >+ * who cares what the sig bits are as long as they are stable >+ */ >+ .sig_type = DAHDI_SIG_NONE, >+ .bits[DAHDI_TXSIG_ONHOOK] = DAHDI_BITS_ACD, >+ }, { >+ .sig_type = DAHDI_SIG_EM, >+ .bits[DAHDI_TXSIG_OFFHOOK] = DAHDI_BITS_ABCD, >+ .bits[DAHDI_TXSIG_START] = DAHDI_BITS_ABCD, >+ }, { >+ .sig_type = DAHDI_SIG_FXSLS, >+ .bits[DAHDI_TXSIG_ONHOOK] = DAHDI_BITS_BD, >+ .bits[DAHDI_TXSIG_OFFHOOK] = DAHDI_BITS_ABCD, >+ .bits[DAHDI_TXSIG_START] = DAHDI_BITS_ABCD, >+ }, { >+ .sig_type = DAHDI_SIG_FXSGS, >+ .bits[DAHDI_TXSIG_ONHOOK] = DAHDI_BITS_BD, >+ .bits[DAHDI_TXSIG_OFFHOOK] = DAHDI_BITS_ABCD, >+#ifndef CONFIG_CAC_GROUNDSTART >+ .bits[DAHDI_TXSIG_START] = DAHDI_BITS_AC, >+#endif >+ }, { >+ .sig_type = DAHDI_SIG_FXSKS, >+ .bits[DAHDI_TXSIG_ONHOOK] = DAHDI_BITS_BD, >+ .bits[DAHDI_TXSIG_OFFHOOK] = DAHDI_BITS_ABCD, >+ .bits[DAHDI_TXSIG_START] = DAHDI_BITS_ABCD, >+ }, { >+ .sig_type = DAHDI_SIG_FXOLS, >+ .bits[DAHDI_TXSIG_ONHOOK] = DAHDI_BITS_BD, >+ .bits[DAHDI_TXSIG_OFFHOOK] = DAHDI_BITS_BD, >+ }, { >+ .sig_type = DAHDI_SIG_FXOGS, >+ .bits[DAHDI_TXSIG_ONHOOK] = DAHDI_BITS_ABCD, >+ .bits[DAHDI_TXSIG_OFFHOOK] = DAHDI_BITS_BD, >+ }, { >+ .sig_type = DAHDI_SIG_FXOKS, >+ .bits[DAHDI_TXSIG_ONHOOK] = DAHDI_BITS_BD, >+ .bits[DAHDI_TXSIG_OFFHOOK] = DAHDI_BITS_BD, >+ .bits[DAHDI_TXSIG_KEWL] = DAHDI_BITS_ABCD, >+ }, { >+ .sig_type = DAHDI_SIG_SF, >+ .bits[DAHDI_TXSIG_ONHOOK] = DAHDI_BITS_BCD, >+ .bits[DAHDI_TXSIG_OFFHOOK] = DAHDI_BITS_ABCD, >+ .bits[DAHDI_TXSIG_START] = DAHDI_BITS_ABCD, >+ .bits[DAHDI_TXSIG_KEWL] = DAHDI_BITS_BCD, >+ }, { >+ .sig_type = DAHDI_SIG_EM_E1, >+ .bits[DAHDI_TXSIG_ONHOOK] = DAHDI_DBIT, >+ .bits[DAHDI_TXSIG_OFFHOOK] = DAHDI_BITS_ABD, >+ .bits[DAHDI_TXSIG_START] = DAHDI_BITS_ABD, >+ .bits[DAHDI_TXSIG_KEWL] = DAHDI_DBIT, >+ } >+ }; >+ int x; >+ >+ /* if no span, return doing nothing */ >+ if (!chan->span) >+ return; >+ >+ if (!chan->span->flags & DAHDI_FLAG_RBS) { >+ module_printk(KERN_NOTICE, "dahdi_rbs: Tried to set RBS hook state on non-RBS channel %s\n", chan->name); >+ return; >+ } >+ if ((txsig > 3) || (txsig < 0)) { >+ module_printk(KERN_NOTICE, "dahdi_rbs: Tried to set RBS hook state %d (> 3) on channel %s\n", txsig, chan->name); >+ return; >+ } >+ if (!chan->span->rbsbits && !chan->span->hooksig) { >+ module_printk(KERN_NOTICE, "dahdi_rbs: Tried to set RBS hook state %d on channel %s while span %s lacks rbsbits or hooksig function\n", >+ txsig, chan->name, chan->span->name); >+ return; >+ } >+ /* Don't do anything for RBS */ >+ if (chan->sig == DAHDI_SIG_DACS_RBS) >+ return; >+ chan->txstate = txstate; >+ >+ /* if tone signalling */ >+ if (chan->sig == DAHDI_SIG_SF) { >+ chan->txhooksig = txsig; >+ if (chan->txtone) { /* if set to make tone for tx */ >+ if ((txsig && !(chan->toneflags & DAHDI_REVERSE_TXTONE)) || >+ ((!txsig) && (chan->toneflags & DAHDI_REVERSE_TXTONE))) { >+ set_txtone(chan,chan->txtone,chan->tx_v2,chan->tx_v3); >+ } else { >+ set_txtone(chan,0,0,0); >+ } >+ } >+ chan->otimer = timeout * DAHDI_CHUNKSIZE; /* Otimer is timer in samples */ >+ return; >+ } >+ if (chan->span->hooksig) { >+ if (chan->txhooksig != txsig) { >+ chan->txhooksig = txsig; >+ chan->span->hooksig(chan, txsig); >+ } >+ chan->otimer = timeout * DAHDI_CHUNKSIZE; /* Otimer is timer in samples */ >+ return; >+ } else { >+ for (x = 0; x < NUM_SIGS; x++) { >+ if (outs[x].sig_type == chan->sig) { >+#ifdef CONFIG_DAHDI_DEBUG >+ module_printk(KERN_NOTICE, "Setting bits to %d for channel %s state %d in %d signalling\n", outs[x].bits[txsig], chan->name, txsig, chan->sig); >+#endif >+ chan->txhooksig = txsig; >+ chan->txsig = outs[x].bits[txsig]; >+ chan->span->rbsbits(chan, chan->txsig); >+ chan->otimer = timeout * DAHDI_CHUNKSIZE; /* Otimer is timer in samples */ >+ return; >+ } >+ } >+ } >+ module_printk(KERN_NOTICE, "dahdi_rbs: Don't know RBS signalling type %d on channel %s\n", chan->sig, chan->name); >+} >+ >+static int dahdi_cas_setbits(struct dahdi_chan *chan, int bits) >+{ >+ /* if no span, return as error */ >+ if (!chan->span) >+ return -1; >+ if (chan->span->rbsbits) { >+ chan->txsig = bits; >+ chan->span->rbsbits(chan, bits); >+ } else { >+ module_printk(KERN_NOTICE, "Huh? CAS setbits, but no RBS bits function\n"); >+ } >+ >+ return 0; >+} >+ >+static int dahdi_hangup(struct dahdi_chan *chan) >+{ >+ int x, res = 0; >+ >+ /* Can't hangup pseudo channels */ >+ if (!chan->span) >+ return 0; >+ >+ /* Can't hang up a clear channel */ >+ if (chan->flags & (DAHDI_FLAG_CLEAR | DAHDI_FLAG_NOSTDTXRX)) >+ return -EINVAL; >+ >+ chan->kewlonhook = 0; >+ >+ if ((chan->sig == DAHDI_SIG_FXSLS) || (chan->sig == DAHDI_SIG_FXSKS) || >+ (chan->sig == DAHDI_SIG_FXSGS)) { >+ chan->ringdebtimer = RING_DEBOUNCE_TIME; >+ } >+ >+ if (chan->span->flags & DAHDI_FLAG_RBS) { >+ if (chan->sig == DAHDI_SIG_CAS) { >+ dahdi_cas_setbits(chan, chan->idlebits); >+ } else if ((chan->sig == DAHDI_SIG_FXOKS) && (chan->txstate != DAHDI_TXSTATE_ONHOOK) >+ /* if other party is already on-hook we shouldn't do any battery drop */ >+ && !((chan->rxhooksig == DAHDI_RXSIG_ONHOOK) && (chan->itimer <= 0))) { >+ /* Do RBS signalling on the channel's behalf */ >+ dahdi_rbs_sethook(chan, DAHDI_TXSIG_KEWL, DAHDI_TXSTATE_KEWL, DAHDI_KEWLTIME); >+ } else >+ dahdi_rbs_sethook(chan, DAHDI_TXSIG_ONHOOK, DAHDI_TXSTATE_ONHOOK, 0); >+ } else { >+ /* Let the driver hang up the line if it wants to */ >+ if (chan->span->sethook) { >+ if (chan->txhooksig != DAHDI_ONHOOK) { >+ chan->txhooksig = DAHDI_ONHOOK; >+ res = chan->span->sethook(chan, DAHDI_ONHOOK); >+ } else >+ res = 0; >+ } >+ } >+ >+ /* if not registered yet, just return here */ >+ if (!test_bit(DAHDI_FLAGBIT_REGISTERED, &chan->flags)) >+ return res; >+ >+ /* Mark all buffers as empty */ >+ for (x = 0; x < chan->numbufs; x++) { >+ chan->writen[x] = >+ chan->writeidx[x]= >+ chan->readn[x]= >+ chan->readidx[x] = 0; >+ } >+ >+ if (chan->readbuf[0]) { >+ chan->inreadbuf = 0; >+ chan->inwritebuf = 0; >+ } else { >+ chan->inreadbuf = -1; >+ chan->inwritebuf = -1; >+ } >+ chan->outreadbuf = -1; >+ chan->outwritebuf = -1; >+ chan->dialing = 0; >+ chan->afterdialingtimer = 0; >+ chan->curtone = NULL; >+ chan->pdialcount = 0; >+ chan->cadencepos = 0; >+ chan->txdialbuf[0] = 0; >+ >+ return res; >+} >+ >+static int initialize_channel(struct dahdi_chan *chan) >+{ >+ int res; >+ unsigned long flags; >+ void *rxgain=NULL; >+ struct dahdi_echocan_state *ec_state; >+ const struct dahdi_echocan_factory *ec_current; >+ >+ if ((res = dahdi_reallocbufs(chan, DAHDI_DEFAULT_BLOCKSIZE, DAHDI_DEFAULT_NUM_BUFS))) >+ return res; >+ >+ spin_lock_irqsave(&chan->lock, flags); >+ >+ chan->rxbufpolicy = DAHDI_POLICY_IMMEDIATE; >+ chan->txbufpolicy = DAHDI_POLICY_IMMEDIATE; >+ >+ ec_state = chan->ec_state; >+ chan->ec_state = NULL; >+ ec_current = chan->ec_current; >+ chan->ec_current = NULL; >+ >+ chan->txdisable = 0; >+ chan->rxdisable = 0; >+ >+ chan->digitmode = DIGIT_MODE_DTMF; >+ chan->dialing = 0; >+ chan->afterdialingtimer = 0; >+ >+ chan->cadencepos = 0; >+ chan->firstcadencepos = 0; /* By default loop back to first cadence position */ >+ >+ /* HDLC & FCS stuff */ >+ fasthdlc_init(&chan->rxhdlc, (chan->flags & DAHDI_FLAG_HDLC56) ? FASTHDLC_MODE_56 : FASTHDLC_MODE_64); >+ fasthdlc_init(&chan->txhdlc, (chan->flags & DAHDI_FLAG_HDLC56) ? FASTHDLC_MODE_56 : FASTHDLC_MODE_64); >+ chan->infcs = PPP_INITFCS; >+ >+ /* Timings for RBS */ >+ chan->prewinktime = DAHDI_DEFAULT_PREWINKTIME; >+ chan->preflashtime = DAHDI_DEFAULT_PREFLASHTIME; >+ chan->winktime = DAHDI_DEFAULT_WINKTIME; >+ chan->flashtime = DAHDI_DEFAULT_FLASHTIME; >+ >+ if (chan->sig & __DAHDI_SIG_FXO) >+ chan->starttime = DAHDI_DEFAULT_RINGTIME; >+ else >+ chan->starttime = DAHDI_DEFAULT_STARTTIME; >+ chan->rxwinktime = DAHDI_DEFAULT_RXWINKTIME; >+ chan->rxflashtime = DAHDI_DEFAULT_RXFLASHTIME; >+ chan->debouncetime = DAHDI_DEFAULT_DEBOUNCETIME; >+ chan->pulsemaketime = DAHDI_DEFAULT_PULSEMAKETIME; >+ chan->pulsebreaktime = DAHDI_DEFAULT_PULSEBREAKTIME; >+ chan->pulseaftertime = DAHDI_DEFAULT_PULSEAFTERTIME; >+ >+ /* Initialize RBS timers */ >+ chan->itimerset = chan->itimer = chan->otimer = 0; >+ chan->ringdebtimer = 0; >+ >+ init_waitqueue_head(&chan->sel); >+ init_waitqueue_head(&chan->readbufq); >+ init_waitqueue_head(&chan->writebufq); >+ init_waitqueue_head(&chan->eventbufq); >+ init_waitqueue_head(&chan->txstateq); >+ >+ /* Reset conferences */ >+ reset_conf(chan); >+ >+ /* I/O Mask, etc */ >+ chan->iomask = 0; >+ /* release conference resource if any */ >+ if (chan->confna) >+ dahdi_check_conf(chan->confna); >+ if ((chan->sig & __DAHDI_SIG_DACS) != __DAHDI_SIG_DACS) { >+ chan->confna = 0; >+ chan->confmode = 0; >+ if (chan->span && chan->span->dacs) >+ chan->span->dacs(chan, NULL); >+ } >+ chan->_confn = 0; >+ memset(chan->conflast, 0, sizeof(chan->conflast)); >+ memset(chan->conflast1, 0, sizeof(chan->conflast1)); >+ memset(chan->conflast2, 0, sizeof(chan->conflast2)); >+ chan->confmute = 0; >+ chan->gotgs = 0; >+ chan->curtone = NULL; >+ chan->tonep = 0; >+ chan->pdialcount = 0; >+ if (chan->gainalloc && chan->rxgain) >+ rxgain = chan->rxgain; >+ chan->rxgain = defgain; >+ chan->txgain = defgain; >+ chan->gainalloc = 0; >+ chan->eventinidx = chan->eventoutidx = 0; >+ dahdi_set_law(chan,0); >+ dahdi_hangup(chan); >+ >+ /* Make sure that the audio flag is cleared on a clear channel */ >+ if ((chan->sig & DAHDI_SIG_CLEAR) || (chan->sig & DAHDI_SIG_HARDHDLC)) >+ chan->flags &= ~DAHDI_FLAG_AUDIO; >+ >+ if ((chan->sig == DAHDI_SIG_CLEAR) || (chan->sig == DAHDI_SIG_HARDHDLC)) >+ chan->flags &= ~(DAHDI_FLAG_PPP | DAHDI_FLAG_FCS | DAHDI_FLAG_HDLC); >+ >+ chan->flags &= ~DAHDI_FLAG_LINEAR; >+ if (chan->curzone) { >+ /* Take cadence from tone zone */ >+ memcpy(chan->ringcadence, chan->curzone->ringcadence, sizeof(chan->ringcadence)); >+ } else { >+ /* Do a default */ >+ memset(chan->ringcadence, 0, sizeof(chan->ringcadence)); >+ chan->ringcadence[0] = chan->starttime; >+ chan->ringcadence[1] = DAHDI_RINGOFFTIME; >+ } >+ >+ if (ec_state) { >+ ec_state->ops->echocan_free(chan, ec_state); >+ release_echocan(ec_current); >+ } >+ >+ spin_unlock_irqrestore(&chan->lock, flags); >+ >+ set_tone_zone(chan, -1); >+ >+ if (rxgain) >+ kfree(rxgain); >+ >+ return 0; >+} >+ >+static int dahdi_timing_open(struct inode *inode, struct file *file) >+{ >+ struct dahdi_timer *t; >+ unsigned long flags; >+ >+ if (!(t = kzalloc(sizeof(*t), GFP_KERNEL))) >+ return -ENOMEM; >+ >+ init_waitqueue_head(&t->sel); >+ INIT_LIST_HEAD(&t->list); >+ file->private_data = t; >+ >+ spin_lock_irqsave(&zaptimerlock, flags); >+ list_add(&t->list, &zaptimers); >+ spin_unlock_irqrestore(&zaptimerlock, flags); >+ >+ return 0; >+} >+ >+static int dahdi_timer_release(struct inode *inode, struct file *file) >+{ >+ struct dahdi_timer *t, *cur, *next; >+ unsigned long flags; >+ >+ if (!(t = file->private_data)) >+ return 0; >+ >+ spin_lock_irqsave(&zaptimerlock, flags); >+ >+ list_for_each_entry_safe(cur, next, &zaptimers, list) { >+ if (t == cur) { >+ list_del(&cur->list); >+ break; >+ } >+ } >+ >+ spin_unlock_irqrestore(&zaptimerlock, flags); >+ >+ if (!cur) { >+ module_printk(KERN_NOTICE, "Timer: Not on list??\n"); >+ return 0; >+ } >+ >+ kfree(cur); >+ >+ return 0; >+} >+ >+static int dahdi_specchan_open(struct inode *inode, struct file *file, int unit) >+{ >+ int res = 0; >+ >+ if (chans[unit] && chans[unit]->sig) { >+ /* Make sure we're not already open, a net device, or a slave device */ >+ if (chans[unit]->flags & DAHDI_FLAG_NETDEV) >+ res = -EBUSY; >+ else if (chans[unit]->master != chans[unit]) >+ res = -EBUSY; >+ else if ((chans[unit]->sig & __DAHDI_SIG_DACS) == __DAHDI_SIG_DACS) >+ res = -EBUSY; >+ else if (!test_and_set_bit(DAHDI_FLAGBIT_OPEN, &chans[unit]->flags)) { >+ unsigned long flags; >+ res = initialize_channel(chans[unit]); >+ if (res) { >+ /* Reallocbufs must have failed */ >+ clear_bit(DAHDI_FLAGBIT_OPEN, &chans[unit]->flags); >+ return res; >+ } >+ spin_lock_irqsave(&chans[unit]->lock, flags); >+ if (chans[unit]->flags & DAHDI_FLAG_PSEUDO) >+ chans[unit]->flags |= DAHDI_FLAG_AUDIO; >+ if (chans[unit]->span && chans[unit]->span->open) { >+ res = chans[unit]->span->open(chans[unit]); >+ } >+ if (!res) { >+ chans[unit]->file = file; >+ spin_unlock_irqrestore(&chans[unit]->lock, flags); >+ } else { >+ spin_unlock_irqrestore(&chans[unit]->lock, flags); >+ close_channel(chans[unit]); >+ clear_bit(DAHDI_FLAGBIT_OPEN, &chans[unit]->flags); >+ } >+ } else >+ res = -EBUSY; >+ } else >+ res = -ENXIO; >+ return res; >+} >+ >+static int dahdi_specchan_release(struct inode *node, struct file *file, int unit) >+{ >+ int res=0; >+ unsigned long flags; >+ >+ if (chans[unit]) { >+ /* Chan lock protects contents against potentially non atomic accesses. >+ * So if the pointer setting is not atomic, we should protect */ >+ spin_lock_irqsave(&chans[unit]->lock, flags); >+ chans[unit]->file = NULL; >+ spin_unlock_irqrestore(&chans[unit]->lock, flags); >+ close_channel(chans[unit]); >+ if (chans[unit]->span && chans[unit]->span->close) >+ res = chans[unit]->span->close(chans[unit]); >+ /* The channel might be destroyed by low-level driver span->close() */ >+ if(chans[unit]) >+ clear_bit(DAHDI_FLAGBIT_OPEN, &chans[unit]->flags); >+ } else >+ res = -ENXIO; >+ return res; >+} >+ >+static struct dahdi_chan *dahdi_alloc_pseudo(void) >+{ >+ struct dahdi_chan *pseudo; >+ >+ /* Don't allow /dev/dahdi/pseudo to open if there are no spans */ >+ if (maxspans < 1) >+ return NULL; >+ >+ if (!(pseudo = kzalloc(sizeof(*pseudo), GFP_KERNEL))) >+ return NULL; >+ >+ pseudo->sig = DAHDI_SIG_CLEAR; >+ pseudo->sigcap = DAHDI_SIG_CLEAR; >+ pseudo->flags = DAHDI_FLAG_PSEUDO | DAHDI_FLAG_AUDIO; >+ >+ if (dahdi_chan_reg(pseudo)) { >+ kfree(pseudo); >+ pseudo = NULL; >+ } else { >+ snprintf(pseudo->name, sizeof(pseudo->name)-1,"Pseudo/%d", pseudo->channo); >+ } >+ >+ return pseudo; >+} >+ >+static void dahdi_free_pseudo(struct dahdi_chan *pseudo) >+{ >+ if (pseudo) { >+ dahdi_chan_unreg(pseudo); >+ kfree(pseudo); >+ } >+} >+ >+static int dahdi_open(struct inode *inode, struct file *file) >+{ >+ int unit = UNIT(file); >+ struct dahdi_chan *chan; >+ /* Minor 0: Special "control" descriptor */ >+ if (!unit) >+ return dahdi_ctl_open(inode, file); >+ if (unit == 250) { >+ if (!dahdi_transcode_fops) { >+ if (request_module("dahdi_transcode")) { >+ return -ENXIO; >+ } >+ } >+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) >+ __MOD_INC_USE_COUNT (dahdi_transcode_fops->owner); >+#else >+ if (!try_module_get(dahdi_transcode_fops->owner)) { >+ return -ENXIO; >+ } >+#endif >+ if (dahdi_transcode_fops && dahdi_transcode_fops->open) { >+ return dahdi_transcode_fops->open(inode, file); >+ } else { >+ /* dahdi_transcode module should have exported a >+ * file_operations table. */ >+ WARN_ON(1); >+ } >+ return -ENXIO; >+ } >+ if (unit == 253) { >+ if (maxspans) { >+ return dahdi_timing_open(inode, file); >+ } else { >+ return -ENXIO; >+ } >+ } >+ if (unit == 254) >+ return dahdi_chan_open(inode, file); >+ if (unit == 255) { >+ if (maxspans) { >+ chan = dahdi_alloc_pseudo(); >+ if (chan) { >+ file->private_data = chan; >+ return dahdi_specchan_open(inode, file, chan->channo); >+ } else { >+ return -ENXIO; >+ } >+ } else >+ return -ENXIO; >+ } >+ return dahdi_specchan_open(inode, file, unit); >+} >+ >+#if 0 >+static int dahdi_open(struct inode *inode, struct file *file) >+{ >+ int res; >+ unsigned long flags; >+ spin_lock_irqsave(&bigzaplock, flags); >+ res = __dahdi_open(inode, file); >+ spin_unlock_irqrestore(&bigzaplock, flags); >+ return res; >+} >+#endif >+ >+static ssize_t dahdi_read(struct file *file, char *usrbuf, size_t count, loff_t *ppos) >+{ >+ int unit = UNIT(file); >+ struct dahdi_chan *chan; >+ >+ /* Can't read from control */ >+ if (!unit) { >+ return -EINVAL; >+ } >+ >+ if (unit == 253) >+ return -EINVAL; >+ >+ if (unit == 254) { >+ chan = file->private_data; >+ if (!chan) >+ return -EINVAL; >+ return dahdi_chan_read(file, usrbuf, count, chan->channo); >+ } >+ >+ if (unit == 255) { >+ chan = file->private_data; >+ if (!chan) { >+ module_printk(KERN_NOTICE, "No pseudo channel structure to read?\n"); >+ return -EINVAL; >+ } >+ return dahdi_chan_read(file, usrbuf, count, chan->channo); >+ } >+ if (count < 0) >+ return -EINVAL; >+ >+ return dahdi_chan_read(file, usrbuf, count, unit); >+} >+ >+static ssize_t dahdi_write(struct file *file, const char *usrbuf, size_t count, loff_t *ppos) >+{ >+ int unit = UNIT(file); >+ struct dahdi_chan *chan; >+ /* Can't read from control */ >+ if (!unit) >+ return -EINVAL; >+ if (count < 0) >+ return -EINVAL; >+ if (unit == 253) >+ return -EINVAL; >+ if (unit == 254) { >+ chan = file->private_data; >+ if (!chan) >+ return -EINVAL; >+ return dahdi_chan_write(file, usrbuf, count, chan->channo); >+ } >+ if (unit == 255) { >+ chan = file->private_data; >+ if (!chan) { >+ module_printk(KERN_NOTICE, "No pseudo channel structure to read?\n"); >+ return -EINVAL; >+ } >+ return dahdi_chan_write(file, usrbuf, count, chan->channo); >+ } >+ return dahdi_chan_write(file, usrbuf, count, unit); >+ >+} >+ >+static int dahdi_set_default_zone(int defzone) >+{ >+ if ((defzone < 0) || (defzone >= DAHDI_TONE_ZONE_MAX)) >+ return -EINVAL; >+ write_lock(&zone_lock); >+ if (!tone_zones[defzone]) { >+ write_unlock(&zone_lock); >+ return -EINVAL; >+ } >+ if ((default_zone != -1) && tone_zones[default_zone]) >+ atomic_dec(&tone_zones[default_zone]->refcount); >+ atomic_inc(&tone_zones[defzone]->refcount); >+ default_zone = defzone; >+ write_unlock(&zone_lock); >+ return 0; >+} >+ >+/* No bigger than 32k for everything per tone zone */ >+#define MAX_SIZE 32768 >+/* No more than 128 subtones */ >+#define MAX_TONES 128 >+ >+/* The tones to be loaded can (will) be a mix of regular tones, >+ DTMF tones and MF tones. We need to load DTMF and MF tones >+ a bit differently than regular tones because their storage >+ format is much simpler (an array structure field of the zone >+ structure, rather an array of pointers). >+*/ >+static int ioctl_load_zone(unsigned long data) >+{ >+ struct dahdi_tone *samples[MAX_TONES] = { NULL, }; >+ short next[MAX_TONES] = { 0, }; >+ struct dahdi_tone_def_header th; >+ struct dahdi_tone_def td; >+ struct dahdi_zone *z; >+ struct dahdi_tone *t; >+ void *slab, *ptr; >+ int x; >+ size_t space; >+ size_t size; >+ int res; >+ >+ if (copy_from_user(&th, (struct dahdi_tone_def_header *) data, sizeof(th))) >+ return -EFAULT; >+ >+ data += sizeof(th); >+ >+ if ((th.count < 0) || (th.count > MAX_TONES)) { >+ module_printk(KERN_NOTICE, "Too many tones included\n"); >+ return -EINVAL; >+ } >+ >+ space = size = sizeof(*z) + th.count * sizeof(*t); >+ >+ if (size > MAX_SIZE) >+ return -E2BIG; >+ >+ if (!(z = ptr = slab = kzalloc(size, GFP_KERNEL))) >+ return -ENOMEM; >+ >+ ptr += sizeof(*z); >+ space -= sizeof(*z); >+ >+ dahdi_copy_string(z->name, th.name, sizeof(z->name)); >+ >+ for (x = 0; x < DAHDI_MAX_CADENCE; x++) >+ z->ringcadence[x] = th.ringcadence[x]; >+ >+ atomic_set(&z->refcount, 0); >+ >+ for (x = 0; x < th.count; x++) { >+ enum { >+ REGULAR_TONE, >+ DTMF_TONE, >+ MFR1_TONE, >+ MFR2_FWD_TONE, >+ MFR2_REV_TONE, >+ } tone_type; >+ >+ if (space < sizeof(*t)) { >+ kfree(slab); >+ module_printk(KERN_NOTICE, "Insufficient tone zone space\n"); >+ return -EINVAL; >+ } >+ >+ if (copy_from_user(&td, (struct dahdi_tone_def *) data, sizeof(td))) { >+ kfree(slab); >+ return -EFAULT; >+ } >+ >+ data += sizeof(td); >+ >+ if ((td.tone >= 0) && (td.tone < DAHDI_TONE_MAX)) { >+ tone_type = REGULAR_TONE; >+ >+ t = samples[x] = ptr; >+ >+ space -= sizeof(*t); >+ ptr += sizeof(*t); >+ >+ /* Remember which sample is next */ >+ next[x] = td.next; >+ >+ /* Make sure the "next" one is sane */ >+ if ((next[x] >= th.count) || (next[x] < 0)) { >+ module_printk(KERN_NOTICE, "Invalid 'next' pointer: %d\n", next[x]); >+ kfree(slab); >+ return -EINVAL; >+ } >+ } else if ((td.tone >= DAHDI_TONE_DTMF_BASE) && >+ (td.tone <= DAHDI_TONE_DTMF_MAX)) { >+ tone_type = DTMF_TONE; >+ td.tone -= DAHDI_TONE_DTMF_BASE; >+ t = &z->dtmf[td.tone]; >+ } else if ((td.tone >= DAHDI_TONE_MFR1_BASE) && >+ (td.tone <= DAHDI_TONE_MFR1_MAX)) { >+ tone_type = MFR1_TONE; >+ td.tone -= DAHDI_TONE_MFR1_BASE; >+ t = &z->mfr1[td.tone]; >+ } else if ((td.tone >= DAHDI_TONE_MFR2_FWD_BASE) && >+ (td.tone <= DAHDI_TONE_MFR2_FWD_MAX)) { >+ tone_type = MFR2_FWD_TONE; >+ td.tone -= DAHDI_TONE_MFR2_FWD_BASE; >+ t = &z->mfr2_fwd[td.tone]; >+ } else if ((td.tone >= DAHDI_TONE_MFR2_REV_BASE) && >+ (td.tone <= DAHDI_TONE_MFR2_REV_MAX)) { >+ tone_type = MFR2_REV_TONE; >+ td.tone -= DAHDI_TONE_MFR2_REV_BASE; >+ t = &z->mfr2_rev[td.tone]; >+ } else { >+ module_printk(KERN_NOTICE, "Invalid tone (%d) defined\n", td.tone); >+ kfree(slab); >+ return -EINVAL; >+ } >+ >+ t->fac1 = td.fac1; >+ t->init_v2_1 = td.init_v2_1; >+ t->init_v3_1 = td.init_v3_1; >+ t->fac2 = td.fac2; >+ t->init_v2_2 = td.init_v2_2; >+ t->init_v3_2 = td.init_v3_2; >+ t->modulate = td.modulate; >+ >+ switch (tone_type) { >+ case REGULAR_TONE: >+ t->tonesamples = td.samples; >+ if (!z->tones[td.tone]) >+ z->tones[td.tone] = t; >+ break; >+ case DTMF_TONE: >+ t->tonesamples = global_dialparams.dtmf_tonelen; >+ t->next = &dtmf_silence; >+ z->dtmf_continuous[td.tone] = *t; >+ z->dtmf_continuous[td.tone].next = &z->dtmf_continuous[td.tone]; >+ break; >+ case MFR1_TONE: >+ switch (td.tone + DAHDI_TONE_MFR1_BASE) { >+ case DAHDI_TONE_MFR1_KP: >+ case DAHDI_TONE_MFR1_ST: >+ case DAHDI_TONE_MFR1_STP: >+ case DAHDI_TONE_MFR1_ST2P: >+ case DAHDI_TONE_MFR1_ST3P: >+ /* signaling control tones are always 100ms */ >+ t->tonesamples = 100 * DAHDI_CHUNKSIZE; >+ break; >+ default: >+ t->tonesamples = global_dialparams.mfv1_tonelen; >+ break; >+ } >+ t->next = &mfr1_silence; >+ break; >+ case MFR2_FWD_TONE: >+ t->tonesamples = global_dialparams.mfr2_tonelen; >+ t->next = &dtmf_silence; >+ z->mfr2_fwd_continuous[td.tone] = *t; >+ z->mfr2_fwd_continuous[td.tone].next = &z->mfr2_fwd_continuous[td.tone]; >+ break; >+ case MFR2_REV_TONE: >+ t->tonesamples = global_dialparams.mfr2_tonelen; >+ t->next = &dtmf_silence; >+ z->mfr2_rev_continuous[td.tone] = *t; >+ z->mfr2_rev_continuous[td.tone].next = &z->mfr2_rev_continuous[td.tone]; >+ break; >+ } >+ } >+ >+ for (x = 0; x < th.count; x++) { >+ if (samples[x]) >+ samples[x]->next = samples[next[x]]; >+ } >+ >+ if ((res = dahdi_register_tone_zone(th.zone, z))) { >+ kfree(slab); >+ } else { >+ if ( -1 == default_zone ) { >+ dahdi_set_default_zone(th.zone); >+ } >+ } >+ >+ return res; >+} >+ >+void dahdi_init_tone_state(struct dahdi_tone_state *ts, struct dahdi_tone *zt) >+{ >+ ts->v1_1 = 0; >+ ts->v2_1 = zt->init_v2_1; >+ ts->v3_1 = zt->init_v3_1; >+ ts->v1_2 = 0; >+ ts->v2_2 = zt->init_v2_2; >+ ts->v3_2 = zt->init_v3_2; >+ ts->modulate = zt->modulate; >+} >+ >+struct dahdi_tone *dahdi_mf_tone(const struct dahdi_chan *chan, char digit, int digitmode) >+{ >+ unsigned int tone_index; >+ >+ if (!chan->curzone) { >+ static int __warnonce = 1; >+ if (__warnonce) { >+ __warnonce = 0; >+ /* The tonezones are loaded by dahdi_cfg based on /etc/dahdi/system.conf. */ >+ module_printk(KERN_WARNING, "Cannot get dtmf tone until tone zone is loaded.\n"); >+ } >+ return NULL; >+ } >+ >+ switch (digitmode) { >+ case DIGIT_MODE_PULSE: >+ /* We should only get here with a pulse digit if we need >+ * to "dial" 'W' (wait 0.5 second) >+ */ >+ if (digit == 'W') >+ return &tone_pause; >+ >+ return NULL; >+ /* You should not get here */ >+ case DIGIT_MODE_DTMF: >+ switch (digit) { >+ case '0': >+ case '1': >+ case '2': >+ case '3': >+ case '4': >+ case '5': >+ case '6': >+ case '7': >+ case '8': >+ case '9': >+ tone_index = DAHDI_TONE_DTMF_0 + (digit - '0'); >+ break; >+ case '*': >+ tone_index = DAHDI_TONE_DTMF_s; >+ break; >+ case '#': >+ tone_index = DAHDI_TONE_DTMF_p; >+ break; >+ case 'A': >+ case 'B': >+ case 'C': >+ case 'D': >+ tone_index = DAHDI_TONE_DTMF_A + (digit - 'A'); >+ case 'W': >+ return &tone_pause; >+ default: >+ return NULL; >+ } >+ return &chan->curzone->dtmf[tone_index - DAHDI_TONE_DTMF_BASE]; >+ case DIGIT_MODE_MFR1: >+ switch (digit) { >+ case '0': >+ case '1': >+ case '2': >+ case '3': >+ case '4': >+ case '5': >+ case '6': >+ case '7': >+ case '8': >+ case '9': >+ tone_index = DAHDI_TONE_MFR1_0 + (digit - '0'); >+ break; >+ case '*': >+ tone_index = DAHDI_TONE_MFR1_KP; >+ break; >+ case '#': >+ tone_index = DAHDI_TONE_MFR1_ST; >+ break; >+ case 'A': >+ tone_index = DAHDI_TONE_MFR1_STP; >+ break; >+ case 'B': >+ tone_index = DAHDI_TONE_MFR1_ST2P; >+ break; >+ case 'C': >+ tone_index = DAHDI_TONE_MFR1_ST3P; >+ break; >+ case 'W': >+ return &tone_pause; >+ default: >+ return NULL; >+ } >+ return &chan->curzone->mfr1[tone_index - DAHDI_TONE_MFR1_BASE]; >+ case DIGIT_MODE_MFR2_FWD: >+ switch (digit) { >+ case '1': >+ case '2': >+ case '3': >+ case '4': >+ case '5': >+ case '6': >+ case '7': >+ case '8': >+ case '9': >+ tone_index = DAHDI_TONE_MFR2_FWD_1 + (digit - '1'); >+ break; >+ case 'A': >+ case 'B': >+ case 'C': >+ case 'D': >+ case 'E': >+ case 'F': >+ tone_index = DAHDI_TONE_MFR2_FWD_10 + (digit - 'A'); >+ break; >+ case 'W': >+ return &tone_pause; >+ default: >+ return NULL; >+ } >+ return &chan->curzone->mfr2_fwd[tone_index - DAHDI_TONE_MFR2_FWD_BASE]; >+ case DIGIT_MODE_MFR2_REV: >+ switch (digit) { >+ case '1': >+ case '2': >+ case '3': >+ case '4': >+ case '5': >+ case '6': >+ case '7': >+ case '8': >+ case '9': >+ tone_index = DAHDI_TONE_MFR2_REV_1 + (digit - '1'); >+ break; >+ case 'A': >+ case 'B': >+ case 'C': >+ case 'D': >+ case 'E': >+ case 'F': >+ tone_index = DAHDI_TONE_MFR2_REV_10 + (digit - 'A'); >+ break; >+ case 'W': >+ return &tone_pause; >+ default: >+ return NULL; >+ } >+ return &chan->curzone->mfr2_rev[tone_index - DAHDI_TONE_MFR2_REV_BASE]; >+ default: >+ return NULL; >+ } >+} >+ >+static void __do_dtmf(struct dahdi_chan *chan) >+{ >+ char c; >+ >+ /* Called with chan->lock held */ >+ while ((c = chan->txdialbuf[0])) { >+ memmove(chan->txdialbuf, chan->txdialbuf + 1, sizeof(chan->txdialbuf) - 1); >+ switch (c) { >+ case 'T': >+ chan->digitmode = DIGIT_MODE_DTMF; >+ chan->tonep = 0; >+ break; >+ case 'M': >+ chan->digitmode = DIGIT_MODE_MFR1; >+ chan->tonep = 0; >+ break; >+ case 'O': >+ chan->digitmode = DIGIT_MODE_MFR2_FWD; >+ chan->tonep = 0; >+ break; >+ case 'R': >+ chan->digitmode = DIGIT_MODE_MFR2_REV; >+ chan->tonep = 0; >+ break; >+ case 'P': >+ chan->digitmode = DIGIT_MODE_PULSE; >+ chan->tonep = 0; >+ break; >+ default: >+ if ((c != 'W') && (chan->digitmode == DIGIT_MODE_PULSE)) { >+ if ((c >= '0') && (c <= '9') && (chan->txhooksig == DAHDI_TXSIG_OFFHOOK)) { >+ chan->pdialcount = (c == '0') ? 10 : c - '0'; >+ dahdi_rbs_sethook(chan, DAHDI_TXSIG_ONHOOK, DAHDI_TXSTATE_PULSEBREAK, >+ chan->pulsebreaktime); >+ return; >+ } >+ } else { >+ chan->curtone = dahdi_mf_tone(chan, c, chan->digitmode); >+ chan->tonep = 0; >+ if (chan->curtone) { >+ dahdi_init_tone_state(&chan->ts, chan->curtone); >+ return; >+ } >+ } >+ } >+ } >+ >+ /* Notify userspace process if there is nothing left */ >+ chan->dialing = 0; >+ __qevent(chan, DAHDI_EVENT_DIALCOMPLETE); >+} >+ >+static int dahdi_release(struct inode *inode, struct file *file) >+{ >+ int unit = UNIT(file); >+ int res; >+ struct dahdi_chan *chan; >+ >+ if (!unit) >+ return dahdi_ctl_release(inode, file); >+ if (unit == 253) { >+ return dahdi_timer_release(inode, file); >+ } >+ if (unit == 250) { >+ /* We should not be here because the dahdi_transcode.ko module >+ * should have updated the file_operations for this file >+ * handle when the file was opened. */ >+ WARN_ON(1); >+ return -EFAULT; >+ } >+ if (unit == 254) { >+ chan = file->private_data; >+ if (!chan) >+ return dahdi_chan_release(inode, file); >+ else >+ return dahdi_specchan_release(inode, file, chan->channo); >+ } >+ if (unit == 255) { >+ chan = file->private_data; >+ if (chan) { >+ res = dahdi_specchan_release(inode, file, chan->channo); >+ dahdi_free_pseudo(chan); >+ } else { >+ module_printk(KERN_NOTICE, "Pseudo release and no private data??\n"); >+ res = 0; >+ } >+ return res; >+ } >+ return dahdi_specchan_release(inode, file, unit); >+} >+ >+#if 0 >+static int dahdi_release(struct inode *inode, struct file *file) >+{ >+ /* Lock the big zap lock when handling a release */ >+ unsigned long flags; >+ int res; >+ spin_lock_irqsave(&bigzaplock, flags); >+ res = __dahdi_release(inode, file); >+ spin_unlock_irqrestore(&bigzaplock, flags); >+ return res; >+} >+#endif >+ >+ >+void dahdi_alarm_channel(struct dahdi_chan *chan, int alarms) >+{ >+ unsigned long flags; >+ >+ spin_lock_irqsave(&chan->lock, flags); >+ if (chan->chan_alarms != alarms) { >+ chan->chan_alarms = alarms; >+ dahdi_qevent_nolock(chan, alarms ? DAHDI_EVENT_ALARM : DAHDI_EVENT_NOALARM); >+ } >+ spin_unlock_irqrestore(&chan->lock, flags); >+} >+ >+void dahdi_alarm_notify(struct dahdi_span *span) >+{ >+ int x; >+ >+ span->alarms &= ~DAHDI_ALARM_LOOPBACK; >+ /* Determine maint status */ >+ if (span->maintstat || span->mainttimer) >+ span->alarms |= DAHDI_ALARM_LOOPBACK; >+ /* DON'T CHANGE THIS AGAIN. THIS WAS DONE FOR A REASON. >+ The expression (a != b) does *NOT* do the same thing >+ as ((!a) != (!b)) */ >+ /* if change in general state */ >+ if ((!span->alarms) != (!span->lastalarms)) { >+ span->lastalarms = span->alarms; >+ for (x = 0; x < span->channels; x++) >+ dahdi_alarm_channel(span->chans[x], span->alarms); >+ /* Switch to other master if current master in alarm */ >+ for (x=1; x<maxspans; x++) { >+ if (spans[x] && !spans[x]->alarms && (spans[x]->flags & DAHDI_FLAG_RUNNING)) { >+ if(master != spans[x]) >+ module_printk(KERN_NOTICE, "Master changed to %s\n", spans[x]->name); >+ master = spans[x]; >+ break; >+ } >+ } >+ } >+} >+ >+#define VALID_SPAN(j) do { \ >+ if ((j >= DAHDI_MAX_SPANS) || (j < 1)) \ >+ return -EINVAL; \ >+ if (!spans[j]) \ >+ return -ENXIO; \ >+} while(0) >+ >+#define CHECK_VALID_SPAN(j) do { \ >+ /* Start a given span */ \ >+ if (get_user(j, (int *)data)) \ >+ return -EFAULT; \ >+ VALID_SPAN(j); \ >+} while(0) >+ >+#define VALID_CHANNEL(j) do { \ >+ if ((j >= DAHDI_MAX_CHANNELS) || (j < 1)) \ >+ return -EINVAL; \ >+ if (!chans[j]) \ >+ return -ENXIO; \ >+} while(0) >+ >+static int dahdi_timer_ioctl(struct inode *node, struct file *file, unsigned int cmd, unsigned long data, struct dahdi_timer *timer) >+{ >+ int j; >+ unsigned long flags; >+ switch(cmd) { >+ case DAHDI_TIMERCONFIG: >+ get_user(j, (int *)data); >+ if (j < 0) >+ j = 0; >+ spin_lock_irqsave(&zaptimerlock, flags); >+ timer->ms = timer->pos = j; >+ spin_unlock_irqrestore(&zaptimerlock, flags); >+ break; >+ case DAHDI_TIMERACK: >+ get_user(j, (int *)data); >+ spin_lock_irqsave(&zaptimerlock, flags); >+ if ((j < 1) || (j > timer->tripped)) >+ j = timer->tripped; >+ timer->tripped -= j; >+ spin_unlock_irqrestore(&zaptimerlock, flags); >+ break; >+ case DAHDI_GETEVENT: /* Get event on queue */ >+ j = DAHDI_EVENT_NONE; >+ spin_lock_irqsave(&zaptimerlock, flags); >+ /* set up for no event */ >+ if (timer->tripped) >+ j = DAHDI_EVENT_TIMER_EXPIRED; >+ if (timer->ping) >+ j = DAHDI_EVENT_TIMER_PING; >+ spin_unlock_irqrestore(&zaptimerlock, flags); >+ put_user(j,(int *)data); >+ break; >+ case DAHDI_TIMERPING: >+ spin_lock_irqsave(&zaptimerlock, flags); >+ timer->ping = 1; >+ wake_up_interruptible(&timer->sel); >+ spin_unlock_irqrestore(&zaptimerlock, flags); >+ break; >+ case DAHDI_TIMERPONG: >+ spin_lock_irqsave(&zaptimerlock, flags); >+ timer->ping = 0; >+ spin_unlock_irqrestore(&zaptimerlock, flags); >+ break; >+ default: >+ return -ENOTTY; >+ } >+ return 0; >+} >+ >+static int dahdi_common_ioctl(struct inode *node, struct file *file, unsigned int cmd, unsigned long data, int unit) >+{ >+ union { >+ struct dahdi_gains gain; >+ struct dahdi_spaninfo spaninfo; >+ struct dahdi_params param; >+ } stack; >+ struct dahdi_chan *chan; >+ unsigned long flags; >+ unsigned char *txgain, *rxgain; >+ int i,j; >+ int return_master = 0; >+ size_t size_to_copy; >+ >+ switch(cmd) { >+ /* get channel parameters */ >+ case DAHDI_GET_PARAMS_V1: /* Intentional drop through. */ >+ case DAHDI_GET_PARAMS: >+ size_to_copy = sizeof(struct dahdi_params); >+ if (copy_from_user(&stack.param, (struct dahdi_params *) data, size_to_copy)) >+ return -EFAULT; >+ >+ /* check to see if the caller wants to receive our master channel number */ >+ if (stack.param.channo & DAHDI_GET_PARAMS_RETURN_MASTER) { >+ return_master = 1; >+ stack.param.channo &= ~DAHDI_GET_PARAMS_RETURN_MASTER; >+ } >+ >+ /* Pick the right channo's */ >+ if (!stack.param.channo || unit) { >+ stack.param.channo = unit; >+ } >+ /* Check validity of channel */ >+ VALID_CHANNEL(stack.param.channo); >+ chan = chans[stack.param.channo]; >+ >+ /* point to relevant structure */ >+ stack.param.sigtype = chan->sig; /* get signalling type */ >+ /* return non-zero if rx not in idle state */ >+ if (chan->span) { >+ j = dahdi_q_sig(chan); >+ if (j >= 0) { /* if returned with success */ >+ stack.param.rxisoffhook = ((chan->rxsig & (j >> 8)) != (j & 0xff)); >+ } else { >+ stack.param.rxisoffhook = ((chan->rxhooksig != DAHDI_RXSIG_ONHOOK) && >+ (chan->rxhooksig != DAHDI_RXSIG_INITIAL)); >+ } >+ } else if ((chan->txstate == DAHDI_TXSTATE_KEWL) || (chan->txstate == DAHDI_TXSTATE_AFTERKEWL)) >+ stack.param.rxisoffhook = 1; >+ else >+ stack.param.rxisoffhook = 0; >+ if (chan->span && chan->span->rbsbits && !(chan->sig & DAHDI_SIG_CLEAR)) { >+ stack.param.rxbits = chan->rxsig; >+ stack.param.txbits = chan->txsig; >+ stack.param.idlebits = chan->idlebits; >+ } else { >+ stack.param.rxbits = -1; >+ stack.param.txbits = -1; >+ stack.param.idlebits = 0; >+ } >+ if (chan->span && (chan->span->rbsbits || chan->span->hooksig) && >+ !(chan->sig & DAHDI_SIG_CLEAR)) { >+ stack.param.rxhooksig = chan->rxhooksig; >+ stack.param.txhooksig = chan->txhooksig; >+ } else { >+ stack.param.rxhooksig = -1; >+ stack.param.txhooksig = -1; >+ } >+ stack.param.prewinktime = chan->prewinktime; >+ stack.param.preflashtime = chan->preflashtime; >+ stack.param.winktime = chan->winktime; >+ stack.param.flashtime = chan->flashtime; >+ stack.param.starttime = chan->starttime; >+ stack.param.rxwinktime = chan->rxwinktime; >+ stack.param.rxflashtime = chan->rxflashtime; >+ stack.param.debouncetime = chan->debouncetime; >+ stack.param.channo = chan->channo; >+ stack.param.chan_alarms = chan->chan_alarms; >+ >+ /* if requested, put the master channel number in the top 16 bits of the result */ >+ if (return_master) >+ stack.param.channo |= chan->master->channo << 16; >+ >+ stack.param.pulsemaketime = chan->pulsemaketime; >+ stack.param.pulsebreaktime = chan->pulsebreaktime; >+ stack.param.pulseaftertime = chan->pulseaftertime; >+ if (chan->span) stack.param.spanno = chan->span->spanno; >+ else stack.param.spanno = 0; >+ dahdi_copy_string(stack.param.name, chan->name, sizeof(stack.param.name)); >+ stack.param.chanpos = chan->chanpos; >+ stack.param.sigcap = chan->sigcap; >+ /* Return current law */ >+ if (chan->xlaw == __dahdi_alaw) >+ stack.param.curlaw = DAHDI_LAW_ALAW; >+ else >+ stack.param.curlaw = DAHDI_LAW_MULAW; >+ >+ if (copy_to_user((struct dahdi_params *) data, &stack.param, size_to_copy)) >+ return -EFAULT; >+ >+ break; >+ /* set channel parameters */ >+ case DAHDI_SET_PARAMS: >+ if (copy_from_user(&stack.param, (struct dahdi_params *) data, sizeof(struct dahdi_params))) >+ return -EFAULT; >+ >+ stack.param.chan_alarms = 0; /* be explicit about the above */ >+ >+ /* Pick the right channo's */ >+ if (!stack.param.channo || unit) { >+ stack.param.channo = unit; >+ } >+ /* Check validity of channel */ >+ VALID_CHANNEL(stack.param.channo); >+ chan = chans[stack.param.channo]; >+ /* point to relevant structure */ >+ /* NOTE: sigtype is *not* included in this */ >+ /* get timing stack.paramters */ >+ chan->prewinktime = stack.param.prewinktime; >+ chan->preflashtime = stack.param.preflashtime; >+ chan->winktime = stack.param.winktime; >+ chan->flashtime = stack.param.flashtime; >+ chan->starttime = stack.param.starttime; >+ /* Update ringtime if not using a tone zone */ >+ if (!chan->curzone) >+ chan->ringcadence[0] = chan->starttime; >+ chan->rxwinktime = stack.param.rxwinktime; >+ chan->rxflashtime = stack.param.rxflashtime; >+ chan->debouncetime = stack.param.debouncetime; >+ chan->pulsemaketime = stack.param.pulsemaketime; >+ chan->pulsebreaktime = stack.param.pulsebreaktime; >+ chan->pulseaftertime = stack.param.pulseaftertime; >+ break; >+ case DAHDI_GETGAINS_V1: /* Intentional drop through. */ >+ case DAHDI_GETGAINS: /* get gain stuff */ >+ if (copy_from_user(&stack.gain,(struct dahdi_gains *) data,sizeof(stack.gain))) >+ return -EFAULT; >+ i = stack.gain.chan; /* get channel no */ >+ /* if zero, use current channel no */ >+ if (!i) i = unit; >+ /* make sure channel number makes sense */ >+ if ((i < 0) || (i > DAHDI_MAX_CHANNELS) || !chans[i]) return(-EINVAL); >+ >+ if (!(chans[i]->flags & DAHDI_FLAG_AUDIO)) return (-EINVAL); >+ stack.gain.chan = i; /* put the span # in here */ >+ for (j=0;j<256;j++) { >+ stack.gain.txgain[j] = chans[i]->txgain[j]; >+ stack.gain.rxgain[j] = chans[i]->rxgain[j]; >+ } >+ if (copy_to_user((struct dahdi_gains *) data,&stack.gain,sizeof(stack.gain))) >+ return -EFAULT; >+ break; >+ case DAHDI_SETGAINS: /* set gain stuff */ >+ if (copy_from_user(&stack.gain,(struct dahdi_gains *) data,sizeof(stack.gain))) >+ return -EFAULT; >+ i = stack.gain.chan; /* get channel no */ >+ /* if zero, use current channel no */ >+ if (!i) i = unit; >+ /* make sure channel number makes sense */ >+ if ((i < 0) || (i > DAHDI_MAX_CHANNELS) || !chans[i]) return(-EINVAL); >+ if (!(chans[i]->flags & DAHDI_FLAG_AUDIO)) return (-EINVAL); >+ >+ if (!(rxgain = kmalloc(512, GFP_KERNEL))) >+ return -ENOMEM; >+ >+ stack.gain.chan = i; /* put the span # in here */ >+ txgain = rxgain + 256; >+ >+ for (j=0;j<256;j++) { >+ rxgain[j] = stack.gain.rxgain[j]; >+ txgain[j] = stack.gain.txgain[j]; >+ } >+ >+ if (!memcmp(rxgain, defgain, 256) && >+ !memcmp(txgain, defgain, 256)) { >+ if (rxgain) >+ kfree(rxgain); >+ spin_lock_irqsave(&chans[i]->lock, flags); >+ if (chans[i]->gainalloc) >+ kfree(chans[i]->rxgain); >+ chans[i]->gainalloc = 0; >+ chans[i]->rxgain = defgain; >+ chans[i]->txgain = defgain; >+ spin_unlock_irqrestore(&chans[i]->lock, flags); >+ } else { >+ /* This is a custom gain setting */ >+ spin_lock_irqsave(&chans[i]->lock, flags); >+ if (chans[i]->gainalloc) >+ kfree(chans[i]->rxgain); >+ chans[i]->gainalloc = 1; >+ chans[i]->rxgain = rxgain; >+ chans[i]->txgain = txgain; >+ spin_unlock_irqrestore(&chans[i]->lock, flags); >+ } >+ if (copy_to_user((struct dahdi_gains *) data,&stack.gain,sizeof(stack.gain))) >+ return -EFAULT; >+ break; >+ case DAHDI_SPANSTAT: >+ size_to_copy = sizeof(struct dahdi_spaninfo); >+ if (copy_from_user(&stack.spaninfo, (struct dahdi_spaninfo *) data, size_to_copy)) >+ return -EFAULT; >+ i = stack.spaninfo.spanno; /* get specified span number */ >+ if ((i < 0) || (i >= maxspans)) return(-EINVAL); /* if bad span no */ >+ if (i == 0) { >+ /* if to figure it out for this chan */ >+ if (!chans[unit]) >+ return -EINVAL; >+ i = chans[unit]->span->spanno; >+ } >+ if (!spans[i]) >+ return -EINVAL; >+ stack.spaninfo.spanno = i; /* put the span # in here */ >+ stack.spaninfo.totalspans = 0; >+ if (maxspans) stack.spaninfo.totalspans = maxspans - 1; /* put total number of spans here */ >+ dahdi_copy_string(stack.spaninfo.desc, spans[i]->desc, sizeof(stack.spaninfo.desc)); >+ dahdi_copy_string(stack.spaninfo.name, spans[i]->name, sizeof(stack.spaninfo.name)); >+ stack.spaninfo.alarms = spans[i]->alarms; /* get alarm status */ >+ stack.spaninfo.bpvcount = spans[i]->bpvcount; /* get BPV count */ >+ stack.spaninfo.rxlevel = spans[i]->rxlevel; /* get rx level */ >+ stack.spaninfo.txlevel = spans[i]->txlevel; /* get tx level */ >+ stack.spaninfo.crc4count = spans[i]->crc4count; /* get CRC4 error count */ >+ stack.spaninfo.ebitcount = spans[i]->ebitcount; /* get E-bit error count */ >+ stack.spaninfo.fascount = spans[i]->fascount; /* get FAS error count */ >+ stack.spaninfo.irqmisses = spans[i]->irqmisses; /* get IRQ miss count */ >+ stack.spaninfo.syncsrc = spans[i]->syncsrc; /* get active sync source */ >+ stack.spaninfo.totalchans = spans[i]->channels; >+ stack.spaninfo.numchans = 0; >+ for (j = 0; j < spans[i]->channels; j++) { >+ if (spans[i]->chans[j]->sig) >+ stack.spaninfo.numchans++; >+ } >+ stack.spaninfo.lbo = spans[i]->lbo; >+ stack.spaninfo.lineconfig = spans[i]->lineconfig; >+ stack.spaninfo.irq = spans[i]->irq; >+ stack.spaninfo.linecompat = spans[i]->linecompat; >+ dahdi_copy_string(stack.spaninfo.lboname, dahdi_lboname(spans[i]->lbo), sizeof(stack.spaninfo.lboname)); >+ if (spans[i]->manufacturer) >+ dahdi_copy_string(stack.spaninfo.manufacturer, spans[i]->manufacturer, >+ sizeof(stack.spaninfo.manufacturer)); >+ if (spans[i]->devicetype) >+ dahdi_copy_string(stack.spaninfo.devicetype, spans[i]->devicetype, sizeof(stack.spaninfo.devicetype)); >+ dahdi_copy_string(stack.spaninfo.location, spans[i]->location, sizeof(stack.spaninfo.location)); >+ if (spans[i]->spantype) >+ dahdi_copy_string(stack.spaninfo.spantype, spans[i]->spantype, sizeof(stack.spaninfo.spantype)); >+ >+ if (copy_to_user((struct dahdi_spaninfo *) data, &stack.spaninfo, size_to_copy)) >+ return -EFAULT; >+ break; >+ case DAHDI_CHANDIAG_V1: /* Intentional drop through. */ >+ case DAHDI_CHANDIAG: >+ { >+ /* there really is no need to initialize this structure because when it is used it has >+ * already been completely overwritten, but apparently the compiler cannot figure that >+ * out and warns about uninitialized usage... so initialize it. >+ */ >+ struct dahdi_echocan_state ec_state = { .ops = NULL, }; >+ >+ get_user(j, (int *) data); /* get channel number from user */ >+ /* make sure its a valid channel number */ >+ if ((j < 1) || (j >= maxchans)) >+ return -EINVAL; >+ /* if channel not mapped, not there */ >+ if (!chans[j]) >+ return -EINVAL; >+ >+ chan = kmalloc(sizeof(*chan), GFP_KERNEL); >+ if (!chan) >+ return -ENOMEM; >+ >+ /* lock channel */ >+ spin_lock_irqsave(&chans[j]->lock, flags); >+ /* make static copy of channel */ >+ *chan = *chans[j]; >+ if (chan->ec_state) { >+ ec_state = *chan->ec_state; >+ } >+ /* release it. */ >+ spin_unlock_irqrestore(&chans[j]->lock, flags); >+ >+ module_printk(KERN_INFO, "Dump of DAHDI Channel %d (%s,%d,%d):\n\n",j, >+ chan->name, chan->channo, chan->chanpos); >+ module_printk(KERN_INFO, "flags: %x hex, writechunk: %p, readchunk: %p\n", >+ (unsigned int) chan->flags, chan->writechunk, chan->readchunk); >+ module_printk(KERN_INFO, "rxgain: %p, txgain: %p, gainalloc: %d\n", >+ chan->rxgain, chan->txgain, chan->gainalloc); >+ module_printk(KERN_INFO, "span: %p, sig: %x hex, sigcap: %x hex\n", >+ chan->span, chan->sig, chan->sigcap); >+ module_printk(KERN_INFO, "inreadbuf: %d, outreadbuf: %d, inwritebuf: %d, outwritebuf: %d\n", >+ chan->inreadbuf, chan->outreadbuf, chan->inwritebuf, chan->outwritebuf); >+ module_printk(KERN_INFO, "blocksize: %d, numbufs: %d, txbufpolicy: %d, txbufpolicy: %d\n", >+ chan->blocksize, chan->numbufs, chan->txbufpolicy, chan->rxbufpolicy); >+ module_printk(KERN_INFO, "txdisable: %d, rxdisable: %d, iomask: %d\n", >+ chan->txdisable, chan->rxdisable, chan->iomask); >+ module_printk(KERN_INFO, "curzone: %p, tonezone: %d, curtone: %p, tonep: %d\n", >+ chan->curzone, chan->tonezone, chan->curtone, chan->tonep); >+ module_printk(KERN_INFO, "digitmode: %d, txdialbuf: %s, dialing: %d, aftdialtimer: %d, cadpos. %d\n", >+ chan->digitmode, chan->txdialbuf, chan->dialing, >+ chan->afterdialingtimer, chan->cadencepos); >+ module_printk(KERN_INFO, "confna: %d, confn: %d, confmode: %d, confmute: %d\n", >+ chan->confna, chan->_confn, chan->confmode, chan->confmute); >+ module_printk(KERN_INFO, "ec: %p, deflaw: %d, xlaw: %p\n", >+ chan->ec_state, chan->deflaw, chan->xlaw); >+ if (chan->ec_state) { >+ module_printk(KERN_INFO, "echostate: %02x, echotimer: %d, echolastupdate: %d\n", >+ ec_state.status.mode, ec_state.status.pretrain_timer, ec_state.status.last_train_tap); >+ } >+ module_printk(KERN_INFO, "itimer: %d, otimer: %d, ringdebtimer: %d\n\n", >+ chan->itimer, chan->otimer, chan->ringdebtimer); >+ kfree(chan); >+ break; >+ } >+ default: >+ return -ENOTTY; >+ } >+ return 0; >+} >+ >+static int (*dahdi_dynamic_ioctl)(unsigned int cmd, unsigned long data); >+ >+void dahdi_set_dynamic_ioctl(int (*func)(unsigned int cmd, unsigned long data)) >+{ >+ dahdi_dynamic_ioctl = func; >+} >+ >+static int (*dahdi_hpec_ioctl)(unsigned int cmd, unsigned long data); >+ >+void dahdi_set_hpec_ioctl(int (*func)(unsigned int cmd, unsigned long data)) >+{ >+ dahdi_hpec_ioctl = func; >+} >+ >+static void recalc_slaves(struct dahdi_chan *chan) >+{ >+ int x; >+ struct dahdi_chan *last = chan; >+ >+ /* Makes no sense if you don't have a span */ >+ if (!chan->span) >+ return; >+ >+#ifdef CONFIG_DAHDI_DEBUG >+ module_printk(KERN_NOTICE, "Recalculating slaves on %s\n", chan->name); >+#endif >+ >+ /* Link all slaves appropriately */ >+ for (x=chan->chanpos;x<chan->span->channels;x++) >+ if (chan->span->chans[x]->master == chan) { >+#ifdef CONFIG_DAHDI_DEBUG >+ module_printk(KERN_NOTICE, "Channel %s, slave to %s, last is %s, its next will be %d\n", >+ chan->span->chans[x]->name, chan->name, last->name, x); >+#endif >+ last->nextslave = x; >+ last = chan->span->chans[x]; >+ } >+ /* Terminate list */ >+ last->nextslave = 0; >+#ifdef CONFIG_DAHDI_DEBUG >+ module_printk(KERN_NOTICE, "Done Recalculating slaves on %s (last is %s)\n", chan->name, last->name); >+#endif >+} >+ >+static int dahdi_ctl_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long data) >+{ >+ /* I/O CTL's for control interface */ >+ int i,j; >+ int sigcap; >+ int res = 0; >+ int x,y; >+ struct dahdi_chan *newmaster; >+ unsigned long flags; >+ int rv; >+ switch(cmd) { >+ case DAHDI_INDIRECT: >+ { >+ struct dahdi_indirect_data ind; >+ >+ if (copy_from_user(&ind, (struct dahdi_indirect_data *)data, sizeof(ind))) >+ return -EFAULT; >+ VALID_CHANNEL(ind.chan); >+ return dahdi_chan_ioctl(inode, file, ind.op, (unsigned long) ind.data, ind.chan); >+ } >+ case DAHDI_SPANCONFIG: >+ { >+ struct dahdi_lineconfig lc; >+ >+ if (copy_from_user(&lc, (struct dahdi_lineconfig *)data, sizeof(lc))) >+ return -EFAULT; >+ VALID_SPAN(lc.span); >+ if ((lc.lineconfig & 0x07f0 & spans[lc.span]->linecompat) != (lc.lineconfig & 0x07f0)) >+ return -EINVAL; >+ if (spans[lc.span]->spanconfig) { >+ spans[lc.span]->lineconfig = lc.lineconfig; >+ spans[lc.span]->lbo = lc.lbo; >+ spans[lc.span]->txlevel = lc.lbo; >+ spans[lc.span]->rxlevel = 0; >+ >+ return spans[lc.span]->spanconfig(spans[lc.span], &lc); >+ } >+ return 0; >+ } >+ case DAHDI_STARTUP: >+ CHECK_VALID_SPAN(j); >+ if (spans[j]->flags & DAHDI_FLAG_RUNNING) >+ return 0; >+ if (spans[j]->startup) >+ res = spans[j]->startup(spans[j]); >+ if (!res) { >+ /* Mark as running and hangup any channels */ >+ spans[j]->flags |= DAHDI_FLAG_RUNNING; >+ for (x=0;x<spans[j]->channels;x++) { >+ y = dahdi_q_sig(spans[j]->chans[x]) & 0xff; >+ if (y >= 0) spans[j]->chans[x]->rxsig = (unsigned char)y; >+ spin_lock_irqsave(&spans[j]->chans[x]->lock, flags); >+ dahdi_hangup(spans[j]->chans[x]); >+ spin_unlock_irqrestore(&spans[j]->chans[x]->lock, flags); >+ spans[j]->chans[x]->rxhooksig = DAHDI_RXSIG_INITIAL; >+ } >+ } >+ return 0; >+ case DAHDI_SHUTDOWN: >+ CHECK_VALID_SPAN(j); >+ if (spans[j]->shutdown) >+ res = spans[j]->shutdown(spans[j]); >+ spans[j]->flags &= ~DAHDI_FLAG_RUNNING; >+ return 0; >+ case DAHDI_ATTACH_ECHOCAN: >+ { >+ struct dahdi_attach_echocan ae; >+ const struct dahdi_echocan_factory *new = NULL, *old; >+ >+ if (copy_from_user(&ae, (struct dahdi_attach_echocan *) data, sizeof(ae))) { >+ return -EFAULT; >+ } >+ >+ VALID_CHANNEL(ae.chan); >+ >+ ae.echocan[sizeof(ae.echocan) - 1] = 0; >+ if (ae.echocan[0]) { >+ if (!(new = find_echocan(ae.echocan))) { >+ return -EINVAL; >+ } >+ } >+ >+ spin_lock_irqsave(&chans[ae.chan]->lock, flags); >+ old = chans[ae.chan]->ec_factory; >+ chans[ae.chan]->ec_factory = new; >+ spin_unlock_irqrestore(&chans[ae.chan]->lock, flags); >+ >+ if (old) { >+ release_echocan(old); >+ } >+ >+ break; >+ } >+ case DAHDI_CHANCONFIG: >+ { >+ struct dahdi_chanconfig ch; >+ >+ if (copy_from_user(&ch, (struct dahdi_chanconfig *)data, sizeof(ch))) >+ return -EFAULT; >+ VALID_CHANNEL(ch.chan); >+ if (ch.sigtype == DAHDI_SIG_SLAVE) { >+ /* We have to use the master's sigtype */ >+ if ((ch.master < 1) || (ch.master >= DAHDI_MAX_CHANNELS)) >+ return -EINVAL; >+ if (!chans[ch.master]) >+ return -EINVAL; >+ ch.sigtype = chans[ch.master]->sig; >+ newmaster = chans[ch.master]; >+ } else if ((ch.sigtype & __DAHDI_SIG_DACS) == __DAHDI_SIG_DACS) { >+ newmaster = chans[ch.chan]; >+ if ((ch.idlebits < 1) || (ch.idlebits >= DAHDI_MAX_CHANNELS)) >+ return -EINVAL; >+ if (!chans[ch.idlebits]) >+ return -EINVAL; >+ } else { >+ newmaster = chans[ch.chan]; >+ } >+ spin_lock_irqsave(&chans[ch.chan]->lock, flags); >+#ifdef CONFIG_DAHDI_NET >+ if (chans[ch.chan]->flags & DAHDI_FLAG_NETDEV) { >+ if (ztchan_to_dev(chans[ch.chan])->flags & IFF_UP) { >+ spin_unlock_irqrestore(&chans[ch.chan]->lock, flags); >+ module_printk(KERN_WARNING, "Can't switch HDLC net mode on channel %s, since current interface is up\n", chans[ch.chan]->name); >+ return -EBUSY; >+ } >+ spin_unlock_irqrestore(&chans[ch.chan]->lock, flags); >+ unregister_hdlc_device(chans[ch.chan]->hdlcnetdev->netdev); >+ spin_lock_irqsave(&chans[ch.chan]->lock, flags); >+ free_netdev(chans[ch.chan]->hdlcnetdev->netdev); >+ kfree(chans[ch.chan]->hdlcnetdev); >+ chans[ch.chan]->hdlcnetdev = NULL; >+ chans[ch.chan]->flags &= ~DAHDI_FLAG_NETDEV; >+ } >+#else >+ if (ch.sigtype == DAHDI_SIG_HDLCNET) { >+ spin_unlock_irqrestore(&chans[ch.chan]->lock, flags); >+ module_printk(KERN_WARNING, "DAHDI networking not supported by this build.\n"); >+ return -ENOSYS; >+ } >+#endif >+ sigcap = chans[ch.chan]->sigcap; >+ /* If they support clear channel, then they support the HDLC and such through >+ us. */ >+ if (sigcap & DAHDI_SIG_CLEAR) >+ sigcap |= (DAHDI_SIG_HDLCRAW | DAHDI_SIG_HDLCFCS | DAHDI_SIG_HDLCNET | DAHDI_SIG_DACS); >+ >+ if ((sigcap & ch.sigtype) != ch.sigtype) >+ res = -EINVAL; >+ >+ if (!res && chans[ch.chan]->span->chanconfig) >+ res = chans[ch.chan]->span->chanconfig(chans[ch.chan], ch.sigtype); >+ >+ if (chans[ch.chan]->master != chans[ch.chan]) { >+ struct dahdi_chan *oldmaster = chans[ch.chan]->master; >+ >+ /* Clear the master channel */ >+ chans[ch.chan]->master = chans[ch.chan]; >+ chans[ch.chan]->nextslave = 0; >+ /* Unlink this channel from the master's channel list */ >+ recalc_slaves(oldmaster); >+ } >+ >+ if (!res) { >+ chans[ch.chan]->sig = ch.sigtype; >+ if (chans[ch.chan]->sig == DAHDI_SIG_CAS) >+ chans[ch.chan]->idlebits = ch.idlebits; >+ else >+ chans[ch.chan]->idlebits = 0; >+ if ((ch.sigtype & DAHDI_SIG_CLEAR) == DAHDI_SIG_CLEAR) { >+ /* Set clear channel flag if appropriate */ >+ chans[ch.chan]->flags &= ~DAHDI_FLAG_AUDIO; >+ chans[ch.chan]->flags |= DAHDI_FLAG_CLEAR; >+ } else { >+ /* Set audio flag and not clear channel otherwise */ >+ chans[ch.chan]->flags |= DAHDI_FLAG_AUDIO; >+ chans[ch.chan]->flags &= ~DAHDI_FLAG_CLEAR; >+ } >+ if ((ch.sigtype & DAHDI_SIG_HDLCRAW) == DAHDI_SIG_HDLCRAW) { >+ /* Set the HDLC flag */ >+ chans[ch.chan]->flags |= DAHDI_FLAG_HDLC; >+ } else { >+ /* Clear the HDLC flag */ >+ chans[ch.chan]->flags &= ~DAHDI_FLAG_HDLC; >+ } >+ if ((ch.sigtype & DAHDI_SIG_HDLCFCS) == DAHDI_SIG_HDLCFCS) { >+ /* Set FCS to be calculated if appropriate */ >+ chans[ch.chan]->flags |= DAHDI_FLAG_FCS; >+ } else { >+ /* Clear FCS flag */ >+ chans[ch.chan]->flags &= ~DAHDI_FLAG_FCS; >+ } >+ if ((ch.sigtype & __DAHDI_SIG_DACS) == __DAHDI_SIG_DACS) { >+ /* Setup conference properly */ >+ chans[ch.chan]->confmode = DAHDI_CONF_DIGITALMON; >+ chans[ch.chan]->confna = ch.idlebits; >+ if (chans[ch.chan]->span && >+ chans[ch.chan]->span->dacs && >+ chans[ch.idlebits] && >+ chans[ch.chan]->span && >+ (chans[ch.chan]->span->dacs == chans[ch.idlebits]->span->dacs)) >+ chans[ch.chan]->span->dacs(chans[ch.chan], chans[ch.idlebits]); >+ } else if (chans[ch.chan]->span && chans[ch.chan]->span->dacs) { >+ chans[ch.chan]->span->dacs(chans[ch.chan], NULL); >+ } >+ chans[ch.chan]->master = newmaster; >+ /* Note new slave if we are not our own master */ >+ if (newmaster != chans[ch.chan]) { >+ recalc_slaves(chans[ch.chan]->master); >+ } >+ if ((ch.sigtype & DAHDI_SIG_HARDHDLC) == DAHDI_SIG_HARDHDLC) { >+ chans[ch.chan]->flags &= ~DAHDI_FLAG_FCS; >+ chans[ch.chan]->flags &= ~DAHDI_FLAG_HDLC; >+ chans[ch.chan]->flags |= DAHDI_FLAG_NOSTDTXRX; >+ } else { >+ chans[ch.chan]->flags &= ~DAHDI_FLAG_NOSTDTXRX; >+ } >+ >+ if ((ch.sigtype & DAHDI_SIG_MTP2) == DAHDI_SIG_MTP2) >+ chans[ch.chan]->flags |= DAHDI_FLAG_MTP2; >+ else >+ chans[ch.chan]->flags &= ~DAHDI_FLAG_MTP2; >+ } >+#ifdef CONFIG_DAHDI_NET >+ if (!res && >+ (newmaster == chans[ch.chan]) && >+ (chans[ch.chan]->sig == DAHDI_SIG_HDLCNET)) { >+ chans[ch.chan]->hdlcnetdev = dahdi_hdlc_alloc(); >+ if (chans[ch.chan]->hdlcnetdev) { >+/* struct hdlc_device *hdlc = chans[ch.chan]->hdlcnetdev; >+ struct net_device *d = hdlc_to_dev(hdlc); mmm...get it right later --byg */ >+ >+ chans[ch.chan]->hdlcnetdev->netdev = alloc_hdlcdev(chans[ch.chan]->hdlcnetdev); >+ if (chans[ch.chan]->hdlcnetdev->netdev) { >+ chans[ch.chan]->hdlcnetdev->chan = chans[ch.chan]; >+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,23) >+ SET_MODULE_OWNER(chans[ch.chan]->hdlcnetdev->netdev); >+#endif >+ chans[ch.chan]->hdlcnetdev->netdev->irq = chans[ch.chan]->span->irq; >+ chans[ch.chan]->hdlcnetdev->netdev->tx_queue_len = 50; >+ chans[ch.chan]->hdlcnetdev->netdev->do_ioctl = dahdi_net_ioctl; >+ chans[ch.chan]->hdlcnetdev->netdev->open = dahdi_net_open; >+ chans[ch.chan]->hdlcnetdev->netdev->stop = dahdi_net_stop; >+ dev_to_hdlc(chans[ch.chan]->hdlcnetdev->netdev)->attach = dahdi_net_attach; >+ dev_to_hdlc(chans[ch.chan]->hdlcnetdev->netdev)->xmit = dahdi_xmit; >+ spin_unlock_irqrestore(&chans[ch.chan]->lock, flags); >+ /* Briefly restore interrupts while we register the device */ >+ res = dahdi_register_hdlc_device(chans[ch.chan]->hdlcnetdev->netdev, ch.netdev_name); >+ spin_lock_irqsave(&chans[ch.chan]->lock, flags); >+ } else { >+ module_printk(KERN_NOTICE, "Unable to allocate hdlc: *shrug*\n"); >+ res = -1; >+ } >+ if (!res) >+ chans[ch.chan]->flags |= DAHDI_FLAG_NETDEV; >+ } else { >+ module_printk(KERN_NOTICE, "Unable to allocate netdev: out of memory\n"); >+ res = -1; >+ } >+ } >+#endif >+ if ((chans[ch.chan]->sig == DAHDI_SIG_HDLCNET) && >+ (chans[ch.chan] == newmaster) && >+ !(chans[ch.chan]->flags & DAHDI_FLAG_NETDEV)) >+ module_printk(KERN_NOTICE, "Unable to register HDLC device for channel %s\n", chans[ch.chan]->name); >+ if (!res) { >+ /* Setup default law */ >+ chans[ch.chan]->deflaw = ch.deflaw; >+ /* Copy back any modified settings */ >+ spin_unlock_irqrestore(&chans[ch.chan]->lock, flags); >+ if (copy_to_user((struct dahdi_chanconfig *)data, &ch, sizeof(ch))) >+ return -EFAULT; >+ spin_lock_irqsave(&chans[ch.chan]->lock, flags); >+ /* And hangup */ >+ dahdi_hangup(chans[ch.chan]); >+ y = dahdi_q_sig(chans[ch.chan]) & 0xff; >+ if (y >= 0) >+ chans[ch.chan]->rxsig = (unsigned char) y; >+ chans[ch.chan]->rxhooksig = DAHDI_RXSIG_INITIAL; >+ } >+#ifdef CONFIG_DAHDI_DEBUG >+ module_printk(KERN_NOTICE, "Configured channel %s, flags %04lx, sig %04x\n", chans[ch.chan]->name, chans[ch.chan]->flags, chans[ch.chan]->sig); >+#endif >+ spin_unlock_irqrestore(&chans[ch.chan]->lock, flags); >+ >+ return res; >+ } >+ case DAHDI_SFCONFIG: >+ { >+ struct dahdi_sfconfig sf; >+ >+ if (copy_from_user(&sf, (struct dahdi_chanconfig *)data, sizeof(sf))) >+ return -EFAULT; >+ VALID_CHANNEL(sf.chan); >+ if (chans[sf.chan]->sig != DAHDI_SIG_SF) return -EINVAL; >+ spin_lock_irqsave(&chans[sf.chan]->lock, flags); >+ chans[sf.chan]->rxp1 = sf.rxp1; >+ chans[sf.chan]->rxp2 = sf.rxp2; >+ chans[sf.chan]->rxp3 = sf.rxp3; >+ chans[sf.chan]->txtone = sf.txtone; >+ chans[sf.chan]->tx_v2 = sf.tx_v2; >+ chans[sf.chan]->tx_v3 = sf.tx_v3; >+ chans[sf.chan]->toneflags = sf.toneflag; >+ if (sf.txtone) /* if set to make tone for tx */ >+ { >+ if ((chans[sf.chan]->txhooksig && !(sf.toneflag & DAHDI_REVERSE_TXTONE)) || >+ ((!chans[sf.chan]->txhooksig) && (sf.toneflag & DAHDI_REVERSE_TXTONE))) >+ { >+ set_txtone(chans[sf.chan],sf.txtone,sf.tx_v2,sf.tx_v3); >+ } >+ else >+ { >+ set_txtone(chans[sf.chan],0,0,0); >+ } >+ } >+ spin_unlock_irqrestore(&chans[sf.chan]->lock, flags); >+ return res; >+ } >+ case DAHDI_DEFAULTZONE: >+ if (get_user(j,(int *)data)) >+ return -EFAULT; >+ return dahdi_set_default_zone(j); >+ case DAHDI_LOADZONE: >+ return ioctl_load_zone(data); >+ case DAHDI_FREEZONE: >+ get_user(j, (int *) data); >+ return free_tone_zone(j); >+ case DAHDI_SET_DIALPARAMS: >+ { >+ struct dahdi_dialparams tdp; >+ >+ if (copy_from_user(&tdp, (struct dahdi_dialparams *) data, sizeof(tdp))) >+ return -EFAULT; >+ >+ if ((tdp.dtmf_tonelen >= 10) && (tdp.dtmf_tonelen <= 4000)) { >+ global_dialparams.dtmf_tonelen = tdp.dtmf_tonelen; >+ } >+ if ((tdp.mfv1_tonelen >= 10) && (tdp.mfv1_tonelen <= 4000)) { >+ global_dialparams.mfv1_tonelen = tdp.mfv1_tonelen; >+ } >+ if ((tdp.mfr2_tonelen >= 10) && (tdp.mfr2_tonelen <= 4000)) { >+ global_dialparams.mfr2_tonelen = tdp.mfr2_tonelen; >+ } >+ >+ /* update the lengths in all currently loaded zones */ >+ write_lock(&zone_lock); >+ for (j = 0; j < ARRAY_SIZE(tone_zones); j++) { >+ struct dahdi_zone *z = tone_zones[j]; >+ >+ if (!z) >+ continue; >+ >+ for (i = 0; i < ARRAY_SIZE(z->dtmf); i++) { >+ z->dtmf[i].tonesamples = global_dialparams.dtmf_tonelen * DAHDI_CHUNKSIZE; >+ } >+ >+ /* for MFR1, we only adjust the length of the digits */ >+ for (i = DAHDI_TONE_MFR1_0; i <= DAHDI_TONE_MFR1_9; i++) { >+ z->mfr1[i - DAHDI_TONE_MFR1_BASE].tonesamples = global_dialparams.mfv1_tonelen * DAHDI_CHUNKSIZE; >+ } >+ >+ for (i = 0; i < ARRAY_SIZE(z->mfr2_fwd); i++) { >+ z->mfr2_fwd[i].tonesamples = global_dialparams.mfr2_tonelen * DAHDI_CHUNKSIZE; >+ } >+ >+ for (i = 0; i < ARRAY_SIZE(z->mfr2_rev); i++) { >+ z->mfr2_rev[i].tonesamples = global_dialparams.mfr2_tonelen * DAHDI_CHUNKSIZE; >+ } >+ } >+ write_unlock(&zone_lock); >+ >+ dtmf_silence.tonesamples = global_dialparams.dtmf_tonelen * DAHDI_CHUNKSIZE; >+ mfr1_silence.tonesamples = global_dialparams.mfv1_tonelen * DAHDI_CHUNKSIZE; >+ mfr2_silence.tonesamples = global_dialparams.mfr2_tonelen * DAHDI_CHUNKSIZE; >+ >+ break; >+ } >+ case DAHDI_GET_DIALPARAMS: >+ { >+ struct dahdi_dialparams tdp; >+ >+ tdp = global_dialparams; >+ if (copy_to_user((struct dahdi_dialparams *) data, &tdp, sizeof(tdp))) >+ return -EFAULT; >+ break; >+ } >+ case DAHDI_GETVERSION: >+ { >+ struct dahdi_versioninfo vi; >+ struct ecfactory *cur; >+ size_t space = sizeof(vi.echo_canceller) - 1; >+ >+ memset(&vi, 0, sizeof(vi)); >+ dahdi_copy_string(vi.version, DAHDI_VERSION, sizeof(vi.version)); >+ read_lock(&ecfactory_list_lock); >+ list_for_each_entry(cur, &ecfactory_list, list) { >+ strncat(vi.echo_canceller + strlen(vi.echo_canceller), cur->ec->name, space); >+ space -= strlen(cur->ec->name); >+ if (space < 1) { >+ break; >+ } >+ if (cur->list.next && (cur->list.next != &ecfactory_list)) { >+ strncat(vi.echo_canceller + strlen(vi.echo_canceller), ", ", space); >+ space -= 2; >+ if (space < 1) { >+ break; >+ } >+ } >+ } >+ read_unlock(&ecfactory_list_lock); >+ if (copy_to_user((struct dahdi_versioninfo *) data, &vi, sizeof(vi))) >+ return -EFAULT; >+ break; >+ } >+ case DAHDI_MAINT: /* do maintenance stuff */ >+ { >+ struct dahdi_maintinfo maint; >+ /* get struct from user */ >+ if (copy_from_user(&maint,(struct dahdi_maintinfo *) data, sizeof(maint))) >+ return -EFAULT; >+ /* must be valid span number */ >+ if ((maint.spanno < 1) || (maint.spanno > DAHDI_MAX_SPANS) || (!spans[maint.spanno])) >+ return -EINVAL; >+ if (!spans[maint.spanno]->maint) >+ return -ENOSYS; >+ spin_lock_irqsave(&spans[maint.spanno]->lock, flags); >+ /* save current maint state */ >+ i = spans[maint.spanno]->maintstat; >+ /* set maint mode */ >+ spans[maint.spanno]->maintstat = maint.command; >+ switch(maint.command) { >+ case DAHDI_MAINT_NONE: >+ case DAHDI_MAINT_LOCALLOOP: >+ case DAHDI_MAINT_REMOTELOOP: >+ /* if same, ignore it */ >+ if (i == maint.command) >+ break; >+ rv = spans[maint.spanno]->maint(spans[maint.spanno], maint.command); >+ spin_unlock_irqrestore(&spans[maint.spanno]->lock, flags); >+ if (rv) >+ return rv; >+ spin_lock_irqsave(&spans[maint.spanno]->lock, flags); >+ break; >+ case DAHDI_MAINT_LOOPUP: >+ case DAHDI_MAINT_LOOPDOWN: >+ spans[maint.spanno]->mainttimer = DAHDI_LOOPCODE_TIME * DAHDI_CHUNKSIZE; >+ rv = spans[maint.spanno]->maint(spans[maint.spanno], maint.command); >+ spin_unlock_irqrestore(&spans[maint.spanno]->lock, flags); >+ if (rv) >+ return rv; >+ rv = schluffen(&spans[maint.spanno]->maintq); >+ if (rv) >+ return rv; >+ spin_lock_irqsave(&spans[maint.spanno]->lock, flags); >+ break; >+ default: >+ module_printk(KERN_NOTICE, "Unknown maintenance event: %d\n", maint.command); >+ } >+ dahdi_alarm_notify(spans[maint.spanno]); /* process alarm-related events */ >+ spin_unlock_irqrestore(&spans[maint.spanno]->lock, flags); >+ break; >+ } >+ case DAHDI_DYNAMIC_CREATE: >+ case DAHDI_DYNAMIC_DESTROY: >+ if (dahdi_dynamic_ioctl) { >+ return dahdi_dynamic_ioctl(cmd, data); >+ } else { >+ request_module("dahdi_dynamic"); >+ if (dahdi_dynamic_ioctl) >+ return dahdi_dynamic_ioctl(cmd, data); >+ } >+ return -ENOSYS; >+ case DAHDI_EC_LICENSE_CHALLENGE: >+ case DAHDI_EC_LICENSE_RESPONSE: >+ if (dahdi_hpec_ioctl) { >+ return dahdi_hpec_ioctl(cmd, data); >+ } else { >+ request_module("dahdi_echocan_hpec"); >+ if (dahdi_hpec_ioctl) >+ return dahdi_hpec_ioctl(cmd, data); >+ } >+ return -ENOSYS; >+ default: >+ return dahdi_common_ioctl(inode, file, cmd, data, 0); >+ } >+ return 0; >+} >+ >+static int ioctl_dahdi_dial(struct dahdi_chan *chan, unsigned long data) >+{ >+ struct dahdi_dialoperation *tdo; >+ unsigned long flags; >+ char *s; >+ int rv; >+ >+ tdo = kmalloc(sizeof(*tdo), GFP_KERNEL); >+ >+ if (!tdo) >+ return -ENOMEM; >+ >+ if (copy_from_user(tdo, (struct dahdi_dialoperation *)data, sizeof(*tdo))) >+ return -EFAULT; >+ rv = 0; >+ /* Force proper NULL termination and uppercase entry */ >+ tdo->dialstr[DAHDI_MAX_DTMF_BUF - 1] = '\0'; >+ for (s = tdo->dialstr; *s; s++) >+ *s = toupper(*s); >+ spin_lock_irqsave(&chan->lock, flags); >+ if (!chan->curzone) { >+ spin_unlock_irqrestore(&chan->lock, flags); >+ /* The tone zones are loaded by dahdi_cfg from /etc/dahdi/system.conf */ >+ module_printk(KERN_WARNING, "Cannot dial until a tone zone is loaded.\n"); >+ return -ENODATA; >+ } >+ switch (tdo->op) { >+ case DAHDI_DIAL_OP_CANCEL: >+ chan->curtone = NULL; >+ chan->dialing = 0; >+ chan->txdialbuf[0] = '\0'; >+ chan->tonep = 0; >+ chan->pdialcount = 0; >+ break; >+ case DAHDI_DIAL_OP_REPLACE: >+ strcpy(chan->txdialbuf, tdo->dialstr); >+ chan->dialing = 1; >+ __do_dtmf(chan); >+ break; >+ case DAHDI_DIAL_OP_APPEND: >+ if (strlen(tdo->dialstr) + strlen(chan->txdialbuf) >= (DAHDI_MAX_DTMF_BUF - 1)) { >+ rv = -EBUSY; >+ break; >+ } >+ dahdi_copy_string(chan->txdialbuf + strlen(chan->txdialbuf), tdo->dialstr, DAHDI_MAX_DTMF_BUF - strlen(chan->txdialbuf)); >+ if (!chan->dialing) { >+ chan->dialing = 1; >+ __do_dtmf(chan); >+ } >+ break; >+ default: >+ rv = -EINVAL; >+ } >+ spin_unlock_irqrestore(&chan->lock, flags); >+ return rv; >+} >+ >+static int dahdi_chanandpseudo_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long data, int unit) >+{ >+ struct dahdi_chan *chan = chans[unit]; >+ union { >+ struct dahdi_bufferinfo bi; >+ struct dahdi_confinfo conf; >+ struct dahdi_ring_cadence cad; >+ } stack; >+ unsigned long flags; >+ int i, j, k, rv; >+ int ret, c; >+ >+ if (!chan) >+ return -EINVAL; >+ switch(cmd) { >+ case DAHDI_DIALING: >+ spin_lock_irqsave(&chan->lock, flags); >+ j = chan->dialing; >+ spin_unlock_irqrestore(&chan->lock, flags); >+ if (copy_to_user((int *)data,&j,sizeof(int))) >+ return -EFAULT; >+ return 0; >+ case DAHDI_DIAL: >+ return ioctl_dahdi_dial(chan, data); >+ case DAHDI_GET_BUFINFO: >+ memset(&stack.bi, 0, sizeof(stack.bi)); >+ stack.bi.rxbufpolicy = chan->rxbufpolicy; >+ stack.bi.txbufpolicy = chan->txbufpolicy; >+ stack.bi.numbufs = chan->numbufs; >+ stack.bi.bufsize = chan->blocksize; >+ /* XXX FIXME! XXX */ >+ stack.bi.readbufs = -1; >+ stack.bi.writebufs = -1; >+ if (copy_to_user((struct dahdi_bufferinfo *)data, &stack.bi, sizeof(stack.bi))) >+ return -EFAULT; >+ break; >+ case DAHDI_SET_BUFINFO: >+ if (copy_from_user(&stack.bi, (struct dahdi_bufferinfo *)data, sizeof(stack.bi))) >+ return -EFAULT; >+ if (stack.bi.bufsize > DAHDI_MAX_BLOCKSIZE) >+ return -EINVAL; >+ if (stack.bi.bufsize < 16) >+ return -EINVAL; >+ if (stack.bi.bufsize * stack.bi.numbufs > DAHDI_MAX_BUF_SPACE) >+ return -EINVAL; >+ /* It does not make sense to allow user mode to change the >+ * receive buffering policy. DAHDI always provides received >+ * buffers to upper layers immediately. Transmission is >+ * different since we might want to allow the kernel to build >+ * up a buffer in order to prevent underruns from the >+ * interrupt context. */ >+ chan->txbufpolicy = stack.bi.txbufpolicy & 0x3; >+ if ((rv = dahdi_reallocbufs(chan, stack.bi.bufsize, stack.bi.numbufs))) >+ return (rv); >+ break; >+ case DAHDI_GET_BLOCKSIZE: /* get blocksize */ >+ put_user(chan->blocksize,(int *)data); /* return block size */ >+ break; >+ case DAHDI_SET_BLOCKSIZE: /* set blocksize */ >+ get_user(j,(int *)data); >+ /* cannot be larger than max amount */ >+ if (j > DAHDI_MAX_BLOCKSIZE) return(-EINVAL); >+ /* cannot be less then 16 */ >+ if (j < 16) return(-EINVAL); >+ /* allocate a single kernel buffer which we then >+ sub divide into four pieces */ >+ if ((rv = dahdi_reallocbufs(chan, j, chan->numbufs))) >+ return (rv); >+ break; >+ case DAHDI_FLUSH: /* flush input buffer, output buffer, and/or event queue */ >+ get_user(i,(int *)data); /* get param */ >+ spin_lock_irqsave(&chan->lock, flags); >+ if (i & DAHDI_FLUSH_READ) /* if for read (input) */ >+ { >+ /* initialize read buffers and pointers */ >+ chan->inreadbuf = 0; >+ chan->outreadbuf = -1; >+ for (j=0;j<chan->numbufs;j++) { >+ /* Do we need this? */ >+ chan->readn[j] = 0; >+ chan->readidx[j] = 0; >+ } >+ wake_up_interruptible(&chan->readbufq); /* wake_up_interruptible waiting on read */ >+ wake_up_interruptible(&chan->sel); /* wake_up_interruptible waiting on select */ >+ } >+ if (i & DAHDI_FLUSH_WRITE) /* if for write (output) */ >+ { >+ /* initialize write buffers and pointers */ >+ chan->outwritebuf = -1; >+ chan->inwritebuf = 0; >+ for (j=0;j<chan->numbufs;j++) { >+ /* Do we need this? */ >+ chan->writen[j] = 0; >+ chan->writeidx[j] = 0; >+ } >+ wake_up_interruptible(&chan->writebufq); /* wake_up_interruptible waiting on write */ >+ wake_up_interruptible(&chan->sel); /* wake_up_interruptible waiting on select */ >+ /* if IO MUX wait on write empty, well, this >+ certainly *did* empty the write */ >+ if (chan->iomask & DAHDI_IOMUX_WRITEEMPTY) >+ wake_up_interruptible(&chan->eventbufq); /* wake_up_interruptible waiting on IOMUX */ >+ } >+ if (i & DAHDI_FLUSH_EVENT) /* if for events */ >+ { >+ /* initialize the event pointers */ >+ chan->eventinidx = chan->eventoutidx = 0; >+ } >+ spin_unlock_irqrestore(&chan->lock, flags); >+ break; >+ case DAHDI_SYNC: /* wait for no tx */ >+ for(;;) /* loop forever */ >+ { >+ spin_lock_irqsave(&chan->lock, flags); >+ /* Know if there is a write pending */ >+ i = (chan->outwritebuf > -1); >+ spin_unlock_irqrestore(&chan->lock, flags); >+ if (!i) break; /* skip if none */ >+ rv = schluffen(&chan->writebufq); >+ if (rv) return(rv); >+ } >+ break; >+ case DAHDI_IOMUX: /* wait for something to happen */ >+ get_user(chan->iomask,(int*)data); /* save mask */ >+ if (!chan->iomask) return(-EINVAL); /* cant wait for nothing */ >+ for(;;) /* loop forever */ >+ { >+ /* has to have SOME mask */ >+ ret = 0; /* start with empty return value */ >+ spin_lock_irqsave(&chan->lock, flags); >+ /* if looking for read */ >+ if (chan->iomask & DAHDI_IOMUX_READ) >+ { >+ /* if read available */ >+ if ((chan->outreadbuf > -1) && !chan->rxdisable) >+ ret |= DAHDI_IOMUX_READ; >+ } >+ /* if looking for write avail */ >+ if (chan->iomask & DAHDI_IOMUX_WRITE) >+ { >+ if (chan->inwritebuf > -1) >+ ret |= DAHDI_IOMUX_WRITE; >+ } >+ /* if looking for write empty */ >+ if (chan->iomask & DAHDI_IOMUX_WRITEEMPTY) >+ { >+ /* if everything empty -- be sure the transmitter is enabled */ >+ chan->txdisable = 0; >+ if (chan->outwritebuf < 0) >+ ret |= DAHDI_IOMUX_WRITEEMPTY; >+ } >+ /* if looking for signalling event */ >+ if (chan->iomask & DAHDI_IOMUX_SIGEVENT) >+ { >+ /* if event */ >+ if (chan->eventinidx != chan->eventoutidx) >+ ret |= DAHDI_IOMUX_SIGEVENT; >+ } >+ spin_unlock_irqrestore(&chan->lock, flags); >+ /* if something to return, or not to wait */ >+ if (ret || (chan->iomask & DAHDI_IOMUX_NOWAIT)) >+ { >+ /* set return value */ >+ put_user(ret,(int *)data); >+ break; /* get out of loop */ >+ } >+ rv = schluffen(&chan->eventbufq); >+ if (rv) return(rv); >+ } >+ /* clear IO MUX mask */ >+ chan->iomask = 0; >+ break; >+ case DAHDI_GETEVENT: /* Get event on queue */ >+ /* set up for no event */ >+ j = DAHDI_EVENT_NONE; >+ spin_lock_irqsave(&chan->lock, flags); >+ /* if some event in queue */ >+ if (chan->eventinidx != chan->eventoutidx) >+ { >+ j = chan->eventbuf[chan->eventoutidx++]; >+ /* get the data, bump index */ >+ /* if index overflow, set to beginning */ >+ if (chan->eventoutidx >= DAHDI_MAX_EVENTSIZE) >+ chan->eventoutidx = 0; >+ } >+ spin_unlock_irqrestore(&chan->lock, flags); >+ put_user(j,(int *)data); >+ break; >+ case DAHDI_CONFMUTE: /* set confmute flag */ >+ get_user(j,(int *)data); /* get conf # */ >+ if (!(chan->flags & DAHDI_FLAG_AUDIO)) return (-EINVAL); >+ spin_lock_irqsave(&bigzaplock, flags); >+ chan->confmute = j; >+ spin_unlock_irqrestore(&bigzaplock, flags); >+ break; >+ case DAHDI_GETCONFMUTE: /* get confmute flag */ >+ if (!(chan->flags & DAHDI_FLAG_AUDIO)) return (-EINVAL); >+ j = chan->confmute; >+ put_user(j,(int *)data); /* get conf # */ >+ rv = 0; >+ break; >+ case DAHDI_SETTONEZONE: >+ get_user(j, (int *) data); >+ rv = set_tone_zone(chan, j); >+ return rv; >+ case DAHDI_GETTONEZONE: >+ spin_lock_irqsave(&chan->lock, flags); >+ if (chan->curzone) >+ j = chan->tonezone; >+ spin_unlock_irqrestore(&chan->lock, flags); >+ put_user(j, (int *) data); >+ break; >+ case DAHDI_SENDTONE: >+ get_user(j,(int *)data); >+ spin_lock_irqsave(&chan->lock, flags); >+ rv = start_tone(chan, j); >+ spin_unlock_irqrestore(&chan->lock, flags); >+ return rv; >+ case DAHDI_GETCONF_V1: /* intentional drop through */ >+ case DAHDI_GETCONF: /* get conf stuff */ >+ if (copy_from_user(&stack.conf,(struct dahdi_confinfo *) data,sizeof(stack.conf))) >+ return -EFAULT; >+ i = stack.conf.chan; /* get channel no */ >+ /* if zero, use current channel no */ >+ if (!i) i = chan->channo; >+ /* make sure channel number makes sense */ >+ if ((i < 0) || (i > DAHDI_MAX_CONF) || (!chans[i])) return(-EINVAL); >+ if (!(chans[i]->flags & DAHDI_FLAG_AUDIO)) return (-EINVAL); >+ stack.conf.chan = i; /* get channel number */ >+ stack.conf.confno = chans[i]->confna; /* get conference number */ >+ stack.conf.confmode = chans[i]->confmode; /* get conference mode */ >+ if (copy_to_user((struct dahdi_confinfo *) data,&stack.conf,sizeof(stack.conf))) >+ return -EFAULT; >+ break; >+ case DAHDI_SETCONF_V1: /* Intentional fall through. */ >+ case DAHDI_SETCONF: /* set conf stuff */ >+ if (copy_from_user(&stack.conf,(struct dahdi_confinfo *) data,sizeof(stack.conf))) >+ return -EFAULT; >+ i = stack.conf.chan; /* get channel no */ >+ /* if zero, use current channel no */ >+ if (!i) i = chan->channo; >+ /* make sure channel number makes sense */ >+ if ((i < 1) || (i > DAHDI_MAX_CHANNELS) || (!chans[i])) return(-EINVAL); >+ if (!(chans[i]->flags & DAHDI_FLAG_AUDIO)) return (-EINVAL); >+ if ((stack.conf.confmode & DAHDI_CONF_MODE_MASK) == DAHDI_CONF_MONITOR || >+ (stack.conf.confmode & DAHDI_CONF_MODE_MASK) == DAHDI_CONF_MONITORTX || >+ (stack.conf.confmode & DAHDI_CONF_MODE_MASK) == DAHDI_CONF_MONITORBOTH || >+ (stack.conf.confmode & DAHDI_CONF_MODE_MASK) == DAHDI_CONF_MONITOR_RX_PREECHO || >+ (stack.conf.confmode & DAHDI_CONF_MODE_MASK) == DAHDI_CONF_MONITOR_TX_PREECHO || >+ (stack.conf.confmode & DAHDI_CONF_MODE_MASK) == DAHDI_CONF_MONITORBOTH_PREECHO) { >+ /* Monitor mode -- it's a channel */ >+ if ((stack.conf.confno < 0) || (stack.conf.confno >= DAHDI_MAX_CHANNELS) || !chans[stack.conf.confno]) return(-EINVAL); >+ } else { >+ /* make sure conf number makes sense, too */ >+ if ((stack.conf.confno < -1) || (stack.conf.confno > DAHDI_MAX_CONF)) return(-EINVAL); >+ } >+ >+ /* if taking off of any conf, must have 0 mode */ >+ if ((!stack.conf.confno) && stack.conf.confmode) return(-EINVAL); >+ /* likewise if 0 mode must have no conf */ >+ if ((!stack.conf.confmode) && stack.conf.confno) return (-EINVAL); >+ stack.conf.chan = i; /* return with real channel # */ >+ spin_lock_irqsave(&bigzaplock, flags); >+ spin_lock(&chan->lock); >+ if (stack.conf.confno == -1) >+ stack.conf.confno = dahdi_first_empty_conference(); >+ if ((stack.conf.confno < 1) && (stack.conf.confmode)) { >+ /* No more empty conferences */ >+ spin_unlock(&chan->lock); >+ spin_unlock_irqrestore(&bigzaplock, flags); >+ return -EBUSY; >+ } >+ /* if changing confs, clear last added info */ >+ if (stack.conf.confno != chans[i]->confna) { >+ memset(chans[i]->conflast, 0, DAHDI_MAX_CHUNKSIZE); >+ memset(chans[i]->conflast1, 0, DAHDI_MAX_CHUNKSIZE); >+ memset(chans[i]->conflast2, 0, DAHDI_MAX_CHUNKSIZE); >+ } >+ j = chans[i]->confna; /* save old conference number */ >+ chans[i]->confna = stack.conf.confno; /* set conference number */ >+ chans[i]->confmode = stack.conf.confmode; /* set conference mode */ >+ chans[i]->_confn = 0; /* Clear confn */ >+ dahdi_check_conf(j); >+ dahdi_check_conf(stack.conf.confno); >+ if (chans[i]->span && chans[i]->span->dacs) { >+ if (((stack.conf.confmode & DAHDI_CONF_MODE_MASK) == DAHDI_CONF_DIGITALMON) && >+ chans[stack.conf.confno]->span && >+ chans[stack.conf.confno]->span->dacs == chans[i]->span->dacs && >+ chans[i]->txgain == defgain && >+ chans[i]->rxgain == defgain && >+ chans[stack.conf.confno]->txgain == defgain && >+ chans[stack.conf.confno]->rxgain == defgain) { >+ chans[i]->span->dacs(chans[i], chans[stack.conf.confno]); >+ } else { >+ chans[i]->span->dacs(chans[i], NULL); >+ } >+ } >+ /* if we are going onto a conf */ >+ if (stack.conf.confno && >+ ((stack.conf.confmode & DAHDI_CONF_MODE_MASK) == DAHDI_CONF_CONF || >+ (stack.conf.confmode & DAHDI_CONF_MODE_MASK) == DAHDI_CONF_CONFANN || >+ (stack.conf.confmode & DAHDI_CONF_MODE_MASK) == DAHDI_CONF_CONFMON || >+ (stack.conf.confmode & DAHDI_CONF_MODE_MASK) == DAHDI_CONF_CONFANNMON || >+ (stack.conf.confmode & DAHDI_CONF_MODE_MASK) == DAHDI_CONF_REALANDPSEUDO)) { >+ /* Get alias */ >+ chans[i]->_confn = dahdi_get_conf_alias(stack.conf.confno); >+ } >+ >+ if (chans[stack.conf.confno]) { >+ if ((stack.conf.confmode & DAHDI_CONF_MODE_MASK) == DAHDI_CONF_MONITOR_RX_PREECHO || >+ (stack.conf.confmode & DAHDI_CONF_MODE_MASK) == DAHDI_CONF_MONITOR_TX_PREECHO || >+ (stack.conf.confmode & DAHDI_CONF_MODE_MASK) == DAHDI_CONF_MONITORBOTH_PREECHO) >+ chans[stack.conf.confno]->readchunkpreec = kmalloc(sizeof(*chans[stack.conf.confno]->readchunkpreec) * DAHDI_CHUNKSIZE, GFP_ATOMIC); >+ else { >+ if (chans[stack.conf.confno]->readchunkpreec) { >+ kfree(chans[stack.conf.confno]->readchunkpreec); >+ chans[stack.conf.confno]->readchunkpreec = NULL; >+ } >+ } >+ } >+ >+ spin_unlock(&chan->lock); >+ spin_unlock_irqrestore(&bigzaplock, flags); >+ if (copy_to_user((struct dahdi_confinfo *) data,&stack.conf,sizeof(stack.conf))) >+ return -EFAULT; >+ break; >+ case DAHDI_CONFLINK: /* do conf link stuff */ >+ if (!(chan->flags & DAHDI_FLAG_AUDIO)) return (-EINVAL); >+ if (copy_from_user(&stack.conf,(struct dahdi_confinfo *) data,sizeof(stack.conf))) >+ return -EFAULT; >+ /* check sanity of arguments */ >+ if ((stack.conf.chan < 0) || (stack.conf.chan > DAHDI_MAX_CONF)) return(-EINVAL); >+ if ((stack.conf.confno < 0) || (stack.conf.confno > DAHDI_MAX_CONF)) return(-EINVAL); >+ /* cant listen to self!! */ >+ if (stack.conf.chan && (stack.conf.chan == stack.conf.confno)) return(-EINVAL); >+ spin_lock_irqsave(&bigzaplock, flags); >+ spin_lock(&chan->lock); >+ /* if to clear all links */ >+ if ((!stack.conf.chan) && (!stack.conf.confno)) >+ { >+ /* clear all the links */ >+ memset(conf_links,0,sizeof(conf_links)); >+ recalc_maxlinks(); >+ spin_unlock(&chan->lock); >+ spin_unlock_irqrestore(&bigzaplock, flags); >+ break; >+ } >+ rv = 0; /* clear return value */ >+ /* look for already existant specified combination */ >+ for(i = 1; i <= DAHDI_MAX_CONF; i++) >+ { >+ /* if found, exit */ >+ if ((conf_links[i].src == stack.conf.chan) && >+ (conf_links[i].dst == stack.conf.confno)) break; >+ } >+ if (i <= DAHDI_MAX_CONF) /* if found */ >+ { >+ if (!stack.conf.confmode) /* if to remove link */ >+ { >+ conf_links[i].src = conf_links[i].dst = 0; >+ } >+ else /* if to add and already there, error */ >+ { >+ rv = -EEXIST; >+ } >+ } >+ else /* if not found */ >+ { >+ if (stack.conf.confmode) /* if to add link */ >+ { >+ /* look for empty location */ >+ for(i = 1; i <= DAHDI_MAX_CONF; i++) >+ { >+ /* if empty, exit loop */ >+ if ((!conf_links[i].src) && >+ (!conf_links[i].dst)) break; >+ } >+ /* if empty spot found */ >+ if (i <= DAHDI_MAX_CONF) >+ { >+ conf_links[i].src = stack.conf.chan; >+ conf_links[i].dst = stack.conf.confno; >+ } >+ else /* if no empties -- error */ >+ { >+ rv = -ENOSPC; >+ } >+ } >+ else /* if to remove, and not found -- error */ >+ { >+ rv = -ENOENT; >+ } >+ } >+ recalc_maxlinks(); >+ spin_unlock(&chan->lock); >+ spin_unlock_irqrestore(&bigzaplock, flags); >+ return(rv); >+ case DAHDI_CONFDIAG_V1: /* Intention fall-through */ >+ case DAHDI_CONFDIAG: /* output diagnostic info to console */ >+ if (!(chan->flags & DAHDI_FLAG_AUDIO)) return (-EINVAL); >+ get_user(j,(int *)data); /* get conf # */ >+ /* loop thru the interesting ones */ >+ for(i = ((j) ? j : 1); i <= ((j) ? j : DAHDI_MAX_CONF); i++) >+ { >+ c = 0; >+ for(k = 1; k < DAHDI_MAX_CHANNELS; k++) >+ { >+ /* skip if no pointer */ >+ if (!chans[k]) continue; >+ /* skip if not in this conf */ >+ if (chans[k]->confna != i) continue; >+ if (!c) module_printk(KERN_NOTICE, "Conf #%d:\n",i); >+ c = 1; >+ module_printk(KERN_NOTICE, "chan %d, mode %x\n", k,chans[k]->confmode); >+ } >+ rv = 0; >+ for(k = 1; k <= DAHDI_MAX_CONF; k++) >+ { >+ if (conf_links[k].dst == i) >+ { >+ if (!c) module_printk(KERN_NOTICE, "Conf #%d:\n",i); >+ c = 1; >+ if (!rv) module_printk(KERN_NOTICE, "Snooping on:\n"); >+ rv = 1; >+ module_printk(KERN_NOTICE, "conf %d\n",conf_links[k].src); >+ } >+ } >+ if (c) module_printk(KERN_NOTICE, "\n"); >+ } >+ break; >+ case DAHDI_CHANNO: /* get channel number of stream */ >+ put_user(unit,(int *)data); /* return unit/channel number */ >+ break; >+ case DAHDI_SETLAW: >+ get_user(j, (int *)data); >+ if ((j < 0) || (j > DAHDI_LAW_ALAW)) >+ return -EINVAL; >+ dahdi_set_law(chan, j); >+ break; >+ case DAHDI_SETLINEAR: >+ get_user(j, (int *)data); >+ /* Makes no sense on non-audio channels */ >+ if (!(chan->flags & DAHDI_FLAG_AUDIO)) >+ return -EINVAL; >+ >+ if (j) >+ chan->flags |= DAHDI_FLAG_LINEAR; >+ else >+ chan->flags &= ~DAHDI_FLAG_LINEAR; >+ break; >+ case DAHDI_SETCADENCE: >+ if (data) { >+ /* Use specific ring cadence */ >+ if (copy_from_user(&stack.cad, (struct dahdi_ring_cadence *)data, sizeof(stack.cad))) >+ return -EFAULT; >+ memcpy(chan->ringcadence, &stack.cad, sizeof(chan->ringcadence)); >+ chan->firstcadencepos = 0; >+ /* Looking for negative ringing time indicating where to loop back into ringcadence */ >+ for (i=0; i<DAHDI_MAX_CADENCE; i+=2 ) { >+ if (chan->ringcadence[i]<0) { >+ chan->ringcadence[i] *= -1; >+ chan->firstcadencepos = i; >+ break; >+ } >+ } >+ } else { >+ /* Reset to default */ >+ chan->firstcadencepos = 0; >+ if (chan->curzone) { >+ memcpy(chan->ringcadence, chan->curzone->ringcadence, sizeof(chan->ringcadence)); >+ /* Looking for negative ringing time indicating where to loop back into ringcadence */ >+ for (i=0; i<DAHDI_MAX_CADENCE; i+=2 ) { >+ if (chan->ringcadence[i]<0) { >+ chan->ringcadence[i] *= -1; >+ chan->firstcadencepos = i; >+ break; >+ } >+ } >+ } else { >+ memset(chan->ringcadence, 0, sizeof(chan->ringcadence)); >+ chan->ringcadence[0] = chan->starttime; >+ chan->ringcadence[1] = DAHDI_RINGOFFTIME; >+ } >+ } >+ break; >+ default: >+ /* Check for common ioctl's and private ones */ >+ rv = dahdi_common_ioctl(inode, file, cmd, data, unit); >+ /* if no span, just return with value */ >+ if (!chan->span) return rv; >+ if ((rv == -ENOTTY) && chan->span->ioctl) >+ rv = chan->span->ioctl(chan, cmd, data); >+ return rv; >+ >+ } >+ return 0; >+} >+ >+#ifdef CONFIG_DAHDI_PPP >+/* >+ * This is called at softirq (BH) level when there are calls >+ * we need to make to the ppp_generic layer. We do it this >+ * way because the ppp_generic layer functions may not be called >+ * at interrupt level. >+ */ >+static void do_ppp_calls(unsigned long data) >+{ >+ struct dahdi_chan *chan = (struct dahdi_chan *) data; >+ struct sk_buff *skb; >+ >+ if (!chan->ppp) >+ return; >+ if (chan->do_ppp_wakeup) { >+ chan->do_ppp_wakeup = 0; >+ ppp_output_wakeup(chan->ppp); >+ } >+ while ((skb = skb_dequeue(&chan->ppp_rq)) != NULL) >+ ppp_input(chan->ppp, skb); >+ if (chan->do_ppp_error) { >+ chan->do_ppp_error = 0; >+ ppp_input_error(chan->ppp, 0); >+ } >+} >+#endif >+ >+static int ioctl_echocancel(struct dahdi_chan *chan, struct dahdi_echocanparams *ecp, void *data) >+{ >+ struct dahdi_echocan_state *ec = NULL, *ec_state; >+ const struct dahdi_echocan_factory *ec_current; >+ struct dahdi_echocanparam *params; >+ int ret; >+ unsigned long flags; >+ >+ if (ecp->param_count > DAHDI_MAX_ECHOCANPARAMS) >+ return -E2BIG; >+ >+ if (ecp->tap_length == 0) { >+ /* disable mode, don't need to inspect params */ >+ spin_lock_irqsave(&chan->lock, flags); >+ ec_state = chan->ec_state; >+ chan->ec_state = NULL; >+ ec_current = chan->ec_current; >+ chan->ec_current = NULL; >+ spin_unlock_irqrestore(&chan->lock, flags); >+ if (ec_state) { >+ ec_state->ops->echocan_free(chan, ec_state); >+ release_echocan(ec_current); >+ } >+ >+ return 0; >+ } >+ >+ params = kmalloc(sizeof(params[0]) * DAHDI_MAX_ECHOCANPARAMS, GFP_KERNEL); >+ >+ if (!params) >+ return -ENOMEM; >+ >+ /* enable mode, need the params */ >+ >+ if (copy_from_user(params, (struct dahdi_echocanparam *) data, sizeof(params[0]) * ecp->param_count)) { >+ ret = -EFAULT; >+ goto exit_with_free; >+ } >+ >+ /* free any echocan that may be on the channel already */ >+ spin_lock_irqsave(&chan->lock, flags); >+ ec_state = chan->ec_state; >+ chan->ec_state = NULL; >+ ec_current = chan->ec_current; >+ chan->ec_current = NULL; >+ spin_unlock_irqrestore(&chan->lock, flags); >+ if (ec_state) { >+ ec_state->ops->echocan_free(chan, ec_state); >+ release_echocan(ec_current); >+ } >+ >+ switch (ecp->tap_length) { >+ case 32: >+ case 64: >+ case 128: >+ case 256: >+ case 512: >+ case 1024: >+ break; >+ default: >+ ecp->tap_length = deftaps; >+ } >+ >+ ret = -ENODEV; >+ ec_current = NULL; >+ >+ /* attempt to use the span's echo canceler; fall back to built-in >+ if it fails (but not if an error occurs) */ >+ if (chan->span && chan->span->echocan_create) >+ ret = chan->span->echocan_create(chan, ecp, params, &ec); >+ >+ if ((ret == -ENODEV) && chan->ec_factory) { >+#ifdef USE_ECHOCAN_REFCOUNT >+ /* try to get another reference to the module providing >+ this channel's echo canceler */ >+ if (!try_module_get(chan->ec_factory->owner)) { >+ module_printk(KERN_ERR, "Cannot get a reference to the '%s' echo canceler\n", chan->ec_factory->name); >+ goto exit_with_free; >+ } >+#endif >+ >+ /* got the reference, copy the pointer and use it for making >+ an echo canceler instance if possible */ >+ ec_current = chan->ec_factory; >+ >+ ret = ec_current->echocan_create(chan, ecp, params, &ec); >+ if (ret) { >+ release_echocan(ec_current); >+ >+ goto exit_with_free; >+ } >+ if (!ec) { >+ module_printk(KERN_ERR, "%s failed to allocate an " \ >+ "dahdi_echocan_state instance.\n", >+ ec_current->name); >+ ret = -EFAULT; >+ goto exit_with_free; >+ } >+ } >+ >+ if (ec) { >+ spin_lock_irqsave(&chan->lock, flags); >+ chan->ec_current = ec_current; >+ chan->ec_state = ec; >+ ec->status.mode = ECHO_MODE_ACTIVE; >+ if (!ec->features.CED_tx_detect) { >+ echo_can_disable_detector_init(&chan->ec_state->txecdis); >+ } >+ if (!ec->features.CED_rx_detect) { >+ echo_can_disable_detector_init(&chan->ec_state->rxecdis); >+ } >+ spin_unlock_irqrestore(&chan->lock, flags); >+ } >+ >+exit_with_free: >+ kfree(params); >+ >+ return ret; >+} >+ >+static void set_echocan_fax_mode(struct dahdi_chan *chan, unsigned int channo, const char *reason, unsigned int enable) >+{ >+ if (enable) { >+ if (!chan->ec_state) >+ module_printk(KERN_NOTICE, "Ignoring FAX mode request because of %s for channel %d with no echo canceller\n", reason, channo); >+ else if (chan->ec_state->status.mode == ECHO_MODE_FAX) >+ module_printk(KERN_NOTICE, "Ignoring FAX mode request because of %s for echo canceller already in FAX mode on channel %d\n", reason, channo); >+ else if (chan->ec_state->status.mode != ECHO_MODE_ACTIVE) >+ module_printk(KERN_NOTICE, "Ignoring FAX mode request because of %s for echo canceller not in active mode on channel %d\n", reason, channo); >+ else if (chan->ec_state->features.NLP_automatic) { >+ /* for echocans that automatically do the right thing, just >+ * mark it as being in FAX mode without making any >+ * changes, as none are necessary. >+ */ >+ chan->ec_state->status.mode = ECHO_MODE_FAX; >+ } else if (chan->ec_state->features.NLP_toggle) { >+ module_printk(KERN_NOTICE, "Disabled echo canceller NLP because of %s on channel %d\n", reason, channo); >+ dahdi_qevent_nolock(chan, DAHDI_EVENT_EC_NLP_DISABLED); >+ chan->ec_state->ops->echocan_NLP_toggle(chan->ec_state, 0); >+ chan->ec_state->status.mode = ECHO_MODE_FAX; >+ } else { >+ module_printk(KERN_NOTICE, "Idled echo canceller because of %s on channel %d\n", reason, channo); >+ chan->ec_state->status.mode = ECHO_MODE_IDLE; >+ } >+ } else { >+ if (!chan->ec_state) >+ module_printk(KERN_NOTICE, "Ignoring voice mode request because of %s for channel %d with no echo canceller\n", reason, channo); >+ else if (chan->ec_state->status.mode == ECHO_MODE_ACTIVE) >+ module_printk(KERN_NOTICE, "Ignoring voice mode request because of %s for echo canceller already in voice mode on channel %d\n", reason, channo); >+ else if ((chan->ec_state->status.mode != ECHO_MODE_FAX) && >+ (chan->ec_state->status.mode != ECHO_MODE_IDLE)) >+ module_printk(KERN_NOTICE, "Ignoring voice mode request because of %s for echo canceller not in FAX or idle mode on channel %d\n", reason, channo); >+ else if (chan->ec_state->features.NLP_automatic) { >+ /* for echocans that automatically do the right thing, just >+ * mark it as being in active mode without making any >+ * changes, as none are necessary. >+ */ >+ chan->ec_state->status.mode = ECHO_MODE_ACTIVE; >+ } else if (chan->ec_state->features.NLP_toggle) { >+ module_printk(KERN_NOTICE, "Enabled echo canceller NLP because of %s on channel %d\n", reason, channo); >+ dahdi_qevent_nolock(chan, DAHDI_EVENT_EC_NLP_ENABLED); >+ chan->ec_state->ops->echocan_NLP_toggle(chan->ec_state, 1); >+ chan->ec_state->status.mode = ECHO_MODE_ACTIVE; >+ } else { >+ module_printk(KERN_NOTICE, "Activated echo canceller because of %s on channel %d\n", reason, channo); >+ chan->ec_state->status.mode = ECHO_MODE_ACTIVE; >+ } >+ } >+} >+ >+static int dahdi_chan_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long data, int unit) >+{ >+ struct dahdi_chan *chan = chans[unit]; >+ unsigned long flags; >+ int j, rv; >+ int ret; >+ int oldconf; >+ void *rxgain=NULL; >+ >+ WARN_ON(!chan->master); >+ if (!chan) >+ return -ENOSYS; >+ >+ switch(cmd) { >+ case DAHDI_SETSIGFREEZE: >+ get_user(j, (int *)data); >+ spin_lock_irqsave(&chan->lock, flags); >+ if (j) { >+ chan->flags |= DAHDI_FLAG_SIGFREEZE; >+ } else { >+ chan->flags &= ~DAHDI_FLAG_SIGFREEZE; >+ } >+ spin_unlock_irqrestore(&chan->lock, flags); >+ break; >+ case DAHDI_GETSIGFREEZE: >+ spin_lock_irqsave(&chan->lock, flags); >+ if (chan->flags & DAHDI_FLAG_SIGFREEZE) >+ j = 1; >+ else >+ j = 0; >+ spin_unlock_irqrestore(&chan->lock, flags); >+ put_user(j, (int *)data); >+ break; >+ case DAHDI_AUDIOMODE: >+ /* Only literal clear channels can be put in */ >+ if (chan->sig != DAHDI_SIG_CLEAR) return (-EINVAL); >+ get_user(j, (int *)data); >+ if (j) { >+ spin_lock_irqsave(&chan->lock, flags); >+ chan->flags |= DAHDI_FLAG_AUDIO; >+ chan->flags &= ~(DAHDI_FLAG_HDLC | DAHDI_FLAG_FCS); >+ spin_unlock_irqrestore(&chan->lock, flags); >+ } else { >+ /* Coming out of audio mode, also clear all >+ conferencing and gain related info as well >+ as echo canceller */ >+ struct dahdi_echocan_state *ec_state; >+ const struct dahdi_echocan_factory *ec_current; >+ >+ spin_lock_irqsave(&chan->lock, flags); >+ chan->flags &= ~DAHDI_FLAG_AUDIO; >+ /* save old conf number, if any */ >+ oldconf = chan->confna; >+ /* initialize conference variables */ >+ chan->_confn = 0; >+ chan->confna = 0; >+ if (chan->span && chan->span->dacs) >+ chan->span->dacs(chan, NULL); >+ chan->confmode = 0; >+ chan->confmute = 0; >+ memset(chan->conflast, 0, sizeof(chan->conflast)); >+ memset(chan->conflast1, 0, sizeof(chan->conflast1)); >+ memset(chan->conflast2, 0, sizeof(chan->conflast2)); >+ ec_state = chan->ec_state; >+ chan->ec_state = NULL; >+ ec_current = chan->ec_current; >+ chan->ec_current = NULL; >+ /* release conference resource, if any to release */ >+ reset_conf(chan); >+ if (chan->gainalloc && chan->rxgain) >+ rxgain = chan->rxgain; >+ else >+ rxgain = NULL; >+ >+ chan->rxgain = defgain; >+ chan->txgain = defgain; >+ chan->gainalloc = 0; >+ spin_unlock_irqrestore(&chan->lock, flags); >+ >+ if (ec_state) { >+ ec_state->ops->echocan_free(chan, ec_state); >+ release_echocan(ec_current); >+ } >+ >+ if (rxgain) >+ kfree(rxgain); >+ if (oldconf) dahdi_check_conf(oldconf); >+ } >+ break; >+ case DAHDI_HDLCPPP: >+#ifdef CONFIG_DAHDI_PPP >+ if (chan->sig != DAHDI_SIG_CLEAR) return (-EINVAL); >+ get_user(j, (int *)data); >+ if (j) { >+ if (!chan->ppp) { >+ chan->ppp = kzalloc(sizeof(struct ppp_channel), GFP_KERNEL); >+ if (chan->ppp) { >+ struct dahdi_echocan_state *tec; >+ const struct dahdi_echocan_factory *ec_current; >+ >+ chan->ppp->private = chan; >+ chan->ppp->ops = &ztppp_ops; >+ chan->ppp->mtu = DAHDI_DEFAULT_MTU_MRU; >+ chan->ppp->hdrlen = 0; >+ skb_queue_head_init(&chan->ppp_rq); >+ chan->do_ppp_wakeup = 0; >+ tasklet_init(&chan->ppp_calls, do_ppp_calls, >+ (unsigned long)chan); >+ if ((ret = dahdi_reallocbufs(chan, DAHDI_DEFAULT_MTU_MRU, DAHDI_DEFAULT_NUM_BUFS))) { >+ kfree(chan->ppp); >+ chan->ppp = NULL; >+ return ret; >+ } >+ >+ if ((ret = ppp_register_channel(chan->ppp))) { >+ kfree(chan->ppp); >+ chan->ppp = NULL; >+ return ret; >+ } >+ tec = chan->ec_state; >+ chan->ec_state = NULL; >+ ec_current = chan->ec_current; >+ chan->ec_current = NULL; >+ /* Make sure there's no gain */ >+ if (chan->gainalloc) >+ kfree(chan->rxgain); >+ chan->rxgain = defgain; >+ chan->txgain = defgain; >+ chan->gainalloc = 0; >+ chan->flags &= ~DAHDI_FLAG_AUDIO; >+ chan->flags |= (DAHDI_FLAG_PPP | DAHDI_FLAG_HDLC | DAHDI_FLAG_FCS); >+ >+ if (tec) { >+ tec->ops->echocan_free(chan, tec); >+ release_echocan(ec_current); >+ } >+ } else >+ return -ENOMEM; >+ } >+ } else { >+ chan->flags &= ~(DAHDI_FLAG_PPP | DAHDI_FLAG_HDLC | DAHDI_FLAG_FCS); >+ if (chan->ppp) { >+ struct ppp_channel *ppp = chan->ppp; >+ chan->ppp = NULL; >+ tasklet_kill(&chan->ppp_calls); >+ skb_queue_purge(&chan->ppp_rq); >+ ppp_unregister_channel(ppp); >+ kfree(ppp); >+ } >+ } >+#else >+ module_printk(KERN_NOTICE, "PPP support not compiled in\n"); >+ return -ENOSYS; >+#endif >+ break; >+ case DAHDI_HDLCRAWMODE: >+ if (chan->sig != DAHDI_SIG_CLEAR) return (-EINVAL); >+ get_user(j, (int *)data); >+ chan->flags &= ~(DAHDI_FLAG_AUDIO | DAHDI_FLAG_HDLC | DAHDI_FLAG_FCS); >+ if (j) { >+ chan->flags |= DAHDI_FLAG_HDLC; >+ fasthdlc_init(&chan->rxhdlc, (chan->flags & DAHDI_FLAG_HDLC56) ? FASTHDLC_MODE_56 : FASTHDLC_MODE_64); >+ fasthdlc_init(&chan->txhdlc, (chan->flags & DAHDI_FLAG_HDLC56) ? FASTHDLC_MODE_56 : FASTHDLC_MODE_64); >+ } >+ break; >+ case DAHDI_HDLCFCSMODE: >+ if (chan->sig != DAHDI_SIG_CLEAR) return (-EINVAL); >+ get_user(j, (int *)data); >+ chan->flags &= ~(DAHDI_FLAG_AUDIO | DAHDI_FLAG_HDLC | DAHDI_FLAG_FCS); >+ if (j) { >+ chan->flags |= DAHDI_FLAG_HDLC | DAHDI_FLAG_FCS; >+ fasthdlc_init(&chan->rxhdlc, (chan->flags & DAHDI_FLAG_HDLC56) ? FASTHDLC_MODE_56 : FASTHDLC_MODE_64); >+ fasthdlc_init(&chan->txhdlc, (chan->flags & DAHDI_FLAG_HDLC56) ? FASTHDLC_MODE_56 : FASTHDLC_MODE_64); >+ } >+ break; >+ case DAHDI_HDLC_RATE: >+ get_user(j, (int *) data); >+ if (j == 56) { >+ chan->flags |= DAHDI_FLAG_HDLC56; >+ } else { >+ chan->flags &= ~DAHDI_FLAG_HDLC56; >+ } >+ >+ fasthdlc_init(&chan->rxhdlc, (chan->flags & DAHDI_FLAG_HDLC56) ? FASTHDLC_MODE_56 : FASTHDLC_MODE_64); >+ fasthdlc_init(&chan->txhdlc, (chan->flags & DAHDI_FLAG_HDLC56) ? FASTHDLC_MODE_56 : FASTHDLC_MODE_64); >+ break; >+ case DAHDI_ECHOCANCEL_PARAMS: >+ { >+ struct dahdi_echocanparams ecp; >+ >+ if (!(chan->flags & DAHDI_FLAG_AUDIO)) >+ return -EINVAL; >+ if (copy_from_user(&ecp, (struct dahdi_echocanparams *) data, sizeof(ecp))) >+ return -EFAULT; >+ data += sizeof(ecp); >+ if ((ret = ioctl_echocancel(chan, &ecp, (void *) data))) >+ return ret; >+ break; >+ } >+ case DAHDI_ECHOCANCEL: >+ { >+ struct dahdi_echocanparams ecp; >+ >+ if (!(chan->flags & DAHDI_FLAG_AUDIO)) >+ return -EINVAL; >+ get_user(j, (int *) data); >+ ecp.tap_length = j; >+ ecp.param_count = 0; >+ if ((ret = ioctl_echocancel(chan, &ecp, NULL))) >+ return ret; >+ break; >+ } >+ case DAHDI_ECHOTRAIN: >+ get_user(j, (int *)data); /* get pre-training time from user */ >+ if ((j < 0) || (j >= DAHDI_MAX_PRETRAINING)) >+ return -EINVAL; >+ j <<= 3; >+ if (chan->ec_state) { >+ /* Start pretraining stage */ >+ spin_lock_irqsave(&chan->lock, flags); >+ chan->ec_state->status.mode = ECHO_MODE_PRETRAINING; >+ chan->ec_state->status.pretrain_timer = j; >+ spin_unlock_irqrestore(&chan->lock, flags); >+ } else >+ return -EINVAL; >+ break; >+ case DAHDI_ECHOCANCEL_FAX_MODE: >+ if (!chan->ec_state) { >+ return -EINVAL; >+ } else { >+ get_user(j, (int *) data); >+ spin_lock_irqsave(&chan->lock, flags); >+ set_echocan_fax_mode(chan, chan->channo, "ioctl", j ? 1 : 0); >+ spin_unlock_irqrestore(&chan->lock, flags); >+ } >+ break; >+ case DAHDI_SETTXBITS: >+ if (chan->sig != DAHDI_SIG_CAS) >+ return -EINVAL; >+ get_user(j,(int *)data); >+ dahdi_cas_setbits(chan, j); >+ break; >+ case DAHDI_GETRXBITS: >+ put_user(chan->rxsig, (int *)data); >+ break; >+ case DAHDI_LOOPBACK: >+ get_user(j, (int *)data); >+ spin_lock_irqsave(&chan->lock, flags); >+ if (j) >+ chan->flags |= DAHDI_FLAG_LOOPED; >+ else >+ chan->flags &= ~DAHDI_FLAG_LOOPED; >+ spin_unlock_irqrestore(&chan->lock, flags); >+ break; >+ case DAHDI_HOOK: >+ get_user(j,(int *)data); >+ if (chan->flags & DAHDI_FLAG_CLEAR) >+ return -EINVAL; >+ if (chan->sig == DAHDI_SIG_CAS) >+ return -EINVAL; >+ /* if no span, just do nothing */ >+ if (!chan->span) return(0); >+ spin_lock_irqsave(&chan->lock, flags); >+ /* if dialing, stop it */ >+ chan->curtone = NULL; >+ chan->dialing = 0; >+ chan->txdialbuf[0] = '\0'; >+ chan->tonep = 0; >+ chan->pdialcount = 0; >+ spin_unlock_irqrestore(&chan->lock, flags); >+ if (chan->span->flags & DAHDI_FLAG_RBS) { >+ switch (j) { >+ case DAHDI_ONHOOK: >+ spin_lock_irqsave(&chan->lock, flags); >+ dahdi_hangup(chan); >+ spin_unlock_irqrestore(&chan->lock, flags); >+ break; >+ case DAHDI_OFFHOOK: >+ spin_lock_irqsave(&chan->lock, flags); >+ if ((chan->txstate == DAHDI_TXSTATE_KEWL) || >+ (chan->txstate == DAHDI_TXSTATE_AFTERKEWL)) { >+ spin_unlock_irqrestore(&chan->lock, flags); >+ return -EBUSY; >+ } >+ dahdi_rbs_sethook(chan, DAHDI_TXSIG_OFFHOOK, DAHDI_TXSTATE_DEBOUNCE, chan->debouncetime); >+ spin_unlock_irqrestore(&chan->lock, flags); >+ break; >+ case DAHDI_RING: >+ case DAHDI_START: >+ spin_lock_irqsave(&chan->lock, flags); >+ if (!chan->curzone) { >+ spin_unlock_irqrestore(&chan->lock, flags); >+ module_printk(KERN_WARNING, "Cannot start tone until a tone zone is loaded.\n"); >+ return -ENODATA; >+ } >+ if (chan->txstate != DAHDI_TXSTATE_ONHOOK) { >+ spin_unlock_irqrestore(&chan->lock, flags); >+ return -EBUSY; >+ } >+ if (chan->sig & __DAHDI_SIG_FXO) { >+ ret = 0; >+ chan->cadencepos = 0; >+ ret = chan->ringcadence[0]; >+ dahdi_rbs_sethook(chan, DAHDI_TXSIG_START, DAHDI_TXSTATE_RINGON, ret); >+ } else >+ dahdi_rbs_sethook(chan, DAHDI_TXSIG_START, DAHDI_TXSTATE_START, chan->starttime); >+ spin_unlock_irqrestore(&chan->lock, flags); >+ if (file->f_flags & O_NONBLOCK) >+ return -EINPROGRESS; >+#if 0 >+ rv = schluffen(&chan->txstateq); >+ if (rv) return rv; >+#endif >+ break; >+ case DAHDI_WINK: >+ spin_lock_irqsave(&chan->lock, flags); >+ if (chan->txstate != DAHDI_TXSTATE_ONHOOK) { >+ spin_unlock_irqrestore(&chan->lock, flags); >+ return -EBUSY; >+ } >+ dahdi_rbs_sethook(chan, DAHDI_TXSIG_ONHOOK, DAHDI_TXSTATE_PREWINK, chan->prewinktime); >+ spin_unlock_irqrestore(&chan->lock, flags); >+ if (file->f_flags & O_NONBLOCK) >+ return -EINPROGRESS; >+ rv = schluffen(&chan->txstateq); >+ if (rv) return rv; >+ break; >+ case DAHDI_FLASH: >+ spin_lock_irqsave(&chan->lock, flags); >+ if (chan->txstate != DAHDI_TXSTATE_OFFHOOK) { >+ spin_unlock_irqrestore(&chan->lock, flags); >+ return -EBUSY; >+ } >+ dahdi_rbs_sethook(chan, DAHDI_TXSIG_OFFHOOK, DAHDI_TXSTATE_PREFLASH, chan->preflashtime); >+ spin_unlock_irqrestore(&chan->lock, flags); >+ if (file->f_flags & O_NONBLOCK) >+ return -EINPROGRESS; >+ rv = schluffen(&chan->txstateq); >+ if (rv) return rv; >+ break; >+ case DAHDI_RINGOFF: >+ spin_lock_irqsave(&chan->lock, flags); >+ dahdi_rbs_sethook(chan, DAHDI_TXSIG_ONHOOK, DAHDI_TXSTATE_ONHOOK, 0); >+ spin_unlock_irqrestore(&chan->lock, flags); >+ break; >+ default: >+ return -EINVAL; >+ } >+ } else if (chan->span->sethook) { >+ if (chan->txhooksig != j) { >+ chan->txhooksig = j; >+ chan->span->sethook(chan, j); >+ } >+ } else >+ return -ENOSYS; >+ break; >+#ifdef CONFIG_DAHDI_PPP >+ case PPPIOCGCHAN: >+ if (chan->flags & DAHDI_FLAG_PPP) >+ return put_user(ppp_channel_index(chan->ppp), (int *)data) ? -EFAULT : 0; >+ else >+ return -EINVAL; >+ break; >+ case PPPIOCGUNIT: >+ if (chan->flags & DAHDI_FLAG_PPP) >+ return put_user(ppp_unit_number(chan->ppp), (int *)data) ? -EFAULT : 0; >+ else >+ return -EINVAL; >+ break; >+#endif >+ default: >+ return dahdi_chanandpseudo_ioctl(inode, file, cmd, data, unit); >+ } >+ return 0; >+} >+ >+static int dahdi_prechan_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long data, int unit) >+{ >+ struct dahdi_chan *chan = file->private_data; >+ int channo; >+ int res; >+ >+ if (chan) { >+ module_printk(KERN_NOTICE, "Huh? Prechan already has private data??\n"); >+ } >+ switch(cmd) { >+ case DAHDI_SPECIFY: >+ get_user(channo,(int *)data); >+ if (channo < 1) >+ return -EINVAL; >+ if (channo > DAHDI_MAX_CHANNELS) >+ return -EINVAL; >+ res = dahdi_specchan_open(inode, file, channo); >+ if (!res) { >+ /* Setup the pointer for future stuff */ >+ chan = chans[channo]; >+ file->private_data = chan; >+ /* Return success */ >+ return 0; >+ } >+ return res; >+ default: >+ return -ENOSYS; >+ } >+ return 0; >+} >+ >+static int dahdi_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long data) >+{ >+ int unit = UNIT(file); >+ struct dahdi_chan *chan; >+ struct dahdi_timer *timer; >+ >+ if (!unit) >+ return dahdi_ctl_ioctl(inode, file, cmd, data); >+ >+ if (unit == 250) { >+ /* dahdi_transcode should have updated the file_operations on >+ * this file object on open, so we shouldn't be here. */ >+ WARN_ON(1); >+ return -EFAULT; >+ } >+ >+ if (unit == 253) { >+ timer = file->private_data; >+ if (timer) >+ return dahdi_timer_ioctl(inode, file, cmd, data, timer); >+ else >+ return -EINVAL; >+ } >+ if (unit == 254) { >+ chan = file->private_data; >+ if (chan) >+ return dahdi_chan_ioctl(inode, file, cmd, data, chan->channo); >+ else >+ return dahdi_prechan_ioctl(inode, file, cmd, data, unit); >+ } >+ if (unit == 255) { >+ chan = file->private_data; >+ if (!chan) { >+ module_printk(KERN_NOTICE, "No pseudo channel structure to read?\n"); >+ return -EINVAL; >+ } >+ return dahdi_chanandpseudo_ioctl(inode, file, cmd, data, chan->channo); >+ } >+ return dahdi_chan_ioctl(inode, file, cmd, data, unit); >+} >+ >+int dahdi_register(struct dahdi_span *span, int prefmaster) >+{ >+ int x; >+ >+ if (!span) >+ return -EINVAL; >+ >+ if (test_bit(DAHDI_FLAGBIT_REGISTERED, &span->flags)) { >+ module_printk(KERN_ERR, "Span %s already appears to be registered\n", span->name); >+ return -EBUSY; >+ } >+ >+ for (x = 1; x < maxspans; x++) { >+ if (spans[x] == span) { >+ module_printk(KERN_ERR, "Span %s already in list\n", span->name); >+ return -EBUSY; >+ } >+ } >+ >+ for (x = 1; x < DAHDI_MAX_SPANS; x++) { >+ if (!spans[x]) >+ break; >+ } >+ >+ if (x < DAHDI_MAX_SPANS) { >+ spans[x] = span; >+ if (maxspans < x + 1) >+ maxspans = x + 1; >+ } else { >+ module_printk(KERN_ERR, "Too many DAHDI spans registered\n"); >+ return -EBUSY; >+ } >+ >+ set_bit(DAHDI_FLAGBIT_REGISTERED, &span->flags); >+ span->spanno = x; >+ >+ spin_lock_init(&span->lock); >+ >+ if (!span->deflaw) { >+ module_printk(KERN_NOTICE, "Span %s didn't specify default law. " >+ "Assuming mulaw, please fix driver!\n", span->name); >+ span->deflaw = DAHDI_LAW_MULAW; >+ } >+ >+ for (x = 0; x < span->channels; x++) { >+ span->chans[x]->span = span; >+ dahdi_chan_reg(span->chans[x]); >+ } >+ >+#ifdef CONFIG_PROC_FS >+ { >+ char tempfile[17]; >+ snprintf(tempfile, sizeof(tempfile), "dahdi/%d", span->spanno); >+ proc_entries[span->spanno] = create_proc_read_entry(tempfile, 0444, >+ NULL, dahdi_proc_read, (int *) (long) span->spanno); >+ } >+#endif >+ >+ for (x = 0; x < span->channels; x++) { >+ if (span->chans[x]->channo < 250) { >+ char chan_name[32]; >+ snprintf(chan_name, sizeof(chan_name), "dahdi!%d", >+ span->chans[x]->channo); >+ CLASS_DEV_CREATE(dahdi_class, MKDEV(DAHDI_MAJOR, >+ span->chans[x]->channo), NULL, chan_name); >+ } >+ } >+ >+ if (debug) { >+ module_printk(KERN_NOTICE, "Registered Span %d ('%s') with " >+ "%d channels\n", span->spanno, span->name, span->channels); >+ } >+ >+ if (!master || prefmaster) { >+ master = span; >+ if (debug) { >+ module_printk(KERN_NOTICE, "Span ('%s') is new master\n", >+ span->name); >+ } >+ } >+ >+ return 0; >+} >+ >+int dahdi_unregister(struct dahdi_span *span) >+{ >+ int x; >+ int new_maxspans; >+ static struct dahdi_span *new_master; >+ >+#ifdef CONFIG_PROC_FS >+ char tempfile[17]; >+#endif /* CONFIG_PROC_FS */ >+ >+ if (!test_bit(DAHDI_FLAGBIT_REGISTERED, &span->flags)) { >+ module_printk(KERN_ERR, "Span %s does not appear to be registered\n", span->name); >+ return -1; >+ } >+ /* Shutdown the span if it's running */ >+ if (span->flags & DAHDI_FLAG_RUNNING) >+ if (span->shutdown) >+ span->shutdown(span); >+ >+ if (spans[span->spanno] != span) { >+ module_printk(KERN_ERR, "Span %s has spanno %d which is something else\n", span->name, span->spanno); >+ return -1; >+ } >+ if (debug) >+ module_printk(KERN_NOTICE, "Unregistering Span '%s' with %d channels\n", span->name, span->channels); >+#ifdef CONFIG_PROC_FS >+ snprintf(tempfile, sizeof(tempfile)-1, "dahdi/%d", span->spanno); >+ remove_proc_entry(tempfile, NULL); >+#endif /* CONFIG_PROC_FS */ >+ >+ for (x = 0; x < span->channels; x++) { >+ if (span->chans[x]->channo < 250) >+ CLASS_DEV_DESTROY(dahdi_class, MKDEV(DAHDI_MAJOR, span->chans[x]->channo)); >+ } >+ >+ spans[span->spanno] = NULL; >+ span->spanno = 0; >+ clear_bit(DAHDI_FLAGBIT_REGISTERED, &span->flags); >+ for (x=0;x<span->channels;x++) >+ dahdi_chan_unreg(span->chans[x]); >+ new_maxspans = 0; >+ new_master = master; /* FIXME: locking */ >+ if (master == span) >+ new_master = NULL; >+ for (x=1;x<DAHDI_MAX_SPANS;x++) { >+ if (spans[x]) { >+ new_maxspans = x+1; >+ if (!new_master) >+ new_master = spans[x]; >+ } >+ } >+ maxspans = new_maxspans; >+ if (master != new_master) >+ if (debug) >+ module_printk(KERN_NOTICE, "%s: Span ('%s') is new master\n", __FUNCTION__, >+ (new_master)? new_master->name: "no master"); >+ master = new_master; >+ >+ return 0; >+} >+ >+/* >+** This routine converts from linear to ulaw >+** >+** Craig Reese: IDA/Supercomputing Research Center >+** Joe Campbell: Department of Defense >+** 29 September 1989 >+** >+** References: >+** 1) CCITT Recommendation G.711 (very difficult to follow) >+** 2) "A New Digital Technique for Implementation of Any >+** Continuous PCM Companding Law," Villeret, Michel, >+** et al. 1973 IEEE Int. Conf. on Communications, Vol 1, >+** 1973, pg. 11.12-11.17 >+** 3) MIL-STD-188-113,"Interoperability and Performance Standards >+** for Analog-to_Digital Conversion Techniques," >+** 17 February 1987 >+** >+** Input: Signed 16 bit linear sample >+** Output: 8 bit ulaw sample >+*/ >+ >+#define ZEROTRAP /* turn on the trap as per the MIL-STD */ >+#define BIAS 0x84 /* define the add-in bias for 16 bit samples */ >+#define CLIP 32635 >+ >+#ifdef CONFIG_CALC_XLAW >+unsigned char >+#else >+static unsigned char __init >+#endif >+__dahdi_lineartoulaw(short sample) >+{ >+ static int exp_lut[256] = {0,0,1,1,2,2,2,2,3,3,3,3,3,3,3,3, >+ 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, >+ 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, >+ 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, >+ 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, >+ 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, >+ 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, >+ 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, >+ 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, >+ 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, >+ 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, >+ 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, >+ 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, >+ 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, >+ 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, >+ 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7}; >+ int sign, exponent, mantissa; >+ unsigned char ulawbyte; >+ >+ /* Get the sample into sign-magnitude. */ >+ sign = (sample >> 8) & 0x80; /* set aside the sign */ >+ if (sign != 0) sample = -sample; /* get magnitude */ >+ if (sample > CLIP) sample = CLIP; /* clip the magnitude */ >+ >+ /* Convert from 16 bit linear to ulaw. */ >+ sample = sample + BIAS; >+ exponent = exp_lut[(sample >> 7) & 0xFF]; >+ mantissa = (sample >> (exponent + 3)) & 0x0F; >+ ulawbyte = ~(sign | (exponent << 4) | mantissa); >+#ifdef ZEROTRAP >+ if (ulawbyte == 0) ulawbyte = 0x02; /* optional CCITT trap */ >+#endif >+ if (ulawbyte == 0xff) ulawbyte = 0x7f; /* never return 0xff */ >+ return(ulawbyte); >+} >+ >+#define AMI_MASK 0x55 >+ >+#ifdef CONFIG_CALC_XLAW >+unsigned char >+#else >+static inline unsigned char __init >+#endif >+__dahdi_lineartoalaw (short linear) >+{ >+ int mask; >+ int seg; >+ int pcm_val; >+ static int seg_end[8] = >+ { >+ 0xFF, 0x1FF, 0x3FF, 0x7FF, 0xFFF, 0x1FFF, 0x3FFF, 0x7FFF >+ }; >+ >+ pcm_val = linear; >+ if (pcm_val >= 0) >+ { >+ /* Sign (7th) bit = 1 */ >+ mask = AMI_MASK | 0x80; >+ } >+ else >+ { >+ /* Sign bit = 0 */ >+ mask = AMI_MASK; >+ pcm_val = -pcm_val; >+ } >+ >+ /* Convert the scaled magnitude to segment number. */ >+ for (seg = 0; seg < 8; seg++) >+ { >+ if (pcm_val <= seg_end[seg]) >+ break; >+ } >+ /* Combine the sign, segment, and quantization bits. */ >+ return ((seg << 4) | ((pcm_val >> ((seg) ? (seg + 3) : 4)) & 0x0F)) ^ mask; >+} >+/*- End of function --------------------------------------------------------*/ >+ >+static inline short int __init alaw2linear (uint8_t alaw) >+{ >+ int i; >+ int seg; >+ >+ alaw ^= AMI_MASK; >+ i = ((alaw & 0x0F) << 4); >+ seg = (((int) alaw & 0x70) >> 4); >+ if (seg) >+ i = (i + 0x100) << (seg - 1); >+ return (short int) ((alaw & 0x80) ? i : -i); >+} >+/*- End of function --------------------------------------------------------*/ >+static void __init dahdi_conv_init(void) >+{ >+ int i; >+ >+ /* >+ * Set up mu-law conversion table >+ */ >+ for(i = 0;i < 256;i++) >+ { >+ short mu,e,f,y; >+ static short etab[]={0,132,396,924,1980,4092,8316,16764}; >+ >+ mu = 255-i; >+ e = (mu & 0x70)/16; >+ f = mu & 0x0f; >+ y = f * (1 << (e + 3)); >+ y += etab[e]; >+ if (mu & 0x80) y = -y; >+ __dahdi_mulaw[i] = y; >+ __dahdi_alaw[i] = alaw2linear(i); >+ /* Default (0.0 db) gain table */ >+ defgain[i] = i; >+ } >+#ifndef CONFIG_CALC_XLAW >+ /* set up the reverse (mu-law) conversion table */ >+ for(i = -32768; i < 32768; i += 4) >+ { >+ __dahdi_lin2mu[((unsigned short)(short)i) >> 2] = __dahdi_lineartoulaw(i); >+ __dahdi_lin2a[((unsigned short)(short)i) >> 2] = __dahdi_lineartoalaw(i); >+ } >+#endif >+} >+ >+static inline void __dahdi_process_getaudio_chunk(struct dahdi_chan *ss, unsigned char *txb) >+{ >+ /* We transmit data from our master channel */ >+ /* Called with ss->lock held */ >+ struct dahdi_chan *ms = ss->master; >+ /* Linear representation */ >+ short getlin[DAHDI_CHUNKSIZE], k[DAHDI_CHUNKSIZE]; >+ int x; >+ >+ /* Okay, now we've got something to transmit */ >+ for (x=0;x<DAHDI_CHUNKSIZE;x++) >+ getlin[x] = DAHDI_XLAW(txb[x], ms); >+ >+ if (ms->ec_state && (ms->ec_state->status.mode == ECHO_MODE_ACTIVE) && !ms->ec_state->features.CED_tx_detect) { >+ for (x = 0; x < DAHDI_CHUNKSIZE; x++) { >+ if (echo_can_disable_detector_update(&ms->ec_state->txecdis, getlin[x])) { >+ set_echocan_fax_mode(ms, ss->channo, "CED tx detected", 1); >+ dahdi_qevent_nolock(ms, DAHDI_EVENT_TX_CED_DETECTED); >+ break; >+ } >+ } >+ } >+ >+ if ((!ms->confmute && !ms->dialing) || (ms->flags & DAHDI_FLAG_PSEUDO)) { >+ /* Handle conferencing on non-clear channel and non-HDLC channels */ >+ switch(ms->confmode & DAHDI_CONF_MODE_MASK) { >+ case DAHDI_CONF_NORMAL: >+ /* Do nuffin */ >+ break; >+ case DAHDI_CONF_MONITOR: /* Monitor a channel's rx mode */ >+ /* if a pseudo-channel, ignore */ >+ if (ms->flags & DAHDI_FLAG_PSEUDO) break; >+ /* Add monitored channel */ >+ if (chans[ms->confna]->flags & DAHDI_FLAG_PSEUDO) { >+ ACSS(getlin, chans[ms->confna]->getlin); >+ } else { >+ ACSS(getlin, chans[ms->confna]->putlin); >+ } >+ for (x=0;x<DAHDI_CHUNKSIZE;x++) >+ txb[x] = DAHDI_LIN2X(getlin[x], ms); >+ break; >+ case DAHDI_CONF_MONITORTX: /* Monitor a channel's tx mode */ >+ /* if a pseudo-channel, ignore */ >+ if (ms->flags & DAHDI_FLAG_PSEUDO) break; >+ /* Add monitored channel */ >+ if (chans[ms->confna]->flags & DAHDI_FLAG_PSEUDO) { >+ ACSS(getlin, chans[ms->confna]->putlin); >+ } else { >+ ACSS(getlin, chans[ms->confna]->getlin); >+ } >+ >+ for (x=0;x<DAHDI_CHUNKSIZE;x++) >+ txb[x] = DAHDI_LIN2X(getlin[x], ms); >+ break; >+ case DAHDI_CONF_MONITORBOTH: /* monitor a channel's rx and tx mode */ >+ /* if a pseudo-channel, ignore */ >+ if (ms->flags & DAHDI_FLAG_PSEUDO) break; >+ ACSS(getlin, chans[ms->confna]->putlin); >+ ACSS(getlin, chans[ms->confna]->getlin); >+ for (x=0;x<DAHDI_CHUNKSIZE;x++) >+ txb[x] = DAHDI_LIN2X(getlin[x], ms); >+ break; >+ case DAHDI_CONF_MONITOR_RX_PREECHO: /* Monitor a channel's rx mode */ >+ /* if a pseudo-channel, ignore */ >+ if (ms->flags & DAHDI_FLAG_PSEUDO) >+ break; >+ >+ if (!chans[ms->confna]->readchunkpreec) >+ break; >+ >+ /* Add monitored channel */ >+ ACSS(getlin, chans[ms->confna]->flags & DAHDI_FLAG_PSEUDO ? >+ chans[ms->confna]->readchunkpreec : chans[ms->confna]->putlin); >+ for (x = 0; x < DAHDI_CHUNKSIZE; x++) >+ txb[x] = DAHDI_LIN2X(getlin[x], ms); >+ >+ break; >+ case DAHDI_CONF_MONITOR_TX_PREECHO: /* Monitor a channel's tx mode */ >+ /* if a pseudo-channel, ignore */ >+ if (ms->flags & DAHDI_FLAG_PSEUDO) >+ break; >+ >+ if (!chans[ms->confna]->readchunkpreec) >+ break; >+ >+ /* Add monitored channel */ >+ ACSS(getlin, chans[ms->confna]->flags & DAHDI_FLAG_PSEUDO ? >+ chans[ms->confna]->putlin : chans[ms->confna]->readchunkpreec); >+ for (x = 0; x < DAHDI_CHUNKSIZE; x++) >+ txb[x] = DAHDI_LIN2X(getlin[x], ms); >+ >+ break; >+ case DAHDI_CONF_MONITORBOTH_PREECHO: /* monitor a channel's rx and tx mode */ >+ /* if a pseudo-channel, ignore */ >+ if (ms->flags & DAHDI_FLAG_PSEUDO) >+ break; >+ >+ if (!chans[ms->confna]->readchunkpreec) >+ break; >+ >+ ACSS(getlin, chans[ms->confna]->putlin); >+ ACSS(getlin, chans[ms->confna]->readchunkpreec); >+ >+ for (x = 0; x < DAHDI_CHUNKSIZE; x++) >+ txb[x] = DAHDI_LIN2X(getlin[x], ms); >+ >+ break; >+ case DAHDI_CONF_REALANDPSEUDO: >+ /* This strange mode takes the transmit buffer and >+ puts it on the conference, minus its last sample, >+ then outputs from the conference minus the >+ real channel's last sample. */ >+ /* if to talk on conf */ >+ if (ms->confmode & DAHDI_CONF_PSEUDO_TALKER) { >+ /* Store temp value */ >+ memcpy(k, getlin, DAHDI_CHUNKSIZE * sizeof(short)); >+ /* Add conf value */ >+ ACSS(k, conf_sums_next[ms->_confn]); >+ /* save last one */ >+ memcpy(ms->conflast2, ms->conflast1, DAHDI_CHUNKSIZE * sizeof(short)); >+ memcpy(ms->conflast1, k, DAHDI_CHUNKSIZE * sizeof(short)); >+ /* get amount actually added */ >+ SCSS(ms->conflast1, conf_sums_next[ms->_confn]); >+ /* Really add in new value */ >+ ACSS(conf_sums_next[ms->_confn], ms->conflast1); >+ } else { >+ memset(ms->conflast1, 0, DAHDI_CHUNKSIZE * sizeof(short)); >+ memset(ms->conflast2, 0, DAHDI_CHUNKSIZE * sizeof(short)); >+ } >+ memset(getlin, 0, DAHDI_CHUNKSIZE * sizeof(short)); >+ txb[0] = DAHDI_LIN2X(0, ms); >+ memset(txb + 1, txb[0], DAHDI_CHUNKSIZE - 1); >+ /* fall through to normal conf mode */ >+ case DAHDI_CONF_CONF: /* Normal conference mode */ >+ if (ms->flags & DAHDI_FLAG_PSEUDO) /* if pseudo-channel */ >+ { >+ /* if to talk on conf */ >+ if (ms->confmode & DAHDI_CONF_TALKER) { >+ /* Store temp value */ >+ memcpy(k, getlin, DAHDI_CHUNKSIZE * sizeof(short)); >+ /* Add conf value */ >+ ACSS(k, conf_sums[ms->_confn]); >+ /* get amount actually added */ >+ memcpy(ms->conflast, k, DAHDI_CHUNKSIZE * sizeof(short)); >+ SCSS(ms->conflast, conf_sums[ms->_confn]); >+ /* Really add in new value */ >+ ACSS(conf_sums[ms->_confn], ms->conflast); >+ memcpy(ms->getlin, getlin, DAHDI_CHUNKSIZE * sizeof(short)); >+ } else { >+ memset(ms->conflast, 0, DAHDI_CHUNKSIZE * sizeof(short)); >+ memcpy(getlin, ms->getlin, DAHDI_CHUNKSIZE * sizeof(short)); >+ } >+ txb[0] = DAHDI_LIN2X(0, ms); >+ memset(txb + 1, txb[0], DAHDI_CHUNKSIZE - 1); >+ break; >+ } >+ /* fall through */ >+ case DAHDI_CONF_CONFMON: /* Conference monitor mode */ >+ if (ms->confmode & DAHDI_CONF_LISTENER) { >+ /* Subtract out last sample written to conf */ >+ SCSS(getlin, ms->conflast); >+ /* Add in conference */ >+ ACSS(getlin, conf_sums[ms->_confn]); >+ } >+ for (x=0;x<DAHDI_CHUNKSIZE;x++) >+ txb[x] = DAHDI_LIN2X(getlin[x], ms); >+ break; >+ case DAHDI_CONF_CONFANN: >+ case DAHDI_CONF_CONFANNMON: >+ /* First, add tx buffer to conf */ >+ ACSS(conf_sums_next[ms->_confn], getlin); >+ /* Start with silence */ >+ memset(getlin, 0, DAHDI_CHUNKSIZE * sizeof(short)); >+ /* If a listener on the conf... */ >+ if (ms->confmode & DAHDI_CONF_LISTENER) { >+ /* Subtract last value written */ >+ SCSS(getlin, ms->conflast); >+ /* Add in conf */ >+ ACSS(getlin, conf_sums[ms->_confn]); >+ } >+ for (x=0;x<DAHDI_CHUNKSIZE;x++) >+ txb[x] = DAHDI_LIN2X(getlin[x], ms); >+ break; >+ case DAHDI_CONF_DIGITALMON: >+ /* Real digital monitoring, but still echo cancel if desired */ >+ if (!chans[ms->confna]) >+ break; >+ if (chans[ms->confna]->flags & DAHDI_FLAG_PSEUDO) { >+ if (ms->ec_state) { >+ for (x=0;x<DAHDI_CHUNKSIZE;x++) >+ txb[x] = DAHDI_LIN2X(chans[ms->confna]->getlin[x], ms); >+ } else { >+ memcpy(txb, chans[ms->confna]->getraw, DAHDI_CHUNKSIZE); >+ } >+ } else { >+ if (ms->ec_state) { >+ for (x=0;x<DAHDI_CHUNKSIZE;x++) >+ txb[x] = DAHDI_LIN2X(chans[ms->confna]->putlin[x], ms); >+ } else { >+ memcpy(txb, chans[ms->confna]->putraw, DAHDI_CHUNKSIZE); >+ } >+ } >+ for (x=0;x<DAHDI_CHUNKSIZE;x++) >+ getlin[x] = DAHDI_XLAW(txb[x], ms); >+ break; >+ } >+ } >+ if (ms->confmute || (ms->ec_state && (ms->ec_state->status.mode) & __ECHO_MODE_MUTE)) { >+ txb[0] = DAHDI_LIN2X(0, ms); >+ memset(txb + 1, txb[0], DAHDI_CHUNKSIZE - 1); >+ if (ms->ec_state && (ms->ec_state->status.mode == ECHO_MODE_STARTTRAINING)) { >+ /* Transmit impulse now */ >+ txb[0] = DAHDI_LIN2X(16384, ms); >+ ms->ec_state->status.mode = ECHO_MODE_AWAITINGECHO; >+ } >+ } >+ /* save value from last chunk */ >+ memcpy(ms->getlin_lastchunk, ms->getlin, DAHDI_CHUNKSIZE * sizeof(short)); >+ /* save value from current */ >+ memcpy(ms->getlin, getlin, DAHDI_CHUNKSIZE * sizeof(short)); >+ /* save value from current */ >+ memcpy(ms->getraw, txb, DAHDI_CHUNKSIZE); >+ /* if to make tx tone */ >+ if (ms->v1_1 || ms->v2_1 || ms->v3_1) >+ { >+ for (x=0;x<DAHDI_CHUNKSIZE;x++) >+ { >+ getlin[x] += dahdi_txtone_nextsample(ms); >+ txb[x] = DAHDI_LIN2X(getlin[x], ms); >+ } >+ } >+ /* This is what to send (after having applied gain) */ >+ for (x=0;x<DAHDI_CHUNKSIZE;x++) >+ txb[x] = ms->txgain[txb[x]]; >+} >+ >+static inline void __dahdi_getbuf_chunk(struct dahdi_chan *ss, unsigned char *txb) >+{ >+ /* Called with ss->lock held */ >+ /* We transmit data from our master channel */ >+ struct dahdi_chan *ms = ss->master; >+ /* Buffer we're using */ >+ unsigned char *buf; >+ /* Old buffer number */ >+ int oldbuf; >+ /* Linear representation */ >+ int getlin; >+ /* How many bytes we need to process */ >+ int bytes = DAHDI_CHUNKSIZE, left; >+ int x; >+ >+ /* Let's pick something to transmit. First source to >+ try is our write-out buffer. Always check it first because >+ its our 'fast path' for whatever that's worth. */ >+ while(bytes) { >+ if ((ms->outwritebuf > -1) && !ms->txdisable) { >+ buf= ms->writebuf[ms->outwritebuf]; >+ left = ms->writen[ms->outwritebuf] - ms->writeidx[ms->outwritebuf]; >+ if (left > bytes) >+ left = bytes; >+ if (ms->flags & DAHDI_FLAG_HDLC) { >+ /* If this is an HDLC channel we only send a byte of >+ HDLC. */ >+ for(x=0;x<left;x++) { >+ if (fasthdlc_tx_need_data(&ms->txhdlc)) >+ /* Load a byte of data only if needed */ >+ fasthdlc_tx_load_nocheck(&ms->txhdlc, buf[ms->writeidx[ms->outwritebuf]++]); >+ *(txb++) = fasthdlc_tx_run_nocheck(&ms->txhdlc); >+ } >+ bytes -= left; >+ } else { >+ memcpy(txb, buf + ms->writeidx[ms->outwritebuf], left); >+ ms->writeidx[ms->outwritebuf]+=left; >+ txb += left; >+ bytes -= left; >+ } >+ /* Check buffer status */ >+ if (ms->writeidx[ms->outwritebuf] >= ms->writen[ms->outwritebuf]) { >+ /* We've reached the end of our buffer. Go to the next. */ >+ oldbuf = ms->outwritebuf; >+ /* Clear out write index and such */ >+ ms->writeidx[oldbuf] = 0; >+ ms->outwritebuf = (ms->outwritebuf + 1) % ms->numbufs; >+ >+ if (!(ms->flags & DAHDI_FLAG_MTP2)) { >+ ms->writen[oldbuf] = 0; >+ if (ms->outwritebuf == ms->inwritebuf) { >+ /* Whoopsies, we're run out of buffers. Mark ours >+ as -1 and wait for the filler to notify us that >+ there is something to write */ >+ ms->outwritebuf = -1; >+ if (ms->iomask & (DAHDI_IOMUX_WRITE | DAHDI_IOMUX_WRITEEMPTY)) >+ wake_up_interruptible(&ms->eventbufq); >+ /* If we're only supposed to start when full, disable the transmitter */ >+ if ((ms->txbufpolicy == DAHDI_POLICY_WHEN_FULL) || >+ (ms->txbufpolicy == DAHDI_POLICY_HALF_FULL)) >+ ms->txdisable = 1; >+ } >+ } else { >+ if (ms->outwritebuf == ms->inwritebuf) { >+ ms->outwritebuf = oldbuf; >+ if (ms->iomask & (DAHDI_IOMUX_WRITE | DAHDI_IOMUX_WRITEEMPTY)) >+ wake_up_interruptible(&ms->eventbufq); >+ /* If we're only supposed to start when full, disable the transmitter */ >+ if ((ms->txbufpolicy == DAHDI_POLICY_WHEN_FULL) || >+ (ms->txbufpolicy == DAHDI_POLICY_HALF_FULL)) >+ ms->txdisable = 1; >+ } >+ } >+ if (ms->inwritebuf < 0) { >+ /* The filler doesn't have a place to put data. Now >+ that we're done with this buffer, notify them. */ >+ ms->inwritebuf = oldbuf; >+ } >+/* In the very orignal driver, it was quite well known to me (Jim) that there >+was a possibility that a channel sleeping on a write block needed to >+be potentially woken up EVERY time a buffer was emptied, not just on the first >+one, because if only done on the first one there is a slight timing potential >+of missing the wakeup (between where it senses the (lack of) active condition >+(with interrupts disabled) and where it does the sleep (interrupts enabled) >+in the read or iomux call, etc). That is why the write and iomux calls start >+with an infinite loop that gets broken out of upon an active condition, >+otherwise keeps sleeping and looking. The part in this code got "optimized" >+out in the later versions, and is put back now. */ >+ if (!(ms->flags & (DAHDI_FLAG_NETDEV | DAHDI_FLAG_PPP))) { >+ wake_up_interruptible(&ms->writebufq); >+ wake_up_interruptible(&ms->sel); >+ if (ms->iomask & DAHDI_IOMUX_WRITE) >+ wake_up_interruptible(&ms->eventbufq); >+ } >+ /* Transmit a flag if this is an HDLC channel */ >+ if (ms->flags & DAHDI_FLAG_HDLC) >+ fasthdlc_tx_frame_nocheck(&ms->txhdlc); >+#ifdef CONFIG_DAHDI_NET >+ if (ms->flags & DAHDI_FLAG_NETDEV) >+ netif_wake_queue(ztchan_to_dev(ms)); >+#endif >+#ifdef CONFIG_DAHDI_PPP >+ if (ms->flags & DAHDI_FLAG_PPP) { >+ ms->do_ppp_wakeup = 1; >+ tasklet_schedule(&ms->ppp_calls); >+ } >+#endif >+ } >+ } else if (ms->curtone && !(ms->flags & DAHDI_FLAG_PSEUDO)) { >+ left = ms->curtone->tonesamples - ms->tonep; >+ if (left > bytes) >+ left = bytes; >+ for (x=0;x<left;x++) { >+ /* Pick our default value from the next sample of the current tone */ >+ getlin = dahdi_tone_nextsample(&ms->ts, ms->curtone); >+ *(txb++) = DAHDI_LIN2X(getlin, ms); >+ } >+ ms->tonep+=left; >+ bytes -= left; >+ if (ms->tonep >= ms->curtone->tonesamples) { >+ struct dahdi_tone *last; >+ /* Go to the next sample of the tone */ >+ ms->tonep = 0; >+ last = ms->curtone; >+ ms->curtone = ms->curtone->next; >+ if (!ms->curtone) { >+ /* No more tones... Is this dtmf or mf? If so, go to the next digit */ >+ if (ms->dialing) >+ __do_dtmf(ms); >+ } else { >+ if (last != ms->curtone) >+ dahdi_init_tone_state(&ms->ts, ms->curtone); >+ } >+ } >+ } else if (ms->flags & DAHDI_FLAG_LOOPED) { >+ for (x = 0; x < bytes; x++) >+ txb[x] = ms->readchunk[x]; >+ bytes = 0; >+ } else if (ms->flags & DAHDI_FLAG_HDLC) { >+ for (x=0;x<bytes;x++) { >+ /* Okay, if we're HDLC, then transmit a flag by default */ >+ if (fasthdlc_tx_need_data(&ms->txhdlc)) >+ fasthdlc_tx_frame_nocheck(&ms->txhdlc); >+ *(txb++) = fasthdlc_tx_run_nocheck(&ms->txhdlc); >+ } >+ bytes = 0; >+ } else if (ms->flags & DAHDI_FLAG_CLEAR) { >+ /* Clear channels that are idle in audio mode need >+ to send silence; in non-audio mode, always send 0xff >+ so stupid switches won't consider the channel active >+ */ >+ if (ms->flags & DAHDI_FLAG_AUDIO) { >+ memset(txb, DAHDI_LIN2X(0, ms), bytes); >+ } else { >+ memset(txb, 0xFF, bytes); >+ } >+ bytes = 0; >+ } else { >+ memset(txb, DAHDI_LIN2X(0, ms), bytes); /* Lastly we use silence on telephony channels */ >+ bytes = 0; >+ } >+ } >+} >+ >+static inline void rbs_itimer_expire(struct dahdi_chan *chan) >+{ >+ /* the only way this could have gotten here, is if a channel >+ went onf hook longer then the wink or flash detect timeout */ >+ /* Called with chan->lock held */ >+ switch(chan->sig) >+ { >+ case DAHDI_SIG_FXOLS: /* if FXO, its definitely on hook */ >+ case DAHDI_SIG_FXOGS: >+ case DAHDI_SIG_FXOKS: >+ __qevent(chan,DAHDI_EVENT_ONHOOK); >+ chan->gotgs = 0; >+ break; >+#if defined(EMFLASH) || defined(EMPULSE) >+ case DAHDI_SIG_EM: >+ case DAHDI_SIG_EM_E1: >+ if (chan->rxhooksig == DAHDI_RXSIG_ONHOOK) { >+ __qevent(chan,DAHDI_EVENT_ONHOOK); >+ break; >+ } >+ __qevent(chan,DAHDI_EVENT_RINGOFFHOOK); >+ break; >+#endif >+#ifdef FXSFLASH >+ case DAHDI_SIG_FXSKS: >+ if (chan->rxhooksig == DAHDI_RXSIG_ONHOOK) { >+ __qevent(chan, DAHDI_EVENT_ONHOOK); >+ break; >+ } >+#endif >+ /* fall thru intentionally */ >+ default: /* otherwise, its definitely off hook */ >+ __qevent(chan,DAHDI_EVENT_RINGOFFHOOK); >+ break; >+ } >+} >+ >+static inline void __rbs_otimer_expire(struct dahdi_chan *chan) >+{ >+ int len = 0; >+ /* Called with chan->lock held */ >+ >+ chan->otimer = 0; >+ /* Move to the next timer state */ >+ switch(chan->txstate) { >+ case DAHDI_TXSTATE_RINGOFF: >+ /* Turn on the ringer now that the silent time has passed */ >+ ++chan->cadencepos; >+ if (chan->cadencepos >= DAHDI_MAX_CADENCE) >+ chan->cadencepos = chan->firstcadencepos; >+ len = chan->ringcadence[chan->cadencepos]; >+ >+ if (!len) { >+ chan->cadencepos = chan->firstcadencepos; >+ len = chan->ringcadence[chan->cadencepos]; >+ } >+ >+ dahdi_rbs_sethook(chan, DAHDI_TXSIG_START, DAHDI_TXSTATE_RINGON, len); >+ __qevent(chan, DAHDI_EVENT_RINGERON); >+ break; >+ >+ case DAHDI_TXSTATE_RINGON: >+ /* Turn off the ringer now that the loud time has passed */ >+ ++chan->cadencepos; >+ if (chan->cadencepos >= DAHDI_MAX_CADENCE) >+ chan->cadencepos = 0; >+ len = chan->ringcadence[chan->cadencepos]; >+ >+ if (!len) { >+ chan->cadencepos = 0; >+ len = chan->curzone->ringcadence[chan->cadencepos]; >+ } >+ >+ dahdi_rbs_sethook(chan, DAHDI_TXSIG_OFFHOOK, DAHDI_TXSTATE_RINGOFF, len); >+ __qevent(chan, DAHDI_EVENT_RINGEROFF); >+ break; >+ >+ case DAHDI_TXSTATE_START: >+ /* If we were starting, go off hook now ready to debounce */ >+ dahdi_rbs_sethook(chan, DAHDI_TXSIG_OFFHOOK, DAHDI_TXSTATE_AFTERSTART, DAHDI_AFTERSTART_TIME); >+ wake_up_interruptible(&chan->txstateq); >+ break; >+ >+ case DAHDI_TXSTATE_PREWINK: >+ /* Actually wink */ >+ dahdi_rbs_sethook(chan, DAHDI_TXSIG_OFFHOOK, DAHDI_TXSTATE_WINK, chan->winktime); >+ break; >+ >+ case DAHDI_TXSTATE_WINK: >+ /* Wink complete, go on hook and stabalize */ >+ dahdi_rbs_sethook(chan, DAHDI_TXSIG_ONHOOK, DAHDI_TXSTATE_ONHOOK, 0); >+ if (chan->file && (chan->file->f_flags & O_NONBLOCK)) >+ __qevent(chan, DAHDI_EVENT_HOOKCOMPLETE); >+ wake_up_interruptible(&chan->txstateq); >+ break; >+ >+ case DAHDI_TXSTATE_PREFLASH: >+ /* Actually flash */ >+ dahdi_rbs_sethook(chan, DAHDI_TXSIG_ONHOOK, DAHDI_TXSTATE_FLASH, chan->flashtime); >+ break; >+ >+ case DAHDI_TXSTATE_FLASH: >+ dahdi_rbs_sethook(chan, DAHDI_TXSIG_OFFHOOK, DAHDI_TXSTATE_OFFHOOK, 0); >+ if (chan->file && (chan->file->f_flags & O_NONBLOCK)) >+ __qevent(chan, DAHDI_EVENT_HOOKCOMPLETE); >+ wake_up_interruptible(&chan->txstateq); >+ break; >+ >+ case DAHDI_TXSTATE_DEBOUNCE: >+ dahdi_rbs_sethook(chan, DAHDI_TXSIG_OFFHOOK, DAHDI_TXSTATE_OFFHOOK, 0); >+ /* See if we've gone back on hook */ >+ if ((chan->rxhooksig == DAHDI_RXSIG_ONHOOK) && (chan->rxflashtime > 2)) >+ chan->itimerset = chan->itimer = chan->rxflashtime * DAHDI_CHUNKSIZE; >+ wake_up_interruptible(&chan->txstateq); >+ break; >+ >+ case DAHDI_TXSTATE_AFTERSTART: >+ dahdi_rbs_sethook(chan, DAHDI_TXSIG_OFFHOOK, DAHDI_TXSTATE_OFFHOOK, 0); >+ if (chan->file && (chan->file->f_flags & O_NONBLOCK)) >+ __qevent(chan, DAHDI_EVENT_HOOKCOMPLETE); >+ wake_up_interruptible(&chan->txstateq); >+ break; >+ >+ case DAHDI_TXSTATE_KEWL: >+ dahdi_rbs_sethook(chan, DAHDI_TXSIG_ONHOOK, DAHDI_TXSTATE_AFTERKEWL, DAHDI_AFTERKEWLTIME); >+ if (chan->file && (chan->file->f_flags & O_NONBLOCK)) >+ __qevent(chan, DAHDI_EVENT_HOOKCOMPLETE); >+ wake_up_interruptible(&chan->txstateq); >+ break; >+ >+ case DAHDI_TXSTATE_AFTERKEWL: >+ if (chan->kewlonhook) { >+ __qevent(chan,DAHDI_EVENT_ONHOOK); >+ } >+ chan->txstate = DAHDI_TXSTATE_ONHOOK; >+ chan->gotgs = 0; >+ break; >+ >+ case DAHDI_TXSTATE_PULSEBREAK: >+ dahdi_rbs_sethook(chan, DAHDI_TXSIG_OFFHOOK, DAHDI_TXSTATE_PULSEMAKE, >+ chan->pulsemaketime); >+ wake_up_interruptible(&chan->txstateq); >+ break; >+ >+ case DAHDI_TXSTATE_PULSEMAKE: >+ if (chan->pdialcount) >+ chan->pdialcount--; >+ if (chan->pdialcount) >+ { >+ dahdi_rbs_sethook(chan, DAHDI_TXSIG_ONHOOK, >+ DAHDI_TXSTATE_PULSEBREAK, chan->pulsebreaktime); >+ break; >+ } >+ chan->txstate = DAHDI_TXSTATE_PULSEAFTER; >+ chan->otimer = chan->pulseaftertime * DAHDI_CHUNKSIZE; >+ wake_up_interruptible(&chan->txstateq); >+ break; >+ >+ case DAHDI_TXSTATE_PULSEAFTER: >+ chan->txstate = DAHDI_TXSTATE_OFFHOOK; >+ __do_dtmf(chan); >+ wake_up_interruptible(&chan->txstateq); >+ break; >+ >+ default: >+ break; >+ } >+} >+ >+static void __dahdi_hooksig_pvt(struct dahdi_chan *chan, enum dahdi_rxsig rxsig) >+{ >+ >+ /* State machines for receive hookstate transitions >+ called with chan->lock held */ >+ >+ if ((chan->rxhooksig) == rxsig) return; >+ >+ if ((chan->flags & DAHDI_FLAG_SIGFREEZE)) return; >+ >+ chan->rxhooksig = rxsig; >+#ifdef RINGBEGIN >+ if ((chan->sig & __DAHDI_SIG_FXS) && (rxsig == DAHDI_RXSIG_RING) && >+ (!chan->ringdebtimer)) >+ __qevent(chan,DAHDI_EVENT_RINGBEGIN); >+#endif >+ switch(chan->sig) { >+ case DAHDI_SIG_EM: /* E and M */ >+ case DAHDI_SIG_EM_E1: >+ switch(rxsig) { >+ case DAHDI_RXSIG_OFFHOOK: /* went off hook */ >+ /* The interface is going off hook */ >+#ifdef EMFLASH >+ if (chan->itimer) >+ { >+ __qevent(chan,DAHDI_EVENT_WINKFLASH); >+ chan->itimerset = chan->itimer = 0; >+ break; >+ } >+#endif >+#ifdef EMPULSE >+ if (chan->itimer) /* if timer still running */ >+ { >+ int plen = chan->itimerset - chan->itimer; >+ if (plen <= DAHDI_MAXPULSETIME) >+ { >+ if (plen >= DAHDI_MINPULSETIME) >+ { >+ chan->pulsecount++; >+ >+ chan->pulsetimer = DAHDI_PULSETIMEOUT; >+ chan->itimerset = chan->itimer = 0; >+ if (chan->pulsecount == 1) >+ __qevent(chan,DAHDI_EVENT_PULSE_START); >+ } >+ } >+ break; >+ } >+#endif >+ /* set wink timer */ >+ chan->itimerset = chan->itimer = chan->rxwinktime * DAHDI_CHUNKSIZE; >+ break; >+ case DAHDI_RXSIG_ONHOOK: /* went on hook */ >+ /* This interface is now going on hook. >+ Check for WINK, etc */ >+ if (chan->itimer) >+ __qevent(chan,DAHDI_EVENT_WINKFLASH); >+#if defined(EMFLASH) || defined(EMPULSE) >+ else { >+#ifdef EMFLASH >+ chan->itimerset = chan->itimer = chan->rxflashtime * DAHDI_CHUNKSIZE; >+ >+#else /* EMFLASH */ >+ chan->itimerset = chan->itimer = chan->rxwinktime * DAHDI_CHUNKSIZE; >+ >+#endif /* EMFLASH */ >+ chan->gotgs = 0; >+ break; >+ } >+#else /* EMFLASH || EMPULSE */ >+ else { >+ __qevent(chan,DAHDI_EVENT_ONHOOK); >+ chan->gotgs = 0; >+ } >+#endif >+ chan->itimerset = chan->itimer = 0; >+ break; >+ default: >+ break; >+ } >+ break; >+ case DAHDI_SIG_FXSKS: /* FXS Kewlstart */ >+ /* ignore a bit error if loop not closed and stable */ >+ if (chan->txstate != DAHDI_TXSTATE_OFFHOOK) break; >+#ifdef FXSFLASH >+ if (rxsig == DAHDI_RXSIG_ONHOOK) { >+ chan->itimer = DAHDI_FXSFLASHMAXTIME * DAHDI_CHUNKSIZE; >+ break; >+ } else if (rxsig == DAHDI_RXSIG_OFFHOOK) { >+ if (chan->itimer) { >+ /* did the offhook occur in the window? if not, ignore both events */ >+ if (chan->itimer <= ((DAHDI_FXSFLASHMAXTIME - DAHDI_FXSFLASHMINTIME) * DAHDI_CHUNKSIZE)) >+ __qevent(chan, DAHDI_EVENT_WINKFLASH); >+ } >+ chan->itimer = 0; >+ break; >+ } >+#endif >+ /* fall through intentionally */ >+ case DAHDI_SIG_FXSGS: /* FXS Groundstart */ >+ if (rxsig == DAHDI_RXSIG_ONHOOK) { >+ chan->ringdebtimer = RING_DEBOUNCE_TIME; >+ chan->ringtrailer = 0; >+ if (chan->txstate != DAHDI_TXSTATE_DEBOUNCE) { >+ chan->gotgs = 0; >+ __qevent(chan,DAHDI_EVENT_ONHOOK); >+ } >+ } >+ break; >+ case DAHDI_SIG_FXOGS: /* FXO Groundstart */ >+ if (rxsig == DAHDI_RXSIG_START) { >+ /* if havent got gs, report it */ >+ if (!chan->gotgs) { >+ __qevent(chan,DAHDI_EVENT_RINGOFFHOOK); >+ chan->gotgs = 1; >+ } >+ } >+ /* fall through intentionally */ >+ case DAHDI_SIG_FXOLS: /* FXO Loopstart */ >+ case DAHDI_SIG_FXOKS: /* FXO Kewlstart */ >+ switch(rxsig) { >+ case DAHDI_RXSIG_OFFHOOK: /* went off hook */ >+ /* if asserti ng ring, stop it */ >+ if (chan->txstate == DAHDI_TXSTATE_START) { >+ dahdi_rbs_sethook(chan,DAHDI_TXSIG_OFFHOOK, DAHDI_TXSTATE_AFTERSTART, DAHDI_AFTERSTART_TIME); >+ } >+ chan->kewlonhook = 0; >+#ifdef CONFIG_DAHDI_DEBUG >+ module_printk(KERN_NOTICE, "Off hook on channel %d, itimer = %d, gotgs = %d\n", chan->channo, chan->itimer, chan->gotgs); >+#endif >+ if (chan->itimer) /* if timer still running */ >+ { >+ int plen = chan->itimerset - chan->itimer; >+ if (plen <= DAHDI_MAXPULSETIME) >+ { >+ if (plen >= DAHDI_MINPULSETIME) >+ { >+ chan->pulsecount++; >+ chan->pulsetimer = DAHDI_PULSETIMEOUT; >+ chan->itimer = chan->itimerset; >+ if (chan->pulsecount == 1) >+ __qevent(chan,DAHDI_EVENT_PULSE_START); >+ } >+ } else >+ __qevent(chan,DAHDI_EVENT_WINKFLASH); >+ } else { >+ /* if havent got GS detect */ >+ if (!chan->gotgs) { >+ __qevent(chan,DAHDI_EVENT_RINGOFFHOOK); >+ chan->gotgs = 1; >+ chan->itimerset = chan->itimer = 0; >+ } >+ } >+ chan->itimerset = chan->itimer = 0; >+ break; >+ case DAHDI_RXSIG_ONHOOK: /* went on hook */ >+ /* if not during offhook debounce time */ >+ if ((chan->txstate != DAHDI_TXSTATE_DEBOUNCE) && >+ (chan->txstate != DAHDI_TXSTATE_KEWL) && >+ (chan->txstate != DAHDI_TXSTATE_AFTERKEWL)) { >+ chan->itimerset = chan->itimer = chan->rxflashtime * DAHDI_CHUNKSIZE; >+ } >+ if (chan->txstate == DAHDI_TXSTATE_KEWL) >+ chan->kewlonhook = 1; >+ break; >+ default: >+ break; >+ } >+ default: >+ break; >+ } >+} >+ >+void dahdi_hooksig(struct dahdi_chan *chan, enum dahdi_rxsig rxsig) >+{ >+ /* skip if no change */ >+ unsigned long flags; >+ spin_lock_irqsave(&chan->lock, flags); >+ __dahdi_hooksig_pvt(chan,rxsig); >+ spin_unlock_irqrestore(&chan->lock, flags); >+} >+ >+void dahdi_rbsbits(struct dahdi_chan *chan, int cursig) >+{ >+ unsigned long flags; >+ if (cursig == chan->rxsig) >+ return; >+ >+ if ((chan->flags & DAHDI_FLAG_SIGFREEZE)) return; >+ >+ spin_lock_irqsave(&chan->lock, flags); >+ switch(chan->sig) { >+ case DAHDI_SIG_FXOGS: /* FXO Groundstart */ >+ /* B-bit only matters for FXO GS */ >+ if (!(cursig & DAHDI_BBIT)) { >+ __dahdi_hooksig_pvt(chan, DAHDI_RXSIG_START); >+ break; >+ } >+ /* Fall through */ >+ case DAHDI_SIG_EM: /* E and M */ >+ case DAHDI_SIG_EM_E1: >+ case DAHDI_SIG_FXOLS: /* FXO Loopstart */ >+ case DAHDI_SIG_FXOKS: /* FXO Kewlstart */ >+ if (cursig & DAHDI_ABIT) /* off hook */ >+ __dahdi_hooksig_pvt(chan,DAHDI_RXSIG_OFFHOOK); >+ else /* on hook */ >+ __dahdi_hooksig_pvt(chan,DAHDI_RXSIG_ONHOOK); >+ break; >+ >+ case DAHDI_SIG_FXSKS: /* FXS Kewlstart */ >+ case DAHDI_SIG_FXSGS: /* FXS Groundstart */ >+ /* Fall through */ >+ case DAHDI_SIG_FXSLS: >+ if (!(cursig & DAHDI_BBIT)) { >+ /* Check for ringing first */ >+ __dahdi_hooksig_pvt(chan, DAHDI_RXSIG_RING); >+ break; >+ } >+ if ((chan->sig != DAHDI_SIG_FXSLS) && (cursig & DAHDI_ABIT)) { >+ /* if went on hook */ >+ __dahdi_hooksig_pvt(chan, DAHDI_RXSIG_ONHOOK); >+ } else { >+ __dahdi_hooksig_pvt(chan, DAHDI_RXSIG_OFFHOOK); >+ } >+ break; >+ case DAHDI_SIG_CAS: >+ /* send event that something changed */ >+ __qevent(chan, DAHDI_EVENT_BITSCHANGED); >+ break; >+ >+ default: >+ break; >+ } >+ /* Keep track of signalling for next time */ >+ chan->rxsig = cursig; >+ spin_unlock_irqrestore(&chan->lock, flags); >+} >+ >+static void process_echocan_events(struct dahdi_chan *chan) >+{ >+ union dahdi_echocan_events events = chan->ec_state->events; >+ >+ if (events.CED_tx_detected) { >+ dahdi_qevent_nolock(chan, DAHDI_EVENT_TX_CED_DETECTED); >+ if (chan->ec_state) { >+ if (chan->ec_state->status.mode == ECHO_MODE_ACTIVE) >+ set_echocan_fax_mode(chan, chan->channo, "CED tx detected", 1); >+ else >+ module_printk(KERN_NOTICE, "Detected CED tone (tx) on channel %d\n", chan->channo); >+ } >+ } >+ >+ if (events.CED_rx_detected) { >+ dahdi_qevent_nolock(chan, DAHDI_EVENT_RX_CED_DETECTED); >+ if (chan->ec_state) { >+ if (chan->ec_state->status.mode == ECHO_MODE_ACTIVE) >+ set_echocan_fax_mode(chan, chan->channo, "CED rx detected", 1); >+ else >+ module_printk(KERN_NOTICE, "Detected CED tone (rx) on channel %d\n", chan->channo); >+ } >+ } >+ >+ if (events.CNG_tx_detected) >+ dahdi_qevent_nolock(chan, DAHDI_EVENT_TX_CNG_DETECTED); >+ >+ if (events.CNG_rx_detected) >+ dahdi_qevent_nolock(chan, DAHDI_EVENT_RX_CNG_DETECTED); >+ >+ if (events.NLP_auto_disabled) { >+ dahdi_qevent_nolock(chan, DAHDI_EVENT_EC_NLP_DISABLED); >+ chan->ec_state->status.mode = ECHO_MODE_FAX; >+ } >+ >+ if (events.NLP_auto_enabled) { >+ dahdi_qevent_nolock(chan, DAHDI_EVENT_EC_NLP_ENABLED); >+ chan->ec_state->status.mode = ECHO_MODE_ACTIVE; >+ } >+} >+ >+static inline void __dahdi_ec_chunk(struct dahdi_chan *ss, unsigned char *rxchunk, const unsigned char *txchunk) >+{ >+ short rxlin, txlin; >+ int x; >+ unsigned long flags; >+ >+ spin_lock_irqsave(&ss->lock, flags); >+ >+ if (ss->readchunkpreec) { >+ /* Save a copy of the audio before the echo can has its way with it */ >+ for (x = 0; x < DAHDI_CHUNKSIZE; x++) >+ /* We only ever really need to deal with signed linear - let's just convert it now */ >+ ss->readchunkpreec[x] = DAHDI_XLAW(rxchunk[x], ss); >+ } >+ >+ /* Perform echo cancellation on a chunk if necessary */ >+ if (ss->ec_state) { >+#if defined(CONFIG_DAHDI_MMX) || defined(ECHO_CAN_FP) >+ dahdi_kernel_fpu_begin(); >+#endif >+ if (ss->ec_state->status.mode & __ECHO_MODE_MUTE) { >+ /* Special stuff for training the echo can */ >+ for (x=0;x<DAHDI_CHUNKSIZE;x++) { >+ rxlin = DAHDI_XLAW(rxchunk[x], ss); >+ txlin = DAHDI_XLAW(txchunk[x], ss); >+ if (ss->ec_state->status.mode == ECHO_MODE_PRETRAINING) { >+ if (--ss->ec_state->status.pretrain_timer <= 0) { >+ ss->ec_state->status.pretrain_timer = 0; >+ ss->ec_state->status.mode = ECHO_MODE_STARTTRAINING; >+ } >+ } >+ if ((ss->ec_state->status.mode == ECHO_MODE_AWAITINGECHO) && (txlin > 8000)) { >+ ss->ec_state->status.last_train_tap = 0; >+ ss->ec_state->status.mode = ECHO_MODE_TRAINING; >+ } >+ if (ss->ec_state->status.mode == ECHO_MODE_TRAINING) { >+ if (ss->ec_state->ops->echocan_traintap(ss->ec_state, ss->ec_state->status.last_train_tap++, rxlin)) { >+#if 0 >+ module_printk(KERN_NOTICE, "Finished training (%d taps trained)!\n", ss->ec_state->status.last_train_tap); >+#endif >+ ss->ec_state->status.mode = ECHO_MODE_ACTIVE; >+ } >+ } >+ rxlin = 0; >+ rxchunk[x] = DAHDI_LIN2X((int)rxlin, ss); >+ } >+ } else if (ss->ec_state->status.mode != ECHO_MODE_IDLE) { >+ ss->ec_state->events.all = 0; >+ >+ if (ss->ec_state->ops->echocan_process) { >+ short rxlins[DAHDI_CHUNKSIZE], txlins[DAHDI_CHUNKSIZE]; >+ >+ for (x = 0; x < DAHDI_CHUNKSIZE; x++) { >+ rxlins[x] = DAHDI_XLAW(rxchunk[x], ss); >+ txlins[x] = DAHDI_XLAW(txchunk[x], ss); >+ } >+ ss->ec_state->ops->echocan_process(ss->ec_state, rxlins, txlins, DAHDI_CHUNKSIZE); >+ >+ for (x = 0; x < DAHDI_CHUNKSIZE; x++) >+ rxchunk[x] = DAHDI_LIN2X((int) rxlins[x], ss); >+ } else if (ss->ec_state->ops->echocan_events) >+ ss->ec_state->ops->echocan_events(ss->ec_state); >+ >+ if (ss->ec_state->events.all) >+ process_echocan_events(ss); >+ >+ } >+#if defined(CONFIG_DAHDI_MMX) || defined(ECHO_CAN_FP) >+ kernel_fpu_end(); >+#endif >+ } >+ spin_unlock_irqrestore(&ss->lock, flags); >+} >+ >+void dahdi_ec_chunk(struct dahdi_chan *ss, unsigned char *rxchunk, const unsigned char *txchunk) >+{ >+ __dahdi_ec_chunk(ss, rxchunk, txchunk); >+} >+ >+void dahdi_ec_span(struct dahdi_span *span) >+{ >+ int x; >+ for (x = 0; x < span->channels; x++) { >+ if (span->chans[x]->ec_current) >+ __dahdi_ec_chunk(span->chans[x], span->chans[x]->readchunk, span->chans[x]->writechunk); >+ } >+} >+ >+/* return 0 if nothing detected, 1 if lack of tone, 2 if presence of tone */ >+/* modifies buffer pointed to by 'amp' with notched-out values */ >+static inline int sf_detect(struct sf_detect_state *s, >+ short *amp, >+ int samples,long p1, long p2, long p3) >+{ >+int i,rv = 0; >+long x,y; >+ >+#define SF_DETECT_SAMPLES (DAHDI_CHUNKSIZE * 5) >+#define SF_DETECT_MIN_ENERGY 500 >+#define NB 14 /* number of bits to shift left */ >+ >+ /* determine energy level before filtering */ >+ for(i = 0; i < samples; i++) >+ { >+ if (amp[i] < 0) s->e1 -= amp[i]; >+ else s->e1 += amp[i]; >+ } >+ /* do 2nd order IIR notch filter at given freq. and calculate >+ energy */ >+ for(i = 0; i < samples; i++) >+ { >+ x = amp[i] << NB; >+ y = s->x2 + (p1 * (s->x1 >> NB)) + x; >+ y += (p2 * (s->y2 >> NB)) + >+ (p3 * (s->y1 >> NB)); >+ s->x2 = s->x1; >+ s->x1 = x; >+ s->y2 = s->y1; >+ s->y1 = y; >+ amp[i] = y >> NB; >+ if (amp[i] < 0) s->e2 -= amp[i]; >+ else s->e2 += amp[i]; >+ } >+ s->samps += i; >+ /* if time to do determination */ >+ if ((s->samps) >= SF_DETECT_SAMPLES) >+ { >+ rv = 1; /* default to no tone */ >+ /* if enough energy, it is determined to be a tone */ >+ if (((s->e1 - s->e2) / s->samps) > SF_DETECT_MIN_ENERGY) rv = 2; >+ /* reset energy processing variables */ >+ s->samps = 0; >+ s->e1 = s->e2 = 0; >+ } >+ return(rv); >+} >+ >+static inline void __dahdi_process_putaudio_chunk(struct dahdi_chan *ss, unsigned char *rxb) >+{ >+ /* We transmit data from our master channel */ >+ /* Called with ss->lock held */ >+ struct dahdi_chan *ms = ss->master; >+ /* Linear version of received data */ >+ short putlin[DAHDI_CHUNKSIZE],k[DAHDI_CHUNKSIZE]; >+ int x,r; >+ >+ if (ms->dialing) ms->afterdialingtimer = 50; >+ else if (ms->afterdialingtimer) ms->afterdialingtimer--; >+ if (ms->afterdialingtimer && (!(ms->flags & DAHDI_FLAG_PSEUDO))) { >+ /* Be careful since memset is likely a macro */ >+ rxb[0] = DAHDI_LIN2X(0, ms); >+ memset(&rxb[1], rxb[0], DAHDI_CHUNKSIZE - 1); /* receive as silence if dialing */ >+ } >+ for (x=0;x<DAHDI_CHUNKSIZE;x++) { >+ rxb[x] = ms->rxgain[rxb[x]]; >+ putlin[x] = DAHDI_XLAW(rxb[x], ms); >+ } >+ >+ if (ms->ec_state && (ms->ec_state->status.mode == ECHO_MODE_ACTIVE) && !ms->ec_state->features.CED_rx_detect) { >+ for (x = 0; x < DAHDI_CHUNKSIZE; x++) { >+ if (echo_can_disable_detector_update(&ms->ec_state->rxecdis, putlin[x])) { >+ set_echocan_fax_mode(ms, ss->channo, "CED rx detected", 1); >+ dahdi_qevent_nolock(ms, DAHDI_EVENT_RX_CED_DETECTED); >+ break; >+ } >+ } >+ } >+ >+ /* if doing rx tone decoding */ >+ if (ms->rxp1 && ms->rxp2 && ms->rxp3) >+ { >+ r = sf_detect(&ms->rd,putlin,DAHDI_CHUNKSIZE,ms->rxp1, >+ ms->rxp2,ms->rxp3); >+ /* Convert back */ >+ for(x=0;x<DAHDI_CHUNKSIZE;x++) >+ rxb[x] = DAHDI_LIN2X(putlin[x], ms); >+ if (r) /* if something happened */ >+ { >+ if (r != ms->rd.lastdetect) >+ { >+ if (((r == 2) && !(ms->toneflags & DAHDI_REVERSE_RXTONE)) || >+ ((r == 1) && (ms->toneflags & DAHDI_REVERSE_RXTONE))) >+ { >+ __qevent(ms,DAHDI_EVENT_RINGOFFHOOK); >+ } >+ else >+ { >+ __qevent(ms,DAHDI_EVENT_ONHOOK); >+ } >+ ms->rd.lastdetect = r; >+ } >+ } >+ } >+ >+ if (!(ms->flags & DAHDI_FLAG_PSEUDO)) { >+ memcpy(ms->putlin, putlin, DAHDI_CHUNKSIZE * sizeof(short)); >+ memcpy(ms->putraw, rxb, DAHDI_CHUNKSIZE); >+ } >+ >+ /* Take the rxc, twiddle it for conferencing if appropriate and put it >+ back */ >+ if ((!ms->confmute && !ms->afterdialingtimer) || >+ (ms->flags & DAHDI_FLAG_PSEUDO)) { >+ switch(ms->confmode & DAHDI_CONF_MODE_MASK) { >+ case DAHDI_CONF_NORMAL: /* Normal mode */ >+ /* Do nothing. rx goes output */ >+ break; >+ case DAHDI_CONF_MONITOR: /* Monitor a channel's rx mode */ >+ /* if not a pseudo-channel, ignore */ >+ if (!(ms->flags & DAHDI_FLAG_PSEUDO)) break; >+ /* Add monitored channel */ >+ if (chans[ms->confna]->flags & DAHDI_FLAG_PSEUDO) { >+ ACSS(putlin, chans[ms->confna]->getlin); >+ } else { >+ ACSS(putlin, chans[ms->confna]->putlin); >+ } >+ /* Convert back */ >+ for(x=0;x<DAHDI_CHUNKSIZE;x++) >+ rxb[x] = DAHDI_LIN2X(putlin[x], ms); >+ break; >+ case DAHDI_CONF_MONITORTX: /* Monitor a channel's tx mode */ >+ /* if not a pseudo-channel, ignore */ >+ if (!(ms->flags & DAHDI_FLAG_PSEUDO)) break; >+ /* Add monitored channel */ >+ if (chans[ms->confna]->flags & DAHDI_FLAG_PSEUDO) { >+ ACSS(putlin, chans[ms->confna]->putlin); >+ } else { >+ ACSS(putlin, chans[ms->confna]->getlin); >+ } >+ /* Convert back */ >+ for(x=0;x<DAHDI_CHUNKSIZE;x++) >+ rxb[x] = DAHDI_LIN2X(putlin[x], ms); >+ break; >+ case DAHDI_CONF_MONITORBOTH: /* Monitor a channel's tx and rx mode */ >+ /* if not a pseudo-channel, ignore */ >+ if (!(ms->flags & DAHDI_FLAG_PSEUDO)) break; >+ /* Note: Technically, saturation should be done at >+ the end of the whole addition, but for performance >+ reasons, we don't do that. Besides, it only matters >+ when you're so loud you're clipping anyway */ >+ ACSS(putlin, chans[ms->confna]->getlin); >+ ACSS(putlin, chans[ms->confna]->putlin); >+ /* Convert back */ >+ for(x=0;x<DAHDI_CHUNKSIZE;x++) >+ rxb[x] = DAHDI_LIN2X(putlin[x], ms); >+ break; >+ case DAHDI_CONF_MONITOR_RX_PREECHO: /* Monitor a channel's rx mode */ >+ /* if not a pseudo-channel, ignore */ >+ if (!(ms->flags & DAHDI_FLAG_PSEUDO)) >+ break; >+ >+ if (!chans[ms->confna]->readchunkpreec) >+ break; >+ >+ /* Add monitored channel */ >+ ACSS(putlin, chans[ms->confna]->flags & DAHDI_FLAG_PSEUDO ? >+ chans[ms->confna]->getlin : chans[ms->confna]->readchunkpreec); >+ for (x = 0; x < DAHDI_CHUNKSIZE; x++) >+ rxb[x] = DAHDI_LIN2X(putlin[x], ms); >+ >+ break; >+ case DAHDI_CONF_MONITOR_TX_PREECHO: /* Monitor a channel's tx mode */ >+ /* if not a pseudo-channel, ignore */ >+ if (!(ms->flags & DAHDI_FLAG_PSEUDO)) >+ break; >+ >+ if (!chans[ms->confna]->readchunkpreec) >+ break; >+ >+ /* Add monitored channel */ >+ ACSS(putlin, chans[ms->confna]->flags & DAHDI_FLAG_PSEUDO ? >+ chans[ms->confna]->readchunkpreec : chans[ms->confna]->getlin); >+ for (x = 0; x < DAHDI_CHUNKSIZE; x++) >+ rxb[x] = DAHDI_LIN2X(putlin[x], ms); >+ >+ break; >+ case DAHDI_CONF_MONITORBOTH_PREECHO: /* Monitor a channel's tx and rx mode */ >+ /* if not a pseudo-channel, ignore */ >+ if (!(ms->flags & DAHDI_FLAG_PSEUDO)) >+ break; >+ >+ if (!chans[ms->confna]->readchunkpreec) >+ break; >+ >+ /* Note: Technically, saturation should be done at >+ the end of the whole addition, but for performance >+ reasons, we don't do that. Besides, it only matters >+ when you're so loud you're clipping anyway */ >+ ACSS(putlin, chans[ms->confna]->getlin); >+ ACSS(putlin, chans[ms->confna]->readchunkpreec); >+ for (x = 0; x < DAHDI_CHUNKSIZE; x++) >+ rxb[x] = DAHDI_LIN2X(putlin[x], ms); >+ >+ break; >+ case DAHDI_CONF_REALANDPSEUDO: >+ /* do normal conf mode processing */ >+ if (ms->confmode & DAHDI_CONF_TALKER) { >+ /* Store temp value */ >+ memcpy(k, putlin, DAHDI_CHUNKSIZE * sizeof(short)); >+ /* Add conf value */ >+ ACSS(k, conf_sums_next[ms->_confn]); >+ /* get amount actually added */ >+ memcpy(ms->conflast, k, DAHDI_CHUNKSIZE * sizeof(short)); >+ SCSS(ms->conflast, conf_sums_next[ms->_confn]); >+ /* Really add in new value */ >+ ACSS(conf_sums_next[ms->_confn], ms->conflast); >+ } else memset(ms->conflast, 0, DAHDI_CHUNKSIZE * sizeof(short)); >+ /* do the pseudo-channel part processing */ >+ memset(putlin, 0, DAHDI_CHUNKSIZE * sizeof(short)); >+ if (ms->confmode & DAHDI_CONF_PSEUDO_LISTENER) { >+ /* Subtract out previous last sample written to conf */ >+ SCSS(putlin, ms->conflast2); >+ /* Add in conference */ >+ ACSS(putlin, conf_sums[ms->_confn]); >+ } >+ /* Convert back */ >+ for(x=0;x<DAHDI_CHUNKSIZE;x++) >+ rxb[x] = DAHDI_LIN2X(putlin[x], ms); >+ break; >+ case DAHDI_CONF_CONF: /* Normal conference mode */ >+ if (ms->flags & DAHDI_FLAG_PSEUDO) /* if a pseudo-channel */ >+ { >+ if (ms->confmode & DAHDI_CONF_LISTENER) { >+ /* Subtract out last sample written to conf */ >+ SCSS(putlin, ms->conflast); >+ /* Add in conference */ >+ ACSS(putlin, conf_sums[ms->_confn]); >+ } >+ /* Convert back */ >+ for(x=0;x<DAHDI_CHUNKSIZE;x++) >+ rxb[x] = DAHDI_LIN2X(putlin[x], ms); >+ memcpy(ss->putlin, putlin, DAHDI_CHUNKSIZE * sizeof(short)); >+ break; >+ } >+ /* fall through */ >+ case DAHDI_CONF_CONFANN: /* Conference with announce */ >+ if (ms->confmode & DAHDI_CONF_TALKER) { >+ /* Store temp value */ >+ memcpy(k, putlin, DAHDI_CHUNKSIZE * sizeof(short)); >+ /* Add conf value */ >+ ACSS(k, conf_sums_next[ms->_confn]); >+ /* get amount actually added */ >+ memcpy(ms->conflast, k, DAHDI_CHUNKSIZE * sizeof(short)); >+ SCSS(ms->conflast, conf_sums_next[ms->_confn]); >+ /* Really add in new value */ >+ ACSS(conf_sums_next[ms->_confn], ms->conflast); >+ } else >+ memset(ms->conflast, 0, DAHDI_CHUNKSIZE * sizeof(short)); >+ /* rxc unmodified */ >+ break; >+ case DAHDI_CONF_CONFMON: >+ case DAHDI_CONF_CONFANNMON: >+ if (ms->confmode & DAHDI_CONF_TALKER) { >+ /* Store temp value */ >+ memcpy(k, putlin, DAHDI_CHUNKSIZE * sizeof(short)); >+ /* Subtract last value */ >+ SCSS(conf_sums[ms->_confn], ms->conflast); >+ /* Add conf value */ >+ ACSS(k, conf_sums[ms->_confn]); >+ /* get amount actually added */ >+ memcpy(ms->conflast, k, DAHDI_CHUNKSIZE * sizeof(short)); >+ SCSS(ms->conflast, conf_sums[ms->_confn]); >+ /* Really add in new value */ >+ ACSS(conf_sums[ms->_confn], ms->conflast); >+ } else >+ memset(ms->conflast, 0, DAHDI_CHUNKSIZE * sizeof(short)); >+ for (x=0;x<DAHDI_CHUNKSIZE;x++) >+ rxb[x] = DAHDI_LIN2X((int)conf_sums_prev[ms->_confn][x], ms); >+ break; >+ case DAHDI_CONF_DIGITALMON: >+ /* if not a pseudo-channel, ignore */ >+ if (!(ms->flags & DAHDI_FLAG_PSEUDO)) break; >+ /* Add monitored channel */ >+ if (chans[ms->confna]->flags & DAHDI_FLAG_PSEUDO) { >+ memcpy(rxb, chans[ms->confna]->getraw, DAHDI_CHUNKSIZE); >+ } else { >+ memcpy(rxb, chans[ms->confna]->putraw, DAHDI_CHUNKSIZE); >+ } >+ break; >+ } >+ } >+} >+ >+/* HDLC (or other) receiver buffer functions for read side */ >+static inline void __putbuf_chunk(struct dahdi_chan *ss, unsigned char *rxb, int bytes) >+{ >+ /* We transmit data from our master channel */ >+ /* Called with ss->lock held */ >+ struct dahdi_chan *ms = ss->master; >+ /* Our receive buffer */ >+ unsigned char *buf; >+#if defined(CONFIG_DAHDI_NET) || defined(CONFIG_DAHDI_PPP) >+ /* SKB for receiving network stuff */ >+ struct sk_buff *skb=NULL; >+#endif >+ int oldbuf; >+ int eof=0; >+ int abort=0; >+ int res; >+ int left, x; >+ >+ while(bytes) { >+#if defined(CONFIG_DAHDI_NET) || defined(CONFIG_DAHDI_PPP) >+ skb = NULL; >+#endif >+ abort = 0; >+ eof = 0; >+ /* Next, figure out if we've got a buffer to receive into */ >+ if (ms->inreadbuf > -1) { >+ /* Read into the current buffer */ >+ buf = ms->readbuf[ms->inreadbuf]; >+ left = ms->blocksize - ms->readidx[ms->inreadbuf]; >+ if (left > bytes) >+ left = bytes; >+ if (ms->flags & DAHDI_FLAG_HDLC) { >+ for (x=0;x<left;x++) { >+ /* Handle HDLC deframing */ >+ fasthdlc_rx_load_nocheck(&ms->rxhdlc, *(rxb++)); >+ bytes--; >+ res = fasthdlc_rx_run(&ms->rxhdlc); >+ /* If there is nothing there, continue */ >+ if (res & RETURN_EMPTY_FLAG) >+ continue; >+ else if (res & RETURN_COMPLETE_FLAG) { >+ /* Only count this if it's a non-empty frame */ >+ if (ms->readidx[ms->inreadbuf]) { >+ if ((ms->flags & DAHDI_FLAG_FCS) && (ms->infcs != PPP_GOODFCS)) { >+ abort = DAHDI_EVENT_BADFCS; >+ } else >+ eof=1; >+ break; >+ } >+ continue; >+ } else if (res & RETURN_DISCARD_FLAG) { >+ /* This could be someone idling with >+ "idle" instead of "flag" */ >+ if (!ms->readidx[ms->inreadbuf]) >+ continue; >+ abort = DAHDI_EVENT_ABORT; >+ break; >+ } else { >+ unsigned char rxc; >+ rxc = res; >+ ms->infcs = PPP_FCS(ms->infcs, rxc); >+ buf[ms->readidx[ms->inreadbuf]++] = rxc; >+ /* Pay attention to the possibility of an overrun */ >+ if (ms->readidx[ms->inreadbuf] >= ms->blocksize) { >+ if (!ss->span->alarms) >+ module_printk(KERN_WARNING, "HDLC Receiver overrun on channel %s (master=%s)\n", ss->name, ss->master->name); >+ abort=DAHDI_EVENT_OVERRUN; >+ /* Force the HDLC state back to frame-search mode */ >+ ms->rxhdlc.state = 0; >+ ms->rxhdlc.bits = 0; >+ ms->readidx[ms->inreadbuf]=0; >+ break; >+ } >+ } >+ } >+ } else { >+ /* Not HDLC */ >+ memcpy(buf + ms->readidx[ms->inreadbuf], rxb, left); >+ rxb += left; >+ ms->readidx[ms->inreadbuf] += left; >+ bytes -= left; >+ /* End of frame is decided by block size of 'N' */ >+ eof = (ms->readidx[ms->inreadbuf] >= ms->blocksize); >+ if (eof && (ss->flags & DAHDI_FLAG_NOSTDTXRX)) { >+ eof = 0; >+ abort = DAHDI_EVENT_OVERRUN; >+ } >+ } >+ if (eof) { >+ /* Finished with this buffer, try another. */ >+ oldbuf = ms->inreadbuf; >+ ms->infcs = PPP_INITFCS; >+ ms->readn[ms->inreadbuf] = ms->readidx[ms->inreadbuf]; >+#ifdef CONFIG_DAHDI_DEBUG >+ module_printk(KERN_NOTICE, "EOF, len is %d\n", ms->readn[ms->inreadbuf]); >+#endif >+#if defined(CONFIG_DAHDI_NET) || defined(CONFIG_DAHDI_PPP) >+ if (ms->flags & (DAHDI_FLAG_NETDEV | DAHDI_FLAG_PPP)) { >+#ifdef CONFIG_DAHDI_NET >+#endif /* CONFIG_DAHDI_NET */ >+ /* Our network receiver logic is MUCH >+ different. We actually only use a single >+ buffer */ >+ if (ms->readn[ms->inreadbuf] > 1) { >+ /* Drop the FCS */ >+ ms->readn[ms->inreadbuf] -= 2; >+ /* Allocate an SKB */ >+#ifdef CONFIG_DAHDI_PPP >+ if (!ms->do_ppp_error) >+#endif >+ skb = dev_alloc_skb(ms->readn[ms->inreadbuf]); >+ if (skb) { >+ /* XXX Get rid of this memcpy XXX */ >+ memcpy(skb->data, ms->readbuf[ms->inreadbuf], ms->readn[ms->inreadbuf]); >+ skb_put(skb, ms->readn[ms->inreadbuf]); >+#ifdef CONFIG_DAHDI_NET >+ if (ms->flags & DAHDI_FLAG_NETDEV) { >+ struct net_device_stats *stats = hdlc_stats(ms->hdlcnetdev->netdev); >+ stats->rx_packets++; >+ stats->rx_bytes += ms->readn[ms->inreadbuf]; >+ } >+#endif >+ >+ } else { >+#ifdef CONFIG_DAHDI_NET >+ if (ms->flags & DAHDI_FLAG_NETDEV) { >+ struct net_device_stats *stats = hdlc_stats(ms->hdlcnetdev->netdev); >+ stats->rx_dropped++; >+ } >+#endif >+#ifdef CONFIG_DAHDI_PPP >+ if (ms->flags & DAHDI_FLAG_PPP) { >+ abort = DAHDI_EVENT_OVERRUN; >+ } >+#endif >+#if 1 >+#ifdef CONFIG_DAHDI_PPP >+ if (!ms->do_ppp_error) >+#endif >+ module_printk(KERN_NOTICE, "Memory squeeze, dropped one\n"); >+#endif >+ } >+ } >+ /* We don't cycle through buffers, just >+ reuse the same one */ >+ ms->readn[ms->inreadbuf] = 0; >+ ms->readidx[ms->inreadbuf] = 0; >+ } else >+#endif >+ { >+ /* This logic might confuse and astound. Basically we need to find >+ * the previous buffer index. It should be safe because, regardless >+ * of whether or not it has been copied to user space, nothing should >+ * have messed around with it since then */ >+ >+ int comparemessage; >+ /* Shut compiler up */ >+ int myres = 0; >+ >+ if (ms->flags & DAHDI_FLAG_MTP2) { >+ comparemessage = (ms->inreadbuf - 1) & (ms->numbufs - 1); >+ >+ myres = memcmp(ms->readbuf[comparemessage], ms->readbuf[ms->inreadbuf], ms->readn[ms->inreadbuf]); >+ } >+ >+ if ((ms->flags & DAHDI_FLAG_MTP2) && !myres) { >+ /* Our messages are the same, so discard - >+ * Don't advance buffers, reset indexes and buffer sizes. */ >+ ms->readn[ms->inreadbuf] = 0; >+ ms->readidx[ms->inreadbuf] = 0; >+ } else { >+ ms->inreadbuf = (ms->inreadbuf + 1) % ms->numbufs; >+ if (ms->inreadbuf == ms->outreadbuf) { >+ /* Whoops, we're full, and have no where else >+ to store into at the moment. We'll drop it >+ until there's a buffer available */ >+#ifdef BUFFER_DEBUG >+ module_printk(KERN_NOTICE, "Out of storage space\n"); >+#endif >+ ms->inreadbuf = -1; >+ /* Enable the receiver in case they've got POLICY_WHEN_FULL */ >+ ms->rxdisable = 0; >+ } >+ if (ms->outreadbuf < 0) { /* start out buffer if not already */ >+ ms->outreadbuf = oldbuf; >+ /* if there are processes waiting in poll() on this channel, >+ wake them up */ >+ if (!ms->rxdisable) { >+ wake_up_interruptible(&ms->sel); >+ } >+ } >+/* In the very orignal driver, it was quite well known to me (Jim) that there >+was a possibility that a channel sleeping on a receive block needed to >+be potentially woken up EVERY time a buffer was filled, not just on the first >+one, because if only done on the first one there is a slight timing potential >+of missing the wakeup (between where it senses the (lack of) active condition >+(with interrupts disabled) and where it does the sleep (interrupts enabled) >+in the read or iomux call, etc). That is why the read and iomux calls start >+with an infinite loop that gets broken out of upon an active condition, >+otherwise keeps sleeping and looking. The part in this code got "optimized" >+out in the later versions, and is put back now. Note that this is *NOT* >+needed for poll() waiters, because the poll_wait() function that is used there >+is atomic enough for this purpose; it will not go to sleep before ensuring >+that the waitqueue is empty. */ >+ if (!ms->rxdisable) { /* if receiver enabled */ >+ /* Notify a blocked reader that there is data available >+ to be read, unless we're waiting for it to be full */ >+#ifdef CONFIG_DAHDI_DEBUG >+ module_printk(KERN_NOTICE, "Notifying reader data in block %d\n", oldbuf); >+#endif >+ wake_up_interruptible(&ms->readbufq); >+ if (ms->iomask & DAHDI_IOMUX_READ) >+ wake_up_interruptible(&ms->eventbufq); >+ } >+ } >+ } >+ } >+ if (abort) { >+ /* Start over reading frame */ >+ ms->readidx[ms->inreadbuf] = 0; >+ ms->infcs = PPP_INITFCS; >+ >+#ifdef CONFIG_DAHDI_NET >+ if (ms->flags & DAHDI_FLAG_NETDEV) { >+ struct net_device_stats *stats = hdlc_stats(ms->hdlcnetdev->netdev); >+ stats->rx_errors++; >+ if (abort == DAHDI_EVENT_OVERRUN) >+ stats->rx_over_errors++; >+ if (abort == DAHDI_EVENT_BADFCS) >+ stats->rx_crc_errors++; >+ if (abort == DAHDI_EVENT_ABORT) >+ stats->rx_frame_errors++; >+ } else >+#endif >+#ifdef CONFIG_DAHDI_PPP >+ if (ms->flags & DAHDI_FLAG_PPP) { >+ ms->do_ppp_error = 1; >+ tasklet_schedule(&ms->ppp_calls); >+ } else >+#endif >+ if (test_bit(DAHDI_FLAGBIT_OPEN, &ms->flags) && !ss->span->alarms) { >+ /* Notify the receiver... */ >+ __qevent(ss->master, abort); >+ } >+#if 0 >+ module_printk(KERN_NOTICE, "torintr_receive: Aborted %d bytes of frame on %d\n", amt, ss->master); >+#endif >+ >+ } >+ } else /* No place to receive -- drop on the floor */ >+ break; >+#ifdef CONFIG_DAHDI_NET >+ if (skb && (ms->flags & DAHDI_FLAG_NETDEV)) >+#ifdef NEW_HDLC_INTERFACE >+ { >+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22) >+ skb->mac.raw = skb->data; >+#else >+ skb_reset_mac_header(skb); >+#endif >+ skb->dev = ztchan_to_dev(ms); >+#ifdef DAHDI_HDLC_TYPE_TRANS >+ skb->protocol = hdlc_type_trans(skb, ztchan_to_dev(ms)); >+#else >+ skb->protocol = htons (ETH_P_HDLC); >+#endif >+ netif_rx(skb); >+ } >+#else >+ hdlc_netif_rx(&ms->hdlcnetdev->netdev, skb); >+#endif >+#endif >+#ifdef CONFIG_DAHDI_PPP >+ if (skb && (ms->flags & DAHDI_FLAG_PPP)) { >+ unsigned char *tmp; >+ tmp = skb->data; >+ skb_pull(skb, 2); >+ /* Make sure that it's addressed to ALL STATIONS and UNNUMBERED */ >+ if (!tmp || (tmp[0] != 0xff) || (tmp[1] != 0x03)) { >+ /* Invalid SKB -- drop */ >+ if (tmp) >+ module_printk(KERN_NOTICE, "Received invalid SKB (%02x, %02x)\n", tmp[0], tmp[1]); >+ dev_kfree_skb_irq(skb); >+ } else { >+ skb_queue_tail(&ms->ppp_rq, skb); >+ tasklet_schedule(&ms->ppp_calls); >+ } >+ } >+#endif >+ } >+} >+ >+static inline void __dahdi_putbuf_chunk(struct dahdi_chan *ss, unsigned char *rxb) >+{ >+ __putbuf_chunk(ss, rxb, DAHDI_CHUNKSIZE); >+} >+ >+static void __dahdi_hdlc_abort(struct dahdi_chan *ss, int event) >+{ >+ if (ss->inreadbuf >= 0) >+ ss->readidx[ss->inreadbuf] = 0; >+ if (test_bit(DAHDI_FLAGBIT_OPEN, &ss->flags) && !ss->span->alarms) >+ __qevent(ss->master, event); >+} >+ >+void dahdi_hdlc_abort(struct dahdi_chan *ss, int event) >+{ >+ unsigned long flags; >+ spin_lock_irqsave(&ss->lock, flags); >+ __dahdi_hdlc_abort(ss, event); >+ spin_unlock_irqrestore(&ss->lock, flags); >+} >+ >+void dahdi_hdlc_putbuf(struct dahdi_chan *ss, unsigned char *rxb, int bytes) >+{ >+ unsigned long flags; >+ int res; >+ int left; >+ >+ spin_lock_irqsave(&ss->lock, flags); >+ if (ss->inreadbuf < 0) { >+#ifdef CONFIG_DAHDI_DEBUG >+ module_printk(KERN_NOTICE, "No place to receive HDLC frame\n"); >+#endif >+ spin_unlock_irqrestore(&ss->lock, flags); >+ return; >+ } >+ /* Read into the current buffer */ >+ left = ss->blocksize - ss->readidx[ss->inreadbuf]; >+ if (left > bytes) >+ left = bytes; >+ if (left > 0) { >+ memcpy(ss->readbuf[ss->inreadbuf] + ss->readidx[ss->inreadbuf], rxb, left); >+ rxb += left; >+ ss->readidx[ss->inreadbuf] += left; >+ bytes -= left; >+ } >+ /* Something isn't fit into buffer */ >+ if (bytes) { >+#ifdef CONFIG_DAHDI_DEBUG >+ module_printk(KERN_NOTICE, "HDLC frame isn't fit into buffer space\n"); >+#endif >+ __dahdi_hdlc_abort(ss, DAHDI_EVENT_OVERRUN); >+ } >+ res = left; >+ spin_unlock_irqrestore(&ss->lock, flags); >+} >+ >+void dahdi_hdlc_finish(struct dahdi_chan *ss) >+{ >+ int oldreadbuf; >+ unsigned long flags; >+ >+ spin_lock_irqsave(&ss->lock, flags); >+ >+ if ((oldreadbuf = ss->inreadbuf) < 0) { >+#ifdef CONFIG_DAHDI_DEBUG >+ module_printk(KERN_NOTICE, "No buffers to finish\n"); >+#endif >+ spin_unlock_irqrestore(&ss->lock, flags); >+ return; >+ } >+ >+ if (!ss->readidx[ss->inreadbuf]) { >+#ifdef CONFIG_DAHDI_DEBUG >+ module_printk(KERN_NOTICE, "Empty HDLC frame received\n"); >+#endif >+ spin_unlock_irqrestore(&ss->lock, flags); >+ return; >+ } >+ >+ ss->readn[ss->inreadbuf] = ss->readidx[ss->inreadbuf]; >+ ss->inreadbuf = (ss->inreadbuf + 1) % ss->numbufs; >+ if (ss->inreadbuf == ss->outreadbuf) { >+ ss->inreadbuf = -1; >+#ifdef CONFIG_DAHDI_DEBUG >+ module_printk(KERN_NOTICE, "Notifying reader data in block %d\n", oldreadbuf); >+#endif >+ ss->rxdisable = 0; >+ } >+ if (ss->outreadbuf < 0) { >+ ss->outreadbuf = oldreadbuf; >+ } >+ >+ if (!ss->rxdisable) { >+ wake_up_interruptible(&ss->readbufq); >+ wake_up_interruptible(&ss->sel); >+ if (ss->iomask & DAHDI_IOMUX_READ) >+ wake_up_interruptible(&ss->eventbufq); >+ } >+ spin_unlock_irqrestore(&ss->lock, flags); >+} >+ >+/* Returns 1 if EOF, 0 if data is still in frame, -1 if EOF and no buffers left */ >+int dahdi_hdlc_getbuf(struct dahdi_chan *ss, unsigned char *bufptr, unsigned int *size) >+{ >+ unsigned char *buf; >+ unsigned long flags; >+ int left = 0; >+ int res; >+ int oldbuf; >+ >+ spin_lock_irqsave(&ss->lock, flags); >+ if (ss->outwritebuf > -1) { >+ buf = ss->writebuf[ss->outwritebuf]; >+ left = ss->writen[ss->outwritebuf] - ss->writeidx[ss->outwritebuf]; >+ /* Strip off the empty HDLC CRC end */ >+ left -= 2; >+ if (left <= *size) { >+ *size = left; >+ res = 1; >+ } else >+ res = 0; >+ >+ memcpy(bufptr, &buf[ss->writeidx[ss->outwritebuf]], *size); >+ ss->writeidx[ss->outwritebuf] += *size; >+ >+ if (res) { >+ /* Rotate buffers */ >+ oldbuf = ss->outwritebuf; >+ ss->writeidx[oldbuf] = 0; >+ ss->writen[oldbuf] = 0; >+ ss->outwritebuf = (ss->outwritebuf + 1) % ss->numbufs; >+ if (ss->outwritebuf == ss->inwritebuf) { >+ ss->outwritebuf = -1; >+ if (ss->iomask & (DAHDI_IOMUX_WRITE | DAHDI_IOMUX_WRITEEMPTY)) >+ wake_up_interruptible(&ss->eventbufq); >+ /* If we're only supposed to start when full, disable the transmitter */ >+ if ((ss->txbufpolicy == DAHDI_POLICY_WHEN_FULL) || (ss->txbufpolicy == DAHDI_POLICY_HALF_FULL)) >+ ss->txdisable = 1; >+ res = -1; >+ } >+ >+ if (ss->inwritebuf < 0) >+ ss->inwritebuf = oldbuf; >+ >+ if (!(ss->flags & (DAHDI_FLAG_NETDEV | DAHDI_FLAG_PPP))) { >+ wake_up_interruptible(&ss->writebufq); >+ wake_up_interruptible(&ss->sel); >+ if ((ss->iomask & DAHDI_IOMUX_WRITE) && (res >= 0)) >+ wake_up_interruptible(&ss->eventbufq); >+ } >+ } >+ } else { >+ res = -1; >+ *size = 0; >+ } >+ spin_unlock_irqrestore(&ss->lock, flags); >+ >+ return res; >+} >+ >+ >+static void process_timers(void) >+{ >+ unsigned long flags; >+ struct dahdi_timer *cur; >+ >+ spin_lock_irqsave(&zaptimerlock, flags); >+ >+ list_for_each_entry(cur, &zaptimers, list) { >+ if (cur->ms) { >+ cur->pos -= DAHDI_CHUNKSIZE; >+ if (cur->pos <= 0) { >+ cur->tripped++; >+ cur->pos = cur->ms; >+ wake_up_interruptible(&cur->sel); >+ } >+ } >+ } >+ >+ spin_unlock_irqrestore(&zaptimerlock, flags); >+} >+ >+static unsigned int dahdi_timer_poll(struct file *file, struct poll_table_struct *wait_table) >+{ >+ struct dahdi_timer *timer = file->private_data; >+ unsigned long flags; >+ int ret = 0; >+ if (timer) { >+ poll_wait(file, &timer->sel, wait_table); >+ spin_lock_irqsave(&zaptimerlock, flags); >+ if (timer->tripped || timer->ping) >+ ret |= POLLPRI; >+ spin_unlock_irqrestore(&zaptimerlock, flags); >+ } else >+ ret = -EINVAL; >+ return ret; >+} >+ >+/* device poll routine */ >+static unsigned int >+dahdi_chan_poll(struct file *file, struct poll_table_struct *wait_table, int unit) >+{ >+ >+ struct dahdi_chan *chan = chans[unit]; >+ int ret; >+ unsigned long flags; >+ >+ /* do the poll wait */ >+ if (chan) { >+ poll_wait(file, &chan->sel, wait_table); >+ ret = 0; /* start with nothing to return */ >+ spin_lock_irqsave(&chan->lock, flags); >+ /* if at least 1 write buffer avail */ >+ if (chan->inwritebuf > -1) { >+ ret |= POLLOUT | POLLWRNORM; >+ } >+ if ((chan->outreadbuf > -1) && !chan->rxdisable) { >+ ret |= POLLIN | POLLRDNORM; >+ } >+ if (chan->eventoutidx != chan->eventinidx) >+ { >+ /* Indicate an exception */ >+ ret |= POLLPRI; >+ } >+ spin_unlock_irqrestore(&chan->lock, flags); >+ } else >+ ret = -EINVAL; >+ return(ret); /* return what we found */ >+} >+ >+static int dahdi_mmap(struct file *file, struct vm_area_struct *vm) >+{ >+ int unit = UNIT(file); >+ if (unit == 250) >+ return dahdi_transcode_fops->mmap(file, vm); >+ return -ENOSYS; >+} >+ >+static unsigned int dahdi_poll(struct file *file, struct poll_table_struct *wait_table) >+{ >+ int unit = UNIT(file); >+ struct dahdi_chan *chan; >+ >+ if (!unit) >+ return -EINVAL; >+ >+ if (unit == 250) >+ return dahdi_transcode_fops->poll(file, wait_table); >+ >+ if (unit == 253) >+ return dahdi_timer_poll(file, wait_table); >+ >+ if (unit == 254) { >+ chan = file->private_data; >+ if (!chan) >+ return -EINVAL; >+ return dahdi_chan_poll(file, wait_table,chan->channo); >+ } >+ if (unit == 255) { >+ chan = file->private_data; >+ if (!chan) { >+ module_printk(KERN_NOTICE, "No pseudo channel structure to read?\n"); >+ return -EINVAL; >+ } >+ return dahdi_chan_poll(file, wait_table, chan->channo); >+ } >+ return dahdi_chan_poll(file, wait_table, unit); >+} >+ >+static void __dahdi_transmit_chunk(struct dahdi_chan *chan, unsigned char *buf) >+{ >+ unsigned char silly[DAHDI_CHUNKSIZE]; >+ /* Called with chan->lock locked */ >+#ifdef OPTIMIZE_CHANMUTE >+ if(likely(chan->chanmute)) >+ return; >+#endif >+ if (!buf) >+ buf = silly; >+ __dahdi_getbuf_chunk(chan, buf); >+ >+ if ((chan->flags & DAHDI_FLAG_AUDIO) || (chan->confmode)) { >+#ifdef CONFIG_DAHDI_MMX >+ dahdi_kernel_fpu_begin(); >+#endif >+ __dahdi_process_getaudio_chunk(chan, buf); >+#ifdef CONFIG_DAHDI_MMX >+ kernel_fpu_end(); >+#endif >+ } >+} >+ >+static inline void __dahdi_real_transmit(struct dahdi_chan *chan) >+{ >+ /* Called with chan->lock held */ >+#ifdef OPTIMIZE_CHANMUTE >+ if(likely(chan->chanmute)) >+ return; >+#endif >+ if (chan->confmode) { >+ /* Pull queued data off the conference */ >+ __buf_pull(&chan->confout, chan->writechunk, chan, "dahdi_real_transmit"); >+ } else { >+ __dahdi_transmit_chunk(chan, chan->writechunk); >+ } >+} >+ >+static void __dahdi_getempty(struct dahdi_chan *ms, unsigned char *buf) >+{ >+ int bytes = DAHDI_CHUNKSIZE; >+ int left; >+ unsigned char *txb = buf; >+ int x; >+ short getlin; >+ /* Called with ms->lock held */ >+ >+ while(bytes) { >+ /* Receive silence, or tone */ >+ if (ms->curtone) { >+ left = ms->curtone->tonesamples - ms->tonep; >+ if (left > bytes) >+ left = bytes; >+ for (x=0;x<left;x++) { >+ /* Pick our default value from the next sample of the current tone */ >+ getlin = dahdi_tone_nextsample(&ms->ts, ms->curtone); >+ *(txb++) = DAHDI_LIN2X(getlin, ms); >+ } >+ ms->tonep+=left; >+ bytes -= left; >+ if (ms->tonep >= ms->curtone->tonesamples) { >+ struct dahdi_tone *last; >+ /* Go to the next sample of the tone */ >+ ms->tonep = 0; >+ last = ms->curtone; >+ ms->curtone = ms->curtone->next; >+ if (!ms->curtone) { >+ /* No more tones... Is this dtmf or mf? If so, go to the next digit */ >+ if (ms->dialing) >+ __do_dtmf(ms); >+ } else { >+ if (last != ms->curtone) >+ dahdi_init_tone_state(&ms->ts, ms->curtone); >+ } >+ } >+ } else { >+ /* Use silence */ >+ memset(txb, DAHDI_LIN2X(0, ms), bytes); >+ bytes = 0; >+ } >+ } >+ >+} >+ >+static void __dahdi_receive_chunk(struct dahdi_chan *chan, unsigned char *buf) >+{ >+ /* Receive chunk of audio -- called with chan->lock held */ >+ unsigned char waste[DAHDI_CHUNKSIZE]; >+ >+#ifdef OPTIMIZE_CHANMUTE >+ if(likely(chan->chanmute)) >+ return; >+#endif >+ if (!buf) { >+ memset(waste, DAHDI_LIN2X(0, chan), sizeof(waste)); >+ buf = waste; >+ } >+ if ((chan->flags & DAHDI_FLAG_AUDIO) || (chan->confmode)) { >+#ifdef CONFIG_DAHDI_MMX >+ dahdi_kernel_fpu_begin(); >+#endif >+ __dahdi_process_putaudio_chunk(chan, buf); >+#ifdef CONFIG_DAHDI_MMX >+ kernel_fpu_end(); >+#endif >+ } >+ __dahdi_putbuf_chunk(chan, buf); >+} >+ >+static inline void __dahdi_real_receive(struct dahdi_chan *chan) >+{ >+ /* Called with chan->lock held */ >+#ifdef OPTIMIZE_CHANMUTE >+ if(likely(chan->chanmute)) >+ return; >+#endif >+ if (chan->confmode) { >+ /* Load into queue if we have space */ >+ __buf_push(&chan->confin, chan->readchunk, "dahdi_real_receive"); >+ } else { >+ __dahdi_receive_chunk(chan, chan->readchunk); >+ } >+} >+ >+int dahdi_transmit(struct dahdi_span *span) >+{ >+ int x,y,z; >+ unsigned long flags; >+ >+#if 1 >+ for (x=0;x<span->channels;x++) { >+ spin_lock_irqsave(&span->chans[x]->lock, flags); >+ if (span->chans[x]->flags & DAHDI_FLAG_NOSTDTXRX) { >+ spin_unlock_irqrestore(&span->chans[x]->lock, flags); >+ continue; >+ } >+ if (span->chans[x] == span->chans[x]->master) { >+ if (span->chans[x]->otimer) { >+ span->chans[x]->otimer -= DAHDI_CHUNKSIZE; >+ if (span->chans[x]->otimer <= 0) { >+ __rbs_otimer_expire(span->chans[x]); >+ } >+ } >+ if (span->chans[x]->flags & DAHDI_FLAG_AUDIO) { >+ __dahdi_real_transmit(span->chans[x]); >+ } else { >+ if (span->chans[x]->nextslave) { >+ u_char data[DAHDI_CHUNKSIZE]; >+ int pos=DAHDI_CHUNKSIZE; >+ /* Process master/slaves one way */ >+ for (y=0;y<DAHDI_CHUNKSIZE;y++) { >+ /* Process slaves for this byte too */ >+ z = x; >+ do { >+ if (pos==DAHDI_CHUNKSIZE) { >+ /* Get next chunk */ >+ __dahdi_transmit_chunk(span->chans[x], data); >+ pos = 0; >+ } >+ span->chans[z]->writechunk[y] = data[pos++]; >+ z = span->chans[z]->nextslave; >+ } while(z); >+ } >+ } else { >+ /* Process independents elsewise */ >+ __dahdi_real_transmit(span->chans[x]); >+ } >+ } >+ if (span->chans[x]->sig == DAHDI_SIG_DACS_RBS) { >+ if (chans[span->chans[x]->confna]) { >+ /* Just set bits for our destination */ >+ if (span->chans[x]->txsig != chans[span->chans[x]->confna]->rxsig) { >+ span->chans[x]->txsig = chans[span->chans[x]->confna]->rxsig; >+ span->rbsbits(span->chans[x], chans[span->chans[x]->confna]->rxsig); >+ } >+ } >+ } >+ >+ } >+ spin_unlock_irqrestore(&span->chans[x]->lock, flags); >+ } >+ if (span->mainttimer) { >+ span->mainttimer -= DAHDI_CHUNKSIZE; >+ if (span->mainttimer <= 0) { >+ span->mainttimer = 0; >+ if (span->maint) >+ span->maint(span, DAHDI_MAINT_LOOPSTOP); >+ span->maintstat = 0; >+ wake_up_interruptible(&span->maintq); >+ } >+ } >+#endif >+ return 0; >+} >+ >+int dahdi_receive(struct dahdi_span *span) >+{ >+ int x,y,z; >+ unsigned long flags; >+ >+#if 1 >+#ifdef CONFIG_DAHDI_WATCHDOG >+ span->watchcounter--; >+#endif >+ for (x=0;x<span->channels;x++) { >+ if (span->chans[x]->master == span->chans[x]) { >+ spin_lock_irqsave(&span->chans[x]->lock, flags); >+ if (span->chans[x]->nextslave) { >+ /* Must process each slave at the same time */ >+ u_char data[DAHDI_CHUNKSIZE]; >+ int pos = 0; >+ for (y=0;y<DAHDI_CHUNKSIZE;y++) { >+ /* Put all its slaves, too */ >+ z = x; >+ do { >+ data[pos++] = span->chans[z]->readchunk[y]; >+ if (pos == DAHDI_CHUNKSIZE) { >+ if(!(span->chans[x]->flags & DAHDI_FLAG_NOSTDTXRX)) >+ __dahdi_receive_chunk(span->chans[x], data); >+ pos = 0; >+ } >+ z=span->chans[z]->nextslave; >+ } while(z); >+ } >+ } else { >+ /* Process a normal channel */ >+ if (!(span->chans[x]->flags & DAHDI_FLAG_NOSTDTXRX)) >+ __dahdi_real_receive(span->chans[x]); >+ } >+ if (span->chans[x]->itimer) { >+ span->chans[x]->itimer -= DAHDI_CHUNKSIZE; >+ if (span->chans[x]->itimer <= 0) { >+ rbs_itimer_expire(span->chans[x]); >+ } >+ } >+ if (span->chans[x]->ringdebtimer) >+ span->chans[x]->ringdebtimer--; >+ if (span->chans[x]->sig & __DAHDI_SIG_FXS) { >+ if (span->chans[x]->rxhooksig == DAHDI_RXSIG_RING) >+ span->chans[x]->ringtrailer = DAHDI_RINGTRAILER; >+ else if (span->chans[x]->ringtrailer) { >+ span->chans[x]->ringtrailer-= DAHDI_CHUNKSIZE; >+ /* See if RING trailer is expired */ >+ if (!span->chans[x]->ringtrailer && !span->chans[x]->ringdebtimer) >+ __qevent(span->chans[x],DAHDI_EVENT_RINGOFFHOOK); >+ } >+ } >+ if (span->chans[x]->pulsetimer) >+ { >+ span->chans[x]->pulsetimer--; >+ if (span->chans[x]->pulsetimer <= 0) >+ { >+ if (span->chans[x]->pulsecount) >+ { >+ if (span->chans[x]->pulsecount > 12) { >+ >+ module_printk(KERN_NOTICE, "Got pulse digit %d on %s???\n", >+ span->chans[x]->pulsecount, >+ span->chans[x]->name); >+ } else if (span->chans[x]->pulsecount > 11) { >+ __qevent(span->chans[x], DAHDI_EVENT_PULSEDIGIT | '#'); >+ } else if (span->chans[x]->pulsecount > 10) { >+ __qevent(span->chans[x], DAHDI_EVENT_PULSEDIGIT | '*'); >+ } else if (span->chans[x]->pulsecount > 9) { >+ __qevent(span->chans[x], DAHDI_EVENT_PULSEDIGIT | '0'); >+ } else { >+ __qevent(span->chans[x], DAHDI_EVENT_PULSEDIGIT | ('0' + >+ span->chans[x]->pulsecount)); >+ } >+ span->chans[x]->pulsecount = 0; >+ } >+ } >+ } >+#ifdef BUFFER_DEBUG >+ span->chans[x]->statcount -= DAHDI_CHUNKSIZE; >+#endif >+ spin_unlock_irqrestore(&span->chans[x]->lock, flags); >+ } >+ } >+ >+ if (span == master) { >+ /* Hold the big zap lock for the duration of major >+ activities which touch all sorts of channels */ >+ spin_lock_irqsave(&bigzaplock, flags); >+ read_lock(&chan_lock); >+ /* Process any timers */ >+ process_timers(); >+ /* If we have dynamic stuff, call the ioctl with 0,0 parameters to >+ make it run */ >+ if (dahdi_dynamic_ioctl) >+ dahdi_dynamic_ioctl(0,0); >+ for (x=1;x<maxchans;x++) { >+ if (chans[x] && chans[x]->confmode && !(chans[x]->flags & DAHDI_FLAG_PSEUDO)) { >+ u_char *data; >+ spin_lock(&chans[x]->lock); >+ data = __buf_peek(&chans[x]->confin); >+ __dahdi_receive_chunk(chans[x], data); >+ if (data) >+ __buf_pull(&chans[x]->confin, NULL,chans[x], "confreceive"); >+ spin_unlock(&chans[x]->lock); >+ } >+ } >+ /* This is the master channel, so make things switch over */ >+ rotate_sums(); >+ /* do all the pseudo and/or conferenced channel receives (getbuf's) */ >+ for (x=1;x<maxchans;x++) { >+ if (chans[x] && (chans[x]->flags & DAHDI_FLAG_PSEUDO)) { >+ spin_lock(&chans[x]->lock); >+ __dahdi_transmit_chunk(chans[x], NULL); >+ spin_unlock(&chans[x]->lock); >+ } >+ } >+ if (maxlinks) { >+#ifdef CONFIG_DAHDI_MMX >+ dahdi_kernel_fpu_begin(); >+#endif >+ /* process all the conf links */ >+ for(x = 1; x <= maxlinks; x++) { >+ /* if we have a destination conf */ >+ if (((z = confalias[conf_links[x].dst]) > 0) && >+ ((y = confalias[conf_links[x].src]) > 0)) { >+ ACSS(conf_sums[z], conf_sums[y]); >+ } >+ } >+#ifdef CONFIG_DAHDI_MMX >+ kernel_fpu_end(); >+#endif >+ } >+ /* do all the pseudo/conferenced channel transmits (putbuf's) */ >+ for (x=1;x<maxchans;x++) { >+ if (chans[x] && (chans[x]->flags & DAHDI_FLAG_PSEUDO)) { >+ unsigned char tmp[DAHDI_CHUNKSIZE]; >+ spin_lock(&chans[x]->lock); >+ __dahdi_getempty(chans[x], tmp); >+ __dahdi_receive_chunk(chans[x], tmp); >+ spin_unlock(&chans[x]->lock); >+ } >+ } >+ for (x=1;x<maxchans;x++) { >+ if (chans[x] && chans[x]->confmode && !(chans[x]->flags & DAHDI_FLAG_PSEUDO)) { >+ u_char *data; >+ spin_lock(&chans[x]->lock); >+ data = __buf_pushpeek(&chans[x]->confout); >+ __dahdi_transmit_chunk(chans[x], data); >+ if (data) >+ __buf_push(&chans[x]->confout, NULL, "conftransmit"); >+ spin_unlock(&chans[x]->lock); >+ } >+ } >+#ifdef DAHDI_SYNC_TICK >+ for (x=0;x<maxspans;x++) { >+ struct dahdi_span *s = spans[x]; >+ >+ if (s && s->sync_tick) >+ s->sync_tick(s, s == master); >+ } >+#endif >+ read_unlock(&chan_lock); >+ spin_unlock_irqrestore(&bigzaplock, flags); >+ } >+#endif >+ return 0; >+} >+ >+MODULE_AUTHOR("Mark Spencer <markster@digium.com>"); >+MODULE_DESCRIPTION("DAHDI Telephony Interface"); >+MODULE_LICENSE("GPL v2"); >+MODULE_VERSION(DAHDI_VERSION); >+ >+module_param(debug, int, 0644); >+module_param(deftaps, int, 0644); >+ >+static struct file_operations dahdi_fops = { >+ .owner = THIS_MODULE, >+ .llseek = NULL, >+ .open = dahdi_open, >+ .release = dahdi_release, >+ .ioctl = dahdi_ioctl, >+ .read = dahdi_read, >+ .write = dahdi_write, >+ .poll = dahdi_poll, >+ .mmap = dahdi_mmap, >+ .flush = NULL, >+ .fsync = NULL, >+ .fasync = NULL, >+}; >+ >+#ifdef CONFIG_DAHDI_WATCHDOG >+static struct timer_list watchdogtimer; >+ >+static void watchdog_check(unsigned long ignored) >+{ >+ int x; >+ unsigned long flags; >+ static int wdcheck=0; >+ >+ local_irq_save(flags); >+ for (x=0;x<maxspans;x++) { >+ if (spans[x] && (spans[x]->flags & DAHDI_FLAG_RUNNING)) { >+ if (spans[x]->watchcounter == DAHDI_WATCHDOG_INIT) { >+ /* Whoops, dead card */ >+ if ((spans[x]->watchstate == DAHDI_WATCHSTATE_OK) || >+ (spans[x]->watchstate == DAHDI_WATCHSTATE_UNKNOWN)) { >+ spans[x]->watchstate = DAHDI_WATCHSTATE_RECOVERING; >+ if (spans[x]->watchdog) { >+ module_printk(KERN_NOTICE, "Kicking span %s\n", spans[x]->name); >+ spans[x]->watchdog(spans[x], DAHDI_WATCHDOG_NOINTS); >+ } else { >+ module_printk(KERN_NOTICE, "Span %s is dead with no revival\n", spans[x]->name); >+ spans[x]->watchstate = DAHDI_WATCHSTATE_FAILED; >+ } >+ } >+ } else { >+ if ((spans[x]->watchstate != DAHDI_WATCHSTATE_OK) && >+ (spans[x]->watchstate != DAHDI_WATCHSTATE_UNKNOWN)) >+ module_printk(KERN_NOTICE, "Span %s is alive!\n", spans[x]->name); >+ spans[x]->watchstate = DAHDI_WATCHSTATE_OK; >+ } >+ spans[x]->watchcounter = DAHDI_WATCHDOG_INIT; >+ } >+ } >+ local_irq_restore(flags); >+ if (!wdcheck) { >+ module_printk(KERN_NOTICE, "watchdog on duty!\n"); >+ wdcheck=1; >+ } >+ mod_timer(&watchdogtimer, jiffies + 2); >+} >+ >+static int __init watchdog_init(void) >+{ >+ init_timer(&watchdogtimer); >+ watchdogtimer.expires = 0; >+ watchdogtimer.data =0; >+ watchdogtimer.function = watchdog_check; >+ /* Run every couple of jiffy or so */ >+ mod_timer(&watchdogtimer, jiffies + 2); >+ return 0; >+} >+ >+static void __exit watchdog_cleanup(void) >+{ >+ del_timer(&watchdogtimer); >+} >+ >+#endif >+ >+int dahdi_register_chardev(struct dahdi_chardev *dev) >+{ >+ char udevname[strlen(dev->name) + sizeof("dahdi!")]; >+ >+ strcpy(udevname, "dahdi!"); >+ strcat(udevname, dev->name); >+ CLASS_DEV_CREATE(dahdi_class, MKDEV(DAHDI_MAJOR, dev->minor), NULL, udevname); >+ >+ return 0; >+} >+ >+int dahdi_unregister_chardev(struct dahdi_chardev *dev) >+{ >+ CLASS_DEV_DESTROY(dahdi_class, MKDEV(DAHDI_MAJOR, dev->minor)); >+ >+ return 0; >+} >+ >+static int __init dahdi_init(void) >+{ >+ int res = 0; >+ >+#ifdef CONFIG_PROC_FS >+ proc_entries[0] = proc_mkdir("dahdi", NULL); >+#endif >+ >+ if ((res = register_chrdev(DAHDI_MAJOR, "dahdi", &dahdi_fops))) { >+ module_printk(KERN_ERR, "Unable to register DAHDI character device handler on %d\n", DAHDI_MAJOR); >+ return res; >+ } >+ >+ dahdi_class = class_create(THIS_MODULE, "dahdi"); >+ CLASS_DEV_CREATE(dahdi_class, MKDEV(DAHDI_MAJOR, 253), NULL, "dahdi!timer"); >+ CLASS_DEV_CREATE(dahdi_class, MKDEV(DAHDI_MAJOR, 254), NULL, "dahdi!channel"); >+ CLASS_DEV_CREATE(dahdi_class, MKDEV(DAHDI_MAJOR, 255), NULL, "dahdi!pseudo"); >+ CLASS_DEV_CREATE(dahdi_class, MKDEV(DAHDI_MAJOR, 0), NULL, "dahdi!ctl"); >+ >+ module_printk(KERN_INFO, "Telephony Interface Registered on major %d\n", DAHDI_MAJOR); >+ module_printk(KERN_INFO, "Version: %s\n", DAHDI_VERSION); >+ dahdi_conv_init(); >+ fasthdlc_precalc(); >+ rotate_sums(); >+#ifdef CONFIG_DAHDI_WATCHDOG >+ watchdog_init(); >+#endif >+ return res; >+} >+ >+static void __exit dahdi_cleanup(void) >+{ >+ int x; >+ >+ CLASS_DEV_DESTROY(dahdi_class, MKDEV(DAHDI_MAJOR, 253)); /* timer */ >+ CLASS_DEV_DESTROY(dahdi_class, MKDEV(DAHDI_MAJOR, 254)); /* channel */ >+ CLASS_DEV_DESTROY(dahdi_class, MKDEV(DAHDI_MAJOR, 255)); /* pseudo */ >+ CLASS_DEV_DESTROY(dahdi_class, MKDEV(DAHDI_MAJOR, 0)); /* ctl */ >+ class_destroy(dahdi_class); >+ >+ unregister_chrdev(DAHDI_MAJOR, "dahdi"); >+ >+#ifdef CONFIG_PROC_FS >+ remove_proc_entry("dahdi", NULL); >+#endif >+ >+ module_printk(KERN_INFO, "Telephony Interface Unloaded\n"); >+ for (x = 0; x < DAHDI_TONE_ZONE_MAX; x++) { >+ if (tone_zones[x]) >+ kfree(tone_zones[x]); >+ } >+ >+#ifdef CONFIG_DAHDI_WATCHDOG >+ watchdog_cleanup(); >+#endif >+} >+ >+module_init(dahdi_init); >+module_exit(dahdi_cleanup); >diff -Naur dahdi-linux-2.2.0/drivers/dahdi/zaphfc/Makefile dahdi-linux-2.2.0_zaphfc/drivers/dahdi/zaphfc/Makefile >--- dahdi-linux-2.2.0/drivers/dahdi/zaphfc/Makefile 1970-01-01 01:00:00.000000000 +0100 >+++ dahdi-linux-2.2.0_zaphfc/drivers/dahdi/zaphfc/Makefile 2009-06-05 15:39:36.000000000 +0200 >@@ -0,0 +1,128 @@ >+ifeq ($(MAKELEVEL),0) >+PWD:=$(shell pwd) >+endif >+ >+ifndef MACHINE >+ MACHINE :=$(shell uname -m) >+endif >+# FIXME: this variable sets ARCH in the kernel Makefile. >+ARCH :=$(shell echo $(MACHINE) | sed -e s/i.86/i386/) >+BRISTUFFBASE = $(shell dirname `pwd`) >+ZAP = $(shell [ -f $(BRISTUFFBASE)/dahdi/kernel.h ] && echo "-I$(BRISTUFFBASE)/dahdi") >+EXTRA_CFLAGS+=$(ZAP) >+ >+# If you want to build for a kernel other than the current kernel, set KVERS >+ifndef KVERS >+KVERS:=$(shell uname -r) >+endif >+ifndef KSRC >+ ifneq (,$(wildcard /lib/modules/$(KVERS)/build)) >+ KSRC:=/lib/modules/$(KVERS)/build >+ else >+ KSRC_SEARCH_PATH:=/usr/src/linux-2.4 /usr/src/linux >+ KSRC:=$(shell for dir in $(KSRC_SEARCH_PATH); do if [ -d $$dir ]; then echo $$dir; break; fi; done) >+ endif >+endif >+KINCLUDES:=$(KSRC)/include >+ >+ifeq (2.6,$(shell echo $(KVERS) | cut -d. -f1-2)) >+ BUILDVER:=linux26 >+else >+ BUILDVER:=linux24 >+endif >+ >+MODULES:=zaphfc >+ >+MODULESO:=$(MODULES:%=%.o) >+MODULESKO:=$(MODULES:%=%.ko) >+ >+ifeq ($(BUILDVER),linux26) >+MODULESO+=$(SUBDIRS_EXTRA:%=%/) >+endif >+ >+#NOTE NOTE NOTE >+# >+# all variables set before the include of Makefile.kernel26 are needed by the 2.6 kernel module build process >+ >+ifneq ($(KBUILD_EXTMOD),) >+ >+include $(src)/Makefile.kernel26 >+ >+else >+ >+HOSTCC=gcc >+ >+INSTALL_PREFIX := /usr >+ >+CFLAGS+=-I. -O4 -g -fPIC -Wall >+ifneq (,$(findstring ppc,$(MACHINE))) >+ CFLAGS += -fsigned-char >+ KFLAGS += -msoft-float -fsigned-char >+endif >+ifneq (,$(findstring x86_64,$(MACHINE))) >+ CFLAGS += -m64 >+ KFLAGS += -mcmodel=kernel >+endif >+KFLAGS:=-I$(KINCLUDES) -O6 >+KFLAGS+=-DMODULE -D__KERNEL__ -DEXPORT_SYMTAB\ >+ -Wall -I. -Wstrict-prototypes -fomit-frame-pointer >+ifneq (,$(wildcard $(KINCLUDES)/linux/modversions.h)) >+ KFLAGS+=-DMODVERSIONS -include $(KINCLUDES)/linux/modversions.h >+endif >+ >+# >+# Features are now configured in zconfig.h >+# >+ >+KMAKE:= $(MAKE) -C $(KSRC) SUBDIRS=$(PWD) >+KMAKE_INST:= $(KMAKE) INSTALL_MOD_PATH=$(DESTDIR) INSTALL_MOD_DIR=misc modules_install >+ >+# sample makefile "trace print" >+#tracedummy=$(shell echo ====== GOT HERE ===== >&2; echo >&2) >+ >+SELINUX_ENABLED := $(shell [ -x /usr/sbin/sestatus ] && (/usr/sbin/sestatus | grep "SELinux status:" | grep -q "enabled")) >+ >+all: modules >+ >+ >+ifeq ($(BUILDVER),linux24) >+modules: $(MODULESO) >+else >+modules: >+ifeq (,$(wildcard $(KSRC)/.config)) >+ @echo "You do not appear to have the sources for the $(KVERS) kernel installed (under $(KSRC))."; exit 1 >+endif >+ $(MAKE) -C $(KSRC) SUBDIRS=$(PWD) HOTPLUG_FIRMWARE=$(HOTPLUG_FIRMWARE) EXTRA_CFLAGS=$(EXTRA_CFLAGS) modules >+endif >+ >+ >+install: all install-modules >+ @echo "###################################################" >+ @echo "###" >+ @echo "### zaphfc installed successfully." >+ @echo "###" >+ @echo "###################################################" >+ >+ >+# Specific to a kernel version: >+install-modules: modules >+ifeq ($(BUILDVER),linux26) >+ for x in $(MODULESKO); do \ >+ rm -f $(DESTDIR)/lib/modules/$(KVERS)/extra/$$x ; \ >+ done >+ $(KMAKE_INST) >+else >+ install -d $(DESTDIR)$(MODS_DIR) >+endif >+ [ `id -u` = 0 ] && /sbin/depmod -a $(KVERS) || : >+ >+clean: >+ $(MAKE) -C $(KSRC) SUBDIRS=$(PWD) clean >+ rm -f Module.symvers >+ >+.EXPORT_ALL_VARIABLES: >+ >+FORCE: >+ >+endif >+ >diff -Naur dahdi-linux-2.2.0/drivers/dahdi/zaphfc/Makefile.kernel26 dahdi-linux-2.2.0_zaphfc/drivers/dahdi/zaphfc/Makefile.kernel26 >--- dahdi-linux-2.2.0/drivers/dahdi/zaphfc/Makefile.kernel26 1970-01-01 01:00:00.000000000 +0100 >+++ dahdi-linux-2.2.0_zaphfc/drivers/dahdi/zaphfc/Makefile.kernel26 2008-01-02 10:25:31.000000000 +0100 >@@ -0,0 +1,8 @@ >+obj-m := $(MODULESO) >+ >+# fix typo present in CentOS and RHEL 2.6.9 kernels >+BAD_KERNELS_VERS := 22 34 34.0.1 34.0.2 >+BAD_KERNELS := $(foreach ver,$(BAD_KERNELS_VERS),2.6.9-$(ver).EL 2.6.9-$(ver).ELsmp) >+ifneq (,$(filter $(KVERS),$(BAD_KERNELS))) >+EXTRA_CFLAGS+=-Drw_lock_t=rwlock_t >+endif >diff -Naur dahdi-linux-2.2.0/drivers/dahdi/zaphfc/Makefile.new dahdi-linux-2.2.0_zaphfc/drivers/dahdi/zaphfc/Makefile.new >--- dahdi-linux-2.2.0/drivers/dahdi/zaphfc/Makefile.new 1970-01-01 01:00:00.000000000 +0100 >+++ dahdi-linux-2.2.0_zaphfc/drivers/dahdi/zaphfc/Makefile.new 2009-06-05 15:36:54.000000000 +0200 >@@ -0,0 +1,118 @@ >+KINCLUDES = /usr/src/linux/include >+BRISTUFFBASE = $(shell dirname `pwd`) >+ >+ZAP = $(shell [ -f $(BRISTUFFBASE)/dahdi/kernel.h ] && echo "-I$(BRISTUFFBASE)/dahdi") >+RTAI = $(shell [ -f /usr/realtime/include/rtai.h ] && echo "-DRTAITIMING -I/usr/realtime/include") >+ >+EXTRA_CFLAGS+=$(ZAP) >+ >+CFLAGS+=-I. $(ZAP) $(RTAI) -O2 -g -Wall -DBUILDING_TONEZONE >+CFLAGS+=$(shell if uname -m | grep -q ppc; then echo "-fsigned-char"; fi) >+ >+KFLAGS=-D__KERNEL__ -DMODULE -DEXPORT_SYMTAB -fomit-frame-pointer -O2 -Wall -I$(KINCLUDES) $(ZAP) $(RTAI) -Wall >+KFLAGS+=$(shell [ -f $(KINCLUDES)/linux/modversions.h ] && echo "-DMODVERSIONS -include $(KINCLUDES)/linux/modversions.h") >+KFLAGS+=$(shell if uname -m | grep -q ppc; then echo "-msoft-float -fsigned-char"; fi) >+ >+ >+BUILDVER=$(shell if uname -r | grep -q ^2.6; then echo "linux26"; else echo "linux24"; fi) >+ >+MODCONF=$(shell if [ -d $(INSTALL_PREFIX)/etc/modprobe.d ]; then echo "$(INSTALL_PREFIX)/etc/modprobe.d/dahdi"; elif [ -d $(INSTALL_PREFIX)/etc/modutils ]; then echo "$(INSTALL_PREFIX)/etc/modutils/dahdi"; elif [ -f $(INSTALL_PREFIX)/etc/modprobe.conf ]; then echo "$(INSTALL_PREFIX)/modprobe.conf"; elif [ -f $(INSTALL_PREFIX)/etc/modules.conf ]; then echo "$(INSTALL_PREFIX)/etc/modules.conf"; else echo $(INSTALL_PREFIX)/etc/conf.modules ; fi) >+ >+OBJS=zaphfc.o >+ >+MODULES=zaphfc >+ >+MODULESO=$(shell for x in $(MODULES); do echo "$$x.o "; done ) >+MODULESKO=$(shell for x in $(MODULES); do echo "$$x.ko "; done ) >+ >+PWD=$(shell pwd) >+ >+obj-m := $(MODULESO) >+ >+all: $(BUILDVER) >+ >+linux24: $(OBJS) >+ sync >+ >+ >+zaphfc.o: zaphfc.c zaphfc.h >+ $(CC) -c zaphfc.c $(KFLAGS) >+ >+clean: >+ rm -f $(OBJS) *.ko *.mod.c *.mod.o .*o.cmd *~ >+ rm -rf .tmp_versions >+ >+test: all >+ modprobe zaptel >+ insmod ./zaphfc.o >+ cat /proc/interrupts >+ sleep 1 >+ cat /proc/interrupts >+ rmmod zaphfc >+ rmmod zaptel >+ >+load: load$(BUILDVER) >+ >+loadNT: load$(BUILDVER)NT >+ >+load-debug: load$(BUILDVER)-debug >+ >+loadNT-debug: load$(BUILDVER)NT-debug >+ >+loadlinux24: all >+ modprobe zaptel >+ insmod ./zaphfc.o >+ ztcfg -v >+ >+loadlinux24-debug: all >+ modprobe zaptel >+ insmod ./zaphfc.o debug=1 >+ ztcfg -v >+ >+loadlinux26: linux26 >+ modprobe zaptel >+ insmod ./zaphfc.ko >+ ztcfg -v >+ >+loadlinux26-debug: linux26 >+ modprobe zaptel >+ insmod ./zaphfc.ko debug=1 >+ ztcfg -v >+ >+loadlinux24NT: all >+ modprobe zaptel >+ insmod ./zaphfc.o modes=1 >+ ztcfg -v >+ >+loadlinux24NT-debug: all >+ modprobe zaptel >+ insmod ./zaphfc.o modes=1 debug=1 >+ ztcfg -v >+ >+loadlinux26NT: linux26 >+ modprobe zaptel >+ insmod ./zaphfc.ko modes=1 >+ ztcfg -v >+ >+loadlinux26NT-debug: linux26 >+ modprobe zaptel >+ insmod ./zaphfc.ko modes=1 debug=1 >+ ztcfg -v >+ >+unload: >+ -rmmod zaphfc zaptel >+ >+zaphfc.ko: zaphfc.c zaphfc.h >+ >+linux26: >+ @if ! [ -d /usr/src/linux-2.6 ]; then echo "Link /usr/src/linux-2.6 to your kernel sources first!"; exit 1 ; fi >+ make -C /usr/src/linux-2.6 SUBDIRS=$(PWD) ZAP=$(ZAP) modules >+ >+install: install$(BUILDVER) >+ >+installlinux26: >+ install -D -m 644 zaphfc.ko $(INSTALL_PREFIX)/lib/modules/`uname -r`/misc/zaphfc.ko >+ >+installlinux24: >+ install -D -m 644 zaphfc.o $(INSTALL_PREFIX)/lib/modules/`uname -r`/misc/zaphfc.o >+ >diff -Naur dahdi-linux-2.2.0/drivers/dahdi/zaphfc/Module.markers dahdi-linux-2.2.0_zaphfc/drivers/dahdi/zaphfc/Module.markers >--- dahdi-linux-2.2.0/drivers/dahdi/zaphfc/Module.markers 1970-01-01 01:00:00.000000000 +0100 >+++ dahdi-linux-2.2.0_zaphfc/drivers/dahdi/zaphfc/Module.markers 2009-06-05 15:33:26.000000000 +0200 >@@ -0,0 +1,7 @@ >+core_marker_format vmlinux name %s format %s >+ext4_discard_blocks vmlinux dev %s blk %llu count %u >+ext4_sync_file vmlinux dev %s datasync %d ino %ld parent %ld >+ext4_sync_fs vmlinux dev %s wait %d >+jbd2_checkpoint vmlinux dev %s need_checkpoint %d >+jbd2_end_commit vmlinux dev %s transaction %d head %d >+jbd2_start_commit vmlinux dev %s transaction %d >diff -Naur dahdi-linux-2.2.0/drivers/dahdi/zaphfc/dahdi_config.h dahdi-linux-2.2.0_zaphfc/drivers/dahdi/zaphfc/dahdi_config.h >--- dahdi-linux-2.2.0/drivers/dahdi/zaphfc/dahdi_config.h 1970-01-01 01:00:00.000000000 +0100 >+++ dahdi-linux-2.2.0_zaphfc/drivers/dahdi/zaphfc/dahdi_config.h 2009-06-05 14:54:38.000000000 +0200 >@@ -0,0 +1,176 @@ >+/* >+ * DAHDI configuration options >+ * >+ */ >+ >+/* >+ * See http://www.asterisk.org for more information about >+ * the Asterisk project. Please do not directly contact >+ * any of the maintainers of this project for assistance; >+ * the project provides a web site, mailing lists and IRC >+ * channels for your use. >+ * >+ * This program is free software, distributed under the terms of >+ * the GNU General Public License Version 2 as published by the >+ * Free Software Foundation. See the LICENSE file included with >+ * this program for more details. >+ */ >+ >+#ifndef _DAHDI_CONFIG_H >+#define _DAHDI_CONFIG_H >+ >+#ifdef __KERNEL__ >+#include <linux/version.h> >+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18) >+#include <linux/config.h> >+#else >+#include <linux/autoconf.h> >+#endif >+#endif >+ >+/* DAHDI compile time options */ >+ >+/* >+ * Uncomment if you have a European phone, or any other phone with a >+ * short flash time. >+ * This will stop the flash being mis-detected as a pulse dial "1" on >+ * phones with short flashes >+ */ >+/* #define SHORT_FLASH_TIME */ >+ >+/* >+ * Uncomment to disable calibration and/or DC/DC converter tests >+ * (not generally recommended) >+ */ >+/* #define NO_CALIBRATION */ >+/* #define NO_DCDC */ >+ >+/* >+ * Boost ring voltage (Higher ring voltage, takes more power) >+ * Note: this only affects the wcfxsusb and wcusb drivers; all other >+ * drivers have a 'boostringer' module parameter. >+ */ >+/* #define BOOST_RINGER */ >+ >+/* >+ * Define CONFIG_CALC_XLAW if you have a small number of channels and/or >+ * a small level 2 cache, to optimize for few channels >+ * >+ */ >+/* #define CONFIG_CALC_XLAW */ >+ >+/* >+ * Define if you want MMX optimizations in DAHDI >+ * >+ * Note: CONFIG_DAHDI_MMX is generally incompatible with AMD >+ * processors and can cause system instability! >+ * >+ */ >+/* #define CONFIG_DAHDI_MMX */ >+ >+/* We now use the linux kernel config to detect which options to use */ >+/* You can still override them below */ >+#if defined(CONFIG_HDLC) || defined(CONFIG_HDLC_MODULE) >+#define DAHDI_HDLC_TYPE_TRANS >+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,3) >+#define HDLC_MAINTAINERS_ARE_MORE_STUPID_THAN_I_THOUGHT >+#endif >+#endif >+ >+#ifdef CONFIG_PPP >+#define CONFIG_DAHDI_PPP >+#endif >+ >+/* >+ * Uncomment CONFIG_DAHDI_NET to enable SyncPPP, CiscoHDLC, and Frame Relay >+ * support. >+ */ >+/* #define CONFIG_DAHDI_NET */ >+ >+/* >+ * Uncomment CONFIG_OLD_HDLC_API if your are compiling with CONFIG_DAHDI_NET >+ * defined and you are using the old kernel HDLC interface (or if you get >+ * an error about ETH_P_HDLC while compiling). >+ */ >+/* #define CONFIG_OLD_HDLC_API */ >+ >+/* >+ * Uncomment for Generic PPP support (i.e. ZapRAS) >+ */ >+/* #define CONFIG_DAHDI_PPP */ >+/* >+ * Uncomment to enable "watchdog" to monitor if interfaces >+ * stop taking interrupts or otherwise misbehave >+ */ >+/* #define CONFIG_DAHDI_WATCHDOG */ >+ >+/* >+ * Uncomment the following to include extra debugging output. >+ */ >+/* #define CONFIG_DAHDI_DEBUG */ >+ >+/* >+ * Uncomment for Non-standard FXS groundstart start state (A=Low, B=Low) >+ * particularly for CAC channel bank groundstart FXO ports. >+ */ >+/* #define CONFIG_CAC_GROUNDSTART */ >+ >+/* >+ * Uncomment if you happen have an early TDM400P Rev H which >+ * sometimes forgets its PCI ID to have wcfxs match essentially all >+ * subvendor ID's >+ */ >+/* #define TDM_REVH_MATCHALL */ >+ >+/* >+ * Uncomment the following if you want to support E&M trunks being >+ * able to "flash" after going off-hook (dont ask why, just nod :-) ). >+ * >+ * NOTE: *DO NOT* Enable "EMFLASH" and "EMPULSE" at the same time!! >+ * >+ */ >+/* #define EMFLASH */ >+ >+/* >+ * Uncomment the following if you want to support E&M trunks being >+ * able to recognize Dial Pulse digits. This can validly be enabled >+ * so that either Dial Pulse or DTMF/MF tones will be recognized, but >+ * the drawback is that the ONHOOK will take an extra {rxwinktime} >+ * to be recognized. >+ * >+ * NOTE: *DO NOT* Enable "EMFLASH" and "EMPULSE" at the same time!! >+ * >+ */ >+/* #define EMPULSE */ >+ >+/* >+ * Comment out the following if you dont want events to indicate the >+ * beginning of an incoming ring. Most non-Asterisk applications will >+ * want this commented out. >+ */ >+#define RINGBEGIN >+ >+/* >+ * Uncomment the following if you need to support FXS Flash events. >+ * Most applications will want this commented out. >+ */ >+/* #define FXSFLASH */ >+ >+/* >+ * Enable sync_tick() calls. Allows low-level drivers to synchronize >+ * their internal clocks to the DAHDI master clock. >+ */ >+#define DAHDI_SYNC_TICK >+ >+/* >+ * Skip processing PCM if low-level driver won't use it anyway >+ */ >+/* #define OPTIMIZE_CHANMUTE */ >+ >+/* >+ * Uncomment the following for BRI D channels >+ * >+ */ >+#define CONFIG_DAHDI_BRI_DCHANS >+ >+#endif >diff -Naur dahdi-linux-2.2.0/drivers/dahdi/zaphfc/fasthdlc.h dahdi-linux-2.2.0_zaphfc/drivers/dahdi/zaphfc/fasthdlc.h >--- dahdi-linux-2.2.0/drivers/dahdi/zaphfc/fasthdlc.h 1970-01-01 01:00:00.000000000 +0100 >+++ dahdi-linux-2.2.0_zaphfc/drivers/dahdi/zaphfc/fasthdlc.h 2009-06-05 12:56:39.000000000 +0200 >@@ -0,0 +1,507 @@ >+/* >+ * Mark's Mythical Table-based raw HDLC implementation >+ * >+ * This is designed to be a very fast, but memory efficient >+ * implementation of standard HDLC protocol. >+ * >+ * This table based HDLC technology is PATENT PENDING, but will always be >+ * remain freely distributable under the terms of the GPL version 2. >+ * >+ * For non-GPL licensing, please contact Mark Spencer at >+ * the below e-mail address. >+ * >+ * Copyright (C) 2001-2008, Digium, Inc. >+ * >+ * Written by Mark Spencer <markster@digium.com> >+ * >+ */ >+ >+/* >+ * See http://www.asterisk.org for more information about >+ * the Asterisk project. Please do not directly contact >+ * any of the maintainers of this project for assistance; >+ * the project provides a web site, mailing lists and IRC >+ * channels for your use. >+ * >+ * This program is free software, distributed under the terms of >+ * the GNU General Public License Version 2 as published by the >+ * Free Software Foundation. See the LICENSE file included with >+ * this program for more details. >+ */ >+ >+#ifndef _FASTHDLC_H >+#define _FASTHDLC_H >+ >+enum fasthdlc_mode { >+ FASTHDLC_MODE_64 = 0, >+ FASTHDLC_MODE_56, >+}; >+ >+struct fasthdlc_state { >+ int state; /* What state we are in */ >+ unsigned int data; /* Our current data queue */ >+ int bits; /* Number of bits in our data queue */ >+ int ones; /* Number of ones */ >+ enum fasthdlc_mode mode; >+}; >+ >+#ifdef FAST_HDLC_NEED_TABLES >+#define RETURN_COMPLETE_FLAG (0x1000) >+#define RETURN_DISCARD_FLAG (0x2000) >+#define RETURN_EMPTY_FLAG (0x4000) >+ >+/* Unlike most HDLC implementations, we define only two states, >+ when we are in a valid frame, and when we are searching for >+ a frame header */ >+ >+#define FRAME_SEARCH 0 >+#define PROCESS_FRAME 1 >+ >+/* >+ >+ HDLC Search State table -- Look for a frame header. The return value >+ of this table is as follows: >+ >+ |---8---|---7---|---6---|---5---|---4---|---3---|---2---|---1---| >+ | Z E R O E S | Next | Bits Consumed | >+ |-------|-------|-------|-------|-------|-------|-------|-------| >+ >+ The indexes for this table are the state (0 or 1) and the next 8 >+ bits of the stream. >+ >+ Note that this table is only used for state 0 and 1. >+ >+ The user should discard the top "bits consumed" bits of data before >+ the next call. "Next state" represents the actual next state for >+ decoding. >+ >+*/ >+static unsigned char hdlc_search[256]; >+ >+/* >+ HDLC Data Table >+ >+ The indexes to this table are the number of one's we've seen so far (0-5) and >+ the next 10 bits of input (which is enough to guarantee us that we >+ will retrieve at least one byte of data (or frame or whatever). >+ >+ The format for the return value is: >+ >+ Bits 15: Status (1=Valid Data, 0=Control Frame (see bits 7-0 for type)) >+ Bits 14-12: Number of ones in a row, so far >+ Bits 11-8: The number of bits consumed (0-10) >+ Bits 7-0: The return data (if appropriate) >+ >+ The next state is simply bit #15 >+ >+*/ >+ >+#define CONTROL_COMPLETE 1 >+#define CONTROL_ABORT 2 >+ >+#define STATUS_MASK (1 << 15) >+#define STATUS_VALID (1 << 15) >+#define STATUS_CONTROL (0 << 15) >+#define STATE_MASK (1 << 15) >+#define ONES_MASK (7 << 12) >+#define DATA_MASK (0xff) >+ >+static unsigned short hdlc_frame[6][1024]; >+ >+static unsigned int minbits[2] = { 8, 10 }; >+ >+/* >+ Last, but not least, we have the encoder table. It takes >+ as its indices the number of ones so far and a byte of data >+ and returns an int composed of the following fields: >+ >+ Bots 31-22: Actual Data >+ Bits 21-16: Unused >+ Bits 15-8: Number of ones >+ Bits 3-0: Number of bits of output (13-4) to use >+ >+ Of course we could optimize by reducing to two tables, but I don't >+ really think it's worth the trouble at this point. >+ */ >+ >+static unsigned int hdlc_encode[6][256]; >+ >+static inline char hdlc_search_precalc(unsigned char c) >+{ >+ int x, p=0; >+ /* Look for a flag. If this isn't a flag, >+ line us up for the next possible shot at >+ a flag */ >+ >+ /* If it's a flag, we go to state 1, and have >+ consumed 8 bits */ >+ if (c == 0x7e) >+ return 0x10 | 8; >+ >+ /* If it's an abort, we stay in the same state >+ and have consumed 8 bits */ >+ if (c == 0x7f) >+ return 0x00 | 8; >+ >+ /* If it's all 1's, we state in the same state and >+ have consumed 8 bits */ >+ if (c == 0xff) >+ return 0x00 | 8; >+ >+ /* If we get here, we must have at least one zero in us >+ but we're not the flag. So, start at the end (LSB) and >+ work our way to the top (MSB) looking for a zero. The >+ position of that 0 is most optimistic start of a real >+ frame header */ >+ x=1; >+ p=7; >+ while(p && (c & x)) { >+ x <<= 1; >+ p--; >+ } >+ return p; >+} >+ >+#ifdef DEBUG_PRECALC >+static inline void hdlc_search_print(char c, char r) >+{ >+ int x=0x80; >+ while(x) { >+ printf("%s", c & x ? "1" : "0"); >+ x >>= 1; >+ } >+ printf(" => State %d, Consume %d\n", (r & 0x10) >> 4, r & 0xf); >+} >+#endif >+ >+#define HFP(status, ones, bits, data) \ >+ ((status) | ((ones) << 12) | ((bits) << 8) | (data)) >+ >+static inline unsigned int hdlc_frame_precalc(unsigned char x, unsigned short c) >+{ >+ /* Assume we have seen 'x' one's so far, and have read the >+ bottom 10 bytes of c (MSB first). Now, we HAVE to have >+ a byte of data or a frame or something. We are assumed >+ to be at the beginning of a byte of data or something */ >+ unsigned char ones = x; >+ unsigned char data=0; >+ int bits=0; >+ int consumed=0; >+ while(bits < 8) { >+ data >>=1; >+ consumed++; >+ if (ones == 5) { >+ /* We've seen five ones */ >+ if (c & 0x0200) { >+ /* Another one -- Some sort of signal frame */ >+ if ((!(c & 0x0100)) && (bits == 6)) { >+ /* This is a frame terminator (10) */ >+ return HFP(0, >+ 0, 8, CONTROL_COMPLETE); >+ } else { >+ /* Yuck! It's something else... >+ Abort this entire frame, and >+ start looking for a good frame */ >+ return HFP(0, >+ 0, consumed+1, CONTROL_ABORT); >+ } >+ } else { >+ /* It's an inserted zero, just skip it */ >+ ones = 0; >+ data <<= 1; >+ } >+ } else { >+ /* Add it to our bit list, LSB to >+ MSB */ >+ if (c & 0x0200) { >+ data |= 0x80; >+ ones++; >+ } else >+ ones=0; >+ bits++; >+ } >+ c <<= 1; >+ } >+ /* Consume the extra 0 now rather than later. */ >+ if (ones == 5) { >+ ones = 0; >+ consumed++; >+ } >+ return HFP(STATUS_VALID, ones, consumed, data); >+} >+ >+#ifdef DEBUG_PRECALC >+ >+static inline void hdlc_frame_print(unsigned char x, unsigned short c, unsigned int res) >+{ >+ int z=0x0200; >+ char *status[] = { >+ "Control", >+ "Valid", >+ }; >+ printf("%d one's then ", x); >+ while(z) { >+ printf("%s", c & z ? "1" : "0"); >+ z >>= 1; >+ } >+ printf(" => Status %s, ", res & STATUS_MASK ? "1" : "0"); >+ printf("Consumed: %d, ", (res & 0x0f00) >> 8); >+ printf("Status: %s, ", status[(res & STATUS_MASK) >> 15]); >+ printf("Ones: %d, ", (res & ONES_MASK) >> 12); >+ printf("Data: %02x\n", res & 0xff); >+ >+} >+ >+#endif >+ >+static inline unsigned int hdlc_encode_precalc(int x, unsigned char y) >+{ >+ int bits=0; >+ int ones=x; >+ unsigned short data=0; >+ int z; >+ for (z=0;z<8;z++) { >+ /* Zero-stuff if needed */ >+ if (ones == 5) { >+ /* Stuff a zero */ >+ data <<= 1; >+ ones=0; >+ bits++; >+ } >+ if (y & 0x01) { >+ /* There's a one */ >+ data <<= 1; >+ data |= 0x1; >+ ones++; >+ bits++; >+ } else { >+ data <<= 1; >+ ones = 0; >+ bits++; >+ } >+ y >>= 1; >+ } >+ /* Special case -- Stuff the zero at the end if appropriate */ >+ if (ones == 5) { >+ /* Stuff a zero */ >+ data <<= 1; >+ ones=0; >+ bits++; >+ } >+ data <<= (10-bits); >+ return (data << 22) | (ones << 8) | (bits); >+} >+ >+#ifdef DEBUG_PRECALC >+static inline void hdlc_encode_print(int x, unsigned char y, unsigned int val) >+{ >+ unsigned int z; >+ unsigned short c; >+ printf("%d ones, %02x (", x, y); >+ z = 0x80; >+ while(z) { >+ printf("%s", y & z ? "1" : "0"); >+ z >>= 1; >+ } >+ printf(") encoded as "); >+ z = 1 << 31; >+ for (x=0;x<(val & 0xf);x++) { >+ printf("%s", val & z ? "1" : "0"); >+ z >>= 1; >+ } >+ printf(" with %d ones now, %d bits in len\n", (val & 0xf00) >> 8, val & 0xf); >+ >+ >+} >+#endif >+ >+static inline void fasthdlc_precalc(void) >+{ >+ int x; >+ int y; >+ /* First the easy part -- the searching */ >+ for (x=0;x<256;x++) { >+ hdlc_search[x] = hdlc_search_precalc(x); >+#ifdef DEBUG_PRECALC >+ hdlc_search_print(x, hdlc_search[x]); >+#endif >+ } >+ /* Now the hard part -- the frame tables */ >+ for (x=0;x<6;x++) { >+ /* Given the # of preceeding ones, process the next >+ byte of input (up to 10 actual bits) */ >+ for (y=0;y<1024;y++) { >+ hdlc_frame[x][y] = hdlc_frame_precalc(x, y); >+#ifdef DEBUG_PRECALC >+ hdlc_frame_print(x, y, hdlc_frame[x][y]); >+#endif >+ } >+ } >+ /* Now another not-so-hard part, the encoding table */ >+ for (x=0;x<6;x++) { >+ for (y=0;y<256;y++) { >+ hdlc_encode[x][y] = hdlc_encode_precalc(x,y); >+#ifdef DEBUG_PRECALC >+ hdlc_encode_print(x,y,hdlc_encode[x][y]); >+#endif >+ } >+ } >+} >+ >+ >+static inline void fasthdlc_init(struct fasthdlc_state *h, enum fasthdlc_mode mode) >+{ >+ /* Initializes all states appropriately */ >+ h->mode = mode; >+ h->state = 0; >+ h->bits = 0; >+ h->data = 0; >+ h->ones = 0; >+ >+} >+ >+static inline int fasthdlc_tx_load_nocheck(struct fasthdlc_state *h, unsigned char c) >+{ >+ unsigned int res; >+ res = hdlc_encode[h->ones][c]; >+ h->ones = (res & 0xf00) >> 8; >+ h->data |= (res & 0xffc00000) >> h->bits; >+ h->bits += (res & 0xf); >+ return 0; >+} >+ >+static inline int fasthdlc_tx_load(struct fasthdlc_state *h, unsigned char c) >+{ >+ /* Gotta have at least 10 bits left */ >+ if (h->bits > 22) >+ return -1; >+ return fasthdlc_tx_load_nocheck(h, c); >+} >+ >+static inline int fasthdlc_tx_frame_nocheck(struct fasthdlc_state *h) >+{ >+ h->ones = 0; >+ h->data |= ( 0x7e000000 >> h->bits); >+ h->bits += 8; >+ return 0; >+} >+ >+static inline int fasthdlc_tx_frame(struct fasthdlc_state *h) >+{ >+ if (h->bits > 24) >+ return -1; >+ return fasthdlc_tx_frame_nocheck(h); >+} >+ >+static inline int fasthdlc_tx_need_data(struct fasthdlc_state *h) >+{ >+ if (h->mode == FASTHDLC_MODE_56) { >+ if (h->bits < 7) >+ return 1; >+ } else { >+ if (h->bits < 8) >+ return 1; >+ } >+ >+ return 0; >+} >+ >+static inline int fasthdlc_tx_run_nocheck(struct fasthdlc_state *h) >+{ >+ unsigned char b; >+ if (h->mode == FASTHDLC_MODE_56) { >+ b = h->data >> 25; >+ h->bits -= 7; >+ h->data <<= 7; >+ >+ return ((b & 0x7f) << 1) | 1; >+ } else { >+ b = h->data >> 24; >+ h->bits -= 8; >+ h->data <<= 8; >+ >+ return b; >+ } >+ >+} >+ >+static inline int fasthdlc_tx_run(struct fasthdlc_state *h) >+{ >+ if (h->bits < 8) >+ return -1; >+ return fasthdlc_tx_run_nocheck(h); >+} >+ >+static inline int fasthdlc_rx_load_nocheck(struct fasthdlc_state *h, unsigned char b) >+{ >+ if (h->mode == FASTHDLC_MODE_56) { >+ h->data |= (b >> 1) << (25-h->bits); >+ h->bits += 7; >+ } else { >+ /* Put the new byte in the data stream */ >+ h->data |= b << (24-h->bits); >+ h->bits += 8; >+ } >+ return 0; >+} >+ >+static inline int fasthdlc_rx_load(struct fasthdlc_state *h, unsigned char b) >+{ >+ /* Make sure we have enough space */ >+ if (h->bits > 24) >+ return -1; >+ return fasthdlc_rx_load_nocheck(h, b); >+} >+ >+/* >+ Returns a data character if available, logical OR'd with >+ zero or more of RETURN_COMPLETE_FLAG, RETURN_DISCARD_FLAG, >+ and RETURN_EMPTY_FLAG, signifying a complete frame, a >+ discarded frame, or there is nothing to return. >+ */ >+ >+static inline int fasthdlc_rx_run(struct fasthdlc_state *h) >+{ >+ unsigned short next; >+ int retval=RETURN_EMPTY_FLAG; >+ while ((h->bits >= minbits[h->state]) && (retval == RETURN_EMPTY_FLAG)) { >+ /* Run until we can no longer be assured that we will >+ have enough bits to continue */ >+ switch(h->state) { >+ case FRAME_SEARCH: >+ /* Look for an HDLC frame, keying from >+ the top byte. */ >+ next = hdlc_search[h->data >> 24]; >+ h->bits -= next & 0x0f; >+ h->data <<= next & 0x0f; >+ h->state = next >> 4; >+ h->ones = 0; >+ break; >+ case PROCESS_FRAME: >+ /* Process as much as the next ten bits */ >+ next = hdlc_frame[h->ones][h->data >> 22]; >+ h->bits -= ((next & 0x0f00) >> 8); >+ h->data <<= ((next & 0x0f00) >> 8); >+ h->state = (next & STATE_MASK) >> 15; >+ h->ones = (next & ONES_MASK) >> 12; >+ switch(next & STATUS_MASK) { >+ case STATUS_CONTROL: >+ if (next & CONTROL_COMPLETE) { >+ /* A complete, valid frame received */ >+ retval = (RETURN_COMPLETE_FLAG); >+ /* Stay in this state */ >+ h->state = 1; >+ } else { >+ /* An abort (either out of sync of explicit) */ >+ retval = (RETURN_DISCARD_FLAG); >+ } >+ break; >+ case STATUS_VALID: >+ retval = (next & DATA_MASK); >+ } >+ } >+ } >+ return retval; >+} >+#endif /* FAST_HDLC_NEED_TABLES */ >+#endif >diff -Naur dahdi-linux-2.2.0/drivers/dahdi/zaphfc/kernel.h dahdi-linux-2.2.0_zaphfc/drivers/dahdi/zaphfc/kernel.h >--- dahdi-linux-2.2.0/drivers/dahdi/zaphfc/kernel.h 1970-01-01 01:00:00.000000000 +0100 >+++ dahdi-linux-2.2.0_zaphfc/drivers/dahdi/zaphfc/kernel.h 2009-06-05 15:52:11.000000000 +0200 >@@ -0,0 +1,1180 @@ >+/* >+ * DAHDI Telephony Interface >+ * >+ * Written by Mark Spencer <markster@digium.com> >+ * Based on previous works, designs, and architectures conceived and >+ * written by Jim Dixon <jim@lambdatel.com>. >+ * >+ * Copyright (C) 2001 Jim Dixon / Zapata Telephony. >+ * Copyright (C) 2001 - 2008 Digium, Inc. >+ * >+ * All rights reserved. >+ * >+ */ >+ >+/* >+ * See http://www.asterisk.org for more information about >+ * the Asterisk project. Please do not directly contact >+ * any of the maintainers of this project for assistance; >+ * the project provides a web site, mailing lists and IRC >+ * channels for your use. >+ * >+ * This program is free software, distributed under the terms of >+ * the GNU General Public License Version 2 as published by the >+ * Free Software Foundation. See the LICENSE file included with >+ * this program for more details. >+ */ >+ >+/*! >+ * \file >+ * \brief DAHDI kernel interface definitions >+ */ >+ >+#ifndef _DAHDI_KERNEL_H >+#define _DAHDI_KERNEL_H >+ >+#include "user.h" >+#include "fasthdlc.h" >+ >+#include "dahdi_config.h" >+#include <linux/version.h> >+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18) >+#include <linux/config.h> >+#endif >+#include <linux/fs.h> >+#include <linux/ioctl.h> >+ >+#ifdef CONFIG_DAHDI_NET >+#include <linux/hdlc.h> >+#endif >+ >+#ifdef CONFIG_DAHDI_PPP >+#include <linux/ppp_channel.h> >+#include <linux/skbuff.h> >+#include <linux/interrupt.h> >+#endif >+ >+#include <linux/poll.h> >+ >+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,10) >+#define dahdi_pci_module pci_register_driver >+#else >+#define dahdi_pci_module pci_module_init >+#endif >+ >+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,19) >+#define DAHDI_IRQ_HANDLER(a) static irqreturn_t a(int irq, void *dev_id) >+#else >+#define DAHDI_IRQ_HANDLER(a) static irqreturn_t a(int irq, void *dev_id, struct pt_regs *regs) >+#endif >+ >+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,18) >+#define DAHDI_IRQ_SHARED IRQF_SHARED >+#define DAHDI_IRQ_DISABLED IRQF_DISABLED >+#define DAHDI_IRQ_SHARED_DISABLED IRQF_SHARED | IRQF_DISABLED >+#else >+#define DAHDI_IRQ_SHARED SA_SHIRQ >+#define DAHDI_IRQ_DISABLED SA_INTERRUPT >+#define DAHDI_IRQ_SHARED_DISABLED SA_SHIRQ | SA_INTERRUPT >+#endif >+ >+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,16) >+#ifndef dev_notice >+#define dev_notice(dev, format, arg...) \ >+ dev_printk(KERN_NOTICE , dev , format , ## arg) >+#endif >+#endif >+ >+/*! Default chunk size for conferences and such -- static right now, might make >+ variable sometime. 8 samples = 1 ms = most frequent service interval possible >+ for a USB device */ >+#define DAHDI_CHUNKSIZE 8 >+#define DAHDI_MIN_CHUNKSIZE DAHDI_CHUNKSIZE >+#define DAHDI_DEFAULT_CHUNKSIZE DAHDI_CHUNKSIZE >+#define DAHDI_MAX_CHUNKSIZE DAHDI_CHUNKSIZE >+#define DAHDI_CB_SIZE 2 >+ >+#define RING_DEBOUNCE_TIME 2000 /*!< 2000 ms ring debounce time */ >+ >+typedef struct >+{ >+ int32_t gain; >+ int32_t a1; >+ int32_t a2; >+ int32_t b1; >+ int32_t b2; >+ >+ int32_t z1; >+ int32_t z2; >+} biquad2_state_t; >+ >+typedef struct >+{ >+ biquad2_state_t notch; >+ int notch_level; >+ int channel_level; >+ int tone_present; >+ int tone_cycle_duration; >+ int good_cycles; >+ int hit; >+} echo_can_disable_detector_state_t; >+ >+struct sf_detect_state { >+ long x1; >+ long x2; >+ long y1; >+ long y2; >+ long e1; >+ long e2; >+ int samps; >+ int lastdetect; >+}; >+ >+struct dahdi_tone_state { >+ int v1_1; >+ int v2_1; >+ int v3_1; >+ int v1_2; >+ int v2_2; >+ int v3_2; >+ int modulate; >+}; >+ >+/*! \brief Conference queue structure */ >+struct confq { >+ u_char buffer[DAHDI_CHUNKSIZE * DAHDI_CB_SIZE]; >+ u_char *buf[DAHDI_CB_SIZE]; >+ int inbuf; >+ int outbuf; >+}; >+ >+struct dahdi_chan; >+struct dahdi_echocan_state; >+ >+/*! Features a DAHDI echo canceler (software or hardware) can provide to the DAHDI core. */ >+struct dahdi_echocan_features { >+ >+ /*! Able to detect CED tone (2100 Hz with phase reversals) in the transmit direction. >+ * If the echocan can detect this tone, it may report it it as an event (see >+ * the events.CED_tx_detected field of dahdi_echocan_state), and if it will automatically >+ * disable itself or its non-linear processor, then the NLP_automatic feature flag should also >+ * be set so that the DAHDI core doesn't bother trying to do so. >+ */ >+ u32 CED_tx_detect:1; >+ >+ /*! Able to detect CED tone (2100 Hz with phase reversals) in the receive direction. >+ * If the echocan can detect this tone, it may report it it as an event (see >+ * the events.CED_rx_detected field of dahdi_echocan_state), and if it will automatically >+ * disable itself or its non-linear processor, then the NLP_automatic flag feature should also >+ * be set so that the DAHDI core doesn't bother trying to do so. >+ */ >+ u32 CED_rx_detect:1; >+ >+ /*! Able to detect CNG tone (1100 Hz) in the transmit direction. */ >+ u32 CNG_tx_detect:1; >+ >+ /*! Able to detect CNG tone (1100 Hz) in the receive direction. */ >+ u32 CNG_rx_detect:1; >+ >+ /*! If the echocan's NLP can be enabled and disabled without requiring destruction >+ * and recreation of the state structure, this feature flag should be set and the >+ * echocan_NLP_toggle field of the dahdi_echocan_ops structure should be filled with a >+ * pointer to the function to perform that operation. >+ */ >+ u32 NLP_toggle:1; >+ >+ /*! If the echocan will automatically disable itself (or even just its NLP) based on >+ * detection of a CED tone in either direction, this feature flag should be set (along >+ * with the tone detection feature flags). >+ */ >+ u32 NLP_automatic:1; >+}; >+ >+/*! Operations (methods) that can be performed on a DAHDI echo canceler instance (state >+ * structure) after it has been created, by either a software or hardware echo canceller. >+ * The echo canceler must populate the owner field of the dahdi_echocan_state structure >+ * with a pointer to the relevant operations structure for that instance. >+ */ >+struct dahdi_echocan_ops { >+ >+ /*! The name of the echocan that created this structure. */ >+ const char *name; >+ >+ /*! \brief Free an echocan state structure. >+ * \param[in,out] ec Pointer to the state structure to free. >+ * >+ * \return Nothing. >+ */ >+ void (*echocan_free)(struct dahdi_chan *chan, struct dahdi_echocan_state *ec); >+ >+ /*! \brief Process an array of audio samples through the echocan. >+ * \param[in,out] ec Pointer to the state structure. >+ * \param[in,out] isig The receive direction data (will be modified). >+ * \param[in] iref The transmit direction data. >+ * \param[in] size The number of elements in the isig and iref arrays. >+ * >+ * Note: This function can also return events in the events field of the >+ * dahdi_echocan_state structure. If it can do so, then the echocan does >+ * not need to provide the echocan_events function. >+ * >+ * \return Nothing. >+ */ >+ void (*echocan_process)(struct dahdi_echocan_state *ec, short *isig, const short *iref, u32 size); >+ >+ /*! \brief Retrieve events from the echocan. >+ * \param[in,out] ec Pointer to the state structure. >+ * >+ * >+ * If any events have occurred, the events field of the dahdi_echocan_state >+ * structure should be updated to include them. >+ * >+ * \return Nothing. >+ */ >+ void (*echocan_events)(struct dahdi_echocan_state *ec); >+ >+ /*! \brief Feed a sample (and its position) for echocan training. >+ * \param[in,out] ec Pointer to the state structure. >+ * \param[in] pos The tap position to be 'trained'. >+ * \param[in] val The receive direction sample for the specified tap position. >+ * >+ * \retval Zero if training should continue. >+ * \retval Non-zero if training is complete. >+ */ >+ int (*echocan_traintap)(struct dahdi_echocan_state *ec, int pos, short val); >+ >+ /*! \brief Enable or disable non-linear processing (NLP) in the echocan. >+ * \param[in,out] ec Pointer to the state structure. >+ * \param[in] enable Zero to disable, non-zero to enable. >+ * >+ * \return Nothing. >+ */ >+ void (*echocan_NLP_toggle)(struct dahdi_echocan_state *ec, unsigned int enable); >+}; >+ >+/*! A factory for creating instances of software echo cancelers to be used on DAHDI channels. */ >+struct dahdi_echocan_factory { >+ >+ /*! The name of the factory. */ >+ const char *name; >+ >+ /*! Pointer to the module that owns this factory; the module's reference count will be >+ * incremented/decremented by the DAHDI core as needed. >+ */ >+ struct module *owner; >+ >+ /*! \brief Function to create an instance of the echocan. >+ * \param[in] ecp Structure defining parameters to be used for the instance creation. >+ * \param[in] p Pointer to the beginning of an (optional) array of user-defined parameters. >+ * \param[out] ec Pointer to the state structure that is created, if any. >+ * >+ * \retval Zero on success. >+ * \retval Non-zero on failure (return value will be returned to userspace so it should be a >+ * standard error number). >+ */ >+ int (*echocan_create)(struct dahdi_chan *chan, struct dahdi_echocanparams *ecp, >+ struct dahdi_echocanparam *p, struct dahdi_echocan_state **ec); >+}; >+ >+/*! \brief Register an echo canceler factory with the DAHDI core. >+ * \param[in] ec Pointer to the dahdi_echocan_factory structure to be registered. >+ * >+ * \retval Zero on success. >+ * \retval Non-zero on failure (return value will be a standard error number). >+ */ >+int dahdi_register_echocan_factory(const struct dahdi_echocan_factory *ec); >+ >+/*! \brief Unregister a previously-registered echo canceler factory from the DAHDI core. >+ * \param[in] ec Pointer to the dahdi_echocan_factory structure to be unregistered. >+ * >+ * \return Nothing. >+ */ >+void dahdi_unregister_echocan_factory(const struct dahdi_echocan_factory *ec); >+ >+enum dahdi_echocan_mode { >+ __ECHO_MODE_MUTE = 1 << 8, >+ ECHO_MODE_IDLE = 0, >+ ECHO_MODE_PRETRAINING = 1 | __ECHO_MODE_MUTE, >+ ECHO_MODE_STARTTRAINING = 2 | __ECHO_MODE_MUTE, >+ ECHO_MODE_AWAITINGECHO = 3 | __ECHO_MODE_MUTE, >+ ECHO_MODE_TRAINING = 4 | __ECHO_MODE_MUTE, >+ ECHO_MODE_ACTIVE = 5, >+ ECHO_MODE_FAX = 6, >+}; >+ >+/*! An instance of a DAHDI echo canceler (software or hardware). */ >+struct dahdi_echocan_state { >+ >+ /*! Pointer to a dahdi_echocan_ops structure of operations that can be >+ * performed on this instance. >+ */ >+ const struct dahdi_echocan_ops *ops; >+ >+ /*! State data used by the DAHDI core's CED detector for the transmit >+ * direction, if needed. >+ */ >+ echo_can_disable_detector_state_t txecdis; >+ >+ /*! State data used by the DAHDI core's CED detector for the receive >+ * direction, if needed. >+ */ >+ echo_can_disable_detector_state_t rxecdis; >+ >+ /*! Features offered by the echo canceler that provided this instance. */ >+ struct dahdi_echocan_features features; >+ >+ struct { >+ /*! The mode the echocan is currently in. */ >+ enum dahdi_echocan_mode mode; >+ >+ /*! The last tap position that was fed to the echocan's training function. */ >+ u32 last_train_tap; >+ >+ /*! How many samples to wait before beginning the training operation. */ >+ u32 pretrain_timer; >+ } status; >+ >+ /*! This structure contains event flags, allowing the echocan to report >+ * events that occurred as it processed the transmit and receive streams >+ * of samples. Each call to the echocan_process operation for this >+ * instance may report events, so the structure should be cleared before >+ * calling that operation. >+ */ >+ union dahdi_echocan_events { >+ u32 all; >+ struct { >+ /*! CED tone was detected in the transmit direction. If the >+ * echocan automatically disables its NLP when this occurs, >+ * it must also signal the NLP_auto_disabled event during the *same* >+ * call to echocan_process that reports the CED detection. >+ */ >+ u32 CED_tx_detected:1; >+ >+ /*! CED tone was detected in the receive direction. If the >+ * echocan automatically disables its NLP when this occurs, >+ * it must also signal the NLP_auto_disabled event during the *same* >+ * call to echocan_process that reports the CED detection. >+ */ >+ u32 CED_rx_detected:1; >+ >+ /*! CNG tone was detected in the transmit direction. */ >+ u32 CNG_tx_detected:1; >+ >+ /*! CNG tone was detected in the receive direction. */ >+ u32 CNG_rx_detected:1; >+ >+ /*! The echocan disabled its NLP automatically. >+ */ >+ u32 NLP_auto_disabled:1; >+ >+ /*! The echocan enabled its NLP automatically. >+ */ >+ u32 NLP_auto_enabled:1; >+ }; >+ } events; >+}; >+ >+struct dahdi_chan { >+#ifdef CONFIG_DAHDI_NET >+ /*! \note Must be first */ >+ struct dahdi_hdlc *hdlcnetdev; >+#endif >+#ifdef CONFIG_DAHDI_PPP >+ struct ppp_channel *ppp; >+ struct tasklet_struct ppp_calls; >+ int do_ppp_wakeup; >+ int do_ppp_error; >+ struct sk_buff_head ppp_rq; >+#endif >+#ifdef BUFFER_DEBUG >+ int statcount; >+ int lastnumbufs; >+#endif >+#ifdef CONFIG_DAHDI_BRI_DCHANS >+ int bytes2receive; >+ int maxbytes2transmit; /* size of the tx buffer in the card driver */ >+ int bytes2transmit; >+ int eofrx; >+ int eoftx; >+#endif >+ spinlock_t lock; >+ char name[40]; >+ /* Specified by DAHDI */ >+ /*! \brief DAHDI channel number */ >+ int channo; >+ int chanpos; >+ unsigned long flags; >+ long rxp1; >+ long rxp2; >+ long rxp3; >+ int txtone; >+ int tx_v2; >+ int tx_v3; >+ int v1_1; >+ int v2_1; >+ int v3_1; >+ int toneflags; >+ struct sf_detect_state rd; >+ >+ struct dahdi_chan *master; /*!< Our Master channel (could be us) */ >+ /*! \brief Next slave (if appropriate) */ >+ int nextslave; >+ >+ u_char *writechunk; /*!< Actual place to write to */ >+ u_char swritechunk[DAHDI_MAX_CHUNKSIZE]; /*!< Buffer to be written */ >+ u_char *readchunk; /*!< Actual place to read from */ >+ u_char sreadchunk[DAHDI_MAX_CHUNKSIZE]; /*!< Preallocated static area */ >+ short *readchunkpreec; >+ >+ /*! Pointer to tx and rx gain tables */ >+ u_char *rxgain; >+ u_char *txgain; >+ >+ /*! Whether or not we have allocated gains or are using the default */ >+ int gainalloc; >+ >+ /* Specified by driver, readable by DAHDI */ >+ void *pvt; /*!< Private channel data */ >+ struct file *file; /*!< File structure */ >+ >+ >+ struct dahdi_span *span; /*!< Span we're a member of */ >+ int sig; /*!< Signalling */ >+ int sigcap; /*!< Capability for signalling */ >+ __u32 chan_alarms; /*!< alarms status */ >+ >+ /* Used only by DAHDI -- NO DRIVER SERVICEABLE PARTS BELOW */ >+ /* Buffer declarations */ >+ u_char *readbuf[DAHDI_MAX_NUM_BUFS]; /*!< read buffer */ >+ int inreadbuf; >+ int outreadbuf; >+ wait_queue_head_t readbufq; /*!< read wait queue */ >+ >+ u_char *writebuf[DAHDI_MAX_NUM_BUFS]; /*!< write buffers */ >+ int inwritebuf; >+ int outwritebuf; >+ wait_queue_head_t writebufq; /*!< write wait queue */ >+ >+ int blocksize; /*!< Block size */ >+ >+ int eventinidx; /*!< out index in event buf (circular) */ >+ int eventoutidx; /*!< in index in event buf (circular) */ >+ unsigned int eventbuf[DAHDI_MAX_EVENTSIZE]; /*!< event circ. buffer */ >+ wait_queue_head_t eventbufq; /*!< event wait queue */ >+ >+ wait_queue_head_t txstateq; /*!< waiting on the tx state to change */ >+ >+ int readn[DAHDI_MAX_NUM_BUFS]; /*!< # of bytes ready in read buf */ >+ int readidx[DAHDI_MAX_NUM_BUFS]; /*!< current read pointer */ >+ int writen[DAHDI_MAX_NUM_BUFS]; /*!< # of bytes ready in write buf */ >+ int writeidx[DAHDI_MAX_NUM_BUFS]; /*!< current write pointer */ >+ >+ int numbufs; /*!< How many buffers in channel */ >+ int txbufpolicy; /*!< Buffer policy */ >+ int rxbufpolicy; /*!< Buffer policy */ >+ int txdisable; /*!< Disable transmitter */ >+ int rxdisable; /*!< Disable receiver */ >+ >+ >+ /* Tone zone stuff */ >+ struct dahdi_zone *curzone; /*!< Zone for selecting tones */ >+ int tonezone; /*!< Tone zone for this channel */ >+ struct dahdi_tone *curtone; /*!< Current tone we're playing (if any) */ >+ int tonep; /*!< Current position in tone */ >+ struct dahdi_tone_state ts; /*!< Tone state */ >+ >+ /* Pulse dial stuff */ >+ int pdialcount; /*!< pulse dial count */ >+ >+ /*! Ring cadence */ >+ int ringcadence[DAHDI_MAX_CADENCE]; >+ int firstcadencepos; /*!< Where to restart ring cadence */ >+ >+ /* Digit string dialing stuff */ >+ int digitmode; /*!< What kind of tones are we sending? */ >+ char txdialbuf[DAHDI_MAX_DTMF_BUF]; >+ int dialing; >+ int afterdialingtimer; >+ int cadencepos; /*!< Where in the cadence we are */ >+ >+ /* I/O Mask */ >+ int iomask; /*! I/O Mux signal mask */ >+ wait_queue_head_t sel; /*! thingy for select stuff */ >+ >+ /* HDLC state machines */ >+ struct fasthdlc_state txhdlc; >+ struct fasthdlc_state rxhdlc; >+ int infcs; >+ >+ /* Conferencing stuff */ >+ int confna; /*! conference number (alias) */ >+ int _confn; /*! Actual conference number */ >+ int confmode; /*! conference mode */ >+ int confmute; /*! conference mute mode */ >+ >+ /* Incoming and outgoing conference chunk queues for >+ communicating between DAHDI master time and >+ other boards */ >+ struct confq confin; >+ struct confq confout; >+ >+ short getlin[DAHDI_MAX_CHUNKSIZE]; /*!< Last transmitted samples */ >+ unsigned char getraw[DAHDI_MAX_CHUNKSIZE]; /*!< Last received raw data */ >+ short getlin_lastchunk[DAHDI_MAX_CHUNKSIZE]; /*!< Last transmitted samples from last chunk */ >+ short putlin[DAHDI_MAX_CHUNKSIZE]; /*!< Last received samples */ >+ unsigned char putraw[DAHDI_MAX_CHUNKSIZE]; /*!< Last received raw data */ >+ short conflast[DAHDI_MAX_CHUNKSIZE]; /*!< Last conference sample -- base part of channel */ >+ short conflast1[DAHDI_MAX_CHUNKSIZE]; /*!< Last conference sample -- pseudo part of channel */ >+ short conflast2[DAHDI_MAX_CHUNKSIZE]; /*!< Previous last conference sample -- pseudo part of channel */ >+ >+ >+ /*! The echo canceler module that should be used to create an >+ instance when this channel needs one */ >+ const struct dahdi_echocan_factory *ec_factory; >+ /*! The echo canceler module that owns the instance currently >+ on this channel, if one is present */ >+ const struct dahdi_echocan_factory *ec_current; >+ /*! The state data of the echo canceler instance in use */ >+ struct dahdi_echocan_state *ec_state; >+ >+ /* RBS timings */ >+ int prewinktime; /*!< pre-wink time (ms) */ >+ int preflashtime; /*!< pre-flash time (ms) */ >+ int winktime; /*!< wink time (ms) */ >+ int flashtime; /*!< flash time (ms) */ >+ int starttime; /*!< start time (ms) */ >+ int rxwinktime; /*!< rx wink time (ms) */ >+ int rxflashtime; /*!< rx flash time (ms) */ >+ int debouncetime; /*!< FXS GS sig debounce time (ms) */ >+ int pulsebreaktime; /*!< pulse line open time (ms) */ >+ int pulsemaketime; /*!< pulse line closed time (ms) */ >+ int pulseaftertime; /*!< pulse time between digits (ms) */ >+ >+ /*! RING debounce timer */ >+ int ringdebtimer; >+ >+ /*! RING trailing detector to make sure a RING is really over */ >+ int ringtrailer; >+ >+ /* PULSE digit receiver stuff */ >+ int pulsecount; >+ int pulsetimer; >+ >+ /* RBS timers */ >+ int itimerset; /*!< what the itimer was set to last */ >+ int itimer; >+ int otimer; >+ >+ /* RBS state */ >+ int gotgs; >+ int txstate; >+ int rxsig; >+ int txsig; >+ int rxsigstate; >+ >+ /* non-RBS rx state */ >+ int rxhooksig; >+ int txhooksig; >+ int kewlonhook; >+ >+ /*! Idle signalling if CAS signalling */ >+ int idlebits; >+ >+ int deflaw; /*! 1 = mulaw, 2=alaw, 0=undefined */ >+ short *xlaw; >+#ifdef OPTIMIZE_CHANMUTE >+ int chanmute; /*!< no need for PCM data */ >+#endif >+#ifdef CONFIG_CALC_XLAW >+ unsigned char (*lineartoxlaw)(short a); >+#else >+ unsigned char *lin2x; >+#endif >+}; >+ >+#ifdef CONFIG_DAHDI_NET >+struct dahdi_hdlc { >+ struct net_device *netdev; >+ struct dahdi_chan *chan; >+}; >+#endif >+ >+/*! Define the maximum block size */ >+#define DAHDI_MAX_BLOCKSIZE 8192 >+ >+ >+#define DAHDI_DEFAULT_WINKTIME 150 /*!< 150 ms default wink time */ >+#define DAHDI_DEFAULT_FLASHTIME 750 /*!< 750 ms default flash time */ >+ >+#define DAHDI_DEFAULT_PREWINKTIME 50 /*!< 50 ms before wink */ >+#define DAHDI_DEFAULT_PREFLASHTIME 50 /*!< 50 ms before flash */ >+#define DAHDI_DEFAULT_STARTTIME 1500 /*!< 1500 ms of start */ >+#define DAHDI_DEFAULT_RINGTIME 2000 /*!< 2000 ms of ring on (start, FXO) */ >+#if 0 >+#define DAHDI_DEFAULT_RXWINKTIME 250 /*!< 250ms longest rx wink */ >+#endif >+#define DAHDI_DEFAULT_RXWINKTIME 300 /*!< 300ms longest rx wink (to work with the Atlas) */ >+#define DAHDI_DEFAULT_RXFLASHTIME 1250 /*!< 1250ms longest rx flash */ >+#define DAHDI_DEFAULT_DEBOUNCETIME 600 /*!< 600ms of FXS GS signalling debounce */ >+#define DAHDI_DEFAULT_PULSEMAKETIME 50 /*!< 50 ms of line closed when dial pulsing */ >+#define DAHDI_DEFAULT_PULSEBREAKTIME 50 /*!< 50 ms of line open when dial pulsing */ >+#define DAHDI_DEFAULT_PULSEAFTERTIME 750 /*!< 750ms between dial pulse digits */ >+ >+#define DAHDI_MINPULSETIME (15 * 8) /*!< 15 ms minimum */ >+ >+#ifdef SHORT_FLASH_TIME >+#define DAHDI_MAXPULSETIME (80 * 8) /*!< we need 80 ms, not 200ms, as we have a short flash */ >+#else >+#define DAHDI_MAXPULSETIME (200 * 8) /*!< 200 ms maximum */ >+#endif >+ >+#define DAHDI_PULSETIMEOUT ((DAHDI_MAXPULSETIME / 8) + 50) >+ >+#define DAHDI_RINGTRAILER (50 * 8) /*!< Don't consider a ring "over" until it's been gone at least this >+ much time */ >+ >+#define DAHDI_LOOPCODE_TIME 10000 /*!< send loop codes for 10 secs */ >+#define DAHDI_ALARMSETTLE_TIME 5000 /*!< allow alarms to settle for 5 secs */ >+#define DAHDI_AFTERSTART_TIME 500 /*!< 500ms after start */ >+ >+#define DAHDI_RINGOFFTIME 4000 /*!< Turn off ringer for 4000 ms */ >+#define DAHDI_KEWLTIME 500 /*!< 500ms for kewl pulse */ >+#define DAHDI_AFTERKEWLTIME 300 /*!< 300ms after kewl pulse */ >+ >+#define DAHDI_MAX_PRETRAINING 1000 /*!< 1000ms max pretraining time */ >+ >+#ifdef FXSFLASH >+#define DAHDI_FXSFLASHMINTIME 450 /*!< min 450ms */ >+#define DAHDI_FXSFLASHMAXTIME 550 /*!< max 550ms */ >+#endif >+ >+ >+struct dahdi_chardev { >+ const char *name; >+ __u8 minor; >+}; >+ >+int dahdi_register_chardev(struct dahdi_chardev *dev); >+int dahdi_unregister_chardev(struct dahdi_chardev *dev); >+ >+/*! \brief defines for transmit signalling */ >+enum dahdi_txsig { >+ DAHDI_TXSIG_ONHOOK, /*!< On hook */ >+ DAHDI_TXSIG_OFFHOOK, /*!< Off hook */ >+ DAHDI_TXSIG_START, /*!< Start / Ring */ >+ DAHDI_TXSIG_KEWL, /*!< Drop battery if possible */ >+ /*! Leave this as the last entry */ >+ DAHDI_TXSIG_TOTAL, >+}; >+ >+enum dahdi_rxsig { >+ DAHDI_RXSIG_ONHOOK, >+ DAHDI_RXSIG_OFFHOOK, >+ DAHDI_RXSIG_START, >+ DAHDI_RXSIG_RING, >+ DAHDI_RXSIG_INITIAL >+}; >+ >+enum { >+ /* Span flags */ >+ DAHDI_FLAGBIT_REGISTERED= 0, >+ DAHDI_FLAGBIT_RUNNING = 1, >+ DAHDI_FLAGBIT_RBS = 12, /*!< Span uses RBS signalling */ >+ >+ /* Channel flags */ >+ DAHDI_FLAGBIT_DTMFDECODE= 2, /*!< Channel supports native DTMF decode */ >+ DAHDI_FLAGBIT_MFDECODE = 3, /*!< Channel supports native MFr2 decode */ >+ DAHDI_FLAGBIT_ECHOCANCEL= 4, /*!< Channel supports native echo cancellation */ >+ DAHDI_FLAGBIT_HDLC = 5, /*!< Perform HDLC */ >+ DAHDI_FLAGBIT_NETDEV = 6, /*!< Send to network */ >+ DAHDI_FLAGBIT_PSEUDO = 7, /*!< Pseudo channel */ >+ DAHDI_FLAGBIT_CLEAR = 8, /*!< Clear channel */ >+ DAHDI_FLAGBIT_AUDIO = 9, /*!< Audio mode channel */ >+ DAHDI_FLAGBIT_OPEN = 10, /*!< Channel is open */ >+ DAHDI_FLAGBIT_FCS = 11, /*!< Calculate FCS */ >+ /* Reserve 12 for uniqueness with span flags */ >+ DAHDI_FLAGBIT_LINEAR = 13, /*!< Talk to user space in linear */ >+ DAHDI_FLAGBIT_PPP = 14, /*!< PPP is available */ >+ DAHDI_FLAGBIT_T1PPP = 15, >+ DAHDI_FLAGBIT_SIGFREEZE = 16, /*!< Freeze signalling */ >+ DAHDI_FLAGBIT_NOSTDTXRX = 17, /*!< Do NOT do standard transmit and receive on every interrupt */ >+ 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 */ >+#define DAHDI_FLAG(x) (1 << (DAHDI_FLAGBIT_ ## x)) >+ >+/*! This is a redefinition of the flags from above to allow use of the >+ * legacy drivers that do not use the kernel atomic bit testing and >+ * changing routines. >+ * >+ * See the above descriptions for DAHDI_FLAGBIT_.... for documentation >+ * about function. */ >+/* Span flags */ >+#define DAHDI_FLAG_REGISTERED DAHDI_FLAG(REGISTERED) >+#define DAHDI_FLAG_RUNNING DAHDI_FLAG(RUNNING) >+#define DAHDI_FLAG_RBS DAHDI_FLAG(RBS) >+ >+/* Channel flags */ >+#define DAHDI_FLAG_DTMFDECODE DAHDI_FLAG(DTMFDECODE) >+#define DAHDI_FLAG_MFDECODE DAHDI_FLAG(MFDECODE) >+#define DAHDI_FLAG_ECHOCANCEL DAHDI_FLAG(ECHOCANCEL) >+ >+#define DAHDI_FLAG_HDLC DAHDI_FLAG(HDLC) >+#define DAHDI_FLAG_NETDEV DAHDI_FLAG(NETDEV) >+#define DAHDI_FLAG_PSEUDO DAHDI_FLAG(PSEUDO) >+#define DAHDI_FLAG_CLEAR DAHDI_FLAG(CLEAR) >+#define DAHDI_FLAG_AUDIO DAHDI_FLAG(AUDIO) >+ >+#define DAHDI_FLAG_OPEN DAHDI_FLAG(OPEN) >+#define DAHDI_FLAG_FCS DAHDI_FLAG(FCS) >+/* Reserve 12 for uniqueness with span flags */ >+#define DAHDI_FLAG_LINEAR DAHDI_FLAG(LINEAR) >+#define DAHDI_FLAG_PPP DAHDI_FLAG(PPP) >+#define DAHDI_FLAG_T1PPP DAHDI_FLAG(T1PPP) >+#define DAHDI_FLAG_SIGFREEZE DAHDI_FLAG(SIGFREEZE) >+#define DAHDI_FLAG_NOSTDTXRX DAHDI_FLAG(NOSTDTXRX) >+#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; >+ void *pvt; /*!< Private stuff */ >+ char name[40]; /*!< Span name */ >+ char desc[80]; /*!< Span description */ >+ const char *spantype; /*!< span type in text form */ >+ const char *manufacturer; /*!< span's device manufacturer */ >+ char devicetype[80]; /*!< span's device type */ >+ char location[40]; /*!< span device's location in system */ >+ int deflaw; /*!< Default law (DAHDI_MULAW or DAHDI_ALAW) */ >+ int alarms; /*!< Pending alarms on span */ >+ unsigned long flags; >+ int irq; /*!< IRQ for this span's hardware */ >+ int lbo; /*!< Span Line-Buildout */ >+ int lineconfig; /*!< Span line configuration */ >+ int linecompat; /*!< Span line compatibility */ >+ int channels; /*!< Number of channels in span */ >+ int txlevel; /*!< Tx level */ >+ int rxlevel; /*!< Rx level */ >+ int syncsrc; /*!< current sync src (gets copied here) */ >+ unsigned int bpvcount; /*!< BPV counter */ >+ unsigned int crc4count; /*!< CRC4 error counter */ >+ unsigned int ebitcount; /*!< current E-bit error count */ >+ unsigned int fascount; /*!< current FAS error count */ >+ >+ int maintstat; /*!< Maintenance state */ >+ wait_queue_head_t maintq; /*!< Maintenance queue */ >+ int mainttimer; /*!< Maintenance timer */ >+ >+ int irqmisses; /*!< Interrupt misses */ >+ >+ int timingslips; /*!< Clock slips */ >+ >+ struct dahdi_chan **chans; /*!< Member channel structures */ >+ >+ /* ==== Span Callback Operations ==== */ >+ /*! Req: Set the requested chunk size. This is the unit in which you must >+ report results for conferencing, etc */ >+ int (*setchunksize)(struct dahdi_span *span, int chunksize); >+ >+ /*! Opt: Configure the span (if appropriate) */ >+ int (*spanconfig)(struct dahdi_span *span, struct dahdi_lineconfig *lc); >+ >+ /*! Opt: Start the span */ >+ int (*startup)(struct dahdi_span *span); >+ >+ /*! Opt: Shutdown the span */ >+ int (*shutdown)(struct dahdi_span *span); >+ >+ /*! Opt: Enable maintenance modes */ >+ int (*maint)(struct dahdi_span *span, int mode); >+ >+#ifdef DAHDI_SYNC_TICK >+ /*! Opt: send sync to spans */ >+ int (*sync_tick)(struct dahdi_span *span, int is_master); >+#endif >+ >+ /* ==== Channel Callback Operations ==== */ >+ /*! Opt: Set signalling type (if appropriate) */ >+ int (*chanconfig)(struct dahdi_chan *chan, int sigtype); >+ >+ /*! Opt: Prepare a channel for I/O */ >+ int (*open)(struct dahdi_chan *chan); >+ >+ /*! Opt: Close channel for I/O */ >+ int (*close)(struct dahdi_chan *chan); >+ >+ /*! Opt: IOCTL */ >+ int (*ioctl)(struct dahdi_chan *chan, unsigned int cmd, unsigned long data); >+ >+ /*! Opt: Provide echo cancellation on a channel */ >+ int (*echocan_create)(struct dahdi_chan *chan, struct dahdi_echocanparams *ecp, >+ struct dahdi_echocanparam *p, struct dahdi_echocan_state **ec); >+ >+ /* Okay, now we get to the signalling. You have several options: */ >+ >+ /* Option 1: If you're a T1 like interface, you can just provide a >+ rbsbits function and we'll assert robbed bits for you. Be sure to >+ set the DAHDI_FLAG_RBS in this case. */ >+ >+ /*! Opt: If the span uses A/B bits, set them here */ >+ int (*rbsbits)(struct dahdi_chan *chan, int bits); >+ >+ /*! Option 2: If you don't know about sig bits, but do have their >+ equivalents (i.e. you can disconnect battery, detect off hook, >+ generate ring, etc directly) then you can just specify a >+ sethook function, and we'll call you with appropriate hook states >+ to set. Still set the DAHDI_FLAG_RBS in this case as well */ >+ int (*hooksig)(struct dahdi_chan *chan, enum dahdi_txsig hookstate); >+ >+ /*! Option 3: If you can't use sig bits, you can write a function >+ which handles the individual hook states */ >+ int (*sethook)(struct dahdi_chan *chan, int hookstate); >+ >+ /*! Opt: Dacs the contents of chan2 into chan1 if possible */ >+ int (*dacs)(struct dahdi_chan *chan1, struct dahdi_chan *chan2); >+ >+ /*! Opt: Used to tell an onboard HDLC controller that there is data ready to transmit */ >+ void (*hdlc_hard_xmit)(struct dahdi_chan *chan); >+ >+ /* Used by DAHDI only -- no user servicable parts inside */ >+ int spanno; /*!< Span number for DAHDI */ >+ int offset; /*!< Offset within a given card */ >+ int lastalarms; /*!< Previous alarms */ >+ /*! If the watchdog detects no received data, it will call the >+ watchdog routine */ >+ int (*watchdog)(struct dahdi_span *span, int cause); >+#ifdef CONFIG_DAHDI_WATCHDOG >+ int watchcounter; >+ int watchstate; >+#endif >+}; >+ >+struct dahdi_transcoder_channel { >+ void *pvt; >+ struct dahdi_transcoder *parent; >+ wait_queue_head_t ready; >+ __u32 built_fmts; >+#define DAHDI_TC_FLAG_BUSY 1 >+#define DAHDI_TC_FLAG_CHAN_BUILT 2 >+#define DAHDI_TC_FLAG_NONBLOCK 3 >+#define DAHDI_TC_FLAG_DATA_WAITING 4 >+ unsigned long flags; >+ u32 dstfmt; >+ u32 srcfmt; >+}; >+ >+static inline int >+dahdi_tc_is_built(struct dahdi_transcoder_channel *dtc) { >+ return test_bit(DAHDI_TC_FLAG_CHAN_BUILT, &dtc->flags); >+} >+static inline void >+dahdi_tc_set_built(struct dahdi_transcoder_channel *dtc) { >+ set_bit(DAHDI_TC_FLAG_CHAN_BUILT, &dtc->flags); >+} >+static inline void >+dahdi_tc_clear_built(struct dahdi_transcoder_channel *dtc) { >+ clear_bit(DAHDI_TC_FLAG_CHAN_BUILT, &dtc->flags); >+} >+static inline int >+dahdi_tc_is_nonblock(struct dahdi_transcoder_channel *dtc) { >+ return test_bit(DAHDI_TC_FLAG_NONBLOCK, &dtc->flags); >+} >+static inline void >+dahdi_tc_set_nonblock(struct dahdi_transcoder_channel *dtc) { >+ set_bit(DAHDI_TC_FLAG_NONBLOCK, &dtc->flags); >+} >+static inline void >+dahdi_tc_clear_nonblock(struct dahdi_transcoder_channel *dtc) { >+ clear_bit(DAHDI_TC_FLAG_NONBLOCK, &dtc->flags); >+} >+static inline int >+dahdi_tc_is_data_waiting(struct dahdi_transcoder_channel *dtc) { >+ return test_bit(DAHDI_TC_FLAG_DATA_WAITING, &dtc->flags); >+} >+static inline int >+dahdi_tc_is_busy(struct dahdi_transcoder_channel *dtc) { >+ return test_bit(DAHDI_TC_FLAG_BUSY, &dtc->flags); >+} >+static inline void >+dahdi_tc_set_busy(struct dahdi_transcoder_channel *dtc) { >+ set_bit(DAHDI_TC_FLAG_BUSY, &dtc->flags); >+} >+static inline void >+dahdi_tc_clear_busy(struct dahdi_transcoder_channel *dtc) { >+ clear_bit(DAHDI_TC_FLAG_BUSY, &dtc->flags); >+} >+static inline void >+dahdi_tc_set_data_waiting(struct dahdi_transcoder_channel *dtc) { >+ set_bit(DAHDI_TC_FLAG_DATA_WAITING, &dtc->flags); >+} >+static inline void >+dahdi_tc_clear_data_waiting(struct dahdi_transcoder_channel *dtc) { >+ clear_bit(DAHDI_TC_FLAG_DATA_WAITING, &dtc->flags); >+} >+ >+struct dahdi_transcoder { >+ struct list_head active_list_node; >+ struct list_head registration_list_node; >+ char name[80]; >+ int numchannels; >+ unsigned int srcfmts; >+ unsigned int dstfmts; >+ struct file_operations fops; >+ int (*allocate)(struct dahdi_transcoder_channel *channel); >+ int (*release)(struct dahdi_transcoder_channel *channel); >+ /* Transcoder channels */ >+ struct dahdi_transcoder_channel channels[0]; >+}; >+ >+#define DAHDI_WATCHDOG_NOINTS (1 << 0) >+ >+#define DAHDI_WATCHDOG_INIT 1000 >+ >+#define DAHDI_WATCHSTATE_UNKNOWN 0 >+#define DAHDI_WATCHSTATE_OK 1 >+#define DAHDI_WATCHSTATE_RECOVERING 2 >+#define DAHDI_WATCHSTATE_FAILED 3 >+ >+ >+struct dahdi_dynamic_driver { >+ /*! Driver name (e.g. Eth) */ >+ char name[20]; >+ >+ /*! Driver description */ >+ char desc[80]; >+ >+ /*! Create a new transmission pipe */ >+ void *(*create)(struct dahdi_span *span, char *address); >+ >+ /*! Destroy a created transmission pipe */ >+ void (*destroy)(void *tpipe); >+ >+ /*! Transmit a given message */ >+ int (*transmit)(void *tpipe, unsigned char *msg, int msglen); >+ >+ /*! Flush any pending messages */ >+ int (*flush)(void); >+ >+ struct dahdi_dynamic_driver *next; >+}; >+ >+/*! \brief Receive a dynamic span message */ >+void dahdi_dynamic_receive(struct dahdi_span *span, unsigned char *msg, int msglen); >+ >+/*! \brief Register a dynamic driver */ >+int dahdi_dynamic_register(struct dahdi_dynamic_driver *driver); >+ >+/*! \brief Unregister a dynamic driver */ >+void dahdi_dynamic_unregister(struct dahdi_dynamic_driver *driver); >+ >+/*! Receive on a span. The DAHDI interface will handle all the calculations for >+ all member channels of the span, pulling the data from the readchunk buffer */ >+int dahdi_receive(struct dahdi_span *span); >+ >+/*! Prepare writechunk buffers on all channels for this span */ >+int dahdi_transmit(struct dahdi_span *span); >+ >+/*! Abort the buffer currently being receive with event "event" */ >+void dahdi_hdlc_abort(struct dahdi_chan *ss, int event); >+ >+/*! Indicate to DAHDI that the end of frame was received and rotate buffers */ >+void dahdi_hdlc_finish(struct dahdi_chan *ss); >+ >+/*! Put a chunk of data into the current receive buffer */ >+void dahdi_hdlc_putbuf(struct dahdi_chan *ss, unsigned char *rxb, int bytes); >+ >+/*! Get a chunk of data from the current transmit buffer. Returns -1 if no data >+ * is left to send, 0 if there is data remaining in the current message to be sent >+ * and 1 if the currently transmitted message is now done */ >+int dahdi_hdlc_getbuf(struct dahdi_chan *ss, unsigned char *bufptr, unsigned int *size); >+ >+ >+/*! Register a span. Returns 0 on success, -1 on failure. Pref-master is non-zero if >+ we should have preference in being the master device */ >+int dahdi_register(struct dahdi_span *span, int prefmaster); >+ >+/*! Allocate / free memory for a transcoder */ >+struct dahdi_transcoder *dahdi_transcoder_alloc(int numchans); >+void dahdi_transcoder_free(struct dahdi_transcoder *ztc); >+ >+/*! \brief Register a transcoder */ >+int dahdi_transcoder_register(struct dahdi_transcoder *tc); >+ >+/*! \brief Unregister a transcoder */ >+int dahdi_transcoder_unregister(struct dahdi_transcoder *tc); >+ >+/*! \brief Alert a transcoder */ >+int dahdi_transcoder_alert(struct dahdi_transcoder_channel *ztc); >+ >+/*! \brief Unregister a span */ >+int dahdi_unregister(struct dahdi_span *span); >+ >+/*! \brief Gives a name to an LBO */ >+char *dahdi_lboname(int lbo); >+ >+/*! \brief Tell DAHDI about changes in received rbs bits */ >+void dahdi_rbsbits(struct dahdi_chan *chan, int bits); >+ >+/*! \brief Tell DAHDI abou changes in received signalling */ >+void dahdi_hooksig(struct dahdi_chan *chan, enum dahdi_rxsig rxsig); >+ >+/*! \brief Queue an event on a channel */ >+void dahdi_qevent_nolock(struct dahdi_chan *chan, int event); >+ >+/*! \brief Queue an event on a channel, locking it first */ >+void dahdi_qevent_lock(struct dahdi_chan *chan, int event); >+ >+/*! \brief Notify a change possible change in alarm status on a channel */ >+void dahdi_alarm_channel(struct dahdi_chan *chan, int alarms); >+ >+/*! \brief Notify a change possible change in alarm status on a span */ >+void dahdi_alarm_notify(struct dahdi_span *span); >+ >+/*! \brief Initialize a tone state */ >+void dahdi_init_tone_state(struct dahdi_tone_state *ts, struct dahdi_tone *zt); >+ >+/*! \brief Get a given MF tone struct, suitable for dahdi_tone_nextsample. */ >+struct dahdi_tone *dahdi_mf_tone(const struct dahdi_chan *chan, char digit, int digitmode); >+ >+/* Echo cancel a receive and transmit chunk for a given channel. This >+ should be called by the low-level driver as close to the interface >+ as possible. ECHO CANCELLATION IS NO LONGER AUTOMATICALLY DONE >+ AT THE DAHDI LEVEL. dahdi_ec_chunk will not echo cancel if it should >+ not be doing so. rxchunk is modified in-place */ >+ >+void dahdi_ec_chunk(struct dahdi_chan *chan, unsigned char *rxchunk, const unsigned char *txchunk); >+void dahdi_ec_span(struct dahdi_span *span); >+ >+extern struct file_operations *dahdi_transcode_fops; >+ >+/* Don't use these directly -- they're not guaranteed to >+ be there. */ >+extern short __dahdi_mulaw[256]; >+extern short __dahdi_alaw[256]; >+#ifdef CONFIG_CALC_XLAW >+u_char __dahdi_lineartoulaw(short a); >+u_char __dahdi_lineartoalaw(short a); >+#else >+extern u_char __dahdi_lin2mu[16384]; >+extern u_char __dahdi_lin2a[16384]; >+#endif >+ >+/*! \brief Used by dynamic DAHDI -- don't use directly */ >+void dahdi_set_dynamic_ioctl(int (*func)(unsigned int cmd, unsigned long data)); >+ >+/*! \brief Used by DAHDI HPEC module -- don't use directly */ >+void dahdi_set_hpec_ioctl(int (*func)(unsigned int cmd, unsigned long data)); >+ >+/*! \brief Used privately by DAHDI. Avoid touching directly */ >+struct dahdi_tone { >+ int fac1; >+ int init_v2_1; >+ int init_v3_1; >+ >+ int fac2; >+ int init_v2_2; >+ int init_v3_2; >+ >+ int tonesamples; /*!< How long to play this tone before >+ going to the next (in samples) */ >+ struct dahdi_tone *next; /* Next tone in this sequence */ >+ >+ int modulate; >+}; >+ >+static inline short dahdi_tone_nextsample(struct dahdi_tone_state *ts, struct dahdi_tone *zt) >+{ >+ /* follow the curves, return the sum */ >+ >+ int p; >+ >+ ts->v1_1 = ts->v2_1; >+ ts->v2_1 = ts->v3_1; >+ ts->v3_1 = (zt->fac1 * ts->v2_1 >> 15) - ts->v1_1; >+ >+ ts->v1_2 = ts->v2_2; >+ ts->v2_2 = ts->v3_2; >+ ts->v3_2 = (zt->fac2 * ts->v2_2 >> 15) - ts->v1_2; >+ >+ /* Return top 16 bits */ >+ if (!ts->modulate) return ts->v3_1 + ts->v3_2; >+ /* we are modulating */ >+ p = ts->v3_2 - 32768; >+ if (p < 0) p = -p; >+ p = ((p * 9) / 10) + 1; >+ return (ts->v3_1 * p) >> 15; >+ >+} >+ >+static inline short dahdi_txtone_nextsample(struct dahdi_chan *ss) >+{ >+ /* follow the curves, return the sum */ >+ >+ ss->v1_1 = ss->v2_1; >+ ss->v2_1 = ss->v3_1; >+ ss->v3_1 = (ss->txtone * ss->v2_1 >> 15) - ss->v1_1; >+ return ss->v3_1; >+} >+ >+/* These are the right functions to use. */ >+ >+#define DAHDI_MULAW(a) (__dahdi_mulaw[(a)]) >+#define DAHDI_ALAW(a) (__dahdi_alaw[(a)]) >+#define DAHDI_XLAW(a,c) (c->xlaw[(a)]) >+ >+#ifdef CONFIG_CALC_XLAW >+#define DAHDI_LIN2MU(a) (__dahdi_lineartoulaw((a))) >+#define DAHDI_LIN2A(a) (__dahdi_lineartoalaw((a))) >+ >+#define DAHDI_LIN2X(a,c) ((c)->lineartoxlaw((a))) >+ >+#else >+/* Use tables */ >+#define DAHDI_LIN2MU(a) (__dahdi_lin2mu[((unsigned short)(a)) >> 2]) >+#define DAHDI_LIN2A(a) (__dahdi_lin2a[((unsigned short)(a)) >> 2]) >+ >+/* Manipulate as appropriate for x-law */ >+#define DAHDI_LIN2X(a,c) ((c)->lin2x[((unsigned short)(a)) >> 2]) >+ >+#endif /* CONFIG_CALC_XLAW */ >+ >+/* Data formats for capabilities and frames alike (from Asterisk) */ >+/*! G.723.1 compression */ >+#define DAHDI_FORMAT_G723_1 (1 << 0) >+/*! GSM compression */ >+#define DAHDI_FORMAT_GSM (1 << 1) >+/*! Raw mu-law data (G.711) */ >+#define DAHDI_FORMAT_ULAW (1 << 2) >+/*! Raw A-law data (G.711) */ >+#define DAHDI_FORMAT_ALAW (1 << 3) >+/*! ADPCM (G.726, 32kbps) */ >+#define DAHDI_FORMAT_G726 (1 << 4) >+/*! ADPCM (IMA) */ >+#define DAHDI_FORMAT_ADPCM (1 << 5) >+/*! Raw 16-bit Signed Linear (8000 Hz) PCM */ >+#define DAHDI_FORMAT_SLINEAR (1 << 6) >+/*! LPC10, 180 samples/frame */ >+#define DAHDI_FORMAT_LPC10 (1 << 7) >+/*! G.729A audio */ >+#define DAHDI_FORMAT_G729A (1 << 8) >+/*! SpeeX Free Compression */ >+#define DAHDI_FORMAT_SPEEX (1 << 9) >+/*! iLBC Free Compression */ >+#define DAHDI_FORMAT_ILBC (1 << 10) >+/*! Maximum audio format */ >+#define DAHDI_FORMAT_MAX_AUDIO (1 << 15) >+/*! Maximum audio mask */ >+#define DAHDI_FORMAT_AUDIO_MASK ((1 << 16) - 1) >+ >+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,14) >+#define kzalloc(a, b) kcalloc(1, a, b) >+#endif >+ >+#endif /* _DAHDI_KERNEL_H */ >diff -Naur dahdi-linux-2.2.0/drivers/dahdi/zaphfc/modules.order dahdi-linux-2.2.0_zaphfc/drivers/dahdi/zaphfc/modules.order >--- dahdi-linux-2.2.0/drivers/dahdi/zaphfc/modules.order 1970-01-01 01:00:00.000000000 +0100 >+++ dahdi-linux-2.2.0_zaphfc/drivers/dahdi/zaphfc/modules.order 2009-06-08 03:46:04.000000000 +0200 >@@ -0,0 +1 @@ >+kernel//usr/src/dahdi-svn/dahdi-kernel/drivers/dahdi/zaphfc/zaphfc.ko >diff -Naur dahdi-linux-2.2.0/drivers/dahdi/zaphfc/user.h dahdi-linux-2.2.0_zaphfc/drivers/dahdi/zaphfc/user.h >--- dahdi-linux-2.2.0/drivers/dahdi/zaphfc/user.h 1970-01-01 01:00:00.000000000 +0100 >+++ dahdi-linux-2.2.0_zaphfc/drivers/dahdi/zaphfc/user.h 2009-06-05 12:56:39.000000000 +0200 >@@ -0,0 +1,1158 @@ >+/* >+ * DAHDI Telephony Interface >+ * >+ * Written by Mark Spencer <markster@digium.com> >+ * Based on previous works, designs, and architectures conceived and >+ * written by Jim Dixon <jim@lambdatel.com>. >+ * >+ * Copyright (C) 2001 Jim Dixon / Zapata Telephony. >+ * Copyright (C) 2001 - 2008 Digium, Inc. >+ * >+ * All rights reserved. >+ * >+ */ >+ >+/* >+ * See http://www.asterisk.org for more information about >+ * the Asterisk project. Please do not directly contact >+ * any of the maintainers of this project for assistance; >+ * the project provides a web site, mailing lists and IRC >+ * channels for your use. >+ * >+ * This program is free software, distributed under the terms of >+ * the GNU Lesser General Public License Version 2.1 as published >+ * by the Free Software Foundation. See the LICENSE.LGPL file >+ * included with this program for more details. >+ * >+ * In addition, when this program is distributed with Asterisk in >+ * any form that would qualify as a 'combined work' or as a >+ * 'derivative work' (but not mere aggregation), you can redistribute >+ * and/or modify the combination under the terms of the license >+ * provided with that copy of Asterisk, instead of the license >+ * terms granted here. >+ */ >+ >+#ifndef _DAHDI_USER_H >+#define _DAHDI_USER_H >+ >+#include <linux/types.h> >+#include <linux/ioctl.h> >+ >+#ifndef ELAST >+#define ELAST 500 >+#endif >+ >+/* Per-span configuration values */ >+#define DAHDI_CONFIG_TXLEVEL 7 /* bits 0-2 are tx level */ >+ >+/* Line configuration */ >+/* These apply to T1 */ >+#define DAHDI_CONFIG_D4 (1 << 4) >+#define DAHDI_CONFIG_ESF (1 << 5) >+#define DAHDI_CONFIG_AMI (1 << 6) >+#define DAHDI_CONFIG_B8ZS (1 << 7) >+/* These apply to E1 */ >+#define DAHDI_CONFIG_CCS (1 << 8) /* CCS (ISDN) instead of CAS (Robbed Bit) */ >+#define DAHDI_CONFIG_HDB3 (1 << 9) /* HDB3 instead of AMI (line coding) */ >+#define DAHDI_CONFIG_CRC4 (1 << 10) /* CRC4 framing */ >+#define DAHDI_CONFIG_NOTOPEN (1 << 16) >+ >+/* Signalling types */ >+#define DAHDI_SIG_BROKEN (1 << 31) /* The port is broken and/or failed initialization */ >+ >+#define __DAHDI_SIG_FXO (1 << 12) /* Never use directly */ >+#define __DAHDI_SIG_FXS (1 << 13) /* Never use directly */ >+ >+#define DAHDI_SIG_NONE (0) /* Channel not configured */ >+#define DAHDI_SIG_FXSLS ((1 << 0) | __DAHDI_SIG_FXS) /* FXS, Loopstart */ >+#define DAHDI_SIG_FXSGS ((1 << 1) | __DAHDI_SIG_FXS) /* FXS, Groundstart */ >+#define DAHDI_SIG_FXSKS ((1 << 2) | __DAHDI_SIG_FXS) /* FXS, Kewlstart */ >+ >+#define DAHDI_SIG_FXOLS ((1 << 3) | __DAHDI_SIG_FXO) /* FXO, Loopstart */ >+#define DAHDI_SIG_FXOGS ((1 << 4) | __DAHDI_SIG_FXO) /* FXO, Groupstart */ >+#define DAHDI_SIG_FXOKS ((1 << 5) | __DAHDI_SIG_FXO) /* FXO, Kewlstart */ >+ >+#define DAHDI_SIG_EM (1 << 6) /* Ear & Mouth (E&M) */ >+ >+/* The following are all variations on clear channel */ >+ >+#define __DAHDI_SIG_DACS (1 << 16) >+ >+#define DAHDI_SIG_CLEAR (1 << 7) /* Clear channel */ >+#define DAHDI_SIG_HDLCRAW ((1 << 8) | DAHDI_SIG_CLEAR) /* Raw unchecked HDLC */ >+#define DAHDI_SIG_HDLCFCS ((1 << 9) | DAHDI_SIG_HDLCRAW) /* HDLC with FCS calculation */ >+#define DAHDI_SIG_HDLCNET ((1 << 10) | DAHDI_SIG_HDLCFCS) /* HDLC Network */ >+#define DAHDI_SIG_SLAVE (1 << 11) /* Slave to another channel */ >+#define DAHDI_SIG_SF (1 << 14) /* Single Freq. tone only, no sig bits */ >+#define DAHDI_SIG_CAS (1 << 15) /* Just get bits */ >+#define DAHDI_SIG_DACS (__DAHDI_SIG_DACS | DAHDI_SIG_CLEAR) /* Cross connect */ >+#define DAHDI_SIG_EM_E1 (1 << 17) /* E1 E&M Variation */ >+#define DAHDI_SIG_DACS_RBS ((1 << 18) | __DAHDI_SIG_DACS) /* Cross connect w/ RBS */ >+#define DAHDI_SIG_HARDHDLC ((1 << 19) | DAHDI_SIG_CLEAR) >+#define DAHDI_SIG_MTP2 ((1 << 20) | DAHDI_SIG_HDLCFCS) /* MTP2 support Need HDLC bitstuff and FCS calcuation too */ >+ >+/* tone flag values */ >+#define DAHDI_REVERSE_RXTONE 1 /* reverse polarity rx tone logic */ >+#define DAHDI_REVERSE_TXTONE 2 /* reverse polarity tx tone logic */ >+ >+#define DAHDI_ABIT (1 << 3) >+#define DAHDI_BBIT (1 << 2) >+#define DAHDI_CBIT (1 << 1) >+#define DAHDI_DBIT (1 << 0) >+ >+#define DAHDI_BITS_ABCD (DAHDI_ABIT | DAHDI_BBIT | DAHDI_CBIT | DAHDI_DBIT) >+#define DAHDI_BITS_ABD (DAHDI_ABIT | DAHDI_BBIT | DAHDI_DBIT) >+#define DAHDI_BITS_ACD (DAHDI_ABIT | DAHDI_CBIT | DAHDI_DBIT) >+#define DAHDI_BITS_BCD (DAHDI_BBIT | DAHDI_CBIT | DAHDI_DBIT) >+#define DAHDI_BITS_AC (DAHDI_ABIT | DAHDI_CBIT) >+#define DAHDI_BITS_BD (DAHDI_BBIT | DAHDI_DBIT) >+ >+#define DAHDI_MAJOR 196 >+ >+#define DAHDI_MAX_BLOCKSIZE 8192 >+#define DAHDI_DEFAULT_NUM_BUFS 2 >+#define DAHDI_MAX_NUM_BUFS 32 >+#define DAHDI_MAX_BUF_SPACE 32768 >+ >+#define DAHDI_DEFAULT_BLOCKSIZE 1024 >+#define DAHDI_DEFAULT_MTR_MRU 2048 >+ >+/*! Define the default network block size */ >+#define DAHDI_DEFAULT_MTU_MRU 2048 >+ >+#define DAHDI_POLICY_IMMEDIATE 0 /* Start play/record immediately */ >+#define DAHDI_POLICY_WHEN_FULL 1 /* Start play/record when buffer is full */ >+#define DAHDI_POLICY_HALF_FULL 2 /* Start play/record when buffer is half full. >+ Note -- This policy only works on tx buffers */ >+ >+#define DAHDI_GET_PARAMS_RETURN_MASTER 0x40000000 >+ >+#define DAHDI_TONE_ZONE_MAX 128 >+ >+#define DAHDI_TONE_ZONE_DEFAULT -1 /* To restore default */ >+ >+#define DAHDI_TONE_STOP -1 >+#define DAHDI_TONE_DIALTONE 0 >+#define DAHDI_TONE_BUSY 1 >+#define DAHDI_TONE_RINGTONE 2 >+#define DAHDI_TONE_CONGESTION 3 >+#define DAHDI_TONE_CALLWAIT 4 >+#define DAHDI_TONE_DIALRECALL 5 >+#define DAHDI_TONE_RECORDTONE 6 >+#define DAHDI_TONE_INFO 7 >+#define DAHDI_TONE_CUST1 8 >+#define DAHDI_TONE_CUST2 9 >+#define DAHDI_TONE_STUTTER 10 >+#define DAHDI_TONE_MAX 16 >+ >+#define DAHDI_TONE_DTMF_BASE 64 >+#define DAHDI_TONE_MFR1_BASE 80 >+#define DAHDI_TONE_MFR2_FWD_BASE 96 >+#define DAHDI_TONE_MFR2_REV_BASE 112 >+ >+enum { >+ DAHDI_TONE_DTMF_0 = DAHDI_TONE_DTMF_BASE, >+ DAHDI_TONE_DTMF_1, >+ DAHDI_TONE_DTMF_2, >+ DAHDI_TONE_DTMF_3, >+ DAHDI_TONE_DTMF_4, >+ DAHDI_TONE_DTMF_5, >+ DAHDI_TONE_DTMF_6, >+ DAHDI_TONE_DTMF_7, >+ DAHDI_TONE_DTMF_8, >+ DAHDI_TONE_DTMF_9, >+ DAHDI_TONE_DTMF_s, >+ DAHDI_TONE_DTMF_p, >+ DAHDI_TONE_DTMF_A, >+ DAHDI_TONE_DTMF_B, >+ DAHDI_TONE_DTMF_C, >+ DAHDI_TONE_DTMF_D >+}; >+ >+#define DAHDI_TONE_DTMF_MAX DAHDI_TONE_DTMF_D >+ >+enum { >+ DAHDI_TONE_MFR1_0 = DAHDI_TONE_MFR1_BASE, >+ DAHDI_TONE_MFR1_1, >+ DAHDI_TONE_MFR1_2, >+ DAHDI_TONE_MFR1_3, >+ DAHDI_TONE_MFR1_4, >+ DAHDI_TONE_MFR1_5, >+ DAHDI_TONE_MFR1_6, >+ DAHDI_TONE_MFR1_7, >+ DAHDI_TONE_MFR1_8, >+ DAHDI_TONE_MFR1_9, >+ DAHDI_TONE_MFR1_KP, >+ DAHDI_TONE_MFR1_ST, >+ DAHDI_TONE_MFR1_STP, >+ DAHDI_TONE_MFR1_ST2P, >+ DAHDI_TONE_MFR1_ST3P, >+}; >+ >+#define DAHDI_TONE_MFR1_MAX DAHDI_TONE_MFR1_ST3P >+ >+enum { >+ DAHDI_TONE_MFR2_FWD_1 = DAHDI_TONE_MFR2_FWD_BASE, >+ DAHDI_TONE_MFR2_FWD_2, >+ DAHDI_TONE_MFR2_FWD_3, >+ DAHDI_TONE_MFR2_FWD_4, >+ DAHDI_TONE_MFR2_FWD_5, >+ DAHDI_TONE_MFR2_FWD_6, >+ DAHDI_TONE_MFR2_FWD_7, >+ DAHDI_TONE_MFR2_FWD_8, >+ DAHDI_TONE_MFR2_FWD_9, >+ DAHDI_TONE_MFR2_FWD_10, >+ DAHDI_TONE_MFR2_FWD_11, >+ DAHDI_TONE_MFR2_FWD_12, >+ DAHDI_TONE_MFR2_FWD_13, >+ DAHDI_TONE_MFR2_FWD_14, >+ DAHDI_TONE_MFR2_FWD_15, >+}; >+ >+#define DAHDI_TONE_MFR2_FWD_MAX DAHDI_TONE_MFR2_FWD_15 >+ >+enum { >+ DAHDI_TONE_MFR2_REV_1 = DAHDI_TONE_MFR2_REV_BASE, >+ DAHDI_TONE_MFR2_REV_2, >+ DAHDI_TONE_MFR2_REV_3, >+ DAHDI_TONE_MFR2_REV_4, >+ DAHDI_TONE_MFR2_REV_5, >+ DAHDI_TONE_MFR2_REV_6, >+ DAHDI_TONE_MFR2_REV_7, >+ DAHDI_TONE_MFR2_REV_8, >+ DAHDI_TONE_MFR2_REV_9, >+ DAHDI_TONE_MFR2_REV_10, >+ DAHDI_TONE_MFR2_REV_11, >+ DAHDI_TONE_MFR2_REV_12, >+ DAHDI_TONE_MFR2_REV_13, >+ DAHDI_TONE_MFR2_REV_14, >+ DAHDI_TONE_MFR2_REV_15, >+}; >+ >+#define DAHDI_TONE_MFR2_REV_MAX DAHDI_TONE_MFR2_REV_15 >+ >+#define DAHDI_LAW_DEFAULT 0 /* Default law for span */ >+#define DAHDI_LAW_MULAW 1 /* Mu-law */ >+#define DAHDI_LAW_ALAW 2 /* A-law */ >+ >+#define DAHDI_DIAL_OP_APPEND 1 >+#define DAHDI_DIAL_OP_REPLACE 2 >+#define DAHDI_DIAL_OP_CANCEL 3 >+ >+#define DAHDI_MAX_CADENCE 16 >+ >+#define DAHDI_TONEDETECT_ON (1 << 0) /* Detect tones */ >+#define DAHDI_TONEDETECT_MUTE (1 << 1) /* Mute audio in received channel */ >+ >+/* Define the max # of outgoing DTMF, MFR1 or MFR2 digits to queue */ >+#define DAHDI_MAX_DTMF_BUF 256 >+ >+#define DAHDI_MAX_EVENTSIZE 64 /* 64 events max in buffer */ >+ >+/* Value for DAHDI_HOOK, set to ON hook */ >+#define DAHDI_ONHOOK 0 >+ >+/* Value for DAHDI_HOOK, set to OFF hook */ >+#define DAHDI_OFFHOOK 1 >+ >+/* Value for DAHDI_HOOK, wink (off hook momentarily) */ >+#define DAHDI_WINK 2 >+ >+/* Value for DAHDI_HOOK, flash (on hook momentarily) */ >+#define DAHDI_FLASH 3 >+ >+/* Value for DAHDI_HOOK, start line */ >+#define DAHDI_START 4 >+ >+/* Value for DAHDI_HOOK, ring line (same as start line) */ >+#define DAHDI_RING 5 >+ >+/* Value for DAHDI_HOOK, turn ringer off */ >+#define DAHDI_RINGOFF 6 >+ >+/* Flush and stop the read (input) process */ >+#define DAHDI_FLUSH_READ 1 >+ >+/* Flush and stop the write (output) process */ >+#define DAHDI_FLUSH_WRITE 2 >+ >+/* Flush and stop both (input and output) processes */ >+#define DAHDI_FLUSH_BOTH (DAHDI_FLUSH_READ | DAHDI_FLUSH_WRITE) >+ >+/* Flush the event queue */ >+#define DAHDI_FLUSH_EVENT 4 >+ >+/* Flush everything */ >+#define DAHDI_FLUSH_ALL (DAHDI_FLUSH_BOTH | DAHDI_FLUSH_EVENT) >+ >+#define DAHDI_MAX_SPANS 128 /* Max, 128 spans */ >+#define DAHDI_MAX_CHANNELS 1024 /* Max, 1024 channels */ >+#define DAHDI_MAX_CONF 1024 /* Max, 1024 conferences */ >+ >+/* Conference modes */ >+#define DAHDI_CONF_MODE_MASK 0xFF /* mask for modes */ >+#define DAHDI_CONF_NORMAL 0 /* normal mode */ >+#define DAHDI_CONF_MONITOR 1 /* monitor mode (rx of other chan) */ >+#define DAHDI_CONF_MONITORTX 2 /* monitor mode (tx of other chan) */ >+#define DAHDI_CONF_MONITORBOTH 3 /* monitor mode (rx & tx of other chan) */ >+#define DAHDI_CONF_CONF 4 /* conference mode */ >+#define DAHDI_CONF_CONFANN 5 /* conference announce mode */ >+#define DAHDI_CONF_CONFMON 6 /* conference monitor mode */ >+#define DAHDI_CONF_CONFANNMON 7 /* conference announce/monitor mode */ >+#define DAHDI_CONF_REALANDPSEUDO 8 /* real and pseudo port both on conf */ >+#define DAHDI_CONF_DIGITALMON 9 /* Do not decode or interpret */ >+#define DAHDI_CONF_MONITOR_RX_PREECHO 10 /* monitor mode (rx of other chan) - before echo can is done */ >+#define DAHDI_CONF_MONITOR_TX_PREECHO 11 /* monitor mode (tx of other chan) - before echo can is done */ >+#define DAHDI_CONF_MONITORBOTH_PREECHO 12 /* monitor mode (rx & tx of other chan) - before echo can is done */ >+#define DAHDI_CONF_FLAG_MASK 0xFF00 /* mask for flags */ >+#define DAHDI_CONF_LISTENER 0x100 /* is a listener on the conference */ >+#define DAHDI_CONF_TALKER 0x200 /* is a talker on the conference */ >+#define DAHDI_CONF_PSEUDO_LISTENER 0x400 /* pseudo is a listener on the conference */ >+#define DAHDI_CONF_PSEUDO_TALKER 0x800 /* pseudo is a talker on the conference */ >+ >+/* Alarm Condition bits */ >+#define DAHDI_ALARM_NONE 0 /* No alarms */ >+#define DAHDI_ALARM_RECOVER 1 /* Recovering from alarm */ >+#define DAHDI_ALARM_LOOPBACK 2 /* In loopback */ >+#define DAHDI_ALARM_YELLOW 4 /* Yellow Alarm */ >+#define DAHDI_ALARM_RED 8 /* Red Alarm */ >+#define DAHDI_ALARM_BLUE 16 /* Blue Alarm */ >+#define DAHDI_ALARM_NOTOPEN 32 >+ >+/* Maintenance modes */ >+#define DAHDI_MAINT_NONE 0 /* Normal Mode */ >+#define DAHDI_MAINT_LOCALLOOP 1 /* Local Loopback */ >+#define DAHDI_MAINT_REMOTELOOP 2 /* Remote Loopback */ >+#define DAHDI_MAINT_LOOPUP 3 /* send loopup code */ >+#define DAHDI_MAINT_LOOPDOWN 4 /* send loopdown code */ >+#define DAHDI_MAINT_LOOPSTOP 5 /* stop sending loop codes */ >+ >+/* Flag Value for IOMUX, read avail */ >+#define DAHDI_IOMUX_READ 1 >+ >+/* Flag Value for IOMUX, write avail */ >+#define DAHDI_IOMUX_WRITE 2 >+ >+/* Flag Value for IOMUX, write done */ >+#define DAHDI_IOMUX_WRITEEMPTY 4 >+ >+/* Flag Value for IOMUX, signalling event avail */ >+#define DAHDI_IOMUX_SIGEVENT 8 >+ >+/* Flag Value for IOMUX, Do Not Wait if nothing to report */ >+#define DAHDI_IOMUX_NOWAIT 0x100 >+ >+/* Ret. Value for GET/WAIT Event, no event */ >+#define DAHDI_EVENT_NONE 0 >+ >+/* Ret. Value for GET/WAIT Event, Went Onhook */ >+#define DAHDI_EVENT_ONHOOK 1 >+ >+/* Ret. Value for GET/WAIT Event, Went Offhook or got Ring */ >+#define DAHDI_EVENT_RINGOFFHOOK 2 >+ >+/* Ret. Value for GET/WAIT Event, Got Wink or Flash */ >+#define DAHDI_EVENT_WINKFLASH 3 >+ >+/* Ret. Value for GET/WAIT Event, Got Alarm */ >+#define DAHDI_EVENT_ALARM 4 >+ >+/* Ret. Value for GET/WAIT Event, Got No Alarm (after alarm) */ >+#define DAHDI_EVENT_NOALARM 5 >+ >+/* Ret. Value for GET/WAIT Event, HDLC Abort frame */ >+#define DAHDI_EVENT_ABORT 6 >+ >+/* Ret. Value for GET/WAIT Event, HDLC Frame overrun */ >+#define DAHDI_EVENT_OVERRUN 7 >+ >+/* Ret. Value for GET/WAIT Event, Bad FCS */ >+#define DAHDI_EVENT_BADFCS 8 >+ >+/* Ret. Value for dial complete */ >+#define DAHDI_EVENT_DIALCOMPLETE 9 >+ >+/* Ret Value for ringer going on */ >+#define DAHDI_EVENT_RINGERON 10 >+ >+/* Ret Value for ringer going off */ >+#define DAHDI_EVENT_RINGEROFF 11 >+ >+/* Ret Value for hook change complete */ >+#define DAHDI_EVENT_HOOKCOMPLETE 12 >+ >+/* Ret Value for bits changing on a CAS / User channel */ >+#define DAHDI_EVENT_BITSCHANGED 13 >+ >+/* Ret value for the beginning of a pulse coming on its way */ >+#define DAHDI_EVENT_PULSE_START 14 >+ >+/* Timer event -- timer expired */ >+#define DAHDI_EVENT_TIMER_EXPIRED 15 >+ >+/* Timer event -- ping ready */ >+#define DAHDI_EVENT_TIMER_PING 16 >+ >+/* Polarity reversal event */ >+#define DAHDI_EVENT_POLARITY 17 >+ >+/* Ring Begin event */ >+#define DAHDI_EVENT_RINGBEGIN 18 >+ >+/* Echo can disabled event */ >+#define DAHDI_EVENT_EC_DISABLED 19 >+ >+/* Channel was disconnected. Hint user to close channel */ >+#define DAHDI_EVENT_REMOVED 20 >+ >+/* A neon MWI pulse was detected */ >+#define DAHDI_EVENT_NEONMWI_ACTIVE 21 >+ >+/* No neon MWI pulses were detected over some period of time */ >+#define DAHDI_EVENT_NEONMWI_INACTIVE 22 >+ >+/* A CED tone was detected on the channel in the transmit direction */ >+#define DAHDI_EVENT_TX_CED_DETECTED 23 >+ >+/* A CED tone was detected on the channel in the receive direction */ >+#define DAHDI_EVENT_RX_CED_DETECTED 24 >+ >+/* A CNG tone was detected on the channel in the transmit direction */ >+#define DAHDI_EVENT_TX_CNG_DETECTED 25 >+ >+/* A CNG tone was detected on the channel in the receive direction */ >+#define DAHDI_EVENT_RX_CNG_DETECTED 26 >+ >+/* The echo canceler's NLP (only) was disabled */ >+#define DAHDI_EVENT_EC_NLP_DISABLED 27 >+ >+/* The echo canceler's NLP (only) was enabled */ >+#define DAHDI_EVENT_EC_NLP_ENABLED 28 >+ >+#define DAHDI_EVENT_PULSEDIGIT (1 << 16) /* This is OR'd with the digit received */ >+#define DAHDI_EVENT_DTMFDOWN (1 << 17) /* Ditto for DTMF key down event */ >+#define DAHDI_EVENT_DTMFUP (1 << 18) /* Ditto for DTMF key up event */ >+ >+/* Transcoder related definitions */ >+ >+struct dahdi_transcoder_formats { >+ __u32 srcfmt; >+ __u32 dstfmt; >+}; >+struct dahdi_transcoder_info { >+ __u32 tcnum; >+ char name[80]; >+ __u32 numchannels; >+ __u32 dstfmts; >+ __u32 srcfmts; >+}; >+ >+#define DAHDI_MAX_ECHOCANPARAMS 8 >+ >+/* ioctl definitions */ >+#define DAHDI_CODE 0xDA >+ >+/* >+ * Get/Set Transfer Block Size. >+ */ >+#define DAHDI_GET_BLOCKSIZE _IOR(DAHDI_CODE, 1, int) >+#define DAHDI_SET_BLOCKSIZE _IOW(DAHDI_CODE, 1, int) >+ >+/* >+ * Flush Buffer(s) and stop I/O >+ */ >+#define DAHDI_FLUSH _IOW(DAHDI_CODE, 3, int) >+ >+/* >+ * Wait for Write to Finish >+ */ >+#define DAHDI_SYNC _IO(DAHDI_CODE, 4) >+ >+/* >+ * Get/set channel parameters >+ */ >+ >+struct dahdi_params { >+ int channo; /* Channel number */ >+ int spanno; /* Span itself */ >+ int chanpos; /* Channel number in span */ >+ int sigtype; /* read-only */ >+ int sigcap; /* read-only */ >+ int rxisoffhook; /* read-only */ >+ int rxbits; /* read-only */ >+ int txbits; /* read-only */ >+ int txhooksig; /* read-only */ >+ int rxhooksig; /* read-only */ >+ int curlaw; /* read-only -- one of DAHDI_LAW_MULAW or DAHDI_LAW_ALAW */ >+ int idlebits; /* read-only -- What is considered the idle state */ >+ char name[40]; /* Name of channel */ >+ int prewinktime; >+ int preflashtime; >+ int winktime; >+ int flashtime; >+ int starttime; >+ int rxwinktime; >+ int rxflashtime; >+ int debouncetime; >+ int pulsebreaktime; >+ int pulsemaketime; >+ int pulseaftertime; >+ __u32 chan_alarms; /* alarms on this channel */ >+}; >+ >+#define DAHDI_GET_PARAMS_V1 _IOR(DAHDI_CODE, 5, struct dahdi_params) >+#define DAHDI_GET_PARAMS _IOWR(DAHDI_CODE, 5, struct dahdi_params) >+#define DAHDI_SET_PARAMS _IOW(DAHDI_CODE, 5, struct dahdi_params) >+ >+/* >+ * Set Hookswitch Status >+ */ >+#define DAHDI_HOOK _IOW(DAHDI_CODE, 7, int) >+ >+/* >+ * Get Signalling Event >+ */ >+#define DAHDI_GETEVENT _IOR(DAHDI_CODE, 8, int) >+ >+/* >+ * Wait for something to happen (IO Mux) >+ */ >+#define DAHDI_IOMUX _IOWR(DAHDI_CODE, 9, int) >+ >+/* >+ * Get Span Status >+ */ >+struct dahdi_spaninfo { >+ int spanno; /* span number */ >+ char name[20]; /* Name */ >+ char desc[40]; /* Description */ >+ int alarms; /* alarms status */ >+ int txlevel; /* what TX level is set to */ >+ int rxlevel; /* current RX level */ >+ int bpvcount; /* current BPV count */ >+ int crc4count; /* current CRC4 error count */ >+ int ebitcount; /* current E-bit error count */ >+ int fascount; /* current FAS error count */ >+ int irqmisses; /* current IRQ misses */ >+ int syncsrc; /* span # of current sync source, or 0 for free run */ >+ int numchans; /* number of configured channels on this span */ >+ int totalchans; /* total number of channels on the span */ >+ int totalspans; /* total number of spans in entire system */ >+ int lbo; /* line build out */ >+ int lineconfig; /* framing/coding */ >+ char lboname[40]; /* line build out in text form */ >+ char location[40]; /* span's device location in system */ >+ char manufacturer[40]; /* manufacturer of span's device */ >+ char devicetype[40]; /* span's device type */ >+ int irq; /* span's device IRQ */ >+ int linecompat; /* signaling modes possible on this span */ >+ char spantype[6]; /* type of span in text form */ >+}; >+ >+#define DAHDI_SPANSTAT _IOWR(DAHDI_CODE, 10, struct dahdi_spaninfo) >+ >+/* >+ * Set Maintenance Mode >+ */ >+struct dahdi_maintinfo { >+ int spanno; /* span number 1-2 */ >+ int command; /* command */ >+}; >+ >+#define DAHDI_MAINT _IOW(DAHDI_CODE, 11, struct dahdi_maintinfo) >+ >+/* >+ * Get/Set Conference Mode >+ */ >+struct dahdi_confinfo { >+ int chan; /* channel number, 0 for current */ >+ int confno; /* conference number */ >+ int confmode; /* conferencing mode */ >+}; >+ >+#define DAHDI_GETCONF_V1 _IOR(DAHDI_CODE, 12, struct dahdi_confinfo) >+#define DAHDI_GETCONF _IOWR(DAHDI_CODE, 12, struct dahdi_confinfo) >+ >+#define DAHDI_SETCONF_V1 _IOW(DAHDI_CODE, 12, struct dahdi_confinfo) >+#define DAHDI_SETCONF _IOWR(DAHDI_CODE, 13, struct dahdi_confinfo) >+ >+/* >+ * Setup or Remove Conference Link >+ */ >+#define DAHDI_CONFLINK _IOW(DAHDI_CODE, 14, struct dahdi_confinfo) >+ >+/* >+ * Display Conference Diagnostic Information on Console >+ */ >+#define DAHDI_CONFDIAG_V1 _IOR(DAHDI_CODE, 15, int) >+#define DAHDI_CONFDIAG _IOW(DAHDI_CODE, 15, int) >+ >+/* >+ * Get/Set Channel audio gains >+ */ >+struct dahdi_gains { >+ int chan; /* channel number, 0 for current */ >+ unsigned char rxgain[256]; /* Receive gain table */ >+ unsigned char txgain[256]; /* Transmit gain table */ >+}; >+ >+#define DAHDI_GETGAINS_V1 _IOR(DAHDI_CODE, 16, struct dahdi_gains) >+#define DAHDI_GETGAINS _IOWR(DAHDI_CODE, 16, struct dahdi_gains) >+#define DAHDI_SETGAINS _IOW(DAHDI_CODE, 16, struct dahdi_gains) >+ >+/* >+ * Set Line (T1) Configurations >+ */ >+struct dahdi_lineconfig { >+ int span; /* Which span number (0 to use name) */ >+ char name[20]; /* Name of span to use */ >+ int lbo; /* line build-outs */ >+ int lineconfig; /* line config parameters (framing, coding) */ >+ int sync; /* what level of sync source we are */ >+}; >+ >+#define DAHDI_SPANCONFIG _IOW(DAHDI_CODE, 18, struct dahdi_lineconfig) >+ >+/* >+ * Set Channel Configuration >+ */ >+struct dahdi_chanconfig { >+ int chan; /* Channel we're applying this to (0 to use name) */ >+ char name[40]; /* Name of channel to use */ >+ int sigtype; /* Signal type */ >+ int deflaw; /* Default law (DAHDI_LAW_DEFAULT, DAHDI_LAW_MULAW, or DAHDI_LAW_ALAW) */ >+ int master; /* Master channel if sigtype is DAHDI_SLAVE */ >+ int idlebits; /* Idle bits (if this is a CAS channel) or >+ channel to monitor (if this is DACS channel) */ >+ char netdev_name[16];/* name for the hdlc network device*/ >+}; >+ >+#define DAHDI_CHANCONFIG _IOW(DAHDI_CODE, 19, struct dahdi_chanconfig) >+ >+/* >+ * Set Conference to mute mode >+ */ >+#define DAHDI_CONFMUTE _IOW(DAHDI_CODE, 20, int) >+ >+/* >+ * Send a particular tone (see DAHDI_TONE_*) >+ */ >+#define DAHDI_SENDTONE _IOW(DAHDI_CODE, 21, int) >+ >+/* >+ * Get/Set your region for tones >+ */ >+#define DAHDI_GETTONEZONE _IOR(DAHDI_CODE, 22, int) >+#define DAHDI_SETTONEZONE _IOW(DAHDI_CODE, 22, int) >+ >+/* >+ * Master unit only -- set default zone (see DAHDI_TONE_ZONE_*) >+ */ >+#define DAHDI_DEFAULTZONE _IOW(DAHDI_CODE, 24, int) >+ >+/* >+ * Load a tone zone from a dahdi_tone_def_header >+ */ >+struct dahdi_tone_def { >+ int tone; /* See DAHDI_TONE_* */ >+ int next; /* What the next position in the cadence is >+ (They're numbered by the order the appear here) */ >+ int samples; /* How many samples to play for this cadence */ >+ int shift; /* How much to scale down the volume (2 is nice) */ >+ >+ /* Now come the constants we need to make tones */ >+ >+ /* >+ Calculate the next 6 factors using the following equations: >+ l = <level in dbm>, f1 = <freq1>, f2 = <freq2> >+ gain = pow(10.0, (l - 3.14) / 20.0) * 65536.0 / 2.0; >+ >+ // Frequency factor 1 >+ fac_1 = 2.0 * cos(2.0 * M_PI * (f1/8000.0)) * 32768.0; >+ // Last previous two samples >+ init_v2_1 = sin(-4.0 * M_PI * (f1/8000.0)) * gain; >+ init_v3_1 = sin(-2.0 * M_PI * (f1/8000.0)) * gain; >+ >+ // Frequency factor 2 >+ fac_2 = 2.0 * cos(2.0 * M_PI * (f2/8000.0)) * 32768.0; >+ // Last previous two samples >+ init_v2_2 = sin(-4.0 * M_PI * (f2/8000.0)) * gain; >+ init_v3_2 = sin(-2.0 * M_PI * (f2/8000.0)) * gain; >+ */ >+ int fac1; >+ int init_v2_1; >+ int init_v3_1; >+ int fac2; >+ int init_v2_2; >+ int init_v3_2; >+ int modulate; >+}; >+ >+struct dahdi_tone_def_header { >+ int count; /* How many samples follow */ >+ int zone; /* Which zone we are loading */ >+ int ringcadence[DAHDI_MAX_CADENCE]; /* Ring cadence in ms (0=on, 1=off, ends with 0 value) */ >+ char name[40]; /* Informational name of zone */ >+ /* immediately follow this structure with dahdi_tone_def structures */ >+ struct dahdi_tone_def tones[0]; >+}; >+ >+#define DAHDI_LOADZONE _IOW(DAHDI_CODE, 25, struct dahdi_tone_def_header) >+ >+/* >+ * Free a tone zone >+ */ >+#define DAHDI_FREEZONE _IOW(DAHDI_CODE, 26, int) >+ >+/* >+ * Get/Set buffer policy >+ */ >+struct dahdi_bufferinfo { >+ int txbufpolicy; /* Policy for handling receive buffers */ >+ int rxbufpolicy; /* Policy for handling receive buffers */ >+ int numbufs; /* How many buffers to use */ >+ int bufsize; /* How big each buffer is */ >+ int readbufs; /* How many read buffers are full (read-only) */ >+ int writebufs; /* How many write buffers are full (read-only) */ >+}; >+ >+#define DAHDI_GET_BUFINFO _IOR(DAHDI_CODE, 27, struct dahdi_bufferinfo) >+#define DAHDI_SET_BUFINFO _IOW(DAHDI_CODE, 27, struct dahdi_bufferinfo) >+ >+/* >+ * Get/Set dialing parameters >+ */ >+struct dahdi_dialparams { >+ int mfv1_tonelen; /* MF R1 tone length for digits */ >+ int dtmf_tonelen; /* DTMF tone length */ >+ int mfr2_tonelen; /* MF R2 tone length */ >+ int reserved[3]; /* Reserved for future expansion -- always set to 0 */ >+}; >+ >+#define DAHDI_GET_DIALPARAMS _IOR(DAHDI_CODE, 29, struct dahdi_dialparams) >+#define DAHDI_SET_DIALPARAMS _IOW(DAHDI_CODE, 29, struct dahdi_dialparams) >+ >+/* >+ * Append, replace, or cancel a dial string >+ */ >+struct dahdi_dialoperation { >+ int op; >+ char dialstr[DAHDI_MAX_DTMF_BUF]; >+}; >+ >+#define DAHDI_DIAL _IOW(DAHDI_CODE, 31, struct dahdi_dialoperation) >+ >+/* >+ * Set a clear channel into audio mode >+ */ >+#define DAHDI_AUDIOMODE _IOW(DAHDI_CODE, 32, int) >+ >+/* >+ * Enable or disable echo cancellation on a channel >+ * >+ * For ECHOCANCEL: >+ * The number is zero to disable echo cancellation and non-zero >+ * to enable echo cancellation. If the number is between 32 >+ * and 1024, it will also set the number of taps in the echo canceller >+ * >+ * For ECHOCANCEL_PARAMS: >+ * The structure contains parameters that should be passed to the >+ * echo canceler instance for the selected channel. >+ */ >+#define DAHDI_ECHOCANCEL _IOW(DAHDI_CODE, 33, int) >+ >+struct dahdi_echocanparam { >+ char name[16]; >+ __s32 value; >+}; >+ >+struct dahdi_echocanparams { >+ /* 8 taps per millisecond */ >+ __u32 tap_length; >+ /* number of parameters supplied */ >+ __u32 param_count; >+ /* immediately follow this structure with dahdi_echocanparam structures */ >+ struct dahdi_echocanparam params[0]; >+}; >+ >+#define DAHDI_ECHOCANCEL_PARAMS _IOW(DAHDI_CODE, 33, struct dahdi_echocanparams) >+ >+/* >+ * Return a channel's channel number >+ */ >+#define DAHDI_CHANNO _IOR(DAHDI_CODE, 34, int) >+ >+/* >+ * Return a flag indicating whether channel is currently dialing >+ */ >+#define DAHDI_DIALING _IOR(DAHDI_CODE, 35, int) >+ >+/* >+ * Set a clear channel into HDLC w/out FCS checking/calculation mode >+ */ >+#define DAHDI_HDLCRAWMODE _IOW(DAHDI_CODE, 36, int) >+ >+/* >+ * Set a clear channel into HDLC w/ FCS mode >+ */ >+#define DAHDI_HDLCFCSMODE _IOW(DAHDI_CODE, 37, int) >+ >+/* >+ * Specify a channel on generic channel selector - must be done before >+ * performing any other ioctls >+ */ >+#define DAHDI_SPECIFY _IOW(DAHDI_CODE, 38, int) >+ >+/* >+ * Temporarily set the law on a channel to >+ * DAHDI_LAW_DEFAULT, DAHDI_LAW_ALAW, or DAHDI_LAW_MULAW. Is reset on close. >+ */ >+#define DAHDI_SETLAW _IOW(DAHDI_CODE, 39, int) >+ >+/* >+ * Temporarily set the channel to operate in linear mode when non-zero >+ * or default law if 0 >+ */ >+#define DAHDI_SETLINEAR _IOW(DAHDI_CODE, 40, int) >+ >+/* >+ * Set a clear channel into HDLC w/ PPP interface mode >+ */ >+#define DAHDI_HDLCPPP _IOW(DAHDI_CODE, 41, int) >+ >+/* >+ * Set the ring cadence for FXS interfaces >+ */ >+struct dahdi_ring_cadence { >+ int ringcadence[DAHDI_MAX_CADENCE]; >+}; >+ >+#define DAHDI_SETCADENCE _IOW(DAHDI_CODE, 42, struct dahdi_ring_cadence) >+ >+/* >+ * Get/Set the signaling bits for CAS interface >+ */ >+#define DAHDI_GETRXBITS _IOR(DAHDI_CODE, 43, int) >+#define DAHDI_SETTXBITS _IOW(DAHDI_CODE, 43, int) >+ >+/* >+ * Display Channel Diagnostic Information on Console >+ */ >+#define DAHDI_CHANDIAG_V1 _IOR(DAHDI_CODE, 44, int) >+#define DAHDI_CHANDIAG _IOW(DAHDI_CODE, 44, int) >+ >+/* >+ * Set Channel's SF Tone Configuration >+ */ >+struct dahdi_sfconfig { >+ int chan; /* Channel we're applying this to (0 to use name) */ >+ char name[40]; /* Name of channel to use */ >+ long rxp1; /* receive tone det. p1 */ >+ long rxp2; /* receive tone det. p2 */ >+ long rxp3; /* receive tone det. p3 */ >+ int txtone; /* Tx tone factor */ >+ int tx_v2; /* initial v2 value */ >+ int tx_v3; /* initial v3 value */ >+ int toneflag; /* Tone flags */ >+}; >+ >+#define DAHDI_SFCONFIG _IOW(DAHDI_CODE, 46, struct dahdi_sfconfig) >+ >+/* >+ * Set timer expiration (in samples) >+ */ >+#define DAHDI_TIMERCONFIG _IOW(DAHDI_CODE, 47, int) >+ >+/* >+ * Acknowledge timer expiration (number to acknowledge, or -1 for all) >+ */ >+#define DAHDI_TIMERACK _IOW(DAHDI_CODE, 48, int) >+ >+/* >+ * Get Conference to mute mode >+ */ >+#define DAHDI_GETCONFMUTE _IOR(DAHDI_CODE, 49, int) >+ >+/* >+ * Request echo training in some number of ms (with muting in the mean time) >+ */ >+#define DAHDI_ECHOTRAIN _IOW(DAHDI_CODE, 50, int) >+ >+/* >+ * Set on hook transfer for n number of ms -- implemnted by low level driver >+ */ >+#define DAHDI_ONHOOKTRANSFER _IOW(DAHDI_CODE, 51, int) >+ >+/* >+ * Queue Ping >+ */ >+#define DAHDI_TIMERPING _IO(DAHDI_CODE, 52) >+ >+/* >+ * Acknowledge ping >+ */ >+#define DAHDI_TIMERPONG _IO(DAHDI_CODE, 53) >+ >+/* >+ * Get/set signalling freeze >+ */ >+#define DAHDI_GETSIGFREEZE _IOR(DAHDI_CODE, 54, int) >+#define DAHDI_SETSIGFREEZE _IOW(DAHDI_CODE, 54, int) >+ >+/* >+ * Perform an indirect ioctl (on a specified channel via master interface) >+ */ >+struct dahdi_indirect_data { >+ int chan; >+ int op; >+ void *data; >+}; >+ >+#define DAHDI_INDIRECT _IOWR(DAHDI_CODE, 56, struct dahdi_indirect_data) >+ >+ >+/* >+ * Get the version of DAHDI that is running, and a description >+ * of the compiled-in echo cancellers (if any) >+ */ >+struct dahdi_versioninfo { >+ char version[80]; >+ char echo_canceller[80]; >+}; >+ >+#define DAHDI_GETVERSION _IOR(DAHDI_CODE, 57, struct dahdi_versioninfo) >+ >+/* >+ * Put the channel in loopback mode (receive from the channel is >+ * transmitted back on the interface) >+ */ >+#define DAHDI_LOOPBACK _IOW(DAHDI_CODE, 58, int) >+ >+/* >+ Attach the desired echo canceler module (or none) to a channel in an >+ audio-supporting mode, so that when the channel needs an echo canceler >+ that module will be used to supply one. >+ */ >+struct dahdi_attach_echocan { >+ int chan; /* Channel we're applying this to */ >+ char echocan[16]; /* Name of echo canceler to attach to this channel >+ (leave empty to have no echocan attached */ >+}; >+ >+#define DAHDI_ATTACH_ECHOCAN _IOW(DAHDI_CODE, 59, struct dahdi_attach_echocan) >+ >+ >+/* >+ * 60-80 are reserved for private drivers >+ * 80-85 are reserved for dynamic span stuff >+ */ >+ >+/* >+ * Create a dynamic span >+ */ >+struct dahdi_dynamic_span { >+ char driver[20]; /* Which low-level driver to use */ >+ char addr[40]; /* Destination address */ >+ int numchans; /* Number of channels */ >+ int timing; /* Timing source preference */ >+ int spanno; /* Span number (filled in by DAHDI) */ >+}; >+ >+#define DAHDI_DYNAMIC_CREATE _IOWR(DAHDI_CODE, 80, struct dahdi_dynamic_span) >+ >+/* >+ * Destroy a dynamic span >+ */ >+#define DAHDI_DYNAMIC_DESTROY _IOW(DAHDI_CODE, 81, struct dahdi_dynamic_span) >+ >+/* >+ * Set the HW gain for a device >+ */ >+struct dahdi_hwgain { >+ __s32 newgain; /* desired gain in dB but x10. -3.5dB would be -35 */ >+ __u32 tx:1; /* 0=rx; 1=tx */ >+}; >+#define DAHDI_SET_HWGAIN _IOW(DAHDI_CODE, 86, struct dahdi_hwgain) >+ >+/* >+ * Enable tone detection -- implemented by low level driver >+ */ >+#define DAHDI_TONEDETECT _IOW(DAHDI_CODE, 91, int) >+ >+/* >+ * Set polarity -- implemented by individual driver. 0 = forward, 1 = reverse >+ */ >+#define DAHDI_SETPOLARITY _IOW(DAHDI_CODE, 92, int) >+ >+/* >+ * Transcoder operations >+ */ >+ >+/* DAHDI_TRANSCODE_OP is an older interface that is deprecated and no longer >+ * supported. >+ */ >+#define DAHDI_TRANSCODE_OP _IOWR(DAHDI_CODE, 93, int) >+ >+#define DAHDI_TC_CODE 'T' >+#define DAHDI_TC_ALLOCATE _IOW(DAHDI_TC_CODE, 1, struct dahdi_transcoder_formats) >+#define DAHDI_TC_GETINFO _IOWR(DAHDI_TC_CODE, 2, struct dahdi_transcoder_info) >+ >+/* >+ * VMWI Specification >+ */ >+struct dahdi_vmwi_info { >+ unsigned int vmwi_type; >+}; >+ >+#define DAHDI_VMWI_LREV (1 << 0) /* Line Reversal */ >+#define DAHDI_VMWI_HVDC (1 << 1) /* HV 90VDC */ >+#define DAHDI_VMWI_HVAC (1 << 2) /* HV 90VAC Neon lamp */ >+ >+/* >+ * VoiceMail Waiting Indication (VMWI) -- implemented by low-level driver. >+ * Value: number of waiting messages (hence 0: switch messages off). >+ */ >+#define DAHDI_VMWI _IOWR(DAHDI_CODE, 94, int) >+#define DAHDI_VMWI_CONFIG _IOW(DAHDI_CODE, 95, struct dahdi_vmwi_info) >+ >+/* >+ * Startup or Shutdown a span >+ */ >+#define DAHDI_STARTUP _IOW(DAHDI_CODE, 99, int) >+#define DAHDI_SHUTDOWN _IOW(DAHDI_CODE, 100, int) >+ >+#define DAHDI_HDLC_RATE _IOW(DAHDI_CODE, 101, int) >+ >+/* Put a channel's echo canceller into 'FAX mode' if possible */ >+ >+#define DAHDI_ECHOCANCEL_FAX_MODE _IOW(DAHDI_CODE, 102, int) >+ >+struct torisa_debug { >+ unsigned int txerrors; >+ unsigned int irqcount; >+ unsigned int taskletsched; >+ unsigned int taskletrun; >+ unsigned int taskletexec; >+ int span1flags; >+ int span2flags; >+}; >+ >+/* Special torisa ioctl */ >+#define TORISA_GETDEBUG _IOW(DAHDI_CODE, 60, struct torisa_debug) >+ >+/* Get current status IOCTL */ >+/* Defines for Radio Status (dahdi_radio_stat.radstat) bits */ >+ >+#define DAHDI_RADSTAT_RX 1 /* currently "receiving " */ >+#define DAHDI_RADSTAT_TX 2 /* currently "transmitting" */ >+#define DAHDI_RADSTAT_RXCT 4 /* currently receiving continuous tone with >+ current settings */ >+#define DAHDI_RADSTAT_RXCOR 8 /* currently receiving COR (irrelevant of COR >+ ignore) */ >+#define DAHDI_RADSTAT_IGNCOR 16 /* currently ignoring COR */ >+#define DAHDI_RADSTAT_IGNCT 32 /* currently ignoring CTCSS/DCS decode */ >+#define DAHDI_RADSTAT_NOENCODE 64 /* currently blocking CTCSS/DCS encode */ >+ >+struct dahdi_radio_stat { >+ unsigned short ctcode_rx; /* code of currently received CTCSS >+ or DCS, 0 for none */ >+ unsigned short ctclass; /* class of currently received CTCSS or >+ DCS code */ >+ unsigned short ctcode_tx; /* code of currently encoded CTCSS or >+ DCS, 0 for none */ >+ unsigned char radstat; /* status bits of radio */ >+}; >+ >+#define DAHDI_RADIO_GETSTAT _IOR(DAHDI_CODE, 57, struct dahdi_radio_stat) >+ >+/* Get/Set a radio channel parameter */ >+/* Defines for Radio Parameters (dahdi_radio_param.radpar) */ >+#define DAHDI_RADPAR_INVERTCOR 1 /* invert the COR signal (0/1) */ >+#define DAHDI_RADPAR_IGNORECOR 2 /* ignore the COR signal (0/1) */ >+#define DAHDI_RADPAR_IGNORECT 3 /* ignore the CTCSS/DCS decode (0/1) */ >+#define DAHDI_RADPAR_NOENCODE 4 /* block the CTCSS/DCS encode (0/1) */ >+#define DAHDI_RADPAR_CORTHRESH 5 /* COR trigger threshold (0-7) */ >+ >+#define DAHDI_RADPAR_EXTRXTONE 6 /* 0 means use internal decoder, 1 means UIOA >+ logic true is CT decode, 2 means UIOA logic >+ false is CT decode */ >+#define DAHDI_RADPAR_NUMTONES 7 /* returns maximum tone index (curently 15) */ >+#define DAHDI_RADPAR_INITTONE 8 /* init all tone indexes to 0 (no tones) */ >+#define DAHDI_RADPAR_RXTONE 9 /* CTCSS tone, (1-32) or DCS tone (1-777), >+ or 0 meaning no tone, set index also (1-15) */ >+#define DAHDI_RADPAR_RXTONECLASS 10 /* Tone class (0-65535), set index also (1-15) */ >+#define DAHDI_RADPAR_TXTONE 11 /* CTCSS tone (1-32) or DCS tone (1-777) or 0 >+ to indicate no tone, to transmit >+ for this tone index (0-32, 0 disables >+ transmit CTCSS), set index also (0-15) */ >+#define DAHDI_RADPAR_DEBOUNCETIME 12 /* receive indication debounce time, >+ milliseconds (1-999) */ >+#define DAHDI_RADPAR_BURSTTIME 13 /* end of transmit with no CT tone in >+ milliseconds (0-999) */ >+ >+ >+#define DAHDI_RADPAR_UIODATA 14 /* read/write UIOA and UIOB data. Bit 0 is >+ UIOA, bit 1 is UIOB */ >+#define DAHDI_RADPAR_UIOMODE 15 /* 0 means UIOA and UIOB are both outputs, 1 >+ means UIOA is input, UIOB is output, 2 >+ means UIOB is input and UIOA is output, >+ 3 means both UIOA and UIOB are inputs. Note >+ mode for UIOA is overridden when in >+ EXTRXTONE mode. */ >+ >+#define DAHDI_RADPAR_REMMODE 16 /* Remote control data mode */ >+ #define DAHDI_RADPAR_REM_NONE 0 /* no remote control data mode */ >+ #define DAHDI_RADPAR_REM_RBI1 1 /* Doug Hall RBI-1 data mode */ >+ #define DAHDI_RADPAR_REM_SERIAL 2 /* Serial Data, 9600 BPS */ >+ #define DAHDI_RADPAR_REM_SERIAL_ASCII 3 /* Serial Ascii Data, 9600 BPS */ >+ >+#define DAHDI_RADPAR_REMCOMMAND 17 /* Remote conrtol write data block & do cmd */ >+ >+#define DAHDI_RADPAR_DEEMP 18 /* Audio De-empahsis (on or off) */ >+ >+#define DAHDI_RADPAR_PREEMP 19 /* Audio Pre-empahsis (on or off) */ >+ >+#define DAHDI_RADPAR_RXGAIN 20 /* Audio (In to system) Rx Gain */ >+ >+#define DAHDI_RADPAR_TXGAIN 21 /* Audio (Out from system) Tx Gain */ >+ >+#define RAD_SERIAL_BUFLEN 128 >+ >+struct dahdi_radio_param { >+ unsigned short radpar; /* param identifier */ >+ unsigned short index; /* tone number */ >+ int data; /* param */ >+ int data2; /* param 2 */ >+ unsigned char buf[RAD_SERIAL_BUFLEN]; >+}; >+#define DAHDI_RADIO_GETPARAM _IOR(DAHDI_CODE, 58, struct dahdi_radio_param) >+#define DAHDI_RADIO_SETPARAM _IOW(DAHDI_CODE, 58, struct dahdi_radio_param) >+ >+ >+/*! >+ \brief Size-limited null-terminating string copy. >+ \param dst The destination buffer >+ \param src The source string >+ \param size The size of the destination buffer >+ \return Nothing. >+ >+ This is similar to \a strncpy, with two important differences: >+ - the destination buffer will \b always be null-terminated >+ - the destination buffer is not filled with zeros past the copied string length >+ These differences make it slightly more efficient, and safer to use since it will >+ not leave the destination buffer unterminated. There is no need to pass an artificially >+ reduced buffer size to this function (unlike \a strncpy), and the buffer does not need >+ to be initialized to zeroes prior to calling this function. >+*/ >+static inline void dahdi_copy_string(char *dst, const char *src, unsigned int size) >+{ >+ while (*src && size) { >+ *dst++ = *src++; >+ size--; >+ } >+ if (__builtin_expect(!size, 0)) >+ dst--; >+ *dst = '\0'; >+} >+ >+#endif /* _DAHDI_USER_H */ >diff -Naur dahdi-linux-2.2.0/drivers/dahdi/zaphfc/version.h dahdi-linux-2.2.0_zaphfc/drivers/dahdi/zaphfc/version.h >--- dahdi-linux-2.2.0/drivers/dahdi/zaphfc/version.h 1970-01-01 01:00:00.000000000 +0100 >+++ dahdi-linux-2.2.0_zaphfc/drivers/dahdi/zaphfc/version.h 2009-06-05 14:16:55.000000000 +0200 >@@ -0,0 +1,6 @@ >+/* >+ * version.h >+ * Automatically generated >+ */ >+#define DAHDI_VERSION "2.2.0-rc5" >+ >diff -Naur dahdi-linux-2.2.0/drivers/dahdi/zaphfc/wctdm_user.h dahdi-linux-2.2.0_zaphfc/drivers/dahdi/zaphfc/wctdm_user.h >--- dahdi-linux-2.2.0/drivers/dahdi/zaphfc/wctdm_user.h 1970-01-01 01:00:00.000000000 +0100 >+++ dahdi-linux-2.2.0_zaphfc/drivers/dahdi/zaphfc/wctdm_user.h 2009-06-05 12:56:39.000000000 +0200 >@@ -0,0 +1,68 @@ >+/* >+ * Wildcard S100P FXS Interface Driver for DAHDI Telephony interface >+ * >+ * Written by Mark Spencer <markster@digium.com> >+ * >+ * Copyright (C) 2001-2008, Digium, Inc. >+ * >+ * All rights reserved. >+ * >+ */ >+ >+/* >+ * See http://www.asterisk.org for more information about >+ * the Asterisk project. Please do not directly contact >+ * any of the maintainers of this project for assistance; >+ * the project provides a web site, mailing lists and IRC >+ * channels for your use. >+ * >+ * This program is free software, distributed under the terms of >+ * the GNU General Public License Version 2 as published by the >+ * Free Software Foundation. See the LICENSE file included with >+ * this program for more details. >+ */ >+ >+#ifndef _WCTDM_H >+#define _WCTDM_H >+ >+#include <linux/ioctl.h> >+ >+#define NUM_REGS 109 >+#define NUM_INDIRECT_REGS 105 >+ >+struct wctdm_stats { >+ int tipvolt; /* TIP voltage (mV) */ >+ int ringvolt; /* RING voltage (mV) */ >+ int batvolt; /* VBAT voltage (mV) */ >+}; >+ >+struct wctdm_regs { >+ unsigned char direct[NUM_REGS]; >+ unsigned short indirect[NUM_INDIRECT_REGS]; >+}; >+ >+struct wctdm_regop { >+ int indirect; >+ unsigned char reg; >+ unsigned short val; >+}; >+ >+struct wctdm_echo_coefs { >+ unsigned char acim; >+ unsigned char coef1; >+ unsigned char coef2; >+ unsigned char coef3; >+ unsigned char coef4; >+ unsigned char coef5; >+ unsigned char coef6; >+ unsigned char coef7; >+ unsigned char coef8; >+}; >+ >+#define WCTDM_GET_STATS _IOR (DAHDI_CODE, 60, struct wctdm_stats) >+#define WCTDM_GET_REGS _IOR (DAHDI_CODE, 61, struct wctdm_regs) >+#define WCTDM_SET_REG _IOW (DAHDI_CODE, 62, struct wctdm_regop) >+#define WCTDM_SET_ECHOTUNE _IOW (DAHDI_CODE, 63, struct wctdm_echo_coefs) >+ >+ >+#endif /* _WCTDM_H */ >diff -Naur dahdi-linux-2.2.0/drivers/dahdi/zaphfc/zaphfc.c dahdi-linux-2.2.0_zaphfc/drivers/dahdi/zaphfc/zaphfc.c >--- dahdi-linux-2.2.0/drivers/dahdi/zaphfc/zaphfc.c 1970-01-01 01:00:00.000000000 +0100 >+++ dahdi-linux-2.2.0_zaphfc/drivers/dahdi/zaphfc/zaphfc.c 2009-07-03 02:15:52.876129350 +0200 >@@ -0,0 +1,905 @@ >+/* >+ * 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> >+ * >+ * 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 General Public License. >+ * >+ */ >+ >+#include <linux/kernel.h> >+#include <linux/module.h> >+#include <linux/pci.h> >+#include <linux/init.h> >+#include <linux/interrupt.h> >+#include <linux/delay.h> >+#include "kernel.h" >+#include "zaphfc.h" >+ >+#include <linux/moduleparam.h> >+ >+#define log2(n) ffz(~(n)) >+ >+#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 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_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); >+ >+ /* Remove interrupt handler */ >+ free_irq(hfctmp->irq,hfctmp); >+} >+ >+void hfc_shutdownCard2(struct hfc_card *hfctmp) { >+ unsigned long flags; >+ >+ spin_lock_irqsave(&hfctmp->lock,flags); >+ >+ /* Reset pending interrupts */ >+ hfc_inb(hfctmp, hfc_INT_S1); >+ >+ /* 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->fifos != NULL) { >+ free_pages((unsigned long)hfctmp->fifos,log2(hfc_FIFO_MEM_SIZE_PAGES)); >+ } >+ 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); >+ 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; >+ >+ 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=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); >+ 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 ! */ >+ } >+ >+ 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; >+ 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 */ >+ hfctmp->regs.int_m2 |= hfc_M2_IRQ_ENABLE; >+ hfc_outb(hfctmp, hfc_INT_M2, hfctmp->regs.int_m2); >+ >+ /* 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); >+} >+ >+/*===========================================================================*/ >+ >+#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; >+ >+ chtmp->rx.f1.p=(u8 *)(hfctmp->fifos+hfc_FIFO_DRX_F1); >+ chtmp->rx.f2.v=0x1f; >+ chtmp->rx.f2.z2.v=0x1ff; >+ >+ 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_bch_init(struct hfc_card *hfctmp){ >+ struct bch *chtmp=&hfctmp->bch; >+ >+ chtmp->checkcnt=0; >+ chtmp->fill_fifo=0; >+ >+ 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; >+ >+ 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; >+ } >+ 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 >+ >+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); >+ } >+ if(!chtmp->fill_fifo) >+ for(x=0;x<2;x++)*chtmp->tx.c[x].z1p=chtmp->tx.z1; >+} >+ >+static void hfc_bch_rx(struct hfc_card *hfctmp){ >+ struct bch *chtmp=&hfctmp->bch; >+ int x; >+ >+ 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; >+ } >+ 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); >+ } >+} >+ >+/*===========================================================================*/ >+ >+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]); >+ } >+ printk("] %d bytes\n",hfctmp->ztdev->chans[2].bytes2transmit); >+ } >+ 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; >+ } >+ } >+ } >+} >+ >+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; >+ 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); >+ } >+} >+ >+DAHDI_IRQ_HANDLER(hfc_interrupt) { >+ struct hfc_card *hfctmp = dev_id; >+ struct hfc_card *hfctmp2; >+ struct dahdi_hfc *zthfc; >+ unsigned char stat, s1, s2, l1state; >+ unsigned long flags = 0; >+ unsigned long flags2 = 0; >+ int x; >+ >+ if (!hfctmp) { >+ return IRQ_NONE; >+ } >+ >+ if (!hfctmp->pci_io) { >+ printk(KERN_WARNING "%s: IO-mem disabled, cannot handle interrupt\n", >+ __FUNCTION__); >+ return IRQ_NONE; >+ } >+ >+ 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; >+ } >+ >+ 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: >+ sprintf(zthfc->span.desc, "HFC-S PCI A ISDN card %d [NT] layer 1 ACTIVATED (G%d)", hfctmp->cardno, l1state); >+ break; >+ default: >+ sprintf(zthfc->span.desc, "HFC-S PCI A ISDN card %d [NT] layer 1 DEACTIVATED (G%d)", hfctmp->cardno, l1state); >+ } >+ 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: >+ sprintf(zthfc->span.desc, "HFC-S PCI A ISDN card %d [TE] layer 1 ACTIVATED (F%d)", hfctmp->cardno, l1state); >+ break; >+ default: >+ sprintf(zthfc->span.desc, "HFC-S PCI A ISDN card %d [TE] layer 1 DEACTIVATED (F%d)", hfctmp->cardno, l1state); >+ } >+ 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 = 1; >+ // 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) >+ } >+ } >+ 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)&&(hfctmp->cardno==timer_card)){ >+ // processing/non-processing transition (bit 0) >+ 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_bch_tx(hfctmp); >+ hfc_dch_tx(hfctmp); >+ } >+ >+ hfc_bch_rx(hfctmp); >+ if (hfctmp->regs.int_drec) { >+ // dchan data to read >+ hfc_dch_rx(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)); >+ } >+ } >+ if(hfctmp!=hfctmp2)spin_unlock_irqrestore(&hfctmp->lock,flags2); >+ } >+ hfctmp=hfctmp->next; >+ } >+ hfctmp=hfctmp2; >+ } >+ } >+ spin_unlock_irqrestore(&hfctmp->lock,flags); >+ return IRQ_RETVAL(1); >+} >+ >+ >+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) 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; >+} >+ >+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) { >+ sprintf(zthfc->span.desc, "HFC-S PCI A ISDN card %d [NT]", hfc_dev_count + 1); >+ } else { >+ sprintf(zthfc->span.desc, "HFC-S PCI A ISDN card %d [TE]", hfc_dev_count + 1); >+ } >+ >+ 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; >+} >+ >+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 = vmalloc(sizeof(struct hfc_card)); >+ if (!hfctmp) { >+ printk(KERN_WARNING "zaphfc: unable to vmalloc!\n"); >+ pci_disable_device(tmp); >+ multi_hfc = NULL; >+ return -ENOMEM; >+ } >+ 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; >+ >+ 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"); >+ vfree(hfctmp); >+ pci_disable_device(tmp); >+ multi_hfc = NULL; >+ return -1; >+ } >+ >+ 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 { >+ pci_write_config_dword(hfctmp->pcidev, 0x80, (u_int) virt_to_bus(hfctmp->fifos)); >+ hfctmp->pci_io = ioremap((ulong) hfctmp->pci_io, 256); >+ } >+ >+ if (request_irq(hfctmp->irq, &hfc_interrupt, DAHDI_IRQ_SHARED, "zaphfc", hfctmp)) { >+ printk(KERN_WARNING "zaphfc: unable to register irq\n"); >+ 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; >+ } >+ >+ printk(KERN_INFO >+ "zaphfc: %s %s configured at mem %#x fifo %#x(%#x) IRQ %d HZ %d\n", >+ vendor_name, card_name, >+ (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 >+ 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; >+ } >+ >+ 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 vmalloc!\n"); >+ hfc_shutdownCard(hfctmp); >+ vfree(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; >+ 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; >+ } >+ 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++; >+ } >+ 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; >+ >+ 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_shutdownCard2(hfc_dev_list); >+ tmpcard = hfc_dev_list; >+ hfc_dev_list = hfc_dev_list->next; >+ if (tmpcard != NULL) { >+ vfree(tmpcard); >+ tmpcard = NULL; >+ printk(KERN_INFO "zaphfc: freed one card.\n"); >+ } >+ } >+// spin_unlock(®isterlock); >+} >+#endif >+ >+ >+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>"); >+#ifdef MODULE_LICENSE >+MODULE_LICENSE("GPL"); >+#endif >diff -Naur dahdi-linux-2.2.0/drivers/dahdi/zaphfc/zaphfc.c.orig dahdi-linux-2.2.0_zaphfc/drivers/dahdi/zaphfc/zaphfc.c.orig >--- dahdi-linux-2.2.0/drivers/dahdi/zaphfc/zaphfc.c.orig 1970-01-01 01:00:00.000000000 +0100 >+++ dahdi-linux-2.2.0_zaphfc/drivers/dahdi/zaphfc/zaphfc.c.orig 2009-06-05 15:48:20.000000000 +0200 >@@ -0,0 +1,1128 @@ >+/* >+ * 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 "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 >diff -Naur dahdi-linux-2.2.0/drivers/dahdi/zaphfc/zaphfc.h dahdi-linux-2.2.0_zaphfc/drivers/dahdi/zaphfc/zaphfc.h >--- dahdi-linux-2.2.0/drivers/dahdi/zaphfc/zaphfc.h 1970-01-01 01:00:00.000000000 +0100 >+++ dahdi-linux-2.2.0_zaphfc/drivers/dahdi/zaphfc/zaphfc.h 2009-07-03 02:15:52.873130303 +0200 >@@ -0,0 +1,344 @@ >+/* >+ * 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 >+#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 >+#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 >+ >+#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 { >+ 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 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; >+ unsigned char *pci_io; >+ 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; >+ int active; >+ struct bch bch; >+ struct dch dch; >+ 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; >+ >diff -Naur dahdi-linux-2.2.0/include/dahdi/dahdi_config.h dahdi-linux-2.2.0_zaphfc/include/dahdi/dahdi_config.h >--- dahdi-linux-2.2.0/include/dahdi/dahdi_config.h 2009-04-29 20:24:04.000000000 +0200 >+++ dahdi-linux-2.2.0_zaphfc/include/dahdi/dahdi_config.h 2009-07-03 02:15:47.961129522 +0200 >@@ -167,4 +167,10 @@ > */ > /* #define OPTIMIZE_CHANMUTE */ > >+/* >+ * Uncomment the following for BRI D channels >+ * >+ */ >+#define CONFIG_DAHDI_BRI_DCHANS >+ > #endif >diff -Naur dahdi-linux-2.2.0/include/dahdi/kernel.h dahdi-linux-2.2.0_zaphfc/include/dahdi/kernel.h >--- dahdi-linux-2.2.0/include/dahdi/kernel.h 2009-04-29 20:24:04.000000000 +0200 >+++ dahdi-linux-2.2.0_zaphfc/include/dahdi/kernel.h 2009-07-03 02:15:47.961129522 +0200 >@@ -389,6 +389,13 @@ > int statcount; > int lastnumbufs; > #endif >+#ifdef CONFIG_DAHDI_BRI_DCHANS >+ int bytes2receive; >+ int maxbytes2transmit; /* size of the tx buffer in the card driver */ >+ int bytes2transmit; >+ int eofrx; >+ int eoftx; >+#endif > spinlock_t lock; > char name[40]; > /* Specified by DAHDI */ >@@ -693,6 +700,9 @@ > 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 */ >@@ -731,6 +741,7 @@ > #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;
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 275635
:
196462
|
196464
| 196465 |
205113
|
205116
|
205118
|
205486
|
205487