diff options
Diffstat (limited to 'drivers/isdn/mISDN')
30 files changed, 2917 insertions, 1987 deletions
diff --git a/drivers/isdn/mISDN/Kconfig b/drivers/isdn/mISDN/Kconfig index 4938355c407..c0730d5c734 100644 --- a/drivers/isdn/mISDN/Kconfig +++ b/drivers/isdn/mISDN/Kconfig @@ -14,13 +14,15 @@ config MISDN_DSP depends on MISDN help Enable support for digital audio processing capability. + This module may be used for special applications that require - cross connecting of bchannels, conferencing, dtmf decoding - echo cancelation, tone generation, and Blowfish encryption and - decryption. - It may use hardware features if available. + cross connecting of bchannels, conferencing, dtmf decoding, + echo cancellation, tone generation, and Blowfish encryption and + decryption. It may use hardware features if available. + E.g. it is required for PBX4Linux. Go to http://isdn.eversberg.eu - and get more informations about this module and it's usage. + and get more information about this module and its usage. + If unsure, say 'N'. config MISDN_L1OIP diff --git a/drivers/isdn/mISDN/Makefile b/drivers/isdn/mISDN/Makefile index 1cb5e633cf7..0a6bd2a9e73 100644 --- a/drivers/isdn/mISDN/Makefile +++ b/drivers/isdn/mISDN/Makefile @@ -8,6 +8,6 @@ obj-$(CONFIG_MISDN_L1OIP) += l1oip.o # multi objects -mISDN_core-objs := core.o fsm.o socket.o hwchannel.o stack.o layer1.o layer2.o tei.o timerdev.o +mISDN_core-objs := core.o fsm.o socket.o clock.o hwchannel.o stack.o layer1.o layer2.o tei.o timerdev.o mISDN_dsp-objs := dsp_core.o dsp_cmx.o dsp_tones.o dsp_dtmf.o dsp_audio.o dsp_blowfish.o dsp_pipeline.o dsp_hwec.o l1oip-objs := l1oip_core.o l1oip_codec.o diff --git a/drivers/isdn/mISDN/clock.c b/drivers/isdn/mISDN/clock.c new file mode 100644 index 00000000000..693fb7c9b59 --- /dev/null +++ b/drivers/isdn/mISDN/clock.c @@ -0,0 +1,217 @@ +/* + * Copyright 2008 by Andreas Eversberg <andreas@eversberg.eu> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * 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. + * + * Quick API description: + * + * A clock source registers using mISDN_register_clock: + * name = text string to name clock source + * priority = value to priorize clock sources (0 = default) + * ctl = callback function to enable/disable clock source + * priv = private pointer of clock source + * return = pointer to clock source structure; + * + * Note: Callback 'ctl' can be called before mISDN_register_clock returns! + * Also it can be called during mISDN_unregister_clock. + * + * A clock source calls mISDN_clock_update with given samples elapsed, if + * enabled. If function call is delayed, tv must be set with the timestamp + * of the actual event. + * + * A clock source unregisters using mISDN_unregister_clock. + * + * To get current clock, call mISDN_clock_get. The signed short value + * counts the number of samples since. Time since last clock event is added. + * + */ + +#include <linux/slab.h> +#include <linux/types.h> +#include <linux/stddef.h> +#include <linux/spinlock.h> +#include <linux/mISDNif.h> +#include <linux/export.h> +#include "core.h" + +static u_int *debug; +static LIST_HEAD(iclock_list); +static DEFINE_RWLOCK(iclock_lock); +static u16 iclock_count; /* counter of last clock */ +static struct timeval iclock_tv; /* time stamp of last clock */ +static int iclock_tv_valid; /* already received one timestamp */ +static struct mISDNclock *iclock_current; + +void +mISDN_init_clock(u_int *dp) +{ + debug = dp; + do_gettimeofday(&iclock_tv); +} + +static void +select_iclock(void) +{ + struct mISDNclock *iclock, *bestclock = NULL, *lastclock = NULL; + int pri = -128; + + list_for_each_entry(iclock, &iclock_list, list) { + if (iclock->pri > pri) { + pri = iclock->pri; + bestclock = iclock; + } + if (iclock_current == iclock) + lastclock = iclock; + } + if (lastclock && bestclock != lastclock) { + /* last used clock source still exists but changes, disable */ + if (*debug & DEBUG_CLOCK) + printk(KERN_DEBUG "Old clock source '%s' disable.\n", + lastclock->name); + lastclock->ctl(lastclock->priv, 0); + } + if (bestclock && bestclock != iclock_current) { + /* new clock source selected, enable */ + if (*debug & DEBUG_CLOCK) + printk(KERN_DEBUG "New clock source '%s' enable.\n", + bestclock->name); + bestclock->ctl(bestclock->priv, 1); + } + if (bestclock != iclock_current) { + /* no clock received yet */ + iclock_tv_valid = 0; + } + iclock_current = bestclock; +} + +struct mISDNclock +*mISDN_register_clock(char *name, int pri, clockctl_func_t *ctl, void *priv) +{ + u_long flags; + struct mISDNclock *iclock; + + if (*debug & (DEBUG_CORE | DEBUG_CLOCK)) + printk(KERN_DEBUG "%s: %s %d\n", __func__, name, pri); + iclock = kzalloc(sizeof(struct mISDNclock), GFP_ATOMIC); + if (!iclock) { + printk(KERN_ERR "%s: No memory for clock entry.\n", __func__); + return NULL; + } + strncpy(iclock->name, name, sizeof(iclock->name) - 1); + iclock->pri = pri; + iclock->priv = priv; + iclock->ctl = ctl; + write_lock_irqsave(&iclock_lock, flags); + list_add_tail(&iclock->list, &iclock_list); + select_iclock(); + write_unlock_irqrestore(&iclock_lock, flags); + return iclock; +} +EXPORT_SYMBOL(mISDN_register_clock); + +void +mISDN_unregister_clock(struct mISDNclock *iclock) +{ + u_long flags; + + if (*debug & (DEBUG_CORE | DEBUG_CLOCK)) + printk(KERN_DEBUG "%s: %s %d\n", __func__, iclock->name, + iclock->pri); + write_lock_irqsave(&iclock_lock, flags); + if (iclock_current == iclock) { + if (*debug & DEBUG_CLOCK) + printk(KERN_DEBUG + "Current clock source '%s' unregisters.\n", + iclock->name); + iclock->ctl(iclock->priv, 0); + } + list_del(&iclock->list); + select_iclock(); + write_unlock_irqrestore(&iclock_lock, flags); +} +EXPORT_SYMBOL(mISDN_unregister_clock); + +void +mISDN_clock_update(struct mISDNclock *iclock, int samples, struct timeval *tv) +{ + u_long flags; + struct timeval tv_now; + time_t elapsed_sec; + int elapsed_8000th; + + write_lock_irqsave(&iclock_lock, flags); + if (iclock_current != iclock) { + printk(KERN_ERR "%s: '%s' sends us clock updates, but we do " + "listen to '%s'. This is a bug!\n", __func__, + iclock->name, + iclock_current ? iclock_current->name : "nothing"); + iclock->ctl(iclock->priv, 0); + write_unlock_irqrestore(&iclock_lock, flags); + return; + } + if (iclock_tv_valid) { + /* increment sample counter by given samples */ + iclock_count += samples; + if (tv) { /* tv must be set, if function call is delayed */ + iclock_tv.tv_sec = tv->tv_sec; + iclock_tv.tv_usec = tv->tv_usec; + } else + do_gettimeofday(&iclock_tv); + } else { + /* calc elapsed time by system clock */ + if (tv) { /* tv must be set, if function call is delayed */ + tv_now.tv_sec = tv->tv_sec; + tv_now.tv_usec = tv->tv_usec; + } else + do_gettimeofday(&tv_now); + elapsed_sec = tv_now.tv_sec - iclock_tv.tv_sec; + elapsed_8000th = (tv_now.tv_usec / 125) + - (iclock_tv.tv_usec / 125); + if (elapsed_8000th < 0) { + elapsed_sec -= 1; + elapsed_8000th += 8000; + } + /* add elapsed time to counter and set new timestamp */ + iclock_count += elapsed_sec * 8000 + elapsed_8000th; + iclock_tv.tv_sec = tv_now.tv_sec; + iclock_tv.tv_usec = tv_now.tv_usec; + iclock_tv_valid = 1; + if (*debug & DEBUG_CLOCK) + printk("Received first clock from source '%s'.\n", + iclock_current ? iclock_current->name : "nothing"); + } + write_unlock_irqrestore(&iclock_lock, flags); +} +EXPORT_SYMBOL(mISDN_clock_update); + +unsigned short +mISDN_clock_get(void) +{ + u_long flags; + struct timeval tv_now; + time_t elapsed_sec; + int elapsed_8000th; + u16 count; + + read_lock_irqsave(&iclock_lock, flags); + /* calc elapsed time by system clock */ + do_gettimeofday(&tv_now); + elapsed_sec = tv_now.tv_sec - iclock_tv.tv_sec; + elapsed_8000th = (tv_now.tv_usec / 125) - (iclock_tv.tv_usec / 125); + if (elapsed_8000th < 0) { + elapsed_sec -= 1; + elapsed_8000th += 8000; + } + /* add elapsed time to counter */ + count = iclock_count + elapsed_sec * 8000 + elapsed_8000th; + read_unlock_irqrestore(&iclock_lock, flags); + return count; +} +EXPORT_SYMBOL(mISDN_clock_get); diff --git a/drivers/isdn/mISDN/core.c b/drivers/isdn/mISDN/core.c index 33068177b7c..faf505462a4 100644 --- a/drivers/isdn/mISDN/core.c +++ b/drivers/isdn/mISDN/core.c @@ -12,6 +12,7 @@ * */ +#include <linux/slab.h> #include <linux/types.h> #include <linux/stddef.h> #include <linux/module.h> @@ -25,39 +26,187 @@ MODULE_AUTHOR("Karsten Keil"); MODULE_LICENSE("GPL"); module_param(debug, uint, S_IRUGO | S_IWUSR); -static LIST_HEAD(devices); -DEFINE_RWLOCK(device_lock); static u64 device_ids; #define MAX_DEVICE_ID 63 static LIST_HEAD(Bprotocols); -DEFINE_RWLOCK(bp_lock); +static DEFINE_RWLOCK(bp_lock); + +static void mISDN_dev_release(struct device *dev) +{ + /* nothing to do: the device is part of its parent's data structure */ +} + +static ssize_t id_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct mISDNdevice *mdev = dev_to_mISDN(dev); + + if (!mdev) + return -ENODEV; + return sprintf(buf, "%d\n", mdev->id); +} +static DEVICE_ATTR_RO(id); + +static ssize_t nrbchan_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct mISDNdevice *mdev = dev_to_mISDN(dev); + + if (!mdev) + return -ENODEV; + return sprintf(buf, "%d\n", mdev->nrbchan); +} +static DEVICE_ATTR_RO(nrbchan); + +static ssize_t d_protocols_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct mISDNdevice *mdev = dev_to_mISDN(dev); + + if (!mdev) + return -ENODEV; + return sprintf(buf, "%d\n", mdev->Dprotocols); +} +static DEVICE_ATTR_RO(d_protocols); + +static ssize_t b_protocols_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct mISDNdevice *mdev = dev_to_mISDN(dev); + + if (!mdev) + return -ENODEV; + return sprintf(buf, "%d\n", mdev->Bprotocols | get_all_Bprotocols()); +} +static DEVICE_ATTR_RO(b_protocols); + +static ssize_t protocol_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct mISDNdevice *mdev = dev_to_mISDN(dev); + + if (!mdev) + return -ENODEV; + return sprintf(buf, "%d\n", mdev->D.protocol); +} +static DEVICE_ATTR_RO(protocol); + +static ssize_t name_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + strcpy(buf, dev_name(dev)); + return strlen(buf); +} +static DEVICE_ATTR_RO(name); + +#if 0 /* hangs */ +static ssize_t name_set(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + int err = 0; + char *out = kmalloc(count + 1, GFP_KERNEL); + + if (!out) + return -ENOMEM; + + memcpy(out, buf, count); + if (count && out[count - 1] == '\n') + out[--count] = 0; + if (count) + err = device_rename(dev, out); + kfree(out); + + return (err < 0) ? err : count; +} +static DEVICE_ATTR_RW(name); +#endif + +static ssize_t channelmap_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct mISDNdevice *mdev = dev_to_mISDN(dev); + char *bp = buf; + int i; + + for (i = 0; i <= mdev->nrbchan; i++) + *bp++ = test_channelmap(i, mdev->channelmap) ? '1' : '0'; + + return bp - buf; +} +static DEVICE_ATTR_RO(channelmap); + +static struct attribute *mISDN_attrs[] = { + &dev_attr_id.attr, + &dev_attr_d_protocols.attr, + &dev_attr_b_protocols.attr, + &dev_attr_protocol.attr, + &dev_attr_channelmap.attr, + &dev_attr_nrbchan.attr, + &dev_attr_name.attr, + NULL, +}; +ATTRIBUTE_GROUPS(mISDN); + +static int mISDN_uevent(struct device *dev, struct kobj_uevent_env *env) +{ + struct mISDNdevice *mdev = dev_to_mISDN(dev); + + if (!mdev) + return 0; + + if (add_uevent_var(env, "nchans=%d", mdev->nrbchan)) + return -ENOMEM; + + return 0; +} + +static void mISDN_class_release(struct class *cls) +{ + /* do nothing, it's static */ +} + +static struct class mISDN_class = { + .name = "mISDN", + .owner = THIS_MODULE, + .dev_uevent = mISDN_uevent, + .dev_groups = mISDN_groups, + .dev_release = mISDN_dev_release, + .class_release = mISDN_class_release, +}; + +static int +_get_mdevice(struct device *dev, const void *id) +{ + struct mISDNdevice *mdev = dev_to_mISDN(dev); + + if (!mdev) + return 0; + if (mdev->id != *(const u_int *)id) + return 0; + return 1; +} struct mISDNdevice *get_mdevice(u_int id) { - struct mISDNdevice *dev; + return dev_to_mISDN(class_find_device(&mISDN_class, NULL, &id, + _get_mdevice)); +} - read_lock(&device_lock); - list_for_each_entry(dev, &devices, D.list) - if (dev->id == id) { - read_unlock(&device_lock); - return dev; - } - read_unlock(&device_lock); - return NULL; +static int +_get_mdevice_count(struct device *dev, void *cnt) +{ + *(int *)cnt += 1; + return 0; } int get_mdevice_count(void) { - struct mISDNdevice *dev; - int cnt = 0; + int cnt = 0; - read_lock(&device_lock); - list_for_each_entry(dev, &devices, D.list) - cnt++; - read_unlock(&device_lock); + class_for_each_device(&mISDN_class, NULL, &cnt, _get_mdevice_count); return cnt; } @@ -68,48 +217,66 @@ get_free_devid(void) for (i = 0; i <= MAX_DEVICE_ID; i++) if (!test_and_set_bit(i, (u_long *)&device_ids)) - return i; - return -1; + break; + if (i > MAX_DEVICE_ID) + return -EBUSY; + return i; } int -mISDN_register_device(struct mISDNdevice *dev, char *name) +mISDN_register_device(struct mISDNdevice *dev, + struct device *parent, char *name) { - u_long flags; int err; - dev->id = get_free_devid(); - if (dev->id < 0) - return -EBUSY; + err = get_free_devid(); + if (err < 0) + goto error1; + dev->id = err; + + device_initialize(&dev->dev); if (name && name[0]) - strcpy(dev->name, name); + dev_set_name(&dev->dev, "%s", name); else - sprintf(dev->name, "mISDN%d", dev->id); + dev_set_name(&dev->dev, "mISDN%d", dev->id); if (debug & DEBUG_CORE) printk(KERN_DEBUG "mISDN_register %s %d\n", - dev->name, dev->id); + dev_name(&dev->dev), dev->id); err = create_stack(dev); if (err) - return err; - write_lock_irqsave(&device_lock, flags); - list_add_tail(&dev->D.list, &devices); - write_unlock_irqrestore(&device_lock, flags); + goto error1; + + dev->dev.class = &mISDN_class; + dev->dev.platform_data = dev; + dev->dev.parent = parent; + dev_set_drvdata(&dev->dev, dev); + + err = device_add(&dev->dev); + if (err) + goto error3; return 0; + +error3: + delete_stack(dev); + return err; +error1: + return err; + } EXPORT_SYMBOL(mISDN_register_device); void mISDN_unregister_device(struct mISDNdevice *dev) { - u_long flags; - if (debug & DEBUG_CORE) printk(KERN_DEBUG "mISDN_unregister %s %d\n", - dev->name, dev->id); - write_lock_irqsave(&device_lock, flags); - list_del(&dev->D.list); - write_unlock_irqrestore(&device_lock, flags); + dev_name(&dev->dev), dev->id); + /* sysfs_remove_link(&dev->dev.kobj, "device"); */ + device_del(&dev->dev); + dev_set_drvdata(&dev->dev, NULL); + test_and_clear_bit(dev->id, (u_long *)&device_ids); delete_stack(dev); + put_device(&dev->dev); } EXPORT_SYMBOL(mISDN_unregister_device); @@ -148,7 +315,7 @@ get_Bprotocol4id(u_int id) if (id < ISDN_P_B_START || id > 63) { printk(KERN_WARNING "%s id not in range %d\n", - __func__, id); + __func__, id); return NULL; } m = 1 << (id & ISDN_P_B_MASK); @@ -163,12 +330,12 @@ mISDN_register_Bprotocol(struct Bprotocol *bp) if (debug & DEBUG_CORE) printk(KERN_DEBUG "%s: %s/%x\n", __func__, - bp->name, bp->Bprotocols); + bp->name, bp->Bprotocols); old = get_Bprotocol4mask(bp->Bprotocols); if (old) { printk(KERN_WARNING - "register duplicate protocol old %s/%x new %s/%x\n", - old->name, old->Bprotocols, bp->name, bp->Bprotocols); + "register duplicate protocol old %s/%x new %s/%x\n", + old->name, old->Bprotocols, bp->name, bp->Bprotocols); return -EBUSY; } write_lock_irqsave(&bp_lock, flags); @@ -185,60 +352,77 @@ mISDN_unregister_Bprotocol(struct Bprotocol *bp) if (debug & DEBUG_CORE) printk(KERN_DEBUG "%s: %s/%x\n", __func__, bp->name, - bp->Bprotocols); + bp->Bprotocols); write_lock_irqsave(&bp_lock, flags); list_del(&bp->list); write_unlock_irqrestore(&bp_lock, flags); } EXPORT_SYMBOL(mISDN_unregister_Bprotocol); -int +static const char *msg_no_channel = "<no channel>"; +static const char *msg_no_stack = "<no stack>"; +static const char *msg_no_stackdev = "<no stack device>"; + +const char *mISDNDevName4ch(struct mISDNchannel *ch) +{ + if (!ch) + return msg_no_channel; + if (!ch->st) + return msg_no_stack; + if (!ch->st->dev) + return msg_no_stackdev; + return dev_name(&ch->st->dev->dev); +}; +EXPORT_SYMBOL(mISDNDevName4ch); + +static int mISDNInit(void) { int err; printk(KERN_INFO "Modular ISDN core version %d.%d.%d\n", - MISDN_MAJOR_VERSION, MISDN_MINOR_VERSION, MISDN_RELEASE); + MISDN_MAJOR_VERSION, MISDN_MINOR_VERSION, MISDN_RELEASE); + mISDN_init_clock(&debug); mISDN_initstack(&debug); + err = class_register(&mISDN_class); + if (err) + goto error1; err = mISDN_inittimer(&debug); if (err) - goto error; + goto error2; err = l1_init(&debug); - if (err) { - mISDN_timer_cleanup(); - goto error; - } + if (err) + goto error3; err = Isdnl2_Init(&debug); - if (err) { - mISDN_timer_cleanup(); - l1_cleanup(); - goto error; - } + if (err) + goto error4; err = misdn_sock_init(&debug); - if (err) { - mISDN_timer_cleanup(); - l1_cleanup(); - Isdnl2_cleanup(); - } -error: + if (err) + goto error5; + return 0; + +error5: + Isdnl2_cleanup(); +error4: + l1_cleanup(); +error3: + mISDN_timer_cleanup(); +error2: + class_unregister(&mISDN_class); +error1: return err; } -void mISDN_cleanup(void) +static void mISDN_cleanup(void) { misdn_sock_cleanup(); - mISDN_timer_cleanup(); - l1_cleanup(); Isdnl2_cleanup(); + l1_cleanup(); + mISDN_timer_cleanup(); + class_unregister(&mISDN_class); - if (!list_empty(&devices)) - printk(KERN_ERR "%s devices still registered\n", __func__); - - if (!list_empty(&Bprotocols)) - printk(KERN_ERR "%s Bprotocols still registered\n", __func__); printk(KERN_DEBUG "mISDNcore unloaded\n"); } module_init(mISDNInit); module_exit(mISDN_cleanup); - diff --git a/drivers/isdn/mISDN/core.h b/drivers/isdn/mISDN/core.h index 7da7233b4c1..52695bb81ee 100644 --- a/drivers/isdn/mISDN/core.h +++ b/drivers/isdn/mISDN/core.h @@ -45,11 +45,11 @@ extern int get_mdevice_count(void); #define MGR_OPT_NETWORK 25 extern int connect_Bstack(struct mISDNdevice *, struct mISDNchannel *, - u_int, struct sockaddr_mISDN *); + u_int, struct sockaddr_mISDN *); extern int connect_layer1(struct mISDNdevice *, struct mISDNchannel *, - u_int, struct sockaddr_mISDN *); + u_int, struct sockaddr_mISDN *); extern int create_l2entity(struct mISDNdevice *, struct mISDNchannel *, - u_int, struct sockaddr_mISDN *); + u_int, struct sockaddr_mISDN *); extern int create_stack(struct mISDNdevice *); extern int create_teimanager(struct mISDNdevice *); @@ -71,7 +71,9 @@ extern void mISDN_timer_cleanup(void); extern int l1_init(u_int *); extern void l1_cleanup(void); -extern int Isdnl2_Init(u_int *); +extern int Isdnl2_Init(u_int *); extern void Isdnl2_cleanup(void); +extern void mISDN_init_clock(u_int *); + #endif diff --git a/drivers/isdn/mISDN/dsp.h b/drivers/isdn/mISDN/dsp.h index 6c3fed6b8d4..fc1733a0884 100644 --- a/drivers/isdn/mISDN/dsp.h +++ b/drivers/isdn/mISDN/dsp.h @@ -15,16 +15,17 @@ #define DEBUG_DSP_TONE 0x0020 #define DEBUG_DSP_BLOWFISH 0x0040 #define DEBUG_DSP_DELAY 0x0100 +#define DEBUG_DSP_CLOCK 0x0200 #define DEBUG_DSP_DTMFCOEFF 0x8000 /* heavy output */ /* options may be: * * bit 0 = use ulaw instead of alaw - * bit 1 = enable hfc hardware accelleration for all channels + * bit 1 = enable hfc hardware acceleration for all channels * */ -#define DSP_OPT_ULAW (1<<0) -#define DSP_OPT_NOHARDWARE (1<<1) +#define DSP_OPT_ULAW (1 << 0) +#define DSP_OPT_NOHARDWARE (1 << 1) #include <linux/timer.h> #include <linux/workqueue.h> @@ -75,7 +76,9 @@ extern u8 dsp_silence; #define MAX_SECONDS_JITTER_CHECK 5 extern struct timer_list dsp_spl_tl; -extern u32 dsp_spl_jiffies; + +/* the datatype need to match jiffies datatype */ +extern unsigned long dsp_spl_jiffies; /* the structure of conferences: * @@ -96,12 +99,12 @@ struct dsp_conf_member { struct dsp_conf { struct list_head list; u32 id; - /* all cmx stacks with the same ID are - connected */ + /* all cmx stacks with the same ID are + connected */ struct list_head mlist; int software; /* conf is processed by software */ int hardware; /* conf is processed by hardware */ - /* note: if both unset, has only one member */ + /* note: if both unset, has only one member */ }; @@ -111,18 +114,20 @@ struct dsp_conf { #define DSP_DTMF_NPOINTS 102 -#define ECHOCAN_BUFLEN (4*128) +#define ECHOCAN_BUFF_SIZE 0x400 /* must be 2**n */ +#define ECHOCAN_BUFF_MASK 0x3ff /* -1 */ struct dsp_dtmf { + int enable; /* dtmf is enabled */ int treshold; /* above this is dtmf (square of) */ int software; /* dtmf uses software decoding */ int hardware; /* dtmf uses hardware decoding */ int size; /* number of bytes in buffer */ signed short buffer[DSP_DTMF_NPOINTS]; - /* buffers one full dtmf frame */ + /* buffers one full dtmf frame */ u8 lastwhat, lastdigit; int count; - u8 digits[16]; /* just the dtmf result */ + u8 digits[16]; /* dtmf result */ }; @@ -149,6 +154,15 @@ struct dsp_tone { struct timer_list tl; }; +/*************** + * echo stuff * + ***************/ + +struct dsp_echo { + int software; /* echo is generated by software */ + int hardware; /* echo is generated by hardware */ +}; + /***************** * general stuff * *****************/ @@ -159,7 +173,7 @@ struct dsp { struct mISDNchannel *up; unsigned char name[64]; int b_active; - int echo; /* echo is enabled */ + struct dsp_echo echo; int rx_disabled; /* what the user wants */ int rx_is_off; /* what the card is */ int tx_mix; @@ -177,7 +191,7 @@ struct dsp { u32 conf_id; struct dsp_conf *conf; struct dsp_conf_member - *member; + *member; /* buffer stuff */ int rx_W; /* current write pos for data without timestamp */ @@ -191,13 +205,14 @@ struct dsp { u8 rx_buff[CMX_BUFF_SIZE]; int last_tx; /* if set, we transmitted last poll interval */ int cmx_delay; /* initial delay of buffers, - or 0 for dynamic jitter buffer */ + or 0 for dynamic jitter buffer */ int tx_dejitter; /* if set, dejitter tx buffer */ int tx_data; /* enables tx-data of CMX to upper layer */ /* hardware stuff */ struct dsp_features features; int features_rx_off; /* set if rx_off is featured */ + int features_fill_empty; /* set if fill_empty is featured */ int pcm_slot_rx; /* current PCM slot (or -1) */ int pcm_bank_rx; int pcm_slot_tx; @@ -218,7 +233,7 @@ struct dsp { int bf_sync; struct dsp_pipeline - pipeline; + pipeline; }; /* functions */ @@ -240,7 +255,7 @@ extern int dsp_cmx_del_conf(struct dsp_conf *conf); extern void dsp_dtmf_goertzel_init(struct dsp *dsp); extern void dsp_dtmf_hardware(struct dsp *dsp); extern u8 *dsp_dtmf_goertzel_decode(struct dsp *dsp, u8 *data, int len, - int fmt); + int fmt); extern int dsp_tone(struct dsp *dsp, int tone); extern void dsp_tone_copy(struct dsp *dsp, u8 *data, int len); @@ -257,7 +272,6 @@ extern int dsp_pipeline_init(struct dsp_pipeline *pipeline); extern void dsp_pipeline_destroy(struct dsp_pipeline *pipeline); extern int dsp_pipeline_build(struct dsp_pipeline *pipeline, const char *cfg); extern void dsp_pipeline_process_tx(struct dsp_pipeline *pipeline, u8 *data, - int len); + int len); extern void dsp_pipeline_process_rx(struct dsp_pipeline *pipeline, u8 *data, - int len); - + int len, unsigned int txlen); diff --git a/drivers/isdn/mISDN/dsp_audio.c b/drivers/isdn/mISDN/dsp_audio.c index 1c2dd569477..06022952a43 100644 --- a/drivers/isdn/mISDN/dsp_audio.c +++ b/drivers/isdn/mISDN/dsp_audio.c @@ -12,6 +12,7 @@ #include <linux/delay.h> #include <linux/mISDNif.h> #include <linux/mISDNdsp.h> +#include <linux/export.h> #include "core.h" #include "dsp.h" @@ -30,7 +31,7 @@ EXPORT_SYMBOL(dsp_audio_s16_to_law); /* alaw -> ulaw */ u8 dsp_audio_alaw_to_ulaw[256]; /* ulaw -> alaw */ -u8 dsp_audio_ulaw_to_alaw[256]; +static u8 dsp_audio_ulaw_to_alaw[256]; u8 dsp_silence; @@ -60,7 +61,7 @@ static inline unsigned char linear2alaw(short int linear) } /* Convert the scaled magnitude to segment number. */ - for (seg = 0; seg < 8; seg++) { + for (seg = 0; seg < 8; seg++) { if (pcm_val <= seg_end[seg]) break; } @@ -210,9 +211,8 @@ dsp_audio_generate_seven(void) j = 0; for (k = 0; k < 256; k++) { if (dsp_audio_alaw_to_s32[k] - < dsp_audio_alaw_to_s32[i]) { - j++; - } + < dsp_audio_alaw_to_s32[i]) + j++; } sorted_alaw[j] = i; } @@ -263,7 +263,7 @@ dsp_audio_generate_mix_table(void) sample = 32767; if (sample < -32768) sample = -32768; - dsp_audio_mix_law[(i<<8)|j] = + dsp_audio_mix_law[(i << 8) | j] = dsp_audio_s16_to_law[sample & 0xffff]; j++; } @@ -431,4 +431,3 @@ dsp_change_volume(struct sk_buff *skb, int volume) i++; } } - diff --git a/drivers/isdn/mISDN/dsp_biquad.h b/drivers/isdn/mISDN/dsp_biquad.h index 038191bc45f..c0c933a5d19 100644 --- a/drivers/isdn/mISDN/dsp_biquad.h +++ b/drivers/isdn/mISDN/dsp_biquad.h @@ -38,7 +38,7 @@ struct biquad2_state { }; static inline void biquad2_init(struct biquad2_state *bq, - int32_t gain, int32_t a1, int32_t a2, int32_t b1, int32_t b2) + int32_t gain, int32_t a1, int32_t a2, int32_t b1, int32_t b2) { bq->gain = gain; bq->a1 = a1; @@ -55,8 +55,8 @@ static inline int16_t biquad2(struct biquad2_state *bq, int16_t sample) int32_t y; int32_t z0; - z0 = sample*bq->gain + bq->z1*bq->a1 + bq->z2*bq->a2; - y = z0 + bq->z1*bq->b1 + bq->z2*bq->b2; + z0 = sample * bq->gain + bq->z1 * bq->a1 + bq->z2 * bq->a2; + y = z0 + bq->z1 * bq->b1 + bq->z2 * bq->b2; bq->z2 = bq->z1; bq->z1 = z0 >> 15; diff --git a/drivers/isdn/mISDN/dsp_blowfish.c b/drivers/isdn/mISDN/dsp_blowfish.c index 18e411e95bb..0aa572f3858 100644 --- a/drivers/isdn/mISDN/dsp_blowfish.c +++ b/drivers/isdn/mISDN/dsp_blowfish.c @@ -354,8 +354,8 @@ static const u32 bf_sbox[256 * 4] = { #define GET32_1(x) (((x) >> (16)) & (0xff)) #define GET32_0(x) (((x) >> (24)) & (0xff)) -#define bf_F(x) (((S[GET32_0(x)] + S[256 + GET32_1(x)]) ^ \ - S[512 + GET32_2(x)]) + S[768 + GET32_3(x)]) +#define bf_F(x) (((S[GET32_0(x)] + S[256 + GET32_1(x)]) ^ \ + S[512 + GET32_2(x)]) + S[768 + GET32_3(x)]) #define EROUND(a, b, n) do { b ^= P[n]; a ^= bf_F(b); } while (0) #define DROUND(a, b, n) do { a ^= bf_F(b); b ^= P[n]; } while (0) @@ -388,17 +388,17 @@ dsp_bf_encrypt(struct dsp *dsp, u8 *data, int len) j = 0; /* transcode 9 samples xlaw to 8 bytes */ yl = dsp_audio_law2seven[bf_data_in[0]]; - yl = (yl<<7) | dsp_audio_law2seven[bf_data_in[1]]; - yl = (yl<<7) | dsp_audio_law2seven[bf_data_in[2]]; - yl = (yl<<7) | dsp_audio_law2seven[bf_data_in[3]]; + yl = (yl << 7) | dsp_audio_law2seven[bf_data_in[1]]; + yl = (yl << 7) | dsp_audio_law2seven[bf_data_in[2]]; + yl = (yl << 7) | dsp_audio_law2seven[bf_data_in[3]]; nibble = dsp_audio_law2seven[bf_data_in[4]]; yr = nibble; - yl = (yl<<4) | (nibble>>3); - yr = (yr<<7) | dsp_audio_law2seven[bf_data_in[5]]; - yr = (yr<<7) | dsp_audio_law2seven[bf_data_in[6]]; - yr = (yr<<7) | dsp_audio_law2seven[bf_data_in[7]]; - yr = (yr<<7) | dsp_audio_law2seven[bf_data_in[8]]; - yr = (yr<<1) | (bf_data_in[0] & 1); + yl = (yl << 4) | (nibble >> 3); + yr = (yr << 7) | dsp_audio_law2seven[bf_data_in[5]]; + yr = (yr << 7) | dsp_audio_law2seven[bf_data_in[6]]; + yr = (yr << 7) | dsp_audio_law2seven[bf_data_in[7]]; + yr = (yr << 7) | dsp_audio_law2seven[bf_data_in[8]]; + yr = (yr << 1) | (bf_data_in[0] & 1); /* fill unused bit with random noise of audio input */ /* encrypt */ @@ -423,24 +423,24 @@ dsp_bf_encrypt(struct dsp *dsp, u8 *data, int len) yr ^= P[17]; /* calculate 3-bit checksumme */ - cs = yl ^ (yl>>3) ^ (yl>>6) ^ (yl>>9) ^ (yl>>12) ^ (yl>>15) - ^ (yl>>18) ^ (yl>>21) ^ (yl>>24) ^ (yl>>27) ^ (yl>>30) - ^ (yr<<2) ^ (yr>>1) ^ (yr>>4) ^ (yr>>7) ^ (yr>>10) - ^ (yr>>13) ^ (yr>>16) ^ (yr>>19) ^ (yr>>22) ^ (yr>>25) - ^ (yr>>28) ^ (yr>>31); + cs = yl ^ (yl >> 3) ^ (yl >> 6) ^ (yl >> 9) ^ (yl >> 12) ^ (yl >> 15) + ^ (yl >> 18) ^ (yl >> 21) ^ (yl >> 24) ^ (yl >> 27) ^ (yl >> 30) + ^ (yr << 2) ^ (yr >> 1) ^ (yr >> 4) ^ (yr >> 7) ^ (yr >> 10) + ^ (yr >> 13) ^ (yr >> 16) ^ (yr >> 19) ^ (yr >> 22) ^ (yr >> 25) + ^ (yr >> 28) ^ (yr >> 31); /* * transcode 8 crypted bytes to 9 data bytes with sync * and checksum information */ - bf_crypt_out[0] = (yl>>25) | 0x80; - bf_crypt_out[1] = (yl>>18) & 0x7f; - bf_crypt_out[2] = (yl>>11) & 0x7f; - bf_crypt_out[3] = (yl>>4) & 0x7f; - bf_crypt_out[4] = ((yl<<3) & 0x78) | ((yr>>29) & 0x07); - bf_crypt_out[5] = ((yr>>22) & 0x7f) | ((cs<<5) & 0x80); - bf_crypt_out[6] = ((yr>>15) & 0x7f) | ((cs<<6) & 0x80); - bf_crypt_out[7] = ((yr>>8) & 0x7f) | (cs<<7); + bf_crypt_out[0] = (yl >> 25) | 0x80; + bf_crypt_out[1] = (yl >> 18) & 0x7f; + bf_crypt_out[2] = (yl >> 11) & 0x7f; + bf_crypt_out[3] = (yl >> 4) & 0x7f; + bf_crypt_out[4] = ((yl << 3) & 0x78) | ((yr >> 29) & 0x07); + bf_crypt_out[5] = ((yr >> 22) & 0x7f) | ((cs << 5) & 0x80); + bf_crypt_out[6] = ((yr >> 15) & 0x7f) | ((cs << 6) & 0x80); + bf_crypt_out[7] = ((yr >> 8) & 0x7f) | (cs << 7); bf_crypt_out[8] = yr; } @@ -474,45 +474,45 @@ dsp_bf_decrypt(struct dsp *dsp, u8 *data, int len) * shift upper bit and rotate data to buffer ring * send current decrypted data */ - sync = (sync<<1) | ((*data)>>7); + sync = (sync << 1) | ((*data) >> 7); bf_crypt_inring[j++ & 15] = *data; *data++ = bf_data_out[k++]; i++; if (k == 9) k = 0; /* repeat if no sync has been found */ /* check if not in sync */ - if ((sync&0x1f0) != 0x100) + if ((sync & 0x1f0) != 0x100) continue; j -= 9; /* transcode receive data to 64 bit block of encrypted data */ yl = bf_crypt_inring[j++ & 15]; - yl = (yl<<7) | bf_crypt_inring[j++ & 15]; /* bit7 = 0 */ - yl = (yl<<7) | bf_crypt_inring[j++ & 15]; /* bit7 = 0 */ - yl = (yl<<7) | bf_crypt_inring[j++ & 15]; /* bit7 = 0 */ + yl = (yl << 7) | bf_crypt_inring[j++ & 15]; /* bit7 = 0 */ + yl = (yl << 7) | bf_crypt_inring[j++ & 15]; /* bit7 = 0 */ + yl = (yl << 7) | bf_crypt_inring[j++ & 15]; /* bit7 = 0 */ nibble = bf_crypt_inring[j++ & 15]; /* bit7 = 0 */ yr = nibble; - yl = (yl<<4) | (nibble>>3); + yl = (yl << 4) | (nibble >> 3); cs2 = bf_crypt_inring[j++ & 15]; - yr = (yr<<7) | (cs2 & 0x7f); + yr = (yr << 7) | (cs2 & 0x7f); cs1 = bf_crypt_inring[j++ & 15]; - yr = (yr<<7) | (cs1 & 0x7f); + yr = (yr << 7) | (cs1 & 0x7f); cs0 = bf_crypt_inring[j++ & 15]; - yr = (yr<<7) | (cs0 & 0x7f); - yr = (yr<<8) | bf_crypt_inring[j++ & 15]; + yr = (yr << 7) | (cs0 & 0x7f); + yr = (yr << 8) | bf_crypt_inring[j++ & 15]; /* calculate 3-bit checksumme */ - cs = yl ^ (yl>>3) ^ (yl>>6) ^ (yl>>9) ^ (yl>>12) ^ (yl>>15) - ^ (yl>>18) ^ (yl>>21) ^ (yl>>24) ^ (yl>>27) ^ (yl>>30) - ^ (yr<<2) ^ (yr>>1) ^ (yr>>4) ^ (yr>>7) ^ (yr>>10) - ^ (yr>>13) ^ (yr>>16) ^ (yr>>19) ^ (yr>>22) ^ (yr>>25) - ^ (yr>>28) ^ (yr>>31); + cs = yl ^ (yl >> 3) ^ (yl >> 6) ^ (yl >> 9) ^ (yl >> 12) ^ (yl >> 15) + ^ (yl >> 18) ^ (yl >> 21) ^ (yl >> 24) ^ (yl >> 27) ^ (yl >> 30) + ^ (yr << 2) ^ (yr >> 1) ^ (yr >> 4) ^ (yr >> 7) ^ (yr >> 10) + ^ (yr >> 13) ^ (yr >> 16) ^ (yr >> 19) ^ (yr >> 22) ^ (yr >> 25) + ^ (yr >> 28) ^ (yr >> 31); /* check if frame is valid */ - if ((cs&0x7) != (((cs2>>5)&4) | ((cs1>>6)&2) | (cs0 >> 7))) { + if ((cs & 0x7) != (((cs2 >> 5) & 4) | ((cs1 >> 6) & 2) | (cs0 >> 7))) { if (dsp_debug & DEBUG_DSP_BLOWFISH) printk(KERN_DEBUG - "DSP BLOWFISH: received corrupt frame, " - "checksumme is not correct\n"); + "DSP BLOWFISH: received corrupt frame, " + "checksumme is not correct\n"); continue; } @@ -537,17 +537,17 @@ dsp_bf_decrypt(struct dsp *dsp, u8 *data, int len) DROUND(yr, yl, 0); /* transcode 8 crypted bytes to 9 sample bytes */ - bf_data_out[0] = dsp_audio_seven2law[(yl>>25) & 0x7f]; - bf_data_out[1] = dsp_audio_seven2law[(yl>>18) & 0x7f]; - bf_data_out[2] = dsp_audio_seven2law[(yl>>11) & 0x7f]; - bf_data_out[3] = dsp_audio_seven2law[(yl>>4) & 0x7f]; - bf_data_out[4] = dsp_audio_seven2law[((yl<<3) & 0x78) | - ((yr>>29) & 0x07)]; - - bf_data_out[5] = dsp_audio_seven2law[(yr>>22) & 0x7f]; - bf_data_out[6] = dsp_audio_seven2law[(yr>>15) & 0x7f]; - bf_data_out[7] = dsp_audio_seven2law[(yr>>8) & 0x7f]; - bf_data_out[8] = dsp_audio_seven2law[(yr>>1) & 0x7f]; + bf_data_out[0] = dsp_audio_seven2law[(yl >> 25) & 0x7f]; + bf_data_out[1] = dsp_audio_seven2law[(yl >> 18) & 0x7f]; + bf_data_out[2] = dsp_audio_seven2law[(yl >> 11) & 0x7f]; + bf_data_out[3] = dsp_audio_seven2law[(yl >> 4) & 0x7f]; + bf_data_out[4] = dsp_audio_seven2law[((yl << 3) & 0x78) | + ((yr >> 29) & 0x07)]; + + bf_data_out[5] = dsp_audio_seven2law[(yr >> 22) & 0x7f]; + bf_data_out[6] = dsp_audio_seven2law[(yr >> 15) & 0x7f]; + bf_data_out[7] = dsp_audio_seven2law[(yr >> 8) & 0x7f]; + bf_data_out[8] = dsp_audio_seven2law[(yr >> 1) & 0x7f]; k = 0; /* start with new decoded frame */ } @@ -631,9 +631,9 @@ dsp_bf_init(struct dsp *dsp, const u8 *key, uint keylen) /* Actual subkey generation */ for (j = 0, i = 0; i < 16 + 2; i++) { temp = (((u32)key[j] << 24) | - ((u32)key[(j + 1) % keylen] << 16) | - ((u32)key[(j + 2) % keylen] << 8) | - ((u32)key[(j + 3) % keylen])); + ((u32)key[(j + 1) % keylen] << 16) | + ((u32)key[(j + 2) % keylen] << 8) | + ((u32)key[(j + 3) % keylen])); P[i] = P[i] ^ temp; j = (j + 4) % keylen; diff --git a/drivers/isdn/mISDN/dsp_cmx.c b/drivers/isdn/mISDN/dsp_cmx.c index e92b1ba4b45..a4f05c54c32 100644 --- a/drivers/isdn/mISDN/dsp_cmx.c +++ b/drivers/isdn/mISDN/dsp_cmx.c @@ -112,7 +112,7 @@ * Disable rx-data: * If cmx is realized in hardware, rx data will be disabled if requested by * the upper layer. If dtmf decoding is done by software and enabled, rx data - * will not be diabled but blocked to the upper layer. + * will not be disabled but blocked to the upper layer. * * HFC conference engine: * If it is possible to realize all features using hardware, hardware will be @@ -124,6 +124,7 @@ /* delay.h is required for hw_lock.h */ +#include <linux/slab.h> #include <linux/delay.h> #include <linux/mISDNif.h> #include <linux/mISDNdsp.h> @@ -137,6 +138,7 @@ /* #define CMX_CONF_DEBUG */ /*#define CMX_DEBUG * massive read/write pointer output */ +/*#define CMX_DELAY_DEBUG * gives rx-buffer delay overview */ /*#define CMX_TX_DEBUG * massive read/write on tx-buffer with content */ static inline int @@ -162,8 +164,9 @@ dsp_cmx_debug(struct dsp *dsp) printk(KERN_DEBUG "-----Current DSP\n"); list_for_each_entry(odsp, &dsp_ilist, list) { - printk(KERN_DEBUG "* %s echo=%d txmix=%d", - odsp->name, odsp->echo, odsp->tx_mix); + printk(KERN_DEBUG "* %s hardecho=%d softecho=%d txmix=%d", + odsp->name, odsp->echo.hardware, odsp->echo.software, + odsp->tx_mix); if (odsp->conf) printk(" (Conf %d)", odsp->conf->id); if (dsp == odsp) @@ -175,12 +178,14 @@ dsp_cmx_debug(struct dsp *dsp) printk(KERN_DEBUG "* Conf %d (%p)\n", conf->id, conf); list_for_each_entry(member, &conf->mlist, list) { printk(KERN_DEBUG - " - member = %s (slot_tx %d, bank_tx %d, " - "slot_rx %d, bank_rx %d hfc_conf %d)%s\n", - member->dsp->name, member->dsp->pcm_slot_tx, - member->dsp->pcm_bank_tx, member->dsp->pcm_slot_rx, - member->dsp->pcm_bank_rx, member->dsp->hfc_conf, - (member->dsp == dsp) ? " *this*" : ""); + " - member = %s (slot_tx %d, bank_tx %d, " + "slot_rx %d, bank_rx %d hfc_conf %d " + "tx_data %d rx_is_off %d)%s\n", + member->dsp->name, member->dsp->pcm_slot_tx, + member->dsp->pcm_bank_tx, member->dsp->pcm_slot_rx, + member->dsp->pcm_bank_rx, member->dsp->hfc_conf, + member->dsp->tx_data, member->dsp->rx_is_off, + (member->dsp == dsp) ? " *this*" : ""); } } printk(KERN_DEBUG "-----end\n"); @@ -222,19 +227,19 @@ dsp_cmx_add_conf_member(struct dsp *dsp, struct dsp_conf *conf) } if (dsp->member) { printk(KERN_WARNING "%s: dsp is already member in a conf.\n", - __func__); + __func__); return -EINVAL; } if (dsp->conf) { printk(KERN_WARNING "%s: dsp is already in a conf.\n", - __func__); + __func__); return -EINVAL; } member = kzalloc(sizeof(struct dsp_conf_member), GFP_ATOMIC); if (!member) { - printk(KERN_ERR "kmalloc struct dsp_conf_member failed\n"); + printk(KERN_ERR "kzalloc struct dsp_conf_member failed\n"); return -ENOMEM; } member->dsp = dsp; @@ -263,19 +268,19 @@ dsp_cmx_del_conf_member(struct dsp *dsp) if (!dsp) { printk(KERN_WARNING "%s: dsp is 0.\n", - __func__); + __func__); return -EINVAL; } if (!dsp->conf) { printk(KERN_WARNING "%s: dsp is not in a conf.\n", - __func__); + __func__); return -EINVAL; } if (list_empty(&dsp->conf->mlist)) { printk(KERN_WARNING "%s: dsp has linked an empty conf.\n", - __func__); + __func__); return -EINVAL; } @@ -290,8 +295,8 @@ dsp_cmx_del_conf_member(struct dsp *dsp) } } printk(KERN_WARNING - "%s: dsp is not present in its own conf_meber list.\n", - __func__); + "%s: dsp is not present in its own conf_meber list.\n", + __func__); return -EINVAL; } @@ -307,13 +312,13 @@ static struct dsp_conf if (!id) { printk(KERN_WARNING "%s: id is 0.\n", - __func__); + __func__); return NULL; } conf = kzalloc(sizeof(struct dsp_conf), GFP_ATOMIC); if (!conf) { - printk(KERN_ERR "kmalloc struct dsp_conf failed\n"); + printk(KERN_ERR "kzalloc struct dsp_conf failed\n"); return NULL; } INIT_LIST_HEAD(&conf->mlist); @@ -333,13 +338,13 @@ dsp_cmx_del_conf(struct dsp_conf *conf) { if (!conf) { printk(KERN_WARNING "%s: conf is null.\n", - __func__); + __func__); return -EINVAL; } if (!list_empty(&conf->mlist)) { printk(KERN_WARNING "%s: conf not empty.\n", - __func__); + __func__); return -EINVAL; } list_del(&conf->list); @@ -354,7 +359,7 @@ dsp_cmx_del_conf(struct dsp_conf *conf) */ static void dsp_cmx_hw_message(struct dsp *dsp, u32 message, u32 param1, u32 param2, - u32 param3, u32 param4) + u32 param3, u32 param4) { struct mISDN_ctrl_req cq; @@ -384,7 +389,7 @@ dsp_cmx_hardware(struct dsp_conf *conf, struct dsp *dsp) int freeunits[8]; u_char freeslots[256]; int same_hfc = -1, same_pcm = -1, current_conf = -1, - all_conf = 1; + all_conf = 1, tx_data = 0; /* dsp gets updated (no conf) */ if (!conf) { @@ -392,33 +397,33 @@ dsp_cmx_hardware(struct dsp_conf *conf, struct dsp *dsp) return; if (dsp_debug & DEBUG_DSP_CMX) printk(KERN_DEBUG "%s checking dsp %s\n", - __func__, dsp->name); -one_member: + __func__, dsp->name); + one_member: /* remove HFC conference if enabled */ if (dsp->hfc_conf >= 0) { if (dsp_debug & DEBUG_DSP_CMX) printk(KERN_DEBUG - "%s removing %s from HFC conf %d " - "because dsp is split\n", __func__, - dsp->name, dsp->hfc_conf); + "%s removing %s from HFC conf %d " + "because dsp is split\n", __func__, + dsp->name, dsp->hfc_conf); dsp_cmx_hw_message(dsp, MISDN_CTRL_HFC_CONF_SPLIT, - 0, 0, 0, 0); + 0, 0, 0, 0); dsp->hfc_conf = -1; } /* process hw echo */ if (dsp->features.pcm_banks < 1) return; - if (!dsp->echo) { + if (!dsp->echo.software && !dsp->echo.hardware) { /* NO ECHO: remove PCM slot if assigned */ if (dsp->pcm_slot_tx >= 0 || dsp->pcm_slot_rx >= 0) { if (dsp_debug & DEBUG_DSP_CMX) printk(KERN_DEBUG "%s removing %s from" - " PCM slot %d (TX) %d (RX) because" - " dsp is split (no echo)\n", - __func__, dsp->name, - dsp->pcm_slot_tx, dsp->pcm_slot_rx); + " PCM slot %d (TX) %d (RX) because" + " dsp is split (no echo)\n", + __func__, dsp->name, + dsp->pcm_slot_tx, dsp->pcm_slot_rx); dsp_cmx_hw_message(dsp, MISDN_CTRL_HFC_PCM_DISC, - 0, 0, 0, 0); + 0, 0, 0, 0); dsp->pcm_slot_tx = -1; dsp->pcm_bank_tx = -1; dsp->pcm_slot_rx = -1; @@ -426,10 +431,15 @@ one_member: } return; } + /* echo is enabled, find out if we use soft or hardware */ + dsp->echo.software = dsp->tx_data; + dsp->echo.hardware = 0; /* ECHO: already echo */ if (dsp->pcm_slot_tx >= 0 && dsp->pcm_slot_rx < 0 && - dsp->pcm_bank_tx == 2 && dsp->pcm_bank_rx == 2) + dsp->pcm_bank_tx == 2 && dsp->pcm_bank_rx == 2) { + dsp->echo.hardware = 1; return; + } /* ECHO: if slot already assigned */ if (dsp->pcm_slot_tx >= 0) { dsp->pcm_slot_rx = dsp->pcm_slot_tx; @@ -437,11 +447,12 @@ one_member: dsp->pcm_bank_rx = 2; if (dsp_debug & DEBUG_DSP_CMX) printk(KERN_DEBUG - "%s refresh %s for echo using slot %d\n", - __func__, dsp->name, - dsp->pcm_slot_tx); + "%s refresh %s for echo using slot %d\n", + __func__, dsp->name, + dsp->pcm_slot_tx); dsp_cmx_hw_message(dsp, MISDN_CTRL_HFC_PCM_CONN, - dsp->pcm_slot_tx, 2, dsp->pcm_slot_rx, 2); + dsp->pcm_slot_tx, 2, dsp->pcm_slot_rx, 2); + dsp->echo.hardware = 1; return; } /* ECHO: find slot */ @@ -452,10 +463,10 @@ one_member: if (finddsp->features.pcm_id == dsp->features.pcm_id) { if (finddsp->pcm_slot_rx >= 0 && finddsp->pcm_slot_rx < sizeof(freeslots)) - freeslots[finddsp->pcm_slot_tx] = 0; + freeslots[finddsp->pcm_slot_rx] = 0; if (finddsp->pcm_slot_tx >= 0 && finddsp->pcm_slot_tx < sizeof(freeslots)) - freeslots[finddsp->pcm_slot_rx] = 0; + freeslots[finddsp->pcm_slot_tx] = 0; } } i = 0; @@ -468,9 +479,10 @@ one_member: if (i == ii) { if (dsp_debug & DEBUG_DSP_CMX) printk(KERN_DEBUG - "%s no slot available for echo\n", - __func__); + "%s no slot available for echo\n", + __func__); /* no more slots available */ + dsp->echo.software = 1; return; } /* assign free slot */ @@ -480,21 +492,22 @@ one_member: dsp->pcm_bank_rx = 2; if (dsp_debug & DEBUG_DSP_CMX) printk(KERN_DEBUG - "%s assign echo for %s using slot %d\n", - __func__, dsp->name, dsp->pcm_slot_tx); + "%s assign echo for %s using slot %d\n", + __func__, dsp->name, dsp->pcm_slot_tx); dsp_cmx_hw_message(dsp, MISDN_CTRL_HFC_PCM_CONN, - dsp->pcm_slot_tx, 2, dsp->pcm_slot_rx, 2); + dsp->pcm_slot_tx, 2, dsp->pcm_slot_rx, 2); + dsp->echo.hardware = 1; return; } /* conf gets updated (all members) */ if (dsp_debug & DEBUG_DSP_CMX) printk(KERN_DEBUG "%s checking conference %d\n", - __func__, conf->id); + __func__, conf->id); if (list_empty(&conf->mlist)) { printk(KERN_ERR "%s: conference whithout members\n", - __func__); + __func__); return; } member = list_entry(conf->mlist.next, struct dsp_conf_member, list); @@ -506,25 +519,25 @@ one_member: if (member->dsp->tx_mix) { if (dsp_debug & DEBUG_DSP_CMX) printk(KERN_DEBUG - "%s dsp %s cannot form a conf, because " - "tx_mix is turned on\n", __func__, - member->dsp->name); -conf_software: + "%s dsp %s cannot form a conf, because " + "tx_mix is turned on\n", __func__, + member->dsp->name); + conf_software: list_for_each_entry(member, &conf->mlist, list) { dsp = member->dsp; /* remove HFC conference if enabled */ if (dsp->hfc_conf >= 0) { if (dsp_debug & DEBUG_DSP_CMX) printk(KERN_DEBUG - "%s removing %s from HFC " - "conf %d because not " - "possible with hardware\n", - __func__, - dsp->name, - dsp->hfc_conf); + "%s removing %s from HFC " + "conf %d because not " + "possible with hardware\n", + __func__, + dsp->name, + dsp->hfc_conf); dsp_cmx_hw_message(dsp, - MISDN_CTRL_HFC_CONF_SPLIT, - 0, 0, 0, 0); + MISDN_CTRL_HFC_CONF_SPLIT, + 0, 0, 0, 0); dsp->hfc_conf = -1; } /* remove PCM slot if assigned */ @@ -532,16 +545,16 @@ conf_software: dsp->pcm_slot_rx >= 0) { if (dsp_debug & DEBUG_DSP_CMX) printk(KERN_DEBUG "%s removing " - "%s from PCM slot %d (TX)" - " slot %d (RX) because not" - " possible with hardware\n", - __func__, - dsp->name, - dsp->pcm_slot_tx, - dsp->pcm_slot_rx); + "%s from PCM slot %d (TX)" + " slot %d (RX) because not" + " possible with hardware\n", + __func__, + dsp->name, + dsp->pcm_slot_tx, + dsp->pcm_slot_rx); dsp_cmx_hw_message(dsp, - MISDN_CTRL_HFC_PCM_DISC, - 0, 0, 0, 0); + MISDN_CTRL_HFC_PCM_DISC, + 0, 0, 0, 0); dsp->pcm_slot_tx = -1; dsp->pcm_bank_tx = -1; dsp->pcm_slot_rx = -1; @@ -553,83 +566,82 @@ conf_software: return; } /* check if member has echo turned on */ - if (member->dsp->echo) { + if (member->dsp->echo.hardware || member->dsp->echo.software) { if (dsp_debug & DEBUG_DSP_CMX) printk(KERN_DEBUG - "%s dsp %s cannot form a conf, because " - "echo is turned on\n", __func__, - member->dsp->name); + "%s dsp %s cannot form a conf, because " + "echo is turned on\n", __func__, + member->dsp->name); goto conf_software; } /* check if member has tx_mix turned on */ if (member->dsp->tx_mix) { if (dsp_debug & DEBUG_DSP_CMX) printk(KERN_DEBUG - "%s dsp %s cannot form a conf, because " - "tx_mix is turned on\n", - __func__, member->dsp->name); + "%s dsp %s cannot form a conf, because " + "tx_mix is turned on\n", + __func__, member->dsp->name); goto conf_software; } /* check if member changes volume at an not suppoted level */ if (member->dsp->tx_volume) { if (dsp_debug & DEBUG_DSP_CMX) printk(KERN_DEBUG - "%s dsp %s cannot form a conf, because " - "tx_volume is changed\n", - __func__, member->dsp->name); + "%s dsp %s cannot form a conf, because " + "tx_volume is changed\n", + __func__, member->dsp->name); goto conf_software; } if (member->dsp->rx_volume) { if (dsp_debug & DEBUG_DSP_CMX) printk(KERN_DEBUG - "%s dsp %s cannot form a conf, because " - "rx_volume is changed\n", - __func__, member->dsp->name); + "%s dsp %s cannot form a conf, because " + "rx_volume is changed\n", + __func__, member->dsp->name); goto conf_software; } /* check if tx-data turned on */ if (member->dsp->tx_data) { if (dsp_debug & DEBUG_DSP_CMX) printk(KERN_DEBUG - "%s dsp %s cannot form a conf, because " - "tx_data is turned on\n", - __func__, member->dsp->name); - goto conf_software; + "%s dsp %s tx_data is turned on\n", + __func__, member->dsp->name); + tx_data = 1; } /* check if pipeline exists */ if (member->dsp->pipeline.inuse) { if (dsp_debug & DEBUG_DSP_CMX) printk(KERN_DEBUG - "%s dsp %s cannot form a conf, because " - "pipeline exists\n", __func__, - member->dsp->name); + "%s dsp %s cannot form a conf, because " + "pipeline exists\n", __func__, + member->dsp->name); goto conf_software; } /* check if encryption is enabled */ if (member->dsp->bf_enable) { if (dsp_debug & DEBUG_DSP_CMX) printk(KERN_DEBUG "%s dsp %s cannot form a " - "conf, because encryption is enabled\n", - __func__, member->dsp->name); + "conf, because encryption is enabled\n", + __func__, member->dsp->name); goto conf_software; } /* check if member is on a card with PCM support */ if (member->dsp->features.pcm_id < 0) { if (dsp_debug & DEBUG_DSP_CMX) printk(KERN_DEBUG - "%s dsp %s cannot form a conf, because " - "dsp has no PCM bus\n", - __func__, member->dsp->name); + "%s dsp %s cannot form a conf, because " + "dsp has no PCM bus\n", + __func__, member->dsp->name); goto conf_software; } /* check if relations are on the same PCM bus */ if (member->dsp->features.pcm_id != same_pcm) { if (dsp_debug & DEBUG_DSP_CMX) printk(KERN_DEBUG - "%s dsp %s cannot form a conf, because " - "dsp is on a different PCM bus than the " - "first dsp\n", - __func__, member->dsp->name); + "%s dsp %s cannot form a conf, because " + "dsp is on a different PCM bus than the " + "first dsp\n", + __func__, member->dsp->name); goto conf_software; } /* determine if members are on the same hfc chip */ @@ -653,12 +665,12 @@ conf_software: if (memb == 1) { if (dsp_debug & DEBUG_DSP_CMX) printk(KERN_DEBUG - "%s conf %d cannot form a HW conference, " - "because dsp is alone\n", __func__, conf->id); + "%s conf %d cannot form a HW conference, " + "because dsp is alone\n", __func__, conf->id); conf->hardware = 0; conf->software = 0; member = list_entry(conf->mlist.next, struct dsp_conf_member, - list); + list); dsp = member->dsp; goto one_member; } @@ -672,30 +684,30 @@ conf_software: /* if we have only two members */ if (memb == 2) { member = list_entry(conf->mlist.next, struct dsp_conf_member, - list); + list); nextm = list_entry(member->list.next, struct dsp_conf_member, - list); + list); /* remove HFC conference if enabled */ if (member->dsp->hfc_conf >= 0) { if (dsp_debug & DEBUG_DSP_CMX) printk(KERN_DEBUG - "%s removing %s from HFC conf %d because " - "two parties require only a PCM slot\n", - __func__, member->dsp->name, - member->dsp->hfc_conf); + "%s removing %s from HFC conf %d because " + "two parties require only a PCM slot\n", + __func__, member->dsp->name, + member->dsp->hfc_conf); dsp_cmx_hw_message(member->dsp, - MISDN_CTRL_HFC_CONF_SPLIT, 0, 0, 0, 0); + MISDN_CTRL_HFC_CONF_SPLIT, 0, 0, 0, 0); member->dsp->hfc_conf = -1; } if (nextm->dsp->hfc_conf >= 0) { if (dsp_debug & DEBUG_DSP_CMX) printk(KERN_DEBUG - "%s removing %s from HFC conf %d because " - "two parties require only a PCM slot\n", - __func__, nextm->dsp->name, - nextm->dsp->hfc_conf); + "%s removing %s from HFC conf %d because " + "two parties require only a PCM slot\n", + __func__, nextm->dsp->name, + nextm->dsp->hfc_conf); dsp_cmx_hw_message(nextm->dsp, - MISDN_CTRL_HFC_CONF_SPLIT, 0, 0, 0, 0); + MISDN_CTRL_HFC_CONF_SPLIT, 0, 0, 0, 0); nextm->dsp->hfc_conf = -1; } /* if members have two banks (and not on the same chip) */ @@ -721,17 +733,17 @@ conf_software: /* all members have same slot */ if (dsp_debug & DEBUG_DSP_CMX) printk(KERN_DEBUG - "%s dsp %s & %s stay joined on " - "PCM slot %d bank %d (TX) bank %d " - "(RX) (on different chips)\n", - __func__, - member->dsp->name, - nextm->dsp->name, - member->dsp->pcm_slot_tx, - member->dsp->pcm_bank_tx, - member->dsp->pcm_bank_rx); - conf->hardware = 0; - conf->software = 1; + "%s dsp %s & %s stay joined on " + "PCM slot %d bank %d (TX) bank %d " + "(RX) (on different chips)\n", + __func__, + member->dsp->name, + nextm->dsp->name, + member->dsp->pcm_slot_tx, + member->dsp->pcm_bank_tx, + member->dsp->pcm_bank_rx); + conf->hardware = 1; + conf->software = tx_data; return; } /* find a new slot */ @@ -744,11 +756,11 @@ conf_software: if (dsp->pcm_slot_rx >= 0 && dsp->pcm_slot_rx < sizeof(freeslots)) - freeslots[dsp->pcm_slot_tx] = 0; + freeslots[dsp->pcm_slot_rx] = 0; if (dsp->pcm_slot_tx >= 0 && dsp->pcm_slot_tx < sizeof(freeslots)) - freeslots[dsp->pcm_slot_rx] = 0; + freeslots[dsp->pcm_slot_tx] = 0; } } i = 0; @@ -761,10 +773,10 @@ conf_software: if (i == ii) { if (dsp_debug & DEBUG_DSP_CMX) printk(KERN_DEBUG - "%s no slot available for " - "%s & %s\n", __func__, - member->dsp->name, - nextm->dsp->name); + "%s no slot available for " + "%s & %s\n", __func__, + member->dsp->name, + nextm->dsp->name); /* no more slots available */ goto conf_software; } @@ -779,23 +791,23 @@ conf_software: nextm->dsp->pcm_bank_tx = 0; if (dsp_debug & DEBUG_DSP_CMX) printk(KERN_DEBUG - "%s adding %s & %s to new PCM slot %d " - "(TX and RX on different chips) because " - "both members have not same slots\n", - __func__, - member->dsp->name, - nextm->dsp->name, - member->dsp->pcm_slot_tx); + "%s adding %s & %s to new PCM slot %d " + "(TX and RX on different chips) because " + "both members have not same slots\n", + __func__, + member->dsp->name, + nextm->dsp->name, + member->dsp->pcm_slot_tx); dsp_cmx_hw_message(member->dsp, MISDN_CTRL_HFC_PCM_CONN, - member->dsp->pcm_slot_tx, member->dsp->pcm_bank_tx, - member->dsp->pcm_slot_rx, member->dsp->pcm_bank_rx); + member->dsp->pcm_slot_tx, member->dsp->pcm_bank_tx, + member->dsp->pcm_slot_rx, member->dsp->pcm_bank_rx); dsp_cmx_hw_message(nextm->dsp, MISDN_CTRL_HFC_PCM_CONN, - nextm->dsp->pcm_slot_tx, nextm->dsp->pcm_bank_tx, - nextm->dsp->pcm_slot_rx, nextm->dsp->pcm_bank_rx); + nextm->dsp->pcm_slot_tx, nextm->dsp->pcm_bank_tx, + nextm->dsp->pcm_slot_rx, nextm->dsp->pcm_bank_rx); conf->hardware = 1; - conf->software = 0; + conf->software = tx_data; return; - /* if members have one bank (or on the same chip) */ + /* if members have one bank (or on the same chip) */ } else { /* if both members have different crossed slots */ if (member->dsp->pcm_slot_tx >= 0 && @@ -815,15 +827,15 @@ conf_software: /* all members have same slot */ if (dsp_debug & DEBUG_DSP_CMX) printk(KERN_DEBUG - "%s dsp %s & %s stay joined on PCM " - "slot %d (TX) %d (RX) on same chip " - "or one bank PCM)\n", __func__, - member->dsp->name, - nextm->dsp->name, - member->dsp->pcm_slot_tx, - member->dsp->pcm_slot_rx); - conf->hardware = 0; - conf->software = 1; + "%s dsp %s & %s stay joined on PCM " + "slot %d (TX) %d (RX) on same chip " + "or one bank PCM)\n", __func__, + member->dsp->name, + nextm->dsp->name, + member->dsp->pcm_slot_tx, + member->dsp->pcm_slot_rx); + conf->hardware = 1; + conf->software = tx_data; return; } /* find two new slot */ @@ -836,11 +848,11 @@ conf_software: if (dsp->pcm_slot_rx >= 0 && dsp->pcm_slot_rx < sizeof(freeslots)) - freeslots[dsp->pcm_slot_tx] = 0; + freeslots[dsp->pcm_slot_rx] = 0; if (dsp->pcm_slot_tx >= 0 && dsp->pcm_slot_tx < sizeof(freeslots)) - freeslots[dsp->pcm_slot_rx] = 0; + freeslots[dsp->pcm_slot_tx] = 0; } } i1 = 0; @@ -853,14 +865,14 @@ conf_software: if (i1 == ii) { if (dsp_debug & DEBUG_DSP_CMX) printk(KERN_DEBUG - "%s no slot available " - "for %s & %s\n", __func__, - member->dsp->name, - nextm->dsp->name); + "%s no slot available " + "for %s & %s\n", __func__, + member->dsp->name, + nextm->dsp->name); /* no more slots available */ goto conf_software; } - i2 = i1+1; + i2 = i1 + 1; while (i2 < ii) { if (freeslots[i2]) break; @@ -869,11 +881,11 @@ conf_software: if (i2 == ii) { if (dsp_debug & DEBUG_DSP_CMX) printk(KERN_DEBUG - "%s no slot available " - "for %s & %s\n", - __func__, - member->dsp->name, - nextm->dsp->name); + "%s no slot available " + "for %s & %s\n", + __func__, + member->dsp->name, + nextm->dsp->name); /* no more slots available */ goto conf_software; } @@ -888,22 +900,22 @@ conf_software: nextm->dsp->pcm_bank_tx = 0; if (dsp_debug & DEBUG_DSP_CMX) printk(KERN_DEBUG - "%s adding %s & %s to new PCM slot %d " - "(TX) %d (RX) on same chip or one bank " - "PCM, because both members have not " - "crossed slots\n", __func__, - member->dsp->name, - nextm->dsp->name, - member->dsp->pcm_slot_tx, - member->dsp->pcm_slot_rx); + "%s adding %s & %s to new PCM slot %d " + "(TX) %d (RX) on same chip or one bank " + "PCM, because both members have not " + "crossed slots\n", __func__, + member->dsp->name, + nextm->dsp->name, + member->dsp->pcm_slot_tx, + member->dsp->pcm_slot_rx); dsp_cmx_hw_message(member->dsp, MISDN_CTRL_HFC_PCM_CONN, - member->dsp->pcm_slot_tx, member->dsp->pcm_bank_tx, - member->dsp->pcm_slot_rx, member->dsp->pcm_bank_rx); + member->dsp->pcm_slot_tx, member->dsp->pcm_bank_tx, + member->dsp->pcm_slot_rx, member->dsp->pcm_bank_rx); dsp_cmx_hw_message(nextm->dsp, MISDN_CTRL_HFC_PCM_CONN, - nextm->dsp->pcm_slot_tx, nextm->dsp->pcm_bank_tx, - nextm->dsp->pcm_slot_rx, nextm->dsp->pcm_bank_rx); + nextm->dsp->pcm_slot_tx, nextm->dsp->pcm_bank_tx, + nextm->dsp->pcm_slot_rx, nextm->dsp->pcm_bank_rx); conf->hardware = 1; - conf->software = 0; + conf->software = tx_data; return; } } @@ -917,29 +929,35 @@ conf_software: if (same_hfc < 0) { if (dsp_debug & DEBUG_DSP_CMX) printk(KERN_DEBUG - "%s conference %d cannot be formed, because " - "members are on different chips or not " - "on HFC chip\n", - __func__, conf->id); + "%s conference %d cannot be formed, because " + "members are on different chips or not " + "on HFC chip\n", + __func__, conf->id); goto conf_software; } /* for more than two members.. */ - /* in case of hdlc, we change to software */ - if (dsp->hdlc) - goto conf_software; - /* if all members already have the same conference */ - if (all_conf) + if (all_conf) { + conf->hardware = 1; + conf->software = tx_data; return; + } /* * if there is an existing conference, but not all members have joined */ if (current_conf >= 0) { -join_members: + join_members: list_for_each_entry(member, &conf->mlist, list) { + /* if no conference engine on our chip, change to + * software */ + if (!member->dsp->features.hfc_conf) + goto conf_software; + /* in case of hdlc, change to software */ + if (member->dsp->hdlc) + goto conf_software; /* join to current conference */ if (member->dsp->hfc_conf == current_conf) continue; @@ -951,10 +969,10 @@ join_members: * slot will be overwritten. */ if ( - dsp != member->dsp && - /* dsp must be on the same PCM */ - member->dsp->features.pcm_id == - dsp->features.pcm_id) { + dsp != member->dsp && + /* dsp must be on the same PCM */ + member->dsp->features.pcm_id == + dsp->features.pcm_id) { /* dsp must be on a slot */ if (dsp->pcm_slot_tx >= 0 && dsp->pcm_slot_tx < @@ -977,16 +995,16 @@ join_members: /* no more slots available */ if (dsp_debug & DEBUG_DSP_CMX) printk(KERN_DEBUG - "%s conference %d cannot be formed," - " because no slot free\n", - __func__, conf->id); + "%s conference %d cannot be formed," + " because no slot free\n", + __func__, conf->id); goto conf_software; } if (dsp_debug & DEBUG_DSP_CMX) printk(KERN_DEBUG - "%s changing dsp %s to HW conference " - "%d slot %d\n", __func__, - member->dsp->name, current_conf, i); + "%s changing dsp %s to HW conference " + "%d slot %d\n", __func__, + member->dsp->name, current_conf, i); /* assign free slot & set PCM & join conf */ member->dsp->pcm_slot_tx = i; member->dsp->pcm_slot_rx = i; @@ -994,10 +1012,12 @@ join_members: member->dsp->pcm_bank_rx = 2; member->dsp->hfc_conf = current_conf; dsp_cmx_hw_message(member->dsp, MISDN_CTRL_HFC_PCM_CONN, - i, 2, i, 2); + i, 2, i, 2); dsp_cmx_hw_message(member->dsp, - MISDN_CTRL_HFC_CONF_JOIN, current_conf, 0, 0, 0); + MISDN_CTRL_HFC_CONF_JOIN, current_conf, 0, 0, 0); } + conf->hardware = 1; + conf->software = tx_data; return; } @@ -1025,9 +1045,9 @@ join_members: /* no more conferences available */ if (dsp_debug & DEBUG_DSP_CMX) printk(KERN_DEBUG - "%s conference %d cannot be formed, because " - "no conference number free\n", - __func__, conf->id); + "%s conference %d cannot be formed, because " + "no conference number free\n", + __func__, conf->id); goto conf_software; } /* join all members */ @@ -1055,7 +1075,7 @@ dsp_cmx_conf(struct dsp *dsp, u32 conf_id) if (dsp->conf_id) { if (dsp_debug & DEBUG_DSP_CMX) printk(KERN_DEBUG "removing us from conference %d\n", - dsp->conf->id); + dsp->conf->id); /* remove us from conf */ conf = dsp->conf; err = dsp_cmx_del_conf_member(dsp); @@ -1070,7 +1090,7 @@ dsp_cmx_conf(struct dsp *dsp, u32 conf_id) if (list_empty(&conf->mlist)) { if (dsp_debug & DEBUG_DSP_CMX) printk(KERN_DEBUG - "conference is empty, so we remove it.\n"); + "conference is empty, so we remove it.\n"); err = dsp_cmx_del_conf(conf); if (err) return err; @@ -1087,29 +1107,29 @@ dsp_cmx_conf(struct dsp *dsp, u32 conf_id) /* now add us to conf */ if (dsp_debug & DEBUG_DSP_CMX) printk(KERN_DEBUG "searching conference %d\n", - conf_id); + conf_id); conf = dsp_cmx_search_conf(conf_id); if (!conf) { if (dsp_debug & DEBUG_DSP_CMX) printk(KERN_DEBUG - "conference doesn't exist yet, creating.\n"); + "conference doesn't exist yet, creating.\n"); /* the conference doesn't exist, so we create */ conf = dsp_cmx_new_conf(conf_id); if (!conf) return -EINVAL; } else if (!list_empty(&conf->mlist)) { member = list_entry(conf->mlist.next, struct dsp_conf_member, - list); + list); if (dsp->hdlc && !member->dsp->hdlc) { if (dsp_debug & DEBUG_DSP_CMX) printk(KERN_DEBUG - "cannot join transparent conference.\n"); + "cannot join transparent conference.\n"); return -EINVAL; } if (!dsp->hdlc && member->dsp->hdlc) { if (dsp_debug & DEBUG_DSP_CMX) printk(KERN_DEBUG - "cannot join hdlc conference.\n"); + "cannot join hdlc conference.\n"); return -EINVAL; } } @@ -1123,7 +1143,7 @@ dsp_cmx_conf(struct dsp *dsp, u32 conf_id) if (list_empty(&conf->mlist)) { if (dsp_debug & DEBUG_DSP_CMX) printk(KERN_DEBUG - "we are alone in this conference, so exit.\n"); + "we are alone in this conference, so exit.\n"); /* update hardware */ dsp_cmx_hardware(NULL, dsp); return 0; @@ -1135,6 +1155,25 @@ dsp_cmx_conf(struct dsp *dsp, u32 conf_id) return 0; } +#ifdef CMX_DELAY_DEBUG +int delaycount; +static void +showdelay(struct dsp *dsp, int samples, int delay) +{ + char bar[] = "--------------------------------------------------|"; + int sdelay; + + delaycount += samples; + if (delaycount < 8000) + return; + delaycount = 0; + + sdelay = delay * 50 / (dsp_poll << 2); + + printk(KERN_DEBUG "DELAY (%s) %3d >%s\n", dsp->name, delay, + sdelay > 50 ? "..." : bar + 50 - sdelay); +} +#endif /* * audio data is received from card @@ -1154,9 +1193,9 @@ dsp_cmx_receive(struct dsp *dsp, struct sk_buff *skb) /* half of the buffer should be larger than maximum packet size */ if (len >= CMX_BUFF_HALF) { printk(KERN_ERR - "%s line %d: packet from card is too large (%d bytes). " - "please make card send smaller packets OR increase " - "CMX_BUFF_SIZE\n", __FILE__, __LINE__, len); + "%s line %d: packet from card is too large (%d bytes). " + "please make card send smaller packets OR increase " + "CMX_BUFF_SIZE\n", __FILE__, __LINE__, len); return; } @@ -1168,11 +1207,18 @@ dsp_cmx_receive(struct dsp *dsp, struct sk_buff *skb) dsp->rx_init = 0; if (dsp->features.unordered) { dsp->rx_R = (hh->id & CMX_BUFF_MASK); - dsp->rx_W = (dsp->rx_R + dsp->cmx_delay) - & CMX_BUFF_MASK; + if (dsp->cmx_delay) + dsp->rx_W = (dsp->rx_R + dsp->cmx_delay) + & CMX_BUFF_MASK; + else + dsp->rx_W = (dsp->rx_R + (dsp_poll >> 1)) + & CMX_BUFF_MASK; } else { dsp->rx_R = 0; - dsp->rx_W = dsp->cmx_delay; + if (dsp->cmx_delay) + dsp->rx_W = dsp->cmx_delay; + else + dsp->rx_W = dsp_poll >> 1; } } /* if frame contains time code, write directly */ @@ -1185,19 +1231,26 @@ dsp_cmx_receive(struct dsp *dsp, struct sk_buff *skb) * we set our new read pointer, and write silence to buffer */ if (((dsp->rx_W-dsp->rx_R) & CMX_BUFF_MASK) >= CMX_BUFF_HALF) { - if (dsp_debug & DEBUG_DSP_CMX) + if (dsp_debug & DEBUG_DSP_CLOCK) printk(KERN_DEBUG - "cmx_receive(dsp=%lx): UNDERRUN (or overrun the " - "maximum delay), adjusting read pointer! " - "(inst %s)\n", (u_long)dsp, dsp->name); - /* flush buffer */ + "cmx_receive(dsp=%lx): UNDERRUN (or overrun the " + "maximum delay), adjusting read pointer! " + "(inst %s)\n", (u_long)dsp, dsp->name); + /* flush rx buffer and set delay to dsp_poll / 2 */ if (dsp->features.unordered) { dsp->rx_R = (hh->id & CMX_BUFF_MASK); - dsp->rx_W = (dsp->rx_R + dsp->cmx_delay) - & CMX_BUFF_MASK; + if (dsp->cmx_delay) + dsp->rx_W = (dsp->rx_R + dsp->cmx_delay) + & CMX_BUFF_MASK; + else + dsp->rx_W = (dsp->rx_R + (dsp_poll >> 1)) + & CMX_BUFF_MASK; } else { dsp->rx_R = 0; - dsp->rx_W = dsp->cmx_delay; + if (dsp->cmx_delay) + dsp->rx_W = dsp->cmx_delay; + else + dsp->rx_W = dsp_poll >> 1; } memset(dsp->rx_buff, dsp_silence, sizeof(dsp->rx_buff)); } @@ -1205,29 +1258,29 @@ dsp_cmx_receive(struct dsp *dsp, struct sk_buff *skb) if (dsp->cmx_delay) if (((dsp->rx_W - dsp->rx_R) & CMX_BUFF_MASK) >= (dsp->cmx_delay << 1)) { - if (dsp_debug & DEBUG_DSP_CMX) + if (dsp_debug & DEBUG_DSP_CLOCK) printk(KERN_DEBUG - "cmx_receive(dsp=%lx): OVERRUN (because " - "twice the delay is reached), adjusting " - "read pointer! (inst %s)\n", - (u_long)dsp, dsp->name); - /* flush buffer */ - if (dsp->features.unordered) { - dsp->rx_R = (hh->id & CMX_BUFF_MASK); - dsp->rx_W = (dsp->rx_R + dsp->cmx_delay) - & CMX_BUFF_MASK; - } else { - dsp->rx_R = 0; - dsp->rx_W = dsp->cmx_delay; + "cmx_receive(dsp=%lx): OVERRUN (because " + "twice the delay is reached), adjusting " + "read pointer! (inst %s)\n", + (u_long)dsp, dsp->name); + /* flush buffer */ + if (dsp->features.unordered) { + dsp->rx_R = (hh->id & CMX_BUFF_MASK); + dsp->rx_W = (dsp->rx_R + dsp->cmx_delay) + & CMX_BUFF_MASK; + } else { + dsp->rx_R = 0; + dsp->rx_W = dsp->cmx_delay; + } + memset(dsp->rx_buff, dsp_silence, sizeof(dsp->rx_buff)); } - memset(dsp->rx_buff, dsp_silence, sizeof(dsp->rx_buff)); - } /* show where to write */ #ifdef CMX_DEBUG printk(KERN_DEBUG - "cmx_receive(dsp=%lx): rx_R(dsp)=%05x rx_W(dsp)=%05x len=%d %s\n", - (u_long)dsp, dsp->rx_R, dsp->rx_W, len, dsp->name); + "cmx_receive(dsp=%lx): rx_R(dsp)=%05x rx_W(dsp)=%05x len=%d %s\n", + (u_long)dsp, dsp->rx_R, dsp->rx_W, len, dsp->name); #endif /* write data into rx_buffer */ @@ -1242,7 +1295,10 @@ dsp_cmx_receive(struct dsp *dsp, struct sk_buff *skb) } /* increase write-pointer */ - dsp->rx_W = ((dsp->rx_W+len) & CMX_BUFF_MASK); + dsp->rx_W = ((dsp->rx_W + len) & CMX_BUFF_MASK); +#ifdef CMX_DELAY_DEBUG + showdelay(dsp, len, (dsp->rx_W-dsp->rx_R) & CMX_BUFF_MASK); +#endif } @@ -1260,23 +1316,31 @@ dsp_cmx_send_member(struct dsp *dsp, int len, s32 *c, int members) int r, rr, t, tt, o_r, o_rr; int preload = 0; struct mISDNhead *hh, *thh; + int tx_data_only = 0; /* don't process if: */ if (!dsp->b_active) { /* if not active */ dsp->last_tx = 0; return; } - if (dsp->pcm_slot_tx >= 0 && /* connected to pcm slot */ + if (((dsp->conf && dsp->conf->hardware) || /* hardware conf */ + dsp->echo.hardware) && /* OR hardware echo */ dsp->tx_R == dsp->tx_W && /* AND no tx-data */ !(dsp->tone.tone && dsp->tone.software)) { /* AND not soft tones */ - dsp->last_tx = 0; - return; + if (!dsp->tx_data) { /* no tx_data for user space required */ + dsp->last_tx = 0; + return; + } + if (dsp->conf && dsp->conf->software && dsp->conf->hardware) + tx_data_only = 1; + if (dsp->echo.software && dsp->echo.hardware) + tx_data_only = 1; } #ifdef CMX_DEBUG printk(KERN_DEBUG - "SEND members=%d dsp=%s, conf=%p, rx_R=%05x rx_W=%05x\n", - members, dsp->name, conf, dsp->rx_R, dsp->rx_W); + "SEND members=%d dsp=%s, conf=%p, rx_R=%05x rx_W=%05x\n", + members, dsp->name, conf, dsp->rx_R, dsp->rx_W); #endif /* preload if we have delay set */ @@ -1290,8 +1354,8 @@ dsp_cmx_send_member(struct dsp *dsp, int len, s32 *c, int members) nskb = mI_alloc_skb(len + preload, GFP_ATOMIC); if (!nskb) { printk(KERN_ERR - "FATAL ERROR in mISDN_dsp.o: cannot alloc %d bytes\n", - len + preload); + "FATAL ERROR in mISDN_dsp.o: cannot alloc %d bytes\n", + len + preload); return; } hh = mISDN_HEAD_P(nskb); @@ -1327,21 +1391,22 @@ dsp_cmx_send_member(struct dsp *dsp, int len, s32 *c, int members) if (!dsp->tx_mix && t != tt) { /* -> send tx-data and continue when not enough */ #ifdef CMX_TX_DEBUG - sprintf(debugbuf, "TX sending (%04x-%04x)%p: ", t, tt, p); + sprintf(debugbuf, "TX sending (%04x-%04x)%p: ", t, tt, p); #endif while (r != rr && t != tt) { #ifdef CMX_TX_DEBUG if (strlen(debugbuf) < 48) - sprintf(debugbuf+strlen(debugbuf), " %02x", p[t]); + sprintf(debugbuf + strlen(debugbuf), " %02x", + p[t]); #endif *d++ = p[t]; /* write tx_buff */ - t = (t+1) & CMX_BUFF_MASK; - r = (r+1) & CMX_BUFF_MASK; + t = (t + 1) & CMX_BUFF_MASK; + r = (r + 1) & CMX_BUFF_MASK; } if (r == rr) { dsp->tx_R = t; #ifdef CMX_TX_DEBUG - printk(KERN_DEBUG "%s\n", debugbuf); + printk(KERN_DEBUG "%s\n", debugbuf); #endif goto send_packet; } @@ -1353,29 +1418,33 @@ dsp_cmx_send_member(struct dsp *dsp, int len, s32 *c, int members) /* PROCESS DATA (one member / no conf) */ if (!conf || members <= 1) { /* -> if echo is NOT enabled */ - if (!dsp->echo) { + if (!dsp->echo.software) { /* -> send tx-data if available or use 0-volume */ while (r != rr && t != tt) { *d++ = p[t]; /* write tx_buff */ - t = (t+1) & CMX_BUFF_MASK; - r = (r+1) & CMX_BUFF_MASK; + t = (t + 1) & CMX_BUFF_MASK; + r = (r + 1) & CMX_BUFF_MASK; } - if (r != rr) - memset(d, dsp_silence, (rr-r)&CMX_BUFF_MASK); - /* -> if echo is enabled */ + if (r != rr) { + if (dsp_debug & DEBUG_DSP_CLOCK) + printk(KERN_DEBUG "%s: RX empty\n", + __func__); + memset(d, dsp_silence, (rr - r) & CMX_BUFF_MASK); + } + /* -> if echo is enabled */ } else { /* * -> mix tx-data with echo if available, * or use echo only */ while (r != rr && t != tt) { - *d++ = dsp_audio_mix_law[(p[t]<<8)|q[r]]; - t = (t+1) & CMX_BUFF_MASK; - r = (r+1) & CMX_BUFF_MASK; + *d++ = dsp_audio_mix_law[(p[t] << 8) | q[r]]; + t = (t + 1) & CMX_BUFF_MASK; + r = (r + 1) & CMX_BUFF_MASK; } while (r != rr) { *d++ = q[r]; /* echo */ - r = (r+1) & CMX_BUFF_MASK; + r = (r + 1) & CMX_BUFF_MASK; } } dsp->tx_R = t; @@ -1385,84 +1454,84 @@ dsp_cmx_send_member(struct dsp *dsp, int len, s32 *c, int members) #ifdef CMX_CONF_DEBUG if (0) { #else - if (members == 2) { + if (members == 2) { #endif - /* "other" becomes other party */ - other = (list_entry(conf->mlist.next, - struct dsp_conf_member, list))->dsp; - if (other == member) - other = (list_entry(conf->mlist.prev, - struct dsp_conf_member, list))->dsp; - o_q = other->rx_buff; /* received data */ - o_rr = (other->rx_R + len) & CMX_BUFF_MASK; + /* "other" becomes other party */ + other = (list_entry(conf->mlist.next, + struct dsp_conf_member, list))->dsp; + if (other == member) + other = (list_entry(conf->mlist.prev, + struct dsp_conf_member, list))->dsp; + o_q = other->rx_buff; /* received data */ + o_rr = (other->rx_R + len) & CMX_BUFF_MASK; /* end of rx-pointer */ - o_r = (o_rr - rr + r) & CMX_BUFF_MASK; + o_r = (o_rr - rr + r) & CMX_BUFF_MASK; /* start rx-pointer at current read position*/ - /* -> if echo is NOT enabled */ - if (!dsp->echo) { - /* - * -> copy other member's rx-data, - * if tx-data is available, mix - */ - while (o_r != o_rr && t != tt) { - *d++ = dsp_audio_mix_law[(p[t]<<8)|o_q[o_r]]; - t = (t+1) & CMX_BUFF_MASK; - o_r = (o_r+1) & CMX_BUFF_MASK; - } - while (o_r != o_rr) { - *d++ = o_q[o_r]; - o_r = (o_r+1) & CMX_BUFF_MASK; - } - /* -> if echo is enabled */ - } else { - /* - * -> mix other member's rx-data with echo, - * if tx-data is available, mix - */ - while (r != rr && t != tt) { - sample = dsp_audio_law_to_s32[p[t]] + - dsp_audio_law_to_s32[q[r]] + - dsp_audio_law_to_s32[o_q[o_r]]; - if (sample < -32768) - sample = -32768; - else if (sample > 32767) - sample = 32767; - *d++ = dsp_audio_s16_to_law[sample & 0xffff]; - /* tx-data + rx_data + echo */ - t = (t+1) & CMX_BUFF_MASK; - r = (r+1) & CMX_BUFF_MASK; - o_r = (o_r+1) & CMX_BUFF_MASK; - } - while (r != rr) { - *d++ = dsp_audio_mix_law[(q[r]<<8)|o_q[o_r]]; - r = (r+1) & CMX_BUFF_MASK; - o_r = (o_r+1) & CMX_BUFF_MASK; + /* -> if echo is NOT enabled */ + if (!dsp->echo.software) { + /* + * -> copy other member's rx-data, + * if tx-data is available, mix + */ + while (o_r != o_rr && t != tt) { + *d++ = dsp_audio_mix_law[(p[t] << 8) | o_q[o_r]]; + t = (t + 1) & CMX_BUFF_MASK; + o_r = (o_r + 1) & CMX_BUFF_MASK; + } + while (o_r != o_rr) { + *d++ = o_q[o_r]; + o_r = (o_r + 1) & CMX_BUFF_MASK; + } + /* -> if echo is enabled */ + } else { + /* + * -> mix other member's rx-data with echo, + * if tx-data is available, mix + */ + while (r != rr && t != tt) { + sample = dsp_audio_law_to_s32[p[t]] + + dsp_audio_law_to_s32[q[r]] + + dsp_audio_law_to_s32[o_q[o_r]]; + if (sample < -32768) + sample = -32768; + else if (sample > 32767) + sample = 32767; + *d++ = dsp_audio_s16_to_law[sample & 0xffff]; + /* tx-data + rx_data + echo */ + t = (t + 1) & CMX_BUFF_MASK; + r = (r + 1) & CMX_BUFF_MASK; + o_r = (o_r + 1) & CMX_BUFF_MASK; + } + while (r != rr) { + *d++ = dsp_audio_mix_law[(q[r] << 8) | o_q[o_r]]; + r = (r + 1) & CMX_BUFF_MASK; + o_r = (o_r + 1) & CMX_BUFF_MASK; + } } + dsp->tx_R = t; + goto send_packet; } - dsp->tx_R = t; - goto send_packet; - } #ifdef DSP_NEVER_DEFINED } #endif /* PROCESS DATA (three or more members) */ /* -> if echo is NOT enabled */ - if (!dsp->echo) { + if (!dsp->echo.software) { /* - * -> substract rx-data from conf-data, + * -> subtract rx-data from conf-data, * if tx-data is available, mix */ while (r != rr && t != tt) { sample = dsp_audio_law_to_s32[p[t]] + *c++ - - dsp_audio_law_to_s32[q[r]]; + dsp_audio_law_to_s32[q[r]]; if (sample < -32768) sample = -32768; else if (sample > 32767) sample = 32767; *d++ = dsp_audio_s16_to_law[sample & 0xffff]; - /* conf-rx+tx */ - r = (r+1) & CMX_BUFF_MASK; - t = (t+1) & CMX_BUFF_MASK; + /* conf-rx+tx */ + r = (r + 1) & CMX_BUFF_MASK; + t = (t + 1) & CMX_BUFF_MASK; } while (r != rr) { sample = *c++ - dsp_audio_law_to_s32[q[r]]; @@ -1471,10 +1540,10 @@ dsp_cmx_send_member(struct dsp *dsp, int len, s32 *c, int members) else if (sample > 32767) sample = 32767; *d++ = dsp_audio_s16_to_law[sample & 0xffff]; - /* conf-rx */ - r = (r+1) & CMX_BUFF_MASK; + /* conf-rx */ + r = (r + 1) & CMX_BUFF_MASK; } - /* -> if echo is enabled */ + /* -> if echo is enabled */ } else { /* * -> encode conf-data, if tx-data @@ -1487,9 +1556,9 @@ dsp_cmx_send_member(struct dsp *dsp, int len, s32 *c, int members) else if (sample > 32767) sample = 32767; *d++ = dsp_audio_s16_to_law[sample & 0xffff]; - /* conf(echo)+tx */ - t = (t+1) & CMX_BUFF_MASK; - r = (r+1) & CMX_BUFF_MASK; + /* conf(echo)+tx */ + t = (t + 1) & CMX_BUFF_MASK; + r = (r + 1) & CMX_BUFF_MASK; } while (r != rr) { sample = *c++; @@ -1498,8 +1567,8 @@ dsp_cmx_send_member(struct dsp *dsp, int len, s32 *c, int members) else if (sample > 32767) sample = 32767; *d++ = dsp_audio_s16_to_law[sample & 0xffff]; - /* conf(echo) */ - r = (r+1) & CMX_BUFF_MASK; + /* conf(echo) */ + r = (r + 1) & CMX_BUFF_MASK; } } dsp->tx_R = t; @@ -1508,30 +1577,43 @@ dsp_cmx_send_member(struct dsp *dsp, int len, s32 *c, int members) send_packet: /* * send tx-data if enabled - don't filter, - * becuase we want what we send, not what we filtered + * because we want what we send, not what we filtered */ if (dsp->tx_data) { - /* PREPARE RESULT */ - txskb = mI_alloc_skb(len, GFP_ATOMIC); - if (!txskb) { - printk(KERN_ERR - "FATAL ERROR in mISDN_dsp.o: " - "cannot alloc %d bytes\n", len); + if (tx_data_only) { + hh->prim = DL_DATA_REQ; + hh->id = 0; + /* queue and trigger */ + skb_queue_tail(&dsp->sendq, nskb); + schedule_work(&dsp->workq); + /* exit because only tx_data is used */ + return; } else { - thh = mISDN_HEAD_P(txskb); - thh->prim = DL_DATA_REQ; - thh->id = 0; - memcpy(skb_put(txskb, len), nskb->data+preload, len); - /* queue (trigger later) */ - skb_queue_tail(&dsp->sendq, txskb); + txskb = mI_alloc_skb(len, GFP_ATOMIC); + if (!txskb) { + printk(KERN_ERR + "FATAL ERROR in mISDN_dsp.o: " + "cannot alloc %d bytes\n", len); + } else { + thh = mISDN_HEAD_P(txskb); + thh->prim = DL_DATA_REQ; + thh->id = 0; + memcpy(skb_put(txskb, len), nskb->data + preload, + len); + /* queue (trigger later) */ + skb_queue_tail(&dsp->sendq, txskb); + } } } + + /* send data only to card, if we don't just calculated tx_data */ /* adjust volume */ if (dsp->tx_volume) dsp_change_volume(nskb, dsp->tx_volume); /* pipeline */ if (dsp->pipeline.inuse) - dsp_pipeline_process_tx(&dsp->pipeline, nskb->data, nskb->len); + dsp_pipeline_process_tx(&dsp->pipeline, nskb->data, + nskb->len); /* crypt */ if (dsp->bf_enable) dsp_bf_encrypt(dsp, nskb->data, nskb->len); @@ -1540,11 +1622,11 @@ send_packet: schedule_work(&dsp->workq); } -u32 samplecount; +static u32 jittercount; /* counter for jitter check */ struct timer_list dsp_spl_tl; -u32 dsp_spl_jiffies; /* calculate the next time to fire */ -u32 dsp_start_jiffies; /* jiffies at the time, the calculation begins */ -struct timeval dsp_start_tv; /* time at start of calculation */ +unsigned long dsp_spl_jiffies; /* calculate the next time to fire */ +static u16 dsp_count; /* last sample count */ +static int dsp_count_valid; /* if we have last sample count */ void dsp_cmx_send(void *arg) @@ -1553,43 +1635,38 @@ dsp_cmx_send(void *arg) struct dsp_conf_member *member; struct dsp *dsp; int mustmix, members; - s32 mixbuffer[MAX_POLL+100], *c; + static s32 mixbuffer[MAX_POLL + 100]; + s32 *c; u8 *p, *q; int r, rr; int jittercheck = 0, delay, i; u_long flags; - struct timeval tv; - u32 elapsed; - s16 length; + u16 length, count; /* lock */ spin_lock_irqsave(&dsp_lock, flags); - if (!dsp_start_tv.tv_sec) { - do_gettimeofday(&dsp_start_tv); + if (!dsp_count_valid) { + dsp_count = mISDN_clock_get(); length = dsp_poll; + dsp_count_valid = 1; } else { - do_gettimeofday(&tv); - elapsed = ((tv.tv_sec - dsp_start_tv.tv_sec) * 8000) - + ((s32)(tv.tv_usec / 125) - (dsp_start_tv.tv_usec / 125)); - dsp_start_tv.tv_sec = tv.tv_sec; - dsp_start_tv.tv_usec = tv.tv_usec; - length = elapsed; + count = mISDN_clock_get(); + length = count - dsp_count; + dsp_count = count; } if (length > MAX_POLL + 100) length = MAX_POLL + 100; -/* printk(KERN_DEBUG "len=%d dsp_count=0x%x.%04x dsp_poll_diff=0x%x.%04x\n", - length, dsp_count >> 16, dsp_count & 0xffff, dsp_poll_diff >> 16, - dsp_poll_diff & 0xffff); - */ + /* printk(KERN_DEBUG "len=%d dsp_count=0x%x\n", length, dsp_count); */ /* - * check if jitter needs to be checked - * (this is about every second = 8192 samples) + * check if jitter needs to be checked (this is every second) */ - samplecount += length; - if ((samplecount & 8191) < length) + jittercount += length; + if (jittercount >= 8000) { + jittercount -= 8000; jittercheck = 1; + } /* loop all members that do not require conference mixing */ list_for_each_entry(dsp, &dsp_ilist, list) { @@ -1603,9 +1680,9 @@ dsp_cmx_send(void *arg) #ifdef CMX_CONF_DEBUG if (conf->software && members > 1) #else - if (conf->software && members > 2) + if (conf->software && members > 2) #endif - mustmix = 1; + mustmix = 1; } /* transmission required */ @@ -1626,261 +1703,263 @@ dsp_cmx_send(void *arg) #ifdef CMX_CONF_DEBUG if (conf->software && members > 1) { #else - if (conf->software && members > 2) { + if (conf->software && members > 2) { #endif - /* check for hdlc conf */ - member = list_entry(conf->mlist.next, - struct dsp_conf_member, list); - if (member->dsp->hdlc) - continue; - /* mix all data */ - memset(mixbuffer, 0, length*sizeof(s32)); - list_for_each_entry(member, &conf->mlist, list) { - dsp = member->dsp; - /* get range of data to mix */ - c = mixbuffer; - q = dsp->rx_buff; - r = dsp->rx_R; - rr = (r + length) & CMX_BUFF_MASK; - /* add member's data */ - while (r != rr) { - *c++ += dsp_audio_law_to_s32[q[r]]; - r = (r+1) & CMX_BUFF_MASK; + /* check for hdlc conf */ + member = list_entry(conf->mlist.next, + struct dsp_conf_member, list); + if (member->dsp->hdlc) + continue; + /* mix all data */ + memset(mixbuffer, 0, length * sizeof(s32)); + list_for_each_entry(member, &conf->mlist, list) { + dsp = member->dsp; + /* get range of data to mix */ + c = mixbuffer; + q = dsp->rx_buff; + r = dsp->rx_R; + rr = (r + length) & CMX_BUFF_MASK; + /* add member's data */ + while (r != rr) { + *c++ += dsp_audio_law_to_s32[q[r]]; + r = (r + 1) & CMX_BUFF_MASK; + } } - } - - /* process each member */ - list_for_each_entry(member, &conf->mlist, list) { - /* transmission */ - dsp_cmx_send_member(member->dsp, length, - mixbuffer, members); - } - } - } - /* delete rx-data, increment buffers, change pointers */ - list_for_each_entry(dsp, &dsp_ilist, list) { - if (dsp->hdlc) - continue; - p = dsp->rx_buff; - q = dsp->tx_buff; - r = dsp->rx_R; - /* move receive pointer when receiving */ - if (!dsp->rx_is_off) { - rr = (r + length) & CMX_BUFF_MASK; - /* delete rx-data */ - while (r != rr) { - p[r] = dsp_silence; - r = (r+1) & CMX_BUFF_MASK; + /* process each member */ + list_for_each_entry(member, &conf->mlist, list) { + /* transmission */ + dsp_cmx_send_member(member->dsp, length, + mixbuffer, members); + } } - /* increment rx-buffer pointer */ - dsp->rx_R = r; /* write incremented read pointer */ } - /* check current rx_delay */ - delay = (dsp->rx_W-dsp->rx_R) & CMX_BUFF_MASK; - if (delay >= CMX_BUFF_HALF) - delay = 0; /* will be the delay before next write */ - /* check for lower delay */ - if (delay < dsp->rx_delay[0]) - dsp->rx_delay[0] = delay; - /* check current tx_delay */ - delay = (dsp->tx_W-dsp->tx_R) & CMX_BUFF_MASK; - if (delay >= CMX_BUFF_HALF) - delay = 0; /* will be the delay before next write */ - /* check for lower delay */ - if (delay < dsp->tx_delay[0]) - dsp->tx_delay[0] = delay; - if (jittercheck) { - /* find the lowest of all rx_delays */ - delay = dsp->rx_delay[0]; - i = 1; - while (i < MAX_SECONDS_JITTER_CHECK) { - if (delay > dsp->rx_delay[i]) - delay = dsp->rx_delay[i]; - i++; - } - /* - * remove rx_delay only if we have delay AND we - * have not preset cmx_delay - */ - if (delay && !dsp->cmx_delay) { - if (dsp_debug & DEBUG_DSP_CMX) - printk(KERN_DEBUG - "%s lowest rx_delay of %d bytes for" - " dsp %s are now removed.\n", - __func__, delay, - dsp->name); - r = dsp->rx_R; - rr = (r + delay) & CMX_BUFF_MASK; + /* delete rx-data, increment buffers, change pointers */ + list_for_each_entry(dsp, &dsp_ilist, list) { + if (dsp->hdlc) + continue; + p = dsp->rx_buff; + q = dsp->tx_buff; + r = dsp->rx_R; + /* move receive pointer when receiving */ + if (!dsp->rx_is_off) { + rr = (r + length) & CMX_BUFF_MASK; /* delete rx-data */ while (r != rr) { p[r] = dsp_silence; - r = (r+1) & CMX_BUFF_MASK; + r = (r + 1) & CMX_BUFF_MASK; } /* increment rx-buffer pointer */ - dsp->rx_R = r; - /* write incremented read pointer */ - } - /* find the lowest of all tx_delays */ - delay = dsp->tx_delay[0]; - i = 1; - while (i < MAX_SECONDS_JITTER_CHECK) { - if (delay > dsp->tx_delay[i]) - delay = dsp->tx_delay[i]; - i++; + dsp->rx_R = r; /* write incremented read pointer */ } - /* - * remove delay only if we have delay AND we - * have enabled tx_dejitter - */ - if (delay && dsp->tx_dejitter) { - if (dsp_debug & DEBUG_DSP_CMX) - printk(KERN_DEBUG - "%s lowest tx_delay of %d bytes for" - " dsp %s are now removed.\n", - __func__, delay, - dsp->name); - r = dsp->tx_R; - rr = (r + delay) & CMX_BUFF_MASK; - /* delete tx-data */ - while (r != rr) { - q[r] = dsp_silence; - r = (r+1) & CMX_BUFF_MASK; + + /* check current rx_delay */ + delay = (dsp->rx_W-dsp->rx_R) & CMX_BUFF_MASK; + if (delay >= CMX_BUFF_HALF) + delay = 0; /* will be the delay before next write */ + /* check for lower delay */ + if (delay < dsp->rx_delay[0]) + dsp->rx_delay[0] = delay; + /* check current tx_delay */ + delay = (dsp->tx_W-dsp->tx_R) & CMX_BUFF_MASK; + if (delay >= CMX_BUFF_HALF) + delay = 0; /* will be the delay before next write */ + /* check for lower delay */ + if (delay < dsp->tx_delay[0]) + dsp->tx_delay[0] = delay; + if (jittercheck) { + /* find the lowest of all rx_delays */ + delay = dsp->rx_delay[0]; + i = 1; + while (i < MAX_SECONDS_JITTER_CHECK) { + if (delay > dsp->rx_delay[i]) + delay = dsp->rx_delay[i]; + i++; } - /* increment rx-buffer pointer */ - dsp->tx_R = r; - /* write incremented read pointer */ - } - /* scroll up delays */ - i = MAX_SECONDS_JITTER_CHECK - 1; - while (i) { - dsp->rx_delay[i] = dsp->rx_delay[i-1]; - dsp->tx_delay[i] = dsp->tx_delay[i-1]; - i--; + /* + * remove rx_delay only if we have delay AND we + * have not preset cmx_delay AND + * the delay is greater dsp_poll + */ + if (delay > dsp_poll && !dsp->cmx_delay) { + if (dsp_debug & DEBUG_DSP_CLOCK) + printk(KERN_DEBUG + "%s lowest rx_delay of %d bytes for" + " dsp %s are now removed.\n", + __func__, delay, + dsp->name); + r = dsp->rx_R; + rr = (r + delay - (dsp_poll >> 1)) + & CMX_BUFF_MASK; + /* delete rx-data */ + while (r != rr) { + p[r] = dsp_silence; + r = (r + 1) & CMX_BUFF_MASK; + } + /* increment rx-buffer pointer */ + dsp->rx_R = r; + /* write incremented read pointer */ + } + /* find the lowest of all tx_delays */ + delay = dsp->tx_delay[0]; + i = 1; + while (i < MAX_SECONDS_JITTER_CHECK) { + if (delay > dsp->tx_delay[i]) + delay = dsp->tx_delay[i]; + i++; + } + /* + * remove delay only if we have delay AND we + * have enabled tx_dejitter + */ + if (delay > dsp_poll && dsp->tx_dejitter) { + if (dsp_debug & DEBUG_DSP_CLOCK) + printk(KERN_DEBUG + "%s lowest tx_delay of %d bytes for" + " dsp %s are now removed.\n", + __func__, delay, + dsp->name); + r = dsp->tx_R; + rr = (r + delay - (dsp_poll >> 1)) + & CMX_BUFF_MASK; + /* delete tx-data */ + while (r != rr) { + q[r] = dsp_silence; + r = (r + 1) & CMX_BUFF_MASK; + } + /* increment rx-buffer pointer */ + dsp->tx_R = r; + /* write incremented read pointer */ + } + /* scroll up delays */ + i = MAX_SECONDS_JITTER_CHECK - 1; + while (i) { + dsp->rx_delay[i] = dsp->rx_delay[i - 1]; + dsp->tx_delay[i] = dsp->tx_delay[i - 1]; + i--; + } + dsp->tx_delay[0] = CMX_BUFF_HALF; /* (infinite) delay */ + dsp->rx_delay[0] = CMX_BUFF_HALF; /* (infinite) delay */ } - dsp->tx_delay[0] = CMX_BUFF_HALF; /* (infinite) delay */ - dsp->rx_delay[0] = CMX_BUFF_HALF; /* (infinite) delay */ } - } - /* if next event would be in the past ... */ - if ((s32)(dsp_spl_jiffies+dsp_tics-jiffies) <= 0) - dsp_spl_jiffies = jiffies + 1; - else - dsp_spl_jiffies += dsp_tics; + /* if next event would be in the past ... */ + if ((s32)(dsp_spl_jiffies + dsp_tics-jiffies) <= 0) + dsp_spl_jiffies = jiffies + 1; + else + dsp_spl_jiffies += dsp_tics; - dsp_spl_tl.expires = dsp_spl_jiffies; - add_timer(&dsp_spl_tl); + dsp_spl_tl.expires = dsp_spl_jiffies; + add_timer(&dsp_spl_tl); - /* unlock */ - spin_unlock_irqrestore(&dsp_lock, flags); -} + /* unlock */ + spin_unlock_irqrestore(&dsp_lock, flags); + } /* * audio data is transmitted from upper layer to the dsp */ -void -dsp_cmx_transmit(struct dsp *dsp, struct sk_buff *skb) -{ - u_int w, ww; - u8 *d, *p; - int space; /* todo: , l = skb->len; */ + void + dsp_cmx_transmit(struct dsp *dsp, struct sk_buff *skb) + { + u_int w, ww; + u8 *d, *p; + int space; /* todo: , l = skb->len; */ #ifdef CMX_TX_DEBUG - char debugbuf[256] = ""; + char debugbuf[256] = ""; #endif - /* check if there is enough space, and then copy */ - w = dsp->tx_W; - ww = dsp->tx_R; - p = dsp->tx_buff; - d = skb->data; - space = ww-w; - if (space <= 0) - space += CMX_BUFF_SIZE; - /* write-pointer should not overrun nor reach read pointer */ - if (space-1 < skb->len) - /* write to the space we have left */ - ww = (ww - 1) & CMX_BUFF_MASK; - else - /* write until all byte are copied */ - ww = (w + skb->len) & CMX_BUFF_MASK; - dsp->tx_W = ww; - - /* show current buffer */ + /* check if there is enough space, and then copy */ + w = dsp->tx_W; + ww = dsp->tx_R; + p = dsp->tx_buff; + d = skb->data; + space = (ww - w - 1) & CMX_BUFF_MASK; + /* write-pointer should not overrun nor reach read pointer */ + if (space < skb->len) { + /* write to the space we have left */ + ww = (ww - 1) & CMX_BUFF_MASK; /* end one byte prior tx_R */ + if (dsp_debug & DEBUG_DSP_CLOCK) + printk(KERN_DEBUG "%s: TX overflow space=%d skb->len=" + "%d, w=0x%04x, ww=0x%04x\n", __func__, space, + skb->len, w, ww); + } else + /* write until all byte are copied */ + ww = (w + skb->len) & CMX_BUFF_MASK; + dsp->tx_W = ww; + + /* show current buffer */ #ifdef CMX_DEBUG - printk(KERN_DEBUG - "cmx_transmit(dsp=%lx) %d bytes to 0x%x-0x%x. %s\n", - (u_long)dsp, (ww-w)&CMX_BUFF_MASK, w, ww, dsp->name); + printk(KERN_DEBUG + "cmx_transmit(dsp=%lx) %d bytes to 0x%x-0x%x. %s\n", + (u_long)dsp, (ww - w) & CMX_BUFF_MASK, w, ww, dsp->name); #endif - /* copy transmit data to tx-buffer */ + /* copy transmit data to tx-buffer */ #ifdef CMX_TX_DEBUG - sprintf(debugbuf, "TX getting (%04x-%04x)%p: ", w, ww, p); + sprintf(debugbuf, "TX getting (%04x-%04x)%p: ", w, ww, p); #endif - while (w != ww) { + while (w != ww) { #ifdef CMX_TX_DEBUG - if (strlen(debugbuf) < 48) - sprintf(debugbuf+strlen(debugbuf), " %02x", *d); + if (strlen(debugbuf) < 48) + sprintf(debugbuf + strlen(debugbuf), " %02x", *d); #endif - p[w] = *d++; - w = (w+1) & CMX_BUFF_MASK; - } + p[w] = *d++; + w = (w + 1) & CMX_BUFF_MASK; + } #ifdef CMX_TX_DEBUG - printk(KERN_DEBUG "%s\n", debugbuf); + printk(KERN_DEBUG "%s\n", debugbuf); #endif -} + } /* * hdlc data is received from card and sent to all members. */ -void -dsp_cmx_hdlc(struct dsp *dsp, struct sk_buff *skb) -{ - struct sk_buff *nskb = NULL; - struct dsp_conf_member *member; - struct mISDNhead *hh; - - /* not if not active */ - if (!dsp->b_active) - return; - - /* check if we have sompen */ - if (skb->len < 1) - return; + void + dsp_cmx_hdlc(struct dsp *dsp, struct sk_buff *skb) + { + struct sk_buff *nskb = NULL; + struct dsp_conf_member *member; + struct mISDNhead *hh; + + /* not if not active */ + if (!dsp->b_active) + return; - /* no conf */ - if (!dsp->conf) { - /* in case of hardware (echo) */ - if (dsp->pcm_slot_tx >= 0) + /* check if we have sompen */ + if (skb->len < 1) return; - if (dsp->echo) - nskb = skb_clone(skb, GFP_ATOMIC); - if (nskb) { - hh = mISDN_HEAD_P(nskb); - hh->prim = PH_DATA_REQ; - hh->id = 0; - skb_queue_tail(&dsp->sendq, nskb); - schedule_work(&dsp->workq); + + /* no conf */ + if (!dsp->conf) { + /* in case of software echo */ + if (dsp->echo.software) { + nskb = skb_clone(skb, GFP_ATOMIC); + if (nskb) { + hh = mISDN_HEAD_P(nskb); + hh->prim = PH_DATA_REQ; + hh->id = 0; + skb_queue_tail(&dsp->sendq, nskb); + schedule_work(&dsp->workq); + } } - return; - } - /* in case of hardware conference */ - if (dsp->conf->hardware) - return; - list_for_each_entry(member, &dsp->conf->mlist, list) { - if (dsp->echo || member->dsp != dsp) { - nskb = skb_clone(skb, GFP_ATOMIC); - if (nskb) { - hh = mISDN_HEAD_P(nskb); - hh->prim = PH_DATA_REQ; - hh->id = 0; - skb_queue_tail(&member->dsp->sendq, nskb); - schedule_work(&member->dsp->workq); + return; + } + /* in case of hardware conference */ + if (dsp->conf->hardware) + return; + list_for_each_entry(member, &dsp->conf->mlist, list) { + if (dsp->echo.software || member->dsp != dsp) { + nskb = skb_clone(skb, GFP_ATOMIC); + if (nskb) { + hh = mISDN_HEAD_P(nskb); + hh->prim = PH_DATA_REQ; + hh->id = 0; + skb_queue_tail(&member->dsp->sendq, nskb); + schedule_work(&member->dsp->workq); + } } } } -} - - diff --git a/drivers/isdn/mISDN/dsp_core.c b/drivers/isdn/mISDN/dsp_core.c index 2f10ed82c0d..77025f5cb57 100644 --- a/drivers/isdn/mISDN/dsp_core.c +++ b/drivers/isdn/mISDN/dsp_core.c @@ -110,12 +110,12 @@ * crossconnections and conferences via software if not possible through * hardware. If hardware capability is available, hardware is used. * - * Echo: Is generated by CMX and is used to check performane of hard and + * Echo: Is generated by CMX and is used to check performance of hard and * software CMX. * * The CMX has special functions for conferences with one, two and more * members. It will allow different types of data flow. Receive and transmit - * data to/form upper layer may be swithed on/off individually without loosing + * data to/form upper layer may be swithed on/off individually without losing * features of CMX, Tones and DTMF. * * Echo Cancellation: Sometimes we like to cancel echo from the interface. @@ -127,9 +127,9 @@ * * If all used features can be realized in hardware, and if transmit and/or * receive data ist disabled, the card may not send/receive any data at all. - * Not receiving is usefull if only announcements are played. Not sending is - * usefull if an answering machine records audio. Not sending and receiving is - * usefull during most states of the call. If supported by hardware, tones + * Not receiving is useful if only announcements are played. Not sending is + * useful if an answering machine records audio. Not sending and receiving is + * useful during most states of the call. If supported by hardware, tones * will be played without cpu load. Small PBXs and NT-Mode applications will * not need expensive hardware when processing calls. * @@ -154,6 +154,7 @@ */ #include <linux/delay.h> +#include <linux/gfp.h> #include <linux/mISDNif.h> #include <linux/mISDNdsp.h> #include <linux/module.h> @@ -161,7 +162,7 @@ #include "core.h" #include "dsp.h" -const char *mISDN_dsp_revision = "2.0"; +static const char *mISDN_dsp_revision = "2.0"; static int debug; static int options; @@ -191,6 +192,8 @@ dsp_rx_off_member(struct dsp *dsp) struct mISDN_ctrl_req cq; int rx_off = 1; + memset(&cq, 0, sizeof(cq)); + if (!dsp->features_rx_off) return; @@ -201,13 +204,13 @@ dsp_rx_off_member(struct dsp *dsp) else if (dsp->dtmf.software) rx_off = 0; /* echo in software */ - else if (dsp->echo && dsp->pcm_slot_tx < 0) + else if (dsp->echo.software) rx_off = 0; /* bridge in software */ - else if (dsp->conf) { - if (dsp->conf->software) - rx_off = 0; - } + else if (dsp->conf && dsp->conf->software) + rx_off = 0; + /* data is not required by user space and not required + * for echo dtmf detection, soft-echo, soft-bridging */ if (rx_off == dsp->rx_is_off) return; @@ -215,20 +218,20 @@ dsp_rx_off_member(struct dsp *dsp) if (!dsp->ch.peer) { if (dsp_debug & DEBUG_DSP_CORE) printk(KERN_DEBUG "%s: no peer, no rx_off\n", - __func__); + __func__); return; } cq.op = MISDN_CTRL_RX_OFF; cq.p1 = rx_off; if (dsp->ch.peer->ctrl(dsp->ch.peer, CONTROL_CHANNEL, &cq)) { printk(KERN_DEBUG "%s: 2nd CONTROL_CHANNEL failed\n", - __func__); + __func__); return; } dsp->rx_is_off = rx_off; if (dsp_debug & DEBUG_DSP_CORE) printk(KERN_DEBUG "%s: %s set rx_off = %d\n", - __func__, dsp->name, rx_off); + __func__, dsp->name, rx_off); } static void dsp_rx_off(struct dsp *dsp) @@ -249,17 +252,46 @@ dsp_rx_off(struct dsp *dsp) } } +/* enable "fill empty" feature */ +static void +dsp_fill_empty(struct dsp *dsp) +{ + struct mISDN_ctrl_req cq; + + memset(&cq, 0, sizeof(cq)); + + if (!dsp->ch.peer) { + if (dsp_debug & DEBUG_DSP_CORE) + printk(KERN_DEBUG "%s: no peer, no fill_empty\n", + __func__); + return; + } + cq.op = MISDN_CTRL_FILL_EMPTY; + cq.p1 = 1; + cq.p2 = dsp_silence; + if (dsp->ch.peer->ctrl(dsp->ch.peer, CONTROL_CHANNEL, &cq)) { + printk(KERN_DEBUG "%s: CONTROL_CHANNEL failed\n", + __func__); + return; + } + if (dsp_debug & DEBUG_DSP_CORE) + printk(KERN_DEBUG "%s: %s set fill_empty = 1\n", + __func__, dsp->name); +} + static int dsp_control_req(struct dsp *dsp, struct mISDNhead *hh, struct sk_buff *skb) { - struct sk_buff *nskb; + struct sk_buff *nskb; int ret = 0; int cont; u8 *data; int len; - if (skb->len < sizeof(int)) + if (skb->len < sizeof(int)) { printk(KERN_ERR "%s: PH_CONTROL message too short\n", __func__); + return -EINVAL; + } cont = *((int *)skb->data); len = skb->len - sizeof(int); data = skb->data + sizeof(int); @@ -273,19 +305,23 @@ dsp_control_req(struct dsp *dsp, struct mISDNhead *hh, struct sk_buff *skb) if (dsp_debug & DEBUG_DSP_CORE) printk(KERN_DEBUG "%s: start dtmf\n", __func__); if (len == sizeof(int)) { - printk(KERN_NOTICE "changing DTMF Threshold " - "to %d\n", *((int *)data)); + if (dsp_debug & DEBUG_DSP_CORE) + printk(KERN_NOTICE "changing DTMF Threshold " + "to %d\n", *((int *)data)); dsp->dtmf.treshold = (*(int *)data) * 10000; } + dsp->dtmf.enable = 1; /* init goertzel */ dsp_dtmf_goertzel_init(dsp); /* check dtmf hardware */ dsp_dtmf_hardware(dsp); + dsp_rx_off(dsp); break; case DTMF_TONE_STOP: /* turn off DTMF */ if (dsp_debug & DEBUG_DSP_CORE) printk(KERN_DEBUG "%s: stop dtmf\n", __func__); + dsp->dtmf.enable = 0; dsp->dtmf.hardware = 0; dsp->dtmf.software = 0; break; @@ -298,19 +334,19 @@ dsp_control_req(struct dsp *dsp, struct mISDNhead *hh, struct sk_buff *skb) goto conf_split; if (dsp_debug & DEBUG_DSP_CORE) printk(KERN_DEBUG "%s: join conference %d\n", - __func__, *((u32 *)data)); + __func__, *((u32 *)data)); ret = dsp_cmx_conf(dsp, *((u32 *)data)); - /* dsp_cmx_hardware will also be called here */ + /* dsp_cmx_hardware will also be called here */ dsp_rx_off(dsp); if (dsp_debug & DEBUG_DSP_CMX) dsp_cmx_debug(dsp); break; case DSP_CONF_SPLIT: /* remove from conference */ -conf_split: + conf_split: if (dsp_debug & DEBUG_DSP_CORE) printk(KERN_DEBUG "%s: release conference\n", __func__); ret = dsp_cmx_conf(dsp, 0); - /* dsp_cmx_hardware will also be called here */ + /* dsp_cmx_hardware will also be called here */ if (dsp_debug & DEBUG_DSP_CMX) dsp_cmx_debug(dsp); dsp_rx_off(dsp); @@ -326,7 +362,7 @@ conf_split: } if (dsp_debug & DEBUG_DSP_CORE) printk(KERN_DEBUG "%s: turn tone 0x%x on\n", - __func__, *((int *)skb->data)); + __func__, *((int *)skb->data)); ret = dsp_tone(dsp, *((int *)data)); if (!ret) { dsp_cmx_hardware(dsp->conf, dsp); @@ -346,7 +382,7 @@ conf_split: dsp_cmx_hardware(dsp->conf, dsp); dsp_rx_off(dsp); /* reset tx buffers (user space data) */ -tone_off: + tone_off: dsp->rx_W = 0; dsp->rx_R = 0; break; @@ -362,7 +398,7 @@ tone_off: dsp->tx_volume = *((int *)data); if (dsp_debug & DEBUG_DSP_CORE) printk(KERN_DEBUG "%s: change tx vol to %d\n", - __func__, dsp->tx_volume); + __func__, dsp->tx_volume); dsp_cmx_hardware(dsp->conf, dsp); dsp_dtmf_hardware(dsp); dsp_rx_off(dsp); @@ -379,13 +415,13 @@ tone_off: dsp->rx_volume = *((int *)data); if (dsp_debug & DEBUG_DSP_CORE) printk(KERN_DEBUG "%s: change rx vol to %d\n", - __func__, dsp->tx_volume); + __func__, dsp->tx_volume); dsp_cmx_hardware(dsp->conf, dsp); dsp_dtmf_hardware(dsp); dsp_rx_off(dsp); break; case DSP_ECHO_ON: /* enable echo */ - dsp->echo = 1; /* soft echo */ + dsp->echo.software = 1; /* soft echo */ if (dsp_debug & DEBUG_DSP_CORE) printk(KERN_DEBUG "%s: enable cmx-echo\n", __func__); dsp_cmx_hardware(dsp->conf, dsp); @@ -394,7 +430,8 @@ tone_off: dsp_cmx_debug(dsp); break; case DSP_ECHO_OFF: /* disable echo */ - dsp->echo = 0; + dsp->echo.software = 0; + dsp->echo.hardware = 0; if (dsp_debug & DEBUG_DSP_CORE) printk(KERN_DEBUG "%s: disable cmx-echo\n", __func__); dsp_cmx_hardware(dsp->conf, dsp); @@ -405,14 +442,14 @@ tone_off: case DSP_RECEIVE_ON: /* enable receive to user space */ if (dsp_debug & DEBUG_DSP_CORE) printk(KERN_DEBUG "%s: enable receive to user " - "space\n", __func__); + "space\n", __func__); dsp->rx_disabled = 0; dsp_rx_off(dsp); break; case DSP_RECEIVE_OFF: /* disable receive to user space */ if (dsp_debug & DEBUG_DSP_CORE) printk(KERN_DEBUG "%s: disable receive to " - "user space\n", __func__); + "user space\n", __func__); dsp->rx_disabled = 1; dsp_rx_off(dsp); break; @@ -423,7 +460,7 @@ tone_off: } if (dsp_debug & DEBUG_DSP_CORE) printk(KERN_DEBUG "%s: enable mixing of " - "tx-data with conf mebers\n", __func__); + "tx-data with conf mebers\n", __func__); dsp->tx_mix = 1; dsp_cmx_hardware(dsp->conf, dsp); dsp_rx_off(dsp); @@ -437,7 +474,7 @@ tone_off: } if (dsp_debug & DEBUG_DSP_CORE) printk(KERN_DEBUG "%s: disable mixing of " - "tx-data with conf mebers\n", __func__); + "tx-data with conf mebers\n", __func__); dsp->tx_mix = 0; dsp_cmx_hardware(dsp->conf, dsp); dsp_rx_off(dsp); @@ -473,18 +510,18 @@ tone_off: break; } dsp->cmx_delay = (*((int *)data)) << 3; - /* miliseconds to samples */ - if (dsp->cmx_delay >= (CMX_BUFF_HALF>>1)) + /* milliseconds to samples */ + if (dsp->cmx_delay >= (CMX_BUFF_HALF >> 1)) /* clip to half of maximum usable buffer - (half of half buffer) */ - dsp->cmx_delay = (CMX_BUFF_HALF>>1) - 1; + (half of half buffer) */ + dsp->cmx_delay = (CMX_BUFF_HALF >> 1) - 1; if (dsp_debug & DEBUG_DSP_CORE) printk(KERN_DEBUG "%s: use delay algorithm to " - "compensate jitter (%d samples)\n", - __func__, dsp->cmx_delay); + "compensate jitter (%d samples)\n", + __func__, dsp->cmx_delay); break; case DSP_JITTER: /* use dynamic jitter algorithm instead of - delay algorithm */ + delay algorithm */ if (dsp->hdlc) { ret = -EINVAL; break; @@ -492,7 +529,7 @@ tone_off: dsp->cmx_delay = 0; if (dsp_debug & DEBUG_DSP_CORE) printk(KERN_DEBUG "%s: use jitter algorithm to " - "compensate jitter\n", __func__); + "compensate jitter\n", __func__); break; case DSP_TX_DEJITTER: /* use dynamic jitter algorithm for tx-buffer */ if (dsp->hdlc) { @@ -502,7 +539,7 @@ tone_off: dsp->tx_dejitter = 1; if (dsp_debug & DEBUG_DSP_CORE) printk(KERN_DEBUG "%s: use dejitter on TX " - "buffer\n", __func__); + "buffer\n", __func__); break; case DSP_TX_DEJ_OFF: /* use tx-buffer without dejittering*/ if (dsp->hdlc) { @@ -512,7 +549,7 @@ tone_off: dsp->tx_dejitter = 0; if (dsp_debug & DEBUG_DSP_CORE) printk(KERN_DEBUG "%s: use TX buffer without " - "dejittering\n", __func__); + "dejittering\n", __func__); break; case DSP_PIPELINE_CFG: if (dsp->hdlc) { @@ -521,13 +558,13 @@ tone_off: } if (len > 0 && ((char *)data)[len - 1]) { printk(KERN_DEBUG "%s: pipeline config string " - "is not NULL terminated!\n", __func__); + "is not NULL terminated!\n", __func__); ret = -EINVAL; } else { dsp->pipeline.inuse = 1; dsp_cmx_hardware(dsp->conf, dsp); ret = dsp_pipeline_build(&dsp->pipeline, - len > 0 ? (char *)data : NULL); + len > 0 ? data : NULL); dsp_cmx_hardware(dsp->conf, dsp); dsp_rx_off(dsp); } @@ -543,7 +580,7 @@ tone_off: } if (dsp_debug & DEBUG_DSP_CORE) printk(KERN_DEBUG "%s: turn blowfish on (key " - "not shown)\n", __func__); + "not shown)\n", __func__); ret = dsp_bf_init(dsp, (u8 *)data, len); /* set new cont */ if (!ret) @@ -552,7 +589,7 @@ tone_off: cont = DSP_BF_REJECT; /* send indication if it worked to set it */ nskb = _alloc_mISDN_skb(PH_CONTROL_IND, MISDN_ID_ANY, - sizeof(int), &cont, GFP_ATOMIC); + sizeof(int), &cont, GFP_ATOMIC); if (nskb) { if (dsp->up) { if (dsp->up->send(dsp->up, nskb)) @@ -581,7 +618,7 @@ tone_off: default: if (dsp_debug & DEBUG_DSP_CORE) printk(KERN_DEBUG "%s: ctrl req %x unhandled\n", - __func__, cont); + __func__, cont); ret = -EINVAL; } return ret; @@ -593,50 +630,50 @@ get_features(struct mISDNchannel *ch) struct dsp *dsp = container_of(ch, struct dsp, ch); struct mISDN_ctrl_req cq; - if (dsp_options & DSP_OPT_NOHARDWARE) - return; if (!ch->peer) { if (dsp_debug & DEBUG_DSP_CORE) printk(KERN_DEBUG "%s: no peer, no features\n", - __func__); + __func__); return; } memset(&cq, 0, sizeof(cq)); cq.op = MISDN_CTRL_GETOP; if (ch->peer->ctrl(ch->peer, CONTROL_CHANNEL, &cq) < 0) { printk(KERN_DEBUG "%s: CONTROL_CHANNEL failed\n", - __func__); + __func__); return; } if (cq.op & MISDN_CTRL_RX_OFF) dsp->features_rx_off = 1; + if (cq.op & MISDN_CTRL_FILL_EMPTY) + dsp->features_fill_empty = 1; + if (dsp_options & DSP_OPT_NOHARDWARE) + return; if ((cq.op & MISDN_CTRL_HW_FEATURES_OP)) { cq.op = MISDN_CTRL_HW_FEATURES; *((u_long *)&cq.p1) = (u_long)&dsp->features; if (ch->peer->ctrl(ch->peer, CONTROL_CHANNEL, &cq)) { printk(KERN_DEBUG "%s: 2nd CONTROL_CHANNEL failed\n", - __func__); + __func__); } } else if (dsp_debug & DEBUG_DSP_CORE) printk(KERN_DEBUG "%s: features not supported for %s\n", - __func__, dsp->name); + __func__, dsp->name); } static int dsp_function(struct mISDNchannel *ch, struct sk_buff *skb) { - struct dsp *dsp = container_of(ch, struct dsp, ch); + struct dsp *dsp = container_of(ch, struct dsp, ch); struct mISDNhead *hh; int ret = 0; - u8 *digits; - int cont; - struct sk_buff *nskb; + u8 *digits = NULL; u_long flags; hh = mISDN_HEAD_P(skb); switch (hh->prim) { - /* FROM DOWN */ + /* FROM DOWN */ case (PH_DATA_CNF): dsp->data_pending = 0; /* trigger next hdlc frame, if any */ @@ -656,8 +693,8 @@ dsp_function(struct mISDNchannel *ch, struct sk_buff *skb) if (dsp->rx_is_off) { if (dsp_debug & DEBUG_DSP_CORE) printk(KERN_DEBUG "%s: rx-data during rx_off" - " for %s\n", - __func__, dsp->name); + " for %s\n", + __func__, dsp->name); } if (dsp->hdlc) { /* hdlc */ @@ -674,49 +711,55 @@ dsp_function(struct mISDNchannel *ch, struct sk_buff *skb) break; } + spin_lock_irqsave(&dsp_lock, flags); + /* decrypt if enabled */ if (dsp->bf_enable) dsp_bf_decrypt(dsp, skb->data, skb->len); /* pipeline */ if (dsp->pipeline.inuse) dsp_pipeline_process_rx(&dsp->pipeline, skb->data, - skb->len); + skb->len, hh->id); /* change volume if requested */ if (dsp->rx_volume) dsp_change_volume(skb, dsp->rx_volume); - /* check if dtmf soft decoding is turned on */ if (dsp->dtmf.software) { digits = dsp_dtmf_goertzel_decode(dsp, skb->data, - skb->len, (dsp_options&DSP_OPT_ULAW)?1:0); + skb->len, (dsp_options & DSP_OPT_ULAW) ? 1 : 0); + } + /* we need to process receive data if software */ + if (dsp->conf && dsp->conf->software) { + /* process data from card at cmx */ + dsp_cmx_receive(dsp, skb); + } + + spin_unlock_irqrestore(&dsp_lock, flags); + + /* send dtmf result, if any */ + if (digits) { while (*digits) { + int k; + struct sk_buff *nskb; if (dsp_debug & DEBUG_DSP_DTMF) printk(KERN_DEBUG "%s: digit" - "(%c) to layer %s\n", - __func__, *digits, dsp->name); - cont = DTMF_TONE_VAL | *digits; + "(%c) to layer %s\n", + __func__, *digits, dsp->name); + k = *digits | DTMF_TONE_VAL; nskb = _alloc_mISDN_skb(PH_CONTROL_IND, - MISDN_ID_ANY, sizeof(int), &cont, - GFP_ATOMIC); + MISDN_ID_ANY, sizeof(int), &k, + GFP_ATOMIC); if (nskb) { if (dsp->up) { if (dsp->up->send( - dsp->up, nskb)) - dev_kfree_skb(nskb); + dsp->up, nskb)) + dev_kfree_skb(nskb); } else dev_kfree_skb(nskb); } digits++; } } - /* we need to process receive data if software */ - spin_lock_irqsave(&dsp_lock, flags); - if (dsp->pcm_slot_tx < 0 && dsp->pcm_slot_rx < 0) { - /* process data from card at cmx */ - dsp_cmx_receive(dsp, skb); - } - spin_unlock_irqrestore(&dsp_lock, flags); - if (dsp->rx_disabled) { /* if receive is not allowed */ break; @@ -728,35 +771,35 @@ dsp_function(struct mISDNchannel *ch, struct sk_buff *skb) case (PH_CONTROL_IND): if (dsp_debug & DEBUG_DSP_DTMFCOEFF) printk(KERN_DEBUG "%s: PH_CONTROL INDICATION " - "received: %x (len %d) %s\n", __func__, - hh->id, skb->len, dsp->name); + "received: %x (len %d) %s\n", __func__, + hh->id, skb->len, dsp->name); switch (hh->id) { case (DTMF_HFC_COEF): /* getting coefficients */ if (!dsp->dtmf.hardware) { if (dsp_debug & DEBUG_DSP_DTMFCOEFF) printk(KERN_DEBUG "%s: ignoring DTMF " - "coefficients from HFC\n", - __func__); + "coefficients from HFC\n", + __func__); break; } digits = dsp_dtmf_goertzel_decode(dsp, skb->data, - skb->len, 2); + skb->len, 2); while (*digits) { int k; struct sk_buff *nskb; if (dsp_debug & DEBUG_DSP_DTMF) printk(KERN_DEBUG "%s: digit" - "(%c) to layer %s\n", - __func__, *digits, dsp->name); + "(%c) to layer %s\n", + __func__, *digits, dsp->name); k = *digits | DTMF_TONE_VAL; nskb = _alloc_mISDN_skb(PH_CONTROL_IND, - MISDN_ID_ANY, sizeof(int), &k, - GFP_ATOMIC); + MISDN_ID_ANY, sizeof(int), &k, + GFP_ATOMIC); if (nskb) { if (dsp->up) { if (dsp->up->send( - dsp->up, nskb)) - dev_kfree_skb(nskb); + dsp->up, nskb)) + dev_kfree_skb(nskb); } else dev_kfree_skb(nskb); } @@ -772,7 +815,7 @@ dsp_function(struct mISDNchannel *ch, struct sk_buff *skb) dsp->tx_volume = *((int *)skb->data); if (dsp_debug & DEBUG_DSP_CORE) printk(KERN_DEBUG "%s: change tx volume to " - "%d\n", __func__, dsp->tx_volume); + "%d\n", __func__, dsp->tx_volume); dsp_cmx_hardware(dsp->conf, dsp); dsp_dtmf_hardware(dsp); dsp_rx_off(dsp); @@ -781,7 +824,7 @@ dsp_function(struct mISDNchannel *ch, struct sk_buff *skb) default: if (dsp_debug & DEBUG_DSP_CORE) printk(KERN_DEBUG "%s: ctrl ind %x unhandled " - "%s\n", __func__, hh->id, dsp->name); + "%s\n", __func__, hh->id, dsp->name); ret = -EINVAL; } break; @@ -789,13 +832,13 @@ dsp_function(struct mISDNchannel *ch, struct sk_buff *skb) case (PH_ACTIVATE_CNF): if (dsp_debug & DEBUG_DSP_CORE) printk(KERN_DEBUG "%s: b_channel is now active %s\n", - __func__, dsp->name); + __func__, dsp->name); /* bchannel now active */ spin_lock_irqsave(&dsp_lock, flags); dsp->b_active = 1; dsp->data_pending = 0; dsp->rx_init = 1; - /* rx_W and rx_R will be adjusted on first frame */ + /* rx_W and rx_R will be adjusted on first frame */ dsp->rx_W = 0; dsp->rx_R = 0; memset(dsp->rx_buff, 0, sizeof(dsp->rx_buff)); @@ -805,8 +848,8 @@ dsp_function(struct mISDNchannel *ch, struct sk_buff *skb) spin_unlock_irqrestore(&dsp_lock, flags); if (dsp_debug & DEBUG_DSP_CORE) printk(KERN_DEBUG "%s: done with activation, sending " - "confirm to user space. %s\n", __func__, - dsp->name); + "confirm to user space. %s\n", __func__, + dsp->name); /* send activation to upper layer */ hh->prim = DL_ESTABLISH_CNF; if (dsp->up) @@ -816,7 +859,7 @@ dsp_function(struct mISDNchannel *ch, struct sk_buff *skb) case (PH_DEACTIVATE_CNF): if (dsp_debug & DEBUG_DSP_CORE) printk(KERN_DEBUG "%s: b_channel is now inactive %s\n", - __func__, dsp->name); + __func__, dsp->name); /* bchannel now inactive */ spin_lock_irqsave(&dsp_lock, flags); dsp->b_active = 0; @@ -828,7 +871,7 @@ dsp_function(struct mISDNchannel *ch, struct sk_buff *skb) if (dsp->up) return dsp->up->send(dsp->up, skb); break; - /* FROM UP */ + /* FROM UP */ case (DL_DATA_REQ): case (PH_DATA_REQ): if (skb->len < 1) { @@ -837,11 +880,14 @@ dsp_function(struct mISDNchannel *ch, struct sk_buff *skb) } if (dsp->hdlc) { /* hdlc */ - spin_lock_irqsave(&dsp_lock, flags); - if (dsp->b_active) { - skb_queue_tail(&dsp->sendq, skb); - schedule_work(&dsp->workq); + if (!dsp->b_active) { + ret = -EIO; + break; } + hh->prim = PH_DATA_REQ; + spin_lock_irqsave(&dsp_lock, flags); + skb_queue_tail(&dsp->sendq, skb); + schedule_work(&dsp->workq); spin_unlock_irqrestore(&dsp_lock, flags); return 0; } @@ -861,10 +907,13 @@ dsp_function(struct mISDNchannel *ch, struct sk_buff *skb) case (PH_ACTIVATE_REQ): if (dsp_debug & DEBUG_DSP_CORE) printk(KERN_DEBUG "%s: activating b_channel %s\n", - __func__, dsp->name); + __func__, dsp->name); if (dsp->dtmf.hardware || dsp->dtmf.software) dsp_dtmf_goertzel_init(dsp); get_features(ch); + /* enable fill_empty feature */ + if (dsp->features_fill_empty) + dsp_fill_empty(dsp); /* send ph_activate */ hh->prim = PH_ACTIVATE_REQ; if (ch->peer) @@ -874,7 +923,7 @@ dsp_function(struct mISDNchannel *ch, struct sk_buff *skb) case (PH_DEACTIVATE_REQ): if (dsp_debug & DEBUG_DSP_CORE) printk(KERN_DEBUG "%s: releasing b_channel %s\n", - __func__, dsp->name); + __func__, dsp->name); spin_lock_irqsave(&dsp_lock, flags); dsp->tone.tone = 0; dsp->tone.hardware = 0; @@ -893,7 +942,7 @@ dsp_function(struct mISDNchannel *ch, struct sk_buff *skb) default: if (dsp_debug & DEBUG_DSP_CORE) printk(KERN_DEBUG "%s: msg %x unhandled %s\n", - __func__, hh->prim, dsp->name); + __func__, hh->prim, dsp->name); ret = -EINVAL; } if (!ret) @@ -909,7 +958,7 @@ dsp_ctrl(struct mISDNchannel *ch, u_int cmd, void *arg) int err = 0; if (debug & DEBUG_DSP_CTRL) - printk(KERN_DEBUG "%s:(%x)\n", __func__, cmd); + printk(KERN_DEBUG "%s:(%x)\n", __func__, cmd); switch (cmd) { case OPEN_CHANNEL: @@ -932,7 +981,7 @@ dsp_ctrl(struct mISDNchannel *ch, u_int cmd, void *arg) skb_queue_purge(&dsp->sendq); if (dsp_debug & DEBUG_DSP_CTRL) printk(KERN_DEBUG "%s: releasing member %s\n", - __func__, dsp->name); + __func__, dsp->name); dsp->b_active = 0; dsp_cmx_conf(dsp, 0); /* dsp_cmx_hardware will also be called here */ @@ -940,13 +989,13 @@ dsp_ctrl(struct mISDNchannel *ch, u_int cmd, void *arg) if (dsp_debug & DEBUG_DSP_CTRL) printk(KERN_DEBUG "%s: remove & destroy object %s\n", - __func__, dsp->name); + __func__, dsp->name); list_del(&dsp->list); spin_unlock_irqrestore(&dsp_lock, flags); if (dsp_debug & DEBUG_DSP_CTRL) printk(KERN_DEBUG "%s: dsp instance released\n", - __func__); + __func__); vfree(dsp); module_put(THIS_MODULE); break; @@ -970,7 +1019,7 @@ dsp_send_bh(struct work_struct *work) if (dsp->data_pending) { if (dsp_debug & DEBUG_DSP_CORE) printk(KERN_DEBUG "%s: fifo full %s, this is " - "no bug!\n", __func__, dsp->name); + "no bug!\n", __func__, dsp->name); /* flush transparent data, if not acked */ dev_kfree_skb(skb); continue; @@ -1004,14 +1053,13 @@ dspcreate(struct channel_req *crq) u_long flags; if (crq->protocol != ISDN_P_B_L2DSP - && crq->protocol != ISDN_P_B_L2DSPHDLC) + && crq->protocol != ISDN_P_B_L2DSPHDLC) return -EPROTONOSUPPORT; - ndsp = vmalloc(sizeof(struct dsp)); + ndsp = vzalloc(sizeof(struct dsp)); if (!ndsp) { printk(KERN_ERR "%s: vmalloc struct dsp failed\n", __func__); return -ENOMEM; } - memset(ndsp, 0, sizeof(struct dsp)); if (dsp_debug & DEBUG_DSP_CTRL) printk(KERN_DEBUG "%s: creating new dsp instance\n", __func__); @@ -1031,7 +1079,7 @@ dspcreate(struct channel_req *crq) } if (!try_module_get(THIS_MODULE)) printk(KERN_WARNING "%s:cannot get module\n", - __func__); + __func__); sprintf(ndsp->name, "DSP_C%x(0x%p)", ndsp->up->st->dev->id + 1, ndsp); @@ -1050,7 +1098,7 @@ dspcreate(struct channel_req *crq) if (dtmfthreshold < 20 || dtmfthreshold > 500) dtmfthreshold = 200; - ndsp->dtmf.treshold = dtmfthreshold*10000; + ndsp->dtmf.treshold = dtmfthreshold * 10000; /* init pipeline append to list */ spin_lock_irqsave(&dsp_lock, flags); @@ -1064,17 +1112,17 @@ dspcreate(struct channel_req *crq) static struct Bprotocol DSP = { .Bprotocols = (1 << (ISDN_P_B_L2DSP & ISDN_P_B_MASK)) - | (1 << (ISDN_P_B_L2DSPHDLC & ISDN_P_B_MASK)), + | (1 << (ISDN_P_B_L2DSPHDLC & ISDN_P_B_MASK)), .name = "dsp", .create = dspcreate }; -static int dsp_init(void) +static int __init dsp_init(void) { int err; int tics; - printk(KERN_INFO "DSP modul %s\n", mISDN_dsp_revision); + printk(KERN_INFO "DSP module %s\n", mISDN_dsp_revision); dsp_options = options; dsp_debug = debug; @@ -1084,28 +1132,28 @@ static int dsp_init(void) if (dsp_poll) { if (dsp_poll > MAX_POLL) { printk(KERN_ERR "%s: Wrong poll value (%d), use %d " - "maximum.\n", __func__, poll, MAX_POLL); + "maximum.\n", __func__, poll, MAX_POLL); err = -EINVAL; return err; } if (dsp_poll < 8) { printk(KERN_ERR "%s: Wrong poll value (%d), use 8 " - "minimum.\n", __func__, dsp_poll); + "minimum.\n", __func__, dsp_poll); err = -EINVAL; return err; } dsp_tics = poll * HZ / 8000; if (dsp_tics * 8000 != poll * HZ) { printk(KERN_INFO "mISDN_dsp: Cannot clock every %d " - "samples (0,125 ms). It is not a multiple of " - "%d HZ.\n", poll, HZ); + "samples (0,125 ms). It is not a multiple of " + "%d HZ.\n", poll, HZ); err = -EINVAL; return err; } } else { poll = 8; while (poll <= MAX_POLL) { - tics = poll * HZ / 8000; + tics = (poll * HZ) / 8000; if (tics * 8000 == poll * HZ) { dsp_tics = tics; dsp_poll = poll; @@ -1117,14 +1165,14 @@ static int dsp_init(void) } if (dsp_poll == 0) { printk(KERN_INFO "mISDN_dsp: There is no multiple of kernel " - "clock that equals exactly the duration of 8-256 " - "samples. (Choose kernel clock speed like 100, 250, " - "300, 1000)\n"); + "clock that equals exactly the duration of 8-256 " + "samples. (Choose kernel clock speed like 100, 250, " + "300, 1000)\n"); err = -EINVAL; return err; } printk(KERN_INFO "mISDN_dsp: DSP clocks every %d samples. This equals " - "%d jiffies.\n", dsp_poll, dsp_tics); + "%d jiffies.\n", dsp_poll, dsp_tics); spin_lock_init(&dsp_lock); INIT_LIST_HEAD(&dsp_ilist); @@ -1132,9 +1180,9 @@ static int dsp_init(void) /* init conversion tables */ dsp_audio_generate_law_tables(); - dsp_silence = (dsp_options&DSP_OPT_ULAW)?0xff:0x2a; - dsp_audio_law_to_s32 = (dsp_options&DSP_OPT_ULAW)?dsp_audio_ulaw_to_s32: - dsp_audio_alaw_to_s32; + dsp_silence = (dsp_options & DSP_OPT_ULAW) ? 0xff : 0x2a; + dsp_audio_law_to_s32 = (dsp_options & DSP_OPT_ULAW) ? + dsp_audio_ulaw_to_s32 : dsp_audio_alaw_to_s32; dsp_audio_generate_s2law_table(); dsp_audio_generate_seven(); dsp_audio_generate_mix_table(); @@ -1145,7 +1193,7 @@ static int dsp_init(void) err = dsp_pipeline_module_init(); if (err) { printk(KERN_ERR "mISDN_dsp: Can't initialize pipeline, " - "error(%d)\n", err); + "error(%d)\n", err); return err; } @@ -1167,20 +1215,19 @@ static int dsp_init(void) } -static void dsp_cleanup(void) +static void __exit dsp_cleanup(void) { mISDN_unregister_Bprotocol(&DSP); - if (timer_pending(&dsp_spl_tl)) - del_timer(&dsp_spl_tl); + del_timer_sync(&dsp_spl_tl); if (!list_empty(&dsp_ilist)) { printk(KERN_ERR "mISDN_dsp: Audio DSP object inst list not " - "empty.\n"); + "empty.\n"); } if (!list_empty(&conf_ilist)) { printk(KERN_ERR "mISDN_dsp: Conference list not empty. Not " - "all memory freed.\n"); + "all memory freed.\n"); } dsp_pipeline_module_exit(); @@ -1188,4 +1235,3 @@ static void dsp_cleanup(void) module_init(dsp_init); module_exit(dsp_cleanup); - diff --git a/drivers/isdn/mISDN/dsp_dtmf.c b/drivers/isdn/mISDN/dsp_dtmf.c index efc371c1f0d..642f30be5ce 100644 --- a/drivers/isdn/mISDN/dsp_dtmf.c +++ b/drivers/isdn/mISDN/dsp_dtmf.c @@ -51,6 +51,9 @@ void dsp_dtmf_hardware(struct dsp *dsp) { int hardware = 1; + if (!dsp->dtmf.enable) + return; + if (!dsp->features.hfc_dtmf) hardware = 0; @@ -58,31 +61,31 @@ void dsp_dtmf_hardware(struct dsp *dsp) if (dsp->tx_volume) { if (dsp_debug & DEBUG_DSP_DTMF) printk(KERN_DEBUG "%s dsp %s cannot do hardware DTMF, " - "because tx_volume is changed\n", - __func__, dsp->name); + "because tx_volume is changed\n", + __func__, dsp->name); hardware = 0; } if (dsp->rx_volume) { if (dsp_debug & DEBUG_DSP_DTMF) printk(KERN_DEBUG "%s dsp %s cannot do hardware DTMF, " - "because rx_volume is changed\n", - __func__, dsp->name); + "because rx_volume is changed\n", + __func__, dsp->name); hardware = 0; } /* check if encryption is enabled */ if (dsp->bf_enable) { if (dsp_debug & DEBUG_DSP_DTMF) printk(KERN_DEBUG "%s dsp %s cannot do hardware DTMF, " - "because encryption is enabled\n", - __func__, dsp->name); + "because encryption is enabled\n", + __func__, dsp->name); hardware = 0; } /* check if pipeline exists */ if (dsp->pipeline.inuse) { if (dsp_debug & DEBUG_DSP_DTMF) printk(KERN_DEBUG "%s dsp %s cannot do hardware DTMF, " - "because pipeline exists.\n", - __func__, dsp->name); + "because pipeline exists.\n", + __func__, dsp->name); hardware = 0; } @@ -103,7 +106,7 @@ void dsp_dtmf_hardware(struct dsp *dsp) * tested it allot. it even works with very short tones (40ms). the only * disadvantage is, that it doesn't work good with different volumes of both * tones. this will happen, if accoustically coupled dialers are used. - * it sometimes detects tones during speach, which is normal for decoders. + * it sometimes detects tones during speech, which is normal for decoders. * use sequences to given commands during calls. * * dtmf - points to a structure of the current dtmf state @@ -147,23 +150,23 @@ again: if (len < 64) { if (len > 0) printk(KERN_ERR "%s: coefficients have invalid " - "size. (is=%d < must=%d)\n", - __func__, len, 64); + "size. (is=%d < must=%d)\n", + __func__, len, 64); return dsp->dtmf.digits; } hfccoeff = (s32 *)data; for (k = 0; k < NCOEFF; k++) { - sk2 = (*hfccoeff++)>>4; - sk = (*hfccoeff++)>>4; + sk2 = (*hfccoeff++) >> 4; + sk = (*hfccoeff++) >> 4; if (sk > 32767 || sk < -32767 || sk2 > 32767 || sk2 < -32767) printk(KERN_WARNING - "DTMF-Detection overflow\n"); + "DTMF-Detection overflow\n"); /* compute |X(k)|**2 */ result[k] = - (sk * sk) - - (((cos2pik[k] * sk) >> 15) * sk2) + - (sk2 * sk2); + (sk * sk) - + (((cos2pik[k] * sk) >> 15) * sk2) + + (sk2 * sk2); } data += 64; len -= 64; @@ -185,7 +188,7 @@ again: buf = dsp->dtmf.buffer; cos2pik_ = cos2pik[k]; for (n = 0; n < DSP_DTMF_NPOINTS; n++) { - sk = ((cos2pik_*sk1)>>15) - sk2 + (*buf++); + sk = ((cos2pik_ * sk1) >> 15) - sk2 + (*buf++); sk2 = sk1; sk1 = sk; } @@ -219,16 +222,25 @@ coefficients: goto storedigit; } - if (dsp_debug & DEBUG_DSP_DTMFCOEFF) + if (dsp_debug & DEBUG_DSP_DTMFCOEFF) { + s32 tresh_100 = tresh/100; + + if (tresh_100 == 0) { + tresh_100 = 1; + printk(KERN_DEBUG + "tresh(%d) too small set tresh/100 to 1\n", + tresh); + } printk(KERN_DEBUG "a %3d %3d %3d %3d %3d %3d %3d %3d" - " tr:%3d r %3d %3d %3d %3d %3d %3d %3d %3d\n", - result[0]/10000, result[1]/10000, result[2]/10000, - result[3]/10000, result[4]/10000, result[5]/10000, - result[6]/10000, result[7]/10000, tresh/10000, - result[0]/(tresh/100), result[1]/(tresh/100), - result[2]/(tresh/100), result[3]/(tresh/100), - result[4]/(tresh/100), result[5]/(tresh/100), - result[6]/(tresh/100), result[7]/(tresh/100)); + " tr:%3d r %3d %3d %3d %3d %3d %3d %3d %3d\n", + result[0] / 10000, result[1] / 10000, result[2] / 10000, + result[3] / 10000, result[4] / 10000, result[5] / 10000, + result[6] / 10000, result[7] / 10000, tresh / 10000, + result[0] / (tresh_100), result[1] / (tresh_100), + result[2] / (tresh_100), result[3] / (tresh_100), + result[4] / (tresh_100), result[5] / (tresh_100), + result[6] / (tresh_100), result[7] / (tresh_100)); + } /* calc digit (lowgroup/highgroup) */ lowgroup = -1; @@ -241,10 +253,10 @@ coefficients: if (result[i] < tresh) { lowgroup = -1; highgroup = -1; - break; /* noise inbetween */ + break; /* noise in between */ } /* good level found. This is allowed only one time per group */ - if (i < NCOEFF/2) { + if (i < NCOEFF / 2) { /* lowgroup */ if (lowgroup >= 0) { /* Bad. Another tone found. */ @@ -259,7 +271,7 @@ coefficients: highgroup = -1; break; } else - highgroup = i-(NCOEFF/2); + highgroup = i - (NCOEFF / 2); } } @@ -282,13 +294,13 @@ storedigit: if (what) { if (dsp_debug & DEBUG_DSP_DTMF) printk(KERN_DEBUG "DTMF digit: %c\n", - what); - if ((strlen(dsp->dtmf.digits)+1) - < sizeof(dsp->dtmf.digits)) { + what); + if ((strlen(dsp->dtmf.digits) + 1) + < sizeof(dsp->dtmf.digits)) { dsp->dtmf.digits[strlen( - dsp->dtmf.digits)+1] = '\0'; + dsp->dtmf.digits) + 1] = '\0'; dsp->dtmf.digits[strlen( - dsp->dtmf.digits)] = what; + dsp->dtmf.digits)] = what; } } } @@ -299,5 +311,3 @@ storedigit: goto again; } - - diff --git a/drivers/isdn/mISDN/dsp_ecdis.h b/drivers/isdn/mISDN/dsp_ecdis.h index 8a20af43308..fed99ac7f6a 100644 --- a/drivers/isdn/mISDN/dsp_ecdis.h +++ b/drivers/isdn/mISDN/dsp_ecdis.h @@ -46,15 +46,15 @@ struct ec_disable_detector_state { static inline void echo_can_disable_detector_init(struct ec_disable_detector_state *det) { - /* Elliptic notch */ - /* This is actually centred at 2095Hz, but gets the balance we want, due - to the asymmetric walls of the notch */ + /* Elliptic notch */ + /* This is actually centred at 2095Hz, but gets the balance we want, due + to the asymmetric walls of the notch */ biquad2_init(&det->notch, - (int32_t) (-0.7600000*32768.0), - (int32_t) (-0.1183852*32768.0), - (int32_t) (-0.5104039*32768.0), - (int32_t) (0.1567596*32768.0), - (int32_t) (1.0000000*32768.0)); + (int32_t)(-0.7600000 * 32768.0), + (int32_t)(-0.1183852 * 32768.0), + (int32_t)(-0.5104039 * 32768.0), + (int32_t)(0.1567596 * 32768.0), + (int32_t)(1.0000000 * 32768.0)); det->channel_level = 0; det->notch_level = 0; @@ -67,7 +67,7 @@ echo_can_disable_detector_init(struct ec_disable_detector_state *det) static inline int echo_can_disable_detector_update(struct ec_disable_detector_state *det, -int16_t amp) + int16_t amp) { int16_t notched; @@ -82,16 +82,16 @@ int16_t amp) det->notch_level += ((abs(notched) - det->notch_level) >> 4); if (det->channel_level > 280) { /* There is adequate energy in the channel. - Is it mostly at 2100Hz? */ - if (det->notch_level*6 < det->channel_level) { + Is it mostly at 2100Hz? */ + if (det->notch_level * 6 < det->channel_level) { /* The notch says yes, so we have the tone. */ if (!det->tone_present) { /* Do we get a kick every 450+-25ms? */ - if (det->tone_cycle_duration >= 425*8 - && det->tone_cycle_duration <= 475*8) { + if (det->tone_cycle_duration >= 425 * 8 + && det->tone_cycle_duration <= 475 * 8) { det->good_cycles++; if (det->good_cycles > 2) - det->hit = TRUE; + det->hit = TRUE; } det->tone_cycle_duration = 0; } diff --git a/drivers/isdn/mISDN/dsp_hwec.c b/drivers/isdn/mISDN/dsp_hwec.c index eb892d9dd5c..a6e87076acc 100644 --- a/drivers/isdn/mISDN/dsp_hwec.c +++ b/drivers/isdn/mISDN/dsp_hwec.c @@ -43,7 +43,7 @@ static struct mISDN_dsp_element dsp_hwec_p = { .free = NULL, .process_tx = NULL, .process_rx = NULL, - .num_args = sizeof(args) / sizeof(struct mISDN_dsp_element_arg), + .num_args = ARRAY_SIZE(args), .args = args, }; struct mISDN_dsp_element *dsp_hwec = &dsp_hwec_p; @@ -56,7 +56,7 @@ void dsp_hwec_enable(struct dsp *dsp, const char *arg) if (!dsp) { printk(KERN_ERR "%s: failed to enable hwec: dsp is NULL\n", - __func__); + __func__); return; } @@ -93,13 +93,13 @@ void dsp_hwec_enable(struct dsp *dsp, const char *arg) _do: printk(KERN_DEBUG "%s: enabling hwec with deftaps=%d\n", - __func__, deftaps); + __func__, deftaps); memset(&cq, 0, sizeof(cq)); cq.op = MISDN_CTRL_HFC_ECHOCAN_ON; cq.p1 = deftaps; if (!dsp->ch.peer->ctrl(&dsp->ch, CONTROL_CHANNEL, &cq)) { printk(KERN_DEBUG "%s: CONTROL_CHANNEL failed\n", - __func__); + __func__); return; } } @@ -110,7 +110,7 @@ void dsp_hwec_disable(struct dsp *dsp) if (!dsp) { printk(KERN_ERR "%s: failed to disable hwec: dsp is NULL\n", - __func__); + __func__); return; } @@ -119,7 +119,7 @@ void dsp_hwec_disable(struct dsp *dsp) cq.op = MISDN_CTRL_HFC_ECHOCAN_OFF; if (!dsp->ch.peer->ctrl(&dsp->ch, CONTROL_CHANNEL, &cq)) { printk(KERN_DEBUG "%s: CONTROL_CHANNEL failed\n", - __func__); + __func__); return; } } @@ -135,4 +135,3 @@ void dsp_hwec_exit(void) { mISDN_dsp_element_unregister(dsp_hwec); } - diff --git a/drivers/isdn/mISDN/dsp_hwec.h b/drivers/isdn/mISDN/dsp_hwec.h index eebe80c3f71..bbca1eb5a88 100644 --- a/drivers/isdn/mISDN/dsp_hwec.h +++ b/drivers/isdn/mISDN/dsp_hwec.h @@ -7,4 +7,3 @@ extern void dsp_hwec_enable(struct dsp *dsp, const char *arg); extern void dsp_hwec_disable(struct dsp *dsp); extern int dsp_hwec_init(void); extern void dsp_hwec_exit(void); - diff --git a/drivers/isdn/mISDN/dsp_pipeline.c b/drivers/isdn/mISDN/dsp_pipeline.c index 850260ab57d..8b1a66c6ca8 100644 --- a/drivers/isdn/mISDN/dsp_pipeline.c +++ b/drivers/isdn/mISDN/dsp_pipeline.c @@ -25,10 +25,12 @@ */ #include <linux/kernel.h> +#include <linux/slab.h> #include <linux/list.h> #include <linux/string.h> #include <linux/mISDNif.h> #include <linux/mISDNdsp.h> +#include <linux/export.h> #include "dsp.h" #include "dsp_hwec.h" @@ -55,26 +57,34 @@ static ssize_t attr_show_args(struct device *dev, struct device_attribute *attr, char *buf) { struct mISDN_dsp_element *elem = dev_get_drvdata(dev); - ssize_t len = 0; - int i = 0; + int i; + char *p = buf; *buf = 0; - for (; i < elem->num_args; ++i) - len = sprintf(buf, "%sName: %s\n%s%s%sDescription: %s\n" - "\n", buf, - elem->args[i].name, - elem->args[i].def ? "Default: " : "", - elem->args[i].def ? elem->args[i].def : "", - elem->args[i].def ? "\n" : "", - elem->args[i].desc); - - return len; + for (i = 0; i < elem->num_args; i++) + p += sprintf(p, "Name: %s\n%s%s%sDescription: %s\n\n", + elem->args[i].name, + elem->args[i].def ? "Default: " : "", + elem->args[i].def ? elem->args[i].def : "", + elem->args[i].def ? "\n" : "", + elem->args[i].desc); + + return p - buf; } static struct device_attribute element_attributes[] = { __ATTR(args, 0444, attr_show_args, NULL), }; +static void +mISDN_dsp_dev_release(struct device *dev) +{ + struct dsp_element_entry *entry = + container_of(dev, struct dsp_element_entry, dev); + list_del(&entry->list); + kfree(entry); +} + int mISDN_dsp_element_register(struct mISDN_dsp_element *elem) { struct dsp_element_entry *entry; @@ -83,40 +93,43 @@ int mISDN_dsp_element_register(struct mISDN_dsp_element *elem) if (!elem) return -EINVAL; - entry = kzalloc(sizeof(struct dsp_element_entry), GFP_KERNEL); + entry = kzalloc(sizeof(struct dsp_element_entry), GFP_ATOMIC); if (!entry) return -ENOMEM; entry->elem = elem; entry->dev.class = elements_class; + entry->dev.release = mISDN_dsp_dev_release; dev_set_drvdata(&entry->dev, elem); - snprintf(entry->dev.bus_id, BUS_ID_SIZE, elem->name); + dev_set_name(&entry->dev, "%s", elem->name); ret = device_register(&entry->dev); if (ret) { printk(KERN_ERR "%s: failed to register %s\n", - __func__, elem->name); + __func__, elem->name); goto err1; } + list_add_tail(&entry->list, &dsp_elements); - for (i = 0; i < (sizeof(element_attributes) - / sizeof(struct device_attribute)); ++i) + for (i = 0; i < ARRAY_SIZE(element_attributes); ++i) { ret = device_create_file(&entry->dev, - &element_attributes[i]); + &element_attributes[i]); if (ret) { printk(KERN_ERR "%s: failed to create device file\n", - __func__); + __func__); goto err2; } + } - list_add_tail(&entry->list, &dsp_elements); - +#ifdef PIPELINE_DEBUG printk(KERN_DEBUG "%s: %s registered\n", __func__, elem->name); +#endif return 0; err2: device_unregister(&entry->dev); + return ret; err1: kfree(entry); return ret; @@ -132,11 +145,11 @@ void mISDN_dsp_element_unregister(struct mISDN_dsp_element *elem) list_for_each_entry_safe(entry, n, &dsp_elements, list) if (entry->elem == elem) { - list_del(&entry->list); device_unregister(&entry->dev); - kfree(entry); +#ifdef PIPELINE_DEBUG printk(KERN_DEBUG "%s: %s unregistered\n", - __func__, elem->name); + __func__, elem->name); +#endif return; } printk(KERN_ERR "%s: element %s not in list.\n", __func__, elem->name); @@ -169,11 +182,13 @@ void dsp_pipeline_module_exit(void) list_for_each_entry_safe(entry, n, &dsp_elements, list) { list_del(&entry->list); printk(KERN_WARNING "%s: element was still registered: %s\n", - __func__, entry->elem->name); + __func__, entry->elem->name); kfree(entry); } +#ifdef PIPELINE_DEBUG printk(KERN_DEBUG "%s: dsp pipeline module exited\n", __func__); +#endif } int dsp_pipeline_init(struct dsp_pipeline *pipeline) @@ -198,7 +213,7 @@ static inline void _dsp_pipeline_destroy(struct dsp_pipeline *pipeline) list_del(&entry->list); if (entry->elem == dsp_hwec) dsp_hwec_disable(container_of(pipeline, struct dsp, - pipeline)); + pipeline)); else entry->elem->free(entry->p); kfree(entry); @@ -239,7 +254,7 @@ int dsp_pipeline_build(struct dsp_pipeline *pipeline, const char *cfg) if (!len) return 0; - dup = kmalloc(len + 1, GFP_KERNEL); + dup = kmalloc(len + 1, GFP_ATOMIC); if (!dup) return 0; strcpy(dup, cfg); @@ -249,18 +264,18 @@ int dsp_pipeline_build(struct dsp_pipeline *pipeline, const char *cfg) name = strsep(&tok, "("); args = strsep(&tok, ")"); if (args && !*args) - args = 0; + args = NULL; list_for_each_entry_safe(entry, n, &dsp_elements, list) if (!strcmp(entry->elem->name, name)) { elem = entry->elem; pipeline_entry = kmalloc(sizeof(struct - dsp_pipeline_entry), GFP_KERNEL); + dsp_pipeline_entry), GFP_ATOMIC); if (!pipeline_entry) { - printk(KERN_DEBUG "%s: failed to add " - "entry to pipeline: %s (out of " - "memory)\n", __func__, elem->name); + printk(KERN_ERR "%s: failed to add " + "entry to pipeline: %s (out of " + "memory)\n", __func__, elem->name); incomplete = 1; goto _out; } @@ -270,26 +285,26 @@ int dsp_pipeline_build(struct dsp_pipeline *pipeline, const char *cfg) /* This is a hack to make the hwec available as a pipeline module */ dsp_hwec_enable(container_of(pipeline, - struct dsp, pipeline), args); + struct dsp, pipeline), args); list_add_tail(&pipeline_entry->list, - &pipeline->list); + &pipeline->list); } else { pipeline_entry->p = elem->new(args); if (pipeline_entry->p) { list_add_tail(&pipeline_entry-> - list, &pipeline->list); + list, &pipeline->list); #ifdef PIPELINE_DEBUG printk(KERN_DEBUG "%s: created " - "instance of %s%s%s\n", - __func__, name, args ? - " with args " : "", args ? - args : ""); + "instance of %s%s%s\n", + __func__, name, args ? + " with args " : "", args ? + args : ""); #endif } else { - printk(KERN_DEBUG "%s: failed " - "to add entry to pipeline: " - "%s (new() returned NULL)\n", - __func__, elem->name); + printk(KERN_ERR "%s: failed " + "to add entry to pipeline: " + "%s (new() returned NULL)\n", + __func__, elem->name); kfree(pipeline_entry); incomplete = 1; } @@ -301,8 +316,8 @@ int dsp_pipeline_build(struct dsp_pipeline *pipeline, const char *cfg) if (found) found = 0; else { - printk(KERN_DEBUG "%s: element not found, skipping: " - "%s\n", __func__, name); + printk(KERN_ERR "%s: element not found, skipping: " + "%s\n", __func__, name); incomplete = 1; } } @@ -315,7 +330,7 @@ _out: #ifdef PIPELINE_DEBUG printk(KERN_DEBUG "%s: dsp pipeline built%s: %s\n", - __func__, incomplete ? " incomplete" : "", cfg); + __func__, incomplete ? " incomplete" : "", cfg); #endif kfree(dup); return 0; @@ -333,7 +348,8 @@ void dsp_pipeline_process_tx(struct dsp_pipeline *pipeline, u8 *data, int len) entry->elem->process_tx(entry->p, data, len); } -void dsp_pipeline_process_rx(struct dsp_pipeline *pipeline, u8 *data, int len) +void dsp_pipeline_process_rx(struct dsp_pipeline *pipeline, u8 *data, int len, + unsigned int txlen) { struct dsp_pipeline_entry *entry; @@ -342,7 +358,5 @@ void dsp_pipeline_process_rx(struct dsp_pipeline *pipeline, u8 *data, int len) list_for_each_entry_reverse(entry, &pipeline->list, list) if (entry->elem->process_rx) - entry->elem->process_rx(entry->p, data, len); + entry->elem->process_rx(entry->p, data, len, txlen); } - - diff --git a/drivers/isdn/mISDN/dsp_tones.c b/drivers/isdn/mISDN/dsp_tones.c index 23dd0dd2152..057e0d6a369 100644 --- a/drivers/isdn/mISDN/dsp_tones.c +++ b/drivers/isdn/mISDN/dsp_tones.c @@ -8,6 +8,7 @@ * */ +#include <linux/gfp.h> #include <linux/mISDNif.h> #include <linux/mISDNdsp.h> #include "core.h" @@ -231,121 +232,127 @@ dsp_audio_generate_ulaw_samples(void) * tone sequence definition * ****************************/ -struct pattern { +static struct pattern { int tone; u8 *data[10]; u32 *siz[10]; u32 seq[10]; } pattern[] = { {TONE_GERMAN_DIALTONE, - {DATA_GA, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {SIZE_GA, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {1900, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, + {DATA_GA, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}, + {SIZE_GA, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}, + {1900, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, {TONE_GERMAN_OLDDIALTONE, - {DATA_GO, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {SIZE_GO, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {1998, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, + {DATA_GO, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}, + {SIZE_GO, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}, + {1998, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, {TONE_AMERICAN_DIALTONE, - {DATA_DT, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {SIZE_DT, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {8000, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, + {DATA_DT, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}, + {SIZE_DT, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}, + {8000, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, {TONE_GERMAN_DIALPBX, - {DATA_GA, DATA_S, DATA_GA, DATA_S, DATA_GA, DATA_S, 0, 0, 0, 0}, - {SIZE_GA, SIZE_S, SIZE_GA, SIZE_S, SIZE_GA, SIZE_S, 0, 0, 0, 0}, - {2000, 2000, 2000, 2000, 2000, 12000, 0, 0, 0, 0} }, + {DATA_GA, DATA_S, DATA_GA, DATA_S, DATA_GA, DATA_S, NULL, NULL, NULL, + NULL}, + {SIZE_GA, SIZE_S, SIZE_GA, SIZE_S, SIZE_GA, SIZE_S, NULL, NULL, NULL, + NULL}, + {2000, 2000, 2000, 2000, 2000, 12000, 0, 0, 0, 0} }, {TONE_GERMAN_OLDDIALPBX, - {DATA_GO, DATA_S, DATA_GO, DATA_S, DATA_GO, DATA_S, 0, 0, 0, 0}, - {SIZE_GO, SIZE_S, SIZE_GO, SIZE_S, SIZE_GO, SIZE_S, 0, 0, 0, 0}, - {2000, 2000, 2000, 2000, 2000, 12000, 0, 0, 0, 0} }, + {DATA_GO, DATA_S, DATA_GO, DATA_S, DATA_GO, DATA_S, NULL, NULL, NULL, + NULL}, + {SIZE_GO, SIZE_S, SIZE_GO, SIZE_S, SIZE_GO, SIZE_S, NULL, NULL, NULL, + NULL}, + {2000, 2000, 2000, 2000, 2000, 12000, 0, 0, 0, 0} }, {TONE_AMERICAN_DIALPBX, - {DATA_DT, DATA_S, DATA_DT, DATA_S, DATA_DT, DATA_S, 0, 0, 0, 0}, - {SIZE_DT, SIZE_S, SIZE_DT, SIZE_S, SIZE_DT, SIZE_S, 0, 0, 0, 0}, - {2000, 2000, 2000, 2000, 2000, 12000, 0, 0, 0, 0} }, + {DATA_DT, DATA_S, DATA_DT, DATA_S, DATA_DT, DATA_S, NULL, NULL, NULL, + NULL}, + {SIZE_DT, SIZE_S, SIZE_DT, SIZE_S, SIZE_DT, SIZE_S, NULL, NULL, NULL, + NULL}, + {2000, 2000, 2000, 2000, 2000, 12000, 0, 0, 0, 0} }, {TONE_GERMAN_RINGING, - {DATA_GA, DATA_S, 0, 0, 0, 0, 0, 0, 0, 0}, - {SIZE_GA, SIZE_S, 0, 0, 0, 0, 0, 0, 0, 0}, - {8000, 32000, 0, 0, 0, 0, 0, 0, 0, 0} }, + {DATA_GA, DATA_S, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}, + {SIZE_GA, SIZE_S, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}, + {8000, 32000, 0, 0, 0, 0, 0, 0, 0, 0} }, {TONE_GERMAN_OLDRINGING, - {DATA_GO, DATA_S, 0, 0, 0, 0, 0, 0, 0, 0}, - {SIZE_GO, SIZE_S, 0, 0, 0, 0, 0, 0, 0, 0}, - {8000, 40000, 0, 0, 0, 0, 0, 0, 0, 0} }, + {DATA_GO, DATA_S, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}, + {SIZE_GO, SIZE_S, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}, + {8000, 40000, 0, 0, 0, 0, 0, 0, 0, 0} }, {TONE_AMERICAN_RINGING, - {DATA_RI, DATA_S, 0, 0, 0, 0, 0, 0, 0, 0}, - {SIZE_RI, SIZE_S, 0, 0, 0, 0, 0, 0, 0, 0}, - {8000, 32000, 0, 0, 0, 0, 0, 0, 0, 0} }, + {DATA_RI, DATA_S, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}, + {SIZE_RI, SIZE_S, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}, + {8000, 32000, 0, 0, 0, 0, 0, 0, 0, 0} }, {TONE_GERMAN_RINGPBX, - {DATA_GA, DATA_S, DATA_GA, DATA_S, 0, 0, 0, 0, 0, 0}, - {SIZE_GA, SIZE_S, SIZE_GA, SIZE_S, 0, 0, 0, 0, 0, 0}, - {4000, 4000, 4000, 28000, 0, 0, 0, 0, 0, 0} }, + {DATA_GA, DATA_S, DATA_GA, DATA_S, NULL, NULL, NULL, NULL, NULL, NULL}, + {SIZE_GA, SIZE_S, SIZE_GA, SIZE_S, NULL, NULL, NULL, NULL, NULL, NULL}, + {4000, 4000, 4000, 28000, 0, 0, 0, 0, 0, 0} }, {TONE_GERMAN_OLDRINGPBX, - {DATA_GO, DATA_S, DATA_GO, DATA_S, 0, 0, 0, 0, 0, 0}, - {SIZE_GO, SIZE_S, SIZE_GO, SIZE_S, 0, 0, 0, 0, 0, 0}, - {4000, 4000, 4000, 28000, 0, 0, 0, 0, 0, 0} }, + {DATA_GO, DATA_S, DATA_GO, DATA_S, NULL, NULL, NULL, NULL, NULL, NULL}, + {SIZE_GO, SIZE_S, SIZE_GO, SIZE_S, NULL, NULL, NULL, NULL, NULL, NULL}, + {4000, 4000, 4000, 28000, 0, 0, 0, 0, 0, 0} }, {TONE_AMERICAN_RINGPBX, - {DATA_RI, DATA_S, DATA_RI, DATA_S, 0, 0, 0, 0, 0, 0}, - {SIZE_RI, SIZE_S, SIZE_RI, SIZE_S, 0, 0, 0, 0, 0, 0}, - {4000, 4000, 4000, 28000, 0, 0, 0, 0, 0, 0} }, + {DATA_RI, DATA_S, DATA_RI, DATA_S, NULL, NULL, NULL, NULL, NULL, NULL}, + {SIZE_RI, SIZE_S, SIZE_RI, SIZE_S, NULL, NULL, NULL, NULL, NULL, NULL}, + {4000, 4000, 4000, 28000, 0, 0, 0, 0, 0, 0} }, {TONE_GERMAN_BUSY, - {DATA_GA, DATA_S, 0, 0, 0, 0, 0, 0, 0, 0}, - {SIZE_GA, SIZE_S, 0, 0, 0, 0, 0, 0, 0, 0}, - {4000, 4000, 0, 0, 0, 0, 0, 0, 0, 0} }, + {DATA_GA, DATA_S, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}, + {SIZE_GA, SIZE_S, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}, + {4000, 4000, 0, 0, 0, 0, 0, 0, 0, 0} }, {TONE_GERMAN_OLDBUSY, - {DATA_GO, DATA_S, 0, 0, 0, 0, 0, 0, 0, 0}, - {SIZE_GO, SIZE_S, 0, 0, 0, 0, 0, 0, 0, 0}, - {1000, 5000, 0, 0, 0, 0, 0, 0, 0, 0} }, + {DATA_GO, DATA_S, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}, + {SIZE_GO, SIZE_S, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}, + {1000, 5000, 0, 0, 0, 0, 0, 0, 0, 0} }, {TONE_AMERICAN_BUSY, - {DATA_BU, DATA_S, 0, 0, 0, 0, 0, 0, 0, 0}, - {SIZE_BU, SIZE_S, 0, 0, 0, 0, 0, 0, 0, 0}, - {4000, 4000, 0, 0, 0, 0, 0, 0, 0, 0} }, + {DATA_BU, DATA_S, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}, + {SIZE_BU, SIZE_S, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}, + {4000, 4000, 0, 0, 0, 0, 0, 0, 0, 0} }, {TONE_GERMAN_HANGUP, - {DATA_GA, DATA_S, 0, 0, 0, 0, 0, 0, 0, 0}, - {SIZE_GA, SIZE_S, 0, 0, 0, 0, 0, 0, 0, 0}, - {4000, 4000, 0, 0, 0, 0, 0, 0, 0, 0} }, + {DATA_GA, DATA_S, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}, + {SIZE_GA, SIZE_S, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}, + {4000, 4000, 0, 0, 0, 0, 0, 0, 0, 0} }, {TONE_GERMAN_OLDHANGUP, - {DATA_GO, DATA_S, 0, 0, 0, 0, 0, 0, 0, 0}, - {SIZE_GO, SIZE_S, 0, 0, 0, 0, 0, 0, 0, 0}, - {1000, 5000, 0, 0, 0, 0, 0, 0, 0, 0} }, + {DATA_GO, DATA_S, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}, + {SIZE_GO, SIZE_S, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}, + {1000, 5000, 0, 0, 0, 0, 0, 0, 0, 0} }, {TONE_AMERICAN_HANGUP, - {DATA_DT, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {SIZE_DT, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {8000, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, + {DATA_DT, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}, + {SIZE_DT, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}, + {8000, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, {TONE_SPECIAL_INFO, - {DATA_S1, DATA_S2, DATA_S3, DATA_S, 0, 0, 0, 0, 0, 0}, - {SIZE_S1, SIZE_S2, SIZE_S3, SIZE_S, 0, 0, 0, 0, 0, 0}, - {2666, 2666, 2666, 8002, 0, 0, 0, 0, 0, 0} }, + {DATA_S1, DATA_S2, DATA_S3, DATA_S, NULL, NULL, NULL, NULL, NULL, NULL}, + {SIZE_S1, SIZE_S2, SIZE_S3, SIZE_S, NULL, NULL, NULL, NULL, NULL, NULL}, + {2666, 2666, 2666, 8002, 0, 0, 0, 0, 0, 0} }, {TONE_GERMAN_GASSENBESETZT, - {DATA_GA, DATA_S, 0, 0, 0, 0, 0, 0, 0, 0}, - {SIZE_GA, SIZE_S, 0, 0, 0, 0, 0, 0, 0, 0}, - {2000, 2000, 0, 0, 0, 0, 0, 0, 0, 0} }, + {DATA_GA, DATA_S, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}, + {SIZE_GA, SIZE_S, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}, + {2000, 2000, 0, 0, 0, 0, 0, 0, 0, 0} }, {TONE_GERMAN_AUFSCHALTTON, - {DATA_GO, DATA_S, DATA_GO, DATA_S, 0, 0, 0, 0, 0, 0}, - {SIZE_GO, SIZE_S, SIZE_GO, SIZE_S, 0, 0, 0, 0, 0, 0}, - {1000, 5000, 1000, 17000, 0, 0, 0, 0, 0, 0} }, + {DATA_GO, DATA_S, DATA_GO, DATA_S, NULL, NULL, NULL, NULL, NULL, NULL}, + {SIZE_GO, SIZE_S, SIZE_GO, SIZE_S, NULL, NULL, NULL, NULL, NULL, NULL}, + {1000, 5000, 1000, 17000, 0, 0, 0, 0, 0, 0} }, {0, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, + {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}, + {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, }; /****************** @@ -379,7 +386,7 @@ void dsp_tone_copy(struct dsp *dsp, u8 *data, int len) /* process pattern */ pat = (struct pattern *)tone->pattern; - /* points to the current pattern */ + /* points to the current pattern */ index = tone->index; /* gives current sequence index */ count = tone->count; /* gives current sample */ @@ -387,7 +394,7 @@ void dsp_tone_copy(struct dsp *dsp, u8 *data, int len) while (len) { /* find sample to start with */ while (42) { - /* warp arround */ + /* wrap around */ if (!pat->seq[index]) { count = 0; index = 0; @@ -397,19 +404,19 @@ void dsp_tone_copy(struct dsp *dsp, u8 *data, int len) break; if (dsp_debug & DEBUG_DSP_TONE) printk(KERN_DEBUG "%s: reaching next sequence " - "(index=%d)\n", __func__, index); + "(index=%d)\n", __func__, index); count -= pat->seq[index]; index++; } /* calculate start and number of samples */ start = count % (*(pat->siz[index])); num = len; - if (num+count > pat->seq[index]) + if (num + count > pat->seq[index]) num = pat->seq[index] - count; - if (num+start > (*(pat->siz[index]))) + if (num + start > (*(pat->siz[index]))) num = (*(pat->siz[index])) - start; /* copy memory */ - memcpy(data, pat->data[index]+start, num); + memcpy(data, pat->data[index] + start, num); /* reduce length */ data += num; count += num; @@ -434,8 +441,8 @@ dsp_tone_hw_message(struct dsp *dsp, u8 *sample, int len) /* unlocking is not required, because we don't expect a response */ nskb = _alloc_mISDN_skb(PH_CONTROL_REQ, - (len)?HFC_SPL_LOOP_ON:HFC_SPL_LOOP_OFF, len, sample, - GFP_ATOMIC); + (len) ? HFC_SPL_LOOP_ON : HFC_SPL_LOOP_OFF, len, sample, + GFP_ATOMIC); if (nskb) { if (dsp->ch.peer) { if (dsp->ch.recv(dsp->ch.peer, nskb)) @@ -467,7 +474,7 @@ dsp_tone_timeout(void *arg) /* set next tone */ if (pat->data[index] == DATA_S) - dsp_tone_hw_message(dsp, 0, 0); + dsp_tone_hw_message(dsp, NULL, 0); else dsp_tone_hw_message(dsp, pat->data[index], *(pat->siz[index])); /* set timer */ @@ -498,8 +505,7 @@ dsp_tone(struct dsp *dsp, int tone) /* we turn off the tone */ if (!tone) { - if (dsp->features.hfc_loops) - if (timer_pending(&tonet->tl)) + if (dsp->features.hfc_loops && timer_pending(&tonet->tl)) del_timer(&tonet->tl); if (dsp->features.hfc_loops) dsp_tone_hw_message(dsp, NULL, 0); @@ -522,7 +528,7 @@ dsp_tone(struct dsp *dsp, int tone) } if (dsp_debug & DEBUG_DSP_TONE) printk(KERN_DEBUG "%s: now starting tone %d (index=%d)\n", - __func__, tone, 0); + __func__, tone, 0); tonet->tone = tone; tonet->pattern = pat; tonet->index = 0; @@ -544,8 +550,3 @@ dsp_tone(struct dsp *dsp, int tone) return 0; } - - - - - diff --git a/drivers/isdn/mISDN/fsm.c b/drivers/isdn/mISDN/fsm.c index b5d6553f2dc..26477d48bbd 100644 --- a/drivers/isdn/mISDN/fsm.c +++ b/drivers/isdn/mISDN/fsm.c @@ -28,23 +28,23 @@ void mISDN_FsmNew(struct Fsm *fsm, - struct FsmNode *fnlist, int fncount) + struct FsmNode *fnlist, int fncount) { int i; fsm->jumpmatrix = kzalloc(sizeof(FSMFNPTR) * fsm->state_count * - fsm->event_count, GFP_KERNEL); + fsm->event_count, GFP_KERNEL); for (i = 0; i < fncount; i++) if ((fnlist[i].state >= fsm->state_count) || (fnlist[i].event >= fsm->event_count)) { printk(KERN_ERR - "mISDN_FsmNew Error: %d st(%ld/%ld) ev(%ld/%ld)\n", - i, (long)fnlist[i].state, (long)fsm->state_count, - (long)fnlist[i].event, (long)fsm->event_count); + "mISDN_FsmNew Error: %d st(%ld/%ld) ev(%ld/%ld)\n", + i, (long)fnlist[i].state, (long)fsm->state_count, + (long)fnlist[i].event, (long)fsm->event_count); } else fsm->jumpmatrix[fsm->state_count * fnlist[i].event + - fnlist[i].state] = (FSMFNPTR) fnlist[i].routine; + fnlist[i].state] = (FSMFNPTR) fnlist[i].routine; } EXPORT_SYMBOL(mISDN_FsmNew); @@ -63,24 +63,24 @@ mISDN_FsmEvent(struct FsmInst *fi, int event, void *arg) if ((fi->state >= fi->fsm->state_count) || (event >= fi->fsm->event_count)) { printk(KERN_ERR - "mISDN_FsmEvent Error st(%ld/%ld) ev(%d/%ld)\n", - (long)fi->state, (long)fi->fsm->state_count, event, - (long)fi->fsm->event_count); + "mISDN_FsmEvent Error st(%ld/%ld) ev(%d/%ld)\n", + (long)fi->state, (long)fi->fsm->state_count, event, + (long)fi->fsm->event_count); return 1; } r = fi->fsm->jumpmatrix[fi->fsm->state_count * event + fi->state]; if (r) { if (fi->debug) fi->printdebug(fi, "State %s Event %s", - fi->fsm->strState[fi->state], - fi->fsm->strEvent[event]); + fi->fsm->strState[fi->state], + fi->fsm->strEvent[event]); r(fi, event, arg); return 0; } else { if (fi->debug) fi->printdebug(fi, "State %s Event %s no action", - fi->fsm->strState[fi->state], - fi->fsm->strEvent[event]); + fi->fsm->strState[fi->state], + fi->fsm->strEvent[event]); return 1; } } @@ -92,7 +92,7 @@ mISDN_FsmChangeState(struct FsmInst *fi, int newstate) fi->state = newstate; if (fi->debug) fi->printdebug(fi, "ChangeState %s", - fi->fsm->strState[newstate]); + fi->fsm->strState[newstate]); } EXPORT_SYMBOL(mISDN_FsmChangeState); @@ -126,7 +126,7 @@ mISDN_FsmDelTimer(struct FsmTimer *ft, int where) #if FSM_TIMER_DEBUG if (ft->fi->debug) ft->fi->printdebug(ft->fi, "mISDN_FsmDelTimer %lx %d", - (long) ft, where); + (long) ft, where); #endif del_timer(&ft->tl); } @@ -134,21 +134,21 @@ EXPORT_SYMBOL(mISDN_FsmDelTimer); int mISDN_FsmAddTimer(struct FsmTimer *ft, - int millisec, int event, void *arg, int where) + int millisec, int event, void *arg, int where) { #if FSM_TIMER_DEBUG if (ft->fi->debug) ft->fi->printdebug(ft->fi, "mISDN_FsmAddTimer %lx %d %d", - (long) ft, millisec, where); + (long) ft, millisec, where); #endif if (timer_pending(&ft->tl)) { if (ft->fi->debug) { printk(KERN_WARNING - "mISDN_FsmAddTimer: timer already active!\n"); + "mISDN_FsmAddTimer: timer already active!\n"); ft->fi->printdebug(ft->fi, - "mISDN_FsmAddTimer already active!"); + "mISDN_FsmAddTimer already active!"); } return -1; } @@ -163,13 +163,13 @@ EXPORT_SYMBOL(mISDN_FsmAddTimer); void mISDN_FsmRestartTimer(struct FsmTimer *ft, - int millisec, int event, void *arg, int where) + int millisec, int event, void *arg, int where) { #if FSM_TIMER_DEBUG if (ft->fi->debug) ft->fi->printdebug(ft->fi, "mISDN_FsmRestartTimer %lx %d %d", - (long) ft, millisec, where); + (long) ft, millisec, where); #endif if (timer_pending(&ft->tl)) diff --git a/drivers/isdn/mISDN/hwchannel.c b/drivers/isdn/mISDN/hwchannel.c index 2596fba4e61..84b4b0f7eb9 100644 --- a/drivers/isdn/mISDN/hwchannel.c +++ b/drivers/isdn/mISDN/hwchannel.c @@ -15,6 +15,7 @@ * */ +#include <linux/gfp.h> #include <linux/module.h> #include <linux/mISDNhw.h> @@ -50,9 +51,6 @@ bchannel_bh(struct work_struct *ws) if (test_and_clear_bit(FLG_RECVQUEUE, &bch->Flags)) { while ((skb = skb_dequeue(&bch->rqueue))) { - if (bch->rcount >= 64) - printk(KERN_WARNING "B-channel %p receive " - "queue if full, but empties...\n", bch); bch->rcount--; if (likely(bch->ch.peer)) { err = bch->ch.recv(bch->ch.peer, skb); @@ -83,10 +81,16 @@ mISDN_initdchannel(struct dchannel *ch, int maxlen, void *phf) EXPORT_SYMBOL(mISDN_initdchannel); int -mISDN_initbchannel(struct bchannel *ch, int maxlen) +mISDN_initbchannel(struct bchannel *ch, unsigned short maxlen, + unsigned short minlen) { ch->Flags = 0; + ch->minlen = minlen; + ch->next_minlen = minlen; + ch->init_minlen = minlen; ch->maxlen = maxlen; + ch->next_maxlen = maxlen; + ch->init_maxlen = maxlen; ch->hw = NULL; ch->rx_skb = NULL; ch->tx_skb = NULL; @@ -112,18 +116,19 @@ mISDN_freedchannel(struct dchannel *ch) } skb_queue_purge(&ch->squeue); skb_queue_purge(&ch->rqueue); - flush_scheduled_work(); + flush_work(&ch->workq); return 0; } EXPORT_SYMBOL(mISDN_freedchannel); -int -mISDN_freebchannel(struct bchannel *ch) +void +mISDN_clear_bchannel(struct bchannel *ch) { if (ch->tx_skb) { dev_kfree_skb(ch->tx_skb); ch->tx_skb = NULL; } + ch->tx_idx = 0; if (ch->rx_skb) { dev_kfree_skb(ch->rx_skb); ch->rx_skb = NULL; @@ -132,13 +137,75 @@ mISDN_freebchannel(struct bchannel *ch) dev_kfree_skb(ch->next_skb); ch->next_skb = NULL; } + test_and_clear_bit(FLG_TX_BUSY, &ch->Flags); + test_and_clear_bit(FLG_TX_NEXT, &ch->Flags); + test_and_clear_bit(FLG_ACTIVE, &ch->Flags); + test_and_clear_bit(FLG_FILLEMPTY, &ch->Flags); + test_and_clear_bit(FLG_TX_EMPTY, &ch->Flags); + test_and_clear_bit(FLG_RX_OFF, &ch->Flags); + ch->dropcnt = 0; + ch->minlen = ch->init_minlen; + ch->next_minlen = ch->init_minlen; + ch->maxlen = ch->init_maxlen; + ch->next_maxlen = ch->init_maxlen; skb_queue_purge(&ch->rqueue); ch->rcount = 0; - flush_scheduled_work(); - return 0; +} +EXPORT_SYMBOL(mISDN_clear_bchannel); + +void +mISDN_freebchannel(struct bchannel *ch) +{ + cancel_work_sync(&ch->workq); + mISDN_clear_bchannel(ch); } EXPORT_SYMBOL(mISDN_freebchannel); +int +mISDN_ctrl_bchannel(struct bchannel *bch, struct mISDN_ctrl_req *cq) +{ + int ret = 0; + + switch (cq->op) { + case MISDN_CTRL_GETOP: + cq->op = MISDN_CTRL_RX_BUFFER | MISDN_CTRL_FILL_EMPTY | + MISDN_CTRL_RX_OFF; + break; + case MISDN_CTRL_FILL_EMPTY: + if (cq->p1) { + memset(bch->fill, cq->p2 & 0xff, MISDN_BCH_FILL_SIZE); + test_and_set_bit(FLG_FILLEMPTY, &bch->Flags); + } else { + test_and_clear_bit(FLG_FILLEMPTY, &bch->Flags); + } + break; + case MISDN_CTRL_RX_OFF: + /* read back dropped byte count */ + cq->p2 = bch->dropcnt; + if (cq->p1) + test_and_set_bit(FLG_RX_OFF, &bch->Flags); + else + test_and_clear_bit(FLG_RX_OFF, &bch->Flags); + bch->dropcnt = 0; + break; + case MISDN_CTRL_RX_BUFFER: + if (cq->p2 > MISDN_CTRL_RX_SIZE_IGNORE) + bch->next_maxlen = cq->p2; + if (cq->p1 > MISDN_CTRL_RX_SIZE_IGNORE) + bch->next_minlen = cq->p1; + /* we return the old values */ + cq->p1 = bch->minlen; + cq->p2 = bch->maxlen; + break; + default: + pr_info("mISDN unhandled control %x operation\n", cq->op); + ret = -EINVAL; + break; + } + return ret; +} +EXPORT_SYMBOL(mISDN_ctrl_bchannel); + static inline u_int get_sapi_tei(u_char *p) { @@ -169,22 +236,56 @@ recv_Dchannel(struct dchannel *dch) EXPORT_SYMBOL(recv_Dchannel); void -recv_Bchannel(struct bchannel *bch) +recv_Echannel(struct dchannel *ech, struct dchannel *dch) { struct mISDNhead *hh; - hh = mISDN_HEAD_P(bch->rx_skb); - hh->prim = PH_DATA_IND; - hh->id = MISDN_ID_ANY; - if (bch->rcount >= 64) { + if (ech->rx_skb->len < 2) { /* at least 2 for sapi / tei */ + dev_kfree_skb(ech->rx_skb); + ech->rx_skb = NULL; + return; + } + hh = mISDN_HEAD_P(ech->rx_skb); + hh->prim = PH_DATA_E_IND; + hh->id = get_sapi_tei(ech->rx_skb->data); + skb_queue_tail(&dch->rqueue, ech->rx_skb); + ech->rx_skb = NULL; + schedule_event(dch, FLG_RECVQUEUE); +} +EXPORT_SYMBOL(recv_Echannel); + +void +recv_Bchannel(struct bchannel *bch, unsigned int id, bool force) +{ + struct mISDNhead *hh; + + /* if allocation did fail upper functions still may call us */ + if (unlikely(!bch->rx_skb)) + return; + if (unlikely(!bch->rx_skb->len)) { + /* we have no data to send - this may happen after recovery + * from overflow or too small allocation. + * We need to free the buffer here */ dev_kfree_skb(bch->rx_skb); bch->rx_skb = NULL; - return; + } else { + if (test_bit(FLG_TRANSPARENT, &bch->Flags) && + (bch->rx_skb->len < bch->minlen) && !force) + return; + hh = mISDN_HEAD_P(bch->rx_skb); + hh->prim = PH_DATA_IND; + hh->id = id; + if (bch->rcount >= 64) { + printk(KERN_WARNING + "B%d receive queue overflow - flushing!\n", + bch->nr); + skb_queue_purge(&bch->rqueue); + } + bch->rcount++; + skb_queue_tail(&bch->rqueue, bch->rx_skb); + bch->rx_skb = NULL; + schedule_event(bch, FLG_RECVQUEUE); } - bch->rcount++; - skb_queue_tail(&bch->rqueue, bch->rx_skb); - bch->rx_skb = NULL; - schedule_event(bch, FLG_RECVQUEUE); } EXPORT_SYMBOL(recv_Bchannel); @@ -200,8 +301,10 @@ void recv_Bchannel_skb(struct bchannel *bch, struct sk_buff *skb) { if (bch->rcount >= 64) { - dev_kfree_skb(skb); - return; + printk(KERN_WARNING "B-channel %p receive queue overflow, " + "flushing!\n", bch); + skb_queue_purge(&bch->rqueue); + bch->rcount = 0; } bch->rcount++; skb_queue_tail(&bch->rqueue, skb); @@ -215,10 +318,10 @@ confirm_Dsend(struct dchannel *dch) struct sk_buff *skb; skb = _alloc_mISDN_skb(PH_DATA_CNF, mISDN_HEAD_ID(dch->tx_skb), - 0, NULL, GFP_ATOMIC); + 0, NULL, GFP_ATOMIC); if (!skb) { printk(KERN_ERR "%s: no skb id %x\n", __func__, - mISDN_HEAD_ID(dch->tx_skb)); + mISDN_HEAD_ID(dch->tx_skb)); return; } skb_queue_tail(&dch->rqueue, skb); @@ -240,25 +343,28 @@ get_next_dframe(struct dchannel *dch) } EXPORT_SYMBOL(get_next_dframe); -void +static void confirm_Bsend(struct bchannel *bch) { struct sk_buff *skb; - if (bch->rcount >= 64) - return; + if (bch->rcount >= 64) { + printk(KERN_WARNING "B-channel %p receive queue overflow, " + "flushing!\n", bch); + skb_queue_purge(&bch->rqueue); + bch->rcount = 0; + } skb = _alloc_mISDN_skb(PH_DATA_CNF, mISDN_HEAD_ID(bch->tx_skb), - 0, NULL, GFP_ATOMIC); + 0, NULL, GFP_ATOMIC); if (!skb) { printk(KERN_ERR "%s: no skb id %x\n", __func__, - mISDN_HEAD_ID(bch->tx_skb)); + mISDN_HEAD_ID(bch->tx_skb)); return; } bch->rcount++; skb_queue_tail(&bch->rqueue, skb); schedule_event(bch, FLG_RECVQUEUE); } -EXPORT_SYMBOL(confirm_Bsend); int get_next_bframe(struct bchannel *bch) @@ -269,8 +375,8 @@ get_next_bframe(struct bchannel *bch) if (bch->tx_skb) { bch->next_skb = NULL; test_and_clear_bit(FLG_TX_NEXT, &bch->Flags); - if (!test_bit(FLG_TRANSPARENT, &bch->Flags)) - confirm_Bsend(bch); /* not for transparent */ + /* confirm imediately to allow next data */ + confirm_Bsend(bch); return 1; } else { test_and_clear_bit(FLG_TX_NEXT, &bch->Flags); @@ -313,7 +419,7 @@ dchannel_senddata(struct dchannel *ch, struct sk_buff *skb) } if (skb->len > ch->maxlen) { printk(KERN_WARNING "%s: skb too large(%d/%d)\n", - __func__, skb->len, ch->maxlen); + __func__, skb->len, ch->maxlen); return -EINVAL; } /* HW lock must be obtained */ @@ -340,15 +446,15 @@ bchannel_senddata(struct bchannel *ch, struct sk_buff *skb) } if (skb->len > ch->maxlen) { printk(KERN_WARNING "%s: skb too large(%d/%d)\n", - __func__, skb->len, ch->maxlen); + __func__, skb->len, ch->maxlen); return -EINVAL; } /* HW lock must be obtained */ /* check for pending next_skb */ if (ch->next_skb) { printk(KERN_WARNING - "%s: next_skb exist ERROR (skb->len=%d next_skb->len=%d)\n", - __func__, skb->len, ch->next_skb->len); + "%s: next_skb exist ERROR (skb->len=%d next_skb->len=%d)\n", + __func__, skb->len, ch->next_skb->len); return -EBUSY; } if (test_and_set_bit(FLG_TX_BUSY, &ch->Flags)) { @@ -359,7 +465,62 @@ bchannel_senddata(struct bchannel *ch, struct sk_buff *skb) /* write to fifo */ ch->tx_skb = skb; ch->tx_idx = 0; + confirm_Bsend(ch); return 1; } } EXPORT_SYMBOL(bchannel_senddata); + +/* The function allocates a new receive skb on demand with a size for the + * requirements of the current protocol. It returns the tailroom of the + * receive skb or an error. + */ +int +bchannel_get_rxbuf(struct bchannel *bch, int reqlen) +{ + int len; + + if (bch->rx_skb) { + len = skb_tailroom(bch->rx_skb); + if (len < reqlen) { + pr_warning("B%d no space for %d (only %d) bytes\n", + bch->nr, reqlen, len); + if (test_bit(FLG_TRANSPARENT, &bch->Flags)) { + /* send what we have now and try a new buffer */ + recv_Bchannel(bch, 0, true); + } else { + /* on HDLC we have to drop too big frames */ + return -EMSGSIZE; + } + } else { + return len; + } + } + /* update current min/max length first */ + if (unlikely(bch->maxlen != bch->next_maxlen)) + bch->maxlen = bch->next_maxlen; + if (unlikely(bch->minlen != bch->next_minlen)) + bch->minlen = bch->next_minlen; + if (unlikely(reqlen > bch->maxlen)) + return -EMSGSIZE; + if (test_bit(FLG_TRANSPARENT, &bch->Flags)) { + if (reqlen >= bch->minlen) { + len = reqlen; + } else { + len = 2 * bch->minlen; + if (len > bch->maxlen) + len = bch->maxlen; + } + } else { + /* with HDLC we do not know the length yet */ + len = bch->maxlen; + } + bch->rx_skb = mI_alloc_skb(len, GFP_ATOMIC); + if (!bch->rx_skb) { + pr_warning("B%d receive no memory for %d bytes\n", + bch->nr, len); + len = -ENOMEM; + } + return len; +} +EXPORT_SYMBOL(bchannel_get_rxbuf); diff --git a/drivers/isdn/mISDN/l1oip.h b/drivers/isdn/mISDN/l1oip.h index a23d575449f..661c060ada4 100644 --- a/drivers/isdn/mISDN/l1oip.h +++ b/drivers/isdn/mISDN/l1oip.h @@ -10,7 +10,7 @@ /* enable to disorder received bchannels by sequence 2143658798... */ /* -#define REORDER_DEBUG + #define REORDER_DEBUG */ /* frames */ @@ -29,8 +29,8 @@ /* channel structure */ struct l1oip_chan { - struct dchannel *dch; - struct bchannel *bch; + struct dchannel *dch; + struct bchannel *bch; u32 tx_counter; /* counts xmit bytes/packets */ u32 rx_counter; /* counts recv bytes/packets */ u32 codecstate; /* used by codec to save data */ @@ -60,23 +60,23 @@ struct l1oip { int limit; /* limit number of bchannels */ /* timer */ - struct timer_list keep_tl; - struct timer_list timeout_tl; + struct timer_list keep_tl; + struct timer_list timeout_tl; int timeout_on; struct work_struct workq; /* socket */ - struct socket *socket; /* if set, socket is created */ - struct completion socket_complete;/* completion of sock thread */ + struct socket *socket; /* if set, socket is created */ + struct completion socket_complete;/* completion of sock thread */ struct task_struct *socket_thread; - spinlock_t socket_lock; /* access sock outside thread */ + spinlock_t socket_lock; /* access sock outside thread */ u32 remoteip; /* if all set, ip is assigned */ - u16 localport; /* must always be set */ - u16 remoteport; /* must always be set */ + u16 localport; /* must always be set */ + u16 remoteport; /* must always be set */ struct sockaddr_in sin_local; /* local socket name */ struct sockaddr_in sin_remote; /* remote socket name */ struct msghdr sendmsg; /* ip message to send */ - struct iovec sendiov; /* iov for message */ + struct kvec sendiov; /* iov for message */ /* frame */ struct l1oip_chan chan[128]; /* channel instances */ @@ -88,4 +88,3 @@ extern int l1oip_alaw_to_ulaw(u8 *data, int len, u8 *result); extern int l1oip_ulaw_to_alaw(u8 *data, int len, u8 *result); extern void l1oip_4bit_free(void); extern int l1oip_4bit_alloc(int ulaw); - diff --git a/drivers/isdn/mISDN/l1oip_codec.c b/drivers/isdn/mISDN/l1oip_codec.c index a2dc4570ef4..a601c847222 100644 --- a/drivers/isdn/mISDN/l1oip_codec.c +++ b/drivers/isdn/mISDN/l1oip_codec.c @@ -27,28 +27,30 @@ /* -How the codec works: --------------------- + How the codec works: + -------------------- -The volume is increased to increase the dynamic range of the audio signal. -Each sample is converted to a-LAW with only 16 steps of level resolution. -A pair of two samples are stored in one byte. + The volume is increased to increase the dynamic range of the audio signal. + Each sample is converted to a-LAW with only 16 steps of level resolution. + A pair of two samples are stored in one byte. -The first byte is stored in the upper bits, the second byte is stored in the -lower bits. + The first byte is stored in the upper bits, the second byte is stored in the + lower bits. -To speed up compression and decompression, two lookup tables are formed: + To speed up compression and decompression, two lookup tables are formed: -- 16 bits index for two samples (law encoded) with 8 bit compressed result. -- 8 bits index for one compressed data with 16 bits decompressed result. + - 16 bits index for two samples (law encoded) with 8 bit compressed result. + - 8 bits index for one compressed data with 16 bits decompressed result. -NOTE: The bytes are handled as they are law-encoded. + NOTE: The bytes are handled as they are law-encoded. */ #include <linux/vmalloc.h> #include <linux/mISDNif.h> +#include <linux/in.h> #include "core.h" +#include "l1oip.h" /* definitions of codec. don't use calculations, code may run slower. */ @@ -230,7 +232,7 @@ l1oip_law_to_4bit(u8 *data, int len, u8 *result, u32 *state) /* send saved byte and first input byte */ if (*state) { - *result++ = table_com[(((*state)<<8)&0xff00) | (*data++)]; + *result++ = table_com[(((*state) << 8) & 0xff00) | (*data++)]; len--; o++; } @@ -265,7 +267,7 @@ l1oip_4bit_to_law(u8 *data, int len, u8 *result) while (i < len) { r = table_dec[*data++]; - *result++ = r>>8; + *result++ = r >> 8; *result++ = r; i++; } @@ -328,14 +330,12 @@ l1oip_4bit_alloc(int ulaw) return 0; /* alloc conversion tables */ - table_com = vmalloc(65536); - table_dec = vmalloc(512); - if (!table_com | !table_dec) { + table_com = vzalloc(65536); + table_dec = vzalloc(512); + if (!table_com || !table_dec) { l1oip_4bit_free(); return -ENOMEM; } - memset(table_com, 0, 65536); - memset(table_dec, 0, 512); /* generate compression table */ i1 = 0; while (i1 < 256) { @@ -345,8 +345,8 @@ l1oip_4bit_alloc(int ulaw) c = alaw_to_4bit[i1]; i2 = 0; while (i2 < 256) { - table_com[(i1<<8) | i2] |= (c<<4); - table_com[(i2<<8) | i1] |= c; + table_com[(i1 << 8) | i2] |= (c << 4); + table_com[(i2 << 8) | i1] |= c; i2++; } i1++; @@ -361,8 +361,8 @@ l1oip_4bit_alloc(int ulaw) sample = _4bit_to_alaw[i1]; i2 = 0; while (i2 < 16) { - table_dec[(i1<<4) | i2] |= (sample<<8); - table_dec[(i2<<4) | i1] |= sample; + table_dec[(i1 << 4) | i2] |= (sample << 8); + table_dec[(i2 << 4) | i1] |= sample; i2++; } i1++; @@ -370,5 +370,3 @@ l1oip_4bit_alloc(int ulaw) return 0; } - - diff --git a/drivers/isdn/mISDN/l1oip_core.c b/drivers/isdn/mISDN/l1oip_core.c index 155b99780c4..9f454d76cc0 100644 --- a/drivers/isdn/mISDN/l1oip_core.c +++ b/drivers/isdn/mISDN/l1oip_core.c @@ -24,63 +24,63 @@ /* module parameters: * type: - Value 1 = BRI - Value 2 = PRI - Value 3 = BRI (multi channel frame, not supported yet) - Value 4 = PRI (multi channel frame, not supported yet) - A multi channel frame reduces overhead to a single frame for all - b-channels, but increases delay. - (NOTE: Multi channel frames are not implemented yet.) + Value 1 = BRI + Value 2 = PRI + Value 3 = BRI (multi channel frame, not supported yet) + Value 4 = PRI (multi channel frame, not supported yet) + A multi channel frame reduces overhead to a single frame for all + b-channels, but increases delay. + (NOTE: Multi channel frames are not implemented yet.) * codec: - Value 0 = transparent (default) - Value 1 = transfer ALAW - Value 2 = transfer ULAW - Value 3 = transfer generic 4 bit compression. + Value 0 = transparent (default) + Value 1 = transfer ALAW + Value 2 = transfer ULAW + Value 3 = transfer generic 4 bit compression. * ulaw: - 0 = we use a-Law (default) - 1 = we use u-Law + 0 = we use a-Law (default) + 1 = we use u-Law * limit: - limitation of B-channels to control bandwidth (1...126) - BRI: 1 or 2 - PRI: 1-30, 31-126 (126, because dchannel ist not counted here) - Also limited ressources are used for stack, resulting in less channels. - It is possible to have more channels than 30 in PRI mode, this must - be supported by the application. + limitation of B-channels to control bandwidth (1...126) + BRI: 1 or 2 + PRI: 1-30, 31-126 (126, because dchannel ist not counted here) + Also limited ressources are used for stack, resulting in less channels. + It is possible to have more channels than 30 in PRI mode, this must + be supported by the application. * ip: - byte representation of remote ip address (127.0.0.1 -> 127,0,0,1) - If not given or four 0, no remote address is set. - For multiple interfaces, concat ip addresses. (127,0,0,1,127,0,0,1) + byte representation of remote ip address (127.0.0.1 -> 127,0,0,1) + If not given or four 0, no remote address is set. + For multiple interfaces, concat ip addresses. (127,0,0,1,127,0,0,1) * port: - port number (local interface) - If not given or 0, port 931 is used for fist instance, 932 for next... - For multiple interfaces, different ports must be given. + port number (local interface) + If not given or 0, port 931 is used for fist instance, 932 for next... + For multiple interfaces, different ports must be given. * remoteport: - port number (remote interface) - If not given or 0, remote port equals local port - For multiple interfaces on equal sites, different ports must be given. + port number (remote interface) + If not given or 0, remote port equals local port + For multiple interfaces on equal sites, different ports must be given. * ondemand: - 0 = fixed (always transmit packets, even when remote side timed out) - 1 = on demand (only transmit packets, when remote side is detected) - the default is 0 - NOTE: ID must also be set for on demand. + 0 = fixed (always transmit packets, even when remote side timed out) + 1 = on demand (only transmit packets, when remote side is detected) + the default is 0 + NOTE: ID must also be set for on demand. * id: - optional value to identify frames. This value must be equal on both - peers and should be random. If omitted or 0, no ID is transmitted. + optional value to identify frames. This value must be equal on both + peers and should be random. If omitted or 0, no ID is transmitted. * debug: - NOTE: only one debug value must be given for all cards - enable debugging (see l1oip.h for debug options) + NOTE: only one debug value must be given for all cards + enable debugging (see l1oip.h for debug options) -Special mISDN controls: + Special mISDN controls: op = MISDN_CTRL_SETPEER* p1 = bytes 0-3 : remote IP address in network order (left element first) @@ -91,133 +91,133 @@ Special mISDN controls: op = MISDN_CTRL_UNSETPEER* * Use l1oipctrl for comfortable setting or removing ip address. - (Layer 1 Over IP CTRL) + (Layer 1 Over IP CTRL) -L1oIP-Protocol --------------- + L1oIP-Protocol + -------------- -Frame Header: + Frame Header: 7 6 5 4 3 2 1 0 -+---------------+ -|Ver|T|I|Coding | -+---------------+ -| ID byte 3 * | -+---------------+ -| ID byte 2 * | -+---------------+ -| ID byte 1 * | -+---------------+ -| ID byte 0 * | -+---------------+ -|M| Channel | -+---------------+ -| Length * | -+---------------+ -| Time Base MSB | -+---------------+ -| Time Base LSB | -+---------------+ -| Data.... | - -... - -| | -+---------------+ -|M| Channel | -+---------------+ -| Length * | -+---------------+ -| Time Base MSB | -+---------------+ -| Time Base LSB | -+---------------+ -| Data.... | - -... - - -* Only included in some cases. - -- Ver = Version -If version is missmatch, the frame must be ignored. - -- T = Type of interface -Must be 0 for S0 or 1 for E1. - -- I = Id present -If bit is set, four ID bytes are included in frame. - -- ID = Connection ID -Additional ID to prevent Denial of Service attacs. Also it prevents hijacking -connections with dynamic IP. The ID should be random and must not be 0. - -- Coding = Type of codec -Must be 0 for no transcoding. Also for D-channel and other HDLC frames. + +---------------+ + |Ver|T|I|Coding | + +---------------+ + | ID byte 3 * | + +---------------+ + | ID byte 2 * | + +---------------+ + | ID byte 1 * | + +---------------+ + | ID byte 0 * | + +---------------+ + |M| Channel | + +---------------+ + | Length * | + +---------------+ + | Time Base MSB | + +---------------+ + | Time Base LSB | + +---------------+ + | Data.... | + + ... + + | | + +---------------+ + |M| Channel | + +---------------+ + | Length * | + +---------------+ + | Time Base MSB | + +---------------+ + | Time Base LSB | + +---------------+ + | Data.... | + + ... + + + * Only included in some cases. + + - Ver = Version + If version is missmatch, the frame must be ignored. + + - T = Type of interface + Must be 0 for S0 or 1 for E1. + + - I = Id present + If bit is set, four ID bytes are included in frame. + + - ID = Connection ID + Additional ID to prevent Denial of Service attacs. Also it prevents hijacking + connections with dynamic IP. The ID should be random and must not be 0. + + - Coding = Type of codec + Must be 0 for no transcoding. Also for D-channel and other HDLC frames. 1 and 2 are reserved for explicitly use of a-LAW or u-LAW codec. 3 is used for generic table compressor. -- M = More channels to come. If this flag is 1, the following byte contains -the length of the channel data. After the data block, the next channel will -be defined. The flag for the last channel block (or if only one channel is -transmitted), must be 0 and no length is given. + - M = More channels to come. If this flag is 1, the following byte contains + the length of the channel data. After the data block, the next channel will + be defined. The flag for the last channel block (or if only one channel is + transmitted), must be 0 and no length is given. -- Channel = Channel number -0 reserved -1-3 channel data for S0 (3 is D-channel) -1-31 channel data for E1 (16 is D-channel) -32-127 channel data for extended E1 (16 is D-channel) + - Channel = Channel number + 0 reserved + 1-3 channel data for S0 (3 is D-channel) + 1-31 channel data for E1 (16 is D-channel) + 32-127 channel data for extended E1 (16 is D-channel) -- The length is used if the M-flag is 1. It is used to find the next channel -inside frame. -NOTE: A value of 0 equals 256 bytes of data. + - The length is used if the M-flag is 1. It is used to find the next channel + inside frame. + NOTE: A value of 0 equals 256 bytes of data. -> For larger data blocks, a single frame must be used. -> For larger streams, a single frame or multiple blocks with same channel ID - must be used. + must be used. -- Time Base = Timestamp of first sample in frame -The "Time Base" is used to rearange packets and to detect packet loss. -The 16 bits are sent in network order (MSB first) and count 1/8000 th of a -second. This causes a wrap arround each 8,192 seconds. There is no requirement -for the initial "Time Base", but 0 should be used for the first packet. -In case of HDLC data, this timestamp counts the packet or byte number. + - Time Base = Timestamp of first sample in frame + The "Time Base" is used to rearange packets and to detect packet loss. + The 16 bits are sent in network order (MSB first) and count 1/8000 th of a + second. This causes a wrap around each 8,192 seconds. There is no requirement + for the initial "Time Base", but 0 should be used for the first packet. + In case of HDLC data, this timestamp counts the packet or byte number. -Two Timers: + Two Timers: -After initialisation, a timer of 15 seconds is started. Whenever a packet is -transmitted, the timer is reset to 15 seconds again. If the timer expires, an -empty packet is transmitted. This keep the connection alive. + After initialisation, a timer of 15 seconds is started. Whenever a packet is + transmitted, the timer is reset to 15 seconds again. If the timer expires, an + empty packet is transmitted. This keep the connection alive. -When a valid packet is received, a timer 65 seconds is started. The interface -become ACTIVE. If the timer expires, the interface becomes INACTIVE. + When a valid packet is received, a timer 65 seconds is started. The interface + become ACTIVE. If the timer expires, the interface becomes INACTIVE. -Dynamic IP handling: + Dynamic IP handling: -To allow dynamic IP, the ID must be non 0. In this case, any packet with the -correct port number and ID will be accepted. If the remote side changes its IP -the new IP is used for all transmitted packets until it changes again. + To allow dynamic IP, the ID must be non 0. In this case, any packet with the + correct port number and ID will be accepted. If the remote side changes its IP + the new IP is used for all transmitted packets until it changes again. -On Demand: + On Demand: -If the ondemand parameter is given, the remote IP is set to 0 on timeout. -This will stop keepalive traffic to remote. If the remote is online again, -traffic will continue to the remote address. This is usefull for road warriors. -This feature only works with ID set, otherwhise it is highly unsecure. + If the ondemand parameter is given, the remote IP is set to 0 on timeout. + This will stop keepalive traffic to remote. If the remote is online again, + traffic will continue to the remote address. This is useful for road warriors. + This feature only works with ID set, otherwhise it is highly unsecure. -Socket and Thread ------------------ + Socket and Thread + ----------------- -The complete socket opening and closing is done by a thread. -When the thread opened a socket, the hc->socket descriptor is set. Whenever a -packet shall be sent to the socket, the hc->socket must be checked wheter not -NULL. To prevent change in socket descriptor, the hc->socket_lock must be used. -To change the socket, a recall of l1oip_socket_open() will safely kill the -socket process and create a new one. + The complete socket opening and closing is done by a thread. + When the thread opened a socket, the hc->socket descriptor is set. Whenever a + packet shall be sent to the socket, the hc->socket must be checked wheter not + NULL. To prevent change in socket descriptor, the hc->socket_lock must be used. + To change the socket, a recall of l1oip_socket_open() will safely kill the + socket process and create a new one. */ @@ -233,6 +233,7 @@ socket process and create a new one. #include <linux/inet.h> #include <linux/workqueue.h> #include <linux/kthread.h> +#include <linux/slab.h> #include <net/sock.h> #include "core.h" #include "l1oip.h" @@ -246,7 +247,7 @@ static struct list_head l1oip_ilist; #define MAX_CARDS 16 static u_int type[MAX_CARDS]; static u_int codec[MAX_CARDS]; -static u_int ip[MAX_CARDS*4]; +static u_int ip[MAX_CARDS * 4]; static u_int port[MAX_CARDS]; static u_int remoteport[MAX_CARDS]; static u_int ondemand[MAX_CARDS]; @@ -273,27 +274,23 @@ module_param(debug, uint, S_IRUGO | S_IWUSR); */ static int l1oip_socket_send(struct l1oip *hc, u8 localcodec, u8 channel, u32 chanmask, - u16 timebase, u8 *buf, int len) + u16 timebase, u8 *buf, int len) { u8 *p; - int multi = 0; - u8 frame[len+32]; + u8 frame[len + 32]; struct socket *socket = NULL; - mm_segment_t oldfs; if (debug & DEBUG_L1OIP_MSG) printk(KERN_DEBUG "%s: sending data to socket (len = %d)\n", - __func__, len); + __func__, len); p = frame; /* restart timer */ - if ((int)(hc->keep_tl.expires-jiffies) < 5*HZ) { - del_timer(&hc->keep_tl); - hc->keep_tl.expires = jiffies + L1OIP_KEEPALIVE*HZ; - add_timer(&hc->keep_tl); - } else - hc->keep_tl.expires = jiffies + L1OIP_KEEPALIVE*HZ; + if (time_before(hc->keep_tl.expires, jiffies + 5 * HZ)) + mod_timer(&hc->keep_tl, jiffies + L1OIP_KEEPALIVE * HZ); + else + hc->keep_tl.expires = jiffies + L1OIP_KEEPALIVE * HZ; if (debug & DEBUG_L1OIP_MSG) printk(KERN_DEBUG "%s: resetting timer\n", __func__); @@ -302,25 +299,23 @@ l1oip_socket_send(struct l1oip *hc, u8 localcodec, u8 channel, u32 chanmask, if (!hc->sin_remote.sin_addr.s_addr || !hc->sin_remote.sin_port) { if (debug & DEBUG_L1OIP_MSG) printk(KERN_DEBUG "%s: dropping frame, because remote " - "IP is not set.\n", __func__); + "IP is not set.\n", __func__); return len; } /* assemble frame */ - *p++ = (L1OIP_VERSION<<6) /* version and coding */ - | (hc->pri?0x20:0x00) /* type */ - | (hc->id?0x10:0x00) /* id */ - | localcodec; + *p++ = (L1OIP_VERSION << 6) /* version and coding */ + | (hc->pri ? 0x20 : 0x00) /* type */ + | (hc->id ? 0x10 : 0x00) /* id */ + | localcodec; if (hc->id) { - *p++ = hc->id>>24; /* id */ - *p++ = hc->id>>16; - *p++ = hc->id>>8; + *p++ = hc->id >> 24; /* id */ + *p++ = hc->id >> 16; + *p++ = hc->id >> 8; *p++ = hc->id; } - *p++ = (multi == 1)?0x80:0x00 + channel; /* m-flag, channel */ - if (multi == 1) - *p++ = len; /* length */ - *p++ = timebase>>8; /* time base */ + *p++ = 0x00 + channel; /* m-flag, channel */ + *p++ = timebase >> 8; /* time base */ *p++ = timebase; if (buf && len) { /* add data to frame */ @@ -330,7 +325,7 @@ l1oip_socket_send(struct l1oip *hc, u8 localcodec, u8 channel, u32 chanmask, l1oip_alaw_to_ulaw(buf, len, p); else if (localcodec == 3) len = l1oip_law_to_4bit(buf, len, p, - &hc->chan[channel].codecstate); + &hc->chan[channel].codecstate); else memcpy(p, buf, len); } @@ -349,13 +344,10 @@ l1oip_socket_send(struct l1oip *hc, u8 localcodec, u8 channel, u32 chanmask, /* send packet */ if (debug & DEBUG_L1OIP_MSG) printk(KERN_DEBUG "%s: sending packet to socket (len " - "= %d)\n", __func__, len); + "= %d)\n", __func__, len); hc->sendiov.iov_base = frame; hc->sendiov.iov_len = len; - oldfs = get_fs(); - set_fs(KERNEL_DS); - len = sock_sendmsg(socket, &hc->sendmsg, len); - set_fs(oldfs); + len = kernel_sendmsg(socket, &hc->sendmsg, &hc->sendiov, 1, len); /* give socket back */ hc->socket = socket; /* no locking required */ @@ -368,7 +360,7 @@ l1oip_socket_send(struct l1oip *hc, u8 localcodec, u8 channel, u32 chanmask, */ static void l1oip_socket_recv(struct l1oip *hc, u8 remotecodec, u8 channel, u16 timebase, - u8 *buf, int len) + u8 *buf, int len) { struct sk_buff *nskb; struct bchannel *bch; @@ -379,34 +371,34 @@ l1oip_socket_recv(struct l1oip *hc, u8 remotecodec, u8 channel, u16 timebase, if (len == 0) { if (debug & DEBUG_L1OIP_MSG) printk(KERN_DEBUG "%s: received empty keepalive data, " - "ignoring\n", __func__); + "ignoring\n", __func__); return; } if (debug & DEBUG_L1OIP_MSG) printk(KERN_DEBUG "%s: received data, sending to mISDN (%d)\n", - __func__, len); + __func__, len); if (channel < 1 || channel > 127) { printk(KERN_WARNING "%s: packet error - channel %d out of " - "range\n", __func__, channel); + "range\n", __func__, channel); return; } dch = hc->chan[channel].dch; bch = hc->chan[channel].bch; if (!dch && !bch) { printk(KERN_WARNING "%s: packet error - channel %d not in " - "stack\n", __func__, channel); + "stack\n", __func__, channel); return; } /* prepare message */ - nskb = mI_alloc_skb((remotecodec == 3)?(len<<1):len, GFP_ATOMIC); + nskb = mI_alloc_skb((remotecodec == 3) ? (len << 1) : len, GFP_ATOMIC); if (!nskb) { printk(KERN_ERR "%s: No mem for skb.\n", __func__); return; } - p = skb_put(nskb, (remotecodec == 3)?(len<<1):len); + p = skb_put(nskb, (remotecodec == 3) ? (len << 1) : len); if (remotecodec == 1 && ulaw) l1oip_alaw_to_ulaw(buf, len, p); @@ -431,7 +423,7 @@ l1oip_socket_recv(struct l1oip *hc, u8 remotecodec, u8 channel, u16 timebase, rx_counter = (rx_counter & 0xffff0000) | timebase; else - rx_counter = ((rx_counter & 0xffff0000)+0x10000) + rx_counter = ((rx_counter & 0xffff0000) + 0x10000) | timebase; } else { /* time has changed backwards */ @@ -439,7 +431,7 @@ l1oip_socket_recv(struct l1oip *hc, u8 remotecodec, u8 channel, u16 timebase, rx_counter = (rx_counter & 0xffff0000) | timebase; else - rx_counter = ((rx_counter & 0xffff0000)-0x10000) + rx_counter = ((rx_counter & 0xffff0000) - 0x10000) | timebase; } hc->chan[channel].rx_counter = rx_counter; @@ -458,7 +450,7 @@ l1oip_socket_recv(struct l1oip *hc, u8 remotecodec, u8 channel, u16 timebase, hc->chan[channel].disorder_flag ^= 1; if (nskb) #endif - queue_ch_frame(&bch->ch, PH_DATA_IND, rx_counter, nskb); + queue_ch_frame(&bch->ch, PH_DATA_IND, rx_counter, nskb); } } @@ -469,7 +461,7 @@ l1oip_socket_recv(struct l1oip *hc, u8 remotecodec, u8 channel, u16 timebase, static void l1oip_socket_parse(struct l1oip *hc, struct sockaddr_in *sin, u8 *buf, int len) { - u32 id; + u32 packet_id; u8 channel; u8 remotecodec; u16 timebase; @@ -479,75 +471,75 @@ l1oip_socket_parse(struct l1oip *hc, struct sockaddr_in *sin, u8 *buf, int len) if (debug & DEBUG_L1OIP_MSG) printk(KERN_DEBUG "%s: received frame, parsing... (%d)\n", - __func__, len); + __func__, len); - /* check lenght */ - if (len < 1+1+2) { + /* check length */ + if (len < 1 + 1 + 2) { printk(KERN_WARNING "%s: packet error - length %d below " - "4 bytes\n", __func__, len); + "4 bytes\n", __func__, len); return; } /* check version */ - if (((*buf)>>6) != L1OIP_VERSION) { + if (((*buf) >> 6) != L1OIP_VERSION) { printk(KERN_WARNING "%s: packet error - unknown version %d\n", - __func__, buf[0]>>6); + __func__, buf[0]>>6); return; } /* check type */ - if (((*buf)&0x20) && !hc->pri) { + if (((*buf) & 0x20) && !hc->pri) { printk(KERN_WARNING "%s: packet error - received E1 packet " - "on S0 interface\n", __func__); + "on S0 interface\n", __func__); return; } - if (!((*buf)&0x20) && hc->pri) { + if (!((*buf) & 0x20) && hc->pri) { printk(KERN_WARNING "%s: packet error - received S0 packet " - "on E1 interface\n", __func__); + "on E1 interface\n", __func__); return; } /* get id flag */ - id = (*buf>>4)&1; + packet_id = (*buf >> 4) & 1; /* check coding */ remotecodec = (*buf) & 0x0f; if (remotecodec > 3) { printk(KERN_WARNING "%s: packet error - remotecodec %d " - "unsupported\n", __func__, remotecodec); + "unsupported\n", __func__, remotecodec); return; } buf++; len--; - /* check id */ - if (id) { + /* check packet_id */ + if (packet_id) { if (!hc->id) { printk(KERN_WARNING "%s: packet error - packet has id " - "0x%x, but we have not\n", __func__, id); + "0x%x, but we have not\n", __func__, packet_id); return; } if (len < 4) { printk(KERN_WARNING "%s: packet error - packet too " - "short for ID value\n", __func__); + "short for ID value\n", __func__); return; } - id = (*buf++) << 24; - id += (*buf++) << 16; - id += (*buf++) << 8; - id += (*buf++); + packet_id = (*buf++) << 24; + packet_id += (*buf++) << 16; + packet_id += (*buf++) << 8; + packet_id += (*buf++); len -= 4; - if (id != hc->id) { + if (packet_id != hc->id) { printk(KERN_WARNING "%s: packet error - ID mismatch, " - "got 0x%x, we 0x%x\n", - __func__, id, hc->id); + "got 0x%x, we 0x%x\n", + __func__, packet_id, hc->id); return; } } else { if (hc->id) { printk(KERN_WARNING "%s: packet error - packet has no " - "ID, but we have\n", __func__); + "ID, but we have\n", __func__); return; } } @@ -555,13 +547,13 @@ l1oip_socket_parse(struct l1oip *hc, struct sockaddr_in *sin, u8 *buf, int len) multiframe: if (len < 1) { printk(KERN_WARNING "%s: packet error - packet too short, " - "channel expected at position %d.\n", - __func__, len-len_start+1); + "channel expected at position %d.\n", + __func__, len-len_start + 1); return; } /* get channel and multiframe flag */ - channel = *buf&0x7f; + channel = *buf & 0x7f; m = *buf >> 7; buf++; len--; @@ -570,8 +562,8 @@ multiframe: if (m) { if (len < 1) { printk(KERN_WARNING "%s: packet error - packet too " - "short, length expected at position %d.\n", - __func__, len_start-len-1); + "short, length expected at position %d.\n", + __func__, len_start - len - 1); return; } @@ -579,26 +571,26 @@ multiframe: len--; if (mlen == 0) mlen = 256; - if (len < mlen+3) { + if (len < mlen + 3) { printk(KERN_WARNING "%s: packet error - length %d at " - "position %d exceeds total length %d.\n", - __func__, mlen, len_start-len-1, len_start); + "position %d exceeds total length %d.\n", + __func__, mlen, len_start-len - 1, len_start); return; } - if (len == mlen+3) { + if (len == mlen + 3) { printk(KERN_WARNING "%s: packet error - length %d at " - "position %d will not allow additional " - "packet.\n", - __func__, mlen, len_start-len+1); + "position %d will not allow additional " + "packet.\n", + __func__, mlen, len_start-len + 1); return; } } else - mlen = len-2; /* single frame, substract timebase */ + mlen = len - 2; /* single frame, subtract timebase */ if (len < 2) { printk(KERN_WARNING "%s: packet error - packet too short, time " - "base expected at position %d.\n", - __func__, len-len_start+1); + "base expected at position %d.\n", + __func__, len-len_start + 1); return; } @@ -609,12 +601,12 @@ multiframe: /* if inactive, we send up a PH_ACTIVATE and activate */ if (!test_bit(FLG_ACTIVE, &dch->Flags)) { - if (debug & (DEBUG_L1OIP_MSG|DEBUG_L1OIP_SOCKET)) + if (debug & (DEBUG_L1OIP_MSG | DEBUG_L1OIP_SOCKET)) printk(KERN_DEBUG "%s: interface become active due to " - "received packet\n", __func__); + "received packet\n", __func__); test_and_set_bit(FLG_ACTIVE, &dch->Flags); _queue_data(&dch->dev.D, PH_ACTIVATE_IND, MISDN_ID_ANY, 0, - NULL, GFP_ATOMIC); + NULL, GFP_ATOMIC); } /* distribute packet */ @@ -627,24 +619,22 @@ multiframe: goto multiframe; /* restart timer */ - if ((int)(hc->timeout_tl.expires-jiffies) < 5*HZ || !hc->timeout_on) { + if (time_before(hc->timeout_tl.expires, jiffies + 5 * HZ) || !hc->timeout_on) { hc->timeout_on = 1; - del_timer(&hc->timeout_tl); - hc->timeout_tl.expires = jiffies + L1OIP_TIMEOUT*HZ; - add_timer(&hc->timeout_tl); + mod_timer(&hc->timeout_tl, jiffies + L1OIP_TIMEOUT * HZ); } else /* only adjust timer */ - hc->timeout_tl.expires = jiffies + L1OIP_TIMEOUT*HZ; + hc->timeout_tl.expires = jiffies + L1OIP_TIMEOUT * HZ; /* if ip or source port changes */ if ((hc->sin_remote.sin_addr.s_addr != sin->sin_addr.s_addr) - || (hc->sin_remote.sin_port != sin->sin_port)) { + || (hc->sin_remote.sin_port != sin->sin_port)) { if (debug & DEBUG_L1OIP_SOCKET) printk(KERN_DEBUG "%s: remote address changes from " - "0x%08x to 0x%08x (port %d to %d)\n", __func__, - ntohl(hc->sin_remote.sin_addr.s_addr), - ntohl(sin->sin_addr.s_addr), - ntohs(hc->sin_remote.sin_port), - ntohs(sin->sin_port)); + "0x%08x to 0x%08x (port %d to %d)\n", __func__, + ntohl(hc->sin_remote.sin_addr.s_addr), + ntohl(sin->sin_addr.s_addr), + ntohs(hc->sin_remote.sin_port), + ntohs(sin->sin_port)); hc->sin_remote.sin_addr.s_addr = sin->sin_addr.s_addr; hc->sin_remote.sin_port = sin->sin_port; } @@ -660,13 +650,20 @@ l1oip_socket_thread(void *data) struct l1oip *hc = (struct l1oip *)data; int ret = 0; struct msghdr msg; - struct iovec iov; - mm_segment_t oldfs; struct sockaddr_in sin_rx; - unsigned char recvbuf[1500]; + unsigned char *recvbuf; + size_t recvbuf_size = 1500; int recvlen; struct socket *socket = NULL; - DECLARE_COMPLETION(wait); + DECLARE_COMPLETION_ONSTACK(wait); + + /* allocate buffer memory */ + recvbuf = kmalloc(recvbuf_size, GFP_KERNEL); + if (!recvbuf) { + printk(KERN_ERR "%s: Failed to alloc recvbuf.\n", __func__); + ret = -ENOMEM; + goto fail; + } /* make daemon */ allow_signal(SIGTERM); @@ -674,7 +671,8 @@ l1oip_socket_thread(void *data) /* create socket */ if (sock_create(PF_INET, SOCK_DGRAM, IPPROTO_UDP, &socket)) { printk(KERN_ERR "%s: Failed to create socket.\n", __func__); - return -EIO; + ret = -EIO; + goto fail; } /* set incoming address */ @@ -687,11 +685,11 @@ l1oip_socket_thread(void *data) hc->sin_remote.sin_addr.s_addr = htonl(hc->remoteip); hc->sin_remote.sin_port = htons((unsigned short)hc->remoteport); - /* bind to incomming port */ + /* bind to incoming port */ if (socket->ops->bind(socket, (struct sockaddr *)&hc->sin_local, - sizeof(hc->sin_local))) { + sizeof(hc->sin_local))) { printk(KERN_ERR "%s: Failed to bind socket to port %d.\n", - __func__, hc->localport); + __func__, hc->localport); ret = -EINVAL; goto fail; } @@ -708,16 +706,12 @@ l1oip_socket_thread(void *data) msg.msg_namelen = sizeof(sin_rx); msg.msg_control = NULL; msg.msg_controllen = 0; - msg.msg_iov = &iov; - msg.msg_iovlen = 1; /* build send message */ hc->sendmsg.msg_name = &hc->sin_remote; hc->sendmsg.msg_namelen = sizeof(hc->sin_remote); hc->sendmsg.msg_control = NULL; hc->sendmsg.msg_controllen = 0; - hc->sendmsg.msg_iov = &hc->sendiov; - hc->sendmsg.msg_iovlen = 1; /* give away socket */ spin_lock(&hc->socket_lock); @@ -727,20 +721,20 @@ l1oip_socket_thread(void *data) /* read loop */ if (debug & DEBUG_L1OIP_SOCKET) printk(KERN_DEBUG "%s: socket created and open\n", - __func__); + __func__); while (!signal_pending(current)) { - iov.iov_base = recvbuf; - iov.iov_len = sizeof(recvbuf); - oldfs = get_fs(); - set_fs(KERNEL_DS); - recvlen = sock_recvmsg(socket, &msg, sizeof(recvbuf), 0); - set_fs(oldfs); + struct kvec iov = { + .iov_base = recvbuf, + .iov_len = recvbuf_size, + }; + recvlen = kernel_recvmsg(socket, &msg, &iov, 1, + recvbuf_size, 0); if (recvlen > 0) { l1oip_socket_parse(hc, &sin_rx, recvbuf, recvlen); } else { if (debug & DEBUG_L1OIP_SOCKET) - printk(KERN_WARNING "%s: broken pipe on socket\n", - __func__); + printk(KERN_WARNING + "%s: broken pipe on socket\n", __func__); } } @@ -749,7 +743,7 @@ l1oip_socket_thread(void *data) /* if hc->socket is NULL, it is in use until it is given back */ while (!hc->socket) { spin_unlock(&hc->socket_lock); - schedule_timeout(HZ/10); + schedule_timeout(HZ / 10); spin_lock(&hc->socket_lock); } hc->socket = NULL; @@ -757,9 +751,12 @@ l1oip_socket_thread(void *data) if (debug & DEBUG_L1OIP_SOCKET) printk(KERN_DEBUG "%s: socket thread terminating\n", - __func__); + __func__); fail: + /* free recvbuf */ + kfree(recvbuf); + /* close socket */ if (socket) sock_release(socket); @@ -770,21 +767,33 @@ fail: if (debug & DEBUG_L1OIP_SOCKET) printk(KERN_DEBUG "%s: socket thread terminated\n", - __func__); + __func__); return ret; } static void l1oip_socket_close(struct l1oip *hc) { + struct dchannel *dch = hc->chan[hc->d_idx].dch; + /* kill thread */ if (hc->socket_thread) { if (debug & DEBUG_L1OIP_SOCKET) printk(KERN_DEBUG "%s: socket thread exists, " - "killing...\n", __func__); + "killing...\n", __func__); send_sig(SIGTERM, hc->socket_thread, 0); wait_for_completion(&hc->socket_complete); } + + /* if active, we send up a PH_DEACTIVATE and deactivate */ + if (test_bit(FLG_ACTIVE, &dch->Flags)) { + if (debug & (DEBUG_L1OIP_MSG | DEBUG_L1OIP_SOCKET)) + printk(KERN_DEBUG "%s: interface become deactivated " + "due to timeout\n", __func__); + test_and_clear_bit(FLG_ACTIVE, &dch->Flags); + _queue_data(&dch->dev.D, PH_DEACTIVATE_IND, MISDN_ID_ANY, 0, + NULL, GFP_ATOMIC); + } } static int @@ -797,11 +806,11 @@ l1oip_socket_open(struct l1oip *hc) /* create receive process */ hc->socket_thread = kthread_run(l1oip_socket_thread, hc, "l1oip_%s", - hc->name); + hc->name); if (IS_ERR(hc->socket_thread)) { int err = PTR_ERR(hc->socket_thread); printk(KERN_ERR "%s: Failed (%d) to create socket process.\n", - __func__, err); + __func__, err); hc->socket_thread = NULL; sock_release(hc->socket); return err; @@ -818,9 +827,9 @@ l1oip_send_bh(struct work_struct *work) { struct l1oip *hc = container_of(work, struct l1oip, workq); - if (debug & (DEBUG_L1OIP_MSG|DEBUG_L1OIP_SOCKET)) + if (debug & (DEBUG_L1OIP_MSG | DEBUG_L1OIP_SOCKET)) printk(KERN_DEBUG "%s: keepalive timer expired, sending empty " - "frame on dchannel\n", __func__); + "frame on dchannel\n", __func__); /* send an empty l1oip frame at D-channel */ l1oip_socket_send(hc, 0, hc->d_idx, 0, 0, NULL, 0); @@ -846,25 +855,25 @@ l1oip_timeout(void *data) if (debug & DEBUG_L1OIP_MSG) printk(KERN_DEBUG "%s: timeout timer expired, turn layer one " - "down.\n", __func__); + "down.\n", __func__); hc->timeout_on = 0; /* state that timer must be initialized next time */ /* if timeout, we send up a PH_DEACTIVATE and deactivate */ if (test_bit(FLG_ACTIVE, &dch->Flags)) { - if (debug & (DEBUG_L1OIP_MSG|DEBUG_L1OIP_SOCKET)) + if (debug & (DEBUG_L1OIP_MSG | DEBUG_L1OIP_SOCKET)) printk(KERN_DEBUG "%s: interface become deactivated " - "due to timeout\n", __func__); + "due to timeout\n", __func__); test_and_clear_bit(FLG_ACTIVE, &dch->Flags); _queue_data(&dch->dev.D, PH_DEACTIVATE_IND, MISDN_ID_ANY, 0, - NULL, GFP_ATOMIC); + NULL, GFP_ATOMIC); } /* if we have ondemand set, we remove ip address */ if (hc->ondemand) { if (debug & DEBUG_L1OIP_MSG) printk(KERN_DEBUG "%s: on demand causes ip address to " - "be removed\n", __func__); + "be removed\n", __func__); hc->sin_remote.sin_addr.s_addr = 0; } } @@ -888,21 +897,21 @@ handle_dmsg(struct mISDNchannel *ch, struct sk_buff *skb) case PH_DATA_REQ: if (skb->len < 1) { printk(KERN_WARNING "%s: skb too small\n", - __func__); + __func__); break; } if (skb->len > MAX_DFRAME_LEN_L1 || skb->len > L1OIP_MAX_LEN) { printk(KERN_WARNING "%s: skb too large\n", - __func__); + __func__); break; } /* send frame */ p = skb->data; l = skb->len; while (l) { - ll = (l < L1OIP_MAX_PERFRAME)?l:L1OIP_MAX_PERFRAME; + ll = (l < L1OIP_MAX_PERFRAME) ? l : L1OIP_MAX_PERFRAME; l1oip_socket_send(hc, 0, dch->slot, 0, - hc->chan[dch->slot].tx_counter++, p, ll); + hc->chan[dch->slot].tx_counter++, p, ll); p += ll; l -= ll; } @@ -910,9 +919,9 @@ handle_dmsg(struct mISDNchannel *ch, struct sk_buff *skb) queue_ch_frame(ch, PH_DATA_CNF, hh->id, skb); return 0; case PH_ACTIVATE_REQ: - if (debug & (DEBUG_L1OIP_MSG|DEBUG_L1OIP_SOCKET)) + if (debug & (DEBUG_L1OIP_MSG | DEBUG_L1OIP_SOCKET)) printk(KERN_DEBUG "%s: PH_ACTIVATE channel %d (1..%d)\n" - , __func__, dch->slot, hc->b_num+1); + , __func__, dch->slot, hc->b_num + 1); skb_trim(skb, 0); if (test_bit(FLG_ACTIVE, &dch->Flags)) queue_ch_frame(ch, PH_ACTIVATE_IND, hh->id, skb); @@ -920,10 +929,10 @@ handle_dmsg(struct mISDNchannel *ch, struct sk_buff *skb) queue_ch_frame(ch, PH_DEACTIVATE_IND, hh->id, skb); return 0; case PH_DEACTIVATE_REQ: - if (debug & (DEBUG_L1OIP_MSG|DEBUG_L1OIP_SOCKET)) + if (debug & (DEBUG_L1OIP_MSG | DEBUG_L1OIP_SOCKET)) printk(KERN_DEBUG "%s: PH_DEACTIVATE channel %d " - "(1..%d)\n", __func__, dch->slot, - hc->b_num+1); + "(1..%d)\n", __func__, dch->slot, + hc->b_num + 1); skb_trim(skb, 0); if (test_bit(FLG_ACTIVE, &dch->Flags)) queue_ch_frame(ch, PH_ACTIVATE_IND, hh->id, skb); @@ -944,7 +953,8 @@ channel_dctrl(struct dchannel *dch, struct mISDN_ctrl_req *cq) switch (cq->op) { case MISDN_CTRL_GETOP: - cq->op = MISDN_CTRL_SETPEER | MISDN_CTRL_UNSETPEER; + cq->op = MISDN_CTRL_SETPEER | MISDN_CTRL_UNSETPEER + | MISDN_CTRL_GETPEER; break; case MISDN_CTRL_SETPEER: hc->remoteip = (u32)cq->p1; @@ -954,19 +964,26 @@ channel_dctrl(struct dchannel *dch, struct mISDN_ctrl_req *cq) hc->remoteport = hc->localport; if (debug & DEBUG_L1OIP_SOCKET) printk(KERN_DEBUG "%s: got new ip address from user " - "space.\n", __func__); - l1oip_socket_open(hc); + "space.\n", __func__); + l1oip_socket_open(hc); break; case MISDN_CTRL_UNSETPEER: if (debug & DEBUG_L1OIP_SOCKET) printk(KERN_DEBUG "%s: removing ip address.\n", - __func__); + __func__); hc->remoteip = 0; l1oip_socket_open(hc); break; + case MISDN_CTRL_GETPEER: + if (debug & DEBUG_L1OIP_SOCKET) + printk(KERN_DEBUG "%s: getting ip address.\n", + __func__); + cq->p1 = hc->remoteip; + cq->p2 = hc->remoteport | (hc->localport << 16); + break; default: printk(KERN_WARNING "%s: unknown Op %x\n", - __func__, cq->op); + __func__, cq->op); ret = -EINVAL; break; } @@ -978,21 +995,21 @@ open_dchannel(struct l1oip *hc, struct dchannel *dch, struct channel_req *rq) { if (debug & DEBUG_HW_OPEN) printk(KERN_DEBUG "%s: dev(%d) open from %p\n", __func__, - dch->dev.id, __builtin_return_address(0)); + dch->dev.id, __builtin_return_address(0)); if (rq->protocol == ISDN_P_NONE) return -EINVAL; if ((dch->dev.D.protocol != ISDN_P_NONE) && (dch->dev.D.protocol != rq->protocol)) { if (debug & DEBUG_HW_OPEN) printk(KERN_WARNING "%s: change protocol %x to %x\n", - __func__, dch->dev.D.protocol, rq->protocol); + __func__, dch->dev.D.protocol, rq->protocol); } if (dch->dev.D.protocol != rq->protocol) dch->dev.D.protocol = rq->protocol; if (test_bit(FLG_ACTIVE, &dch->Flags)) { _queue_data(&dch->dev.D, PH_ACTIVATE_IND, MISDN_ID_ANY, - 0, NULL, GFP_KERNEL); + 0, NULL, GFP_KERNEL); } rq->ch = &dch->dev.D; if (!try_module_get(THIS_MODULE)) @@ -1006,8 +1023,7 @@ open_bchannel(struct l1oip *hc, struct dchannel *dch, struct channel_req *rq) struct bchannel *bch; int ch; - if (!test_bit(rq->adr.channel & 0x1f, - &dch->dev.channelmap[rq->adr.channel >> 5])) + if (!test_channelmap(rq->adr.channel, dch->dev.channelmap)) return -EINVAL; if (rq->protocol == ISDN_P_NONE) return -EINVAL; @@ -1015,7 +1031,7 @@ open_bchannel(struct l1oip *hc, struct dchannel *dch, struct channel_req *rq) bch = hc->chan[ch].bch; if (!bch) { printk(KERN_ERR "%s:internal error ch %d has no bch\n", - __func__, ch); + __func__, ch); return -EINVAL; } if (test_and_set_bit(FLG_OPEN, &bch->Flags)) @@ -1038,7 +1054,7 @@ l1oip_dctrl(struct mISDNchannel *ch, u_int cmd, void *arg) if (dch->debug & DEBUG_HW) printk(KERN_DEBUG "%s: cmd:%x %p\n", - __func__, cmd, arg); + __func__, cmd, arg); switch (cmd) { case OPEN_CHANNEL: rq = arg; @@ -1066,8 +1082,8 @@ l1oip_dctrl(struct mISDNchannel *ch, u_int cmd, void *arg) case CLOSE_CHANNEL: if (debug & DEBUG_HW_OPEN) printk(KERN_DEBUG "%s: dev(%d) close from %p\n", - __func__, dch->dev.id, - __builtin_return_address(0)); + __func__, dch->dev.id, + __builtin_return_address(0)); module_put(THIS_MODULE); break; case CONTROL_CHANNEL: @@ -1076,7 +1092,7 @@ l1oip_dctrl(struct mISDNchannel *ch, u_int cmd, void *arg) default: if (dch->debug & DEBUG_HW) printk(KERN_DEBUG "%s: unknown command %x\n", - __func__, cmd); + __func__, cmd); err = -EINVAL; } return err; @@ -1089,48 +1105,38 @@ handle_bmsg(struct mISDNchannel *ch, struct sk_buff *skb) struct l1oip *hc = bch->hw; int ret = -EINVAL; struct mISDNhead *hh = mISDN_HEAD_P(skb); - int l, ll, i; + int l, ll; unsigned char *p; switch (hh->prim) { case PH_DATA_REQ: if (skb->len <= 0) { printk(KERN_WARNING "%s: skb too small\n", - __func__); + __func__); break; } if (skb->len > MAX_DFRAME_LEN_L1 || skb->len > L1OIP_MAX_LEN) { printk(KERN_WARNING "%s: skb too large\n", - __func__); + __func__); break; } /* check for AIS / ulaw-silence */ - p = skb->data; l = skb->len; - for (i = 0; i < l; i++) { - if (*p++ != 0xff) - break; - } - if (i == l) { + if (!memchr_inv(skb->data, 0xff, l)) { if (debug & DEBUG_L1OIP_MSG) printk(KERN_DEBUG "%s: got AIS, not sending, " - "but counting\n", __func__); + "but counting\n", __func__); hc->chan[bch->slot].tx_counter += l; skb_trim(skb, 0); queue_ch_frame(ch, PH_DATA_CNF, hh->id, skb); return 0; } /* check for silence */ - p = skb->data; l = skb->len; - for (i = 0; i < l; i++) { - if (*p++ != 0x2a) - break; - } - if (i == l) { + if (!memchr_inv(skb->data, 0x2a, l)) { if (debug & DEBUG_L1OIP_MSG) printk(KERN_DEBUG "%s: got silence, not sending" - ", but counting\n", __func__); + ", but counting\n", __func__); hc->chan[bch->slot].tx_counter += l; skb_trim(skb, 0); queue_ch_frame(ch, PH_DATA_CNF, hh->id, skb); @@ -1141,9 +1147,9 @@ handle_bmsg(struct mISDNchannel *ch, struct sk_buff *skb) p = skb->data; l = skb->len; while (l) { - ll = (l < L1OIP_MAX_PERFRAME)?l:L1OIP_MAX_PERFRAME; + ll = (l < L1OIP_MAX_PERFRAME) ? l : L1OIP_MAX_PERFRAME; l1oip_socket_send(hc, hc->codec, bch->slot, 0, - hc->chan[bch->slot].tx_counter, p, ll); + hc->chan[bch->slot].tx_counter, p, ll); hc->chan[bch->slot].tx_counter += ll; p += ll; l -= ll; @@ -1152,19 +1158,19 @@ handle_bmsg(struct mISDNchannel *ch, struct sk_buff *skb) queue_ch_frame(ch, PH_DATA_CNF, hh->id, skb); return 0; case PH_ACTIVATE_REQ: - if (debug & (DEBUG_L1OIP_MSG|DEBUG_L1OIP_SOCKET)) + if (debug & (DEBUG_L1OIP_MSG | DEBUG_L1OIP_SOCKET)) printk(KERN_DEBUG "%s: PH_ACTIVATE channel %d (1..%d)\n" - , __func__, bch->slot, hc->b_num+1); + , __func__, bch->slot, hc->b_num + 1); hc->chan[bch->slot].codecstate = 0; test_and_set_bit(FLG_ACTIVE, &bch->Flags); skb_trim(skb, 0); queue_ch_frame(ch, PH_ACTIVATE_IND, hh->id, skb); return 0; case PH_DEACTIVATE_REQ: - if (debug & (DEBUG_L1OIP_MSG|DEBUG_L1OIP_SOCKET)) + if (debug & (DEBUG_L1OIP_MSG | DEBUG_L1OIP_SOCKET)) printk(KERN_DEBUG "%s: PH_DEACTIVATE channel %d " - "(1..%d)\n", __func__, bch->slot, - hc->b_num+1); + "(1..%d)\n", __func__, bch->slot, + hc->b_num + 1); test_and_clear_bit(FLG_ACTIVE, &bch->Flags); skb_trim(skb, 0); queue_ch_frame(ch, PH_DEACTIVATE_IND, hh->id, skb); @@ -1189,14 +1195,14 @@ channel_bctrl(struct bchannel *bch, struct mISDN_ctrl_req *cq) case MISDN_CTRL_HW_FEATURES: /* fill features structure */ if (debug & DEBUG_L1OIP_MSG) printk(KERN_DEBUG "%s: HW_FEATURE request\n", - __func__); + __func__); /* create confirm */ features->unclocked = 1; features->unordered = 1; break; default: printk(KERN_WARNING "%s: unknown Op %x\n", - __func__, cq->op); + __func__, cq->op); ret = -EINVAL; break; } @@ -1211,7 +1217,7 @@ l1oip_bctrl(struct mISDNchannel *ch, u_int cmd, void *arg) if (bch->debug & DEBUG_HW) printk(KERN_DEBUG "%s: cmd:%x %p\n", - __func__, cmd, arg); + __func__, cmd, arg); switch (cmd) { case CLOSE_CHANNEL: test_and_clear_bit(FLG_OPEN, &bch->Flags); @@ -1226,7 +1232,7 @@ l1oip_bctrl(struct mISDNchannel *ch, u_int cmd, void *arg) break; default: printk(KERN_WARNING "%s: unknown prim(%x)\n", - __func__, cmd); + __func__, cmd); } return err; } @@ -1246,6 +1252,8 @@ release_card(struct l1oip *hc) if (timer_pending(&hc->timeout_tl)) del_timer(&hc->timeout_tl); + cancel_work_sync(&hc->workq); + if (hc->socket_thread) l1oip_socket_close(hc); @@ -1299,8 +1307,8 @@ init_card(struct l1oip *hc, int pri, int bundle) spin_lock_init(&hc->socket_lock); hc->idx = l1oip_cnt; hc->pri = pri; - hc->d_idx = pri?16:3; - hc->b_num = pri?30:2; + hc->d_idx = pri ? 16 : 3; + hc->b_num = pri ? 30 : 2; hc->bundle = bundle; if (hc->pri) sprintf(hc->name, "l1oip-e1.%d", l1oip_cnt + 1); @@ -1315,18 +1323,18 @@ init_card(struct l1oip *hc, int pri, int bundle) break; default: printk(KERN_ERR "Codec(%d) not supported.\n", - codec[l1oip_cnt]); + codec[l1oip_cnt]); return -EINVAL; } hc->codec = codec[l1oip_cnt]; if (debug & DEBUG_L1OIP_INIT) printk(KERN_DEBUG "%s: using codec %d\n", - __func__, hc->codec); + __func__, hc->codec); if (id[l1oip_cnt] == 0) { printk(KERN_WARNING "Warning: No 'id' value given or " - "0, this is highly unsecure. Please use 32 " - "bit randmom number 0x...\n"); + "0, this is highly unsecure. Please use 32 " + "bit randmom number 0x...\n"); } hc->id = id[l1oip_cnt]; if (debug & DEBUG_L1OIP_INIT) @@ -1335,7 +1343,7 @@ init_card(struct l1oip *hc, int pri, int bundle) hc->ondemand = ondemand[l1oip_cnt]; if (hc->ondemand && !hc->id) { printk(KERN_ERR "%s: ondemand option only allowed in " - "conjunction with non 0 ID\n", __func__); + "conjunction with non 0 ID\n", __func__); return -EINVAL; } @@ -1343,37 +1351,37 @@ init_card(struct l1oip *hc, int pri, int bundle) hc->b_num = limit[l1oip_cnt]; if (!pri && hc->b_num > 2) { printk(KERN_ERR "Maximum limit for BRI interface is 2 " - "channels.\n"); + "channels.\n"); return -EINVAL; } if (pri && hc->b_num > 126) { printk(KERN_ERR "Maximum limit for PRI interface is 126 " - "channels.\n"); + "channels.\n"); return -EINVAL; } if (pri && hc->b_num > 30) { printk(KERN_WARNING "Maximum limit for BRI interface is 30 " - "channels.\n"); + "channels.\n"); printk(KERN_WARNING "Your selection of %d channels must be " - "supported by application.\n", hc->limit); + "supported by application.\n", hc->limit); } - hc->remoteip = ip[l1oip_cnt<<2] << 24 - | ip[(l1oip_cnt<<2)+1] << 16 - | ip[(l1oip_cnt<<2)+2] << 8 - | ip[(l1oip_cnt<<2)+3]; - hc->localport = port[l1oip_cnt]?:(L1OIP_DEFAULTPORT+l1oip_cnt); + hc->remoteip = ip[l1oip_cnt << 2] << 24 + | ip[(l1oip_cnt << 2) + 1] << 16 + | ip[(l1oip_cnt << 2) + 2] << 8 + | ip[(l1oip_cnt << 2) + 3]; + hc->localport = port[l1oip_cnt]?:(L1OIP_DEFAULTPORT + l1oip_cnt); if (remoteport[l1oip_cnt]) hc->remoteport = remoteport[l1oip_cnt]; else hc->remoteport = hc->localport; if (debug & DEBUG_L1OIP_INIT) printk(KERN_DEBUG "%s: using local port %d remote ip " - "%d.%d.%d.%d port %d ondemand %d\n", __func__, - hc->localport, hc->remoteip >> 24, - (hc->remoteip >> 16) & 0xff, - (hc->remoteip >> 8) & 0xff, hc->remoteip & 0xff, - hc->remoteport, hc->ondemand); + "%d.%d.%d.%d port %d ondemand %d\n", __func__, + hc->localport, hc->remoteip >> 24, + (hc->remoteip >> 16) & 0xff, + (hc->remoteip >> 8) & 0xff, hc->remoteip & 0xff, + hc->remoteport, hc->ondemand); dch = kzalloc(sizeof(struct dchannel), GFP_KERNEL); if (!dch) @@ -1386,7 +1394,7 @@ init_card(struct l1oip *hc, int pri, int bundle) else dch->dev.Dprotocols = (1 << ISDN_P_TE_S0) | (1 << ISDN_P_NT_S0); dch->dev.Bprotocols = (1 << (ISDN_P_B_RAW & ISDN_P_B_MASK)) | - (1 << (ISDN_P_B_HDLC & ISDN_P_B_MASK)); + (1 << (ISDN_P_B_HDLC & ISDN_P_B_MASK)); dch->dev.D.send = handle_dmsg; dch->dev.D.ctrl = l1oip_dctrl; dch->dev.nrbchan = hc->b_num; @@ -1399,30 +1407,30 @@ init_card(struct l1oip *hc, int pri, int bundle) bch = kzalloc(sizeof(struct bchannel), GFP_KERNEL); if (!bch) { printk(KERN_ERR "%s: no memory for bchannel\n", - __func__); + __func__); return -ENOMEM; } bch->nr = i + ch; bch->slot = i + ch; bch->debug = debug; - mISDN_initbchannel(bch, MAX_DATA_MEM); + mISDN_initbchannel(bch, MAX_DATA_MEM, 0); bch->hw = hc; bch->ch.send = handle_bmsg; bch->ch.ctrl = l1oip_bctrl; bch->ch.nr = i + ch; list_add(&bch->ch.list, &dch->dev.bchannels); hc->chan[i + ch].bch = bch; - test_and_set_bit(bch->nr & 0x1f, - &dch->dev.channelmap[bch->nr >> 5]); + set_channelmap(bch->nr, dch->dev.channelmap); } - ret = mISDN_register_device(&dch->dev, hc->name); + /* TODO: create a parent device for this driver */ + ret = mISDN_register_device(&dch->dev, NULL, hc->name); if (ret) return ret; hc->registered = 1; if (debug & DEBUG_L1OIP_INIT) printk(KERN_DEBUG "%s: Setting up network card(%d)\n", - __func__, l1oip_cnt + 1); + __func__, l1oip_cnt + 1); ret = l1oip_socket_open(hc); if (ret) return ret; @@ -1430,7 +1438,7 @@ init_card(struct l1oip *hc, int pri, int bundle) hc->keep_tl.function = (void *)l1oip_keepalive; hc->keep_tl.data = (ulong)hc; init_timer(&hc->keep_tl); - hc->keep_tl.expires = jiffies + 2*HZ; /* two seconds first time */ + hc->keep_tl.expires = jiffies + 2 * HZ; /* two seconds first time */ add_timer(&hc->keep_tl); hc->timeout_tl.function = (void *)l1oip_timeout; @@ -1449,7 +1457,7 @@ l1oip_init(void) int ret; printk(KERN_INFO "mISDN: Layer-1-over-IP driver Rev. %s\n", - l1oip_revision); + l1oip_revision); INIT_LIST_HEAD(&l1oip_ilist); spin_lock_init(&l1oip_lock); @@ -1458,7 +1466,7 @@ l1oip_init(void) return -ENOMEM; l1oip_cnt = 0; - while (type[l1oip_cnt] && l1oip_cnt < MAX_CARDS) { + while (l1oip_cnt < MAX_CARDS && type[l1oip_cnt]) { switch (type[l1oip_cnt] & 0xff) { case 1: pri = 0; @@ -1478,16 +1486,16 @@ l1oip_init(void) break; default: printk(KERN_ERR "Card type(%d) not supported.\n", - type[l1oip_cnt] & 0xff); + type[l1oip_cnt] & 0xff); l1oip_cleanup(); return -EINVAL; } if (debug & DEBUG_L1OIP_INIT) printk(KERN_DEBUG "%s: interface %d is %s with %s.\n", - __func__, l1oip_cnt, pri?"PRI":"BRI", - bundle?"bundled IP packet for all B-channels" - :"seperate IP packets for every B-channel"); + __func__, l1oip_cnt, pri ? "PRI" : "BRI", + bundle ? "bundled IP packet for all B-channels" : + "separate IP packets for every B-channel"); hc = kzalloc(sizeof(struct l1oip), GFP_ATOMIC); if (!hc) { @@ -1515,4 +1523,3 @@ l1oip_init(void) module_init(l1oip_init); module_exit(l1oip_cleanup); - diff --git a/drivers/isdn/mISDN/layer1.c b/drivers/isdn/mISDN/layer1.c index fced1a2755f..bebc57b7213 100644 --- a/drivers/isdn/mISDN/layer1.c +++ b/drivers/isdn/mISDN/layer1.c @@ -16,23 +16,27 @@ */ +#include <linux/slab.h> #include <linux/module.h> #include <linux/mISDNhw.h> +#include "core.h" #include "layer1.h" #include "fsm.h" -static int *debug; +static u_int *debug; struct layer1 { - u_long Flags; - struct FsmInst l1m; - struct FsmTimer timer; - int delay; - struct dchannel *dch; - dchannel_l1callback *dcb; + u_long Flags; + struct FsmInst l1m; + struct FsmTimer timer3; + struct FsmTimer timerX; + int delay; + int t3_value; + struct dchannel *dch; + dchannel_l1callback *dcb; }; -#define TIMER3_VALUE 7000 +#define TIMER3_DEFAULT_VALUE 7000 static struct Fsm l1fsm_s = {NULL, 0, 0, NULL, NULL}; @@ -47,7 +51,7 @@ enum { ST_L1_F8, }; -#define L1S_STATE_COUNT (ST_L1_F8+1) +#define L1S_STATE_COUNT (ST_L1_F8 + 1) static char *strL1SState[] = { @@ -97,12 +101,16 @@ static void l1m_debug(struct FsmInst *fi, char *fmt, ...) { struct layer1 *l1 = fi->userdata; + struct va_format vaf; va_list va; va_start(va, fmt); - printk(KERN_DEBUG "%s: ", l1->dch->dev.name); - vprintk(fmt, va); - printk("\n"); + + vaf.fmt = fmt; + vaf.va = &va; + + printk(KERN_DEBUG "%s: %pV\n", dev_name(&l1->dch->dev.dev), &vaf); + va_end(va); } @@ -128,7 +136,7 @@ l1_deact_req_s(struct FsmInst *fi, int event, void *arg) struct layer1 *l1 = fi->userdata; mISDN_FsmChangeState(fi, ST_L1_F3); - mISDN_FsmRestartTimer(&l1->timer, 550, EV_TIMER_DEACT, NULL, 2); + mISDN_FsmRestartTimer(&l1->timerX, 550, EV_TIMER_DEACT, NULL, 2); test_and_set_bit(FLG_L1_DEACTTIMER, &l1->Flags); } @@ -173,11 +181,11 @@ l1_info4_ind(struct FsmInst *fi, int event, void *arg) mISDN_FsmChangeState(fi, ST_L1_F7); l1->dcb(l1->dch, INFO3_P8); if (test_and_clear_bit(FLG_L1_DEACTTIMER, &l1->Flags)) - mISDN_FsmDelTimer(&l1->timer, 4); + mISDN_FsmDelTimer(&l1->timerX, 4); if (!test_bit(FLG_L1_ACTIVATED, &l1->Flags)) { if (test_and_clear_bit(FLG_L1_T3RUN, &l1->Flags)) - mISDN_FsmDelTimer(&l1->timer, 3); - mISDN_FsmRestartTimer(&l1->timer, 110, EV_TIMER_ACT, NULL, 2); + mISDN_FsmDelTimer(&l1->timer3, 3); + mISDN_FsmRestartTimer(&l1->timerX, 110, EV_TIMER_ACT, NULL, 2); test_and_set_bit(FLG_L1_ACTTIMER, &l1->Flags); } } @@ -195,7 +203,7 @@ l1_timer3(struct FsmInst *fi, int event, void *arg) } if (l1->l1m.state != ST_L1_F6) { mISDN_FsmChangeState(fi, ST_L1_F3); - l1->dcb(l1->dch, HW_POWERUP_REQ); + /* do not force anything here, we need send INFO 0 */ } } @@ -227,8 +235,9 @@ l1_activate_s(struct FsmInst *fi, int event, void *arg) { struct layer1 *l1 = fi->userdata; - mISDN_FsmRestartTimer(&l1->timer, TIMER3_VALUE, EV_TIMER3, NULL, 2); + mISDN_FsmRestartTimer(&l1->timer3, l1->t3_value, EV_TIMER3, NULL, 2); test_and_set_bit(FLG_L1_T3RUN, &l1->Flags); + /* Tell HW to send INFO 1 */ l1->dcb(l1->dch, HW_RESET_REQ); } @@ -296,7 +305,8 @@ static struct FsmNode L1SFnList[] = static void release_l1(struct layer1 *l1) { - mISDN_FsmDelTimer(&l1->timer, 0); + mISDN_FsmDelTimer(&l1->timerX, 0); + mISDN_FsmDelTimer(&l1->timer3, 0); if (l1->dch) l1->dch->l1 = NULL; module_put(THIS_MODULE); @@ -350,9 +360,19 @@ l1_event(struct layer1 *l1, u_int event) release_l1(l1); break; default: + if ((event & ~HW_TIMER3_VMASK) == HW_TIMER3_VALUE) { + int val = event & HW_TIMER3_VMASK; + + if (val < 5) + val = 5; + if (val > 30) + val = 30; + l1->t3_value = val; + break; + } if (*debug & DEBUG_L1) printk(KERN_DEBUG "%s %x unhandled\n", - __func__, event); + __func__, event); err = -EINVAL; } return err; @@ -371,13 +391,15 @@ create_l1(struct dchannel *dch, dchannel_l1callback *dcb) { nl1->l1m.fsm = &l1fsm_s; nl1->l1m.state = ST_L1_F3; nl1->Flags = 0; + nl1->t3_value = TIMER3_DEFAULT_VALUE; nl1->l1m.debug = *debug & DEBUG_L1_FSM; nl1->l1m.userdata = nl1; nl1->l1m.userint = 0; nl1->l1m.printdebug = l1m_debug; nl1->dch = dch; nl1->dcb = dcb; - mISDN_FsmInitTimer(&nl1->l1m, &nl1->timer); + mISDN_FsmInitTimer(&nl1->l1m, &nl1->timer3); + mISDN_FsmInitTimer(&nl1->l1m, &nl1->timerX); __module_get(THIS_MODULE); dch->l1 = nl1; return 0; diff --git a/drivers/isdn/mISDN/layer1.h b/drivers/isdn/mISDN/layer1.h index 9c8125fd89a..d1d332ced05 100644 --- a/drivers/isdn/mISDN/layer1.h +++ b/drivers/isdn/mISDN/layer1.h @@ -23,4 +23,3 @@ #define FLG_L1_PULL_REQ 6 #define FLG_L1_UINT 7 #define FLG_L1_DBLOCKED 8 - diff --git a/drivers/isdn/mISDN/layer2.c b/drivers/isdn/mISDN/layer2.c index a7915a156c0..949cabb88f1 100644 --- a/drivers/isdn/mISDN/layer2.c +++ b/drivers/isdn/mISDN/layer2.c @@ -15,10 +15,13 @@ * */ +#include <linux/mISDNif.h> +#include <linux/slab.h> +#include "core.h" #include "fsm.h" #include "layer2.h" -static int *debug; +static u_int *debug; static struct Fsm l2fsm = {NULL, 0, 0, NULL, NULL}; @@ -55,12 +58,14 @@ enum { EV_L1_DEACTIVATE, EV_L2_T200, EV_L2_T203, + EV_L2_T200I, + EV_L2_T203I, EV_L2_SET_OWN_BUSY, EV_L2_CLEAR_OWN_BUSY, EV_L2_FRAME_ERROR, }; -#define L2_EVENT_COUNT (EV_L2_FRAME_ERROR+1) +#define L2_EVENT_COUNT (EV_L2_FRAME_ERROR + 1) static char *strL2Event[] = { @@ -83,6 +88,8 @@ static char *strL2Event[] = "EV_L1_DEACTIVATE", "EV_L2_T200", "EV_L2_T203", + "EV_L2_T200I", + "EV_L2_T203I", "EV_L2_SET_OWN_BUSY", "EV_L2_CLEAR_OWN_BUSY", "EV_L2_FRAME_ERROR", @@ -92,14 +99,20 @@ static void l2m_debug(struct FsmInst *fi, char *fmt, ...) { struct layer2 *l2 = fi->userdata; + struct va_format vaf; va_list va; if (!(*debug & DEBUG_L2_FSM)) return; + va_start(va, fmt); - printk(KERN_DEBUG "l2 (tei %d): ", l2->tei); - vprintk(fmt, va); - printk("\n"); + + vaf.fmt = fmt; + vaf.va = &va; + + printk(KERN_DEBUG "%s l2 (sapi %d tei %d): %pV\n", + mISDNDevName4ch(&l2->ch), l2->sapi, l2->tei, &vaf); + va_end(va); } @@ -141,7 +154,8 @@ l2up(struct layer2 *l2, u_int prim, struct sk_buff *skb) mISDN_HEAD_ID(skb) = (l2->ch.nr << 16) | l2->ch.addr; err = l2->up->send(l2->up, skb); if (err) { - printk(KERN_WARNING "%s: err=%d\n", __func__, err); + printk(KERN_WARNING "%s: dev %s err=%d\n", __func__, + mISDNDevName4ch(&l2->ch), err); dev_kfree_skb(skb); } } @@ -165,7 +179,8 @@ l2up_create(struct layer2 *l2, u_int prim, int len, void *arg) memcpy(skb_put(skb, len), arg, len); err = l2->up->send(l2->up, skb); if (err) { - printk(KERN_WARNING "%s: err=%d\n", __func__, err); + printk(KERN_WARNING "%s: dev %s err=%d\n", __func__, + mISDNDevName4ch(&l2->ch), err); dev_kfree_skb(skb); } } @@ -176,7 +191,8 @@ l2down_skb(struct layer2 *l2, struct sk_buff *skb) { ret = l2->ch.recv(l2->ch.peer, skb); if (ret && (*debug & DEBUG_L2_RECV)) - printk(KERN_DEBUG "l2down_skb: ret(%d)\n", ret); + printk(KERN_DEBUG "l2down_skb: dev %s ret(%d)\n", + mISDNDevName4ch(&l2->ch), ret); return ret; } @@ -267,14 +283,39 @@ ph_data_confirm(struct layer2 *l2, struct mISDNhead *hh, struct sk_buff *skb) { return ret; } +static void +l2_timeout(struct FsmInst *fi, int event, void *arg) +{ + struct layer2 *l2 = fi->userdata; + struct sk_buff *skb; + struct mISDNhead *hh; + + skb = mI_alloc_skb(0, GFP_ATOMIC); + if (!skb) { + printk(KERN_WARNING "%s: L2(%d,%d) nr:%x timer %s no skb\n", + mISDNDevName4ch(&l2->ch), l2->sapi, l2->tei, + l2->ch.nr, event == EV_L2_T200 ? "T200" : "T203"); + return; + } + hh = mISDN_HEAD_P(skb); + hh->prim = event == EV_L2_T200 ? DL_TIMER200_IND : DL_TIMER203_IND; + hh->id = l2->ch.nr; + if (*debug & DEBUG_TIMER) + printk(KERN_DEBUG "%s: L2(%d,%d) nr:%x timer %s expired\n", + mISDNDevName4ch(&l2->ch), l2->sapi, l2->tei, + l2->ch.nr, event == EV_L2_T200 ? "T200" : "T203"); + if (l2->ch.st) + l2->ch.st->own.recv(&l2->ch.st->own, skb); +} + static int l2mgr(struct layer2 *l2, u_int prim, void *arg) { long c = (long)arg; - printk(KERN_WARNING - "l2mgr: addr:%x prim %x %c\n", l2->id, prim, (char)c); + printk(KERN_WARNING "l2mgr: dev %s addr:%x prim %x %c\n", + mISDNDevName4ch(&l2->ch), l2->id, prim, (char)c); if (test_bit(FLG_LAPD, &l2->flag) && - !test_bit(FLG_FIXED_TEI, &l2->flag)) { + !test_bit(FLG_FIXED_TEI, &l2->flag)) { switch (c) { case 'C': case 'D': @@ -331,7 +372,7 @@ ReleaseWin(struct layer2 *l2) if (cnt) printk(KERN_WARNING - "isdnl2 freed %d skbuffs in release\n", cnt); + "isdnl2 freed %d skbuffs in release\n", cnt); } inline unsigned int @@ -462,10 +503,10 @@ inline int IsRNR(u_char *data, struct layer2 *l2) { return test_bit(FLG_MOD128, &l2->flag) ? - data[0] == RNR : (data[0] & 0xf) == RNR; + data[0] == RNR : (data[0] & 0xf) == RNR; } -int +static int iframe_error(struct layer2 *l2, struct sk_buff *skb) { u_int i; @@ -483,7 +524,7 @@ iframe_error(struct layer2 *l2, struct sk_buff *skb) return 0; } -int +static int super_error(struct layer2 *l2, struct sk_buff *skb) { if (skb->len != l2addrsize(l2) + @@ -492,7 +533,7 @@ super_error(struct layer2 *l2, struct sk_buff *skb) return 0; } -int +static int unnum_error(struct layer2 *l2, struct sk_buff *skb, int wantrsp) { int rsp = (*skb->data & 0x2) >> 1; @@ -505,7 +546,7 @@ unnum_error(struct layer2 *l2, struct sk_buff *skb, int wantrsp) return 0; } -int +static int UI_error(struct layer2 *l2, struct sk_buff *skb) { int rsp = *skb->data & 0x2; @@ -518,7 +559,7 @@ UI_error(struct layer2 *l2, struct sk_buff *skb) return 0; } -int +static int FRMR_error(struct layer2 *l2, struct sk_buff *skb) { u_int headers = l2addrsize(l2) + 1; @@ -534,15 +575,15 @@ FRMR_error(struct layer2 *l2, struct sk_buff *skb) return 'N'; else if (*debug & DEBUG_L2) l2m_debug(&l2->l2m, - "FRMR information %2x %2x %2x %2x %2x", - datap[0], datap[1], datap[2], datap[3], datap[4]); + "FRMR information %2x %2x %2x %2x %2x", + datap[0], datap[1], datap[2], datap[3], datap[4]); } else { if (skb->len < headers + 3) return 'N'; else if (*debug & DEBUG_L2) l2m_debug(&l2->l2m, - "FRMR information %2x %2x %2x", - datap[0], datap[1], datap[2]); + "FRMR information %2x %2x %2x", + datap[0], datap[1], datap[2]); } return 0; } @@ -594,8 +635,8 @@ send_uframe(struct layer2 *l2, struct sk_buff *skb, u_char cmd, u_char cr) else { skb = mI_alloc_skb(i, GFP_ATOMIC); if (!skb) { - printk(KERN_WARNING "%s: can't alloc skbuff\n", - __func__); + printk(KERN_WARNING "%s: can't alloc skbuff in %s\n", + mISDNDevName4ch(&l2->ch), __func__); return; } } @@ -1042,7 +1083,7 @@ l2_st5_dm_release(struct FsmInst *fi, int event, void *arg) skb_queue_purge(&l2->i_queue); if (test_bit(FLG_LAPB, &l2->flag)) l2down_create(l2, PH_DEACTIVATE_REQ, - l2_newid(l2), 0, NULL); + l2_newid(l2), 0, NULL); st5_dl_release_l2l3(l2); mISDN_FsmChangeState(fi, ST_L2_4); if (l2->tm) @@ -1065,7 +1106,7 @@ l2_st6_dm_release(struct FsmInst *fi, int event, void *arg) } } -void +static void enquiry_cr(struct layer2 *l2, u_char typ, u_char cr, u_char pf) { struct sk_buff *skb; @@ -1080,8 +1121,8 @@ enquiry_cr(struct layer2 *l2, u_char typ, u_char cr, u_char pf) tmp[i++] = (l2->vr << 5) | typ | (pf ? 0x10 : 0); skb = mI_alloc_skb(i, GFP_ATOMIC); if (!skb) { - printk(KERN_WARNING - "isdnl2 can't alloc sbbuff for enquiry_cr\n"); + printk(KERN_WARNING "%s: isdnl2 can't alloc sbbuff in %s\n", + mISDNDevName4ch(&l2->ch), __func__); return; } memcpy(skb_put(skb, i), tmp, i); @@ -1140,8 +1181,8 @@ invoke_retransmission(struct layer2 *l2, unsigned int nr) skb_queue_head(&l2->i_queue, l2->windowar[p1]); else printk(KERN_WARNING - "%s: windowar[%d] is NULL\n", - __func__, p1); + "%s: windowar[%d] is NULL\n", + mISDNDevName4ch(&l2->ch), p1); l2->windowar[p1] = NULL; } mISDN_FsmEvent(&l2->l2m, EV_L2_ACK_PULL, NULL); @@ -1190,13 +1231,13 @@ l2_st7_got_super(struct FsmInst *fi, int event, void *arg) invoke_retransmission(l2, nr); stop_t200(l2, 10); if (mISDN_FsmAddTimer(&l2->t203, l2->T203, - EV_L2_T203, NULL, 6)) + EV_L2_T203, NULL, 6)) l2m_debug(&l2->l2m, "Restart T203 ST7 REJ"); } else if ((nr == l2->vs) && (typ == RR)) { setva(l2, nr); stop_t200(l2, 11); mISDN_FsmRestartTimer(&l2->t203, l2->T203, - EV_L2_T203, NULL, 7); + EV_L2_T203, NULL, 7); } else if ((l2->va != nr) || (typ == RNR)) { setva(l2, nr); if (typ != RR) @@ -1294,7 +1335,7 @@ l2_got_iframe(struct FsmInst *fi, int event, void *arg) if (nr == l2->vs) { stop_t200(l2, 13); mISDN_FsmRestartTimer(&l2->t203, l2->T203, - EV_L2_T203, NULL, 7); + EV_L2_T203, NULL, 7); } else if (nr != l2->va) restart_t200(l2, 14); } @@ -1334,7 +1375,7 @@ l2_st5_tout_200(struct FsmInst *fi, int event, void *arg) struct layer2 *l2 = fi->userdata; if (test_bit(FLG_LAPD, &l2->flag) && - test_bit(FLG_DCHAN_BUSY, &l2->flag)) { + test_bit(FLG_DCHAN_BUSY, &l2->flag)) { mISDN_FsmAddTimer(&l2->t200, l2->T200, EV_L2_T200, NULL, 9); } else if (l2->rc == l2->N200) { mISDN_FsmChangeState(fi, ST_L2_4); @@ -1343,7 +1384,7 @@ l2_st5_tout_200(struct FsmInst *fi, int event, void *arg) l2mgr(l2, MDL_ERROR_IND, (void *) 'G'); if (test_bit(FLG_LAPB, &l2->flag)) l2down_create(l2, PH_DEACTIVATE_REQ, - l2_newid(l2), 0, NULL); + l2_newid(l2), 0, NULL); st5_dl_release_l2l3(l2); if (l2->tm) l2_tei(l2, MDL_STATUS_DOWN_IND, 0); @@ -1351,7 +1392,7 @@ l2_st5_tout_200(struct FsmInst *fi, int event, void *arg) l2->rc++; mISDN_FsmAddTimer(&l2->t200, l2->T200, EV_L2_T200, NULL, 9); send_uframe(l2, NULL, (test_bit(FLG_MOD128, &l2->flag) ? - SABME : SABM) | 0x10, CMD); + SABME : SABM) | 0x10, CMD); } } @@ -1361,7 +1402,7 @@ l2_st6_tout_200(struct FsmInst *fi, int event, void *arg) struct layer2 *l2 = fi->userdata; if (test_bit(FLG_LAPD, &l2->flag) && - test_bit(FLG_DCHAN_BUSY, &l2->flag)) { + test_bit(FLG_DCHAN_BUSY, &l2->flag)) { mISDN_FsmAddTimer(&l2->t200, l2->T200, EV_L2_T200, NULL, 9); } else if (l2->rc == l2->N200) { mISDN_FsmChangeState(fi, ST_L2_4); @@ -1373,7 +1414,7 @@ l2_st6_tout_200(struct FsmInst *fi, int event, void *arg) } else { l2->rc++; mISDN_FsmAddTimer(&l2->t200, l2->T200, EV_L2_T200, - NULL, 9); + NULL, 9); send_uframe(l2, NULL, DISC | 0x10, CMD); } } @@ -1384,7 +1425,7 @@ l2_st7_tout_200(struct FsmInst *fi, int event, void *arg) struct layer2 *l2 = fi->userdata; if (test_bit(FLG_LAPD, &l2->flag) && - test_bit(FLG_DCHAN_BUSY, &l2->flag)) { + test_bit(FLG_DCHAN_BUSY, &l2->flag)) { mISDN_FsmAddTimer(&l2->t200, l2->T200, EV_L2_T200, NULL, 9); return; } @@ -1401,7 +1442,7 @@ l2_st8_tout_200(struct FsmInst *fi, int event, void *arg) struct layer2 *l2 = fi->userdata; if (test_bit(FLG_LAPD, &l2->flag) && - test_bit(FLG_DCHAN_BUSY, &l2->flag)) { + test_bit(FLG_DCHAN_BUSY, &l2->flag)) { mISDN_FsmAddTimer(&l2->t200, l2->T200, EV_L2_T200, NULL, 9); return; } @@ -1422,7 +1463,7 @@ l2_st7_tout_203(struct FsmInst *fi, int event, void *arg) struct layer2 *l2 = fi->userdata; if (test_bit(FLG_LAPD, &l2->flag) && - test_bit(FLG_DCHAN_BUSY, &l2->flag)) { + test_bit(FLG_DCHAN_BUSY, &l2->flag)) { mISDN_FsmAddTimer(&l2->t203, l2->T203, EV_L2_T203, NULL, 9); return; } @@ -1452,8 +1493,8 @@ l2_pull_iqueue(struct FsmInst *fi, int event, void *arg) p1 = (l2->vs - l2->va) % 8; p1 = (p1 + l2->sow) % l2->window; if (l2->windowar[p1]) { - printk(KERN_WARNING "isdnl2 try overwrite ack queue entry %d\n", - p1); + printk(KERN_WARNING "%s: l2 try overwrite ack queue entry %d\n", + mISDNDevName4ch(&l2->ch), p1); dev_kfree_skb(l2->windowar[p1]); } l2->windowar[p1] = skb; @@ -1473,12 +1514,14 @@ l2_pull_iqueue(struct FsmInst *fi, int event, void *arg) memcpy(skb_push(nskb, i), header, i); else { printk(KERN_WARNING - "isdnl2 pull_iqueue skb header(%d/%d) too short\n", i, p1); + "%s: L2 pull_iqueue skb header(%d/%d) too short\n", + mISDNDevName4ch(&l2->ch), i, p1); oskb = nskb; nskb = mI_alloc_skb(oskb->len + i, GFP_ATOMIC); if (!nskb) { dev_kfree_skb(oskb); - printk(KERN_WARNING "%s: no skb mem\n", __func__); + printk(KERN_WARNING "%s: no skb mem in %s\n", + mISDNDevName4ch(&l2->ch), __func__); return; } memcpy(skb_put(nskb, i), header, i); @@ -1528,7 +1571,7 @@ l2_st8_got_super(struct FsmInst *fi, int event, void *arg) } else { stop_t200(l2, 16); mISDN_FsmAddTimer(&l2->t203, l2->T203, - EV_L2_T203, NULL, 5); + EV_L2_T203, NULL, 5); setva(l2, nr); } invoke_retransmission(l2, nr); @@ -1631,7 +1674,7 @@ l2_tei_remove(struct FsmInst *fi, int event, void *arg) } static void -l2_st14_persistant_da(struct FsmInst *fi, int event, void *arg) +l2_st14_persistent_da(struct FsmInst *fi, int event, void *arg) { struct layer2 *l2 = fi->userdata; struct sk_buff *skb = arg; @@ -1645,7 +1688,7 @@ l2_st14_persistant_da(struct FsmInst *fi, int event, void *arg) } static void -l2_st5_persistant_da(struct FsmInst *fi, int event, void *arg) +l2_st5_persistent_da(struct FsmInst *fi, int event, void *arg) { struct layer2 *l2 = fi->userdata; struct sk_buff *skb = arg; @@ -1662,7 +1705,7 @@ l2_st5_persistant_da(struct FsmInst *fi, int event, void *arg) } static void -l2_st6_persistant_da(struct FsmInst *fi, int event, void *arg) +l2_st6_persistent_da(struct FsmInst *fi, int event, void *arg) { struct layer2 *l2 = fi->userdata; struct sk_buff *skb = arg; @@ -1676,7 +1719,7 @@ l2_st6_persistant_da(struct FsmInst *fi, int event, void *arg) } static void -l2_persistant_da(struct FsmInst *fi, int event, void *arg) +l2_persistent_da(struct FsmInst *fi, int event, void *arg) { struct layer2 *l2 = fi->userdata; struct sk_buff *skb = arg; @@ -1805,11 +1848,16 @@ static struct FsmNode L2FnList[] = {ST_L2_8, EV_L2_SUPER, l2_st8_got_super}, {ST_L2_7, EV_L2_I, l2_got_iframe}, {ST_L2_8, EV_L2_I, l2_got_iframe}, - {ST_L2_5, EV_L2_T200, l2_st5_tout_200}, - {ST_L2_6, EV_L2_T200, l2_st6_tout_200}, - {ST_L2_7, EV_L2_T200, l2_st7_tout_200}, - {ST_L2_8, EV_L2_T200, l2_st8_tout_200}, - {ST_L2_7, EV_L2_T203, l2_st7_tout_203}, + {ST_L2_5, EV_L2_T200, l2_timeout}, + {ST_L2_6, EV_L2_T200, l2_timeout}, + {ST_L2_7, EV_L2_T200, l2_timeout}, + {ST_L2_8, EV_L2_T200, l2_timeout}, + {ST_L2_7, EV_L2_T203, l2_timeout}, + {ST_L2_5, EV_L2_T200I, l2_st5_tout_200}, + {ST_L2_6, EV_L2_T200I, l2_st6_tout_200}, + {ST_L2_7, EV_L2_T200I, l2_st7_tout_200}, + {ST_L2_8, EV_L2_T200I, l2_st8_tout_200}, + {ST_L2_7, EV_L2_T203I, l2_st7_tout_203}, {ST_L2_7, EV_L2_ACK_PULL, l2_pull_iqueue}, {ST_L2_7, EV_L2_SET_OWN_BUSY, l2_set_own_busy}, {ST_L2_8, EV_L2_SET_OWN_BUSY, l2_set_own_busy}, @@ -1820,18 +1868,16 @@ static struct FsmNode L2FnList[] = {ST_L2_6, EV_L2_FRAME_ERROR, l2_frame_error}, {ST_L2_7, EV_L2_FRAME_ERROR, l2_frame_error_reest}, {ST_L2_8, EV_L2_FRAME_ERROR, l2_frame_error_reest}, - {ST_L2_1, EV_L1_DEACTIVATE, l2_st14_persistant_da}, + {ST_L2_1, EV_L1_DEACTIVATE, l2_st14_persistent_da}, {ST_L2_2, EV_L1_DEACTIVATE, l2_st24_tei_remove}, {ST_L2_3, EV_L1_DEACTIVATE, l2_st3_tei_remove}, - {ST_L2_4, EV_L1_DEACTIVATE, l2_st14_persistant_da}, - {ST_L2_5, EV_L1_DEACTIVATE, l2_st5_persistant_da}, - {ST_L2_6, EV_L1_DEACTIVATE, l2_st6_persistant_da}, - {ST_L2_7, EV_L1_DEACTIVATE, l2_persistant_da}, - {ST_L2_8, EV_L1_DEACTIVATE, l2_persistant_da}, + {ST_L2_4, EV_L1_DEACTIVATE, l2_st14_persistent_da}, + {ST_L2_5, EV_L1_DEACTIVATE, l2_st5_persistent_da}, + {ST_L2_6, EV_L1_DEACTIVATE, l2_st6_persistent_da}, + {ST_L2_7, EV_L1_DEACTIVATE, l2_persistent_da}, + {ST_L2_8, EV_L1_DEACTIVATE, l2_persistent_da}, }; -#define L2_FN_COUNT (sizeof(L2FnList)/sizeof(struct FsmNode)) - static int ph_data_indication(struct layer2 *l2, struct mISDNhead *hh, struct sk_buff *skb) { @@ -1851,26 +1897,26 @@ ph_data_indication(struct layer2 *l2, struct mISDNhead *hh, struct sk_buff *skb) ptei = *datap++; if ((psapi & 1) || !(ptei & 1)) { printk(KERN_WARNING - "l2 D-channel frame wrong EA0/EA1\n"); + "%s l2 D-channel frame wrong EA0/EA1\n", + mISDNDevName4ch(&l2->ch)); return ret; } psapi >>= 2; ptei >>= 1; if (psapi != l2->sapi) { - /* not our bussiness - * printk(KERN_DEBUG "%s: sapi %d/%d sapi mismatch\n", - * __func__, - * psapi, l2->sapi); - */ + /* not our business */ + if (*debug & DEBUG_L2) + printk(KERN_DEBUG "%s: sapi %d/%d mismatch\n", + mISDNDevName4ch(&l2->ch), psapi, + l2->sapi); dev_kfree_skb(skb); return 0; } if ((ptei != l2->tei) && (ptei != GROUP_TEI)) { - /* not our bussiness - * printk(KERN_DEBUG "%s: tei %d/%d sapi %d mismatch\n", - * __func__, - * ptei, l2->tei, psapi); - */ + /* not our business */ + if (*debug & DEBUG_L2) + printk(KERN_DEBUG "%s: tei %d/%d mismatch\n", + mISDNDevName4ch(&l2->ch), ptei, l2->tei); dev_kfree_skb(skb); return 0; } @@ -1911,7 +1957,8 @@ ph_data_indication(struct layer2 *l2, struct mISDNhead *hh, struct sk_buff *skb) } else c = 'L'; if (c) { - printk(KERN_WARNING "l2 D-channel frame error %c\n", c); + printk(KERN_WARNING "%s:l2 D-channel frame error %c\n", + mISDNDevName4ch(&l2->ch), c); mISDN_FsmEvent(&l2->l2m, EV_L2_FRAME_ERROR, (void *)(long)c); } return ret; @@ -1922,11 +1969,20 @@ l2_send(struct mISDNchannel *ch, struct sk_buff *skb) { struct layer2 *l2 = container_of(ch, struct layer2, ch); struct mISDNhead *hh = mISDN_HEAD_P(skb); - int ret = -EINVAL; + int ret = -EINVAL; if (*debug & DEBUG_L2_RECV) - printk(KERN_DEBUG "%s: prim(%x) id(%x) tei(%d)\n", - __func__, hh->prim, hh->id, l2->tei); + printk(KERN_DEBUG "%s: %s prim(%x) id(%x) sapi(%d) tei(%d)\n", + __func__, mISDNDevName4ch(&l2->ch), hh->prim, hh->id, + l2->sapi, l2->tei); + if (hh->prim == DL_INTERN_MSG) { + struct mISDNhead *chh = hh + 1; /* saved copy */ + + *hh = *chh; + if (*debug & DEBUG_L2_RECV) + printk(KERN_DEBUG "%s: prim(%x) id(%x) internal msg\n", + mISDNDevName4ch(&l2->ch), hh->prim, hh->id); + } switch (hh->prim) { case PH_DATA_IND: ret = ph_data_indication(l2, hh, skb); @@ -1939,7 +1995,7 @@ l2_send(struct mISDNchannel *ch, struct sk_buff *skb) l2up_create(l2, MPH_ACTIVATE_IND, 0, NULL); if (test_and_clear_bit(FLG_ESTAB_PEND, &l2->flag)) ret = mISDN_FsmEvent(&l2->l2m, - EV_L2_DL_ESTABLISH_REQ, skb); + EV_L2_DL_ESTABLISH_REQ, skb); break; case PH_DEACTIVATE_IND: test_and_clear_bit(FLG_L1_ACTIV, &l2->flag); @@ -1962,30 +2018,36 @@ l2_send(struct mISDNchannel *ch, struct sk_buff *skb) test_and_set_bit(FLG_ORIG, &l2->flag); if (test_bit(FLG_L1_ACTIV, &l2->flag)) { if (test_bit(FLG_LAPD, &l2->flag) || - test_bit(FLG_ORIG, &l2->flag)) + test_bit(FLG_ORIG, &l2->flag)) ret = mISDN_FsmEvent(&l2->l2m, - EV_L2_DL_ESTABLISH_REQ, skb); + EV_L2_DL_ESTABLISH_REQ, skb); } else { if (test_bit(FLG_LAPD, &l2->flag) || - test_bit(FLG_ORIG, &l2->flag)) { + test_bit(FLG_ORIG, &l2->flag)) { test_and_set_bit(FLG_ESTAB_PEND, - &l2->flag); + &l2->flag); } ret = l2down(l2, PH_ACTIVATE_REQ, l2_newid(l2), - skb); + skb); } break; case DL_RELEASE_REQ: if (test_bit(FLG_LAPB, &l2->flag)) l2down_create(l2, PH_DEACTIVATE_REQ, - l2_newid(l2), 0, NULL); + l2_newid(l2), 0, NULL); ret = mISDN_FsmEvent(&l2->l2m, EV_L2_DL_RELEASE_REQ, - skb); + skb); + break; + case DL_TIMER200_IND: + mISDN_FsmEvent(&l2->l2m, EV_L2_T200I, NULL); + break; + case DL_TIMER203_IND: + mISDN_FsmEvent(&l2->l2m, EV_L2_T203I, NULL); break; default: if (*debug & DEBUG_L2) l2m_debug(&l2->l2m, "l2 unknown pr %04x", - hh->prim); + hh->prim); } if (ret) { dev_kfree_skb(skb); @@ -2000,7 +2062,8 @@ tei_l2(struct layer2 *l2, u_int cmd, u_long arg) int ret = -EINVAL; if (*debug & DEBUG_L2_TEI) - printk(KERN_DEBUG "%s: cmd(%x)\n", __func__, cmd); + printk(KERN_DEBUG "%s: cmd(%x) in %s\n", + mISDNDevName4ch(&l2->ch), cmd, __func__); switch (cmd) { case (MDL_ASSIGN_REQ): ret = mISDN_FsmEvent(&l2->l2m, EV_L2_MDL_ASSIGN, (void *)arg); @@ -2013,7 +2076,8 @@ tei_l2(struct layer2 *l2, u_int cmd, u_long arg) break; case (MDL_ERROR_RSP): /* ETS 300-125 5.3.2.1 Test: TC13010 */ - printk(KERN_NOTICE "MDL_ERROR|REQ (tei_l2)\n"); + printk(KERN_NOTICE "%s: MDL_ERROR|REQ (tei_l2)\n", + mISDNDevName4ch(&l2->ch)); ret = mISDN_FsmEvent(&l2->l2m, EV_L2_MDL_ERROR, NULL); break; } @@ -2033,7 +2097,7 @@ release_l2(struct layer2 *l2) TEIrelease(l2); if (l2->ch.st) l2->ch.st->dev->D.ctrl(&l2->ch.st->dev->D, - CLOSE_CHANNEL, NULL); + CLOSE_CHANNEL, NULL); } kfree(l2); } @@ -2045,7 +2109,8 @@ l2_ctrl(struct mISDNchannel *ch, u_int cmd, void *arg) u_int info; if (*debug & DEBUG_L2_CTRL) - printk(KERN_DEBUG "%s:(%x)\n", __func__, cmd); + printk(KERN_DEBUG "%s: %s cmd(%x)\n", + mISDNDevName4ch(ch), __func__, cmd); switch (cmd) { case OPEN_CHANNEL: @@ -2053,7 +2118,7 @@ l2_ctrl(struct mISDNchannel *ch, u_int cmd, void *arg) set_channel_address(&l2->ch, l2->sapi, l2->tei); info = DL_INFO_L2_CONNECT; l2up_create(l2, DL_INFORMATION_IND, - sizeof(info), &info); + sizeof(info), &info); } break; case CLOSE_CHANNEL: @@ -2066,7 +2131,8 @@ l2_ctrl(struct mISDNchannel *ch, u_int cmd, void *arg) } struct layer2 * -create_l2(struct mISDNchannel *ch, u_int protocol, u_long options, u_long arg) +create_l2(struct mISDNchannel *ch, u_int protocol, u_long options, int tei, + int sapi) { struct layer2 *l2; struct channel_req rq; @@ -2087,7 +2153,7 @@ create_l2(struct mISDNchannel *ch, u_int protocol, u_long options, u_long arg) test_and_set_bit(FLG_LAPD, &l2->flag); test_and_set_bit(FLG_LAPD_NET, &l2->flag); test_and_set_bit(FLG_MOD128, &l2->flag); - l2->sapi = 0; + l2->sapi = sapi; l2->maxlen = MAX_DFRAME_LEN; if (test_bit(OPTION_L2_PMX, &options)) l2->window = 7; @@ -2097,7 +2163,7 @@ create_l2(struct mISDNchannel *ch, u_int protocol, u_long options, u_long arg) test_and_set_bit(FLG_PTP, &l2->flag); if (test_bit(OPTION_L2_FIXEDTEI, &options)) test_and_set_bit(FLG_FIXED_TEI, &l2->flag); - l2->tei = (u_int)arg; + l2->tei = tei; l2->T200 = 1000; l2->N200 = 3; l2->T203 = 10000; @@ -2112,7 +2178,7 @@ create_l2(struct mISDNchannel *ch, u_int protocol, u_long options, u_long arg) test_and_set_bit(FLG_LAPD, &l2->flag); test_and_set_bit(FLG_MOD128, &l2->flag); test_and_set_bit(FLG_ORIG, &l2->flag); - l2->sapi = 0; + l2->sapi = sapi; l2->maxlen = MAX_DFRAME_LEN; if (test_bit(OPTION_L2_PMX, &options)) l2->window = 7; @@ -2122,7 +2188,7 @@ create_l2(struct mISDNchannel *ch, u_int protocol, u_long options, u_long arg) test_and_set_bit(FLG_PTP, &l2->flag); if (test_bit(OPTION_L2_FIXEDTEI, &options)) test_and_set_bit(FLG_FIXED_TEI, &l2->flag); - l2->tei = (u_int)arg; + l2->tei = tei; l2->T200 = 1000; l2->N200 = 3; l2->T203 = 10000; @@ -2145,7 +2211,7 @@ create_l2(struct mISDNchannel *ch, u_int protocol, u_long options, u_long arg) break; default: printk(KERN_ERR "layer2 create failed prt %x\n", - protocol); + protocol); kfree(l2); return NULL; } @@ -2156,8 +2222,8 @@ create_l2(struct mISDNchannel *ch, u_int protocol, u_long options, u_long arg) InitWin(l2); l2->l2m.fsm = &l2fsm; if (test_bit(FLG_LAPB, &l2->flag) || - test_bit(FLG_PTP, &l2->flag) || - test_bit(FLG_LAPD_NET, &l2->flag)) + test_bit(FLG_FIXED_TEI, &l2->flag) || + test_bit(FLG_LAPD_NET, &l2->flag)) l2->l2m.state = ST_L2_4; else l2->l2m.state = ST_L2_1; @@ -2178,7 +2244,7 @@ x75create(struct channel_req *crq) if (crq->protocol != ISDN_P_B_X75SLP) return -EPROTONOSUPPORT; - l2 = create_l2(crq->ch, crq->protocol, 0, 0); + l2 = create_l2(crq->ch, crq->protocol, 0, 0, 0); if (!l2) return -ENOMEM; crq->ch = &l2->ch; @@ -2213,4 +2279,3 @@ Isdnl2_cleanup(void) TEIFree(); mISDN_FsmFree(&l2fsm); } - diff --git a/drivers/isdn/mISDN/layer2.h b/drivers/isdn/mISDN/layer2.h index 6293f80dc2d..fe68d94c1b7 100644 --- a/drivers/isdn/mISDN/layer2.h +++ b/drivers/isdn/mISDN/layer2.h @@ -87,18 +87,18 @@ enum { ST_L2_8, }; -#define L2_STATE_COUNT (ST_L2_8+1) +#define L2_STATE_COUNT (ST_L2_8 + 1) extern struct layer2 *create_l2(struct mISDNchannel *, u_int, - u_long, u_long); + u_long, int, int); extern int tei_l2(struct layer2 *, u_int, u_long arg); /* from tei.c */ -extern int l2_tei(struct layer2 *, u_int, u_long arg); -extern void TEIrelease(struct layer2 *); -extern int TEIInit(u_int *); -extern void TEIFree(void); +extern int l2_tei(struct layer2 *, u_int, u_long arg); +extern void TEIrelease(struct layer2 *); +extern int TEIInit(u_int *); +extern void TEIFree(void); #define MAX_L2HEADER_LEN 4 diff --git a/drivers/isdn/mISDN/socket.c b/drivers/isdn/mISDN/socket.c index 4ba4cc364c9..1be82284cf9 100644 --- a/drivers/isdn/mISDN/socket.c +++ b/drivers/isdn/mISDN/socket.c @@ -16,9 +16,11 @@ */ #include <linux/mISDNif.h> +#include <linux/slab.h> +#include <linux/export.h> #include "core.h" -static int *debug; +static u_int *debug; static struct proto mISDN_proto = { .name = "misdn", @@ -111,18 +113,17 @@ mISDN_sock_cmsg(struct sock *sk, struct msghdr *msg, struct sk_buff *skb) static int mISDN_sock_recvmsg(struct kiocb *iocb, struct socket *sock, - struct msghdr *msg, size_t len, int flags) + struct msghdr *msg, size_t len, int flags) { struct sk_buff *skb; struct sock *sk = sock->sk; - struct sockaddr_mISDN *maddr; int copied, err; if (*debug & DEBUG_SOCKET) printk(KERN_DEBUG "%s: len %d, flags %x ch.nr %d, proto %x\n", - __func__, (int)len, flags, _pms(sk)->ch.nr, - sk->sk_protocol); + __func__, (int)len, flags, _pms(sk)->ch.nr, + sk->sk_protocol); if (flags & (MSG_OOB)) return -EOPNOTSUPP; @@ -133,9 +134,9 @@ mISDN_sock_recvmsg(struct kiocb *iocb, struct socket *sock, if (!skb) return err; - if (msg->msg_namelen >= sizeof(struct sockaddr_mISDN)) { - msg->msg_namelen = sizeof(struct sockaddr_mISDN); - maddr = (struct sockaddr_mISDN *)msg->msg_name; + if (msg->msg_name) { + DECLARE_SOCKADDR(struct sockaddr_mISDN *, maddr, msg->msg_name); + maddr->family = AF_ISDN; maddr->dev = _pms(sk)->dev->id; if ((sk->sk_protocol == ISDN_P_LAPD_TE) || @@ -148,11 +149,7 @@ mISDN_sock_recvmsg(struct kiocb *iocb, struct socket *sock, maddr->sapi = _pms(sk)->ch.addr & 0xFF; maddr->tei = (_pms(sk)->ch.addr >> 8) & 0xFF; } - } else { - if (msg->msg_namelen) - printk(KERN_WARNING "%s: too small namelen %d\n", - __func__, msg->msg_namelen); - msg->msg_namelen = 0; + msg->msg_namelen = sizeof(*maddr); } copied = skb->len + MISDN_HEADER_LEN; @@ -164,7 +161,7 @@ mISDN_sock_recvmsg(struct kiocb *iocb, struct socket *sock, return -ENOSPC; } memcpy(skb_push(skb, MISDN_HEADER_LEN), mISDN_HEAD_P(skb), - MISDN_HEADER_LEN); + MISDN_HEADER_LEN); err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied); @@ -177,22 +174,21 @@ mISDN_sock_recvmsg(struct kiocb *iocb, struct socket *sock, static int mISDN_sock_sendmsg(struct kiocb *iocb, struct socket *sock, - struct msghdr *msg, size_t len) + struct msghdr *msg, size_t len) { struct sock *sk = sock->sk; struct sk_buff *skb; int err = -ENOMEM; - struct sockaddr_mISDN *maddr; if (*debug & DEBUG_SOCKET) printk(KERN_DEBUG "%s: len %d flags %x ch %d proto %x\n", - __func__, (int)len, msg->msg_flags, _pms(sk)->ch.nr, - sk->sk_protocol); + __func__, (int)len, msg->msg_flags, _pms(sk)->ch.nr, + sk->sk_protocol); if (msg->msg_flags & MSG_OOB) return -EOPNOTSUPP; - if (msg->msg_flags & ~(MSG_DONTWAIT|MSG_NOSIGNAL|MSG_ERRQUEUE)) + if (msg->msg_flags & ~(MSG_DONTWAIT | MSG_NOSIGNAL | MSG_ERRQUEUE)) return -EINVAL; if (len < MISDN_HEADER_LEN) @@ -209,7 +205,7 @@ mISDN_sock_sendmsg(struct kiocb *iocb, struct socket *sock, if (memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len)) { err = -EFAULT; - goto drop; + goto done; } memcpy(mISDN_HEAD_P(skb), skb->data, MISDN_HEADER_LEN); @@ -217,32 +213,34 @@ mISDN_sock_sendmsg(struct kiocb *iocb, struct socket *sock, if (msg->msg_namelen >= sizeof(struct sockaddr_mISDN)) { /* if we have a address, we use it */ - maddr = (struct sockaddr_mISDN *)msg->msg_name; + DECLARE_SOCKADDR(struct sockaddr_mISDN *, maddr, msg->msg_name); mISDN_HEAD_ID(skb) = maddr->channel; } else { /* use default for L2 messages */ if ((sk->sk_protocol == ISDN_P_LAPD_TE) || (sk->sk_protocol == ISDN_P_LAPD_NT)) - mISDN_HEAD_ID(skb) = _pms(sk)->ch.nr; + mISDN_HEAD_ID(skb) = _pms(sk)->ch.nr; } if (*debug & DEBUG_SOCKET) printk(KERN_DEBUG "%s: ID:%x\n", - __func__, mISDN_HEAD_ID(skb)); + __func__, mISDN_HEAD_ID(skb)); err = -ENODEV; - if (!_pms(sk)->ch.peer || - (err = _pms(sk)->ch.recv(_pms(sk)->ch.peer, skb))) - goto drop; - - err = len; + if (!_pms(sk)->ch.peer) + goto done; + err = _pms(sk)->ch.recv(_pms(sk)->ch.peer, skb); + if (err) + goto done; + else { + skb = NULL; + err = len; + } done: + if (skb) + kfree_skb(skb); release_sock(sk); return err; - -drop: - kfree_skb(skb); - goto done; } static int @@ -292,7 +290,7 @@ static int data_sock_ioctl_bound(struct sock *sk, unsigned int cmd, void __user *p) { struct mISDN_ctrl_req cq; - int err = -EINVAL, val; + int err = -EINVAL, val[2]; struct mISDNchannel *bchan, *next; lock_sock(sk); @@ -308,16 +306,16 @@ data_sock_ioctl_bound(struct sock *sk, unsigned int cmd, void __user *p) } if ((sk->sk_protocol & ~ISDN_P_B_MASK) == ISDN_P_B_START) { list_for_each_entry_safe(bchan, next, - &_pms(sk)->dev->bchannels, list) { + &_pms(sk)->dev->bchannels, list) { if (bchan->nr == cq.channel) { err = bchan->ctrl(bchan, - CONTROL_CHANNEL, &cq); + CONTROL_CHANNEL, &cq); break; } } } else err = _pms(sk)->dev->D.ctrl(&_pms(sk)->dev->D, - CONTROL_CHANNEL, &cq); + CONTROL_CHANNEL, &cq); if (err) break; if (copy_to_user(p, &cq, sizeof(cq))) @@ -328,12 +326,27 @@ data_sock_ioctl_bound(struct sock *sk, unsigned int cmd, void __user *p) err = -EINVAL; break; } - if (get_user(val, (int __user *)p)) { + val[0] = cmd; + if (get_user(val[1], (int __user *)p)) { + err = -EFAULT; + break; + } + err = _pms(sk)->dev->teimgr->ctrl(_pms(sk)->dev->teimgr, + CONTROL_CHANNEL, val); + break; + case IMHOLD_L1: + if (sk->sk_protocol != ISDN_P_LAPD_NT + && sk->sk_protocol != ISDN_P_LAPD_TE) { + err = -EINVAL; + break; + } + val[0] = cmd; + if (get_user(val[1], (int __user *)p)) { err = -EFAULT; break; } err = _pms(sk)->dev->teimgr->ctrl(_pms(sk)->dev->teimgr, - CONTROL_CHANNEL, &val); + CONTROL_CHANNEL, val); break; default: err = -EINVAL; @@ -347,7 +360,7 @@ done: static int data_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) { - int err = 0, id; + int err = 0, id; struct sock *sk = sock->sk; struct mISDNdevice *dev; struct mISDNversion ver; @@ -374,14 +387,15 @@ data_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) if (dev) { struct mISDN_devinfo di; + memset(&di, 0, sizeof(di)); di.id = dev->id; di.Dprotocols = dev->Dprotocols; di.Bprotocols = dev->Bprotocols | get_all_Bprotocols(); di.protocol = dev->D.protocol; memcpy(di.channelmap, dev->channelmap, - MISDN_CHMAP_SIZE * 4); + sizeof(di.channelmap)); di.nrbchan = dev->nrbchan; - strcpy(di.name, dev->name); + strcpy(di.name, dev_name(&dev->dev)); if (copy_to_user((void __user *)arg, &di, sizeof(di))) err = -EFAULT; } else @@ -390,7 +404,7 @@ data_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) default: if (sk->sk_state == MISDN_BOUND) err = data_sock_ioctl_bound(sk, cmd, - (void __user *)arg); + (void __user *)arg); else err = -ENOTCONN; } @@ -398,14 +412,14 @@ data_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) } static int data_sock_setsockopt(struct socket *sock, int level, int optname, - char __user *optval, int len) + char __user *optval, unsigned int len) { struct sock *sk = sock->sk; int err = 0, opt = 0; if (*debug & DEBUG_SOCKET) printk(KERN_DEBUG "%s(%p, %d, %x, %p, %d)\n", __func__, sock, - level, optname, optval, len); + level, optname, optval, len); lock_sock(sk); @@ -430,7 +444,7 @@ static int data_sock_setsockopt(struct socket *sock, int level, int optname, } static int data_sock_getsockopt(struct socket *sock, int level, int optname, - char __user *optval, int __user *optlen) + char __user *optval, int __user *optlen) { struct sock *sk = sock->sk; int len, opt; @@ -438,6 +452,9 @@ static int data_sock_getsockopt(struct socket *sock, int level, int optname, if (get_user(len, optlen)) return -EFAULT; + if (len != sizeof(char)) + return -EINVAL; + switch (optname) { case MISDN_TIME_STAMP: if (_pms(sk)->cmask & MISDN_TIME_STAMP) @@ -460,6 +477,7 @@ data_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_len) { struct sockaddr_mISDN *maddr = (struct sockaddr_mISDN *) addr; struct sock *sk = sock->sk; + struct sock *csk; int err = 0; if (*debug & DEBUG_SOCKET) @@ -480,6 +498,26 @@ data_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_len) err = -ENODEV; goto done; } + + if (sk->sk_protocol < ISDN_P_B_START) { + read_lock_bh(&data_sockets.lock); + sk_for_each(csk, &data_sockets.head) { + if (sk == csk) + continue; + if (_pms(csk)->dev != _pms(sk)->dev) + continue; + if (csk->sk_protocol >= ISDN_P_B_START) + continue; + if (IS_ISDN_P_TE(csk->sk_protocol) + == IS_ISDN_P_TE(sk->sk_protocol)) + continue; + read_unlock_bh(&data_sockets.lock); + err = -EBUSY; + goto done; + } + read_unlock_bh(&data_sockets.lock); + } + _pms(sk)->ch.send = mISDN_send; _pms(sk)->ch.ctrl = mISDN_ctrl; @@ -490,14 +528,14 @@ data_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_len) case ISDN_P_NT_E1: mISDN_sock_unlink(&data_sockets, sk); err = connect_layer1(_pms(sk)->dev, &_pms(sk)->ch, - sk->sk_protocol, maddr); + sk->sk_protocol, maddr); if (err) mISDN_sock_link(&data_sockets, sk); break; case ISDN_P_LAPD_TE: case ISDN_P_LAPD_NT: err = create_l2entity(_pms(sk)->dev, &_pms(sk)->ch, - sk->sk_protocol, maddr); + sk->sk_protocol, maddr); break; case ISDN_P_B_RAW: case ISDN_P_B_HDLC: @@ -506,7 +544,7 @@ data_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_len) case ISDN_P_B_L2DSP: case ISDN_P_B_L2DSPHDLC: err = connect_Bstack(_pms(sk)->dev, &_pms(sk)->ch, - sk->sk_protocol, maddr); + sk->sk_protocol, maddr); break; default: err = -EPROTONOSUPPORT; @@ -523,9 +561,9 @@ done: static int data_sock_getname(struct socket *sock, struct sockaddr *addr, - int *addr_len, int peer) + int *addr_len, int peer) { - struct sockaddr_mISDN *maddr = (struct sockaddr_mISDN *) addr; + struct sockaddr_mISDN *maddr = (struct sockaddr_mISDN *) addr; struct sock *sk = sock->sk; if (!_pms(sk)->dev) @@ -534,6 +572,7 @@ data_sock_getname(struct socket *sock, struct sockaddr *addr, lock_sock(sk); *addr_len = sizeof(*maddr); + maddr->family = AF_ISDN; maddr->dev = _pms(sk)->dev->id; maddr->channel = _pms(sk)->ch.nr; maddr->sapi = _pms(sk)->ch.addr & 0xff; @@ -606,7 +645,7 @@ base_sock_release(struct socket *sock) static int base_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) { - int err = 0, id; + int err = 0, id; struct mISDNdevice *dev; struct mISDNversion ver; @@ -632,19 +671,35 @@ base_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) if (dev) { struct mISDN_devinfo di; + memset(&di, 0, sizeof(di)); di.id = dev->id; di.Dprotocols = dev->Dprotocols; di.Bprotocols = dev->Bprotocols | get_all_Bprotocols(); di.protocol = dev->D.protocol; memcpy(di.channelmap, dev->channelmap, - MISDN_CHMAP_SIZE * 4); + sizeof(di.channelmap)); di.nrbchan = dev->nrbchan; - strcpy(di.name, dev->name); + strcpy(di.name, dev_name(&dev->dev)); if (copy_to_user((void __user *)arg, &di, sizeof(di))) err = -EFAULT; } else err = -ENODEV; break; + case IMSETDEVNAME: + { + struct mISDN_devrename dn; + if (copy_from_user(&dn, (void __user *)arg, + sizeof(dn))) { + err = -EFAULT; + break; + } + dev = get_mdevice(dn.id); + if (dev) + err = device_rename(&dev->dev, dn.name); + else + err = -ENODEV; + } + break; default: err = -EINVAL; } @@ -725,11 +780,11 @@ base_sock_create(struct net *net, struct socket *sock, int protocol) } static int -mISDN_sock_create(struct net *net, struct socket *sock, int proto) +mISDN_sock_create(struct net *net, struct socket *sock, int proto, int kern) { int err = -EPROTONOSUPPORT; - switch (proto) { + switch (proto) { case ISDN_P_BASE: err = base_sock_create(net, sock, proto); break; @@ -754,8 +809,7 @@ mISDN_sock_create(struct net *net, struct socket *sock, int proto) return err; } -static struct -net_proto_family mISDN_sock_family_ops = { +static const struct net_proto_family mISDN_sock_family_ops = { .owner = THIS_MODULE, .family = PF_ISDN, .create = mISDN_sock_create, @@ -778,4 +832,3 @@ misdn_sock_cleanup(void) { sock_unregister(PF_ISDN); } - diff --git a/drivers/isdn/mISDN/stack.c b/drivers/isdn/mISDN/stack.c index 54cfddcc478..9cb4b621fbc 100644 --- a/drivers/isdn/mISDN/stack.c +++ b/drivers/isdn/mISDN/stack.c @@ -15,8 +15,10 @@ * */ +#include <linux/slab.h> #include <linux/mISDNif.h> #include <linux/kthread.h> +#include <linux/sched.h> #include "core.h" static u_int *debug; @@ -28,7 +30,7 @@ _queue_message(struct mISDNstack *st, struct sk_buff *skb) if (*debug & DEBUG_QUEUE_FUNC) printk(KERN_DEBUG "%s prim(%x) id(%x) %p\n", - __func__, hh->prim, hh->id, skb); + __func__, hh->prim, hh->id, skb); skb_queue_tail(&st->msgq, skb); if (likely(!test_bit(mISDN_STACK_STOPPED, &st->status))) { test_and_set_bit(mISDN_STACK_WORK, &st->status); @@ -36,7 +38,7 @@ _queue_message(struct mISDNstack *st, struct sk_buff *skb) } } -int +static int mISDN_queue_message(struct mISDNchannel *ch, struct sk_buff *skb) { _queue_message(ch->st, skb); @@ -62,12 +64,11 @@ unlock: static void send_socklist(struct mISDN_sock_list *sl, struct sk_buff *skb) { - struct hlist_node *node; struct sock *sk; struct sk_buff *cskb = NULL; read_lock(&sl->lock); - sk_for_each(sk, node, &sl->head) { + sk_for_each(sk, &sl->head) { if (sk->sk_state != MISDN_BOUND) continue; if (!cskb) @@ -108,15 +109,15 @@ send_layer2(struct mISDNstack *st, struct sk_buff *skb) if (ret) { if (*debug & DEBUG_SEND_ERR) printk(KERN_DEBUG - "%s ch%d prim(%x) addr(%x)" - " err %d\n", - __func__, ch->nr, - hh->prim, ch->addr, ret); + "%s ch%d prim(%x) addr(%x)" + " err %d\n", + __func__, ch->nr, + hh->prim, ch->addr, ret); dev_kfree_skb(cskb); } } else { printk(KERN_WARNING "%s ch%d addr %x no mem\n", - __func__, ch->nr, ch->addr); + __func__, ch->nr, ch->addr); goto out; } } @@ -134,8 +135,8 @@ send_layer2(struct mISDNstack *st, struct sk_buff *skb) skb = NULL; else if (*debug & DEBUG_SEND_ERR) printk(KERN_DEBUG - "%s ch%d mgr prim(%x) addr(%x) err %d\n", - __func__, ch->nr, hh->prim, ch->addr, ret); + "%s mgr prim(%x) err %d\n", + __func__, hh->prim, ret); } out: mutex_unlock(&st->lmutex); @@ -153,7 +154,7 @@ send_msg_to_layer(struct mISDNstack *st, struct sk_buff *skb) lm = hh->prim & MISDN_LAYERMASK; if (*debug & DEBUG_QUEUE_FUNC) printk(KERN_DEBUG "%s prim(%x) id(%x) %p\n", - __func__, hh->prim, hh->id, skb); + __func__, hh->prim, hh->id, skb); if (lm == 0x1) { if (!hlist_empty(&st->l1sock.head)) { __net_timestamp(skb); @@ -171,8 +172,9 @@ send_msg_to_layer(struct mISDNstack *st, struct sk_buff *skb) return ch->send(ch, skb); else printk(KERN_WARNING - "%s: dev(%s) prim(%x) id(%x) no channel\n", - __func__, st->dev->name, hh->prim, hh->id); + "%s: dev(%s) prim(%x) id(%x) no channel\n", + __func__, dev_name(&st->dev->dev), hh->prim, + hh->id); } else if (lm == 0x8) { WARN_ON(lm == 0x8); ch = get_channel4id(st, hh->id); @@ -180,12 +182,13 @@ send_msg_to_layer(struct mISDNstack *st, struct sk_buff *skb) return ch->send(ch, skb); else printk(KERN_WARNING - "%s: dev(%s) prim(%x) id(%x) no channel\n", - __func__, st->dev->name, hh->prim, hh->id); + "%s: dev(%s) prim(%x) id(%x) no channel\n", + __func__, dev_name(&st->dev->dev), hh->prim, + hh->id); } else { /* broadcast not handled yet */ printk(KERN_WARNING "%s: dev(%s) prim %x not delivered\n", - __func__, st->dev->name, hh->prim); + __func__, dev_name(&st->dev->dev), hh->prim); } return -ESRCH; } @@ -199,17 +202,15 @@ static int mISDNStackd(void *data) { struct mISDNstack *st = data; +#ifdef MISDN_MSG_STATS + cputime_t utime, stime; +#endif int err = 0; -#ifdef CONFIG_SMP - lock_kernel(); -#endif sigfillset(¤t->blocked); -#ifdef CONFIG_SMP - unlock_kernel(); -#endif if (*debug & DEBUG_MSG_THREAD) - printk(KERN_DEBUG "mISDNStackd %s started\n", st->dev->name); + printk(KERN_DEBUG "mISDNStackd %s started\n", + dev_name(&st->dev->dev)); if (st->notify != NULL) { complete(st->notify); @@ -228,13 +229,13 @@ mISDNStackd(void *data) skb = skb_dequeue(&st->msgq); if (!skb) { test_and_clear_bit(mISDN_STACK_WORK, - &st->status); + &st->status); /* test if a race happens */ skb = skb_dequeue(&st->msgq); if (!skb) continue; test_and_set_bit(mISDN_STACK_WORK, - &st->status); + &st->status); } #ifdef MISDN_MSG_STATS st->msg_cnt++; @@ -243,20 +244,20 @@ mISDNStackd(void *data) if (unlikely(err)) { if (*debug & DEBUG_SEND_ERR) printk(KERN_DEBUG - "%s: %s prim(%x) id(%x) " - "send call(%d)\n", - __func__, st->dev->name, - mISDN_HEAD_PRIM(skb), - mISDN_HEAD_ID(skb), err); + "%s: %s prim(%x) id(%x) " + "send call(%d)\n", + __func__, dev_name(&st->dev->dev), + mISDN_HEAD_PRIM(skb), + mISDN_HEAD_ID(skb), err); dev_kfree_skb(skb); continue; } if (unlikely(test_bit(mISDN_STACK_STOPPED, - &st->status))) { + &st->status))) { test_and_clear_bit(mISDN_STACK_WORK, - &st->status); + &st->status); test_and_clear_bit(mISDN_STACK_RUNNING, - &st->status); + &st->status); break; } } @@ -272,7 +273,7 @@ mISDNStackd(void *data) test_and_set_bit(mISDN_STACK_RUNNING, &st->status); if (!skb_queue_empty(&st->msgq)) test_and_set_bit(mISDN_STACK_WORK, - &st->status); + &st->status); } if (test_bit(mISDN_STACK_ABORT, &st->status)) break; @@ -285,10 +286,10 @@ mISDNStackd(void *data) #endif test_and_clear_bit(mISDN_STACK_ACTIVE, &st->status); wait_event_interruptible(st->workq, (st->status & - mISDN_STACK_ACTION_MASK)); + mISDN_STACK_ACTION_MASK)); if (*debug & DEBUG_MSG_THREAD) printk(KERN_DEBUG "%s: %s wake status %08lx\n", - __func__, st->dev->name, st->status); + __func__, dev_name(&st->dev->dev), st->status); test_and_set_bit(mISDN_STACK_ACTIVE, &st->status); test_and_clear_bit(mISDN_STACK_WAKEUP, &st->status); @@ -302,16 +303,18 @@ mISDNStackd(void *data) } #ifdef MISDN_MSG_STATS printk(KERN_DEBUG "mISDNStackd daemon for %s proceed %d " - "msg %d sleep %d stopped\n", - st->dev->name, st->msg_cnt, st->sleep_cnt, st->stopped_cnt); + "msg %d sleep %d stopped\n", + dev_name(&st->dev->dev), st->msg_cnt, st->sleep_cnt, + st->stopped_cnt); + task_cputime(st->thread, &utime, &stime); printk(KERN_DEBUG - "mISDNStackd daemon for %s utime(%ld) stime(%ld)\n", - st->dev->name, st->thread->utime, st->thread->stime); + "mISDNStackd daemon for %s utime(%ld) stime(%ld)\n", + dev_name(&st->dev->dev), utime, stime); printk(KERN_DEBUG - "mISDNStackd daemon for %s nvcsw(%ld) nivcsw(%ld)\n", - st->dev->name, st->thread->nvcsw, st->thread->nivcsw); + "mISDNStackd daemon for %s nvcsw(%ld) nivcsw(%ld)\n", + dev_name(&st->dev->dev), st->thread->nvcsw, st->thread->nivcsw); printk(KERN_DEBUG "mISDNStackd daemon for %s killed now\n", - st->dev->name); + dev_name(&st->dev->dev)); #endif test_and_set_bit(mISDN_STACK_KILLED, &st->status); test_and_clear_bit(mISDN_STACK_RUNNING, &st->status); @@ -359,7 +362,7 @@ add_layer2(struct mISDNchannel *ch, struct mISDNstack *st) static int st_own_ctrl(struct mISDNchannel *ch, u_int cmd, void *arg) { - if (!ch->st || ch->st->layer1) + if (!ch->st || !ch->st->layer1) return -EINVAL; return ch->st->layer1->ctrl(ch->st->layer1, cmd, arg); } @@ -401,15 +404,16 @@ create_stack(struct mISDNdevice *dev) newst->own.send = mISDN_queue_message; newst->own.recv = mISDN_queue_message; if (*debug & DEBUG_CORE_FUNC) - printk(KERN_DEBUG "%s: st(%s)\n", __func__, newst->dev->name); + printk(KERN_DEBUG "%s: st(%s)\n", __func__, + dev_name(&newst->dev->dev)); newst->notify = &done; newst->thread = kthread_run(mISDNStackd, (void *)newst, "mISDN_%s", - newst->dev->name); + dev_name(&newst->dev->dev)); if (IS_ERR(newst->thread)) { err = PTR_ERR(newst->thread); printk(KERN_ERR - "mISDN:cannot create kernel thread for %s (%d)\n", - newst->dev->name, err); + "mISDN:cannot create kernel thread for %s (%d)\n", + dev_name(&newst->dev->dev), err); delete_teimanager(dev->teimgr); kfree(newst); } else @@ -419,7 +423,7 @@ create_stack(struct mISDNdevice *dev) int connect_layer1(struct mISDNdevice *dev, struct mISDNchannel *ch, - u_int protocol, struct sockaddr_mISDN *adr) + u_int protocol, struct sockaddr_mISDN *adr) { struct mISDN_sock *msk = container_of(ch, struct mISDN_sock, ch); struct channel_req rq; @@ -428,29 +432,21 @@ connect_layer1(struct mISDNdevice *dev, struct mISDNchannel *ch, if (*debug & DEBUG_CORE_FUNC) printk(KERN_DEBUG "%s: %s proto(%x) adr(%d %d %d %d)\n", - __func__, dev->name, protocol, adr->dev, adr->channel, - adr->sapi, adr->tei); + __func__, dev_name(&dev->dev), protocol, adr->dev, + adr->channel, adr->sapi, adr->tei); switch (protocol) { case ISDN_P_NT_S0: case ISDN_P_NT_E1: case ISDN_P_TE_S0: case ISDN_P_TE_E1: -#ifdef PROTOCOL_CHECK - /* this should be enhanced */ - if (!list_empty(&dev->D.st->layer2) - && dev->D.protocol != protocol) - return -EBUSY; - if (!hlist_empty(&dev->D.st->l1sock.head) - && dev->D.protocol != protocol) - return -EBUSY; -#endif ch->recv = mISDN_queue_message; ch->peer = &dev->D.st->own; ch->st = dev->D.st; rq.protocol = protocol; - rq.adr.channel = 0; + rq.adr.channel = adr->channel; err = dev->D.ctrl(&dev->D, OPEN_CHANNEL, &rq); - printk(KERN_DEBUG "%s: ret 1 %d\n", __func__, err); + printk(KERN_DEBUG "%s: ret %d (dev %d)\n", __func__, err, + dev->id); if (err) return err; write_lock_bh(&dev->D.st->l1sock.lock); @@ -465,7 +461,7 @@ connect_layer1(struct mISDNdevice *dev, struct mISDNchannel *ch, int connect_Bstack(struct mISDNdevice *dev, struct mISDNchannel *ch, - u_int protocol, struct sockaddr_mISDN *adr) + u_int protocol, struct sockaddr_mISDN *adr) { struct channel_req rq, rq2; int pmask, err; @@ -473,9 +469,9 @@ connect_Bstack(struct mISDNdevice *dev, struct mISDNchannel *ch, if (*debug & DEBUG_CORE_FUNC) printk(KERN_DEBUG "%s: %s proto(%x) adr(%d %d %d %d)\n", - __func__, dev->name, protocol, - adr->dev, adr->channel, adr->sapi, - adr->tei); + __func__, dev_name(&dev->dev), protocol, + adr->dev, adr->channel, adr->sapi, + adr->tei); ch->st = dev->D.st; pmask = 1 << (protocol & ISDN_P_B_MASK); if (pmask & dev->Bprotocols) { @@ -522,16 +518,16 @@ connect_Bstack(struct mISDNdevice *dev, struct mISDNchannel *ch, int create_l2entity(struct mISDNdevice *dev, struct mISDNchannel *ch, - u_int protocol, struct sockaddr_mISDN *adr) + u_int protocol, struct sockaddr_mISDN *adr) { struct channel_req rq; int err; if (*debug & DEBUG_CORE_FUNC) printk(KERN_DEBUG "%s: %s proto(%x) adr(%d %d %d %d)\n", - __func__, dev->name, protocol, - adr->dev, adr->channel, adr->sapi, - adr->tei); + __func__, dev_name(&dev->dev), protocol, + adr->dev, adr->channel, adr->sapi, + adr->tei); rq.protocol = ISDN_P_TE_S0; if (dev->Dprotocols & (1 << ISDN_P_TE_E1)) rq.protocol = ISDN_P_TE_E1; @@ -541,15 +537,6 @@ create_l2entity(struct mISDNdevice *dev, struct mISDNchannel *ch, if (dev->Dprotocols & (1 << ISDN_P_NT_E1)) rq.protocol = ISDN_P_NT_E1; case ISDN_P_LAPD_TE: -#ifdef PROTOCOL_CHECK - /* this should be enhanced */ - if (!list_empty(&dev->D.st->layer2) - && dev->D.protocol != protocol) - return -EBUSY; - if (!hlist_empty(&dev->D.st->l1sock.head) - && dev->D.protocol != protocol) - return -EBUSY; -#endif ch->recv = mISDN_queue_message; ch->peer = &dev->D.st->own; ch->st = dev->D.st; @@ -590,7 +577,7 @@ delete_channel(struct mISDNchannel *ch) } if (*debug & DEBUG_CORE_FUNC) printk(KERN_DEBUG "%s: st(%s) protocol(%x)\n", __func__, - ch->st->dev->name, ch->protocol); + dev_name(&ch->st->dev->dev), ch->protocol); if (ch->protocol >= ISDN_P_B_START) { if (ch->peer) { ch->peer->ctrl(ch->peer, CLOSE_CHANNEL, NULL); @@ -619,7 +606,7 @@ delete_channel(struct mISDNchannel *ch) pch->ctrl(pch, CLOSE_CHANNEL, NULL); } else printk(KERN_WARNING "%s: no l2 channel\n", - __func__); + __func__); break; case ISDN_P_LAPD_NT: pch = ch->st->dev->teimgr; @@ -627,7 +614,7 @@ delete_channel(struct mISDNchannel *ch) pch->ctrl(pch, CLOSE_CHANNEL, NULL); } else printk(KERN_WARNING "%s: no l2 channel\n", - __func__); + __func__); break; default: break; @@ -643,14 +630,14 @@ delete_stack(struct mISDNdevice *dev) if (*debug & DEBUG_CORE_FUNC) printk(KERN_DEBUG "%s: st(%s)\n", __func__, - st->dev->name); + dev_name(&st->dev->dev)); if (dev->teimgr) delete_teimanager(dev->teimgr); if (st->thread) { if (st->notify) { printk(KERN_WARNING "%s: notifier in use\n", - __func__); - complete(st->notify); + __func__); + complete(st->notify); } st->notify = &done; test_and_set_bit(mISDN_STACK_ABORT, &st->status); @@ -660,10 +647,10 @@ delete_stack(struct mISDNdevice *dev) } if (!list_empty(&st->layer2)) printk(KERN_WARNING "%s: layer2 list not empty\n", - __func__); + __func__); if (!hlist_empty(&st->l1sock.head)) printk(KERN_WARNING "%s: layer1 list not empty\n", - __func__); + __func__); kfree(st); } diff --git a/drivers/isdn/mISDN/tei.c b/drivers/isdn/mISDN/tei.c index 6fbae42127b..592f597d895 100644 --- a/drivers/isdn/mISDN/tei.c +++ b/drivers/isdn/mISDN/tei.c @@ -16,6 +16,7 @@ */ #include "layer2.h" #include <linux/random.h> +#include <linux/slab.h> #include "core.h" #define ID_REQUEST 1 @@ -33,7 +34,7 @@ #define DATIMER_VAL 10000 -static u_int *debug; +static u_int *debug; static struct Fsm deactfsm = {NULL, 0, 0, NULL, NULL}; static struct Fsm teifsmu = {NULL, 0, 0, NULL, NULL}; @@ -44,7 +45,7 @@ enum { ST_L1_DEACT_PENDING, ST_L1_ACTIV, }; -#define DEACT_STATE_COUNT (ST_L1_ACTIV+1) +#define DEACT_STATE_COUNT (ST_L1_ACTIV + 1) static char *strDeactState[] = { @@ -62,7 +63,7 @@ enum { EV_DATIMER, }; -#define DEACT_EVENT_COUNT (EV_DATIMER+1) +#define DEACT_EVENT_COUNT (EV_DATIMER + 1) static char *strDeactEvent[] = { @@ -78,14 +79,19 @@ static void da_debug(struct FsmInst *fi, char *fmt, ...) { struct manager *mgr = fi->userdata; + struct va_format vaf; va_list va; if (!(*debug & DEBUG_L2_TEIFSM)) return; + va_start(va, fmt); - printk(KERN_DEBUG "mgr(%d): ", mgr->ch.st->dev->id); - vprintk(fmt, va); - printk("\n"); + + vaf.fmt = fmt; + vaf.va = &va; + + printk(KERN_DEBUG "mgr(%d): %pV\n", mgr->ch.st->dev->id, &vaf); + va_end(va); } @@ -122,8 +128,11 @@ da_deactivate(struct FsmInst *fi, int event, void *arg) } read_unlock_irqrestore(&mgr->lock, flags); /* All TEI are inactiv */ - mISDN_FsmAddTimer(&mgr->datimer, DATIMER_VAL, EV_DATIMER, NULL, 1); - mISDN_FsmChangeState(fi, ST_L1_DEACT_PENDING); + if (!test_bit(OPTION_L1_HOLD, &mgr->options)) { + mISDN_FsmAddTimer(&mgr->datimer, DATIMER_VAL, EV_DATIMER, + NULL, 1); + mISDN_FsmChangeState(fi, ST_L1_DEACT_PENDING); + } } static void @@ -132,9 +141,11 @@ da_ui(struct FsmInst *fi, int event, void *arg) struct manager *mgr = fi->userdata; /* restart da timer */ - mISDN_FsmDelTimer(&mgr->datimer, 2); - mISDN_FsmAddTimer(&mgr->datimer, DATIMER_VAL, EV_DATIMER, NULL, 2); - + if (!test_bit(OPTION_L1_HOLD, &mgr->options)) { + mISDN_FsmDelTimer(&mgr->datimer, 2); + mISDN_FsmAddTimer(&mgr->datimer, DATIMER_VAL, EV_DATIMER, + NULL, 2); + } } static void @@ -158,7 +169,7 @@ da_timer(struct FsmInst *fi, int event, void *arg) /* All TEI are inactiv */ mISDN_FsmChangeState(fi, ST_L1_DEACT); _queue_data(&mgr->ch, PH_DEACTIVATE_REQ, MISDN_ID_ANY, 0, NULL, - GFP_ATOMIC); + GFP_ATOMIC); } static struct FsmNode DeactFnList[] = @@ -177,7 +188,7 @@ enum { ST_TEI_IDVERIFY, }; -#define TEI_STATE_COUNT (ST_TEI_IDVERIFY+1) +#define TEI_STATE_COUNT (ST_TEI_IDVERIFY + 1) static char *strTeiState[] = { @@ -198,7 +209,7 @@ enum { EV_TIMER, }; -#define TEI_EVENT_COUNT (EV_TIMER+1) +#define TEI_EVENT_COUNT (EV_TIMER + 1) static char *strTeiEvent[] = { @@ -217,14 +228,20 @@ static void tei_debug(struct FsmInst *fi, char *fmt, ...) { struct teimgr *tm = fi->userdata; + struct va_format vaf; va_list va; if (!(*debug & DEBUG_L2_TEIFSM)) return; + va_start(va, fmt); - printk(KERN_DEBUG "tei(%d): ", tm->l2->tei); - vprintk(fmt, va); - printk("\n"); + + vaf.fmt = fmt; + vaf.va = &va; + + printk(KERN_DEBUG "sapi(%d) tei(%d): %pV\n", + tm->l2->sapi, tm->l2->tei, &vaf); + va_end(va); } @@ -233,31 +250,31 @@ tei_debug(struct FsmInst *fi, char *fmt, ...) static int get_free_id(struct manager *mgr) { - u64 ids = 0; + DECLARE_BITMAP(ids, 64) = { [0 ... BITS_TO_LONGS(64) - 1] = 0 }; int i; struct layer2 *l2; list_for_each_entry(l2, &mgr->layer2, list) { if (l2->ch.nr > 63) { printk(KERN_WARNING - "%s: more as 63 layer2 for one device\n", - __func__); + "%s: more as 63 layer2 for one device\n", + __func__); return -EBUSY; } - test_and_set_bit(l2->ch.nr, (u_long *)&ids); + __set_bit(l2->ch.nr, ids); } - for (i = 1; i < 64; i++) - if (!test_bit(i, (u_long *)&ids)) - return i; + i = find_next_zero_bit(ids, 64, 1); + if (i < 64) + return i; printk(KERN_WARNING "%s: more as 63 layer2 for one device\n", - __func__); + __func__); return -EBUSY; } static int get_free_tei(struct manager *mgr) { - u64 ids = 0; + DECLARE_BITMAP(ids, 64) = { [0 ... BITS_TO_LONGS(64) - 1] = 0 }; int i; struct layer2 *l2; @@ -271,13 +288,13 @@ get_free_tei(struct manager *mgr) continue; i -= 64; - test_and_set_bit(i, (u_long *)&ids); + __set_bit(i, ids); } - for (i = 0; i < 64; i++) - if (!test_bit(i, (u_long *)&ids)) - return i + 64; + i = find_first_zero_bit(ids, 64); + if (i < 64) + return i + 64; printk(KERN_WARNING "%s: more as 63 dynamic tei for one device\n", - __func__); + __func__); return -1; } @@ -368,7 +385,7 @@ mgr_send_down(struct manager *mgr, struct sk_buff *skb) skb_queue_tail(&mgr->sendq, skb); if (!test_bit(MGR_PH_ACTIVE, &mgr->options)) { _queue_data(&mgr->ch, PH_ACTIVATE_REQ, MISDN_ID_ANY, 0, - NULL, GFP_KERNEL); + NULL, GFP_KERNEL); } else { do_send(mgr); } @@ -381,7 +398,7 @@ dl_unit_data(struct manager *mgr, struct sk_buff *skb) return -EINVAL; if (!test_bit(MGR_PH_ACTIVE, &mgr->options)) _queue_data(&mgr->ch, PH_ACTIVATE_REQ, MISDN_ID_ANY, 0, - NULL, GFP_KERNEL); + NULL, GFP_KERNEL); skb_push(skb, 3); skb->data[0] = 0x02; /* SAPI 0 C/R = 1 */ skb->data[1] = 0xff; /* TEI 127 */ @@ -393,7 +410,7 @@ dl_unit_data(struct manager *mgr, struct sk_buff *skb) return 0; } -unsigned int +static unsigned int random_ri(void) { u16 x; @@ -421,7 +438,7 @@ done: } static void -put_tei_msg(struct manager *mgr, u_char m_id, unsigned int ri, u_char tei) +put_tei_msg(struct manager *mgr, u_char m_id, unsigned int ri, int tei) { struct sk_buff *skb; u_char bp[8]; @@ -435,9 +452,8 @@ put_tei_msg(struct manager *mgr, u_char m_id, unsigned int ri, u_char tei) bp[4] = ri >> 8; bp[5] = ri & 0xff; bp[6] = m_id; - bp[7] = (tei << 1) | 1; - skb = _alloc_mISDN_skb(PH_DATA_REQ, new_id(mgr), - 8, bp, GFP_ATOMIC); + bp[7] = ((tei << 1) & 0xff) | 1; + skb = _alloc_mISDN_skb(PH_DATA_REQ, new_id(mgr), 8, bp, GFP_ATOMIC); if (!skb) { printk(KERN_WARNING "%s: no skb for tei msg\n", __func__); return; @@ -452,14 +468,14 @@ tei_id_request(struct FsmInst *fi, int event, void *arg) if (tm->l2->tei != GROUP_TEI) { tm->tei_m.printdebug(&tm->tei_m, - "assign request for allready assigned tei %d", - tm->l2->tei); + "assign request for already assigned tei %d", + tm->l2->tei); return; } tm->ri = random_ri(); if (*debug & DEBUG_L2_TEI) tm->tei_m.printdebug(&tm->tei_m, - "assign request ri %d", tm->ri); + "assign request ri %d", tm->ri); put_tei_msg(tm->mgr, ID_REQUEST, tm->ri, GROUP_TEI); mISDN_FsmChangeState(fi, ST_TEI_IDREQ); mISDN_FsmAddTimer(&tm->timer, tm->tval, EV_TIMER, NULL, 1); @@ -480,12 +496,12 @@ tei_id_assign(struct FsmInst *fi, int event, void *arg) tei = *dp >> 1; if (*debug & DEBUG_L2_TEI) tm->tei_m.printdebug(fi, "identity assign ri %d tei %d", - ri, tei); + ri, tei); l2 = findtei(tm->mgr, tei); if (l2) { /* same tei is in use */ if (ri != l2->tm->ri) { tm->tei_m.printdebug(fi, - "possible duplicate assignment tei %d", tei); + "possible duplicate assignment tei %d", tei); tei_l2(l2, MDL_ERROR_RSP, 0); } } else if (ri == tm->ri) { @@ -509,12 +525,12 @@ tei_id_test_dup(struct FsmInst *fi, int event, void *arg) tei = *dp >> 1; if (*debug & DEBUG_L2_TEI) tm->tei_m.printdebug(fi, "foreign identity assign ri %d tei %d", - ri, tei); + ri, tei); l2 = findtei(tm->mgr, tei); if (l2) { /* same tei is in use */ if (ri != l2->tm->ri) { /* and it wasn't our request */ tm->tei_m.printdebug(fi, - "possible duplicate assignment tei %d", tei); + "possible duplicate assignment tei %d", tei); mISDN_FsmEvent(&l2->tm->tei_m, EV_VERIFY, NULL); } } @@ -533,7 +549,7 @@ tei_id_denied(struct FsmInst *fi, int event, void *arg) tei = *dp >> 1; if (*debug & DEBUG_L2_TEI) tm->tei_m.printdebug(fi, "identity denied ri %d tei %d", - ri, tei); + ri, tei); } static void @@ -543,11 +559,11 @@ tei_id_chk_req(struct FsmInst *fi, int event, void *arg) u_char *dp = arg; int tei; - tei = *(dp+3) >> 1; + tei = *(dp + 3) >> 1; if (*debug & DEBUG_L2_TEI) tm->tei_m.printdebug(fi, "identity check req tei %d", tei); if ((tm->l2->tei != GROUP_TEI) && ((tei == GROUP_TEI) || - (tei == tm->l2->tei))) { + (tei == tm->l2->tei))) { mISDN_FsmDelTimer(&tm->timer, 4); mISDN_FsmChangeState(&tm->tei_m, ST_TEI_NOP); put_tei_msg(tm->mgr, ID_CHK_RES, random_ri(), tm->l2->tei); @@ -561,7 +577,7 @@ tei_id_remove(struct FsmInst *fi, int event, void *arg) u_char *dp = arg; int tei; - tei = *(dp+3) >> 1; + tei = *(dp + 3) >> 1; if (*debug & DEBUG_L2_TEI) tm->tei_m.printdebug(fi, "identity remove tei %d", tei); if ((tm->l2->tei != GROUP_TEI) && @@ -579,7 +595,7 @@ tei_id_verify(struct FsmInst *fi, int event, void *arg) if (*debug & DEBUG_L2_TEI) tm->tei_m.printdebug(fi, "id verify request for tei %d", - tm->l2->tei); + tm->l2->tei); put_tei_msg(tm->mgr, ID_VERIFY, 0, tm->l2->tei); mISDN_FsmChangeState(&tm->tei_m, ST_TEI_IDVERIFY); mISDN_FsmAddTimer(&tm->timer, tm->tval, EV_TIMER, NULL, 2); @@ -595,7 +611,7 @@ tei_id_req_tout(struct FsmInst *fi, int event, void *arg) tm->ri = random_ri(); if (*debug & DEBUG_L2_TEI) tm->tei_m.printdebug(fi, "assign req(%d) ri %d", - 4 - tm->nval, tm->ri); + 4 - tm->nval, tm->ri); put_tei_msg(tm->mgr, ID_REQUEST, tm->ri, GROUP_TEI); mISDN_FsmAddTimer(&tm->timer, tm->tval, EV_TIMER, NULL, 3); } else { @@ -613,13 +629,13 @@ tei_id_ver_tout(struct FsmInst *fi, int event, void *arg) if (--tm->nval) { if (*debug & DEBUG_L2_TEI) tm->tei_m.printdebug(fi, - "id verify req(%d) for tei %d", - 3 - tm->nval, tm->l2->tei); + "id verify req(%d) for tei %d", + 3 - tm->nval, tm->l2->tei); put_tei_msg(tm->mgr, ID_VERIFY, 0, tm->l2->tei); mISDN_FsmAddTimer(&tm->timer, tm->tval, EV_TIMER, NULL, 4); } else { tm->tei_m.printdebug(fi, "verify req for tei %d failed", - tm->l2->tei); + tm->l2->tei); tei_l2(tm->l2, MDL_REMOVE_REQ, 0); mISDN_FsmChangeState(fi, ST_TEI_NOP); } @@ -657,14 +673,14 @@ tei_assign_req(struct FsmInst *fi, int event, void *arg) if (tm->l2->tei == GROUP_TEI) { tm->tei_m.printdebug(&tm->tei_m, - "net tei assign request without tei"); + "net tei assign request without tei"); return; } tm->ri = ((unsigned int) *dp++ << 8); tm->ri += *dp++; if (*debug & DEBUG_L2_TEI) tm->tei_m.printdebug(&tm->tei_m, - "net assign request ri %d teim %d", tm->ri, *dp); + "net assign request ri %d teim %d", tm->ri, *dp); put_tei_msg(tm->mgr, ID_ASSIGNED, tm->ri, tm->l2->tei); mISDN_FsmChangeState(fi, ST_TEI_NOP); } @@ -676,7 +692,7 @@ tei_id_chk_req_net(struct FsmInst *fi, int event, void *arg) if (*debug & DEBUG_L2_TEI) tm->tei_m.printdebug(fi, "id check request for tei %d", - tm->l2->tei); + tm->l2->tei); tm->rcnt = 0; put_tei_msg(tm->mgr, ID_CHK_REQ, 0, tm->l2->tei); mISDN_FsmChangeState(&tm->tei_m, ST_TEI_IDVERIFY); @@ -708,7 +724,7 @@ tei_id_verify_net(struct FsmInst *fi, int event, void *arg) tei = dp[3] >> 1; if (*debug & DEBUG_L2_TEI) tm->tei_m.printdebug(fi, "identity verify req tei %d/%d", - tei, tm->l2->tei); + tei, tm->l2->tei); if (tei == tm->l2->tei) tei_id_chk_req_net(fi, event, arg); } @@ -721,7 +737,7 @@ tei_id_ver_tout_net(struct FsmInst *fi, int event, void *arg) if (tm->rcnt == 1) { if (*debug & DEBUG_L2_TEI) tm->tei_m.printdebug(fi, - "check req for tei %d sucessful\n", tm->l2->tei); + "check req for tei %d successful\n", tm->l2->tei); mISDN_FsmChangeState(fi, ST_TEI_NOP); } else if (tm->rcnt > 1) { /* duplicate assignment; remove */ @@ -729,13 +745,13 @@ tei_id_ver_tout_net(struct FsmInst *fi, int event, void *arg) } else if (--tm->nval) { if (*debug & DEBUG_L2_TEI) tm->tei_m.printdebug(fi, - "id check req(%d) for tei %d", - 3 - tm->nval, tm->l2->tei); + "id check req(%d) for tei %d", + 3 - tm->nval, tm->l2->tei); put_tei_msg(tm->mgr, ID_CHK_REQ, 0, tm->l2->tei); mISDN_FsmAddTimer(&tm->timer, tm->tval, EV_TIMER, NULL, 4); } else { tm->tei_m.printdebug(fi, "check req for tei %d failed", - tm->l2->tei); + tm->l2->tei); mISDN_FsmChangeState(fi, ST_TEI_NOP); tei_l2remove(tm->l2); } @@ -772,21 +788,26 @@ tei_ph_data_ind(struct teimgr *tm, u_int mt, u_char *dp, int len) } static struct layer2 * -create_new_tei(struct manager *mgr, int tei) +create_new_tei(struct manager *mgr, int tei, int sapi) { - u_long opt = 0; - u_long flags; - int id; - struct layer2 *l2; + unsigned long opt = 0; + unsigned long flags; + int id; + struct layer2 *l2; + struct channel_req rq; if (!mgr->up) return NULL; - if (tei < 64) + if ((tei >= 0) && (tei < 64)) test_and_set_bit(OPTION_L2_FIXEDTEI, &opt); - if (mgr->ch.st->dev->Dprotocols - & ((1 << ISDN_P_TE_E1) | (1 << ISDN_P_NT_E1))) + if (mgr->ch.st->dev->Dprotocols & ((1 << ISDN_P_TE_E1) | + (1 << ISDN_P_NT_E1))) { test_and_set_bit(OPTION_L2_PMX, &opt); - l2 = create_l2(mgr->up, ISDN_P_LAPD_NT, (u_int)opt, (u_long)tei); + rq.protocol = ISDN_P_NT_E1; + } else { + rq.protocol = ISDN_P_NT_S0; + } + l2 = create_l2(mgr->up, ISDN_P_LAPD_NT, opt, tei, sapi); if (!l2) { printk(KERN_WARNING "%s:no memory for layer2\n", __func__); return NULL; @@ -820,6 +841,14 @@ create_new_tei(struct manager *mgr, int tei) l2->ch.recv = mgr->ch.recv; l2->ch.peer = mgr->ch.peer; l2->ch.ctrl(&l2->ch, OPEN_CHANNEL, NULL); + /* We need open here L1 for the manager as well (refcounting) */ + rq.adr.dev = mgr->ch.st->dev->id; + id = mgr->ch.st->own.ctrl(&mgr->ch.st->own, OPEN_CHANNEL, &rq); + if (id < 0) { + printk(KERN_WARNING "%s: cannot open L1\n", __func__); + l2->ch.ctrl(&l2->ch, CLOSE_CHANNEL, NULL); + l2 = NULL; + } } return l2; } @@ -834,12 +863,17 @@ new_tei_req(struct manager *mgr, u_char *dp) ri += dp[1]; if (!mgr->up) goto denied; - tei = get_free_tei(mgr); + if (!(dp[3] & 1)) /* Extension bit != 1 */ + goto denied; + if (dp[3] != 0xff) + tei = dp[3] >> 1; /* 3GPP TS 08.56 6.1.11.2 */ + else + tei = get_free_tei(mgr); if (tei < 0) { printk(KERN_WARNING "%s:No free tei\n", __func__); goto denied; } - l2 = create_new_tei(mgr, tei); + l2 = create_new_tei(mgr, tei, CTRL_SAPI); if (!l2) goto denied; else @@ -853,17 +887,15 @@ static int ph_data_ind(struct manager *mgr, struct sk_buff *skb) { int ret = -EINVAL; - struct layer2 *l2; - u_long flags; + struct layer2 *l2, *nl2; u_char mt; if (skb->len < 8) { if (*debug & DEBUG_L2_TEI) printk(KERN_DEBUG "%s: short mgr frame %d/8\n", - __func__, skb->len); + __func__, skb->len); goto done; } - if (*debug & DEBUG_L2_TEI) if ((skb->data[0] >> 2) != TEI_SAPI) /* not for us */ goto done; @@ -900,11 +932,9 @@ ph_data_ind(struct manager *mgr, struct sk_buff *skb) new_tei_req(mgr, &skb->data[4]); goto done; } - read_lock_irqsave(&mgr->lock, flags); - list_for_each_entry(l2, &mgr->layer2, list) { + list_for_each_entry_safe(l2, nl2, &mgr->layer2, list) { tei_ph_data_ind(l2->tm, mt, &skb->data[4], skb->len - 4); } - read_unlock_irqrestore(&mgr->lock, flags); done: return ret; } @@ -961,18 +991,17 @@ TEIrelease(struct layer2 *l2) static int create_teimgr(struct manager *mgr, struct channel_req *crq) { - struct layer2 *l2; - u_long opt = 0; - u_long flags; - int id; + struct layer2 *l2; + unsigned long opt = 0; + unsigned long flags; + int id; + struct channel_req l1rq; if (*debug & DEBUG_L2_TEI) printk(KERN_DEBUG "%s: %s proto(%x) adr(%d %d %d %d)\n", - __func__, mgr->ch.st->dev->name, crq->protocol, - crq->adr.dev, crq->adr.channel, crq->adr.sapi, - crq->adr.tei); - if (crq->adr.sapi != 0) /* not supported yet */ - return -EINVAL; + __func__, dev_name(&mgr->ch.st->dev->dev), + crq->protocol, crq->adr.dev, crq->adr.channel, + crq->adr.sapi, crq->adr.tei); if (crq->adr.tei > GROUP_TEI) return -EINVAL; if (crq->adr.tei < 64) @@ -986,8 +1015,8 @@ create_teimgr(struct manager *mgr, struct channel_req *crq) return -EINVAL; if (mgr->up) { printk(KERN_WARNING - "%s: only one network manager is allowed\n", - __func__); + "%s: only one network manager is allowed\n", + __func__); return -EBUSY; } } else if (test_bit(MGR_OPT_USER, &mgr->options)) { @@ -1001,13 +1030,16 @@ create_teimgr(struct manager *mgr, struct channel_req *crq) if (crq->protocol == ISDN_P_LAPD_TE) test_and_set_bit(MGR_OPT_USER, &mgr->options); } + l1rq.adr = crq->adr; if (mgr->ch.st->dev->Dprotocols - & ((1 << ISDN_P_TE_E1) | (1 << ISDN_P_NT_E1))) + & ((1 << ISDN_P_TE_E1) | (1 << ISDN_P_NT_E1))) test_and_set_bit(OPTION_L2_PMX, &opt); if ((crq->protocol == ISDN_P_LAPD_NT) && (crq->adr.tei == 127)) { mgr->up = crq->ch; id = DL_INFO_L2_CONNECT; teiup_create(mgr, DL_INFORMATION_IND, sizeof(id), &id); + if (test_bit(MGR_PH_ACTIVE, &mgr->options)) + teiup_create(mgr, PH_ACTIVATE_IND, 0, NULL); crq->ch = NULL; if (!list_empty(&mgr->layer2)) { read_lock_irqsave(&mgr->lock, flags); @@ -1019,8 +1051,8 @@ create_teimgr(struct manager *mgr, struct channel_req *crq) } return 0; } - l2 = create_l2(crq->ch, crq->protocol, (u_int)opt, - (u_long)crq->adr.tei); + l2 = create_l2(crq->ch, crq->protocol, opt, + crq->adr.tei, crq->adr.sapi); if (!l2) return -ENOMEM; l2->tm = kzalloc(sizeof(struct teimgr), GFP_KERNEL); @@ -1038,24 +1070,34 @@ create_teimgr(struct manager *mgr, struct channel_req *crq) l2->tm->tei_m.fsm = &teifsmu; l2->tm->tei_m.state = ST_TEI_NOP; l2->tm->tval = 1000; /* T201 1 sec */ + if (test_bit(OPTION_L2_PMX, &opt)) + l1rq.protocol = ISDN_P_TE_E1; + else + l1rq.protocol = ISDN_P_TE_S0; } else { l2->tm->tei_m.fsm = &teifsmn; l2->tm->tei_m.state = ST_TEI_NOP; l2->tm->tval = 2000; /* T202 2 sec */ + if (test_bit(OPTION_L2_PMX, &opt)) + l1rq.protocol = ISDN_P_NT_E1; + else + l1rq.protocol = ISDN_P_NT_S0; } mISDN_FsmInitTimer(&l2->tm->tei_m, &l2->tm->timer); write_lock_irqsave(&mgr->lock, flags); id = get_free_id(mgr); list_add_tail(&l2->list, &mgr->layer2); write_unlock_irqrestore(&mgr->lock, flags); - if (id < 0) { - l2->ch.ctrl(&l2->ch, CLOSE_CHANNEL, NULL); - } else { + if (id >= 0) { l2->ch.nr = id; l2->up->nr = id; crq->ch = &l2->ch; - id = 0; + /* We need open here L1 for the manager as well (refcounting) */ + id = mgr->ch.st->own.ctrl(&mgr->ch.st->own, OPEN_CHANNEL, + &l1rq); } + if (id < 0) + l2->ch.ctrl(&l2->ch, CLOSE_CHANNEL, NULL); return id; } @@ -1069,7 +1111,7 @@ mgr_send(struct mISDNchannel *ch, struct sk_buff *skb) mgr = container_of(ch, struct manager, ch); if (*debug & DEBUG_L2_RECV) printk(KERN_DEBUG "%s: prim(%x) id(%x)\n", - __func__, hh->prim, hh->id); + __func__, hh->prim, hh->id); switch (hh->prim) { case PH_DATA_IND: mISDN_FsmEvent(&mgr->deact, EV_UI, NULL); @@ -1081,12 +1123,16 @@ mgr_send(struct mISDNchannel *ch, struct sk_buff *skb) break; case PH_ACTIVATE_IND: test_and_set_bit(MGR_PH_ACTIVE, &mgr->options); + if (mgr->up) + teiup_create(mgr, PH_ACTIVATE_IND, 0, NULL); mISDN_FsmEvent(&mgr->deact, EV_ACTIVATE_IND, NULL); do_send(mgr); ret = 0; break; case PH_DEACTIVATE_IND: test_and_clear_bit(MGR_PH_ACTIVE, &mgr->options); + if (mgr->up) + teiup_create(mgr, PH_DEACTIVATE_IND, 0, NULL); mISDN_FsmEvent(&mgr->deact, EV_DEACTIVATE_IND, NULL); ret = 0; break; @@ -1103,6 +1149,7 @@ free_teimanager(struct manager *mgr) { struct layer2 *l2, *nl2; + test_and_clear_bit(OPTION_L1_HOLD, &mgr->options); if (test_bit(MGR_OPT_NETWORK, &mgr->options)) { /* not locked lock is taken in release tei */ mgr->up = NULL; @@ -1133,13 +1180,26 @@ static int ctrl_teimanager(struct manager *mgr, void *arg) { /* currently we only have one option */ - int clean = *((int *)arg); - - if (clean) - test_and_set_bit(OPTION_L2_CLEANUP, &mgr->options); - else - test_and_clear_bit(OPTION_L2_CLEANUP, &mgr->options); - return 0; + int *val = (int *)arg; + int ret = 0; + + switch (val[0]) { + case IMCLEAR_L2: + if (val[1]) + test_and_set_bit(OPTION_L2_CLEANUP, &mgr->options); + else + test_and_clear_bit(OPTION_L2_CLEANUP, &mgr->options); + break; + case IMHOLD_L1: + if (val[1]) + test_and_set_bit(OPTION_L1_HOLD, &mgr->options); + else + test_and_clear_bit(OPTION_L1_HOLD, &mgr->options); + break; + default: + ret = -EINVAL; + } + return ret; } /* This function does create a L2 for fixed TEI in NT Mode */ @@ -1147,32 +1207,39 @@ static int check_data(struct manager *mgr, struct sk_buff *skb) { struct mISDNhead *hh = mISDN_HEAD_P(skb); - int ret, tei; + int ret, tei, sapi; struct layer2 *l2; if (*debug & DEBUG_L2_CTRL) printk(KERN_DEBUG "%s: prim(%x) id(%x)\n", - __func__, hh->prim, hh->id); + __func__, hh->prim, hh->id); if (test_bit(MGR_OPT_USER, &mgr->options)) return -ENOTCONN; if (hh->prim != PH_DATA_IND) return -ENOTCONN; if (skb->len != 3) return -ENOTCONN; - if (skb->data[0] != 0) - /* only SAPI 0 command */ - return -ENOTCONN; + if (skb->data[0] & 3) /* EA0 and CR must be 0 */ + return -EINVAL; + sapi = skb->data[0] >> 2; if (!(skb->data[1] & 1)) /* invalid EA1 */ return -EINVAL; - tei = skb->data[1] >> 0; + tei = skb->data[1] >> 1; if (tei > 63) /* not a fixed tei */ return -ENOTCONN; if ((skb->data[2] & ~0x10) != SABME) return -ENOTCONN; /* We got a SABME for a fixed TEI */ - l2 = create_new_tei(mgr, tei); - if (!l2) + if (*debug & DEBUG_L2_CTRL) + printk(KERN_DEBUG "%s: SABME sapi(%d) tei(%d)\n", + __func__, sapi, tei); + l2 = create_new_tei(mgr, tei, sapi); + if (!l2) { + if (*debug & DEBUG_L2_CTRL) + printk(KERN_DEBUG "%s: failed to create new tei\n", + __func__); return -ENOMEM; + } ret = l2->ch.send(&l2->ch, skb); return ret; } @@ -1227,7 +1294,7 @@ static int mgr_bcast(struct mISDNchannel *ch, struct sk_buff *skb) { struct manager *mgr = container_of(ch, struct manager, bcast); - struct mISDNhead *hh = mISDN_HEAD_P(skb); + struct mISDNhead *hhc, *hh = mISDN_HEAD_P(skb); struct sk_buff *cskb = NULL; struct layer2 *l2; u_long flags; @@ -1242,22 +1309,29 @@ mgr_bcast(struct mISDNchannel *ch, struct sk_buff *skb) skb = NULL; } else { if (!cskb) - cskb = skb_copy(skb, GFP_KERNEL); + cskb = skb_copy(skb, GFP_ATOMIC); } if (cskb) { - ret = l2->ch.send(&l2->ch, cskb); + hhc = mISDN_HEAD_P(cskb); + /* save original header behind normal header */ + hhc++; + *hhc = *hh; + hhc--; + hhc->prim = DL_INTERN_MSG; + hhc->id = l2->ch.nr; + ret = ch->st->own.recv(&ch->st->own, cskb); if (ret) { if (*debug & DEBUG_SEND_ERR) printk(KERN_DEBUG - "%s ch%d prim(%x) addr(%x)" - " err %d\n", - __func__, l2->ch.nr, - hh->prim, l2->ch.addr, ret); + "%s ch%d prim(%x) addr(%x)" + " err %d\n", + __func__, l2->ch.nr, + hh->prim, l2->ch.addr, ret); } else cskb = NULL; } else { printk(KERN_WARNING "%s ch%d addr %x no mem\n", - __func__, ch->nr, ch->addr); + __func__, ch->nr, ch->addr); goto out; } } @@ -1287,7 +1361,7 @@ create_teimanager(struct mISDNdevice *dev) if (!mgr) return -ENOMEM; INIT_LIST_HEAD(&mgr->layer2); - mgr->lock = __RW_LOCK_UNLOCKED(mgr->lock); + rwlock_init(&mgr->lock); skb_queue_head_init(&mgr->sendq); mgr->nextid = 1; mgr->lastid = MISDN_ID_NONE; diff --git a/drivers/isdn/mISDN/timerdev.c b/drivers/isdn/mISDN/timerdev.c index b5fabc7019d..9438d7ec330 100644 --- a/drivers/isdn/mISDN/timerdev.c +++ b/drivers/isdn/mISDN/timerdev.c @@ -19,12 +19,16 @@ #include <linux/poll.h> #include <linux/vmalloc.h> +#include <linux/slab.h> #include <linux/timer.h> #include <linux/miscdevice.h> #include <linux/module.h> #include <linux/mISDNif.h> +#include <linux/mutex.h> +#include "core.h" -static int *debug; +static DEFINE_MUTEX(mISDN_mutex); +static u_int *debug; struct mISDNtimerdev { @@ -60,82 +64,81 @@ mISDN_open(struct inode *ino, struct file *filep) dev->work = 0; init_waitqueue_head(&dev->wait); filep->private_data = dev; - __module_get(THIS_MODULE); - return 0; + return nonseekable_open(ino, filep); } static int mISDN_close(struct inode *ino, struct file *filep) { struct mISDNtimerdev *dev = filep->private_data; + struct list_head *list = &dev->pending; struct mISDNtimer *timer, *next; if (*debug & DEBUG_TIMER) printk(KERN_DEBUG "%s(%p,%p)\n", __func__, ino, filep); - list_for_each_entry_safe(timer, next, &dev->pending, list) { - del_timer(&timer->tl); + + spin_lock_irq(&dev->lock); + while (!list_empty(list)) { + timer = list_first_entry(list, struct mISDNtimer, list); + spin_unlock_irq(&dev->lock); + del_timer_sync(&timer->tl); + spin_lock_irq(&dev->lock); + /* it might have been moved to ->expired */ + list_del(&timer->list); kfree(timer); } + spin_unlock_irq(&dev->lock); + list_for_each_entry_safe(timer, next, &dev->expired, list) { kfree(timer); } kfree(dev); - module_put(THIS_MODULE); return 0; } static ssize_t -mISDN_read(struct file *filep, char *buf, size_t count, loff_t *off) +mISDN_read(struct file *filep, char __user *buf, size_t count, loff_t *off) { struct mISDNtimerdev *dev = filep->private_data; + struct list_head *list = &dev->expired; struct mISDNtimer *timer; - u_long flags; int ret = 0; if (*debug & DEBUG_TIMER) printk(KERN_DEBUG "%s(%p, %p, %d, %p)\n", __func__, - filep, buf, (int)count, off); - if (*off != filep->f_pos) - return -ESPIPE; + filep, buf, (int)count, off); + + if (count < sizeof(int)) + return -ENOSPC; - if (list_empty(&dev->expired) && (dev->work == 0)) { + spin_lock_irq(&dev->lock); + while (list_empty(list) && (dev->work == 0)) { + spin_unlock_irq(&dev->lock); if (filep->f_flags & O_NONBLOCK) return -EAGAIN; wait_event_interruptible(dev->wait, (dev->work || - !list_empty(&dev->expired))); + !list_empty(list))); if (signal_pending(current)) return -ERESTARTSYS; + spin_lock_irq(&dev->lock); } - if (count < sizeof(int)) - return -ENOSPC; if (dev->work) dev->work = 0; - if (!list_empty(&dev->expired)) { - spin_lock_irqsave(&dev->lock, flags); - timer = (struct mISDNtimer *)dev->expired.next; + if (!list_empty(list)) { + timer = list_first_entry(list, struct mISDNtimer, list); list_del(&timer->list); - spin_unlock_irqrestore(&dev->lock, flags); - if (put_user(timer->id, (int *)buf)) + spin_unlock_irq(&dev->lock); + if (put_user(timer->id, (int __user *)buf)) ret = -EFAULT; else ret = sizeof(int); kfree(timer); + } else { + spin_unlock_irq(&dev->lock); } return ret; } -static loff_t -mISDN_llseek(struct file *filep, loff_t offset, int orig) -{ - return -ESPIPE; -} - -static ssize_t -mISDN_write(struct file *filep, const char *buf, size_t count, loff_t *off) -{ - return -EOPNOTSUPP; -} - static unsigned int mISDN_poll(struct file *filep, poll_table *wait) { @@ -151,19 +154,20 @@ mISDN_poll(struct file *filep, poll_table *wait) mask |= (POLLIN | POLLRDNORM); if (*debug & DEBUG_TIMER) printk(KERN_DEBUG "%s work(%d) empty(%d)\n", __func__, - dev->work, list_empty(&dev->expired)); + dev->work, list_empty(&dev->expired)); } return mask; } static void -dev_expire_timer(struct mISDNtimer *timer) +dev_expire_timer(unsigned long data) { + struct mISDNtimer *timer = (void *)data; u_long flags; spin_lock_irqsave(&timer->dev->lock, flags); - list_del(&timer->list); - list_add_tail(&timer->list, &timer->dev->expired); + if (timer->id >= 0) + list_move_tail(&timer->list, &timer->dev->expired); spin_unlock_irqrestore(&timer->dev->lock, flags); wake_up_interruptible(&timer->dev->wait); } @@ -171,8 +175,7 @@ dev_expire_timer(struct mISDNtimer *timer) static int misdn_add_timer(struct mISDNtimerdev *dev, int timeout) { - int id; - u_long flags; + int id; struct mISDNtimer *timer; if (!timeout) { @@ -183,19 +186,16 @@ misdn_add_timer(struct mISDNtimerdev *dev, int timeout) timer = kzalloc(sizeof(struct mISDNtimer), GFP_KERNEL); if (!timer) return -ENOMEM; - spin_lock_irqsave(&dev->lock, flags); - timer->id = dev->next_id++; + timer->dev = dev; + setup_timer(&timer->tl, dev_expire_timer, (long)timer); + spin_lock_irq(&dev->lock); + id = timer->id = dev->next_id++; if (dev->next_id < 0) dev->next_id = 1; list_add_tail(&timer->list, &dev->pending); - spin_unlock_irqrestore(&dev->lock, flags); - timer->dev = dev; - timer->tl.data = (long)timer; - timer->tl.function = (void *) dev_expire_timer; - init_timer(&timer->tl); timer->tl.expires = jiffies + ((HZ * (u_long)timeout) / 1000); add_timer(&timer->tl); - id = timer->id; + spin_unlock_irq(&dev->lock); } return id; } @@ -203,28 +203,25 @@ misdn_add_timer(struct mISDNtimerdev *dev, int timeout) static int misdn_del_timer(struct mISDNtimerdev *dev, int id) { - u_long flags; struct mISDNtimer *timer; - int ret = 0; - spin_lock_irqsave(&dev->lock, flags); + spin_lock_irq(&dev->lock); list_for_each_entry(timer, &dev->pending, list) { if (timer->id == id) { list_del_init(&timer->list); - del_timer(&timer->tl); - ret = timer->id; + timer->id = -1; + spin_unlock_irq(&dev->lock); + del_timer_sync(&timer->tl); kfree(timer); - goto unlock; + return id; } } -unlock: - spin_unlock_irqrestore(&dev->lock, flags); - return ret; + spin_unlock_irq(&dev->lock); + return 0; } -static int -mISDN_ioctl(struct inode *inode, struct file *filep, unsigned int cmd, - unsigned long arg) +static long +mISDN_ioctl(struct file *filep, unsigned int cmd, unsigned long arg) { struct mISDNtimerdev *dev = filep->private_data; int id, tout, ret = 0; @@ -232,7 +229,8 @@ mISDN_ioctl(struct inode *inode, struct file *filep, unsigned int cmd, if (*debug & DEBUG_TIMER) printk(KERN_DEBUG "%s(%p, %x, %lx)\n", __func__, - filep, cmd, arg); + filep, cmd, arg); + mutex_lock(&mISDN_mutex); switch (cmd) { case IMADDTIMER: if (get_user(tout, (int __user *)arg)) { @@ -242,7 +240,7 @@ mISDN_ioctl(struct inode *inode, struct file *filep, unsigned int cmd, id = misdn_add_timer(dev, tout); if (*debug & DEBUG_TIMER) printk(KERN_DEBUG "%s add %d id %d\n", __func__, - tout, id); + tout, id); if (id < 0) { ret = id; break; @@ -264,17 +262,18 @@ mISDN_ioctl(struct inode *inode, struct file *filep, unsigned int cmd, default: ret = -EINVAL; } + mutex_unlock(&mISDN_mutex); return ret; } -static struct file_operations mISDN_fops = { - .llseek = mISDN_llseek, +static const struct file_operations mISDN_fops = { + .owner = THIS_MODULE, .read = mISDN_read, - .write = mISDN_write, .poll = mISDN_poll, - .ioctl = mISDN_ioctl, + .unlocked_ioctl = mISDN_ioctl, .open = mISDN_open, .release = mISDN_close, + .llseek = no_llseek, }; static struct miscdevice mISDNtimer = { @@ -284,7 +283,7 @@ static struct miscdevice mISDNtimer = { }; int -mISDN_inittimer(int *deb) +mISDN_inittimer(u_int *deb) { int err; |
