diff options
author | tzafrir <tzafrir@5390a7c7-147a-4af0-8ec9-7488f05a26cb> | 2008-02-04 23:00:48 +0000 |
---|---|---|
committer | tzafrir <tzafrir@5390a7c7-147a-4af0-8ec9-7488f05a26cb> | 2008-02-04 23:00:48 +0000 |
commit | 7e068801fbf82413ac0a5e63e586c268bd457434 (patch) | |
tree | 9b61e9a4e07167e0b7d347e4336245724befa29c /zaptel-base.c | |
parent | 29daeebad888269fa0ee2ca7e54e238c8498ca2d (diff) |
Move kernel stuff to under kernel/
(merged branch /zaptel/team/tzafrir/move )
Closes issue #7117.
git-svn-id: http://svn.digium.com/svn/zaptel/branches/1.4@3793 5390a7c7-147a-4af0-8ec9-7488f05a26cb
Diffstat (limited to 'zaptel-base.c')
-rw-r--r-- | zaptel-base.c | 7451 |
1 files changed, 0 insertions, 7451 deletions
diff --git a/zaptel-base.c b/zaptel-base.c deleted file mode 100644 index 45b08f2..0000000 --- a/zaptel-base.c +++ /dev/null @@ -1,7451 +0,0 @@ -/* - * Zapata 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 zaptel 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 -2006 Digium, Inc. - * - * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - - -#include "zconfig.h" -#include "version.h" - -#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> -#ifdef CONFIG_DEVFS_FS -#include <linux/devfs_fs_kernel.h> -#endif /* CONFIG_DEVFS_FS */ -#ifdef CONFIG_ZAPATA_NET -#include <linux/netdevice.h> -#endif /* CONFIG_ZAPATA_NET */ -#include <linux/ppp_defs.h> -#ifdef CONFIG_ZAPATA_PPP -#include <linux/netdevice.h> -#include <linux/if.h> -#include <linux/if_ppp.h> -#endif -#include <asm/atomic.h> - -#ifndef CONFIG_OLD_HDLC_API -#define NEW_HDLC_INTERFACE -#endif - -#define __ECHO_STATE_MUTE (1 << 8) -#define ECHO_STATE_IDLE (0) -#define ECHO_STATE_PRETRAINING (1 | (__ECHO_STATE_MUTE)) -#define ECHO_STATE_STARTTRAINING (2 | (__ECHO_STATE_MUTE)) -#define ECHO_STATE_AWAITINGECHO (3 | (__ECHO_STATE_MUTE)) -#define ECHO_STATE_TRAINING (4 | (__ECHO_STATE_MUTE)) -#define ECHO_STATE_ACTIVE (5) - -/* #define BUF_MUNGE */ - -/* Grab fasthdlc with tables */ -#define FAST_HDLC_NEED_TABLES -#include "fasthdlc.h" - -#include "zaptel.h" - -#ifdef LINUX26 -#include <linux/moduleparam.h> -#endif - -/* Get helper arithmetic */ -#include "arith.h" -#if defined(CONFIG_ZAPTEL_MMX) || defined(ECHO_CAN_FP) -#include <asm/i387.h> -#endif - -#define hdlc_to_ztchan(h) (((struct zt_hdlc *)(h))->chan) -#define dev_to_ztchan(h) (((struct zt_hdlc *)(dev_to_hdlc(h)->priv))->chan) -#ifdef LINUX26 -#define ztchan_to_dev(h) ((h)->hdlcnetdev->netdev) -#else -#define ztchan_to_dev(h) (&((h)->hdlcnetdev->netdev.netdev)) -#endif - -/* 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 *zt_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(zt_transcode_fops); -EXPORT_SYMBOL(zt_init_tone_state); -EXPORT_SYMBOL(zt_dtmf_tone); -EXPORT_SYMBOL(zt_register); -EXPORT_SYMBOL(zt_unregister); -EXPORT_SYMBOL(__zt_mulaw); -EXPORT_SYMBOL(__zt_alaw); -#ifdef CONFIG_CALC_XLAW -EXPORT_SYMBOL(__zt_lineartoulaw); -EXPORT_SYMBOL(__zt_lineartoalaw); -#else -EXPORT_SYMBOL(__zt_lin2mu); -EXPORT_SYMBOL(__zt_lin2a); -#endif -EXPORT_SYMBOL(zt_lboname); -EXPORT_SYMBOL(zt_transmit); -EXPORT_SYMBOL(zt_receive); -EXPORT_SYMBOL(zt_rbsbits); -EXPORT_SYMBOL(zt_qevent_nolock); -EXPORT_SYMBOL(zt_qevent_lock); -EXPORT_SYMBOL(zt_hooksig); -EXPORT_SYMBOL(zt_alarm_notify); -EXPORT_SYMBOL(zt_set_dynamic_ioctl); -EXPORT_SYMBOL(zt_ec_chunk); -EXPORT_SYMBOL(zt_ec_span); -EXPORT_SYMBOL(zt_hdlc_abort); -EXPORT_SYMBOL(zt_hdlc_finish); -EXPORT_SYMBOL(zt_hdlc_getbuf); -EXPORT_SYMBOL(zt_hdlc_putbuf); -EXPORT_SYMBOL(zt_alarm_channel); -EXPORT_SYMBOL(zt_register_chardev); -EXPORT_SYMBOL(zt_unregister_chardev); - -#ifdef CONFIG_PROC_FS -static struct proc_dir_entry *proc_entries[ZT_MAX_SPANS]; -#endif - -/* Here are a couple important little additions for devfs */ -#ifdef CONFIG_DEVFS_FS -#define ZT_DEVFS_MODE (S_IFCHR|S_IRUGO|S_IWUGO) -static devfs_handle_t zaptel_devfs_dir; -static devfs_handle_t channel; -static devfs_handle_t pseudo; -static devfs_handle_t ctl; -static devfs_handle_t timer; -#endif - -/* udev necessary data structures. Yeah! */ -#ifdef CONFIG_ZAP_UDEV - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,15) -#define CLASS_DEV_CREATE(class, devt, device, name) \ - class_device_create(class, NULL, devt, device, name) -#else -#define CLASS_DEV_CREATE(class, devt, device, name) \ - class_device_create(class, devt, device, name) -#endif - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,13) -static struct class *zap_class = NULL; -#else -static struct class_simple *zap_class = NULL; -#define class_create class_simple_create -#define class_destroy class_simple_destroy -#define class_device_create class_simple_device_add -#define class_device_destroy(a, b) class_simple_device_remove(b) -#endif - -#endif /* CONFIG_ZAP_UDEV */ - - -/* There is a table like this in the PPP driver, too */ - -static int deftaps = 64; - -#if !defined(LINUX26) -static -__u16 fcstab[256] = -{ - 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf, - 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7, - 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e, - 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876, - 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd, - 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5, - 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c, - 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974, - 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb, - 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3, - 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a, - 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72, - 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9, - 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1, - 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738, - 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70, - 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7, - 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff, - 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036, - 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e, - 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5, - 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd, - 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134, - 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c, - 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3, - 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb, - 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232, - 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a, - 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1, - 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9, - 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330, - 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78 -}; -#endif - -static int debug; - -/* states for transmit signalling */ -typedef enum {ZT_TXSTATE_ONHOOK,ZT_TXSTATE_OFFHOOK,ZT_TXSTATE_START, - ZT_TXSTATE_PREWINK,ZT_TXSTATE_WINK,ZT_TXSTATE_PREFLASH, - ZT_TXSTATE_FLASH,ZT_TXSTATE_DEBOUNCE,ZT_TXSTATE_AFTERSTART, - ZT_TXSTATE_RINGON,ZT_TXSTATE_RINGOFF,ZT_TXSTATE_KEWL, - ZT_TXSTATE_AFTERKEWL,ZT_TXSTATE_PULSEBREAK,ZT_TXSTATE_PULSEMAKE, - ZT_TXSTATE_PULSEAFTER - } ZT_TXSTATE_t; - -typedef short sumtype[ZT_MAX_CHUNKSIZE]; - -static sumtype sums[(ZT_MAX_CONF + 1) * 3]; - -/* Translate conference aliases into actual conferences - and vice-versa */ -static short confalias[ZT_MAX_CONF + 1]; -static short confrev[ZT_MAX_CONF + 1]; - -static sumtype *conf_sums_next; -static sumtype *conf_sums; -static sumtype *conf_sums_prev; - -static struct zt_span *master; -static struct file_operations zt_fops; -struct file_operations *zt_transcode_fops = NULL; - -static struct -{ - int src; /* source conf number */ - int dst; /* dst conf number */ -} conf_links[ZT_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). - -*/ - -#define DIGIT_MODE_DTMF 0 -#define DIGIT_MODE_MFV1 1 -#define DIGIT_MODE_PULSE 2 - -#include "digits.h" - -static struct zt_dialparams global_dialparams = { - .dtmf_tonelen = DEFAULT_DTMF_LENGTH, - .mfv1_tonelen = DEFAULT_MFV1_LENGTH, -}; - -static int zt_chan_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long data, int unit); - -#if defined(CONFIG_ZAPTEL_MMX) || defined(ECHO_CAN_FP) -/* XXX kernel_fpu_begin() is NOT exported properly (in 2.4), so we have to make - a local version. Somebody fix this! XXX */ - -#ifndef LINUX26 -static inline void __save_init_fpu( struct task_struct *tsk ) -{ - if ( cpu_has_fxsr ) { - asm volatile( "fxsave %0 ; fnclex" - : "=m" (tsk->thread.i387.fxsave) ); - } else { - asm volatile( "fnsave %0 ; fwait" - : "=m" (tsk->thread.i387.fsave) ); - } - tsk->flags &= ~PF_USEDFPU; -} - -static inline void zt_kernel_fpu_begin(void) -{ - struct task_struct *tsk = current; - if (tsk->flags & PF_USEDFPU) { - __save_init_fpu(tsk); - return; - } - clts(); -} -#else -#define zt_kernel_fpu_begin kernel_fpu_begin -#endif /* LINUX26 */ -#endif - -static struct zt_timer { - int ms; /* Countdown */ - int pos; /* Position */ - int ping; /* Whether we've been ping'd */ - int tripped; /* Whether we're tripped */ - struct zt_timer *next; /* Linked list */ - wait_queue_head_t sel; -} *zaptimers = NULL; - -#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 zt_zone { - atomic_t refcount; - char name[40]; /* Informational, only */ - int ringcadence[ZT_MAX_CADENCE]; - struct zt_tone *tones[ZT_TONE_MAX]; - /* Each of these is a circular list - of zt_tones to generate what we - want. Use NULL if the tone is - unavailable */ - struct zt_tone dtmf[16]; /* DTMF tones for this zone, with desired length */ - struct zt_tone dtmf_continuous[16]; /* DTMF tones for this zone, continuous play */ - struct zt_tone mf[15]; /* MF tones for this zone, with desired length */ - struct zt_tone mf_continuous[15]; /* MF tones for this zone, continuous play */ -}; - -static struct zt_span *spans[ZT_MAX_SPANS]; -static struct zt_chan *chans[ZT_MAX_CHANNELS]; - -static int maxspans = 0; -static int maxchans = 0; -static int maxconfs = 0; -static int maxlinks = 0; - -static int default_zone = -1; - -short __zt_mulaw[256]; -short __zt_alaw[256]; - -#ifndef CONFIG_CALC_XLAW -u_char __zt_lin2mu[16384]; - -u_char __zt_lin2a[16384]; -#endif - -static u_char defgain[256]; - -#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 zt_zone *tone_zones[ZT_TONE_ZONE_MAX]; - -#define NUM_SIGS 10 - - -/* Echo cancellation */ -#if defined(ECHO_CAN_HPEC) -#include "hpec/hpec_zaptel.h" -#elif defined(ECHO_CAN_STEVE) -#include "sec.h" -#elif defined(ECHO_CAN_STEVE2) -#include "sec-2.h" -#elif defined(ECHO_CAN_KB1) -#include "kb1ec.h" -#elif defined(ECHO_CAN_MG2) -#include "mg2ec.h" -#elif defined(ECHO_CAN_JP1) -#include "jpah.h" -#endif - -static inline void rotate_sums(void) -{ - /* Rotate where we sum and so forth */ - static int pos = 0; - conf_sums_prev = sums + (ZT_MAX_CONF + 1) * pos; - conf_sums = sums + (ZT_MAX_CONF + 1) * ((pos + 1) % 3); - conf_sums_next = sums + (ZT_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 zt_q_sig(struct zt_chan *chan) -{ -int x; - -static unsigned int in_sig[NUM_SIGS][2] = { - { ZT_SIG_NONE, 0}, - { ZT_SIG_EM, 0 | (ZT_ABIT << 8)}, - { ZT_SIG_FXSLS,ZT_BBIT | (ZT_BBIT << 8)}, - { ZT_SIG_FXSGS,ZT_ABIT | ZT_BBIT | ((ZT_ABIT | ZT_BBIT) << 8)}, - { ZT_SIG_FXSKS,ZT_BBIT | ZT_BBIT | ((ZT_ABIT | ZT_BBIT) << 8)}, - { ZT_SIG_FXOLS,0 | (ZT_ABIT << 8)}, - { ZT_SIG_FXOGS,ZT_BBIT | ((ZT_ABIT | ZT_BBIT) << 8)}, - { ZT_SIG_FXOKS,0 | (ZT_ABIT << 8)}, - { ZT_SIG_SF, 0}, - { ZT_SIG_EM_E1, ZT_DBIT | ((ZT_ABIT | ZT_DBIT) << 8) }, - } ; - - /* must have span to begin with */ - if (!chan->span) return(-1); - /* if RBS does not apply, return error */ - if (!(chan->span->flags & ZT_FLAG_RBS) || - !chan->span->rbsbits) return(-1); - if (chan->sig == ZT_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 char *sigstr(int sig) -{ - switch (sig) { - case ZT_SIG_FXSLS: - return "FXSLS"; - case ZT_SIG_FXSKS: - return "FXSKS"; - case ZT_SIG_FXSGS: - return "FXSGS"; - case ZT_SIG_FXOLS: - return "FXOLS"; - case ZT_SIG_FXOKS: - return "FXOKS"; - case ZT_SIG_FXOGS: - return "FXOGS"; - case ZT_SIG_EM: - return "E&M"; - case ZT_SIG_EM_E1: - return "E&M-E1"; - case ZT_SIG_CLEAR: - return "Clear"; - case ZT_SIG_HDLCRAW: - return "HDLCRAW"; - case ZT_SIG_HDLCFCS: - return "HDLCFCS"; - case ZT_SIG_HDLCNET: - return "HDLCNET"; - case ZT_SIG_HARDHDLC: - return "Hardware-assisted HDLC"; - case ZT_SIG_SLAVE: - return "Slave"; - case ZT_SIG_CAS: - return "CAS"; - case ZT_SIG_DACS: - return "DACS"; - case ZT_SIG_DACS_RBS: - return "DACS+RBS"; - case ZT_SIG_SF: - return "SF (ToneOnly)"; - case ZT_SIG_NONE: - default: - return "Unconfigured"; - } - -} - -static int zaptel_proc_read(char *page, char **start, off_t off, int count, int *eof, void *data) -{ - int x, len = 0; - long span; - - /* In Linux 2.6, this MUST NOT EXECEED 1024 bytes in one read! */ - - span = (long)data; - - if (!span) - return 0; - - if (spans[span]->name) - len += sprintf(page + len, "Span %ld: %s ", span, spans[span]->name); - if (spans[span]->desc) - len += sprintf(page + len, "\"%s\"", spans[span]->desc); - else - len += sprintf(page + len, "\"\""); - - if(spans[span] == master) - len += sprintf(page + len, " (MASTER)"); - - if (spans[span]->lineconfig) { - /* framing first */ - if (spans[span]->lineconfig & ZT_CONFIG_B8ZS) - len += sprintf(page + len, " B8ZS/"); - else if (spans[span]->lineconfig & ZT_CONFIG_AMI) - len += sprintf(page + len, " AMI/"); - else if (spans[span]->lineconfig & ZT_CONFIG_HDB3) - len += sprintf(page + len, " HDB3/"); - /* then coding */ - if (spans[span]->lineconfig & ZT_CONFIG_ESF) - len += sprintf(page + len, "ESF"); - else if (spans[span]->lineconfig & ZT_CONFIG_D4) - len += sprintf(page + len, "D4"); - else if (spans[span]->lineconfig & ZT_CONFIG_CCS) - len += sprintf(page + len, "CCS"); - /* E1's can enable CRC checking */ - if (spans[span]->lineconfig & ZT_CONFIG_CRC4) - len += sprintf(page + len, "/CRC4"); - } - - len += sprintf(page + len, " "); - - /* list alarms */ - if (spans[span]->alarms && (spans[span]->alarms > 0)) { - if (spans[span]->alarms & ZT_ALARM_BLUE) - len += sprintf(page + len, "BLUE "); - if (spans[span]->alarms & ZT_ALARM_YELLOW) - len += sprintf(page + len, "YELLOW "); - if (spans[span]->alarms & ZT_ALARM_RED) - len += sprintf(page + len, "RED "); - if (spans[span]->alarms & ZT_ALARM_LOOPBACK) - len += sprintf(page + len, "LOOP "); - if (spans[span]->alarms & ZT_ALARM_RECOVER) - len += sprintf(page + len, "RECOVERING "); - if (spans[span]->alarms & ZT_ALARM_NOTOPEN) - len += sprintf(page + len, "NOTOPEN "); - - } - if (spans[span]->syncsrc && (spans[span]->syncsrc == spans[span]->spanno)) - len += sprintf(page + len, "ClockSource "); - len += sprintf(page + len, "\n"); - if (spans[span]->bpvcount) - len += sprintf(page + len, "\tBPV count: %d\n", spans[span]->bpvcount); - if (spans[span]->crc4count) - len += sprintf(page + len, "\tCRC4 error count: %d\n", spans[span]->crc4count); - if (spans[span]->ebitcount) - len += sprintf(page + len, "\tE-bit error count: %d\n", spans[span]->ebitcount); - if (spans[span]->fascount) - len += sprintf(page + len, "\tFAS error count: %d\n", spans[span]->fascount); - if (spans[span]->irqmisses) - len += sprintf(page + len, "\tIRQ misses: %d\n", spans[span]->irqmisses); - if (spans[span]->timingslips) - len += sprintf(page + len, "\tTiming slips: %d\n", spans[span]->timingslips); - len += sprintf(page + len, "\n"); - - - for (x=1;x<ZT_MAX_CHANNELS;x++) { - if (chans[x]) { - if (chans[x]->span && (chans[x]->span->spanno == span)) { - if (chans[x]->name) - len += sprintf(page + len, "\t%4d %s ", x, chans[x]->name); - if (chans[x]->sig) { - if (chans[x]->sig == ZT_SIG_SLAVE) - len += sprintf(page + len, "%s ", sigstr(chans[x]->master->sig)); - else { - len += sprintf(page + len, "%s ", sigstr(chans[x]->sig)); - if (chans[x]->nextslave && chans[x]->master->channo == x) - len += sprintf(page + len, "Master "); - } - } - if ((chans[x]->flags & ZT_FLAG_OPEN)) { - len += sprintf(page + len, "(In use) "); - } -#ifdef OPTIMIZE_CHANMUTE - if ((chans[x]->chanmute)) { - len += sprintf(page + len, "(no pcm) "); - } -#endif - len += sprintf(page + len, "\n"); - } - if (len <= off) { /* If everything printed so far is before beginning of request */ - off -= len; - len = 0; - } - if (len > off+count) /* stop if we've already generated enough */ - break; - } - } - if (len <= off) { /* If everything printed so far is before beginning of request */ - off -= len; - len = 0; - } - *start = page + off; - len -= off; /* un-count any remaining offset */ - if (len > count) len = count; /* don't return bytes not asked for */ - return len; -} -#endif - -static int zt_first_empty_alias(void) -{ - /* Find the first conference which has no alias pointing to it */ - int x; - for (x=1;x<ZT_MAX_CONF;x++) { - if (!confrev[x]) - return x; - } - return -1; -} - -static void recalc_maxconfs(void) -{ - int x; - for (x=ZT_MAX_CONF-1;x>0;x--) { - if (confrev[x]) { - maxconfs = x+1; - return; - } - } - maxconfs = 0; -} - -static void recalc_maxlinks(void) -{ - int x; - for (x=ZT_MAX_CONF-1;x>0;x--) { - if (conf_links[x].src || conf_links[x].dst) { - maxlinks = x+1; - return; - } - } - maxlinks = 0; -} - -static int zt_first_empty_conference(void) -{ - /* Find the first conference which has no alias */ - int x; - for (x=ZT_MAX_CONF-1;x>0;x--) { - if (!confalias[x]) - return x; - } - return -1; -} - -static int zt_get_conf_alias(int x) -{ - int a; - if (confalias[x]) { - return confalias[x]; - } - - /* Allocate an alias */ - a = zt_first_empty_alias(); - confalias[x] = a; - confrev[a] = x; - - /* Highest conference may have changed */ - recalc_maxconfs(); - return a; -} - -static void zt_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 & ZT_CONF_MODE_MASK) == ZT_CONF_CONF || - (chans[y]->confmode & ZT_CONF_MODE_MASK) == ZT_CONF_CONFANN || - (chans[y]->confmode & ZT_CONF_MODE_MASK) == ZT_CONF_CONFMON || - (chans[y]->confmode & ZT_CONF_MODE_MASK) == ZT_CONF_CONFANNMON || - (chans[y]->confmode & ZT_CONF_MODE_MASK) == ZT_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 zt_chan *chan, int event) -{ - - /* if full, ignore */ - if ((chan->eventoutidx == 0) && (chan->eventinidx == (ZT_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 >= ZT_MAX_EVENTSIZE) chan->eventinidx = 0; - /* wake em all up */ - if (chan->iomask & ZT_IOMUX_SIGEVENT) wake_up_interruptible(&chan->eventbufq); - wake_up_interruptible(&chan->readbufq); - wake_up_interruptible(&chan->writebufq); - wake_up_interruptible(&chan->sel); - return; -} - -void zt_qevent_nolock(struct zt_chan *chan, int event) -{ - __qevent(chan, event); -} - -void zt_qevent_lock(struct zt_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 zt_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 zt_reallocbufs(struct zt_chan *ss, int j, int numbufs) -{ - unsigned char *newbuf, *oldbuf; - unsigned long flags; - int x; - /* Check numbufs */ - if (numbufs < 2) - numbufs = 2; - if (numbufs > ZT_MAX_NUM_BUFS) - numbufs = ZT_MAX_NUM_BUFS; - /* We need to allocate our buffers now */ - if (j) { - newbuf = kmalloc(j * 2 * numbufs, GFP_KERNEL); - if (!newbuf) - 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 == ZT_POLICY_WHEN_FULL) - ss->txdisable = 1; - else - ss->txdisable = 0; - - if (ss->rxbufpolicy == ZT_POLICY_WHEN_FULL) - ss->rxdisable = 1; - else - ss->rxdisable = 0; - - spin_unlock_irqrestore(&ss->lock, flags); - if (oldbuf) - kfree(oldbuf); - return 0; -} - -static int zt_hangup(struct zt_chan *chan); -static void zt_set_law(struct zt_chan *chan, int law); - -/* Pull a ZT_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 zt_chan *c, char *label) -{ - int oldoutbuf = q->outbuf; - /* Ain't nuffin to read */ - if (q->outbuf < 0) { - if (data) - memset(data, ZT_LIN2X(0,c), ZT_CHUNKSIZE); - return -1; - } - if (data) - memcpy(data, q->buf[q->outbuf], ZT_CHUNKSIZE); - q->outbuf = (q->outbuf + 1) % ZT_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 += ZT_CB_SIZE; - return q->buf[pos]; -} - -static void __buf_munge(struct zt_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<ZT_CHUNKSIZE;x++) { - val = x * ZT_XLAW(new[x], chan) + (ZT_CHUNKSIZE - x - 1) * ZT_XLAW(old[x], chan); - val = val / (ZT_CHUNKSIZE - 1); - old[x] = ZT_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, ZT_CHUNKSIZE); - - /* Advance the inbuf pointer */ - q->inbuf = (q->inbuf + 1) % ZT_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 zt_chan *chan) -{ - int x; - /* Empty out buffers and reset to initialization */ - for (x=0;x<ZT_CB_SIZE;x++) - chan->confin.buf[x] = chan->confin.buffer + ZT_CHUNKSIZE * x; - chan->confin.inbuf = 0; - chan->confin.outbuf = -1; - - for (x=0;x<ZT_CB_SIZE;x++) - chan->confout.buf[x] = chan->confout.buffer + ZT_CHUNKSIZE * x; - chan->confout.inbuf = 0; - chan->confout.outbuf = -1; -} - - -static void close_channel(struct zt_chan *chan) -{ - unsigned long flags; - void *rxgain = NULL; - struct echo_can_state *ec = NULL; - int oldconf; - short *readchunkpreec; -#ifdef CONFIG_ZAPATA_PPP - struct ppp_channel *ppp; -#endif - - /* XXX Buffers should be send out before reallocation!!! XXX */ - if (!(chan->flags & ZT_FLAG_NOSTDTXRX)) - zt_reallocbufs(chan, 0, 0); - spin_lock_irqsave(&chan->lock, flags); -#ifdef CONFIG_ZAPATA_PPP - ppp = chan->ppp; - chan->ppp = NULL; -#endif - ec = chan->ec; - chan->ec = 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; - zt_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 & __ZT_SIG_DACS) != __ZT_SIG_DACS) { - chan->confna = 0; - chan->confmode = 0; - } - chan->confmute = 0; - /* release conference resource, if any to release */ - if (oldconf) zt_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 &= ~(ZT_FLAG_LOOPED | ZT_FLAG_LINEAR | ZT_FLAG_PPP | ZT_FLAG_SIGFREEZE); - - zt_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); - - spin_unlock_irqrestore(&chan->lock, flags); - - if (chan->span && chan->span->echocan) - chan->span->echocan(chan, 0); - - if (rxgain) - kfree(rxgain); - if (ec) - echo_can_free(ec); - if (readchunkpreec) - kfree(readchunkpreec); - -#ifdef CONFIG_ZAPATA_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 zt_zone *z; - - if ((num >= ZT_TONE_ZONE_MAX) || (num < 0)) - return -EINVAL; - - write_lock(&zone_lock); - z = tone_zones[num]; - tone_zones[num] = NULL; - write_unlock(&zone_lock); - if (!z) - return 0; - - if (atomic_read(&z->refcount)) { - /* channels are still using this zone so put it back */ - write_lock(&zone_lock); - tone_zones[num] = z; - write_unlock(&zone_lock); - - return -EBUSY; - } else { - kfree(z); - - return 0; - } -} - -static int zt_register_tone_zone(int num, struct zt_zone *zone) -{ - int res = 0; - - if ((num >= ZT_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) - printk(KERN_INFO "Registered tone zone %d (%s)\n", num, zone->name); - - return res; -} - -static int start_tone(struct zt_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 ((tone >= 0 && tone <= ZT_TONE_MAX)) { - if (chan->curzone) { - /* 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 /* Note that no tone zone exists at the moment */ - res = -ENODATA; - } else if (tone >= ZT_TONE_DTMF_BASE && tone <= ZT_TONE_DTMF_MAX) { - /* ZT_SENDTONE should never be used on a channel configured for pulse dialing */ - chan->dialing = 1; - res = 0; - if ((chan->digitmode == DIGIT_MODE_DTMF) && - (tone >= ZT_TONE_DTMF_BASE) && - (tone <= ZT_TONE_DTMF_MAX)) - chan->curtone = &chan->curzone->dtmf_continuous[tone - ZT_TONE_DTMF_BASE]; - else if ((chan->digitmode == DIGIT_MODE_MFV1) && - (tone >= ZT_TONE_MF_BASE) && - (tone <= ZT_TONE_MF_MAX)) - chan->curtone = &chan->curzone->mf_continuous[tone - ZT_TONE_MF_BASE]; - else { - chan->dialing = 0; - res = -EINVAL; - } - } - - if (chan->curtone) - zt_init_tone_state(&chan->ts, chan->curtone); - - return res; -} - -static int set_tone_zone(struct zt_chan *chan, int zone) -{ - int res = 0; - struct zt_zone *z; - unsigned long flags; - - /* Do not call with the channel locked. */ - - if (zone == -1) - zone = default_zone; - - if ((zone >= ZT_TONE_ZONE_MAX) || (zone < 0)) - return -EINVAL; - - read_lock(&zone_lock); - - if ((z = tone_zones[zone])) { - 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 zt_set_law(struct zt_chan *chan, int law) -{ - if (!law) { - if (chan->deflaw) - law = chan->deflaw; - else - if (chan->span) law = chan->span->deflaw; - else law = ZT_LAW_MULAW; - } - if (law == ZT_LAW_ALAW) { - chan->xlaw = __zt_alaw; -#ifdef CONFIG_CALC_XLAW - chan->lineartoxlaw = __zt_lineartoalaw; -#else - chan->lin2x = __zt_lin2a; -#endif - } else { - chan->xlaw = __zt_mulaw; -#ifdef CONFIG_CALC_XLAW - chan->lineartoxlaw = __zt_lineartoulaw; -#else - chan->lin2x = __zt_lin2mu; -#endif - } -} - -#ifdef CONFIG_DEVFS_FS -static devfs_handle_t register_devfs_channel(struct zt_chan *chan, devfs_handle_t dir) -{ - char path[100]; - char link[100]; - char buf[50]; - char tmp[100]; - int link_offset = 0; - int tmp_offset = 0; - int path_offset = 0; - int err = 0; - devfs_handle_t chan_dev; - umode_t mode = S_IFCHR|S_IRUGO|S_IWUGO; - unsigned int flags = DEVFS_FL_AUTO_OWNER; - - sprintf(path, "%d", chan->chanpos); - chan_dev = devfs_register(dir, path, flags, ZT_MAJOR, chan->channo, mode, &zt_fops, NULL); - if (!chan_dev) { - printk("zaptel: Something really bad happened. Unable to register devfs entry\n"); - return NULL; - } - - /* Set up the path of the destination of the link */ - link_offset = devfs_generate_path(chan_dev, link, sizeof(link) - 1); - /* Now we need to strip off the leading "zap/". If we don't, then we build a broken symlink */ - path_offset = devfs_generate_path(zaptel_devfs_dir, path, sizeof(path) - 1); /* We'll just "borrow" path for a second */ - path_offset = strlen(path+path_offset); - link_offset += path_offset; /* Taking out the "zap" */ - link_offset++; /* Add one more place for the '/'. The path generated does not contain the '/' we need to strip */ - - /* Set up the path of the file/link itself */ - tmp_offset = devfs_generate_path(zaptel_devfs_dir, tmp, sizeof(tmp) - 1); - sprintf(buf, "/%d", chan->channo); - strncpy(path, tmp+tmp_offset, sizeof(path) - 1); - strncat(path, buf, sizeof(path) - 1); - - err = devfs_mk_symlink(NULL, path, DEVFS_FL_DEFAULT, link+link_offset, &chan->fhandle_symlink, NULL); - if (err != 0) { - printk("Problem with making devfs symlink: %d\n", err); - } - - return chan_dev; -} -#endif /* CONFIG_DEVFS_FS */ - -static int zt_chan_reg(struct zt_chan *chan) -{ - int x; - int res=0; - unsigned long flags; - - write_lock_irqsave(&chan_lock, flags); - for (x=1;x<ZT_MAX_CHANNELS;x++) { - if (!chans[x]) { - spin_lock_init(&chan->lock); - chans[x] = chan; - if (maxchans < x + 1) - maxchans = x + 1; - chan->channo = x; - if (!chan->master) - chan->master = chan; - if (!chan->readchunk) - chan->readchunk = chan->sreadchunk; - if (!chan->writechunk) - chan->writechunk = chan->swritechunk; - zt_set_law(chan, 0); - close_channel(chan); - /* set this AFTER running close_channel() so that - HDLC channels wont cause hangage */ - chan->flags |= ZT_FLAG_REGISTERED; - res = 0; - break; - } - } - write_unlock_irqrestore(&chan_lock, flags); - if (x >= ZT_MAX_CHANNELS) - printk(KERN_ERR "No more channels available\n"); - return res; -} - -char *zt_lboname(int x) -{ - if ((x < 0) || ( x > 7)) - return "Unknown"; - return zt_txlevelnames[x]; -} - -#if defined(CONFIG_ZAPATA_NET) || defined(CONFIG_ZAPATA_PPP) -#endif - -#ifdef CONFIG_ZAPATA_NET -#ifdef NEW_HDLC_INTERFACE -static int zt_net_open(struct net_device *dev) -{ -#ifdef LINUX26 - int res = hdlc_open(dev); - struct zt_chan *ms = dev_to_ztchan(dev); -#else - hdlc_device *hdlc = dev_to_hdlc(dev); - struct zt_chan *ms = hdlc_to_ztchan(hdlc); - int res = hdlc_open(hdlc); -#endif - -/* 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 zt_net_open(hdlc_device *hdlc) -{ - struct zt_chan *ms = hdlc_to_ztchan(hdlc); - int res; -#endif - if (!ms) { - printk("zt_net_open: nothing??\n"); - return -EINVAL; - } - if (ms->flags & ZT_FLAG_OPEN) { - printk("%s is already open!\n", ms->name); - return -EBUSY; - } - if (!(ms->flags & ZT_FLAG_NETDEV)) { - printk("%s is not a net device!\n", ms->name); - return -EINVAL; - } - ms->txbufpolicy = ZT_POLICY_IMMEDIATE; - ms->rxbufpolicy = ZT_POLICY_IMMEDIATE; - - res = zt_reallocbufs(ms, ZT_DEFAULT_MTU_MRU, ZT_DEFAULT_NUM_BUFS); - if (res) - return res; - - fasthdlc_init(&ms->rxhdlc); - fasthdlc_init(&ms->txhdlc); - ms->infcs = PPP_INITFCS; - - netif_start_queue(ztchan_to_dev(ms)); - -#ifndef LINUX26 - MOD_INC_USE_COUNT; -#endif -#ifdef CONFIG_ZAPATA_DEBUG - printk("ZAPNET: Opened channel %d name %s\n", ms->channo, ms->name); -#endif - return 0; -} - -#ifdef LINUX26 -static int zt_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; -} -#endif - -#ifdef NEW_HDLC_INTERFACE -static int zt_net_stop(struct net_device *dev) -{ -#ifdef LINUX26 - hdlc_device *h = dev_to_hdlc(dev); - struct zt_hdlc *hdlc = h->priv; -#else - hdlc_device *hdlc = dev_to_hdlc(dev); -#endif - -#else -static void zt_net_close(hdlc_device *hdlc) -{ -#endif - struct zt_chan *ms = hdlc_to_ztchan(hdlc); - if (!ms) { -#ifdef NEW_HDLC_INTERFACE - printk("zt_net_stop: nothing??\n"); - return 0; -#else - printk("zt_net_close: nothing??\n"); - return; -#endif - } - if (!(ms->flags & ZT_FLAG_NETDEV)) { -#ifdef NEW_HDLC_INTERFACE - printk("zt_net_stop: %s is not a net device!\n", ms->name); - return 0; -#else - printk("zt_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)); - zt_reallocbufs(ms, 0, 0); -#ifdef LINUX26 - hdlc_close(dev); -#else -#ifndef CONFIG_OLD_HDLC_API - hdlc_close(hdlc); -#endif -#endif -#ifndef LINUX26 - MOD_DEC_USE_COUNT; -#endif -#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 */ -#ifdef LINUX26 -static int zt_net_attach(struct net_device *dev, unsigned short encoding, - unsigned short parity) -#else -static int zt_net_attach(hdlc_device *hdlc, unsigned short encoding, - unsigned short parity) -#endif -{ -/* 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 zt_hdlc *zt_hdlc_alloc(void) -{ - struct zt_hdlc *tmp; - tmp = kmalloc(sizeof(struct zt_hdlc), GFP_KERNEL); - if (tmp) { - memset(tmp, 0, sizeof(struct zt_hdlc)); - } - return tmp; -} - -#ifdef NEW_HDLC_INTERFACE -static int zt_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 zt_chan *ss = hdlc_to_ztchan(list_entry(dev, struct zt_hdlc, netdev.netdev));*/ -#ifdef LINUX26 - struct zt_chan *ss = dev_to_ztchan(dev); - struct net_device_stats *stats = hdlc_stats(dev); -#else - struct zt_chan *ss = (list_entry(dev, struct zt_hdlc, netdev.netdev)->chan); - struct net_device_stats *stats = &ss->hdlcnetdev->netdev.stats; -#endif - -#else -static int zt_xmit(hdlc_device *hdlc, struct sk_buff *skb) -{ - struct zt_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) { - printk(KERN_ERR "zt_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]; -#ifdef CONFIG_ZAPATA_DEBUG - printk("Buffered %d bytes to go out in buffer %d\n", ss->writen[oldbuf], oldbuf); - for (x=0;x<ss->writen[oldbuf];x++) - printk("%02x ", ss->writebuf[oldbuf][x]); - printk("\n"); -#endif - retval = 0; - /* Free the SKB */ - dev_kfree_skb_any(skb); - } - spin_unlock_irqrestore(&ss->lock, flags); - return retval; -} - -#ifdef NEW_HDLC_INTERFACE -static int zt_net_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) -{ - return hdlc_ioctl(dev, ifr, cmd); -} -#else -static int zt_net_ioctl(hdlc_device *hdlc, struct ifreq *ifr, int cmd) -{ - return -EIO; -} -#endif - -#endif - -#ifdef CONFIG_ZAPATA_PPP - -static int zt_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 zt_chan *ss = ppp->private; - int x,oldbuf; - unsigned int fcs; - unsigned char *data; - long flags; - int retval = 0; - - /* See if we have any buffers */ - spin_lock_irqsave(&ss->lock, flags); - if (!(ss->flags & ZT_FLAG_OPEN)) { - printk("Can't transmit on closed channel\n"); - retval = 1; - } else if (skb->len > ss->blocksize - 4) { - printk(KERN_ERR "zt_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; - } -#ifdef CONFIG_ZAPATA_DEBUG - printk("Buffered %d bytes (skblen = %d) to go out in buffer %d\n", ss->writen[oldbuf], skb->len, oldbuf); - for (x=0;x<ss->writen[oldbuf];x++) - printk("%02x ", ss->writebuf[oldbuf][x]); - printk("\n"); -#endif - 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 zt_ppp_ioctl(struct ppp_channel *ppp, unsigned int cmd, unsigned long flags) -{ - return -EIO; -} - -static struct ppp_channel_ops ztppp_ops = -{ - start_xmit: zt_ppp_xmit, - ioctl: zt_ppp_ioctl, -}; - -#endif - -static void zt_chan_unreg(struct zt_chan *chan) -{ - int x; - unsigned long flags; -#ifdef CONFIG_ZAPATA_NET - if (chan->flags & ZT_FLAG_NETDEV) { -#ifdef LINUX26 - unregister_hdlc_device(chan->hdlcnetdev->netdev); - free_netdev(chan->hdlcnetdev->netdev); -#else - unregister_hdlc_device(&chan->hdlcnetdev->netdev); -#endif - kfree(chan->hdlcnetdev); - chan->hdlcnetdev = NULL; - } -#endif - write_lock_irqsave(&chan_lock, flags); - if (chan->flags & ZT_FLAG_REGISTERED) { - chans[chan->channo] = NULL; - chan->flags &= ~ZT_FLAG_REGISTERED; - } -#ifdef CONFIG_ZAPATA_PPP - if (chan->ppp) { - printk("HUH??? PPP still attached??\n"); - } -#endif - maxchans = 0; - for (x=1;x<ZT_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 & ZT_CONF_MODE_MASK) == ZT_CONF_MONITOR || - (chans[x]->confmode & ZT_CONF_MODE_MASK) == ZT_CONF_MONITORTX || - (chans[x]->confmode & ZT_CONF_MODE_MASK) == ZT_CONF_MONITORBOTH || - (chans[x]->confmode & ZT_CONF_MODE_MASK) == ZT_CONF_MONITOR_RX_PREECHO || - (chans[x]->confmode & ZT_CONF_MODE_MASK) == ZT_CONF_MONITOR_TX_PREECHO || - (chans[x]->confmode & ZT_CONF_MODE_MASK) == ZT_CONF_MONITORBOTH_PREECHO || - (chans[x]->confmode & ZT_CONF_MODE_MASK) == ZT_CONF_DIGITALMON)) { - /* Take them out of conference with us */ - /* release conference resource if any */ - if (chans[x]->confna) { - zt_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 zt_chan_read(struct file *file, char *usrbuf, size_t count, int unit) -{ - struct zt_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]; - printk("zt_chan_read(unit: %d, inwritebuf: %d, outwritebuf: %d amnt: %d\n", - unit, chan->inwritebuf, chan->outwritebuf, myamnt); - printk("\t("); for (x = 0; x < myamnt; x++) printk((x ? " %02x" : "%02x"), (unsigned char)usrbuf[x]); - printk(")\n"); - } -#endif -/* end addition */ - if (chan->flags & ZT_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] = ZT_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 == ZT_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 ssize_t zt_chan_write(struct file *file, const char *usrbuf, size_t count, int unit) -{ - unsigned long flags; - struct zt_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 & ZT_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) - return -EAGAIN; - /* Wait for something to be available */ - rv = schluffen(&chan->writebufq); - if (rv) - return rv; - } - - amnt = count; - if (chan->flags & ZT_FLAG_LINEAR) { - if (amnt > (chan->blocksize << 1)) - amnt = chan->blocksize << 1; - } else { - if (amnt > chan->blocksize) - amnt = chan->blocksize; - } - -#ifdef CONFIG_ZAPATA_DEBUG - printk("zt_chan_write(unit: %d, res: %d, outwritebuf: %d amnt: %d\n", - unit, chan->res, chan->outwritebuf, amnt); -#endif -#if 0 - if ((unit == 24) || (unit == 48) || (unit == 16) || (unit == 47)) { - int x; - printk("zt_chan_write/in(unit: %d, res: %d, outwritebuf: %d amnt: %d, txdisable: %d)\n", - unit, res, chan->outwritebuf, amnt, chan->txdisable); - printk("\t("); for (x = 0; x < amnt; x++) printk((x ? " %02x" : "%02x"), (unsigned char)usrbuf[x]); - printk(")\n"); - } -#endif - - if (amnt) { - if (chan->flags & ZT_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] = ZT_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 & ZT_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; - } - spin_unlock_irqrestore(&chan->lock, flags); - - if (chan->flags & ZT_FLAG_NOSTDTXRX && chan->span->hdlc_hard_xmit) - chan->span->hdlc_hard_xmit(chan); - } - return amnt; -} - -static int zt_ctl_open(struct inode *inode, struct file *file) -{ - /* Nothing to do, really */ -#ifndef LINUX26 - MOD_INC_USE_COUNT; -#endif - return 0; -} - -static int zt_chan_open(struct inode *inode, struct file *file) -{ - /* Nothing to do here for now either */ -#ifndef LINUX26 - MOD_INC_USE_COUNT; -#endif - return 0; -} - -static int zt_ctl_release(struct inode *inode, struct file *file) -{ - /* Nothing to do */ -#ifndef LINUX26 - MOD_DEC_USE_COUNT; -#endif - return 0; -} - -static int zt_chan_release(struct inode *inode, struct file *file) -{ - /* Nothing to do for now */ -#ifndef LINUX26 - MOD_DEC_USE_COUNT; -#endif - return 0; -} - -static void set_txtone(struct zt_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 zt_rbs_sethook(struct zt_chan *chan, int txsig, int txstate, int timeout) -{ -static int outs[NUM_SIGS][5] = { -/* We set the idle case of the ZT_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 */ - { ZT_SIG_NONE, ZT_ABIT | ZT_CBIT | ZT_DBIT, 0, 0, 0 }, /* no signalling */ - { ZT_SIG_EM, 0, ZT_ABIT | ZT_BBIT | ZT_CBIT | ZT_DBIT, - ZT_ABIT | ZT_BBIT | ZT_CBIT | ZT_DBIT, 0 }, /* E and M */ - { ZT_SIG_FXSLS, ZT_BBIT | ZT_DBIT, - ZT_ABIT | ZT_BBIT | ZT_CBIT | ZT_DBIT, - ZT_ABIT | ZT_BBIT | ZT_CBIT | ZT_DBIT, 0 }, /* FXS Loopstart */ - { ZT_SIG_FXSGS, ZT_BBIT | ZT_DBIT, -#ifdef CONFIG_CAC_GROUNDSTART - ZT_ABIT | ZT_BBIT | ZT_CBIT | ZT_DBIT, 0, 0 }, /* FXS Groundstart (CAC-style) */ -#else - ZT_ABIT | ZT_BBIT | ZT_CBIT | ZT_DBIT, ZT_ABIT | ZT_CBIT, 0 }, /* FXS Groundstart (normal) */ -#endif - { ZT_SIG_FXSKS, ZT_BBIT | ZT_DBIT, - ZT_ABIT | ZT_BBIT | ZT_CBIT | ZT_DBIT, - ZT_ABIT | ZT_BBIT | ZT_CBIT | ZT_DBIT, 0 }, /* FXS Kewlstart */ - { ZT_SIG_FXOLS, ZT_BBIT | ZT_DBIT, ZT_BBIT | ZT_DBIT, 0, 0 }, /* FXO Loopstart */ - { ZT_SIG_FXOGS, ZT_ABIT | ZT_BBIT | ZT_CBIT | ZT_DBIT, - ZT_BBIT | ZT_DBIT, 0, 0 }, /* FXO Groundstart */ - { ZT_SIG_FXOKS, ZT_BBIT | ZT_DBIT, ZT_BBIT | ZT_DBIT, 0, - ZT_ABIT | ZT_BBIT | ZT_CBIT | ZT_DBIT }, /* FXO Kewlstart */ - { ZT_SIG_SF, ZT_BBIT | ZT_CBIT | ZT_DBIT, - ZT_ABIT | ZT_BBIT | ZT_CBIT | ZT_DBIT, - ZT_ABIT | ZT_BBIT | ZT_CBIT | ZT_DBIT, - ZT_BBIT | ZT_CBIT | ZT_DBIT }, /* no signalling */ - { ZT_SIG_EM_E1, ZT_DBIT, ZT_ABIT | ZT_BBIT | ZT_DBIT, - ZT_ABIT | ZT_BBIT | ZT_DBIT, ZT_DBIT }, /* E and M E1 */ - } ; - int x; - - /* if no span, return doing nothing */ - if (!chan->span) return; - if (!chan->span->flags & ZT_FLAG_RBS) { - printk("zt_rbs: Tried to set RBS hook state on non-RBS channel %s\n", chan->name); - return; - } - if ((txsig > 3) || (txsig < 0)) { - printk("zt_rbs: Tried to set RBS hook state %d (> 3) on channel %s\n", txsig, chan->name); - return; - } - if (!chan->span->rbsbits && !chan->span->hooksig) { - printk("zt_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 == ZT_SIG_DACS_RBS) - return; - chan->txstate = txstate; - - /* if tone signalling */ - if (chan->sig == ZT_SIG_SF) - { - chan->txhooksig = txsig; - if (chan->txtone) /* if set to make tone for tx */ - { - if ((txsig && !(chan->toneflags & ZT_REVERSE_TXTONE)) || - ((!txsig) && (chan->toneflags & ZT_REVERSE_TXTONE))) - { - set_txtone(chan,chan->txtone,chan->tx_v2,chan->tx_v3); - } - else - { - set_txtone(chan,0,0,0); - } - } - chan->otimer = timeout * ZT_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 * ZT_CHUNKSIZE; /* Otimer is timer in samples */ - return; - } else { - for (x=0;x<NUM_SIGS;x++) { - if (outs[x][0] == chan->sig) { -#ifdef CONFIG_ZAPATA_DEBUG - printk("Setting bits to %d for channel %s state %d in %d signalling\n", outs[x][txsig + 1], chan->name, txsig, chan->sig); -#endif - chan->txhooksig = txsig; - chan->txsig = outs[x][txsig+1]; - chan->span->rbsbits(chan, chan->txsig); - chan->otimer = timeout * ZT_CHUNKSIZE; /* Otimer is timer in samples */ - return; - } - } - } - printk("zt_rbs: Don't know RBS signalling type %d on channel %s\n", chan->sig, chan->name); -} - -static int zt_cas_setbits(struct zt_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 { - printk("Huh? CAS setbits, but no RBS bits function\n"); - } - return 0; -} - -static int zt_hangup(struct zt_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 & (ZT_FLAG_CLEAR | ZT_FLAG_NOSTDTXRX)) - return -EINVAL; - - chan->kewlonhook = 0; - - - if ((chan->sig == ZT_SIG_FXSLS) || (chan->sig == ZT_SIG_FXSKS) || - (chan->sig == ZT_SIG_FXSGS)) chan->ringdebtimer = RING_DEBOUNCE_TIME; - - if (chan->span->flags & ZT_FLAG_RBS) { - if (chan->sig == ZT_SIG_CAS) { - zt_cas_setbits(chan, chan->idlebits); - } else if ((chan->sig == ZT_SIG_FXOKS) && (chan->txstate != ZT_TXSTATE_ONHOOK)) { - /* Do RBS signalling on the channel's behalf */ - zt_rbs_sethook(chan, ZT_TXSIG_KEWL, ZT_TXSTATE_KEWL, ZT_KEWLTIME); - } else - zt_rbs_sethook(chan, ZT_TXSIG_ONHOOK, ZT_TXSTATE_ONHOOK, 0); - } else { - /* Let the driver hang up the line if it wants to */ - if (chan->span->sethook) { - if (chan->txhooksig != ZT_ONHOOK) { - chan->txhooksig = ZT_ONHOOK; - res = chan->span->sethook(chan, ZT_ONHOOK); - } else - res = 0; - } - } - /* if not registered yet, just return here */ - if (!(chan->flags & ZT_FLAG_REGISTERED)) 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 zt_chan *chan) -{ - int res; - unsigned long flags; - void *rxgain=NULL; - struct echo_can_state *ec=NULL; - if ((res = zt_reallocbufs(chan, ZT_DEFAULT_BLOCKSIZE, ZT_DEFAULT_NUM_BUFS))) - return res; - - spin_lock_irqsave(&chan->lock, flags); - - chan->rxbufpolicy = ZT_POLICY_IMMEDIATE; - chan->txbufpolicy = ZT_POLICY_IMMEDIATE; - - /* Free up the echo canceller if there is one */ - ec = chan->ec; - chan->ec = NULL; - chan->echocancel = 0; - chan->echostate = ECHO_STATE_IDLE; - chan->echolastupdate = 0; - chan->echotimer = 0; - - 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); - fasthdlc_init(&chan->txhdlc); - chan->infcs = PPP_INITFCS; - - /* Timings for RBS */ - chan->prewinktime = ZT_DEFAULT_PREWINKTIME; - chan->preflashtime = ZT_DEFAULT_PREFLASHTIME; - chan->winktime = ZT_DEFAULT_WINKTIME; - chan->flashtime = ZT_DEFAULT_FLASHTIME; - - if (chan->sig & __ZT_SIG_FXO) - chan->starttime = ZT_DEFAULT_RINGTIME; - else - chan->starttime = ZT_DEFAULT_STARTTIME; - chan->rxwinktime = ZT_DEFAULT_RXWINKTIME; - chan->rxflashtime = ZT_DEFAULT_RXFLASHTIME; - chan->debouncetime = ZT_DEFAULT_DEBOUNCETIME; - chan->pulsemaketime = ZT_DEFAULT_PULSEMAKETIME; - chan->pulsebreaktime = ZT_DEFAULT_PULSEBREAKTIME; - chan->pulseaftertime = ZT_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) zt_check_conf(chan->confna); - if ((chan->sig & __ZT_SIG_DACS) != __ZT_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; - zt_set_law(chan,0); - zt_hangup(chan); - - /* Make sure that the audio flag is cleared on a clear channel */ - if ((chan->sig & ZT_SIG_CLEAR) || (chan->sig & ZT_SIG_HARDHDLC)) - chan->flags &= ~ZT_FLAG_AUDIO; - - if ((chan->sig == ZT_SIG_CLEAR) || (chan->sig == ZT_SIG_HARDHDLC)) - chan->flags &= ~(ZT_FLAG_PPP | ZT_FLAG_FCS | ZT_FLAG_HDLC); - - chan->flags &= ~ZT_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] = ZT_RINGOFFTIME; - } - - spin_unlock_irqrestore(&chan->lock, flags); - set_tone_zone(chan, -1); - - if (chan->span && chan->span->echocan) - chan->span->echocan(chan, 0); - - if (rxgain) - kfree(rxgain); - if (ec) - echo_can_free(ec); - return 0; -} - -static int zt_timing_open(struct inode *inode, struct file *file) -{ - struct zt_timer *t; - unsigned long flags; - t = kmalloc(sizeof(struct zt_timer), GFP_KERNEL); - if (!t) - return -ENOMEM; - /* Allocate a new timer */ - memset(t, 0, sizeof(struct zt_timer)); - init_waitqueue_head(&t->sel); - file->private_data = t; -#ifndef LINUX26 - MOD_INC_USE_COUNT; -#endif - spin_lock_irqsave(&zaptimerlock, flags); - t->next = zaptimers; - zaptimers = t; - spin_unlock_irqrestore(&zaptimerlock, flags); - return 0; -} - -static int zt_timer_release(struct inode *inode, struct file *file) -{ - struct zt_timer *t, *cur, *prev; - unsigned long flags; - t = file->private_data; - if (t) { - spin_lock_irqsave(&zaptimerlock, flags); - prev = NULL; - cur = zaptimers; - while(cur) { - if (t == cur) - break; - prev = cur; - cur = cur->next; - } - if (cur) { - if (prev) - prev->next = cur->next; - else - zaptimers = cur->next; - } - spin_unlock_irqrestore(&zaptimerlock, flags); - if (!cur) { - printk("Zap Timer: Not on list??\n"); - return 0; - } - kfree(t); -#ifndef LINUX26 - MOD_DEC_USE_COUNT; -#endif - } - return 0; -} - -static int zt_specchan_open(struct inode *inode, struct file *file, int unit, int inc) -{ - 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 & ZT_FLAG_OPEN) - res = -EBUSY; - else if (chans[unit]->flags & ZT_FLAG_NETDEV) - res = -EBUSY; - else if (chans[unit]->master != chans[unit]) - res = -EBUSY; - else if ((chans[unit]->sig & __ZT_SIG_DACS) == __ZT_SIG_DACS) - res = -EBUSY; - else { - unsigned long flags; - /* Assume everything is going to be okay */ - res = initialize_channel(chans[unit]); - spin_lock_irqsave(&chans[unit]->lock, flags); - if (chans[unit]->flags & ZT_FLAG_PSEUDO) - chans[unit]->flags |= ZT_FLAG_AUDIO; - if (chans[unit]->span && chans[unit]->span->open) { - res = chans[unit]->span->open(chans[unit]); - } - if (!res) { - chans[unit]->file = file; -#ifndef LINUX26 - if (inc) - MOD_INC_USE_COUNT; -#endif - chans[unit]->flags |= ZT_FLAG_OPEN; - spin_unlock_irqrestore(&chans[unit]->lock, flags); - } else { - spin_unlock_irqrestore(&chans[unit]->lock, flags); - close_channel(chans[unit]); - } - } - } else - res = -ENXIO; - return res; -} - -static int zt_specchan_release(struct inode *node, struct file *file, int unit) -{ - int res=0; - if (chans[unit]) { - unsigned long flags; - spin_lock_irqsave(&chans[unit]->lock, flags); - chans[unit]->flags &= ~ZT_FLAG_OPEN; - spin_unlock_irqrestore(&chans[unit]->lock, flags); - chans[unit]->file = NULL; - close_channel(chans[unit]); - if (chans[unit]->span && chans[unit]->span->close) - res = chans[unit]->span->close(chans[unit]); - } else - res = -ENXIO; -#ifndef LINUX26 - MOD_DEC_USE_COUNT; -#endif - return res; -} - -static struct zt_chan *zt_alloc_pseudo(void) -{ - struct zt_chan *pseudo; - unsigned long flags; - /* Don't allow /dev/zap/pseudo to open if there are no spans */ - if (maxspans < 1) - return NULL; - pseudo = kmalloc(sizeof(struct zt_chan), GFP_KERNEL); - if (!pseudo) - return NULL; - memset(pseudo, 0, sizeof(struct zt_chan)); - pseudo->sig = ZT_SIG_CLEAR; - pseudo->sigcap = ZT_SIG_CLEAR; - pseudo->flags = ZT_FLAG_PSEUDO | ZT_FLAG_AUDIO; - spin_lock_irqsave(&bigzaplock, flags); - if (zt_chan_reg(pseudo)) { - kfree(pseudo); - pseudo = NULL; - } else - sprintf(pseudo->name, "Pseudo/%d", pseudo->channo); - spin_unlock_irqrestore(&bigzaplock, flags); - return pseudo; -} - -static void zt_free_pseudo(struct zt_chan *pseudo) -{ - unsigned long flags; - if (pseudo) { - spin_lock_irqsave(&bigzaplock, flags); - zt_chan_unreg(pseudo); - spin_unlock_irqrestore(&bigzaplock, flags); - kfree(pseudo); - } -} - -static int zt_open(struct inode *inode, struct file *file) -{ - int unit = UNIT(file); - int ret = -ENXIO; - struct zt_chan *chan; - /* Minor 0: Special "control" descriptor */ - if (!unit) - return zt_ctl_open(inode, file); - if (unit == 250) { - if (!zt_transcode_fops) - request_module("zttranscode"); - if (zt_transcode_fops && zt_transcode_fops->open) { -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) - if (zt_transcode_fops->owner) { - __MOD_INC_USE_COUNT (zt_transcode_fops->owner); -#else - if (try_module_get(zt_transcode_fops->owner)) { -#endif - ret = zt_transcode_fops->open(inode, file); - if (ret) -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) - __MOD_DEC_USE_COUNT (zt_transcode_fops->owner); -#else - module_put(zt_transcode_fops->owner); -#endif - } - return ret; - } - return -ENXIO; - } - if (unit == 253) { - if (maxspans) { - return zt_timing_open(inode, file); - } else { - return -ENXIO; - } - } - if (unit == 254) - return zt_chan_open(inode, file); - if (unit == 255) { - if (maxspans) { - chan = zt_alloc_pseudo(); - if (chan) { - file->private_data = chan; - return zt_specchan_open(inode, file, chan->channo, 1); - } else { - return -ENXIO; - } - } else - return -ENXIO; - } - return zt_specchan_open(inode, file, unit, 1); -} - -#if 0 -static int zt_open(struct inode *inode, struct file *file) -{ - int res; - unsigned long flags; - spin_lock_irqsave(&bigzaplock, flags); - res = __zt_open(inode, file); - spin_unlock_irqrestore(&bigzaplock, flags); - return res; -} -#endif - -static ssize_t zt_read(struct file *file, char *usrbuf, size_t count, loff_t *ppos) -{ - int unit = UNIT(file); - struct zt_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 zt_chan_read(file, usrbuf, count, chan->channo); - } - - if (unit == 255) { - chan = file->private_data; - if (!chan) { - printk("No pseudo channel structure to read?\n"); - return -EINVAL; - } - return zt_chan_read(file, usrbuf, count, chan->channo); - } - if (count < 0) - return -EINVAL; - - return zt_chan_read(file, usrbuf, count, unit); -} - -static ssize_t zt_write(struct file *file, const char *usrbuf, size_t count, loff_t *ppos) -{ - int unit = UNIT(file); - struct zt_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 zt_chan_write(file, usrbuf, count, chan->channo); - } - if (unit == 255) { - chan = file->private_data; - if (!chan) { - printk("No pseudo channel structure to read?\n"); - return -EINVAL; - } - return zt_chan_write(file, usrbuf, count, chan->channo); - } - return zt_chan_write(file, usrbuf, count, unit); - -} - -/* 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 zt_tone *samples[MAX_TONES] = { NULL, }; - short next[MAX_TONES] = { 0, }; - struct zt_tone_def_header th; - struct zt_tone_def td; - struct zt_zone *z; - struct zt_tone *t; - void *slab, *ptr; - int x; - size_t space; - size_t size; - int res; - - if (copy_from_user(&th, (struct zt_tone_def_header *) data, sizeof(th))) - return -EFAULT; - - data += sizeof(th); - - if ((th.count < 0) || (th.count > MAX_TONES)) { - printk("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 = kmalloc(size, GFP_KERNEL))) - return -ENOMEM; - - memset(slab, 0, size); - - ptr += sizeof(*z); - space -= sizeof(*z); - - strncpy(z->name, th.name, sizeof(z->name) - 1); - - for (x = 0; x < ZT_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, - MF_TONE, - } tone_type; - - if (space < sizeof(*t)) { - kfree(slab); - printk("Insufficient tone zone space\n"); - return -EINVAL; - } - - if (copy_from_user(&td, (struct zt_tone_def *) data, sizeof(td))) { - kfree(slab); - return -EFAULT; - } - - data += sizeof(td); - - if ((td.tone >= 0) && (td.tone < ZT_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)) { - printk("Invalid 'next' pointer: %d\n", next[x]); - kfree(slab); - return -EINVAL; - } - } else if ((td.tone >= ZT_TONE_DTMF_BASE) && - (td.tone <= ZT_TONE_DTMF_MAX)) { - tone_type = DTMF_TONE; - - td.tone -= ZT_TONE_DTMF_BASE; - t = &z->dtmf[td.tone]; - } else if ((td.tone >= ZT_TONE_MF_BASE) && - (td.tone <= ZT_TONE_MF_MAX)) { - tone_type = MF_TONE; - - td.tone -= ZT_TONE_MF_BASE; - t = &z->mf[td.tone]; - } else { - printk("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 MF_TONE: - t->tonesamples = global_dialparams.mfv1_tonelen; - t->next = &mfv1_silence; - /* Special case for K/P tone */ - if (td.tone == 10) - t->tonesamples *= 5 / 3; - z->mf_continuous[td.tone] = *t; - z->mf_continuous[td.tone].next = &z->mf_continuous[td.tone]; - break; - } - } - - for (x = 0; x < th.count; x++) { - if (samples[x]) - samples[x]->next = samples[next[x]]; - } - - if ((res = zt_register_tone_zone(th.zone, z))) - kfree(slab); - - return res; -} - -void zt_init_tone_state(struct zt_tone_state *ts, struct zt_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 zt_tone *zt_dtmf_tone(const struct zt_chan *chan, char digit) -{ - struct zt_tone *z; - - switch (chan->digitmode) { - case DIGIT_MODE_DTMF: - z = &chan->curzone->dtmf[0]; - break; - case DIGIT_MODE_MFV1: - z = &chan->curzone->mf[0]; - break; - default: - z = NULL; - } - - switch (digit) { - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - return z + (digit - '0'); - case '*': - return z + 10; - case '#': - return z + 11; - case 'A': - case 'B': - case 'C': - return z + (digit + 12 - 'A'); - case 'D': - if (chan->digitmode == DIGIT_MODE_MFV1) - return NULL; - else - return z + (digit + 12 - 'A'); - case 'W': - return &tone_pause; - } - - return NULL; -} - -static void __do_dtmf(struct zt_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_MFV1; - 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 == ZT_TXSIG_OFFHOOK)) { - chan->pdialcount = (c == '0') ? 10 : c - '0'; - zt_rbs_sethook(chan, ZT_TXSIG_ONHOOK, ZT_TXSTATE_PULSEBREAK, - chan->pulsebreaktime); - return; - } - } else { - chan->curtone = zt_dtmf_tone(chan, c); - chan->tonep = 0; - if (chan->curtone) { - zt_init_tone_state(&chan->ts, chan->curtone); - return; - } - } - } - } - - /* Notify userspace process if there is nothing left */ - chan->dialing = 0; - __qevent(chan, ZT_EVENT_DIALCOMPLETE); -} - -static int zt_release(struct inode *inode, struct file *file) -{ - int unit = UNIT(file); - int res; - struct zt_chan *chan; - - if (!unit) - return zt_ctl_release(inode, file); - if (unit == 253) { - return zt_timer_release(inode, file); - } - if (unit == 250) { - res = zt_transcode_fops->release(inode, file); -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) - if (zt_transcode_fops->owner) - __MOD_DEC_USE_COUNT (zt_transcode_fops->owner); -#else - module_put(zt_transcode_fops->owner); -#endif - return res; - } - if (unit == 254) { - chan = file->private_data; - if (!chan) - return zt_chan_release(inode, file); - else - return zt_specchan_release(inode, file, chan->channo); - } - if (unit == 255) { - chan = file->private_data; - if (chan) { - res = zt_specchan_release(inode, file, chan->channo); - zt_free_pseudo(chan); - } else { - printk("Pseudo release and no private data??\n"); - res = 0; - } - return res; - } - return zt_specchan_release(inode, file, unit); -} - -#if 0 -static int zt_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 = __zt_release(inode, file); - spin_unlock_irqrestore(&bigzaplock, flags); - return res; -} -#endif - - -void zt_alarm_channel(struct zt_chan *chan, int alarms) -{ - unsigned long flags; - - spin_lock_irqsave(&chan->lock, flags); - if (chan->chan_alarms != alarms) { - chan->chan_alarms = alarms; - zt_qevent_nolock(chan, alarms ? ZT_EVENT_ALARM : ZT_EVENT_NOALARM); - } - spin_unlock_irqrestore(&chan->lock, flags); -} - -void zt_alarm_notify(struct zt_span *span) -{ - int x; - - span->alarms &= ~ZT_ALARM_LOOPBACK; - /* Determine maint status */ - if (span->maintstat || span->mainttimer) - span->alarms |= ZT_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++) - zt_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 & ZT_FLAG_RUNNING)) { - if(master != spans[x]) - printk("Zaptel: Master changed to %s\n", spans[x]->name); - master = spans[x]; - break; - } - } - } -} - -#define VALID_SPAN(j) do { \ - if ((j >= ZT_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 >= ZT_MAX_CHANNELS) || (j < 1)) \ - return -EINVAL; \ - if (!chans[j]) \ - return -ENXIO; \ -} while(0) - -static int zt_timer_ioctl(struct inode *node, struct file *file, unsigned int cmd, unsigned long data, struct zt_timer *timer) -{ - int j; - unsigned long flags; - switch(cmd) { - case ZT_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 ZT_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 ZT_GETEVENT: /* Get event on queue */ - j = ZT_EVENT_NONE; - spin_lock_irqsave(&zaptimerlock, flags); - /* set up for no event */ - if (timer->tripped) - j = ZT_EVENT_TIMER_EXPIRED; - if (timer->ping) - j = ZT_EVENT_TIMER_PING; - spin_unlock_irqrestore(&zaptimerlock, flags); - put_user(j,(int *)data); - break; - case ZT_TIMERPING: - spin_lock_irqsave(&zaptimerlock, flags); - timer->ping = 1; - wake_up_interruptible(&timer->sel); - spin_unlock_irqrestore(&zaptimerlock, flags); - break; - case ZT_TIMERPONG: - spin_lock_irqsave(&zaptimerlock, flags); - timer->ping = 0; - spin_unlock_irqrestore(&zaptimerlock, flags); - break; - default: - return -ENOTTY; - } - return 0; -} - -static int zt_common_ioctl(struct inode *node, struct file *file, unsigned int cmd, unsigned long data, int unit) -{ - union { - struct zt_gains gain; - struct zt_spaninfo spaninfo; - struct zt_params param; - } stack; - struct zt_chan *chan; - unsigned long flags; - unsigned char *txgain, *rxgain; - struct zt_chan *mychan; - int i,j; - int return_master = 0; - size_t size_to_copy; - - switch(cmd) { - /* get channel parameters */ - case ZT_GET_PARAMS_V1: - case ZT_GET_PARAMS: - size_to_copy = (cmd == ZT_GET_PARAMS_V1) ? sizeof(struct zt_params_v1) : - sizeof(struct zt_params); - if (copy_from_user(&stack.param, (struct zt_params *) data, size_to_copy)) - return -EFAULT; - - /* check to see if the caller wants to receive our master channel number */ - if (stack.param.channo & ZT_GET_PARAMS_RETURN_MASTER) { - return_master = 1; - stack.param.channo &= ~ZT_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 = zt_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 != ZT_RXSIG_ONHOOK) && - (chan->rxhooksig != ZT_RXSIG_INITIAL)); - } - } else if ((chan->txstate == ZT_TXSTATE_KEWL) || (chan->txstate == ZT_TXSTATE_AFTERKEWL)) - stack.param.rxisoffhook = 1; - else - stack.param.rxisoffhook = 0; - if (chan->span && chan->span->rbsbits && !(chan->sig & ZT_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 & ZT_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; - strncpy(stack.param.name, chan->name, sizeof(stack.param.name) - 1); - stack.param.chanpos = chan->chanpos; - stack.param.sigcap = chan->sigcap; - /* Return current law */ - if (chan->xlaw == __zt_alaw) - stack.param.curlaw = ZT_LAW_ALAW; - else - stack.param.curlaw = ZT_LAW_MULAW; - - if (copy_to_user((struct zt_params *) data, &stack.param, size_to_copy)) - return -EFAULT; - - break; - /* set channel parameters */ - case ZT_SET_PARAMS_V1: - case ZT_SET_PARAMS: - /* The difference between zt_params and zt_params_v1 is just the - * last field, which is read-only anyway. Thus we just read the - * size of the older struct. - */ - if (copy_from_user(&stack.param, (struct zt_params *) data, sizeof(struct zt_params_v1))) - 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 ZT_GETGAINS: /* get gain stuff */ - if (copy_from_user(&stack.gain,(struct zt_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 > ZT_MAX_CHANNELS) || !chans[i]) return(-EINVAL); - - if (!(chans[i]->flags & ZT_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 zt_gains *) data,&stack.gain,sizeof(stack.gain))) - return -EFAULT; - break; - case ZT_SETGAINS: /* set gain stuff */ - if (copy_from_user(&stack.gain,(struct zt_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 > ZT_MAX_CHANNELS) || !chans[i]) return(-EINVAL); - if (!(chans[i]->flags & ZT_FLAG_AUDIO)) return (-EINVAL); - - rxgain = kmalloc(512, GFP_KERNEL); - if (!rxgain) - 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 zt_gains *) data,&stack.gain,sizeof(stack.gain))) - return -EFAULT; - break; - case ZT_SPANSTAT_V1: - case ZT_SPANSTAT_V2: - case ZT_SPANSTAT: - size_to_copy = (cmd == ZT_SPANSTAT_V1) ? sizeof(struct zt_spaninfo_v1) : - (cmd == ZT_SPANSTAT_V2) ? sizeof(struct zt_spaninfo_v2) : - sizeof(struct zt_spaninfo); - if (copy_from_user(&stack.spaninfo, (struct zt_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 */ - strncpy(stack.spaninfo.desc, spans[i]->desc, sizeof(stack.spaninfo.desc) - 1); - strncpy(stack.spaninfo.name, spans[i]->name, sizeof(stack.spaninfo.name) - 1); - 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++; - } - /* version 2 fields */ - stack.spaninfo.lbo = spans[i]->lbo; - stack.spaninfo.lineconfig = spans[i]->lineconfig; - /* version 3 fields */ - stack.spaninfo.irq = spans[i]->irq; - stack.spaninfo.linecompat = spans[i]->linecompat; - strncpy(stack.spaninfo.lboname, zt_lboname(spans[i]->lbo), sizeof(stack.spaninfo.lboname) - 1); - if (spans[i]->manufacturer) - strncpy(stack.spaninfo.manufacturer, spans[i]->manufacturer, - sizeof(stack.spaninfo.manufacturer) - 1); - if (spans[i]->devicetype) - strncpy(stack.spaninfo.devicetype, spans[i]->devicetype, sizeof(stack.spaninfo.devicetype) - 1); - strncpy(stack.spaninfo.location, spans[i]->location, sizeof(stack.spaninfo.location) - 1); - if (spans[i]->spantype) - strncpy(stack.spaninfo.spantype, spans[i]->spantype, sizeof(stack.spaninfo.spantype) - 1); - - if (copy_to_user((struct zt_spaninfo *) data, &stack.spaninfo, size_to_copy)) - return -EFAULT; - break; - case ZT_CHANDIAG: - 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; - - if (!(mychan = kmalloc(sizeof(*mychan), GFP_KERNEL))) - return -ENOMEM; - - /* lock channel */ - spin_lock_irqsave(&chans[j]->lock, flags); - /* make static copy of channel */ - memcpy(mychan, chans[j], sizeof(*mychan)); - /* release it. */ - spin_unlock_irqrestore(&chans[j]->lock, flags); - - printk(KERN_INFO "Dump of Zaptel Channel %d (%s,%d,%d):\n\n",j, - mychan->name,mychan->channo,mychan->chanpos); - printk(KERN_INFO "flags: %x hex, writechunk: %08lx, readchunk: %08lx\n", - mychan->flags, (long) mychan->writechunk, (long) mychan->readchunk); - printk(KERN_INFO "rxgain: %08lx, txgain: %08lx, gainalloc: %d\n", - (long) mychan->rxgain, (long)mychan->txgain, mychan->gainalloc); - printk(KERN_INFO "span: %08lx, sig: %x hex, sigcap: %x hex\n", - (long)mychan->span, mychan->sig, mychan->sigcap); - printk(KERN_INFO "inreadbuf: %d, outreadbuf: %d, inwritebuf: %d, outwritebuf: %d\n", - mychan->inreadbuf, mychan->outreadbuf, mychan->inwritebuf, mychan->outwritebuf); - printk(KERN_INFO "blocksize: %d, numbufs: %d, txbufpolicy: %d, txbufpolicy: %d\n", - mychan->blocksize, mychan->numbufs, mychan->txbufpolicy, mychan->rxbufpolicy); - printk(KERN_INFO "txdisable: %d, rxdisable: %d, iomask: %d\n", - mychan->txdisable, mychan->rxdisable, mychan->iomask); - printk(KERN_INFO "curzone: %08lx, tonezone: %d, curtone: %08lx, tonep: %d\n", - (long) mychan->curzone, mychan->tonezone, (long) mychan->curtone, mychan->tonep); - printk(KERN_INFO "digitmode: %d, txdialbuf: %s, dialing: %d, aftdialtimer: %d, cadpos. %d\n", - mychan->digitmode, mychan->txdialbuf, mychan->dialing, - mychan->afterdialingtimer, mychan->cadencepos); - printk(KERN_INFO "confna: %d, confn: %d, confmode: %d, confmute: %d\n", - mychan->confna, mychan->_confn, mychan->confmode, mychan->confmute); - printk(KERN_INFO "ec: %08lx, echocancel: %d, deflaw: %d, xlaw: %08lx\n", - (long) mychan->ec, mychan->echocancel, mychan->deflaw, (long) mychan->xlaw); - printk(KERN_INFO "echostate: %02x, echotimer: %d, echolastupdate: %d\n", - (int) mychan->echostate, mychan->echotimer, mychan->echolastupdate); - printk(KERN_INFO "itimer: %d, otimer: %d, ringdebtimer: %d\n\n", - mychan->itimer, mychan->otimer, mychan->ringdebtimer); -#if 0 - if (mychan->ec) { - int x; - /* Dump the echo canceller parameters */ - for (x=0;x<mychan->ec->taps;x++) { - printk(KERN_INFO "tap %d: %d\n", x, mychan->ec->fir_taps[x]); - } - } -#endif - kfree(mychan); - break; - default: - return -ENOTTY; - } - return 0; -} - -static int (*zt_dynamic_ioctl)(unsigned int cmd, unsigned long data); - -void zt_set_dynamic_ioctl(int (*func)(unsigned int cmd, unsigned long data)) -{ - zt_dynamic_ioctl = func; -} - -static void recalc_slaves(struct zt_chan *chan) -{ - int x; - struct zt_chan *last = chan; - - /* Makes no sense if you don't have a span */ - if (!chan->span) - return; - -#ifdef CONFIG_ZAPATA_DEBUG - printk("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_ZAPATA_DEBUG - printk("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_ZAPATA_DEBUG - printk("Done Recalculating slaves on %s (last is %s)\n", chan->name, last->name); -#endif -} - -static int zt_ctl_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long data) -{ - /* I/O CTL's for control interface */ - int i,j; - struct zt_lineconfig lc; - struct zt_chanconfig ch; - struct zt_sfconfig sf; - int sigcap; - int res = 0; - int x,y; - struct zt_chan *newmaster; - struct zt_dialparams tdp; - struct zt_maintinfo maint; - struct zt_indirect_data ind; - struct zt_versioninfo vi; - unsigned long flags; - int rv; - switch(cmd) { - case ZT_INDIRECT: - if (copy_from_user(&ind, (struct zt_indirect_data *)data, sizeof(ind))) - return -EFAULT; - VALID_CHANNEL(ind.chan); - return zt_chan_ioctl(inode, file, ind.op, (unsigned long) ind.data, ind.chan); - case ZT_SPANCONFIG: - if (copy_from_user(&lc, (struct zt_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 ZT_STARTUP: - CHECK_VALID_SPAN(j); - if (spans[j]->flags & ZT_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 |= ZT_FLAG_RUNNING; - for (x=0;x<spans[j]->channels;x++) { - y = zt_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); - zt_hangup(&spans[j]->chans[x]); - spin_unlock_irqrestore(&spans[j]->chans[x].lock, flags); - spans[j]->chans[x].rxhooksig = ZT_RXSIG_INITIAL; - } - } - return 0; - case ZT_SHUTDOWN: - CHECK_VALID_SPAN(j); - if (spans[j]->shutdown) - res = spans[j]->shutdown(spans[j]); - spans[j]->flags &= ~ZT_FLAG_RUNNING; - return 0; - case ZT_CHANCONFIG: - if (copy_from_user(&ch, (struct zt_chanconfig *)data, sizeof(ch))) - return -EFAULT; - VALID_CHANNEL(ch.chan); - if (ch.sigtype == ZT_SIG_SLAVE) { - /* We have to use the master's sigtype */ - if ((ch.master < 1) || (ch.master >= ZT_MAX_CHANNELS)) - return -EINVAL; - if (!chans[ch.master]) - return -EINVAL; - ch.sigtype = chans[ch.master]->sig; - newmaster = chans[ch.master]; - } else if ((ch.sigtype & __ZT_SIG_DACS) == __ZT_SIG_DACS) { - newmaster = chans[ch.chan]; - if ((ch.idlebits < 1) || (ch.idlebits >= ZT_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_ZAPATA_NET - if (chans[ch.chan]->flags & ZT_FLAG_NETDEV) { - if (ztchan_to_dev(chans[ch.chan])->flags & IFF_UP) { - spin_unlock_irqrestore(&chans[ch.chan]->lock, flags); - printk(KERN_WARNING "Can't switch HDLC net mode on channel %s, since current interface is up\n", chans[ch.chan]->name); - return -EBUSY; - } -#ifdef LINUX26 - 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); -#else - unregister_hdlc_device(&chans[ch.chan]->hdlcnetdev->netdev); -#endif - kfree(chans[ch.chan]->hdlcnetdev); - chans[ch.chan]->hdlcnetdev = NULL; - chans[ch.chan]->flags &= ~ZT_FLAG_NETDEV; - } -#else - if (ch.sigtype == ZT_SIG_HDLCNET) { - spin_unlock_irqrestore(&chans[ch.chan]->lock, flags); - printk(KERN_WARNING "Zaptel 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 & ZT_SIG_CLEAR) - sigcap |= (ZT_SIG_HDLCRAW | ZT_SIG_HDLCFCS | ZT_SIG_HDLCNET | ZT_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) { - /* Clear the master channel */ - recalc_slaves(chans[ch.chan]->master); - chans[ch.chan]->nextslave = 0; - } - if (!res) { - chans[ch.chan]->sig = ch.sigtype; - if (chans[ch.chan]->sig == ZT_SIG_CAS) - chans[ch.chan]->idlebits = ch.idlebits; - else - chans[ch.chan]->idlebits = 0; - if ((ch.sigtype & ZT_SIG_CLEAR) == ZT_SIG_CLEAR) { - /* Set clear channel flag if appropriate */ - chans[ch.chan]->flags &= ~ZT_FLAG_AUDIO; - chans[ch.chan]->flags |= ZT_FLAG_CLEAR; - } else { - /* Set audio flag and not clear channel otherwise */ - chans[ch.chan]->flags |= ZT_FLAG_AUDIO; - chans[ch.chan]->flags &= ~ZT_FLAG_CLEAR; - } - if ((ch.sigtype & ZT_SIG_HDLCRAW) == ZT_SIG_HDLCRAW) { - /* Set the HDLC flag */ - chans[ch.chan]->flags |= ZT_FLAG_HDLC; - } else { - /* Clear the HDLC flag */ - chans[ch.chan]->flags &= ~ZT_FLAG_HDLC; - } - if ((ch.sigtype & ZT_SIG_HDLCFCS) == ZT_SIG_HDLCFCS) { - /* Set FCS to be calculated if appropriate */ - chans[ch.chan]->flags |= ZT_FLAG_FCS; - } else { - /* Clear FCS flag */ - chans[ch.chan]->flags &= ~ZT_FLAG_FCS; - } - if ((ch.sigtype & __ZT_SIG_DACS) == __ZT_SIG_DACS) { - /* Setup conference properly */ - chans[ch.chan]->confmode = ZT_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 & ZT_SIG_HARDHDLC) == ZT_SIG_HARDHDLC) { - chans[ch.chan]->flags &= ~ZT_FLAG_FCS; - chans[ch.chan]->flags &= ~ZT_FLAG_HDLC; - chans[ch.chan]->flags |= ZT_FLAG_NOSTDTXRX; - } else - chans[ch.chan]->flags &= ~ZT_FLAG_NOSTDTXRX; - } -#ifdef CONFIG_ZAPATA_NET - if (!res && - (newmaster == chans[ch.chan]) && - (chans[ch.chan]->sig == ZT_SIG_HDLCNET)) { - chans[ch.chan]->hdlcnetdev = zt_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 */ -#ifdef LINUX26 - 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 = zt_net_ioctl; - chans[ch.chan]->hdlcnetdev->netdev->open = zt_net_open; - chans[ch.chan]->hdlcnetdev->netdev->stop = zt_net_stop; - dev_to_hdlc(chans[ch.chan]->hdlcnetdev->netdev)->attach = zt_net_attach; - dev_to_hdlc(chans[ch.chan]->hdlcnetdev->netdev)->xmit = zt_xmit; - spin_unlock_irqrestore(&chans[ch.chan]->lock, flags); - /* Briefly restore interrupts while we register the device */ - res = zt_register_hdlc_device(chans[ch.chan]->hdlcnetdev->netdev, ch.netdev_name); - spin_lock_irqsave(&chans[ch.chan]->lock, flags); - } else { - printk("Unable to allocate hdlc: *shrug*\n"); - res = -1; - } -#else /* LINUX26 */ - chans[ch.chan]->hdlcnetdev->chan = chans[ch.chan]; -#ifndef HDLC_MAINTAINERS_ARE_MORE_STUPID_THAN_I_THOUGHT - chans[ch.chan]->hdlcnetdev->netdev.ioctl = zt_net_ioctl; -#endif - chans[ch.chan]->hdlcnetdev->netdev.netdev.do_ioctl = zt_net_ioctl; -#ifdef NEW_HDLC_INTERFACE - chans[ch.chan]->hdlcnetdev->netdev.netdev.open = zt_net_open; - chans[ch.chan]->hdlcnetdev->netdev.netdev.stop = zt_net_stop; - chans[ch.chan]->hdlcnetdev->netdev.xmit = zt_xmit; - chans[ch.chan]->hdlcnetdev->netdev.attach = zt_net_attach; -#else - chans[ch.chan]->hdlcnetdev->netdev.open = zt_net_open; - chans[ch.chan]->hdlcnetdev->netdev.close = zt_net_close; - chans[ch.chan]->hdlcnetdev->netdev.set_mode = NULL; - chans[ch.chan]->hdlcnetdev->netdev.xmit = zt_xmit; -#endif /* NEW_HDLC_INTERFACE */ - chans[ch.chan]->hdlcnetdev->netdev.netdev.irq = chans[ch.chan]->span->irq; - chans[ch.chan]->hdlcnetdev->netdev.netdev.tx_queue_len = 50; - res = register_hdlc_device(&chans[ch.chan]->hdlcnetdev->netdev); -#endif /* LINUX26 */ - if (!res) - chans[ch.chan]->flags |= ZT_FLAG_NETDEV; - } else { - printk("Unable to allocate netdev: out of memory\n"); - res = -1; - } - } -#endif - if ((chans[ch.chan]->sig == ZT_SIG_HDLCNET) && - (chans[ch.chan] == newmaster) && - !(chans[ch.chan]->flags & ZT_FLAG_NETDEV)) - printk("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 zt_chanconfig *)data, &ch, sizeof(ch))) - return -EFAULT; - spin_lock_irqsave(&chans[ch.chan]->lock, flags); - /* And hangup */ - zt_hangup(chans[ch.chan]); - y = zt_q_sig(chans[ch.chan]) & 0xff; - if (y >= 0) chans[ch.chan]->rxsig = (unsigned char)y; - chans[ch.chan]->rxhooksig = ZT_RXSIG_INITIAL; - } -#ifdef CONFIG_ZAPATA_DEBUG - printk("Configured channel %s, flags %04x, 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 ZT_SFCONFIG: - if (copy_from_user(&sf, (struct zt_chanconfig *)data, sizeof(sf))) - return -EFAULT; - VALID_CHANNEL(sf.chan); - if (chans[sf.chan]->sig != ZT_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 & ZT_REVERSE_TXTONE)) || - ((!chans[sf.chan]->txhooksig) && (sf.toneflag & ZT_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 ZT_DEFAULTZONE: - if (get_user(j,(int *)data)) - return -EFAULT; - if ((j < 0) || (j >= ZT_TONE_ZONE_MAX)) - return -EINVAL; - write_lock(&zone_lock); - if (!tone_zones[j]) { - 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[j]->refcount); - default_zone = j; - write_unlock(&zone_lock); - break; - case ZT_LOADZONE: - return ioctl_load_zone(data); - case ZT_FREEZONE: - get_user(j, (int *) data); - return free_tone_zone(j); - case ZT_SET_DIALPARAMS: - if (copy_from_user(&tdp, (struct zt_dialparams *) data, sizeof(tdp))) - return -EFAULT; - if ((tdp.dtmf_tonelen > 4000) || (tdp.dtmf_tonelen < 10)) - return -EINVAL; - if ((tdp.mfv1_tonelen > 4000) || (tdp.mfv1_tonelen < 10)) - return -EINVAL; - - global_dialparams = tdp; - - /* update the lengths in all currently loaded zones */ - write_lock(&zone_lock); - for (j = 0; j < sizeof(tone_zones) / sizeof(tone_zones[0]); j++) { - struct zt_zone *z = tone_zones[j]; - - if (!z) - continue; - - for (i = 0; i < sizeof(z->dtmf) / sizeof(z->dtmf[0]); i++) - z->dtmf[i].tonesamples = tdp.dtmf_tonelen * ZT_CHUNKSIZE; - - for (i = 0; i < sizeof(z->mf) / sizeof(z->mf[0]); i++) - z->mf[i].tonesamples = tdp.mfv1_tonelen * ZT_CHUNKSIZE; - - /* Special case for K/P tone */ - z->mf[10].tonesamples *= 5 / 3; - } - write_unlock(&zone_lock); - - dtmf_silence.tonesamples = tdp.dtmf_tonelen * ZT_CHUNKSIZE; - mfv1_silence.tonesamples = tdp.mfv1_tonelen * ZT_CHUNKSIZE; - - break; - case ZT_GET_DIALPARAMS: - tdp = global_dialparams; - if (copy_to_user((struct zt_dialparams *) data, &tdp, sizeof(tdp))) - return -EFAULT; - break; - case ZT_GETVERSION: - memset(&vi, 0, sizeof(vi)); - strncpy(vi.version, ZAPTEL_VERSION, sizeof(vi.version) - 1); - echo_can_identify(vi.echo_canceller, sizeof(vi.echo_canceller) - 1); - if (copy_to_user((struct zt_versioninfo *) data, &vi, sizeof(vi))) - return -EFAULT; - break; - case ZT_MAINT: /* do maintenance stuff */ - /* get struct from user */ - if (copy_from_user(&maint,(struct zt_maintinfo *) data, sizeof(maint))) - return -EFAULT; - /* must be valid span number */ - if ((maint.spanno < 1) || (maint.spanno > ZT_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 ZT_MAINT_NONE: - case ZT_MAINT_LOCALLOOP: - case ZT_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 ZT_MAINT_LOOPUP: - case ZT_MAINT_LOOPDOWN: - spans[maint.spanno]->mainttimer = ZT_LOOPCODE_TIME * ZT_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: - printk("zaptel: Unknown maintenance event: %d\n", maint.command); - } - zt_alarm_notify(spans[maint.spanno]); /* process alarm-related events */ - spin_unlock_irqrestore(&spans[maint.spanno]->lock, flags); - break; - case ZT_DYNAMIC_CREATE: - case ZT_DYNAMIC_DESTROY: - if (zt_dynamic_ioctl) - return zt_dynamic_ioctl(cmd, data); - else { - request_module("ztdynamic"); - if (zt_dynamic_ioctl) - return zt_dynamic_ioctl(cmd, data); - } - return -ENOSYS; -#if defined(ECHO_CAN_HPEC) - case ZT_EC_LICENSE_CHALLENGE: - case ZT_EC_LICENSE_RESPONSE: - return hpec_license_ioctl(cmd, data); -#endif /* defined(ECHO_CAN_HPEC) */ - default: - return zt_common_ioctl(inode, file, cmd, data, 0); - } - return 0; -} - -static int zt_chanandpseudo_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long data, int unit) -{ - struct zt_chan *chan = chans[unit]; - union { - struct zt_dialoperation tdo; - struct zt_bufferinfo bi; - struct zt_confinfo conf; - struct zt_ring_cadence cad; - } stack; - unsigned long flags, flagso; - int i, j, k, rv; - int ret, c; - char *s; - - if (!chan) - return -EINVAL; - switch(cmd) { - case ZT_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 ZT_DIAL: - if (copy_from_user(&stack.tdo, (struct zt_dialoperation *)data, sizeof(stack.tdo))) - return -EFAULT; - rv = 0; - /* Force proper NULL termination and uppercase entry */ - stack.tdo.dialstr[ZT_MAX_DTMF_BUF - 1] = '\0'; - for (s = stack.tdo.dialstr; *s; s++) - *s = toupper(*s); - spin_lock_irqsave(&chan->lock, flags); - switch (stack.tdo.op) { - case ZT_DIAL_OP_CANCEL: - chan->curtone = NULL; - chan->dialing = 0; - chan->txdialbuf[0] = '\0'; - chan->tonep = 0; - chan->pdialcount = 0; - break; - case ZT_DIAL_OP_REPLACE: - strcpy(chan->txdialbuf, stack.tdo.dialstr); - chan->dialing = 1; - __do_dtmf(chan); - break; - case ZT_DIAL_OP_APPEND: - if (strlen(stack.tdo.dialstr) + strlen(chan->txdialbuf) >= (ZT_MAX_DTMF_BUF - 1)) { - rv = -EBUSY; - break; - } - strncpy(chan->txdialbuf + strlen(chan->txdialbuf), stack.tdo.dialstr, ZT_MAX_DTMF_BUF - strlen(chan->txdialbuf) - 1); - if (!chan->dialing) { - chan->dialing = 1; - __do_dtmf(chan); - } - break; - default: - rv = -EINVAL; - } - spin_unlock_irqrestore(&chan->lock, flags); - return rv; - case ZT_GET_BUFINFO: - 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 zt_bufferinfo *)data, &stack.bi, sizeof(stack.bi))) - return -EFAULT; - break; - case ZT_SET_BUFINFO: - if (copy_from_user(&stack.bi, (struct zt_bufferinfo *)data, sizeof(stack.bi))) - return -EFAULT; - if (stack.bi.bufsize > ZT_MAX_BLOCKSIZE) - return -EINVAL; - if (stack.bi.bufsize < 16) - return -EINVAL; - if (stack.bi.bufsize * stack.bi.numbufs > ZT_MAX_BUF_SPACE) - return -EINVAL; - chan->rxbufpolicy = stack.bi.rxbufpolicy & 0x1; - chan->txbufpolicy = stack.bi.txbufpolicy & 0x1; - if ((rv = zt_reallocbufs(chan, stack.bi.bufsize, stack.bi.numbufs))) - return (rv); - break; - case ZT_GET_BLOCKSIZE: /* get blocksize */ - put_user(chan->blocksize,(int *)data); /* return block size */ - break; - case ZT_SET_BLOCKSIZE: /* set blocksize */ - get_user(j,(int *)data); - /* cannot be larger than max amount */ - if (j > ZT_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 = zt_reallocbufs(chan, j, chan->numbufs))) - return (rv); - break; - case ZT_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 & ZT_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 & ZT_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 & ZT_IOMUX_WRITEEMPTY) - wake_up_interruptible(&chan->eventbufq); /* wake_up_interruptible waiting on IOMUX */ - } - if (i & ZT_FLUSH_EVENT) /* if for events */ - { - /* initialize the event pointers */ - chan->eventinidx = chan->eventoutidx = 0; - } - spin_unlock_irqrestore(&chan->lock, flags); - break; - case ZT_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 ZT_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 & ZT_IOMUX_READ) - { - /* if read available */ - if ((chan->outreadbuf > -1) && !chan->rxdisable) - ret |= ZT_IOMUX_READ; - } - /* if looking for write avail */ - if (chan->iomask & ZT_IOMUX_WRITE) - { - if (chan->inwritebuf > -1) - ret |= ZT_IOMUX_WRITE; - } - /* if looking for write empty */ - if (chan->iomask & ZT_IOMUX_WRITEEMPTY) - { - /* if everything empty -- be sure the transmitter is enabled */ - chan->txdisable = 0; - if (chan->outwritebuf < 0) - ret |= ZT_IOMUX_WRITEEMPTY; - } - /* if looking for signalling event */ - if (chan->iomask & ZT_IOMUX_SIGEVENT) - { - /* if event */ - if (chan->eventinidx != chan->eventoutidx) - ret |= ZT_IOMUX_SIGEVENT; - } - spin_unlock_irqrestore(&chan->lock, flags); - /* if something to return, or not to wait */ - if (ret || (chan->iomask & ZT_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 ZT_GETEVENT: /* Get event on queue */ - /* set up for no event */ - j = ZT_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 >= ZT_MAX_EVENTSIZE) - chan->eventoutidx = 0; - } - spin_unlock_irqrestore(&chan->lock, flags); - put_user(j,(int *)data); - break; - case ZT_CONFMUTE: /* set confmute flag */ - get_user(j,(int *)data); /* get conf # */ - if (!(chan->flags & ZT_FLAG_AUDIO)) return (-EINVAL); - spin_lock_irqsave(&bigzaplock, flags); - chan->confmute = j; - spin_unlock_irqrestore(&bigzaplock, flags); - break; - case ZT_GETCONFMUTE: /* get confmute flag */ - if (!(chan->flags & ZT_FLAG_AUDIO)) return (-EINVAL); - j = chan->confmute; - put_user(j,(int *)data); /* get conf # */ - rv = 0; - break; - case ZT_SETTONEZONE: - get_user(j, (int *) data); - rv = set_tone_zone(chan, j); - return rv; - case ZT_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 ZT_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 ZT_GETCONF: /* get conf stuff */ - if (copy_from_user(&stack.conf,(struct zt_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 > ZT_MAX_CONF) || (!chans[i])) return(-EINVAL); - if (!(chans[i]->flags & ZT_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 zt_confinfo *) data,&stack.conf,sizeof(stack.conf))) - return -EFAULT; - break; - case ZT_SETCONF: /* set conf stuff */ - if (copy_from_user(&stack.conf,(struct zt_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 > ZT_MAX_CHANNELS) || (!chans[i])) return(-EINVAL); - if (!(chans[i]->flags & ZT_FLAG_AUDIO)) return (-EINVAL); - if ((stack.conf.confmode & ZT_CONF_MODE_MASK) == ZT_CONF_MONITOR || - (stack.conf.confmode & ZT_CONF_MODE_MASK) == ZT_CONF_MONITORTX || - (stack.conf.confmode & ZT_CONF_MODE_MASK) == ZT_CONF_MONITORBOTH || - (stack.conf.confmode & ZT_CONF_MODE_MASK) == ZT_CONF_MONITOR_RX_PREECHO || - (stack.conf.confmode & ZT_CONF_MODE_MASK) == ZT_CONF_MONITOR_TX_PREECHO || - (stack.conf.confmode & ZT_CONF_MODE_MASK) == ZT_CONF_MONITORBOTH_PREECHO) { - /* Monitor mode -- it's a channel */ - if ((stack.conf.confno < 0) || (stack.conf.confno >= ZT_MAX_CHANNELS) || !chans[stack.conf.confno]) return(-EINVAL); - } else { - /* make sure conf number makes sense, too */ - if ((stack.conf.confno < -1) || (stack.conf.confno > ZT_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, flagso); - spin_lock_irqsave(&chan->lock, flags); - if (stack.conf.confno == -1) - stack.conf.confno = zt_first_empty_conference(); - if ((stack.conf.confno < 1) && (stack.conf.confmode)) { - /* No more empty conferences */ - spin_unlock_irqrestore(&chan->lock, flags); - spin_unlock_irqrestore(&bigzaplock, flagso); - return -EBUSY; - } - /* if changing confs, clear last added info */ - if (stack.conf.confno != chans[i]->confna) { - memset(chans[i]->conflast, 0, ZT_MAX_CHUNKSIZE); - memset(chans[i]->conflast1, 0, ZT_MAX_CHUNKSIZE); - memset(chans[i]->conflast2, 0, ZT_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 */ - zt_check_conf(j); - zt_check_conf(stack.conf.confno); - if (chans[i]->span && chans[i]->span->dacs) { - if (((stack.conf.confmode & ZT_CONF_MODE_MASK) == ZT_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 & ZT_CONF_MODE_MASK) == ZT_CONF_CONF || - (stack.conf.confmode & ZT_CONF_MODE_MASK) == ZT_CONF_CONFANN || - (stack.conf.confmode & ZT_CONF_MODE_MASK) == ZT_CONF_CONFMON || - (stack.conf.confmode & ZT_CONF_MODE_MASK) == ZT_CONF_CONFANNMON || - (stack.conf.confmode & ZT_CONF_MODE_MASK) == ZT_CONF_REALANDPSEUDO)) { - /* Get alias */ - chans[i]->_confn = zt_get_conf_alias(stack.conf.confno); - } - - if (chans[stack.conf.confno]) { - if ((stack.conf.confmode & ZT_CONF_MODE_MASK) == ZT_CONF_MONITOR_RX_PREECHO || - (stack.conf.confmode & ZT_CONF_MODE_MASK) == ZT_CONF_MONITOR_TX_PREECHO || - (stack.conf.confmode & ZT_CONF_MODE_MASK) == ZT_CONF_MONITORBOTH_PREECHO) - chans[stack.conf.confno]->readchunkpreec = kmalloc(sizeof(*chans[stack.conf.confno]->readchunkpreec) * ZT_CHUNKSIZE, GFP_ATOMIC); - else { - if (chans[stack.conf.confno]->readchunkpreec) { - kfree(chans[stack.conf.confno]->readchunkpreec); - chans[stack.conf.confno]->readchunkpreec = NULL; - } - } - } - - spin_unlock_irqrestore(&chan->lock, flags); - spin_unlock_irqrestore(&bigzaplock, flagso); - if (copy_to_user((struct zt_confinfo *) data,&stack.conf,sizeof(stack.conf))) - return -EFAULT; - break; - case ZT_CONFLINK: /* do conf link stuff */ - if (!(chan->flags & ZT_FLAG_AUDIO)) return (-EINVAL); - if (copy_from_user(&stack.conf,(struct zt_confinfo *) data,sizeof(stack.conf))) - return -EFAULT; - /* check sanity of arguments */ - if ((stack.conf.chan < 0) || (stack.conf.chan > ZT_MAX_CONF)) return(-EINVAL); - if ((stack.conf.confno < 0) || (stack.conf.confno > ZT_MAX_CONF)) return(-EINVAL); - /* cant listen to self!! */ - if (stack.conf.chan && (stack.conf.chan == stack.conf.confno)) return(-EINVAL); - spin_lock_irqsave(&bigzaplock, flagso); - spin_lock_irqsave(&chan->lock, flags); - /* 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_irqrestore(&chan->lock, flags); - spin_unlock_irqrestore(&bigzaplock, flagso); - break; - } - rv = 0; /* clear return value */ - /* look for already existant specified combination */ - for(i = 1; i <= ZT_MAX_CONF; i++) - { - /* if found, exit */ - if ((conf_links[i].src == stack.conf.chan) && - (conf_links[i].dst == stack.conf.confno)) break; - } - if (i <= ZT_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 <= ZT_MAX_CONF; i++) - { - /* if empty, exit loop */ - if ((!conf_links[i].src) && - (!conf_links[i].dst)) break; - } - /* if empty spot found */ - if (i <= ZT_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_irqrestore(&chan->lock, flags); - spin_unlock_irqrestore(&bigzaplock, flagso); - return(rv); - case ZT_CONFDIAG: /* output diagnostic info to console */ - if (!(chan->flags & ZT_FLAG_AUDIO)) return (-EINVAL); - get_user(j,(int *)data); /* get conf # */ - /* loop thru the interesting ones */ - for(i = ((j) ? j : 1); i <= ((j) ? j : ZT_MAX_CONF); i++) - { - c = 0; - for(k = 1; k < ZT_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) printk("Conf #%d:\n",i); - c = 1; - printk("chan %d, mode %x\n", - k,chans[k]->confmode); - } - rv = 0; - for(k = 1; k <= ZT_MAX_CONF; k++) - { - if (conf_links[k].dst == i) - { - if (!c) printk("Conf #%d:\n",i); - c = 1; - if (!rv) printk("Snooping on:\n"); - rv = 1; - printk("conf %d\n",conf_links[k].src); - } - } - if (c) printk("\n"); - } - break; - case ZT_CHANNO: /* get channel number of stream */ - put_user(unit,(int *)data); /* return unit/channel number */ - break; - case ZT_SETLAW: - get_user(j, (int *)data); - if ((j < 0) || (j > ZT_LAW_ALAW)) - return -EINVAL; - zt_set_law(chan, j); - break; - case ZT_SETLINEAR: - get_user(j, (int *)data); - /* Makes no sense on non-audio channels */ - if (!(chan->flags & ZT_FLAG_AUDIO)) - return -EINVAL; - - if (j) - chan->flags |= ZT_FLAG_LINEAR; - else - chan->flags &= ~ZT_FLAG_LINEAR; - break; - case ZT_SETCADENCE: - if (data) { - /* Use specific ring cadence */ - if (copy_from_user(&stack.cad, (struct zt_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<ZT_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<ZT_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] = ZT_RINGOFFTIME; - } - } - break; - default: - /* Check for common ioctl's and private ones */ - rv = zt_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_ZAPATA_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 zt_chan *chan = (struct zt_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 zt_chan *chan, struct zt_echocanparams *ecp, void *data) -{ - struct echo_can_state *ec = NULL, *tec; - struct zt_echocanparam params[ZT_MAX_ECHOCANPARAMS]; - int ret; - unsigned long flags; - - if (ecp->param_count > ZT_MAX_ECHOCANPARAMS) - return -E2BIG; - - if (ecp->tap_length == 0) { - /* disable mode, don't need to inspect params */ - spin_lock_irqsave(&chan->lock, flags); - tec = chan->ec; - chan->ec = NULL; - chan->echocancel = 0; - chan->echostate = ECHO_STATE_IDLE; - chan->echolastupdate = 0; - chan->echotimer = 0; - spin_unlock_irqrestore(&chan->lock, flags); - - /* Make sure this is zero if we're disabling echo can */ - ecp->param_count = 0; - - if (chan->span) { - if (chan->span->echocan_with_params) - chan->span->echocan_with_params(chan, ecp, NULL); - else if (chan->span->echocan) - chan->span->echocan(chan, 0); - } - - if (tec) - echo_can_free(tec); - - return 0; - } - - /* if parameters were supplied and this channel's span provides an echocan, - but not one that takes params, then we must punt here and return an error */ - if (ecp->param_count && chan->span && chan->span->echocan && - !chan->span->echocan_with_params) - return -EINVAL; - - /* enable mode, need the params */ - - if (copy_from_user(params, (struct zt_echocanparam *) data, sizeof(params[0]) * ecp->param_count)) - return -EFAULT; - - spin_lock_irqsave(&chan->lock, flags); - tec = chan->ec; - chan->ec = NULL; - spin_unlock_irqrestore(&chan->lock, flags); - - if (tec) - echo_can_free(tec); - - ret = -ENODEV; - - /* 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) { - if (ecp->param_count) { - if (chan->span->echocan_with_params) - ret = chan->span->echocan_with_params(chan, ecp, params); - } else if (chan->span->echocan) { - ret = chan->span->echocan(chan, ecp->tap_length); - } else if (chan->span->echocan_with_params) { - ret = chan->span->echocan_with_params(chan, ecp, NULL); - } - } - - if (ret == -ENODEV) { - switch (ecp->tap_length) { - case 32: - case 64: - case 128: - case 256: - case 512: - case 1024: - break; - default: - ecp->tap_length = deftaps; - } - - if ((ret = echo_can_create(ecp, params, &ec))) - return ret; - - spin_lock_irqsave(&chan->lock, flags); - chan->echocancel = ecp->tap_length; - chan->ec = ec; - chan->echostate = ECHO_STATE_IDLE; - chan->echolastupdate = 0; - chan->echotimer = 0; - echo_can_disable_detector_init(&chan->txecdis); - echo_can_disable_detector_init(&chan->rxecdis); - spin_unlock_irqrestore(&chan->lock, flags); - } - - return ret; -} - -static int zt_chan_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long data, int unit) -{ - struct zt_chan *chan = chans[unit]; - unsigned long flags; - int j, rv; - int ret; - int oldconf; - void *rxgain=NULL; - struct echo_can_state *ec; - struct zt_echocanparams ecp; - - if (!chan) - return -ENOSYS; - - switch(cmd) { - case ZT_SIGFREEZE: - get_user(j, (int *)data); - spin_lock_irqsave(&chan->lock, flags); - if (j) { - chan->flags |= ZT_FLAG_SIGFREEZE; - } else { - chan->flags &= ~ZT_FLAG_SIGFREEZE; - } - spin_unlock_irqrestore(&chan->lock, flags); - break; - case ZT_GETSIGFREEZE: - spin_lock_irqsave(&chan->lock, flags); - if (chan->flags & ZT_FLAG_SIGFREEZE) - j = 1; - else - j = 0; - spin_unlock_irqrestore(&chan->lock, flags); - put_user(j, (int *)data); - break; - case ZT_AUDIOMODE: - /* Only literal clear channels can be put in */ - if (chan->sig != ZT_SIG_CLEAR) return (-EINVAL); - get_user(j, (int *)data); - if (j) { - spin_lock_irqsave(&chan->lock, flags); - chan->flags |= ZT_FLAG_AUDIO; - chan->flags &= ~(ZT_FLAG_HDLC | ZT_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 */ - spin_lock_irqsave(&chan->lock, flags); - chan->flags &= ~ZT_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 = chan->ec; - chan->ec = 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; - /* Disable any native echo cancellation as well */ - spin_unlock_irqrestore(&chan->lock, flags); - - if (chan->span && chan->span->echocan) - chan->span->echocan(chan, 0); - - if (rxgain) - kfree(rxgain); - if (ec) - echo_can_free(ec); - if (oldconf) zt_check_conf(oldconf); - } - break; - case ZT_HDLCPPP: -#ifdef CONFIG_ZAPATA_PPP - if (chan->sig != ZT_SIG_CLEAR) return (-EINVAL); - get_user(j, (int *)data); - if (j) { - if (!chan->ppp) { - chan->ppp = kmalloc(sizeof(struct ppp_channel), GFP_KERNEL); - if (chan->ppp) { - struct echo_can_state *tec; - memset(chan->ppp, 0, sizeof(struct ppp_channel)); - chan->ppp->private = chan; - chan->ppp->ops = &ztppp_ops; - chan->ppp->mtu = ZT_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 = zt_reallocbufs(chan, ZT_DEFAULT_MTU_MRU, ZT_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; - chan->ec = NULL; - chan->echocancel = 0; - chan->echostate = ECHO_STATE_IDLE; - chan->echolastupdate = 0; - chan->echotimer = 0; - /* Make sure there's no gain */ - if (chan->gainalloc) - kfree(chan->rxgain); - chan->rxgain = defgain; - chan->txgain = defgain; - chan->gainalloc = 0; - chan->flags &= ~ZT_FLAG_AUDIO; - chan->flags |= (ZT_FLAG_PPP | ZT_FLAG_HDLC | ZT_FLAG_FCS); - if (chan->span && chan->span->echocan) - chan->span->echocan(chan, 0); - if (tec) - echo_can_free(tec); - } else - return -ENOMEM; - } - } else { - chan->flags &= ~(ZT_FLAG_PPP | ZT_FLAG_HDLC | ZT_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 - printk("Zaptel: Zaptel PPP support not compiled in\n"); - return -ENOSYS; -#endif - break; - case ZT_HDLCRAWMODE: - if (chan->sig != ZT_SIG_CLEAR) return (-EINVAL); - get_user(j, (int *)data); - chan->flags &= ~(ZT_FLAG_AUDIO | ZT_FLAG_HDLC | ZT_FLAG_FCS); - if (j) { - chan->flags |= ZT_FLAG_HDLC; - fasthdlc_init(&chan->rxhdlc); - fasthdlc_init(&chan->txhdlc); - } - break; - case ZT_HDLCFCSMODE: - if (chan->sig != ZT_SIG_CLEAR) return (-EINVAL); - get_user(j, (int *)data); - chan->flags &= ~(ZT_FLAG_AUDIO | ZT_FLAG_HDLC | ZT_FLAG_FCS); - if (j) { - chan->flags |= ZT_FLAG_HDLC | ZT_FLAG_FCS; - fasthdlc_init(&chan->rxhdlc); - fasthdlc_init(&chan->txhdlc); - } - break; - case ZT_ECHOCANCEL_PARAMS: - if (!(chan->flags & ZT_FLAG_AUDIO)) - return -EINVAL; - if (copy_from_user(&ecp, (struct zt_echocanparams *) data, sizeof(ecp))) - return -EFAULT; - data += sizeof(ecp); - if ((ret = ioctl_echocancel(chan, &ecp, (void *) data))) - return ret; - break; - case ZT_ECHOCANCEL: - if (!(chan->flags & ZT_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 ZT_ECHOTRAIN: - get_user(j, (int *)data); /* get pre-training time from user */ - if ((j < 0) || (j >= ZT_MAX_PRETRAINING)) - return -EINVAL; - j <<= 3; - if (chan->ec) { - /* Start pretraining stage */ - chan->echostate = ECHO_STATE_PRETRAINING; - chan->echotimer = j; - } else - return -EINVAL; - break; - case ZT_SETTXBITS: - if (chan->sig != ZT_SIG_CAS) - return -EINVAL; - get_user(j,(int *)data); - zt_cas_setbits(chan, j); - rv = 0; - break; - case ZT_GETRXBITS: - put_user(chan->rxsig, (int *)data); - rv = 0; - break; - case ZT_LOOPBACK: - get_user(j, (int *)data); - spin_lock_irqsave(&chan->lock, flags); - if (j) - chan->flags |= ZT_FLAG_LOOPED; - else - chan->flags &= ~ZT_FLAG_LOOPED; - spin_unlock_irqrestore(&chan->lock, flags); - rv = 0; - break; - case ZT_HOOK: - get_user(j,(int *)data); - if (chan->flags & ZT_FLAG_CLEAR) - return -EINVAL; - if (chan->sig == ZT_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 & ZT_FLAG_RBS) { - switch (j) { - case ZT_ONHOOK: - spin_lock_irqsave(&chan->lock, flags); - zt_hangup(chan); - spin_unlock_irqrestore(&chan->lock, flags); - break; - case ZT_OFFHOOK: - spin_lock_irqsave(&chan->lock, flags); - if ((chan->txstate == ZT_TXSTATE_KEWL) || - (chan->txstate == ZT_TXSTATE_AFTERKEWL)) { - spin_unlock_irqrestore(&chan->lock, flags); - return -EBUSY; - } - zt_rbs_sethook(chan, ZT_TXSIG_OFFHOOK, ZT_TXSTATE_DEBOUNCE, chan->debouncetime); - spin_unlock_irqrestore(&chan->lock, flags); - break; - case ZT_RING: - case ZT_START: - spin_lock_irqsave(&chan->lock, flags); - if (chan->txstate != ZT_TXSTATE_ONHOOK) { - spin_unlock_irqrestore(&chan->lock, flags); - return -EBUSY; - } - if (chan->sig & __ZT_SIG_FXO) { - ret = 0; - chan->cadencepos = 0; - ret = chan->ringcadence[0]; - zt_rbs_sethook(chan, ZT_TXSIG_START, ZT_TXSTATE_RINGON, ret); - } else - zt_rbs_sethook(chan, ZT_TXSIG_START, ZT_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 - rv = 0; - break; - case ZT_WINK: - spin_lock_irqsave(&chan->lock, flags); - if (chan->txstate != ZT_TXSTATE_ONHOOK) { - spin_unlock_irqrestore(&chan->lock, flags); - return -EBUSY; - } - zt_rbs_sethook(chan, ZT_TXSIG_ONHOOK, ZT_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 ZT_FLASH: - spin_lock_irqsave(&chan->lock, flags); - if (chan->txstate != ZT_TXSTATE_OFFHOOK) { - spin_unlock_irqrestore(&chan->lock, flags); - return -EBUSY; - } - zt_rbs_sethook(chan, ZT_TXSIG_OFFHOOK, ZT_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 ZT_RINGOFF: - spin_lock_irqsave(&chan->lock, flags); - zt_rbs_sethook(chan, ZT_TXSIG_ONHOOK, ZT_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_ZAPATA_PPP - case PPPIOCGCHAN: - if (chan->flags & ZT_FLAG_PPP) - return put_user(ppp_channel_index(chan->ppp), (int *)data) ? -EFAULT : 0; - else - return -EINVAL; - break; - case PPPIOCGUNIT: - if (chan->flags & ZT_FLAG_PPP) - return put_user(ppp_unit_number(chan->ppp), (int *)data) ? -EFAULT : 0; - else - return -EINVAL; - break; -#endif - default: - return zt_chanandpseudo_ioctl(inode, file, cmd, data, unit); - } - return 0; -} - -static int zt_prechan_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long data, int unit) -{ - struct zt_chan *chan = file->private_data; - int channo; - int res; - - if (chan) { - printk("Huh? Prechan already has private data??\n"); - } - switch(cmd) { - case ZT_SPECIFY: - get_user(channo,(int *)data); - if (channo < 1) - return -EINVAL; - if (channo > ZT_MAX_CHANNELS) - return -EINVAL; - res = zt_specchan_open(inode, file, channo, 0); - 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 zt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long data) -{ - int unit = UNIT(file); - struct zt_chan *chan; - struct zt_timer *timer; - - if (!unit) - return zt_ctl_ioctl(inode, file, cmd, data); - - if (unit == 250) - return zt_transcode_fops->ioctl(inode, file, cmd, data); - - if (unit == 253) { - timer = file->private_data; - if (timer) - return zt_timer_ioctl(inode, file, cmd, data, timer); - else - return -EINVAL; - } - if (unit == 254) { - chan = file->private_data; - if (chan) - return zt_chan_ioctl(inode, file, cmd, data, chan->channo); - else - return zt_prechan_ioctl(inode, file, cmd, data, unit); - } - if (unit == 255) { - chan = file->private_data; - if (!chan) { - printk("No pseudo channel structure to read?\n"); - return -EINVAL; - } - return zt_chanandpseudo_ioctl(inode, file, cmd, data, chan->channo); - } - return zt_chan_ioctl(inode, file, cmd, data, unit); -} - -int zt_register(struct zt_span *span, int prefmaster) -{ - int x; - -#ifdef CONFIG_PROC_FS - char tempfile[17]; -#endif - if (!span) - return -EINVAL; - if (span->flags & ZT_FLAG_REGISTERED) { - 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) { - printk(KERN_ERR "Span %s already in list\n", span->name); - return -EBUSY; - } - for (x=1;x<ZT_MAX_SPANS;x++) - if (!spans[x]) - break; - if (x < ZT_MAX_SPANS) { - spans[x] = span; - if (maxspans < x + 1) - maxspans = x + 1; - } else { - printk(KERN_ERR "Too many zapata spans registered\n"); - return -EBUSY; - } - span->flags |= ZT_FLAG_REGISTERED; - span->spanno = x; - spin_lock_init(&span->lock); - if (!span->deflaw) { - printk("zaptel: Span %s didn't specify default law. Assuming mulaw, please fix driver!\n", span->name); - span->deflaw = ZT_LAW_MULAW; - } - - for (x=0;x<span->channels;x++) { - span->chans[x].span = span; - zt_chan_reg(&span->chans[x]); - } - -#ifdef CONFIG_PROC_FS - sprintf(tempfile, "zaptel/%d", span->spanno); - proc_entries[span->spanno] = create_proc_read_entry(tempfile, 0444, NULL , zaptel_proc_read, (int *)(long)span->spanno); -#endif - -#ifdef CONFIG_DEVFS_FS - { - char span_name[50]; - sprintf(span_name, "span%d", span->spanno); - span->dhandle = devfs_mk_dir(zaptel_devfs_dir, span_name, NULL); - for (x = 0; x < span->channels; x++) { - struct zt_chan *chan = &span->chans[x]; - chan->fhandle = register_devfs_channel(chan, chan->span->dhandle); /* Register our stuff with devfs */ - } - } -#endif /* CONFIG_DEVFS_FS */ - -#ifdef CONFIG_ZAP_UDEV - for (x = 0; x < span->channels; x++) { - char chan_name[50]; - if (span->chans[x].channo < 250) { - sprintf(chan_name, "zap%d", span->chans[x].channo); - CLASS_DEV_CREATE(zap_class, MKDEV(ZT_MAJOR, span->chans[x].channo), NULL, chan_name); - } - } -#endif /* CONFIG_ZAP_UDEV */ - - if (debug) - printk("Registered Span %d ('%s') with %d channels\n", span->spanno, span->name, span->channels); - if (!master || prefmaster) { - master = span; - if (debug) - printk("Span ('%s') is new master\n", span->name); - } - return 0; -} - -int zt_unregister(struct zt_span *span) -{ - int x; - int new_maxspans; - static struct zt_span *new_master; - -#ifdef CONFIG_PROC_FS - char tempfile[17]; -#endif /* CONFIG_PROC_FS */ - - if (!(span->flags & ZT_FLAG_REGISTERED)) { - 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 & ZT_FLAG_RUNNING) - if (span->shutdown) - span->shutdown(span); - - if (spans[span->spanno] != span) { - printk(KERN_ERR "Span %s has spanno %d which is something else\n", span->name, span->spanno); - return -1; - } - if (debug) - printk("Unregistering Span '%s' with %d channels\n", span->name, span->channels); -#ifdef CONFIG_PROC_FS - sprintf(tempfile, "zaptel/%d", span->spanno); - remove_proc_entry(tempfile, NULL); -#endif /* CONFIG_PROC_FS */ -#ifdef CONFIG_DEVFS_FS - for (x = 0; x < span->channels; x++) { - devfs_unregister(span->chans[x].fhandle); - devfs_unregister(span->chans[x].fhandle_symlink); - } - devfs_unregister(span->dhandle); -#endif /* CONFIG_DEVFS_FS */ - -#ifdef CONFIG_ZAP_UDEV - for (x = 0; x < span->channels; x++) { - if (span->chans[x].channo < 250) - class_device_destroy(zap_class, MKDEV(ZT_MAJOR, span->chans[x].channo)); - } -#endif /* CONFIG_ZAP_UDEV */ - - spans[span->spanno] = NULL; - span->spanno = 0; - span->flags &= ~ZT_FLAG_REGISTERED; - for (x=0;x<span->channels;x++) - zt_chan_unreg(&span->chans[x]); - new_maxspans = 0; - new_master = master; /* FIXME: locking */ - if (master == span) - new_master = NULL; - for (x=1;x<ZT_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) - printk("%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 -__zt_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 -__zt_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 zt_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; - __zt_mulaw[i] = y; - __zt_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) - { - __zt_lin2mu[((unsigned short)(short)i) >> 2] = __zt_lineartoulaw(i); - __zt_lin2a[((unsigned short)(short)i) >> 2] = __zt_lineartoalaw(i); - } -#endif -} - -static inline void __zt_process_getaudio_chunk(struct zt_chan *ss, unsigned char *txb) -{ - /* We transmit data from our master channel */ - /* Called with ss->lock held */ - struct zt_chan *ms = ss->master; - /* Linear representation */ - short getlin[ZT_CHUNKSIZE], k[ZT_CHUNKSIZE]; - int x; - - /* Okay, now we've got something to transmit */ - for (x=0;x<ZT_CHUNKSIZE;x++) - getlin[x] = ZT_XLAW(txb[x], ms); -#ifndef NO_ECHOCAN_DISABLE - if (ms->ec) { - for (x=0;x<ZT_CHUNKSIZE;x++) { - /* Check for echo cancel disabling tone */ - if (echo_can_disable_detector_update(&ms->txecdis, getlin[x])) { - printk("zaptel Disabled echo canceller because of tone (tx) on channel %d\n", ss->channo); - ms->echocancel = 0; - ms->echostate = ECHO_STATE_IDLE; - ms->echolastupdate = 0; - ms->echotimer = 0; - echo_can_free(ms->ec); - ms->ec = NULL; - __qevent(ss, ZT_EVENT_EC_DISABLED); - break; - } - } - } -#endif - if ((!ms->confmute && !ms->dialing) || (ms->flags & ZT_FLAG_PSEUDO)) { - /* Handle conferencing on non-clear channel and non-HDLC channels */ - switch(ms->confmode & ZT_CONF_MODE_MASK) { - case ZT_CONF_NORMAL: - /* Do nuffin */ - break; - case ZT_CONF_MONITOR: /* Monitor a channel's rx mode */ - /* if a pseudo-channel, ignore */ - if (ms->flags & ZT_FLAG_PSEUDO) break; - /* Add monitored channel */ - if (chans[ms->confna]->flags & ZT_FLAG_PSEUDO) { - ACSS(getlin, chans[ms->confna]->getlin); - } else { - ACSS(getlin, chans[ms->confna]->putlin); - } - for (x=0;x<ZT_CHUNKSIZE;x++) - txb[x] = ZT_LIN2X(getlin[x], ms); - break; - case ZT_CONF_MONITORTX: /* Monitor a channel's tx mode */ - /* if a pseudo-channel, ignore */ - if (ms->flags & ZT_FLAG_PSEUDO) break; - /* Add monitored channel */ - if (chans[ms->confna]->flags & ZT_FLAG_PSEUDO) { - ACSS(getlin, chans[ms->confna]->putlin); - } else { - ACSS(getlin, chans[ms->confna]->getlin); - } - - for (x=0;x<ZT_CHUNKSIZE;x++) - txb[x] = ZT_LIN2X(getlin[x], ms); - break; - case ZT_CONF_MONITORBOTH: /* monitor a channel's rx and tx mode */ - /* if a pseudo-channel, ignore */ - if (ms->flags & ZT_FLAG_PSEUDO) break; - ACSS(getlin, chans[ms->confna]->putlin); - ACSS(getlin, chans[ms->confna]->getlin); - for (x=0;x<ZT_CHUNKSIZE;x++) - txb[x] = ZT_LIN2X(getlin[x], ms); - break; - case ZT_CONF_MONITOR_RX_PREECHO: /* Monitor a channel's rx mode */ - /* if a pseudo-channel, ignore */ - if (ms->flags & ZT_FLAG_PSEUDO) - break; - - if (!chans[ms->confna]->readchunkpreec) - break; - - /* Add monitored channel */ - ACSS(getlin, chans[ms->confna]->flags & ZT_FLAG_PSEUDO ? - chans[ms->confna]->readchunkpreec : chans[ms->confna]->putlin); - for (x = 0; x < ZT_CHUNKSIZE; x++) - txb[x] = ZT_LIN2X(getlin[x], ms); - - break; - case ZT_CONF_MONITOR_TX_PREECHO: /* Monitor a channel's tx mode */ - /* if a pseudo-channel, ignore */ - if (ms->flags & ZT_FLAG_PSEUDO) - break; - - if (!chans[ms->confna]->readchunkpreec) - break; - - /* Add monitored channel */ - ACSS(getlin, chans[ms->confna]->flags & ZT_FLAG_PSEUDO ? - chans[ms->confna]->putlin : chans[ms->confna]->readchunkpreec); - for (x = 0; x < ZT_CHUNKSIZE; x++) - txb[x] = ZT_LIN2X(getlin[x], ms); - - break; - case ZT_CONF_MONITORBOTH_PREECHO: /* monitor a channel's rx and tx mode */ - /* if a pseudo-channel, ignore */ - if (ms->flags & ZT_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 < ZT_CHUNKSIZE; x++) - txb[x] = ZT_LIN2X(getlin[x], ms); - - break; - case ZT_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 & ZT_CONF_PSEUDO_TALKER) { - /* Store temp value */ - memcpy(k, getlin, ZT_CHUNKSIZE * sizeof(short)); - /* Add conf value */ - ACSS(k, conf_sums_next[ms->_confn]); - /* save last one */ - memcpy(ms->conflast2, ms->conflast1, ZT_CHUNKSIZE * sizeof(short)); - memcpy(ms->conflast1, k, ZT_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, ZT_CHUNKSIZE * sizeof(short)); - memset(ms->conflast2, 0, ZT_CHUNKSIZE * sizeof(short)); - } - memset(getlin, 0, ZT_CHUNKSIZE * sizeof(short)); - txb[0] = ZT_LIN2X(0, ms); - memset(txb + 1, txb[0], ZT_CHUNKSIZE - 1); - /* fall through to normal conf mode */ - case ZT_CONF_CONF: /* Normal conference mode */ - if (ms->flags & ZT_FLAG_PSEUDO) /* if pseudo-channel */ - { - /* if to talk on conf */ - if (ms->confmode & ZT_CONF_TALKER) { - /* Store temp value */ - memcpy(k, getlin, ZT_CHUNKSIZE * sizeof(short)); - /* Add conf value */ - ACSS(k, conf_sums[ms->_confn]); - /* get amount actually added */ - memcpy(ms->conflast, k, ZT_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, ZT_CHUNKSIZE * sizeof(short)); - memcpy(getlin, ms->getlin, ZT_CHUNKSIZE * sizeof(short)); - txb[0] = ZT_LIN2X(0, ms); - memset(txb + 1, txb[0], ZT_CHUNKSIZE - 1); - break; - } - /* fall through */ - case ZT_CONF_CONFMON: /* Conference monitor mode */ - if (ms->confmode & ZT_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<ZT_CHUNKSIZE;x++) - txb[x] = ZT_LIN2X(getlin[x], ms); - break; - case ZT_CONF_CONFANN: - case ZT_CONF_CONFANNMON: - /* First, add tx buffer to conf */ - ACSS(conf_sums_next[ms->_confn], getlin); - /* Start with silence */ - memset(getlin, 0, ZT_CHUNKSIZE * sizeof(short)); - /* If a listener on the conf... */ - if (ms->confmode & ZT_CONF_LISTENER) { - /* Subtract last value written */ - SCSS(getlin, ms->conflast); - /* Add in conf */ - ACSS(getlin, conf_sums[ms->_confn]); - } - for (x=0;x<ZT_CHUNKSIZE;x++) - txb[x] = ZT_LIN2X(getlin[x], ms); - break; - case ZT_CONF_DIGITALMON: - /* Real digital monitoring, but still echo cancel if desired */ - if (!chans[ms->confna]) - break; - if (chans[ms->confna]->flags & ZT_FLAG_PSEUDO) { - if (ms->ec) { - for (x=0;x<ZT_CHUNKSIZE;x++) - txb[x] = ZT_LIN2X(chans[ms->confna]->getlin[x], ms); - } else { - memcpy(txb, chans[ms->confna]->getraw, ZT_CHUNKSIZE); - } - } else { - if (ms->ec) { - for (x=0;x<ZT_CHUNKSIZE;x++) - txb[x] = ZT_LIN2X(chans[ms->confna]->putlin[x], ms); - } else { - memcpy(txb, chans[ms->confna]->putraw, ZT_CHUNKSIZE); - } - } - for (x=0;x<ZT_CHUNKSIZE;x++) - getlin[x] = ZT_XLAW(txb[x], ms); - break; - } - } - if (ms->confmute || (ms->echostate & __ECHO_STATE_MUTE)) { - txb[0] = ZT_LIN2X(0, ms); - memset(txb + 1, txb[0], ZT_CHUNKSIZE - 1); - if (ms->echostate == ECHO_STATE_STARTTRAINING) { - /* Transmit impulse now */ - txb[0] = ZT_LIN2X(16384, ms); - ms->echostate = ECHO_STATE_AWAITINGECHO; - } - } - /* save value from last chunk */ - memcpy(ms->getlin_lastchunk, ms->getlin, ZT_CHUNKSIZE * sizeof(short)); - /* save value from current */ - memcpy(ms->getlin, getlin, ZT_CHUNKSIZE * sizeof(short)); - /* save value from current */ - memcpy(ms->getraw, txb, ZT_CHUNKSIZE); - /* if to make tx tone */ - if (ms->v1_1 || ms->v2_1 || ms->v3_1) - { - for (x=0;x<ZT_CHUNKSIZE;x++) - { - getlin[x] += zt_txtone_nextsample(ms); - txb[x] = ZT_LIN2X(getlin[x], ms); - } - } - /* This is what to send (after having applied gain) */ - for (x=0;x<ZT_CHUNKSIZE;x++) - txb[x] = ms->txgain[txb[x]]; -} - -static inline void __zt_getbuf_chunk(struct zt_chan *ss, unsigned char *txb) -{ - /* Called with ss->lock held */ - /* We transmit data from our master channel */ - struct zt_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 = ZT_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 & ZT_FLAG_HDLC) { - /* If this is an HDLC channel we only send a byte of - HDLC. */ - for(x=0;x<left;x++) { - if (ms->txhdlc.bits < 8) - /* 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->writen[oldbuf] = 0; - ms->outwritebuf = (ms->outwritebuf + 1) % ms->numbufs; - 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 & (ZT_IOMUX_WRITE | ZT_IOMUX_WRITEEMPTY)) - wake_up_interruptible(&ms->eventbufq); - /* If we're only supposed to start when full, disable the transmitter */ - if (ms->txbufpolicy == ZT_POLICY_WHEN_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 & (ZT_FLAG_NETDEV | ZT_FLAG_PPP))) { - wake_up_interruptible(&ms->writebufq); - wake_up_interruptible(&ms->sel); - if (ms->iomask & ZT_IOMUX_WRITE) - wake_up_interruptible(&ms->eventbufq); - } - /* Transmit a flag if this is an HDLC channel */ - if (ms->flags & ZT_FLAG_HDLC) - fasthdlc_tx_frame_nocheck(&ms->txhdlc); -#ifdef CONFIG_ZAPATA_NET - if (ms->flags & ZT_FLAG_NETDEV) - netif_wake_queue(ztchan_to_dev(ms)); -#endif -#ifdef CONFIG_ZAPATA_PPP - if (ms->flags & ZT_FLAG_PPP) { - ms->do_ppp_wakeup = 1; - tasklet_schedule(&ms->ppp_calls); - } -#endif - } - } else if (ms->curtone && !(ms->flags & ZT_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 = zt_tone_nextsample(&ms->ts, ms->curtone); - *(txb++) = ZT_LIN2X(getlin, ms); - } - ms->tonep+=left; - bytes -= left; - if (ms->tonep >= ms->curtone->tonesamples) { - struct zt_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) - zt_init_tone_state(&ms->ts, ms->curtone); - } - } - } else if (ms->flags & ZT_FLAG_LOOPED) { - for (x = 0; x < bytes; x++) - txb[x] = ms->readchunk[x]; - bytes = 0; - } else if (ms->flags & ZT_FLAG_HDLC) { - for (x=0;x<bytes;x++) { - /* Okay, if we're HDLC, then transmit a flag by default */ - if (ms->txhdlc.bits < 8) - fasthdlc_tx_frame_nocheck(&ms->txhdlc); - *(txb++) = fasthdlc_tx_run_nocheck(&ms->txhdlc); - } - bytes = 0; - } else if (ms->flags & ZT_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 & ZT_FLAG_AUDIO) { - memset(txb, ZT_LIN2X(0, ms), bytes); - } else { - memset(txb, 0xFF, bytes); - } - bytes = 0; - } else { - memset(txb, ZT_LIN2X(0, ms), bytes); /* Lastly we use silence on telephony channels */ - bytes = 0; - } - } -} - -static inline void rbs_itimer_expire(struct zt_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 ZT_SIG_FXOLS: /* if FXO, its definitely on hook */ - case ZT_SIG_FXOGS: - case ZT_SIG_FXOKS: - __qevent(chan,ZT_EVENT_ONHOOK); - chan->gotgs = 0; - break; -#if defined(EMFLASH) || defined(EMPULSE) - case ZT_SIG_EM: - case ZT_SIG_EM_E1: - if (chan->rxhooksig == ZT_RXSIG_ONHOOK) { - __qevent(chan,ZT_EVENT_ONHOOK); - break; - } - __qevent(chan,ZT_EVENT_RINGOFFHOOK); - break; -#endif -#ifdef FXSFLASH - case ZT_SIG_FXSKS: - if (chan->rxhooksig == ZT_RXSIG_ONHOOK) { - __qevent(chan, ZT_EVENT_ONHOOK); - break; - } -#endif - /* fall thru intentionally */ - default: /* otherwise, its definitely off hook */ - __qevent(chan,ZT_EVENT_RINGOFFHOOK); - break; - } -} - -static inline void __rbs_otimer_expire(struct zt_chan *chan) -{ - int len = 0; - /* Called with chan->lock held */ - - chan->otimer = 0; - /* Move to the next timer state */ - switch(chan->txstate) { - case ZT_TXSTATE_RINGOFF: - /* Turn on the ringer now that the silent time has passed */ - ++chan->cadencepos; - if (chan->cadencepos >= ZT_MAX_CADENCE) - chan->cadencepos = chan->firstcadencepos; - len = chan->ringcadence[chan->cadencepos]; - - if (!len) { - chan->cadencepos = chan->firstcadencepos; - len = chan->ringcadence[chan->cadencepos]; - } - - zt_rbs_sethook(chan, ZT_TXSIG_START, ZT_TXSTATE_RINGON, len); - __qevent(chan, ZT_EVENT_RINGERON); - break; - - case ZT_TXSTATE_RINGON: - /* Turn off the ringer now that the loud time has passed */ - ++chan->cadencepos; - if (chan->cadencepos >= ZT_MAX_CADENCE) - chan->cadencepos = 0; - len = chan->ringcadence[chan->cadencepos]; - - if (!len) { - chan->cadencepos = 0; - len = chan->curzone->ringcadence[chan->cadencepos]; - } - - zt_rbs_sethook(chan, ZT_TXSIG_OFFHOOK, ZT_TXSTATE_RINGOFF, len); - __qevent(chan, ZT_EVENT_RINGEROFF); - break; - - case ZT_TXSTATE_START: - /* If we were starting, go off hook now ready to debounce */ - zt_rbs_sethook(chan, ZT_TXSIG_OFFHOOK, ZT_TXSTATE_AFTERSTART, ZT_AFTERSTART_TIME); - wake_up_interruptible(&chan->txstateq); - break; - - case ZT_TXSTATE_PREWINK: - /* Actually wink */ - zt_rbs_sethook(chan, ZT_TXSIG_OFFHOOK, ZT_TXSTATE_WINK, chan->winktime); - break; - - case ZT_TXSTATE_WINK: - /* Wink complete, go on hook and stabalize */ - zt_rbs_sethook(chan, ZT_TXSIG_ONHOOK, ZT_TXSTATE_ONHOOK, 0); - if (chan->file && (chan->file->f_flags & O_NONBLOCK)) - __qevent(chan, ZT_EVENT_HOOKCOMPLETE); - wake_up_interruptible(&chan->txstateq); - break; - - case ZT_TXSTATE_PREFLASH: - /* Actually flash */ - zt_rbs_sethook(chan, ZT_TXSIG_ONHOOK, ZT_TXSTATE_FLASH, chan->flashtime); - break; - - case ZT_TXSTATE_FLASH: - zt_rbs_sethook(chan, ZT_TXSIG_OFFHOOK, ZT_TXSTATE_OFFHOOK, 0); - if (chan->file && (chan->file->f_flags & O_NONBLOCK)) - __qevent(chan, ZT_EVENT_HOOKCOMPLETE); - wake_up_interruptible(&chan->txstateq); - break; - - case ZT_TXSTATE_DEBOUNCE: - zt_rbs_sethook(chan, ZT_TXSIG_OFFHOOK, ZT_TXSTATE_OFFHOOK, 0); - /* See if we've gone back on hook */ - if ((chan->rxhooksig == ZT_RXSIG_ONHOOK) && (chan->rxflashtime > 2)) - chan->itimerset = chan->itimer = chan->rxflashtime * ZT_CHUNKSIZE; - wake_up_interruptible(&chan->txstateq); - break; - - case ZT_TXSTATE_AFTERSTART: - zt_rbs_sethook(chan, ZT_TXSIG_OFFHOOK, ZT_TXSTATE_OFFHOOK, 0); - if (chan->file && (chan->file->f_flags & O_NONBLOCK)) - __qevent(chan, ZT_EVENT_HOOKCOMPLETE); - wake_up_interruptible(&chan->txstateq); - break; - - case ZT_TXSTATE_KEWL: - zt_rbs_sethook(chan, ZT_TXSIG_ONHOOK, ZT_TXSTATE_AFTERKEWL, ZT_AFTERKEWLTIME); - if (chan->file && (chan->file->f_flags & O_NONBLOCK)) - __qevent(chan, ZT_EVENT_HOOKCOMPLETE); - wake_up_interruptible(&chan->txstateq); - break; - - case ZT_TXSTATE_AFTERKEWL: - if (chan->kewlonhook) { - __qevent(chan,ZT_EVENT_ONHOOK); - } - chan->txstate = ZT_TXSTATE_ONHOOK; - chan->gotgs = 0; - break; - - case ZT_TXSTATE_PULSEBREAK: - zt_rbs_sethook(chan, ZT_TXSIG_OFFHOOK, ZT_TXSTATE_PULSEMAKE, - chan->pulsemaketime); - wake_up_interruptible(&chan->txstateq); - break; - - case ZT_TXSTATE_PULSEMAKE: - if (chan->pdialcount) - chan->pdialcount--; - if (chan->pdialcount) - { - zt_rbs_sethook(chan, ZT_TXSIG_ONHOOK, - ZT_TXSTATE_PULSEBREAK, chan->pulsebreaktime); - break; - } - chan->txstate = ZT_TXSTATE_PULSEAFTER; - chan->otimer = chan->pulseaftertime * ZT_CHUNKSIZE; - wake_up_interruptible(&chan->txstateq); - break; - - case ZT_TXSTATE_PULSEAFTER: - chan->txstate = ZT_TXSTATE_OFFHOOK; - __do_dtmf(chan); - wake_up_interruptible(&chan->txstateq); - break; - - default: - break; - } -} - -static void __zt_hooksig_pvt(struct zt_chan *chan, zt_rxsig_t rxsig) -{ - - /* State machines for receive hookstate transitions - called with chan->lock held */ - - if ((chan->rxhooksig) == rxsig) return; - - if ((chan->flags & ZT_FLAG_SIGFREEZE)) return; - - chan->rxhooksig = rxsig; -#ifdef RINGBEGIN - if ((chan->sig & __ZT_SIG_FXS) && (rxsig == ZT_RXSIG_RING) && - (!chan->ringdebtimer)) - __qevent(chan,ZT_EVENT_RINGBEGIN); -#endif - switch(chan->sig) { - case ZT_SIG_EM: /* E and M */ - case ZT_SIG_EM_E1: - switch(rxsig) { - case ZT_RXSIG_OFFHOOK: /* went off hook */ - /* The interface is going off hook */ -#ifdef EMFLASH - if (chan->itimer) - { - __qevent(chan,ZT_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 <= ZT_MAXPULSETIME) - { - if (plen >= ZT_MINPULSETIME) - { - chan->pulsecount++; - - chan->pulsetimer = ZT_PULSETIMEOUT; - chan->itimerset = chan->itimer = 0; - if (chan->pulsecount == 1) - __qevent(chan,ZT_EVENT_PULSE_START); - } - } - break; - } -#endif - /* set wink timer */ - chan->itimerset = chan->itimer = chan->rxwinktime * ZT_CHUNKSIZE; - break; - case ZT_RXSIG_ONHOOK: /* went on hook */ - /* This interface is now going on hook. - Check for WINK, etc */ - if (chan->itimer) - __qevent(chan,ZT_EVENT_WINKFLASH); -#if defined(EMFLASH) || defined(EMPULSE) - else { -#ifdef EMFLASH - chan->itimerset = chan->itimer = chan->rxflashtime * ZT_CHUNKSIZE; - -#else /* EMFLASH */ - chan->itimerset = chan->itimer = chan->rxwinktime * ZT_CHUNKSIZE; - -#endif /* EMFLASH */ - chan->gotgs = 0; - break; - } -#else /* EMFLASH || EMPULSE */ - else { - __qevent(chan,ZT_EVENT_ONHOOK); - chan->gotgs = 0; - } -#endif - chan->itimerset = chan->itimer = 0; - break; - default: - break; - } - break; - case ZT_SIG_FXSKS: /* FXS Kewlstart */ - /* ignore a bit poopy if loop not closed and stable */ - if (chan->txstate != ZT_TXSTATE_OFFHOOK) break; -#ifdef FXSFLASH - if (rxsig == ZT_RXSIG_ONHOOK) { - chan->itimer = ZT_FXSFLASHMAXTIME * ZT_CHUNKSIZE; - break; - } else if (rxsig == ZT_RXSIG_OFFHOOK) { - if (chan->itimer) { - /* did the offhook occur in the window? if not, ignore both events */ - if (chan->itimer <= ((ZT_FXSFLASHMAXTIME - ZT_FXSFLASHMINTIME) * ZT_CHUNKSIZE)) - __qevent(chan, ZT_EVENT_WINKFLASH); - } - chan->itimer = 0; - break; - } -#endif - /* fall through intentionally */ - case ZT_SIG_FXSGS: /* FXS Groundstart */ - if (rxsig == ZT_RXSIG_ONHOOK) { - chan->ringdebtimer = RING_DEBOUNCE_TIME; - chan->ringtrailer = 0; - if (chan->txstate != ZT_TXSTATE_DEBOUNCE) { - chan->gotgs = 0; - __qevent(chan,ZT_EVENT_ONHOOK); - } - } - break; - case ZT_SIG_FXOGS: /* FXO Groundstart */ - if (rxsig == ZT_RXSIG_START) { - /* if havent got gs, report it */ - if (!chan->gotgs) { - __qevent(chan,ZT_EVENT_RINGOFFHOOK); - chan->gotgs = 1; - } - } - /* fall through intentionally */ - case ZT_SIG_FXOLS: /* FXO Loopstart */ - case ZT_SIG_FXOKS: /* FXO Kewlstart */ - switch(rxsig) { - case ZT_RXSIG_OFFHOOK: /* went off hook */ - /* if asserti ng ring, stop it */ - if (chan->txstate == ZT_TXSTATE_START) { - zt_rbs_sethook(chan,ZT_TXSIG_OFFHOOK, ZT_TXSTATE_AFTERSTART, ZT_AFTERSTART_TIME); - } - chan->kewlonhook = 0; -#ifdef CONFIG_ZAPATA_DEBUG - printk("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 <= ZT_MAXPULSETIME) - { - if (plen >= ZT_MINPULSETIME) - { - chan->pulsecount++; - chan->pulsetimer = ZT_PULSETIMEOUT; - chan->itimer = chan->itimerset; - if (chan->pulsecount == 1) - __qevent(chan,ZT_EVENT_PULSE_START); - } - } else - __qevent(chan,ZT_EVENT_WINKFLASH); - } else { - /* if havent got GS detect */ - if (!chan->gotgs) { - __qevent(chan,ZT_EVENT_RINGOFFHOOK); - chan->gotgs = 1; - chan->itimerset = chan->itimer = 0; - } - } - chan->itimerset = chan->itimer = 0; - break; - case ZT_RXSIG_ONHOOK: /* went on hook */ - /* if not during offhook debounce time */ - if ((chan->txstate != ZT_TXSTATE_DEBOUNCE) && - (chan->txstate != ZT_TXSTATE_KEWL) && - (chan->txstate != ZT_TXSTATE_AFTERKEWL)) { - chan->itimerset = chan->itimer = chan->rxflashtime * ZT_CHUNKSIZE; - } - if (chan->txstate == ZT_TXSTATE_KEWL) - chan->kewlonhook = 1; - break; - default: - break; - } - default: - break; - } -} - -void zt_hooksig(struct zt_chan *chan, zt_rxsig_t rxsig) -{ - /* skip if no change */ - unsigned long flags; - spin_lock_irqsave(&chan->lock, flags); - __zt_hooksig_pvt(chan,rxsig); - spin_unlock_irqrestore(&chan->lock, flags); -} - -void zt_rbsbits(struct zt_chan *chan, int cursig) -{ - unsigned long flags; - if (cursig == chan->rxsig) - return; - - if ((chan->flags & ZT_FLAG_SIGFREEZE)) return; - - spin_lock_irqsave(&chan->lock, flags); - switch(chan->sig) { - case ZT_SIG_FXOGS: /* FXO Groundstart */ - /* B-bit only matters for FXO GS */ - if (!(cursig & ZT_BBIT)) { - __zt_hooksig_pvt(chan, ZT_RXSIG_START); - break; - } - /* Fall through */ - case ZT_SIG_EM: /* E and M */ - case ZT_SIG_EM_E1: - case ZT_SIG_FXOLS: /* FXO Loopstart */ - case ZT_SIG_FXOKS: /* FXO Kewlstart */ - if (cursig & ZT_ABIT) /* off hook */ - __zt_hooksig_pvt(chan,ZT_RXSIG_OFFHOOK); - else /* on hook */ - __zt_hooksig_pvt(chan,ZT_RXSIG_ONHOOK); - break; - - case ZT_SIG_FXSKS: /* FXS Kewlstart */ - case ZT_SIG_FXSGS: /* FXS Groundstart */ - /* Fall through */ - case ZT_SIG_FXSLS: - if (!(cursig & ZT_BBIT)) { - /* Check for ringing first */ - __zt_hooksig_pvt(chan, ZT_RXSIG_RING); - break; - } - if ((chan->sig != ZT_SIG_FXSLS) && (cursig & ZT_ABIT)) { - /* if went on hook */ - __zt_hooksig_pvt(chan, ZT_RXSIG_ONHOOK); - } else { - __zt_hooksig_pvt(chan, ZT_RXSIG_OFFHOOK); - } - break; - case ZT_SIG_CAS: - /* send event that something changed */ - __qevent(chan, ZT_EVENT_BITSCHANGED); - break; - - default: - break; - } - /* Keep track of signalling for next time */ - chan->rxsig = cursig; - spin_unlock_irqrestore(&chan->lock, flags); -} - -static inline void __zt_ec_chunk(struct zt_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 < ZT_CHUNKSIZE; x++) - /* We only ever really need to deal with signed linear - let's just convert it now */ - ss->readchunkpreec[x] = ZT_XLAW(rxchunk[x], ss); - } - - /* Perform echo cancellation on a chunk if necessary */ - if (ss->ec) { -#if defined(CONFIG_ZAPTEL_MMX) || defined(ECHO_CAN_FP) - zt_kernel_fpu_begin(); -#endif - if (ss->echostate & __ECHO_STATE_MUTE) { - /* Special stuff for training the echo can */ - for (x=0;x<ZT_CHUNKSIZE;x++) { - rxlin = ZT_XLAW(rxchunk[x], ss); - txlin = ZT_XLAW(txchunk[x], ss); - if (ss->echostate == ECHO_STATE_PRETRAINING) { - if (--ss->echotimer <= 0) { - ss->echotimer = 0; - ss->echostate = ECHO_STATE_STARTTRAINING; - } - } - if ((ss->echostate == ECHO_STATE_AWAITINGECHO) && (txlin > 8000)) { - ss->echolastupdate = 0; - ss->echostate = ECHO_STATE_TRAINING; - } - if (ss->echostate == ECHO_STATE_TRAINING) { - if (echo_can_traintap(ss->ec, ss->echolastupdate++, rxlin)) { -#if 0 - printk("Finished training (%d taps trained)!\n", ss->echolastupdate); -#endif - ss->echostate = ECHO_STATE_ACTIVE; - } - } - rxlin = 0; - rxchunk[x] = ZT_LIN2X((int)rxlin, ss); - } - } else { -#if !defined(ZT_EC_ARRAY_UPDATE) - for (x=0;x<ZT_CHUNKSIZE;x++) { - rxlin = ZT_XLAW(rxchunk[x], ss); - rxlin = echo_can_update(ss->ec, ZT_XLAW(txchunk[x], ss), rxlin); - rxchunk[x] = ZT_LIN2X((int) rxlin, ss); - } -#else /* defined(ZT_EC_ARRAY_UPDATE) */ - short rxlins[ZT_CHUNKSIZE], txlins[ZT_CHUNKSIZE]; - for (x = 0; x < ZT_CHUNKSIZE; x++) { - rxlins[x] = ZT_XLAW(rxchunk[x], ss); - txlins[x] = ZT_XLAW(txchunk[x], ss); - } - echo_can_array_update(ss->ec, rxlins, txlins); - for (x = 0; x < ZT_CHUNKSIZE; x++) - rxchunk[x] = ZT_LIN2X((int) rxlins[x], ss); -#endif /* defined(ZT_EC_ARRAY_UPDATE) */ - } -#if defined(CONFIG_ZAPTEL_MMX) || defined(ECHO_CAN_FP) - kernel_fpu_end(); -#endif - } - spin_unlock_irqrestore(&ss->lock, flags); -} - -void zt_ec_chunk(struct zt_chan *ss, unsigned char *rxchunk, const unsigned char *txchunk) -{ - __zt_ec_chunk(ss, rxchunk, txchunk); -} - -void zt_ec_span(struct zt_span *span) -{ - int x; - for (x = 0; x < span->channels; x++) { - if (span->chans[x].ec) - __zt_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 (sf_detect_state_t *s, - short *amp, - int samples,long p1, long p2, long p3) -{ -int i,rv = 0; -long x,y; - -#define SF_DETECT_SAMPLES (ZT_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 __zt_process_putaudio_chunk(struct zt_chan *ss, unsigned char *rxb) -{ - /* We transmit data from our master channel */ - /* Called with ss->lock held */ - struct zt_chan *ms = ss->master; - /* Linear version of received data */ - short putlin[ZT_CHUNKSIZE],k[ZT_CHUNKSIZE]; - int x,r; - - if (ms->dialing) ms->afterdialingtimer = 50; - else if (ms->afterdialingtimer) ms->afterdialingtimer--; - if (ms->afterdialingtimer && (!(ms->flags & ZT_FLAG_PSEUDO))) { - /* Be careful since memset is likely a macro */ - rxb[0] = ZT_LIN2X(0, ms); - memset(&rxb[1], rxb[0], ZT_CHUNKSIZE - 1); /* receive as silence if dialing */ - } - for (x=0;x<ZT_CHUNKSIZE;x++) { - rxb[x] = ms->rxgain[rxb[x]]; - putlin[x] = ZT_XLAW(rxb[x], ms); - } - -#ifndef NO_ECHOCAN_DISABLE - if (ms->ec) { - for (x=0;x<ZT_CHUNKSIZE;x++) { - if (echo_can_disable_detector_update(&ms->rxecdis, putlin[x])) { - printk("zaptel Disabled echo canceller because of tone (rx) on channel %d\n", ss->channo); - ms->echocancel = 0; - ms->echostate = ECHO_STATE_IDLE; - ms->echolastupdate = 0; - ms->echotimer = 0; - echo_can_free(ms->ec); - ms->ec = NULL; - break; - } - } - } -#endif - /* if doing rx tone decoding */ - if (ms->rxp1 && ms->rxp2 && ms->rxp3) - { - r = sf_detect(&ms->rd,putlin,ZT_CHUNKSIZE,ms->rxp1, - ms->rxp2,ms->rxp3); - /* Convert back */ - for(x=0;x<ZT_CHUNKSIZE;x++) - rxb[x] = ZT_LIN2X(putlin[x], ms); - if (r) /* if something happened */ - { - if (r != ms->rd.lastdetect) - { - if (((r == 2) && !(ms->toneflags & ZT_REVERSE_RXTONE)) || - ((r == 1) && (ms->toneflags & ZT_REVERSE_RXTONE))) - { - __qevent(ms,ZT_EVENT_RINGOFFHOOK); - } - else - { - __qevent(ms,ZT_EVENT_ONHOOK); - } - ms->rd.lastdetect = r; - } - } - } - - if (!(ms->flags & ZT_FLAG_PSEUDO)) { - memcpy(ms->putlin, putlin, ZT_CHUNKSIZE * sizeof(short)); - memcpy(ms->putraw, rxb, ZT_CHUNKSIZE); - } - - /* Take the rxc, twiddle it for conferencing if appropriate and put it - back */ - if ((!ms->confmute && !ms->afterdialingtimer) || - (ms->flags & ZT_FLAG_PSEUDO)) { - switch(ms->confmode & ZT_CONF_MODE_MASK) { - case ZT_CONF_NORMAL: /* Normal mode */ - /* Do nothing. rx goes output */ - break; - case ZT_CONF_MONITOR: /* Monitor a channel's rx mode */ - /* if not a pseudo-channel, ignore */ - if (!(ms->flags & ZT_FLAG_PSEUDO)) break; - /* Add monitored channel */ - if (chans[ms->confna]->flags & ZT_FLAG_PSEUDO) { - ACSS(putlin, chans[ms->confna]->getlin); - } else { - ACSS(putlin, chans[ms->confna]->putlin); - } - /* Convert back */ - for(x=0;x<ZT_CHUNKSIZE;x++) - rxb[x] = ZT_LIN2X(putlin[x], ms); - break; - case ZT_CONF_MONITORTX: /* Monitor a channel's tx mode */ - /* if not a pseudo-channel, ignore */ - if (!(ms->flags & ZT_FLAG_PSEUDO)) break; - /* Add monitored channel */ - if (chans[ms->confna]->flags & ZT_FLAG_PSEUDO) { - ACSS(putlin, chans[ms->confna]->putlin); - } else { - ACSS(putlin, chans[ms->confna]->getlin); - } - /* Convert back */ - for(x=0;x<ZT_CHUNKSIZE;x++) - rxb[x] = ZT_LIN2X(putlin[x], ms); - break; - case ZT_CONF_MONITORBOTH: /* Monitor a channel's tx and rx mode */ - /* if not a pseudo-channel, ignore */ - if (!(ms->flags & ZT_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<ZT_CHUNKSIZE;x++) - rxb[x] = ZT_LIN2X(putlin[x], ms); - break; - case ZT_CONF_MONITOR_RX_PREECHO: /* Monitor a channel's rx mode */ - /* if not a pseudo-channel, ignore */ - if (!(ms->flags & ZT_FLAG_PSEUDO)) - break; - - if (!chans[ms->confna]->readchunkpreec) - break; - - /* Add monitored channel */ - ACSS(putlin, chans[ms->confna]->flags & ZT_FLAG_PSEUDO ? - chans[ms->confna]->getlin : chans[ms->confna]->readchunkpreec); - for (x = 0; x < ZT_CHUNKSIZE; x++) - rxb[x] = ZT_LIN2X(putlin[x], ms); - - break; - case ZT_CONF_MONITOR_TX_PREECHO: /* Monitor a channel's tx mode */ - /* if not a pseudo-channel, ignore */ - if (!(ms->flags & ZT_FLAG_PSEUDO)) - break; - - if (!chans[ms->confna]->readchunkpreec) - break; - - /* Add monitored channel */ - ACSS(putlin, chans[ms->confna]->flags & ZT_FLAG_PSEUDO ? - chans[ms->confna]->readchunkpreec : chans[ms->confna]->getlin); - for (x = 0; x < ZT_CHUNKSIZE; x++) - rxb[x] = ZT_LIN2X(putlin[x], ms); - - break; - case ZT_CONF_MONITORBOTH_PREECHO: /* Monitor a channel's tx and rx mode */ - /* if not a pseudo-channel, ignore */ - if (!(ms->flags & ZT_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 < ZT_CHUNKSIZE; x++) - rxb[x] = ZT_LIN2X(putlin[x], ms); - - break; - case ZT_CONF_REALANDPSEUDO: - /* do normal conf mode processing */ - if (ms->confmode & ZT_CONF_TALKER) { - /* Store temp value */ - memcpy(k, putlin, ZT_CHUNKSIZE * sizeof(short)); - /* Add conf value */ - ACSS(k, conf_sums_next[ms->_confn]); - /* get amount actually added */ - memcpy(ms->conflast, k, ZT_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, ZT_CHUNKSIZE * sizeof(short)); - /* do the pseudo-channel part processing */ - memset(putlin, 0, ZT_CHUNKSIZE * sizeof(short)); - if (ms->confmode & ZT_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<ZT_CHUNKSIZE;x++) - rxb[x] = ZT_LIN2X(putlin[x], ms); - break; - case ZT_CONF_CONF: /* Normal conference mode */ - if (ms->flags & ZT_FLAG_PSEUDO) /* if a pseudo-channel */ - { - if (ms->confmode & ZT_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<ZT_CHUNKSIZE;x++) - rxb[x] = ZT_LIN2X(putlin[x], ms); - memcpy(ss->getlin, putlin, ZT_CHUNKSIZE * sizeof(short)); - break; - } - /* fall through */ - case ZT_CONF_CONFANN: /* Conference with announce */ - if (ms->confmode & ZT_CONF_TALKER) { - /* Store temp value */ - memcpy(k, putlin, ZT_CHUNKSIZE * sizeof(short)); - /* Add conf value */ - ACSS(k, conf_sums_next[ms->_confn]); - /* get amount actually added */ - memcpy(ms->conflast, k, ZT_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, ZT_CHUNKSIZE * sizeof(short)); - /* rxc unmodified */ - break; - case ZT_CONF_CONFMON: - case ZT_CONF_CONFANNMON: - if (ms->confmode & ZT_CONF_TALKER) { - /* Store temp value */ - memcpy(k, putlin, ZT_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, ZT_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, ZT_CHUNKSIZE * sizeof(short)); - for (x=0;x<ZT_CHUNKSIZE;x++) - rxb[x] = ZT_LIN2X((int)conf_sums_prev[ms->_confn][x], ms); - break; - case ZT_CONF_DIGITALMON: - /* if not a pseudo-channel, ignore */ - if (!(ms->flags & ZT_FLAG_PSEUDO)) break; - /* Add monitored channel */ - if (chans[ms->confna]->flags & ZT_FLAG_PSEUDO) { - memcpy(rxb, chans[ms->confna]->getraw, ZT_CHUNKSIZE); - } else { - memcpy(rxb, chans[ms->confna]->putraw, ZT_CHUNKSIZE); - } - break; - } - } -} - -/* HDLC (or other) receiver buffer functions for read side */ -static inline void __putbuf_chunk(struct zt_chan *ss, unsigned char *rxb, int bytes) -{ - /* We transmit data from our master channel */ - /* Called with ss->lock held */ - struct zt_chan *ms = ss->master; - /* Our receive buffer */ - unsigned char *buf; -#if defined(CONFIG_ZAPATA_NET) || defined(CONFIG_ZAPATA_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_ZAPATA_NET) || defined(CONFIG_ZAPATA_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 & ZT_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 & ZT_FLAG_FCS) && (ms->infcs != PPP_GOODFCS)) { - abort = ZT_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 = ZT_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) - printk(KERN_WARNING "HDLC Receiver overrun on channel %s (master=%s)\n", ss->name, ss->master->name); - abort=ZT_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 & ZT_FLAG_NOSTDTXRX)) { - eof = 0; - abort = ZT_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_ZAPATA_DEBUG - printk("EOF, len is %d\n", ms->readn[ms->inreadbuf]); -#endif -#if defined(CONFIG_ZAPATA_NET) || defined(CONFIG_ZAPATA_PPP) - if (ms->flags & (ZT_FLAG_NETDEV | ZT_FLAG_PPP)) { -#ifdef CONFIG_ZAPATA_NET -#endif /* CONFIG_ZAPATA_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_ZAPATA_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_ZAPATA_NET - if (ms->flags & ZT_FLAG_NETDEV) { -#ifdef LINUX26 - struct net_device_stats *stats = hdlc_stats(ms->hdlcnetdev->netdev); -#else /* LINUX26 */ - struct net_device_stats *stats = &ms->hdlcnetdev->netdev.stats; -#endif /* LINUX26 */ - stats->rx_packets++; - stats->rx_bytes += ms->readn[ms->inreadbuf]; - } -#endif - - } else { -#ifdef CONFIG_ZAPATA_NET - if (ms->flags & ZT_FLAG_NETDEV) { -#ifdef LINUX26 - struct net_device_stats *stats = hdlc_stats(ms->hdlcnetdev->netdev); -#else /* LINUX26 */ - struct net_device_stats *stats = &ms->hdlcnetdev->netdev.stats; -#endif /* LINUX26 */ - stats->rx_dropped++; - } -#endif -#ifdef CONFIG_ZAPATA_PPP - if (ms->flags & ZT_FLAG_PPP) { - abort = ZT_EVENT_OVERRUN; - } -#endif -#if 1 -#ifdef CONFIG_ZAPATA_PPP - if (!ms->do_ppp_error) -#endif - printk("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 - { - 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 CONFIG_ZAPATA_DEBUG - printk("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; - } -/* 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. */ - 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_ZAPATA_DEBUG - printk("Notifying reader data in block %d\n", oldbuf); -#endif - wake_up_interruptible(&ms->readbufq); - wake_up_interruptible(&ms->sel); - if (ms->iomask & ZT_IOMUX_READ) - wake_up_interruptible(&ms->eventbufq); - } - } - } - if (abort) { - /* Start over reading frame */ - ms->readidx[ms->inreadbuf] = 0; - ms->infcs = PPP_INITFCS; - -#ifdef CONFIG_ZAPATA_NET - if (ms->flags & ZT_FLAG_NETDEV) { -#ifdef LINUX26 - struct net_device_stats *stats = hdlc_stats(ms->hdlcnetdev->netdev); -#else /* LINUX26 */ - struct net_device_stats *stats = &ms->hdlcnetdev->netdev.stats; -#endif /* LINUX26 */ - stats->rx_errors++; - if (abort == ZT_EVENT_OVERRUN) - stats->rx_over_errors++; - if (abort == ZT_EVENT_BADFCS) - stats->rx_crc_errors++; - if (abort == ZT_EVENT_ABORT) - stats->rx_frame_errors++; - } else -#endif -#ifdef CONFIG_ZAPATA_PPP - if (ms->flags & ZT_FLAG_PPP) { - ms->do_ppp_error = 1; - tasklet_schedule(&ms->ppp_calls); - } else -#endif - - if ((ms->flags & ZT_FLAG_OPEN) && !ss->span->alarms) - /* Notify the receiver... */ - __qevent(ss->master, abort); -#if 0 - printk("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_ZAPATA_NET - if (skb && (ms->flags & ZT_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 ZAP_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_ZAPATA_PPP - if (skb && (ms->flags & ZT_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) - printk("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 __zt_putbuf_chunk(struct zt_chan *ss, unsigned char *rxb) -{ - __putbuf_chunk(ss, rxb, ZT_CHUNKSIZE); -} - -static void __zt_hdlc_abort(struct zt_chan *ss, int event) -{ - if (ss->inreadbuf >= 0) - ss->readidx[ss->inreadbuf] = 0; - if ((ss->flags & ZT_FLAG_OPEN) && !ss->span->alarms) - __qevent(ss->master, event); -} - -extern void zt_hdlc_abort(struct zt_chan *ss, int event) -{ - unsigned long flags; - spin_lock_irqsave(&ss->lock, flags); - __zt_hdlc_abort(ss, event); - spin_unlock_irqrestore(&ss->lock, flags); -} - -extern void zt_hdlc_putbuf(struct zt_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_ZAPATA_DEBUG - printk("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_ZAPATA_DEBUG - printk("HDLC frame isn't fit into buffer space\n"); -#endif - __zt_hdlc_abort(ss, ZT_EVENT_OVERRUN); - } - res = left; - spin_unlock_irqrestore(&ss->lock, flags); -} - -extern void zt_hdlc_finish(struct zt_chan *ss) -{ - int oldreadbuf; - unsigned long flags; - - spin_lock_irqsave(&ss->lock, flags); - - if ((oldreadbuf = ss->inreadbuf) < 0) { -#ifdef CONFIG_ZAPATA_DEBUG - printk("No buffers to finish\n"); -#endif - spin_unlock_irqrestore(&ss->lock, flags); - return; - } - - if (!ss->readidx[ss->inreadbuf]) { -#ifdef CONFIG_ZAPATA_DEBUG - printk("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_ZAPATA_DEBUG - printk("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 & ZT_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 */ -extern int zt_hdlc_getbuf(struct zt_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 & (ZT_IOMUX_WRITE | ZT_IOMUX_WRITEEMPTY)) - wake_up_interruptible(&ss->eventbufq); - /* If we're only supposed to start when full, disable the transmitter */ - if (ss->txbufpolicy == ZT_POLICY_WHEN_FULL) - ss->txdisable = 1; - res = -1; - } - - if (ss->inwritebuf < 0) - ss->inwritebuf = oldbuf; - - if (!(ss->flags & (ZT_FLAG_NETDEV | ZT_FLAG_PPP))) { - wake_up_interruptible(&ss->writebufq); - wake_up_interruptible(&ss->sel); - if ((ss->iomask & ZT_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 zt_timer *cur; - spin_lock_irqsave(&zaptimerlock, flags); - cur = zaptimers; - while(cur) { - if (cur->ms) { - cur->pos -= ZT_CHUNKSIZE; - if (cur->pos <= 0) { - cur->tripped++; - cur->pos = cur->ms; - wake_up_interruptible(&cur->sel); - } - } - cur = cur->next; - } - spin_unlock_irqrestore(&zaptimerlock, flags); -} - -static unsigned int zt_timer_poll(struct file *file, struct poll_table_struct *wait_table) -{ - struct zt_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 -zt_chan_poll(struct file *file, struct poll_table_struct *wait_table, int unit) -{ - - struct zt_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 zt_mmap(struct file *file, struct vm_area_struct *vm) -{ - int unit = UNIT(file); - if (unit == 250) - return zt_transcode_fops->mmap(file, vm); - return -ENOSYS; -} - -static unsigned int zt_poll(struct file *file, struct poll_table_struct *wait_table) -{ - int unit = UNIT(file); - struct zt_chan *chan; - - if (!unit) - return -EINVAL; - - if (unit == 250) - return zt_transcode_fops->poll(file, wait_table); - - if (unit == 253) - return zt_timer_poll(file, wait_table); - - if (unit == 254) { - chan = file->private_data; - if (!chan) - return -EINVAL; - return zt_chan_poll(file, wait_table,chan->channo); - } - if (unit == 255) { - chan = file->private_data; - if (!chan) { - printk("No pseudo channel structure to read?\n"); - return -EINVAL; - } - return zt_chan_poll(file, wait_table, chan->channo); - } - return zt_chan_poll(file, wait_table, unit); -} - -static void __zt_transmit_chunk(struct zt_chan *chan, unsigned char *buf) -{ - unsigned char silly[ZT_CHUNKSIZE]; - /* Called with chan->lock locked */ -#ifdef OPTIMIZE_CHANMUTE - if(likely(chan->chanmute)) - return; -#endif - if (!buf) - buf = silly; - __zt_getbuf_chunk(chan, buf); - - if ((chan->flags & ZT_FLAG_AUDIO) || (chan->confmode)) { -#ifdef CONFIG_ZAPTEL_MMX - zt_kernel_fpu_begin(); -#endif - __zt_process_getaudio_chunk(chan, buf); -#ifdef CONFIG_ZAPTEL_MMX - kernel_fpu_end(); -#endif - } -} - -static inline void __zt_real_transmit(struct zt_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, "zt_real_transmit"); - } else { - __zt_transmit_chunk(chan, chan->writechunk); - } -} - -static void __zt_getempty(struct zt_chan *ms, unsigned char *buf) -{ - int bytes = ZT_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 = zt_tone_nextsample(&ms->ts, ms->curtone); - *(txb++) = ZT_LIN2X(getlin, ms); - } - ms->tonep+=left; - bytes -= left; - if (ms->tonep >= ms->curtone->tonesamples) { - struct zt_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) - zt_init_tone_state(&ms->ts, ms->curtone); - } - } - } else { - /* Use silence */ - memset(txb, ZT_LIN2X(0, ms), bytes); - bytes = 0; - } - } - -} - -static void __zt_receive_chunk(struct zt_chan *chan, unsigned char *buf) -{ - /* Receive chunk of audio -- called with chan->lock held */ - unsigned char waste[ZT_CHUNKSIZE]; - -#ifdef OPTIMIZE_CHANMUTE - if(likely(chan->chanmute)) - return; -#endif - if (!buf) { - memset(waste, ZT_LIN2X(0, chan), sizeof(waste)); - buf = waste; - } - if ((chan->flags & ZT_FLAG_AUDIO) || (chan->confmode)) { -#ifdef CONFIG_ZAPTEL_MMX - zt_kernel_fpu_begin(); -#endif - __zt_process_putaudio_chunk(chan, buf); -#ifdef CONFIG_ZAPTEL_MMX - kernel_fpu_end(); -#endif - } - __zt_putbuf_chunk(chan, buf); -} - -static inline void __zt_real_receive(struct zt_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, "zt_real_receive"); - } else { - __zt_receive_chunk(chan, chan->readchunk); - } -} - -int zt_transmit(struct zt_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 & ZT_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 -= ZT_CHUNKSIZE; - if (span->chans[x].otimer <= 0) { - __rbs_otimer_expire(&span->chans[x]); - } - } - if (span->chans[x].flags & ZT_FLAG_AUDIO) { - __zt_real_transmit(&span->chans[x]); - } else { - if (span->chans[x].nextslave) { - u_char data[ZT_CHUNKSIZE]; - int pos=ZT_CHUNKSIZE; - /* Process master/slaves one way */ - for (y=0;y<ZT_CHUNKSIZE;y++) { - /* Process slaves for this byte too */ - z = x; - do { - if (pos==ZT_CHUNKSIZE) { - /* Get next chunk */ - __zt_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 */ - __zt_real_transmit(&span->chans[x]); - } - } - if (span->chans[x].sig == ZT_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 -= ZT_CHUNKSIZE; - if (span->mainttimer <= 0) { - span->mainttimer = 0; - if (span->maint) - span->maint(span, ZT_MAINT_LOOPSTOP); - span->maintstat = 0; - wake_up_interruptible(&span->maintq); - } - } -#endif - return 0; -} - -int zt_receive(struct zt_span *span) -{ - int x,y,z; - unsigned long flags, flagso; - -#if 1 -#ifdef CONFIG_ZAPTEL_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[ZT_CHUNKSIZE]; - int pos = 0; - for (y=0;y<ZT_CHUNKSIZE;y++) { - /* Put all its slaves, too */ - z = x; - do { - data[pos++] = span->chans[z].readchunk[y]; - if (pos == ZT_CHUNKSIZE) { - if(!(span->chans[x].flags & ZT_FLAG_NOSTDTXRX)) - __zt_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 & ZT_FLAG_NOSTDTXRX)) - __zt_real_receive(&span->chans[x]); - } - if (span->chans[x].itimer) { - span->chans[x].itimer -= ZT_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 & __ZT_SIG_FXS) { - if (span->chans[x].rxhooksig == ZT_RXSIG_RING) - span->chans[x].ringtrailer = ZT_RINGTRAILER; - else if (span->chans[x].ringtrailer) { - span->chans[x].ringtrailer-= ZT_CHUNKSIZE; - /* See if RING trailer is expired */ - if (!span->chans[x].ringtrailer && !span->chans[x].ringdebtimer) - __qevent(&span->chans[x],ZT_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) { - - printk("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], ZT_EVENT_PULSEDIGIT | '#'); - } else if (span->chans[x].pulsecount > 10) { - __qevent(&span->chans[x], ZT_EVENT_PULSEDIGIT | '*'); - } else if (span->chans[x].pulsecount > 9) { - __qevent(&span->chans[x], ZT_EVENT_PULSEDIGIT | '0'); - } else { - __qevent(&span->chans[x], ZT_EVENT_PULSEDIGIT | ('0' + - span->chans[x].pulsecount)); - } - span->chans[x].pulsecount = 0; - } - } - } - 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, flagso); - /* Process any timers */ - process_timers(); - /* If we have dynamic stuff, call the ioctl with 0,0 parameters to - make it run */ - if (zt_dynamic_ioctl) - zt_dynamic_ioctl(0,0); - for (x=1;x<maxchans;x++) { - if (chans[x] && chans[x]->confmode && !(chans[x]->flags & ZT_FLAG_PSEUDO)) { - u_char *data; - spin_lock_irqsave(&chans[x]->lock, flags); - data = __buf_peek(&chans[x]->confin); - __zt_receive_chunk(chans[x], data); - if (data) - __buf_pull(&chans[x]->confin, NULL,chans[x], "confreceive"); - spin_unlock_irqrestore(&chans[x]->lock, flags); - } - } - /* 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 & ZT_FLAG_PSEUDO)) { - spin_lock_irqsave(&chans[x]->lock, flags); - __zt_transmit_chunk(chans[x], NULL); - spin_unlock_irqrestore(&chans[x]->lock, flags); - } - } - if (maxlinks) { -#ifdef CONFIG_ZAPTEL_MMX - zt_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_ZAPTEL_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 & ZT_FLAG_PSEUDO)) { - unsigned char tmp[ZT_CHUNKSIZE]; - spin_lock_irqsave(&chans[x]->lock, flags); - __zt_getempty(chans[x], tmp); - __zt_receive_chunk(chans[x], tmp); - spin_unlock_irqrestore(&chans[x]->lock, flags); - } - } - for (x=1;x<maxchans;x++) { - if (chans[x] && chans[x]->confmode && !(chans[x]->flags & ZT_FLAG_PSEUDO)) { - u_char *data; - spin_lock_irqsave(&chans[x]->lock, flags); - data = __buf_pushpeek(&chans[x]->confout); - __zt_transmit_chunk(chans[x], data); - if (data) - __buf_push(&chans[x]->confout, NULL, "conftransmit"); - spin_unlock_irqrestore(&chans[x]->lock, flags); - } - } -#ifdef ZAPTEL_SYNC_TICK - for (x=0;x<maxspans;x++) { - struct zt_span *s = spans[x]; - - if (s && s->sync_tick) - s->sync_tick(s, s == master); - } -#endif - spin_unlock_irqrestore(&bigzaplock, flagso); - } -#endif - return 0; -} - -MODULE_AUTHOR("Mark Spencer <markster@digium.com>"); -MODULE_DESCRIPTION("Zapata Telephony Interface"); -#ifdef MODULE_LICENSE -MODULE_LICENSE("GPL"); -#endif -#ifdef MODULE_VERSION -MODULE_VERSION(ZAPTEL_VERSION); -#endif - -#ifdef LINUX26 -module_param(debug, int, 0600); -module_param(deftaps, int, 0600); -#else -MODULE_PARM(debug, "i"); -MODULE_PARM(deftaps, "i"); -#endif - -static struct file_operations zt_fops = { - owner: THIS_MODULE, - llseek: NULL, - open: zt_open, - release: zt_release, - ioctl: zt_ioctl, - read: zt_read, - write: zt_write, - poll: zt_poll, - mmap: zt_mmap, - flush: NULL, - fsync: NULL, - fasync: NULL, -}; - -#ifdef CONFIG_ZAPTEL_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 & ZT_FLAG_RUNNING)) { - if (spans[x]->watchcounter == ZT_WATCHDOG_INIT) { - /* Whoops, dead card */ - if ((spans[x]->watchstate == ZT_WATCHSTATE_OK) || - (spans[x]->watchstate == ZT_WATCHSTATE_UNKNOWN)) { - spans[x]->watchstate = ZT_WATCHSTATE_RECOVERING; - if (spans[x]->watchdog) { - printk("Kicking span %s\n", spans[x]->name); - spans[x]->watchdog(spans[x], ZT_WATCHDOG_NOINTS); - } else { - printk("Span %s is dead with no revival\n", spans[x]->name); - spans[x]->watchstate = ZT_WATCHSTATE_FAILED; - } - } - } else { - if ((spans[x]->watchstate != ZT_WATCHSTATE_OK) && - (spans[x]->watchstate != ZT_WATCHSTATE_UNKNOWN)) - printk("Span %s is alive!\n", spans[x]->name); - spans[x]->watchstate = ZT_WATCHSTATE_OK; - } - spans[x]->watchcounter = ZT_WATCHDOG_INIT; - } - } - local_irq_restore(flags); - if (!wdcheck) { - printk("Zaptel 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 zt_register_chardev(struct zt_chardev *dev) -{ -#ifdef CONFIG_ZAP_UDEV - char udevname[strlen(dev->name) + 3]; - - strcpy(udevname, "zap"); - strcat(udevname, dev->name); - CLASS_DEV_CREATE(zap_class, MKDEV(ZT_MAJOR, dev->minor), NULL, udevname); -#endif /* CONFIG_ZAP_UDEV */ - -#ifdef CONFIG_DEVFS_FS - dev->devfs_handle = devfs_register(zaptel_devfs_dir, dev->name, DEVFS_FL_DEFAULT, ZT_MAJOR, dev->minor, ZT_DEVFS_MODE, &zt_fops, NULL); -#endif /* CONFIG_DEVFS_FS */ - - return 0; -} - -int zt_unregister_chardev(struct zt_chardev *dev) -{ -#ifdef CONFIG_ZAP_UDEV - class_device_destroy(zap_class, MKDEV(ZT_MAJOR, dev->minor)); -#endif /* CONFIG_ZAP_UDEV */ - -#ifdef CONFIG_DEVFS_FS - devfs_unregister(dev->devfs_handle); -#endif /* CONFIG_DEVFS_FS */ - - return 0; -} - -static int __init zt_init(void) { - int res = 0; - -#ifdef CONFIG_PROC_FS - proc_entries[0] = proc_mkdir("zaptel", NULL); -#endif - -#ifdef CONFIG_ZAP_UDEV /* udev support functions */ - zap_class = class_create(THIS_MODULE, "zaptel"); - CLASS_DEV_CREATE(zap_class, MKDEV(ZT_MAJOR, 253), NULL, "zaptimer"); - CLASS_DEV_CREATE(zap_class, MKDEV(ZT_MAJOR, 254), NULL, "zapchannel"); - CLASS_DEV_CREATE(zap_class, MKDEV(ZT_MAJOR, 255), NULL, "zappseudo"); - CLASS_DEV_CREATE(zap_class, MKDEV(ZT_MAJOR, 0), NULL, "zapctl"); -#endif /* CONFIG_ZAP_UDEV */ - -#ifdef CONFIG_DEVFS_FS - { - devfs_register_chrdev(ZT_MAJOR, "zaptel", &zt_fops); - if (!(zaptel_devfs_dir = devfs_mk_dir(NULL, "zap", NULL))) - return -EBUSY; /* This would be bad */ - timer = devfs_register(zaptel_devfs_dir, "timer", DEVFS_FL_DEFAULT, ZT_MAJOR, 253, ZT_DEVFS_MODE, &zt_fops, NULL); - channel = devfs_register(zaptel_devfs_dir, "channel", DEVFS_FL_DEFAULT, ZT_MAJOR, 254, ZT_DEVFS_MODE, &zt_fops, NULL); - pseudo = devfs_register(zaptel_devfs_dir, "pseudo", DEVFS_FL_DEFAULT, ZT_MAJOR, 255, ZT_DEVFS_MODE, &zt_fops, NULL); - ctl = devfs_register(zaptel_devfs_dir, "ctl", DEVFS_FL_DEFAULT, ZT_MAJOR, 0, ZT_DEVFS_MODE, &zt_fops, NULL); - } -#else - if ((res = register_chrdev(ZT_MAJOR, "zaptel", &zt_fops))) { - printk(KERN_ERR "Unable to register Zaptel character device handler on %d\n", ZT_MAJOR); - return res; - } -#endif /* CONFIG_DEVFS_FS */ - - printk(KERN_INFO "Zapata Telephony Interface Registered on major %d\n", ZT_MAJOR); - printk(KERN_INFO "Zaptel Version: %s\n", ZAPTEL_VERSION); - echo_can_init(); - zt_conv_init(); - fasthdlc_precalc(); - rotate_sums(); - rwlock_init(&chan_lock); -#ifdef CONFIG_ZAPTEL_WATCHDOG - watchdog_init(); -#endif - return res; -} - -static void __exit zt_cleanup(void) { - int x; - -#ifdef CONFIG_PROC_FS - remove_proc_entry("zaptel", NULL); -#endif - - printk(KERN_INFO "Zapata Telephony Interface Unloaded\n"); - for (x = 0; x < ZT_TONE_ZONE_MAX; x++) { - if (tone_zones[x]) - kfree(tone_zones[x]); - } - -#ifdef CONFIG_DEVFS_FS - devfs_unregister(timer); - devfs_unregister(channel); - devfs_unregister(pseudo); - devfs_unregister(ctl); - devfs_unregister(zaptel_devfs_dir); - devfs_unregister_chrdev(ZT_MAJOR, "zaptel"); -#else -#ifdef CONFIG_ZAP_UDEV - class_device_destroy(zap_class, MKDEV(ZT_MAJOR, 253)); /* timer */ - class_device_destroy(zap_class, MKDEV(ZT_MAJOR, 254)); /* channel */ - class_device_destroy(zap_class, MKDEV(ZT_MAJOR, 255)); /* pseudo */ - class_device_destroy(zap_class, MKDEV(ZT_MAJOR, 0)); /* ctl */ - class_destroy(zap_class); -#endif /* CONFIG_ZAP_UDEV */ - unregister_chrdev(ZT_MAJOR, "zaptel"); -#endif -#ifdef CONFIG_ZAPTEL_WATCHDOG - watchdog_cleanup(); -#endif - - echo_can_shutdown(); -} - -module_init(zt_init); -module_exit(zt_cleanup); |