aboutsummaryrefslogtreecommitdiff
path: root/drivers/isdn/mISDN
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/isdn/mISDN')
-rw-r--r--drivers/isdn/mISDN/Kconfig12
-rw-r--r--drivers/isdn/mISDN/Makefile2
-rw-r--r--drivers/isdn/mISDN/clock.c217
-rw-r--r--drivers/isdn/mISDN/core.c324
-rw-r--r--drivers/isdn/mISDN/core.h10
-rw-r--r--drivers/isdn/mISDN/dsp.h50
-rw-r--r--drivers/isdn/mISDN/dsp_audio.c13
-rw-r--r--drivers/isdn/mISDN/dsp_biquad.h6
-rw-r--r--drivers/isdn/mISDN/dsp_blowfish.c112
-rw-r--r--drivers/isdn/mISDN/dsp_cmx.c1247
-rw-r--r--drivers/isdn/mISDN/dsp_core.c318
-rw-r--r--drivers/isdn/mISDN/dsp_dtmf.c84
-rw-r--r--drivers/isdn/mISDN/dsp_ecdis.h28
-rw-r--r--drivers/isdn/mISDN/dsp_hwec.c13
-rw-r--r--drivers/isdn/mISDN/dsp_hwec.h1
-rw-r--r--drivers/isdn/mISDN/dsp_pipeline.c114
-rw-r--r--drivers/isdn/mISDN/dsp_tones.c169
-rw-r--r--drivers/isdn/mISDN/fsm.c42
-rw-r--r--drivers/isdn/mISDN/hwchannel.c231
-rw-r--r--drivers/isdn/mISDN/l1oip.h23
-rw-r--r--drivers/isdn/mISDN/l1oip_codec.c46
-rw-r--r--drivers/isdn/mISDN/l1oip_core.c715
-rw-r--r--drivers/isdn/mISDN/layer1.c64
-rw-r--r--drivers/isdn/mISDN/layer1.h1
-rw-r--r--drivers/isdn/mISDN/layer2.c269
-rw-r--r--drivers/isdn/mISDN/layer2.h12
-rw-r--r--drivers/isdn/mISDN/socket.c169
-rw-r--r--drivers/isdn/mISDN/stack.c163
-rw-r--r--drivers/isdn/mISDN/tei.c320
-rw-r--r--drivers/isdn/mISDN/timerdev.c129
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(&current->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;