diff options
Diffstat (limited to 'drivers/isdn/mISDN')
-rw-r--r-- | drivers/isdn/mISDN/Makefile | 2 | ||||
-rw-r--r-- | drivers/isdn/mISDN/clock.c | 216 | ||||
-rw-r--r-- | drivers/isdn/mISDN/core.c | 280 | ||||
-rw-r--r-- | drivers/isdn/mISDN/core.h | 2 | ||||
-rw-r--r-- | drivers/isdn/mISDN/dsp.h | 2 | ||||
-rw-r--r-- | drivers/isdn/mISDN/dsp_cmx.c | 149 | ||||
-rw-r--r-- | drivers/isdn/mISDN/dsp_core.c | 55 | ||||
-rw-r--r-- | drivers/isdn/mISDN/dsp_pipeline.c | 38 | ||||
-rw-r--r-- | drivers/isdn/mISDN/hwchannel.c | 42 | ||||
-rw-r--r-- | drivers/isdn/mISDN/l1oip_core.c | 25 | ||||
-rw-r--r-- | drivers/isdn/mISDN/layer1.c | 2 | ||||
-rw-r--r-- | drivers/isdn/mISDN/socket.c | 41 | ||||
-rw-r--r-- | drivers/isdn/mISDN/stack.c | 66 | ||||
-rw-r--r-- | drivers/isdn/mISDN/tei.c | 6 |
14 files changed, 734 insertions, 192 deletions
diff --git a/drivers/isdn/mISDN/Makefile b/drivers/isdn/mISDN/Makefile index 1cb5e633cf75..0a6bd2a9e730 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 000000000000..44d9c3d5d33d --- /dev/null +++ b/drivers/isdn/mISDN/clock.c @@ -0,0 +1,216 @@ +/* + * 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/types.h> +#include <linux/stddef.h> +#include <linux/spinlock.h> +#include <linux/mISDNif.h> +#include "core.h" + +static u_int *debug; +static LIST_HEAD(iclock_list); +DEFINE_RWLOCK(iclock_lock); +u16 iclock_count; /* counter of last clock */ +struct timeval iclock_tv; /* time stamp of last clock */ +int iclock_tv_valid; /* already received one timestamp */ +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 751665c448d0..9426c9827e47 100644 --- a/drivers/isdn/mISDN/core.c +++ b/drivers/isdn/mISDN/core.c @@ -25,39 +25,183 @@ MODULE_AUTHOR("Karsten Keil"); MODULE_LICENSE("GPL"); module_param(debug, uint, S_IRUGO | S_IWUSR); -static LIST_HEAD(devices); -static DEFINE_RWLOCK(device_lock); static u64 device_ids; #define MAX_DEVICE_ID 63 static LIST_HEAD(Bprotocols); 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 _show_id(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 ssize_t _show_nrbchan(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 ssize_t _show_d_protocols(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 ssize_t _show_b_protocols(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 ssize_t _show_protocol(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 ssize_t _show_name(struct device *dev, + struct device_attribute *attr, char *buf) +{ + strcpy(buf, dev_name(dev)); + return strlen(buf); +} + +#if 0 /* hangs */ +static ssize_t _set_name(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; +} +#endif + +static ssize_t _show_channelmap(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 struct device_attribute mISDN_dev_attrs[] = { + __ATTR(id, S_IRUGO, _show_id, NULL), + __ATTR(d_protocols, S_IRUGO, _show_d_protocols, NULL), + __ATTR(b_protocols, S_IRUGO, _show_b_protocols, NULL), + __ATTR(protocol, S_IRUGO, _show_protocol, NULL), + __ATTR(channelmap, S_IRUGO, _show_channelmap, NULL), + __ATTR(nrbchan, S_IRUGO, _show_nrbchan, NULL), + __ATTR(name, S_IRUGO, _show_name, NULL), +/* __ATTR(name, S_IRUGO|S_IWUSR, _show_name, _set_name), */ + {} +}; + +#ifdef CONFIG_HOTPLUG +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; +} +#endif + +static void mISDN_class_release(struct class *cls) +{ + /* do nothing, it's static */ +} + +static struct class mISDN_class = { + .name = "mISDN", + .owner = THIS_MODULE, +#ifdef CONFIG_HOTPLUG + .dev_uevent = mISDN_uevent, +#endif + .dev_attrs = mISDN_dev_attrs, + .dev_release = mISDN_dev_release, + .class_release = mISDN_class_release, +}; + +static int +_get_mdevice(struct device *dev, void *id) +{ + struct mISDNdevice *mdev = dev_to_mISDN(dev); + + if (!mdev) + return 0; + if (mdev->id != *(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 +212,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 -1; + 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(); + err = -EBUSY; if (dev->id < 0) - return -EBUSY; + goto error1; + + 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); @@ -199,43 +361,45 @@ mISDNInit(void) printk(KERN_INFO "Modular ISDN core version %d.%d.%d\n", 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; } 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"); } diff --git a/drivers/isdn/mISDN/core.h b/drivers/isdn/mISDN/core.h index 7da7233b4c1a..7ac2f81a812b 100644 --- a/drivers/isdn/mISDN/core.h +++ b/drivers/isdn/mISDN/core.h @@ -74,4 +74,6 @@ extern void l1_cleanup(void); 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 6c3fed6b8d4f..98a33c58f091 100644 --- a/drivers/isdn/mISDN/dsp.h +++ b/drivers/isdn/mISDN/dsp.h @@ -15,6 +15,7 @@ #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: @@ -198,6 +199,7 @@ struct dsp { /* 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; diff --git a/drivers/isdn/mISDN/dsp_cmx.c b/drivers/isdn/mISDN/dsp_cmx.c index c884511e2d49..58c43e429f73 100644 --- a/drivers/isdn/mISDN/dsp_cmx.c +++ b/drivers/isdn/mISDN/dsp_cmx.c @@ -137,6 +137,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 @@ -744,11 +745,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; @@ -836,11 +837,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; @@ -926,10 +927,6 @@ 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) return; @@ -940,6 +937,9 @@ conf_software: if (current_conf >= 0) { join_members: list_for_each_entry(member, &conf->mlist, list) { + /* 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; @@ -1135,6 +1135,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 @@ -1168,11 +1187,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 +1211,25 @@ 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 */ + /* 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; + 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,7 +1237,7 @@ 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 " @@ -1243,6 +1275,9 @@ dsp_cmx_receive(struct dsp *dsp, struct sk_buff *skb) /* increase write-pointer */ 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 } @@ -1360,8 +1395,12 @@ dsp_cmx_send_member(struct dsp *dsp, int len, s32 *c, int members) t = (t+1) & CMX_BUFF_MASK; r = (r+1) & CMX_BUFF_MASK; } - if (r != rr) + 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 { /* @@ -1540,13 +1579,11 @@ send_packet: schedule_work(&dsp->workq); } -static 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 */ -#ifdef UNUSED -static u32 dsp_start_jiffies; /* jiffies at the time, the calculation begins */ -#endif /* UNUSED */ -static struct timeval dsp_start_tv; /* time at start of calculation */ +static u16 dsp_count; /* last sample count */ +static int dsp_count_valid ; /* if we have last sample count */ void dsp_cmx_send(void *arg) @@ -1560,38 +1597,32 @@ dsp_cmx_send(void *arg) 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) { @@ -1704,17 +1735,19 @@ dsp_cmx_send(void *arg) } /* * remove rx_delay only if we have delay AND we - * have not preset cmx_delay + * have not preset cmx_delay AND + * the delay is greater dsp_poll */ - if (delay && !dsp->cmx_delay) { - if (dsp_debug & DEBUG_DSP_CMX) + 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) & CMX_BUFF_MASK; + rr = (r + delay - (dsp_poll >> 1)) + & CMX_BUFF_MASK; /* delete rx-data */ while (r != rr) { p[r] = dsp_silence; @@ -1736,15 +1769,16 @@ dsp_cmx_send(void *arg) * remove delay only if we have delay AND we * have enabled tx_dejitter */ - if (delay && dsp->tx_dejitter) { - if (dsp_debug & DEBUG_DSP_CMX) + 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) & CMX_BUFF_MASK; + rr = (r + delay - (dsp_poll >> 1)) + & CMX_BUFF_MASK; /* delete tx-data */ while (r != rr) { q[r] = dsp_silence; @@ -1797,14 +1831,16 @@ dsp_cmx_transmit(struct dsp *dsp, struct sk_buff *skb) ww = dsp->tx_R; p = dsp->tx_buff; d = skb->data; - space = ww-w; - if (space <= 0) - space += CMX_BUFF_SIZE; + space = (ww - w - 1) & CMX_BUFF_MASK; /* write-pointer should not overrun nor reach read pointer */ - if (space-1 < skb->len) + if (space < skb->len) { /* write to the space we have left */ - ww = (ww - 1) & CMX_BUFF_MASK; - else + 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; @@ -1857,7 +1893,7 @@ dsp_cmx_hdlc(struct dsp *dsp, struct sk_buff *skb) /* in case of hardware (echo) */ if (dsp->pcm_slot_tx >= 0) return; - if (dsp->echo) + if (dsp->echo) { nskb = skb_clone(skb, GFP_ATOMIC); if (nskb) { hh = mISDN_HEAD_P(nskb); @@ -1866,6 +1902,7 @@ dsp_cmx_hdlc(struct dsp *dsp, struct sk_buff *skb) skb_queue_tail(&dsp->sendq, nskb); schedule_work(&dsp->workq); } + } return; } /* in case of hardware conference */ diff --git a/drivers/isdn/mISDN/dsp_core.c b/drivers/isdn/mISDN/dsp_core.c index 1dc21d803410..3083338716b2 100644 --- a/drivers/isdn/mISDN/dsp_core.c +++ b/drivers/isdn/mISDN/dsp_core.c @@ -191,6 +191,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; @@ -249,6 +251,32 @@ 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; + 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) { @@ -273,8 +301,9 @@ 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; } /* init goertzel */ @@ -593,8 +622,6 @@ 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", @@ -610,6 +637,10 @@ get_features(struct mISDNchannel *ch) } 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; @@ -837,11 +868,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; } @@ -865,6 +899,9 @@ dsp_function(struct mISDNchannel *ch, struct sk_buff *skb) 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) @@ -1105,7 +1142,7 @@ static int dsp_init(void) } 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; diff --git a/drivers/isdn/mISDN/dsp_pipeline.c b/drivers/isdn/mISDN/dsp_pipeline.c index 83639be7f7ad..18cf87c113e7 100644 --- a/drivers/isdn/mISDN/dsp_pipeline.c +++ b/drivers/isdn/mISDN/dsp_pipeline.c @@ -75,6 +75,15 @@ 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,13 +92,14 @@ 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); dev_set_name(&entry->dev, elem->name); ret = device_register(&entry->dev); @@ -98,9 +108,9 @@ int mISDN_dsp_element_register(struct mISDN_dsp_element *elem) __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]); if (ret) { @@ -108,15 +118,17 @@ int mISDN_dsp_element_register(struct mISDN_dsp_element *elem) __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 +144,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); +#endif return; } printk(KERN_ERR "%s: element %s not in list.\n", __func__, elem->name); @@ -173,7 +185,9 @@ void dsp_pipeline_module_exit(void) kfree(entry); } +#ifdef PIPELINE_DEBUG printk(KERN_DEBUG "%s: dsp pipeline module exited\n", __func__); +#endif } int dsp_pipeline_init(struct dsp_pipeline *pipeline) @@ -239,7 +253,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); @@ -256,9 +270,9 @@ int dsp_pipeline_build(struct dsp_pipeline *pipeline, const char *cfg) 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 " + printk(KERN_ERR "%s: failed to add " "entry to pipeline: %s (out of " "memory)\n", __func__, elem->name); incomplete = 1; @@ -286,7 +300,7 @@ int dsp_pipeline_build(struct dsp_pipeline *pipeline, const char *cfg) args : ""); #endif } else { - printk(KERN_DEBUG "%s: failed " + printk(KERN_ERR "%s: failed " "to add entry to pipeline: " "%s (new() returned NULL)\n", __func__, elem->name); @@ -301,7 +315,7 @@ int dsp_pipeline_build(struct dsp_pipeline *pipeline, const char *cfg) if (found) found = 0; else { - printk(KERN_DEBUG "%s: element not found, skipping: " + printk(KERN_ERR "%s: element not found, skipping: " "%s\n", __func__, name); incomplete = 1; } diff --git a/drivers/isdn/mISDN/hwchannel.c b/drivers/isdn/mISDN/hwchannel.c index 2596fba4e614..ab1168a110ae 100644 --- a/drivers/isdn/mISDN/hwchannel.c +++ b/drivers/isdn/mISDN/hwchannel.c @@ -50,9 +50,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); @@ -169,6 +166,25 @@ recv_Dchannel(struct dchannel *dch) EXPORT_SYMBOL(recv_Dchannel); void +recv_Echannel(struct dchannel *ech, struct dchannel *dch) +{ + struct mISDNhead *hh; + + 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) { struct mISDNhead *hh; @@ -177,8 +193,10 @@ recv_Bchannel(struct bchannel *bch) hh->prim = PH_DATA_IND; hh->id = MISDN_ID_ANY; if (bch->rcount >= 64) { - dev_kfree_skb(bch->rx_skb); - bch->rx_skb = NULL; + printk(KERN_WARNING "B-channel %p receive queue overflow, " + "fushing!\n", bch); + skb_queue_purge(&bch->rqueue); + bch->rcount = 0; return; } bch->rcount++; @@ -200,8 +218,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, " + "fushing!\n", bch); + skb_queue_purge(&bch->rqueue); + bch->rcount = 0; } bch->rcount++; skb_queue_tail(&bch->rqueue, skb); @@ -245,8 +265,12 @@ 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, " + "fushing!\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); if (!skb) { diff --git a/drivers/isdn/mISDN/l1oip_core.c b/drivers/isdn/mISDN/l1oip_core.c index 0884dd6892f8..abe574989572 100644 --- a/drivers/isdn/mISDN/l1oip_core.c +++ b/drivers/isdn/mISDN/l1oip_core.c @@ -777,6 +777,8 @@ fail: 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) @@ -785,6 +787,16 @@ l1oip_socket_close(struct l1oip *hc) 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 @@ -944,7 +956,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; @@ -964,6 +977,13 @@ channel_dctrl(struct dchannel *dch, struct mISDN_ctrl_req *cq) 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); @@ -1413,7 +1433,8 @@ init_card(struct l1oip *hc, int pri, int bundle) hc->chan[i + ch].bch = bch; 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; diff --git a/drivers/isdn/mISDN/layer1.c b/drivers/isdn/mISDN/layer1.c index b73e952d12cf..e826eeb1ecec 100644 --- a/drivers/isdn/mISDN/layer1.c +++ b/drivers/isdn/mISDN/layer1.c @@ -101,7 +101,7 @@ l1m_debug(struct FsmInst *fi, char *fmt, ...) va_list va; va_start(va, fmt); - printk(KERN_DEBUG "%s: ", l1->dch->dev.name); + printk(KERN_DEBUG "%s: ", dev_name(&l1->dch->dev.dev)); vprintk(fmt, va); printk("\n"); va_end(va); diff --git a/drivers/isdn/mISDN/socket.c b/drivers/isdn/mISDN/socket.c index 37a2de18cfd0..508945d1b9c1 100644 --- a/drivers/isdn/mISDN/socket.c +++ b/drivers/isdn/mISDN/socket.c @@ -381,7 +381,7 @@ data_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) memcpy(di.channelmap, dev->channelmap, 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 @@ -460,6 +460,8 @@ 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 hlist_node *node; + struct sock *csk; int err = 0; if (*debug & DEBUG_SOCKET) @@ -480,6 +482,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, node, &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; @@ -639,12 +661,27 @@ base_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) memcpy(di.channelmap, dev->channelmap, 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; } diff --git a/drivers/isdn/mISDN/stack.c b/drivers/isdn/mISDN/stack.c index d55b14ae4e99..e2f45019ebf0 100644 --- a/drivers/isdn/mISDN/stack.c +++ b/drivers/isdn/mISDN/stack.c @@ -172,7 +172,8 @@ send_msg_to_layer(struct mISDNstack *st, struct sk_buff *skb) else printk(KERN_WARNING "%s: dev(%s) prim(%x) id(%x) no channel\n", - __func__, st->dev->name, hh->prim, hh->id); + __func__, dev_name(&st->dev->dev), hh->prim, + hh->id); } else if (lm == 0x8) { WARN_ON(lm == 0x8); ch = get_channel4id(st, hh->id); @@ -181,11 +182,12 @@ send_msg_to_layer(struct mISDNstack *st, struct sk_buff *skb) else printk(KERN_WARNING "%s: dev(%s) prim(%x) id(%x) no channel\n", - __func__, st->dev->name, hh->prim, hh->id); + __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; } @@ -209,7 +211,8 @@ mISDNStackd(void *data) 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); @@ -245,7 +248,7 @@ mISDNStackd(void *data) printk(KERN_DEBUG "%s: %s prim(%x) id(%x) " "send call(%d)\n", - __func__, st->dev->name, + __func__, dev_name(&st->dev->dev), mISDN_HEAD_PRIM(skb), mISDN_HEAD_ID(skb), err); dev_kfree_skb(skb); @@ -288,7 +291,7 @@ mISDNStackd(void *data) 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); @@ -303,15 +306,16 @@ 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); + dev_name(&st->dev->dev), st->msg_cnt, st->sleep_cnt, + st->stopped_cnt); printk(KERN_DEBUG "mISDNStackd daemon for %s utime(%ld) stime(%ld)\n", - st->dev->name, st->thread->utime, st->thread->stime); + dev_name(&st->dev->dev), st->thread->utime, st->thread->stime); printk(KERN_DEBUG "mISDNStackd daemon for %s nvcsw(%ld) nivcsw(%ld)\n", - st->dev->name, st->thread->nvcsw, st->thread->nivcsw); + 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); @@ -401,15 +405,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); + dev_name(&newst->dev->dev), err); delete_teimanager(dev->teimgr); kfree(newst); } else @@ -428,29 +433,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); @@ -473,7 +470,7 @@ 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, + __func__, dev_name(&dev->dev), protocol, adr->dev, adr->channel, adr->sapi, adr->tei); ch->st = dev->D.st; @@ -529,7 +526,7 @@ create_l2entity(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, + __func__, dev_name(&dev->dev), protocol, adr->dev, adr->channel, adr->sapi, adr->tei); rq.protocol = ISDN_P_TE_S0; @@ -541,15 +538,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 +578,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); @@ -643,7 +631,7 @@ 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) { diff --git a/drivers/isdn/mISDN/tei.c b/drivers/isdn/mISDN/tei.c index 5c43d19e7c11..b452dead8fd0 100644 --- a/drivers/isdn/mISDN/tei.c +++ b/drivers/isdn/mISDN/tei.c @@ -968,9 +968,9 @@ create_teimgr(struct manager *mgr, struct channel_req *crq) 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); + __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.sapi != 0) /* not supported yet */ return -EINVAL; if (crq->adr.tei > GROUP_TEI) |