patch-2.1.92 linux/drivers/isdn/isdn_common.c
Next file: linux/drivers/isdn/isdn_common.h
Previous file: linux/drivers/isdn/isdn_cards.c
Back to the patch index
Back to the overall index
- Lines: 976
- Date:
Wed Apr 1 16:21:03 1998
- Orig file:
v2.1.91/linux/drivers/isdn/isdn_common.c
- Orig date:
Tue Mar 10 10:03:32 1998
diff -u --recursive --new-file v2.1.91/linux/drivers/isdn/isdn_common.c linux/drivers/isdn/isdn_common.c
@@ -1,4 +1,4 @@
-/* $Id: isdn_common.c,v 1.44 1997/05/27 15:17:23 fritz Exp $
+/* $Id: isdn_common.c,v 1.55 1998/02/23 23:35:32 fritz Exp $
* Linux ISDN subsystem, common used functions (linklevel).
*
@@ -21,6 +21,55 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: isdn_common.c,v $
+ * Revision 1.55 1998/02/23 23:35:32 fritz
+ * Eliminated some compiler warnings.
+ *
+ * Revision 1.54 1998/02/22 19:44:19 fritz
+ * Bugfixes and improvements regarding V.110, V.110 now running.
+ *
+ * Revision 1.53 1998/02/20 17:18:05 fritz
+ * Changes for recent kernels.
+ * Added common stub for sending commands to lowlevel.
+ * Added V.110.
+ *
+ * Revision 1.52 1998/01/31 22:05:57 keil
+ * Lots of changes for X.25 support:
+ * Added generic support for connection-controlling encapsulation protocols
+ * Added support of BHUP status message
+ * Added support for additional p_encap X25IFACE
+ * Added support for kernels >= 2.1.72
+ *
+ * Revision 1.51 1998/01/31 19:17:29 calle
+ * merged changes from and for 2.1.82
+ *
+ * Revision 1.50 1997/12/12 06:12:11 calle
+ * moved EXPORT_SYMBOL(register_isdn) from isdn_syms.c to isdn_common.c
+ *
+ * Revision 1.49 1997/11/06 17:16:52 keil
+ * Sync to 2.1.62 changes
+ *
+ * Revision 1.48 1997/11/02 23:55:50 keil
+ * Andi Kleen's changes for 2.1.60
+ * without it the isdninfo and isdnctrl devices won't work
+ *
+ * Revision 1.47 1997/10/09 21:28:46 fritz
+ * New HL<->LL interface:
+ * New BSENT callback with nr. of bytes included.
+ * Sending without ACK.
+ * New L1 error status (not yet in use).
+ * Cleaned up obsolete structures.
+ * Implemented Cisco-SLARP.
+ * Changed local net-interface data to be dynamically allocated.
+ * Removed old 2.0 compatibility stuff.
+ *
+ * Revision 1.46 1997/10/01 09:20:27 fritz
+ * Removed old compatibility stuff for 2.0.X kernels.
+ * From now on, this code is for 2.1.X ONLY!
+ * Old stuff is still in the separate branch.
+ *
+ * Revision 1.45 1997/08/21 23:11:41 fritz
+ * Added changes for kernels >= 2.1.45
+ *
* Revision 1.44 1997/05/27 15:17:23 fritz
* Added changes for recent 2.1.x kernels:
* changed return type of isdn_close
@@ -197,12 +246,9 @@
*/
#include <linux/config.h>
-#define __NO_VERSION__
#include <linux/module.h>
#include <linux/version.h>
-#if (LINUX_VERSION_CODE >= 0x020117)
#include <linux/poll.h>
-#endif
#include <linux/isdn.h>
#include "isdn_common.h"
#include "isdn_tty.h"
@@ -211,6 +257,7 @@
#ifdef CONFIG_ISDN_AUDIO
#include "isdn_audio.h"
#endif
+#include "isdn_v110.h"
#include "isdn_cards.h"
/* Debugflags */
@@ -218,7 +265,7 @@
isdn_dev *dev = (isdn_dev *) 0;
-static char *isdn_revision = "$Revision: 1.44 $";
+static char *isdn_revision = "$Revision: 1.55 $";
extern char *isdn_net_revision;
extern char *isdn_tty_revision;
@@ -232,6 +279,7 @@
#else
static char *isdn_audio_revision = ": none $";
#endif
+extern char *isdn_v110_revision;
static int isdn_writebuf_stub(int, int, const u_char *, int, int);
@@ -260,13 +308,6 @@
}
#endif
-static __inline void
-isdn_trash_skb(struct sk_buff *skb)
-{
- SET_SKB_FREE(skb);
- kfree_skb(skb);
-}
-
static void
isdn_free_queue(struct sk_buff_head *queue)
{
@@ -277,7 +318,7 @@
cli();
if (skb_queue_len(queue))
while ((skb = skb_dequeue(queue)))
- isdn_trash_skb(skb);
+ dev_kfree_skb(skb);
restore_flags(flags);
}
@@ -294,6 +335,7 @@
static int isdn_timer_cnt1 = 0;
static int isdn_timer_cnt2 = 0;
static int isdn_timer_cnt3 = 0;
+static int isdn_timer_cnt4 = 0;
static void
isdn_timer_funct(ulong dummy)
@@ -323,6 +365,11 @@
if (tf & ISDN_TIMER_MODEMRING)
isdn_tty_modem_ring();
}
+ if (++isdn_timer_cnt4 > ISDN_TIMER_KEEPINT) {
+ isdn_timer_cnt4 = 0;
+ if (tf & ISDN_TIMER_KEEPALIVE)
+ isdn_net_slarp_out();
+ }
#if (defined CONFIG_ISDN_PPP) && (defined CONFIG_ISDN_MPP)
if (tf & ISDN_TIMER_IPPP)
isdn_ppp_timer_timeout();
@@ -374,22 +421,71 @@
int i;
if ((i = isdn_dc2minor(di, channel)) == -1) {
- isdn_trash_skb(skb);
+ dev_kfree_skb(skb);
return;
}
/* Update statistics */
dev->ibytes[i] += skb->len;
+
/* First, try to deliver data to network-device */
if (isdn_net_rcv_skb(i, skb))
return;
+
+ /* V.110 handling
+ * makes sense for async streams only, so it is
+ * called after possible net-device delivery.
+ */
+ if (dev->v110[i]) {
+ atomic_inc(&dev->v110use[i]);
+ skb = isdn_v110_decode(dev->v110[i], skb);
+ atomic_dec(&dev->v110use[i]);
+ if (!skb)
+ return;
+ }
+
/* No network-device found, deliver to tty or raw-channel */
- SET_SKB_FREE(skb);
if (skb->len) {
if (isdn_tty_rcv_skb(i, di, channel, skb))
return;
wake_up_interruptible(&dev->drv[di]->rcv_waitq[channel]);
} else
- isdn_trash_skb(skb);
+ dev_kfree_skb(skb);
+}
+
+/*
+ * Intercept command from Linklevel to Lowlevel.
+ * If layer 2 protocol is V.110 and this is not supported by current
+ * lowlevel-driver, use driver's transparent mode and handle V.110 in
+ * linklevel instead.
+ */
+int
+isdn_command(isdn_ctrl *cmd)
+{
+ if (cmd->command == ISDN_CMD_SETL2) {
+ int idx = isdn_dc2minor(cmd->driver, cmd->arg & 255);
+ unsigned long l2prot = (cmd->arg >> 8) & 255;
+ unsigned long features = (dev->drv[cmd->driver]->interface->features
+ >> ISDN_FEATURE_L2_SHIFT) &
+ ISDN_FEATURE_L2_MASK;
+ unsigned long l2_feature = (1 << l2prot);
+
+ switch (l2prot) {
+ case ISDN_PROTO_L2_V11096:
+ case ISDN_PROTO_L2_V11019:
+ case ISDN_PROTO_L2_V11038:
+ /* If V.110 requested, but not supported by
+ * HL-driver, set emulator-flag and change
+ * Layer-2 to transparent
+ */
+ if (!(features & l2_feature)) {
+ dev->v110emu[idx] = l2prot;
+ cmd->arg = (cmd->arg & 255) |
+ (ISDN_PROTO_L2_TRANS << 8);
+ } else
+ dev->v110emu[idx] = 0;
+ }
+ }
+ return dev->drv[cmd->driver]->interface->command(cmd);
}
void
@@ -403,7 +499,7 @@
cmd.arg = ch;
cmd.command = ISDN_CMD_SETEAZ;
cmd.parm.num[0] = '\0';
- (void) dev->drv[di]->interface->command(&cmd);
+ isdn_command(&cmd);
}
static int
@@ -424,7 +520,9 @@
return -1;
if (dev->global_flags & ISDN_GLOBAL_STOPPED)
return 0;
- if (isdn_net_stat_callback(i, c->command))
+ if (isdn_net_stat_callback(i, c))
+ return 0;
+ if (isdn_v110_stat_callback(i, c))
return 0;
if (isdn_tty_stat_callback(i, c))
return 0;
@@ -456,14 +554,14 @@
cmd.driver = di;
cmd.arg = c->arg;
cmd.command = ISDN_CMD_HANGUP;
- dev->drv[di]->interface->command(&cmd);
+ isdn_command(&cmd);
return 0;
}
/* Try to find a network-interface which will accept incoming call */
cmd.driver = di;
cmd.arg = c->arg;
cmd.command = ISDN_CMD_LOCK;
- dev->drv[di]->interface->command(&cmd);
+ isdn_command(&cmd);
r = isdn_net_find_icall(di, c->arg, i, c->parm.setup);
switch (r) {
case 0:
@@ -476,7 +574,7 @@
cmd.driver = di;
cmd.arg = c->arg;
cmd.command = ISDN_CMD_HANGUP;
- dev->drv[di]->interface->command(&cmd);
+ isdn_command(&cmd);
retval = 2;
}
break;
@@ -486,7 +584,7 @@
cmd.driver = di;
cmd.arg = c->arg;
cmd.command = ISDN_CMD_ACCEPTD;
- dev->drv[di]->interface->command(&cmd);
+ isdn_command(&cmd);
retval = 1;
break;
case 2: /* For calling back, first reject incoming call ... */
@@ -496,7 +594,7 @@
cmd.driver = di;
cmd.arg = c->arg;
cmd.command = ISDN_CMD_HANGUP;
- dev->drv[di]->interface->command(&cmd);
+ isdn_command(&cmd);
if (r == 3)
break;
/* Fall through */
@@ -509,7 +607,7 @@
cmd.driver = di;
cmd.arg = c->arg;
cmd.command = ISDN_CMD_UNLOCK;
- dev->drv[di]->interface->command(&cmd);
+ isdn_command(&cmd);
}
return retval;
break;
@@ -522,7 +620,8 @@
if (dev->global_flags & ISDN_GLOBAL_STOPPED)
return 0;
if (strcmp(c->parm.num, "0"))
- isdn_net_stat_callback(i, c->command);
+ isdn_net_stat_callback(i, c);
+ isdn_tty_stat_callback(i, c);
break;
case ISDN_STAT_CAUSE:
#ifdef ISDN_DEBUG_STATCALLB
@@ -541,14 +640,15 @@
if (dev->global_flags & ISDN_GLOBAL_STOPPED)
return 0;
/* Find any net-device, waiting for D-channel setup */
- if (isdn_net_stat_callback(i, c->command))
+ if (isdn_net_stat_callback(i, c))
break;
+ isdn_v110_stat_callback(i, c);
/* Find any ttyI, waiting for D-channel setup */
if (isdn_tty_stat_callback(i, c)) {
cmd.driver = di;
cmd.arg = c->arg;
cmd.command = ISDN_CMD_ACCEPTB;
- dev->drv[di]->interface->command(&cmd);
+ isdn_command(&cmd);
break;
}
break;
@@ -563,8 +663,9 @@
dev->drv[di]->flags &= ~(1 << (c->arg));
isdn_info_update();
/* Signal hangup to network-devices */
- if (isdn_net_stat_callback(i, c->command))
+ if (isdn_net_stat_callback(i, c))
break;
+ isdn_v110_stat_callback(i, c);
if (isdn_tty_stat_callback(i, c))
break;
break;
@@ -579,8 +680,9 @@
return 0;
dev->drv[di]->flags |= (1 << (c->arg));
isdn_info_update();
- if (isdn_net_stat_callback(i, c->command))
+ if (isdn_net_stat_callback(i, c))
break;
+ isdn_v110_stat_callback(i, c);
if (isdn_tty_stat_callback(i, c))
break;
break;
@@ -594,6 +696,12 @@
return 0;
dev->drv[di]->flags &= ~(1 << (c->arg));
isdn_info_update();
+#ifdef CONFIG_ISDN_X25
+ /* Signal hangup to network-devices */
+ if (isdn_net_stat_callback(i, c))
+ break;
+#endif
+ isdn_v110_stat_callback(i, c);
if (isdn_tty_stat_callback(i, c))
break;
break;
@@ -605,7 +713,7 @@
#endif
if (dev->global_flags & ISDN_GLOBAL_STOPPED)
return 0;
- if (isdn_net_stat_callback(i, c->command))
+ if (isdn_net_stat_callback(i, c))
break;
if (isdn_tty_stat_callback(i, c))
break;
@@ -636,6 +744,8 @@
isdn_info_update();
restore_flags(flags);
return 0;
+ case ISDN_STAT_L1ERR:
+ break;
default:
return -1;
}
@@ -752,7 +862,7 @@
ISDN_AUDIO_SKB_LOCK(skb) = 0;
#endif
skb = skb_dequeue(&dev->drv[di]->rpqueue[channel]);
- isdn_trash_skb(skb);
+ dev_kfree_skb(skb);
} else {
/* Not yet emptied this buff, so it
* must stay in the queue, for further calls
@@ -848,8 +958,8 @@
wake_up_interruptible(&(dev->info_waitq));
}
-static RWTYPE
-isdn_read(struct file *file, char *buf, RWARG count, loff_t *off)
+static ssize_t
+isdn_read(struct file *file, char *buf, size_t count, loff_t * off)
{
uint minor = MINOR(file->f_dentry->d_inode->i_rdev);
int len = 0;
@@ -857,6 +967,9 @@
int drvidx;
int chidx;
+ if (off != &file->f_pos)
+ return -ESPIPE;
+
if (minor == ISDN_MINOR_STATUS) {
char *p;
if (!file->private_data) {
@@ -922,18 +1035,22 @@
return -ENODEV;
}
-static LSTYPE isdn_lseek(struct file *file, LSARG offset, int orig)
+static loff_t
+isdn_lseek(struct file *file, loff_t offset, int orig)
{
return -ESPIPE;
}
-static RWTYPE
-isdn_write(struct file *file, const char *buf, RWARG count, loff_t * off)
+static ssize_t
+isdn_write(struct file *file, const char *buf, size_t count, loff_t * off)
{
uint minor = MINOR(file->f_dentry->d_inode->i_rdev);
int drvidx;
int chidx;
+ if (off != &file->f_pos)
+ return -ESPIPE;
+
if (minor == ISDN_MINOR_STATUS)
return -EPERM;
if (!dev->drivers)
@@ -972,41 +1089,6 @@
return -ENODEV;
}
-#if (LINUX_VERSION_CODE < 0x020117)
-static int
-isdn_select(struct inode *inode, struct file *file, int type, select_table * st)
-{
- uint minor = MINOR(inode->i_rdev);
- int drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL);
-
- if (minor == ISDN_MINOR_STATUS) {
- if (file->private_data)
- return 1;
- else {
- if (st)
- select_wait(&(dev->info_waitq), st);
- return 0;
- }
- }
- if (minor >= ISDN_MINOR_CTRL && minor <= ISDN_MINOR_CTRLMAX) {
- if (drvidx < 0)
- return -ENODEV;
- if (dev->drv[drvidx]->stavail)
- return 1;
- else {
- if (st)
- select_wait(&(dev->drv[drvidx]->st_waitq), st);
- return 0;
- }
- return 1;
- }
-#ifdef CONFIG_ISDN_PPP
- if (minor <= ISDN_MINOR_PPPMAX)
- return (isdn_ppp_select(minor - ISDN_MINOR_PPP, file, type, st));
-#endif
- return -ENODEV;
-}
-#else
static unsigned int
isdn_poll(struct file *file, poll_table * wait)
{
@@ -1041,7 +1123,6 @@
printk(KERN_ERR "isdn_common: isdn_poll 2 -> what the hell\n");
return POLLERR;
}
-#endif
static int
isdn_set_allcfg(char *src)
@@ -1055,7 +1136,7 @@
if ((ret = isdn_net_rmall()))
return ret;
if ((ret = copy_from_user((char *) &i, src, sizeof(int))))
- return ret;
+ return ret;
save_flags(flags);
cli();
src += sizeof(int);
@@ -1082,7 +1163,7 @@
restore_flags(flags);
return ret;
}
- GET_USER(phone.phone[phone_len], src++);
+ get_user(phone.phone[phone_len], src++);
if ((phone.phone[phone_len] == ' ') ||
(phone.phone[phone_len] == '\0')) {
if (phone_len) {
@@ -1122,28 +1203,30 @@
cli();
p = dev->netdev;
while (p) {
+ isdn_net_local *lp = p->local;
+
if ((ret = verify_area(VERIFY_WRITE, (void *) dest, sizeof(cfg) + 200))) {
restore_flags(flags);
return ret;
}
- strcpy(cfg.eaz, p->local.msn);
- cfg.exclusive = p->local.exclusive;
- if (p->local.pre_device >= 0) {
- sprintf(cfg.drvid, "%s,%d", dev->drvid[p->local.pre_device],
- p->local.pre_channel);
+ strcpy(cfg.eaz, lp->msn);
+ cfg.exclusive = lp->exclusive;
+ if (lp->pre_device >= 0) {
+ sprintf(cfg.drvid, "%s,%d", dev->drvid[lp->pre_device],
+ lp->pre_channel);
} else
cfg.drvid[0] = '\0';
- cfg.onhtime = p->local.onhtime;
- cfg.charge = p->local.charge;
- cfg.l2_proto = p->local.l2_proto;
- cfg.l3_proto = p->local.l3_proto;
- cfg.p_encap = p->local.p_encap;
- cfg.secure = (p->local.flags & ISDN_NET_SECURE) ? 1 : 0;
- cfg.callback = (p->local.flags & ISDN_NET_CALLBACK) ? 1 : 0;
- cfg.chargehup = (p->local.hupflags & ISDN_CHARGEHUP) ? 1 : 0;
- cfg.ihup = (p->local.hupflags & ISDN_INHUP) ? 1 : 0;
- cfg.chargeint = p->local.chargeint;
- if (copy_to_user(dest, p->local.name, 10)) {
+ cfg.onhtime = lp->onhtime;
+ cfg.charge = lp->charge;
+ cfg.l2_proto = lp->l2_proto;
+ cfg.l3_proto = lp->l3_proto;
+ cfg.p_encap = lp->p_encap;
+ cfg.secure = (lp->flags & ISDN_NET_SECURE) ? 1 : 0;
+ cfg.callback = (lp->flags & ISDN_NET_CALLBACK) ? 1 : 0;
+ cfg.chargehup = (lp->hupflags & ISDN_CHARGEHUP) ? 1 : 0;
+ cfg.ihup = (lp->hupflags & ISDN_INHUP) ? 1 : 0;
+ cfg.chargeint = lp->chargeint;
+ if (copy_to_user(dest, lp->name, 10)) {
restore_flags(flags);
return -EFAULT;
}
@@ -1153,14 +1236,14 @@
return -EFAULT;
}
dest += sizeof(cfg);
- strcpy(phone.name, p->local.name);
+ strcpy(phone.name, lp->name);
phone.outgoing = 0;
if ((ret = isdn_net_getphones(&phone, dest)) < 0) {
restore_flags(flags);
return ret;
} else
dest += ret;
- strcpy(phone.name, p->local.name);
+ strcpy(phone.name, lp->name);
phone.outgoing = 1;
if ((ret = isdn_net_getphones(&phone, dest)) < 0) {
restore_flags(flags);
@@ -1343,9 +1426,9 @@
/* Force hangup of a network-interface */
if (!arg)
return -EINVAL;
- if ((ret = copy_from_user(name, (char *) arg, sizeof(name))))
- return ret;
- return isdn_net_force_hangup(name);
+ if ((ret = copy_from_user(name, (char *) arg, sizeof(name))))
+ return ret;
+ return isdn_net_force_hangup(name);
break;
#endif /* CONFIG_NETDEVICES */
case IIOCSETVER:
@@ -1366,7 +1449,7 @@
int i;
char *p;
if ((ret = copy_from_user((char *) &iocts, (char *) arg,
- sizeof(isdn_ioctl_struct))))
+ sizeof(isdn_ioctl_struct))))
return ret;
if (strlen(iocts.drvid)) {
if ((p = strchr(iocts.drvid, ',')))
@@ -1440,7 +1523,7 @@
for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
if ((ret = copy_from_user(dev->mdm.info[i].emu.profile, p,
- ISDN_MODEM_ANZREG)))
+ ISDN_MODEM_ANZREG)))
return ret;
p += ISDN_MODEM_ANZREG;
if ((ret = copy_from_user(dev->mdm.info[i].emu.pmsn, p, ISDN_MSNLEN)))
@@ -1482,7 +1565,7 @@
while (1) {
if ((ret = verify_area(VERIFY_READ, p, 1)))
return ret;
- GET_USER(bname[j], p++);
+ get_user(bname[j], p++);
switch (bname[j]) {
case '\0':
loop = 0;
@@ -1554,7 +1637,7 @@
c.command = ISDN_CMD_IOCTL;
c.arg = cmd;
memcpy(c.parm.num, (char *) &iocts.arg, sizeof(ulong));
- ret = dev->drv[drvidx]->interface->command(&c);
+ ret = isdn_command(&c);
memcpy((char *) &iocts.arg, c.parm.num, sizeof(ulong));
if ((copy_to_user((char *) arg, &iocts, sizeof(isdn_ioctl_struct))))
return -EFAULT;
@@ -1616,7 +1699,7 @@
return -ENODEV;
c.command = ISDN_CMD_LOCK;
c.driver = drvidx;
- (void) dev->drv[drvidx]->interface->command(&c);
+ isdn_command(&c);
MOD_INC_USE_COUNT;
return 0;
}
@@ -1627,7 +1710,7 @@
c.command = ISDN_CMD_LOCK;
c.driver = drvidx;
MOD_INC_USE_COUNT;
- (void) dev->drv[drvidx]->interface->command(&c);
+ isdn_command(&c);
return 0;
}
#ifdef CONFIG_ISDN_PPP
@@ -1641,7 +1724,7 @@
return -ENODEV;
}
-static CLOSETYPE
+static int
isdn_close(struct inode *ino, struct file *filep)
{
uint minor = MINOR(ino->i_rdev);
@@ -1659,39 +1742,39 @@
else
dev->infochain = (infostruct *) (p->next);
kfree(p);
- return CLOSEVAL;
+ return 0;
}
q = p;
p = (infostruct *) (p->next);
}
printk(KERN_WARNING "isdn: No private data while closing isdnctrl\n");
- return CLOSEVAL;
+ return 0;
}
if (minor < ISDN_MINOR_CTRL) {
drvidx = isdn_minor2drv(minor);
if (drvidx < 0)
- return CLOSEVAL;
+ return 0;
c.command = ISDN_CMD_UNLOCK;
c.driver = drvidx;
- (void) dev->drv[drvidx]->interface->command(&c);
- return CLOSEVAL;
+ isdn_command(&c);
+ return 0;
}
if (minor <= ISDN_MINOR_CTRLMAX) {
drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL);
if (drvidx < 0)
- return CLOSEVAL;
+ return 0;
if (dev->profd == current)
dev->profd = NULL;
c.command = ISDN_CMD_UNLOCK;
c.driver = drvidx;
- (void) dev->drv[drvidx]->interface->command(&c);
- return CLOSEVAL;
+ isdn_command(&c);
+ return 0;
}
#ifdef CONFIG_ISDN_PPP
if (minor <= ISDN_MINOR_PPPMAX)
isdn_ppp_release(minor - ISDN_MINOR_PPP, filep);
#endif
- return CLOSEVAL;
+ return 0;
}
static struct file_operations isdn_fops =
@@ -1700,11 +1783,7 @@
isdn_read,
isdn_write,
NULL, /* isdn_readdir */
-#if (LINUX_VERSION_CODE < 0x020117)
- isdn_select, /* isdn_select */
-#else
isdn_poll, /* isdn_poll */
-#endif
isdn_ioctl, /* isdn_ioctl */
NULL, /* isdn_mmap */
isdn_open,
@@ -1731,6 +1810,8 @@
* Find an unused ISDN-channel, whose feature-flags match the
* given L2- and L3-protocols.
*/
+#define L2V (~(ISDN_FEATURE_L2_V11096|ISDN_FEATURE_L2_V11019|ISDN_FEATURE_L2_V11038))
+
int
isdn_get_free_channel(int usage, int l2_proto, int l3_proto, int pre_dev
,int pre_chan)
@@ -1738,11 +1819,18 @@
int i;
ulong flags;
ulong features;
+ ulong vfeatures;
isdn_ctrl cmd;
save_flags(flags);
cli();
- features = (1 << l2_proto) | (0x100 << l3_proto);
+ features = ((1 << l2_proto) | (0x10000 << l3_proto));
+ vfeatures = (((1 << l2_proto) | (0x10000 << l3_proto)) &
+ ~(ISDN_FEATURE_L2_V11096|ISDN_FEATURE_L2_V11019|ISDN_FEATURE_L2_V11038));
+ /* If Layer-2 protocol is V.110, accept drivers with
+ * transparent feature even if these don't support V.110
+ * because we can emulate this in linklevel.
+ */
for (i = 0; i < ISDN_MAX_CHANNELS; i++)
if (USG_NONE(dev->usage[i]) &&
(dev->drvmap[i] != -1)) {
@@ -1751,7 +1839,9 @@
((pre_dev != d) || (pre_chan != dev->chanmap[i])))
continue;
if ((dev->drv[d]->running)) {
- if ((dev->drv[d]->interface->features & features) == features) {
+ if (((dev->drv[d]->interface->features & features) == features) ||
+ (((dev->drv[d]->interface->features & vfeatures) == vfeatures) &&
+ (dev->drv[d]->interface->features & ISDN_FEATURE_L2_TRANS))) {
if ((pre_dev < 0) || (pre_chan < 0)) {
dev->usage[i] &= ISDN_USAGE_EXCLUSIVE;
dev->usage[i] |= usage;
@@ -1759,7 +1849,7 @@
cmd.driver = d;
cmd.arg = 0;
cmd.command = ISDN_CMD_LOCK;
- (void) dev->drv[d]->interface->command(&cmd);
+ isdn_command(&cmd);
restore_flags(flags);
return i;
} else {
@@ -1770,7 +1860,7 @@
cmd.driver = d;
cmd.arg = 0;
cmd.command = ISDN_CMD_LOCK;
- (void) dev->drv[d]->interface->command(&cmd);
+ isdn_command(&cmd);
restore_flags(flags);
return i;
}
@@ -1808,7 +1898,7 @@
cmd.arg = ch;
cmd.command = ISDN_CMD_UNLOCK;
restore_flags(flags);
- (void) dev->drv[di]->interface->command(&cmd);
+ isdn_command(&cmd);
return;
}
restore_flags(flags);
@@ -1837,31 +1927,6 @@
}
/*
- * receive callback handler for drivers not supporting sk_buff's.
- * Parameters:
- *
- * di = Driver-Index.
- * channel = Number of B-Channel (0...)
- * buf = pointer to packet-data
- * len = Length of packet-data
- *
- */
-static void
-isdn_receive_callback(int drvidx, int chan, u_char * buf, int len)
-{
- struct sk_buff *skb;
-
- if (dev->global_flags & ISDN_GLOBAL_STOPPED)
- return;
- skb = dev_alloc_skb(len);
- if (skb) {
- memcpy(skb_put(skb, len), buf, len);
- isdn_receive_skb_callback(drvidx, chan, skb);
- } else
- printk(KERN_WARNING "isdn: rcv alloc_skb failed, packet dropped.\n");
-}
-
-/*
* writebuf replacement for SKB_ABLE drivers
*/
static int
@@ -1869,60 +1934,69 @@
int user)
{
int ret;
+ int hl = dev->drv[drvidx]->interface->hl_hdrlen;
+ struct sk_buff *skb = alloc_skb(hl + len, GFP_ATOMIC);
- if (dev->drv[drvidx]->interface->writebuf)
- ret = dev->drv[drvidx]->interface->writebuf(drvidx, chan, buf,
- len, user);
- else {
- struct sk_buff *skb;
-
- skb = alloc_skb(dev->drv[drvidx]->interface->hl_hdrlen + len,
- GFP_ATOMIC);
- if (skb == NULL)
- return 0;
-
- skb_reserve(skb, dev->drv[drvidx]->interface->hl_hdrlen);
- SET_SKB_FREE(skb);
-
- if (user)
- copy_from_user(skb_put(skb, len), buf, len);
- else
- memcpy(skb_put(skb, len), buf, len);
+ if (!skb)
+ return 0;
+ skb_reserve(skb, hl);
+ if (user)
+ copy_from_user(skb_put(skb, len), buf, len);
+ else
+ memcpy(skb_put(skb, len), buf, len);
- ret = dev->drv[drvidx]->interface->writebuf_skb(drvidx,
- chan, skb);
- if (ret <= 0)
- kfree_skb(skb);
- }
+ ret = dev->drv[drvidx]->interface->writebuf_skb(drvidx, chan, 1, skb);
+ if (ret <= 0)
+ dev_kfree_skb(skb);
if (ret > 0)
dev->obytes[isdn_dc2minor(drvidx, chan)] += ret;
return ret;
}
/*
- * writebuf_skb replacement for NON SKB_ABLE drivers
- * If lowlevel-device does not support supports skbufs, use
- * standard send-routine, else sind directly.
- *
* Return: length of data on success, -ERRcode on failure.
*/
-
int
-isdn_writebuf_skb_stub(int drvidx, int chan, struct sk_buff *skb)
+isdn_writebuf_skb_stub(int drvidx, int chan, int ack, struct sk_buff *skb)
{
int ret;
- int len = skb->len; /* skb pointer no longer valid after free */
-
- if (dev->drv[drvidx]->interface->writebuf_skb)
- ret = dev->drv[drvidx]->interface->
- writebuf_skb(drvidx, chan, skb);
- else {
- if ((ret = dev->drv[drvidx]->interface->
- writebuf(drvidx, chan, skb->data, skb->len, 0)) == len)
+ struct sk_buff *nskb = NULL;
+ int v110_ret = skb->len;
+ int idx = isdn_dc2minor(drvidx, chan);
+
+ if (dev->v110[idx]) {
+ atomic_inc(&dev->v110use[idx]);
+ nskb = isdn_v110_encode(dev->v110[idx], skb);
+ atomic_dec(&dev->v110use[idx]);
+ if (!nskb)
+ return 0;
+ v110_ret = *((int *)nskb->data);
+ skb_pull(nskb, sizeof(int));
+ if (!nskb->len) {
+ dev_kfree_skb(nskb);
dev_kfree_skb(skb);
- }
- if (ret > 0)
- dev->obytes[isdn_dc2minor(drvidx, chan)] += len;
+ return v110_ret;
+ }
+ /* V.110 must always be acknowledged */
+ ack = 1;
+ ret = dev->drv[drvidx]->interface->writebuf_skb(drvidx, chan, ack, nskb);
+ } else
+ ret = dev->drv[drvidx]->interface->writebuf_skb(drvidx, chan, ack, skb);
+ if (ret > 0) {
+ dev->obytes[idx] += ret;
+ if (dev->v110[idx]) {
+ atomic_inc(&dev->v110use[idx]);
+ dev->v110[idx]->skbuser++;
+ atomic_dec(&dev->v110use[idx]);
+ dev_kfree_skb(skb);
+ /* For V.110 return unencoded data length */
+ ret = v110_ret;
+ if (ret == skb->len)
+ dev_kfree_skb(skb);
+ }
+ } else
+ if (dev->v110[idx])
+ dev_kfree_skb(nskb);
return ret;
}
@@ -1930,6 +2004,8 @@
* Low-level-driver registration
*/
+EXPORT_SYMBOL(register_isdn);
+
int
register_isdn(isdn_if * i)
{
@@ -1951,7 +2027,7 @@
ISDN_MAX_CHANNELS);
return 0;
}
- if ((!i->writebuf_skb) && (!i->writebuf)) {
+ if (!i->writebuf_skb) {
printk(KERN_WARNING "register_isdn: No write routine given.\n");
return 0;
}
@@ -2019,7 +2095,6 @@
i->channels = drvidx;
i->rcvcallb_skb = isdn_receive_skb_callback;
- i->rcvcallb = isdn_receive_callback;
i->statcallb = isdn_status_callback;
if (!strlen(i->id))
sprintf(i->id, "line%d", drvidx);
@@ -2078,11 +2153,7 @@
isdn_init(void)
{
int i;
- char irev[50];
- char trev[50];
- char nrev[50];
- char prev[50];
- char arev[50];
+ char tmprev[50];
sti();
if (!(dev = (isdn_dev *) kmalloc(sizeof(isdn_dev), GFP_KERNEL))) {
@@ -2126,18 +2197,18 @@
}
#endif /* CONFIG_ISDN_PPP */
- isdn_export_syms();
-
- strcpy(irev, isdn_revision);
- strcpy(trev, isdn_tty_revision);
- strcpy(nrev, isdn_net_revision);
- strcpy(prev, isdn_ppp_revision);
- strcpy(arev, isdn_audio_revision);
- printk(KERN_NOTICE "ISDN subsystem Rev: %s/", isdn_getrev(irev));
- printk("%s/", isdn_getrev(trev));
- printk("%s/", isdn_getrev(nrev));
- printk("%s/", isdn_getrev(prev));
- printk("%s", isdn_getrev(arev));
+ strcpy(tmprev, isdn_revision);
+ printk(KERN_NOTICE "ISDN subsystem Rev: %s/", isdn_getrev(tmprev));
+ strcpy(tmprev, isdn_tty_revision);
+ printk("%s/", isdn_getrev(tmprev));
+ strcpy(tmprev, isdn_net_revision);
+ printk("%s/", isdn_getrev(tmprev));
+ strcpy(tmprev, isdn_ppp_revision);
+ printk("%s/", isdn_getrev(tmprev));
+ strcpy(tmprev, isdn_audio_revision);
+ printk("%s/", isdn_getrev(tmprev));
+ strcpy(tmprev, isdn_v110_revision);
+ printk("%s", isdn_getrev(tmprev));
#ifdef MODULE
printk(" loaded\n");
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov