patch-2.0.31 linux/drivers/isdn/isdn_common.c
Next file: linux/drivers/isdn/isdn_common.h
Previous file: linux/drivers/isdn/isdn_cards.h
Back to the patch index
Back to the overall index
- Lines: 2751
- Date:
Tue Aug 5 11:05:16 1997
- Orig file:
v2.0.30/linux/drivers/isdn/isdn_common.c
- Orig date:
Tue Nov 12 22:36:19 1996
diff -u --recursive --new-file v2.0.30/linux/drivers/isdn/isdn_common.c linux/drivers/isdn/isdn_common.c
@@ -1,11 +1,11 @@
-/* $Id: isdn_common.c,v 1.28 1996/11/13 02:33:19 fritz Exp $
- *
+/* $Id: isdn_common.c,v 1.44 1997/05/27 15:17:23 fritz Exp $
+
* Linux ISDN subsystem, common used functions (linklevel).
*
* Copyright 1994,95,96 by Fritz Elfert (fritz@wuemaus.franken.de)
* Copyright 1995,96 Thinking Objects Software GmbH Wuerzburg
* Copyright 1995,96 by Michael Hipp (Michael.Hipp@student.uni-tuebingen.de)
- *
+ *
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
@@ -18,9 +18,72 @@
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: isdn_common.c,v $
+ * Revision 1.44 1997/05/27 15:17:23 fritz
+ * Added changes for recent 2.1.x kernels:
+ * changed return type of isdn_close
+ * queue_task_* -> queue_task
+ * clear/set_bit -> test_and_... where apropriate.
+ * changed type of hard_header_cache parameter.
+ *
+ * Revision 1.43 1997/03/31 14:09:43 fritz
+ * Fixed memory leak in isdn_close().
+ *
+ * Revision 1.42 1997/03/30 16:51:08 calle
+ * changed calls to copy_from_user/copy_to_user and removed verify_area
+ * were possible.
+ *
+ * Revision 1.41 1997/03/24 22:54:41 fritz
+ * Some small fixes in debug code.
+ *
+ * Revision 1.40 1997/03/08 08:13:51 fritz
+ * Bugfix: IIOCSETMAP (Set mapping) was broken.
+ *
+ * Revision 1.39 1997/03/07 01:32:54 fritz
+ * Added proper ifdef's for CONFIG_ISDN_AUDIO
+ *
+ * Revision 1.38 1997/03/05 21:15:02 fritz
+ * Fix: reduced stack usage of isdn_ioctl() and isdn_set_allcfg()
+ *
+ * Revision 1.37 1997/03/02 14:29:18 fritz
+ * More ttyI related cleanup.
+ *
+ * Revision 1.36 1997/02/28 02:32:40 fritz
+ * Cleanup: Moved some tty related stuff from isdn_common.c
+ * to isdn_tty.c
+ * Bugfix: Bisync protocol did not behave like documented.
+ *
+ * Revision 1.35 1997/02/21 13:01:19 fritz
+ * Changes CAUSE message output in kernel log.
+ *
+ * Revision 1.34 1997/02/10 20:12:43 fritz
+ * Changed interface for reporting incoming calls.
+ *
+ * Revision 1.33 1997/02/10 10:05:42 fritz
+ * More changes for Kernel 2.1.X
+ * Symbol information moved to isdn_syms.c
+ *
+ * Revision 1.32 1997/02/03 22:55:26 fritz
+ * Reformatted according CodingStyle.
+ * Changed isdn_writebuf_stub static.
+ * Slow down tty-RING counter.
+ * skb->free stuff replaced by macro.
+ * Bugfix in audio-skb locking.
+ * Bugfix in HL-driver locking.
+ *
+ * Revision 1.31 1997/01/17 01:19:18 fritz
+ * Applied chargeint patch.
+ *
+ * Revision 1.30 1997/01/14 01:27:47 fritz
+ * Changed audio receive not to rely on skb->users and skb->lock.
+ * Added ATI2 and related variables.
+ * Started adding full-duplex audio capability.
+ *
+ * Revision 1.29 1997/01/12 23:33:03 fritz
+ * Made isdn_all_eaz foolproof.
+ *
* Revision 1.28 1996/11/13 02:33:19 fritz
* Fixed a race condition.
*
@@ -134,11 +197,13 @@
*/
#include <linux/config.h>
+#define __NO_VERSION__
#include <linux/module.h>
#include <linux/version.h>
-#ifndef __GENKSYMS__ /* Don't want genksyms report unneeded structs */
-#include <linux/isdn.h>
+#if (LINUX_VERSION_CODE >= 0x020117)
+#include <asm/poll.h>
#endif
+#include <linux/isdn.h>
#include "isdn_common.h"
#include "isdn_tty.h"
#include "isdn_net.h"
@@ -149,13 +214,11 @@
#include "isdn_cards.h"
/* Debugflags */
-#undef ISDN_DEBUG_STATCALLB
-#define NEW_ISDN_TIMER_CTRL
+#undef ISDN_DEBUG_STATCALLB
isdn_dev *dev = (isdn_dev *) 0;
-static int has_exported = 0;
-static char *isdn_revision = "$Revision: 1.28 $";
+static char *isdn_revision = "$Revision: 1.44 $";
extern char *isdn_net_revision;
extern char *isdn_tty_revision;
@@ -170,18 +233,23 @@
static char *isdn_audio_revision = ": none $";
#endif
-void isdn_MOD_INC_USE_COUNT(void)
+static int isdn_writebuf_stub(int, int, const u_char *, int, int);
+
+void
+isdn_MOD_INC_USE_COUNT(void)
{
MOD_INC_USE_COUNT;
}
-void isdn_MOD_DEC_USE_COUNT(void)
+void
+isdn_MOD_DEC_USE_COUNT(void)
{
MOD_DEC_USE_COUNT;
}
#if defined(ISDN_DEBUG_NET_DUMP) || defined(ISDN_DEBUG_MODEM_DUMP)
-void isdn_dumppkt(char *s, u_char * p, int len, int dumplen)
+void
+isdn_dumppkt(char *s, u_char * p, int len, int dumplen)
{
int dumpc;
@@ -192,26 +260,29 @@
}
#endif
-static __inline void isdn_trash_skb(struct sk_buff *skb, int rw)
+static __inline void
+isdn_trash_skb(struct sk_buff *skb, int rw)
{
- skb->free = 1;
- kfree_skb(skb, rw);
+ SET_SKB_FREE(skb);
+ kfree_skb(skb, rw);
}
-static void isdn_free_queue(struct sk_buff_head *queue)
+static void
+isdn_free_queue(struct sk_buff_head *queue)
{
- struct sk_buff *skb;
- unsigned long flags;
+ struct sk_buff *skb;
+ unsigned long flags;
- save_flags(flags);
- cli();
- if (skb_queue_len(queue))
- while ((skb = skb_dequeue(queue)))
- isdn_trash_skb(skb, FREE_READ);
- restore_flags(flags);
+ save_flags(flags);
+ cli();
+ if (skb_queue_len(queue))
+ while ((skb = skb_dequeue(queue)))
+ isdn_trash_skb(skb, FREE_READ);
+ restore_flags(flags);
}
-int isdn_dc2minor(int di, int ch)
+int
+isdn_dc2minor(int di, int ch)
{
int i;
for (i = 0; i < ISDN_MAX_CHANNELS; i++)
@@ -222,8 +293,10 @@
static int isdn_timer_cnt1 = 0;
static int isdn_timer_cnt2 = 0;
+static int isdn_timer_cnt3 = 0;
-static void isdn_timer_funct(ulong dummy)
+static void
+isdn_timer_funct(ulong dummy)
{
int tf = dev->tflags;
@@ -241,34 +314,35 @@
if (tf & ISDN_TIMER_NETDIAL)
isdn_net_dial();
}
- if (++isdn_timer_cnt2 >= ISDN_TIMER_1SEC) {
- isdn_timer_cnt2 = 0;
- if (tf & ISDN_TIMER_NETHANGUP)
- isdn_net_autohup();
- if (tf & ISDN_TIMER_MODEMRING)
- isdn_tty_modem_ring();
+ if (++isdn_timer_cnt2 >= ISDN_TIMER_1SEC) {
+ isdn_timer_cnt2 = 0;
+ if (tf & ISDN_TIMER_NETHANGUP)
+ isdn_net_autohup();
+ if (++isdn_timer_cnt3 > ISDN_TIMER_RINGING) {
+ isdn_timer_cnt3 = 0;
+ if (tf & ISDN_TIMER_MODEMRING)
+ isdn_tty_modem_ring();
+ }
#if (defined CONFIG_ISDN_PPP) && (defined CONFIG_ISDN_MPP)
- if (tf & ISDN_TIMER_IPPP)
- isdn_ppp_timer_timeout();
+ if (tf & ISDN_TIMER_IPPP)
+ isdn_ppp_timer_timeout();
#endif
- }
+ }
}
if (tf) {
- int flags;
+ int flags;
save_flags(flags);
cli();
- del_timer(&dev->timer);
-#ifndef NEW_ISDN_TIMER_CTRL
- dev->timer.function = isdn_timer_funct;
-#endif
+ del_timer(&dev->timer);
dev->timer.expires = jiffies + ISDN_TIMER_RES;
add_timer(&dev->timer);
restore_flags(flags);
}
}
-void isdn_timer_ctrl(int tf, int onoff)
+void
+isdn_timer_ctrl(int tf, int onoff)
{
int flags;
@@ -283,447 +357,287 @@
dev->tflags |= tf;
else
dev->tflags &= ~tf;
-#ifdef NEW_ISDN_TIMER_CTRL
if (dev->tflags) {
- if (!del_timer(&dev->timer)) /* del_timer is 1, when active */
- dev->timer.expires = jiffies + ISDN_TIMER_RES;
+ if (!del_timer(&dev->timer)) /* del_timer is 1, when active */
+ dev->timer.expires = jiffies + ISDN_TIMER_RES;
add_timer(&dev->timer);
}
-#else
- if (dev->tflags) {
- del_timer(&dev->timer);
- dev->timer.function = isdn_timer_funct;
- dev->timer.expires = jiffies + ISDN_TIMER_RES;
- add_timer(&dev->timer);
- }
-#endif
restore_flags(flags);
}
/*
* Receive a packet from B-Channel. (Called from low-level-module)
*/
-static void isdn_receive_skb_callback(int di, int channel, struct sk_buff *skb)
+static void
+isdn_receive_skb_callback(int di, int channel, struct sk_buff *skb)
{
- ulong flags;
int i;
- int midx;
-#ifdef CONFIG_ISDN_AUDIO
- int ifmt;
-#endif
- modem_info *info;
-
- if ((i = isdn_dc2minor(di,channel))==-1) {
- isdn_trash_skb(skb, FREE_READ);
- return;
- }
+
+ if ((i = isdn_dc2minor(di, channel)) == -1) {
+ isdn_trash_skb(skb, FREE_READ);
+ return;
+ }
/* Update statistics */
- dev->ibytes[i] += skb->len;
+ dev->ibytes[i] += skb->len;
/* First, try to deliver data to network-device */
if (isdn_net_rcv_skb(i, skb))
return;
/* No network-device found, deliver to tty or raw-channel */
- skb->free = 1;
+ SET_SKB_FREE(skb);
if (skb->len) {
- if ((midx = dev->m_idx[i])<0) {
- /* if midx is invalid, drop packet */
- isdn_trash_skb(skb, FREE_READ);
- return;
- }
- info = &dev->mdm.info[midx];
-#ifdef CONFIG_ISDN_AUDIO
- ifmt = 1;
-
- if (info->vonline)
- isdn_audio_calc_dtmf(info, skb->data, skb->len, ifmt);
-#endif
- if ((info->online < 2) &&
- (!(info->vonline & 1))) {
- /* If Modem not listening, drop data */
- isdn_trash_skb(skb, FREE_READ);
- return;
- }
- if (info->emu.mdmreg[13] & 2)
- /* T.70 decoding: Simply throw away the T.70 header (4 bytes) */
- if ((skb->data[0] == 1) && ((skb->data[1] == 0) || (skb->data[1] == 1)))
- skb_pull(skb,4);
- /* The users field of an sk_buff is used in a special way
- * with tty's incoming data:
- * users is set to the number of DLE codes when in audio mode.
- */
- skb->users = 0;
-#ifdef CONFIG_ISDN_AUDIO
- if (info->vonline & 1) {
- /* voice conversion/compression */
- switch (info->emu.vpar[3]) {
- case 2:
- case 3:
- case 4:
- /* adpcm
- * Since compressed data takes less
- * space, we can overwrite the buffer.
- */
- skb_trim(skb,isdn_audio_xlaw2adpcm(info->adpcmr,
- ifmt,
- skb->data,
- skb->data,
- skb->len));
- break;
- case 5:
- /* a-law */
- if (!ifmt)
- isdn_audio_ulaw2alaw(skb->data,skb->len);
- break;
- case 6:
- /* u-law */
- if (ifmt)
- isdn_audio_alaw2ulaw(skb->data,skb->len);
- break;
- }
- skb->users = isdn_tty_countDLE(skb->data,skb->len);
- }
-#endif
- /* Try to deliver directly via tty-flip-buf if queue is empty */
- save_flags(flags);
- cli();
- if (skb_queue_empty(&dev->drv[di]->rpqueue[channel]))
- if (isdn_tty_try_read(info, skb)) {
- restore_flags(flags);
- return;
- }
- /* Direct deliver failed or queue wasn't empty.
- * Queue up for later dequeueing via timer-irq.
- */
- __skb_queue_tail(&dev->drv[di]->rpqueue[channel], skb);
- dev->drv[di]->rcvcount[channel] += (skb->len + skb->users);
- restore_flags(flags);
- /* Schedule dequeuing */
- if ((dev->modempoll) && (info->rcvsched))
- isdn_timer_ctrl(ISDN_TIMER_MODEMREAD, 1);
- wake_up_interruptible(&dev->drv[di]->rcv_waitq[channel]);
+ if (isdn_tty_rcv_skb(i, di, channel, skb))
+ return;
+ wake_up_interruptible(&dev->drv[di]->rcv_waitq[channel]);
} else
- isdn_trash_skb(skb, FREE_READ);
+ isdn_trash_skb(skb, FREE_READ);
}
-void isdn_all_eaz(int di, int ch)
+void
+isdn_all_eaz(int di, int ch)
{
isdn_ctrl cmd;
+ if (di < 0)
+ return;
cmd.driver = di;
cmd.arg = ch;
cmd.command = ISDN_CMD_SETEAZ;
- cmd.num[0] = '\0';
+ cmd.parm.num[0] = '\0';
(void) dev->drv[di]->interface->command(&cmd);
}
-static int isdn_status_callback(isdn_ctrl * c)
+static int
+isdn_status_callback(isdn_ctrl * c)
{
int di;
- int mi;
ulong flags;
int i;
int r;
- int retval=0;
- modem_info *info;
+ int retval = 0;
isdn_ctrl cmd;
di = c->driver;
- i = isdn_dc2minor(di, c->arg);
+ i = isdn_dc2minor(di, c->arg);
switch (c->command) {
- case ISDN_STAT_BSENT:
- if (i<0)
+ case ISDN_STAT_BSENT:
+ if (i < 0)
return -1;
- if (dev->global_flags & ISDN_GLOBAL_STOPPED)
- return 0;
- if (isdn_net_stat_callback(i, c->command))
- return 0;
- isdn_tty_bsent(di, c->arg);
- wake_up_interruptible(&dev->drv[di]->snd_waitq[c->arg]);
- break;
- case ISDN_STAT_STAVAIL:
- save_flags(flags);
- cli();
- dev->drv[di]->stavail += c->arg;
- restore_flags(flags);
- wake_up_interruptible(&dev->drv[di]->st_waitq);
- break;
- case ISDN_STAT_RUN:
- dev->drv[di]->running = 1;
- for (i = 0; i < ISDN_MAX_CHANNELS; i++)
- if (dev->drvmap[i] == di)
- isdn_all_eaz(di, dev->chanmap[i]);
- break;
- case ISDN_STAT_STOP:
- dev->drv[di]->running = 0;
- break;
- case ISDN_STAT_ICALL:
- if (i<0)
+ if (dev->global_flags & ISDN_GLOBAL_STOPPED)
+ return 0;
+ if (isdn_net_stat_callback(i, c->command))
+ return 0;
+ if (isdn_tty_stat_callback(i, c))
+ return 0;
+ wake_up_interruptible(&dev->drv[di]->snd_waitq[c->arg]);
+ break;
+ case ISDN_STAT_STAVAIL:
+ save_flags(flags);
+ cli();
+ dev->drv[di]->stavail += c->arg;
+ restore_flags(flags);
+ wake_up_interruptible(&dev->drv[di]->st_waitq);
+ break;
+ case ISDN_STAT_RUN:
+ dev->drv[di]->running = 1;
+ for (i = 0; i < ISDN_MAX_CHANNELS; i++)
+ if (dev->drvmap[i] == di)
+ isdn_all_eaz(di, dev->chanmap[i]);
+ break;
+ case ISDN_STAT_STOP:
+ dev->drv[di]->running = 0;
+ break;
+ case ISDN_STAT_ICALL:
+ if (i < 0)
return -1;
#ifdef ISDN_DEBUG_STATCALLB
- printk(KERN_DEBUG "ICALL (net): %d %ld %s\n", di, c->arg, c->num);
+ printk(KERN_DEBUG "ICALL (net): %d %ld %s\n", di, c->arg, c->parm.num);
#endif
- if (dev->global_flags & ISDN_GLOBAL_STOPPED) {
- cmd.driver = di;
- cmd.arg = c->arg;
- cmd.command = ISDN_CMD_HANGUP;
- dev->drv[di]->interface->command(&cmd);
- return 0;
- }
-
+ if (dev->global_flags & ISDN_GLOBAL_STOPPED) {
+ cmd.driver = di;
+ cmd.arg = c->arg;
+ cmd.command = ISDN_CMD_HANGUP;
+ dev->drv[di]->interface->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);
- r = isdn_net_find_icall(di, c->arg, i, c->num);
+ cmd.driver = di;
+ cmd.arg = c->arg;
+ cmd.command = ISDN_CMD_LOCK;
+ dev->drv[di]->interface->command(&cmd);
+ r = isdn_net_find_icall(di, c->arg, i, c->parm.setup);
switch (r) {
- case 0:
- /* No network-device replies. Schedule RING-message to
- * tty and set RI-bit of modem-status.
- */
- if ((mi = isdn_tty_find_icall(di, c->arg, c->num)) >= 0) {
- info = &dev->mdm.info[mi];
- info->msr |= UART_MSR_RI;
- isdn_tty_modem_result(2, info);
- isdn_timer_ctrl(ISDN_TIMER_MODEMRING, 1);
- return 1;
- } else if (dev->drv[di]->reject_bus) {
- cmd.driver = di;
- cmd.arg = c->arg;
- cmd.command = ISDN_CMD_HANGUP;
- dev->drv[di]->interface->command(&cmd);
- retval=2;
- }
- break;
- case 1:
- /* Schedule connection-setup */
- isdn_net_dial();
- cmd.driver = di;
- cmd.arg = c->arg;
- cmd.command = ISDN_CMD_ACCEPTD;
- dev->drv[di]->interface->command(&cmd);
- return 1;
- break;
- case 2: /* For calling back, first reject incoming call ... */
- case 3: /* Interface found, but down, reject call actively */
- retval=2;
- printk(KERN_INFO "isdn: Rejecting Call\n");
- cmd.driver = di;
- cmd.arg = c->arg;
- cmd.command = ISDN_CMD_HANGUP;
- dev->drv[di]->interface->command(&cmd);
- if (r == 3)
- break;
- /* Fall through */
- case 4:
- /* ... then start callback. */
- isdn_net_dial();
- return 2;
+ case 0:
+ /* No network-device replies.
+ * Try ttyI's
+ */
+ if (isdn_tty_find_icall(di, c->arg, c->parm.setup) >= 0)
+ retval = 1;
+ else if (dev->drv[di]->reject_bus) {
+ cmd.driver = di;
+ cmd.arg = c->arg;
+ cmd.command = ISDN_CMD_HANGUP;
+ dev->drv[di]->interface->command(&cmd);
+ retval = 2;
+ }
+ break;
+ case 1:
+ /* Schedule connection-setup */
+ isdn_net_dial();
+ cmd.driver = di;
+ cmd.arg = c->arg;
+ cmd.command = ISDN_CMD_ACCEPTD;
+ dev->drv[di]->interface->command(&cmd);
+ retval = 1;
+ break;
+ case 2: /* For calling back, first reject incoming call ... */
+ case 3: /* Interface found, but down, reject call actively */
+ retval = 2;
+ printk(KERN_INFO "isdn: Rejecting Call\n");
+ cmd.driver = di;
+ cmd.arg = c->arg;
+ cmd.command = ISDN_CMD_HANGUP;
+ dev->drv[di]->interface->command(&cmd);
+ if (r == 3)
+ break;
+ /* Fall through */
+ case 4:
+ /* ... then start callback. */
+ isdn_net_dial();
+ break;
}
- cmd.driver = di;
- cmd.arg = c->arg;
- cmd.command = ISDN_CMD_UNLOCK;
- dev->drv[di]->interface->command(&cmd);
- return retval;
- break;
- case ISDN_STAT_CINF:
- if (i<0)
+ if (retval != 1) {
+ cmd.driver = di;
+ cmd.arg = c->arg;
+ cmd.command = ISDN_CMD_UNLOCK;
+ dev->drv[di]->interface->command(&cmd);
+ }
+ return retval;
+ break;
+ case ISDN_STAT_CINF:
+ if (i < 0)
return -1;
#ifdef ISDN_DEBUG_STATCALLB
- printk(KERN_DEBUG "CINF: %ld %s\n", c->arg, c->num);
+ printk(KERN_DEBUG "CINF: %ld %s\n", c->arg, c->parm.num);
#endif
- if (dev->global_flags & ISDN_GLOBAL_STOPPED)
- return 0;
- if (strcmp(c->num, "0"))
- isdn_net_stat_callback(i, c->command);
- break;
- case ISDN_STAT_CAUSE:
+ if (dev->global_flags & ISDN_GLOBAL_STOPPED)
+ return 0;
+ if (strcmp(c->parm.num, "0"))
+ isdn_net_stat_callback(i, c->command);
+ break;
+ case ISDN_STAT_CAUSE:
#ifdef ISDN_DEBUG_STATCALLB
- printk(KERN_DEBUG "CAUSE: %ld %s\n", c->arg, c->num);
+ printk(KERN_DEBUG "CAUSE: %ld %s\n", c->arg, c->parm.num);
#endif
- printk(KERN_INFO "isdn: cause: %s\n", c->num);
- break;
- case ISDN_STAT_DCONN:
- if (i<0)
+ printk(KERN_INFO "isdn: %s,ch%ld cause: %s\n",
+ dev->drvid[di], c->arg, c->parm.num);
+ isdn_tty_stat_callback(i, c);
+ break;
+ case ISDN_STAT_DCONN:
+ if (i < 0)
return -1;
#ifdef ISDN_DEBUG_STATCALLB
- printk(KERN_DEBUG "DCONN: %ld\n", c->arg);
+ printk(KERN_DEBUG "DCONN: %ld\n", c->arg);
#endif
- if (dev->global_flags & ISDN_GLOBAL_STOPPED)
- return 0;
- /* Find any network-device, waiting for D-channel setup */
- if (isdn_net_stat_callback(i, c->command))
- break;
-
- if ((mi = dev->m_idx[i]) >= 0) {
- /* If any tty has just dialed-out, setup B-Channel */
- info = &dev->mdm.info[mi];
- if (info->flags &
- (ISDN_ASYNC_NORMAL_ACTIVE | ISDN_ASYNC_CALLOUT_ACTIVE)) {
- if (info->dialing == 1) {
- info->dialing = 2;
- cmd.driver = di;
- cmd.arg = c->arg;
- cmd.command = ISDN_CMD_ACCEPTB;
- dev->drv[di]->interface->command(&cmd);
- return 0;
- }
- }
- }
- break;
- case ISDN_STAT_DHUP:
- if (i<0)
+ 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))
+ break;
+ /* 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);
+ break;
+ }
+ break;
+ case ISDN_STAT_DHUP:
+ if (i < 0)
return -1;
#ifdef ISDN_DEBUG_STATCALLB
- printk(KERN_DEBUG "DHUP: %ld\n", c->arg);
-#endif
- if (dev->global_flags & ISDN_GLOBAL_STOPPED)
- return 0;
- dev->drv[di]->flags &= ~(1 << (c->arg));
- isdn_info_update();
- /* Signal hangup to network-devices */
- if (isdn_net_stat_callback(i, c->command))
- break;
- if ((mi = dev->m_idx[i]) >= 0) {
- /* Signal hangup to tty-device */
- info = &dev->mdm.info[mi];
- if (info->flags &
- (ISDN_ASYNC_NORMAL_ACTIVE | ISDN_ASYNC_CALLOUT_ACTIVE)) {
- if (info->dialing == 1) {
- info->dialing = 0;
- isdn_tty_modem_result(7, info);
- }
- if (info->online)
- isdn_tty_modem_result(3, info);
-#ifdef ISDN_DEBUG_MODEM_HUP
- printk(KERN_DEBUG "Mhup in ISDN_STAT_DHUP\n");
+ printk(KERN_DEBUG "DHUP: %ld\n", c->arg);
#endif
- isdn_tty_modem_hup(info);
- return 0;
- }
- }
- break;
- case ISDN_STAT_BCONN:
- if (i<0)
+ if (dev->global_flags & ISDN_GLOBAL_STOPPED)
+ return 0;
+ dev->drv[di]->flags &= ~(1 << (c->arg));
+ isdn_info_update();
+ /* Signal hangup to network-devices */
+ if (isdn_net_stat_callback(i, c->command))
+ break;
+ if (isdn_tty_stat_callback(i, c))
+ break;
+ break;
+ case ISDN_STAT_BCONN:
+ if (i < 0)
return -1;
#ifdef ISDN_DEBUG_STATCALLB
- printk(KERN_DEBUG "BCONN: %ld\n", c->arg);
+ printk(KERN_DEBUG "BCONN: %ld\n", c->arg);
#endif
- /* Signal B-channel-connect to network-devices */
- if (dev->global_flags & ISDN_GLOBAL_STOPPED)
- return 0;
- dev->drv[di]->flags |= (1 << (c->arg));
- isdn_info_update();
- if (isdn_net_stat_callback(i, c->command))
- break;
- if ((mi = dev->m_idx[i]) >= 0) {
- /* Schedule CONNECT-Message to any tty, waiting for it and
- * set DCD-bit of its modem-status.
- */
- info = &dev->mdm.info[mi];
- if (info->flags &
- (ISDN_ASYNC_NORMAL_ACTIVE | ISDN_ASYNC_CALLOUT_ACTIVE)) {
- info->msr |= UART_MSR_DCD;
- if (info->dialing)
- info->dialing = 0;
- info->rcvsched = 1;
- if (USG_MODEM(dev->usage[i]))
- isdn_tty_modem_result(5, info);
- if (USG_VOICE(dev->usage[i]))
- isdn_tty_modem_result(11, info);
- }
- }
- break;
- case ISDN_STAT_BHUP:
- if (i<0)
+ /* Signal B-channel-connect to network-devices */
+ if (dev->global_flags & ISDN_GLOBAL_STOPPED)
+ return 0;
+ dev->drv[di]->flags |= (1 << (c->arg));
+ isdn_info_update();
+ if (isdn_net_stat_callback(i, c->command))
+ break;
+ if (isdn_tty_stat_callback(i, c))
+ break;
+ break;
+ case ISDN_STAT_BHUP:
+ if (i < 0)
return -1;
#ifdef ISDN_DEBUG_STATCALLB
- printk(KERN_DEBUG "BHUP: %ld\n", c->arg);
-#endif
- if (dev->global_flags & ISDN_GLOBAL_STOPPED)
- return 0;
- dev->drv[di]->flags &= ~(1 << (c->arg));
- isdn_info_update();
- if ((mi = dev->m_idx[i]) >= 0) {
- /* Signal hangup to tty-device, schedule NO CARRIER-message */
- info = &dev->mdm.info[mi];
- if (info->flags &
- (ISDN_ASYNC_NORMAL_ACTIVE | ISDN_ASYNC_CALLOUT_ACTIVE)) {
- if (info->msr & UART_MSR_DCD)
- isdn_tty_modem_result(3, info);
- info->msr &= ~(UART_MSR_DCD | UART_MSR_RI);
-#ifdef ISDN_DEBUG_MODEM_HUP
- printk(KERN_DEBUG "Mhup in ISDN_STAT_BHUP\n");
+ printk(KERN_DEBUG "BHUP: %ld\n", c->arg);
#endif
- isdn_tty_modem_hup(info);
- }
- }
- break;
- case ISDN_STAT_NODCH:
- if (i<0)
+ if (dev->global_flags & ISDN_GLOBAL_STOPPED)
+ return 0;
+ dev->drv[di]->flags &= ~(1 << (c->arg));
+ isdn_info_update();
+ if (isdn_tty_stat_callback(i, c))
+ break;
+ break;
+ case ISDN_STAT_NODCH:
+ if (i < 0)
return -1;
#ifdef ISDN_DEBUG_STATCALLB
- printk(KERN_DEBUG "NODCH: %ld\n", c->arg);
+ printk(KERN_DEBUG "NODCH: %ld\n", c->arg);
#endif
- if (dev->global_flags & ISDN_GLOBAL_STOPPED)
- return 0;
- if (isdn_net_stat_callback(i, c->command))
- break;
- if ((mi = dev->m_idx[i]) >= 0) {
- info = &dev->mdm.info[mi];
- if (info->flags &
- (ISDN_ASYNC_NORMAL_ACTIVE | ISDN_ASYNC_CALLOUT_ACTIVE)) {
- if (info->dialing) {
- info->dialing = 0;
- isdn_tty_modem_result(6, info);
- }
- info->msr &= ~UART_MSR_DCD;
- if (info->online) {
- isdn_tty_modem_result(3, info);
- info->online = 0;
- }
+ if (dev->global_flags & ISDN_GLOBAL_STOPPED)
+ return 0;
+ if (isdn_net_stat_callback(i, c->command))
+ break;
+ if (isdn_tty_stat_callback(i, c))
+ break;
+ break;
+ case ISDN_STAT_ADDCH:
+ break;
+ case ISDN_STAT_UNLOAD:
+ save_flags(flags);
+ cli();
+ isdn_tty_stat_callback(i, c);
+ for (i = 0; i < ISDN_MAX_CHANNELS; i++)
+ if (dev->drvmap[i] == di) {
+ dev->drvmap[i] = -1;
+ dev->chanmap[i] = -1;
}
- }
- break;
- case ISDN_STAT_ADDCH:
- break;
- case ISDN_STAT_UNLOAD:
- save_flags(flags);
- cli();
- for (i = 0; i < ISDN_MAX_CHANNELS; i++)
- if (dev->drvmap[i] == di) {
- dev->drvmap[i] = -1;
- dev->chanmap[i] = -1;
- }
- for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
- modem_info *info = &dev->mdm.info[i];
-
- if (info->isdn_driver == di) {
- info->isdn_driver = -1;
- info->isdn_channel = -1;
- if (info->online) {
- isdn_tty_modem_result(3, info);
- isdn_tty_modem_hup(info);
- }
- }
- }
- dev->drivers--;
- dev->channels -= dev->drv[di]->channels;
- kfree(dev->drv[di]->rcverr);
- kfree(dev->drv[di]->rcvcount);
- for (i = 0; i < dev->drv[di]->channels; i++)
- isdn_free_queue(&dev->drv[di]->rpqueue[i]);
- kfree(dev->drv[di]->rpqueue);
- kfree(dev->drv[di]->rcv_waitq);
- kfree(dev->drv[di]->snd_waitq);
- kfree(dev->drv[di]);
- dev->drv[di] = NULL;
- dev->drvid[di][0] = '\0';
- isdn_info_update();
- restore_flags(flags);
- return 0;
- default:
- return -1;
+ dev->drivers--;
+ dev->channels -= dev->drv[di]->channels;
+ kfree(dev->drv[di]->rcverr);
+ kfree(dev->drv[di]->rcvcount);
+ for (i = 0; i < dev->drv[di]->channels; i++)
+ isdn_free_queue(&dev->drv[di]->rpqueue[i]);
+ kfree(dev->drv[di]->rpqueue);
+ kfree(dev->drv[di]->rcv_waitq);
+ kfree(dev->drv[di]->snd_waitq);
+ kfree(dev->drv[di]);
+ dev->drv[di] = NULL;
+ dev->drvid[di][0] = '\0';
+ isdn_info_update();
+ restore_flags(flags);
+ return 0;
+ default:
+ return -1;
}
return 0;
}
@@ -731,7 +645,8 @@
/*
* Get integer from char-pointer, set pointer to end of number
*/
-int isdn_getnum(char **p)
+int
+isdn_getnum(char **p)
{
int v = -1;
@@ -746,14 +661,15 @@
* isdn_readbchan() tries to get data from the read-queue.
* It MUST be called with interrupts off.
*/
-int isdn_readbchan(int di, int channel, u_char * buf, u_char * fp, int len, int user)
+int
+isdn_readbchan(int di, int channel, u_char * buf, u_char * fp, int len, int user)
{
int left;
int count;
int count_pull;
- int count_put;
+ int count_put;
int dflag;
- struct sk_buff *skb;
+ struct sk_buff *skb;
u_char *cp;
if (!dev->drv[di])
@@ -768,99 +684,106 @@
cp = buf;
count = 0;
while (left) {
- if (!(skb = skb_peek(&dev->drv[di]->rpqueue[channel])))
- break;
- if (skb->lock)
- break;
- skb->lock = 1;
- if (skb->users) {
- /* users is the count of DLE's in
- * this buff when in voice mode.
- */
- char *p = skb->data;
- unsigned long DLEmask = (1 << channel);
-
- dflag = 0;
- count_pull = count_put = 0;
- while ((count_pull < skb->len) && (left-- > 0)) {
- if (dev->drv[di]->DLEflag & DLEmask) {
- if (user)
- put_user(DLE,cp++);
- else
- *cp++ = DLE;
- dev->drv[di]->DLEflag &= ~DLEmask;
- } else {
- if (user)
- put_user(*p,cp++);
- else
- *cp++ = *p;
- if (*p == DLE) {
- dev->drv[di]->DLEflag |= DLEmask;
- skb->users--;
- }
- p++;
- count_pull++;
- }
- count_put++;
- }
- if (count_pull >= skb->len)
- dflag = 1;
- } else {
- /* No DLE's in buff, so simply copy it */
- dflag = 1;
- if ((count_pull = skb->len) > left) {
- count_pull = left;
- dflag = 0;
- }
- count_put = count_pull;
- if (user)
- copy_to_user(cp, skb->data, count_put);
- else
- memcpy(cp, skb->data, count_put);
- cp += count_put;
- left -= count_put;
- }
- count += count_put;
- if (fp) {
- memset(fp, 0, count_put);
- fp += count_put;
- }
- if (dflag) {
- /* We got all the data in this buff.
- * Now we can dequeue it.
- */
+ if (!(skb = skb_peek(&dev->drv[di]->rpqueue[channel])))
+ break;
+#ifdef CONFIG_ISDN_AUDIO
+ if (ISDN_AUDIO_SKB_LOCK(skb))
+ break;
+ ISDN_AUDIO_SKB_LOCK(skb) = 1;
+ if (ISDN_AUDIO_SKB_DLECOUNT(skb)) {
+ char *p = skb->data;
+ unsigned long DLEmask = (1 << channel);
+
+ dflag = 0;
+ count_pull = count_put = 0;
+ while ((count_pull < skb->len) && (left-- > 0)) {
+ if (dev->drv[di]->DLEflag & DLEmask) {
+ if (user)
+ put_user(DLE, cp++);
+ else
+ *cp++ = DLE;
+ dev->drv[di]->DLEflag &= ~DLEmask;
+ } else {
+ if (user)
+ put_user(*p, cp++);
+ else
+ *cp++ = *p;
+ if (*p == DLE) {
+ dev->drv[di]->DLEflag |= DLEmask;
+ (ISDN_AUDIO_SKB_DLECOUNT(skb))--;
+ }
+ p++;
+ count_pull++;
+ }
+ count_put++;
+ }
+ if (count_pull >= skb->len)
+ dflag = 1;
+ } else {
+#endif
+ /* No DLE's in buff, so simply copy it */
+ dflag = 1;
+ if ((count_pull = skb->len) > left) {
+ count_pull = left;
+ dflag = 0;
+ }
+ count_put = count_pull;
+ if (user)
+ copy_to_user(cp, skb->data, count_put);
+ else
+ memcpy(cp, skb->data, count_put);
+ cp += count_put;
+ left -= count_put;
+#ifdef CONFIG_ISDN_AUDIO
+ }
+#endif
+ count += count_put;
+ if (fp) {
+ memset(fp, 0, count_put);
+ fp += count_put;
+ }
+ if (dflag) {
+ /* We got all the data in this buff.
+ * Now we can dequeue it.
+ */
if (fp)
*(fp - 1) = 0xff;
- skb->lock = 0;
- skb = skb_dequeue(&dev->drv[di]->rpqueue[channel]);
- isdn_trash_skb(skb, FREE_READ);
+#ifdef CONFIG_ISDN_AUDIO
+ ISDN_AUDIO_SKB_LOCK(skb) = 0;
+#endif
+ skb = skb_dequeue(&dev->drv[di]->rpqueue[channel]);
+ isdn_trash_skb(skb, FREE_READ);
} else {
- /* Not yet emptied this buff, so it
- * must stay in the queue, for further calls
- * but we pull off the data we got until now.
- */
- skb_pull(skb,count_pull);
- skb->lock = 0;
- }
+ /* Not yet emptied this buff, so it
+ * must stay in the queue, for further calls
+ * but we pull off the data we got until now.
+ */
+ skb_pull(skb, count_pull);
+#ifdef CONFIG_ISDN_AUDIO
+ ISDN_AUDIO_SKB_LOCK(skb) = 0;
+#endif
+ }
dev->drv[di]->rcvcount[channel] -= count_put;
}
return count;
}
-static __inline int isdn_minor2drv(int minor)
+static __inline int
+isdn_minor2drv(int minor)
{
return (dev->drvmap[minor]);
}
-static __inline int isdn_minor2chan(int minor)
+static __inline int
+isdn_minor2chan(int minor)
{
return (dev->chanmap[minor]);
}
-#define INF_DV 0x01 /* Data version for /dev/isdninfo */
+#define INF_DV 0x01 /* Data version for /dev/isdninfo */
static char *
- isdn_statstr(void)
+isdn_statstr(void)
{
static char istatbuf[2048];
char *p;
@@ -913,7 +836,8 @@
/* Module interface-code */
-void isdn_info_update(void)
+void
+isdn_info_update(void)
{
infostruct *p = dev->infochain;
@@ -924,7 +848,8 @@
wake_up_interruptible(&(dev->info_waitq));
}
-static RWTYPE isdn_read(struct inode *inode, struct file *file, char *buf, RWARG count)
+static RWTYPE
+isdn_read(struct inode *inode, struct file *file, char *buf, RWARG count)
{
uint minor = MINOR(inode->i_rdev);
int len = 0;
@@ -935,14 +860,15 @@
if (minor == ISDN_MINOR_STATUS) {
char *p;
if (!file->private_data) {
- if (file->f_flags & O_NONBLOCK)
- return -EAGAIN;
+ if (file->f_flags & O_NONBLOCK)
+ return -EAGAIN;
interruptible_sleep_on(&(dev->info_waitq));
- }
+ }
p = isdn_statstr();
file->private_data = 0;
if ((len = strlen(p)) <= count) {
- copy_to_user(buf, p, len);
+ if (copy_to_user(buf, p, len))
+ return -EFAULT;
file->f_pos += len;
return len;
}
@@ -957,11 +883,11 @@
if (!dev->drv[drvidx]->running)
return -ENODEV;
chidx = isdn_minor2chan(minor);
- save_flags(flags);
- cli();
+ save_flags(flags);
+ cli();
len = isdn_readbchan(drvidx, chidx, buf, 0, count, 1);
file->f_pos += len;
- restore_flags(flags);
+ restore_flags(flags);
return len;
}
if (minor <= ISDN_MINOR_CTRLMAX) {
@@ -969,10 +895,10 @@
if (drvidx < 0)
return -ENODEV;
if (!dev->drv[drvidx]->stavail) {
- if (file->f_flags & O_NONBLOCK)
- return -EAGAIN;
+ if (file->f_flags & O_NONBLOCK)
+ return -EAGAIN;
interruptible_sleep_on(&(dev->drv[drvidx]->st_waitq));
- }
+ }
if (dev->drv[drvidx]->interface->readstat)
len = dev->drv[drvidx]->interface->
readstat(buf, MIN(count, dev->drv[drvidx]->stavail),
@@ -981,10 +907,10 @@
len = 0;
save_flags(flags);
cli();
- if (len)
- dev->drv[drvidx]->stavail -= len;
- else
- dev->drv[drvidx]->stavail = 0;
+ if (len)
+ dev->drv[drvidx]->stavail -= len;
+ else
+ dev->drv[drvidx]->stavail = 0;
restore_flags(flags);
file->f_pos += len;
return len;
@@ -996,12 +922,14 @@
return -ENODEV;
}
-static LSTYPE isdn_lseek(struct inode *inode, struct file *file, LSARG offset, int orig)
+static LSTYPE
+isdn_lseek(struct inode *inode, struct file *file, LSARG offset, int orig)
{
return -ESPIPE;
}
-static RWTYPE isdn_write(struct inode *inode, struct file *file, const char *buf, RWARG count)
+static RWTYPE
+isdn_write(struct inode *inode, struct file *file, const char *buf, RWARG count)
{
uint minor = MINOR(inode->i_rdev);
int drvidx;
@@ -1045,10 +973,12 @@
return -ENODEV;
}
-static int isdn_select(struct inode *inode, struct file *file, int type, select_table * st)
+#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);
+ int drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL);
if (minor == ISDN_MINOR_STATUS) {
if (file->private_data)
@@ -1063,49 +993,81 @@
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;
+ 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)
+{
+ unsigned int mask = 0;
+ unsigned int minor = MINOR(file->f_inode->i_rdev);
+ int drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL);
+
+ if (minor == ISDN_MINOR_STATUS) {
+ poll_wait(&(dev->info_waitq), wait);
+ /* mask = POLLOUT | POLLWRNORM; */
+ if (file->private_data) {
+ mask |= POLLIN | POLLRDNORM;
+ }
+ return mask;
+ }
+ if (minor >= ISDN_MINOR_CTRL && minor <= ISDN_MINOR_CTRLMAX) {
+ poll_wait(&(dev->drv[drvidx]->st_waitq), wait);
+ if (drvidx < 0) {
+ printk(KERN_ERR "isdn_common: isdn_poll 1 -> what the hell\n");
+ return POLLERR;
+ }
+ mask = POLLOUT | POLLWRNORM;
+ if (dev->drv[drvidx]->stavail) {
+ mask |= POLLIN | POLLRDNORM;
+ }
+ return mask;
+ }
+#ifdef CONFIG_ISDN_PPP
+ if (minor <= ISDN_MINOR_PPPMAX)
+ return (isdn_ppp_poll(file, wait));
+#endif
+ printk(KERN_ERR "isdn_common: isdn_poll 2 -> what the hell\n");
+ return POLLERR;
+}
+#endif
-static int isdn_set_allcfg(char *src)
+static int
+isdn_set_allcfg(char *src)
{
int ret;
int i;
ulong flags;
- char buf[1024];
isdn_net_ioctl_cfg cfg;
isdn_net_ioctl_phone phone;
if ((ret = isdn_net_rmall()))
return ret;
+ if ((ret = copy_from_user((char *) &i, src, sizeof(int))))
+ return ret;
save_flags(flags);
cli();
- if ((ret = verify_area(VERIFY_READ, (void *) src, sizeof(int)))) {
- restore_flags(flags);
- return ret;
- }
- copy_from_user((char *) &i, src, sizeof(int));
- src += sizeof(int);
+ src += sizeof(int);
while (i) {
- char *c;
- char *c2;
+ int phone_len;
+ int out_flag;
- if ((ret = verify_area(VERIFY_READ, (void *) src, sizeof(cfg)))) {
+ if ((ret = copy_from_user((char *) &cfg, src, sizeof(cfg)))) {
restore_flags(flags);
return ret;
}
- copy_from_user((char *) &cfg, src, sizeof(cfg));
src += sizeof(cfg);
if (!isdn_net_new(cfg.name, NULL)) {
restore_flags(flags);
@@ -1115,49 +1077,31 @@
restore_flags(flags);
return ret;
}
- if ((ret = verify_area(VERIFY_READ, (void *) src, sizeof(buf)))) {
- restore_flags(flags);
- return ret;
- }
- copy_from_user(buf, src, sizeof(buf));
- src += sizeof(buf);
- c = buf;
- while (*c) {
- if ((c2 = strchr(c, ' ')))
- *c2++ = '\0';
- strcpy(phone.phone, c);
- strcpy(phone.name, cfg.name);
- phone.outgoing = 0;
- if ((ret = isdn_net_addphone(&phone))) {
+ phone_len = out_flag = 0;
+ while (out_flag < 2) {
+ if ((ret = verify_area(VERIFY_READ, src, 1))) {
restore_flags(flags);
return ret;
}
- if (c2)
- c = c2;
- else
- c += strlen(c);
- }
- if ((ret = verify_area(VERIFY_READ, (void *) src, sizeof(buf)))) {
- restore_flags(flags);
- return ret;
- }
- copy_from_user(buf, src, sizeof(buf));
- src += sizeof(buf);
- c = buf;
- while (*c) {
- if ((c2 = strchr(c, ' ')))
- *c2++ = '\0';
- strcpy(phone.phone, c);
- strcpy(phone.name, cfg.name);
- phone.outgoing = 1;
- if ((ret = isdn_net_addphone(&phone))) {
- restore_flags(flags);
- return ret;
+ GET_USER(phone.phone[phone_len], src++);
+ if ((phone.phone[phone_len] == ' ') ||
+ (phone.phone[phone_len] == '\0')) {
+ if (phone_len) {
+ phone.phone[phone_len] = '\0';
+ strcpy(phone.name, cfg.name);
+ phone.outgoing = out_flag;
+ if ((ret = isdn_net_addphone(&phone))) {
+ restore_flags(flags);
+ return ret;
+ }
+ } else
+ out_flag++;
+ phone_len = 0;
}
- if (c2)
- c = c2;
- else
- c += strlen(c);
+ if (++phone_len >= sizeof(phone.phone))
+ printk(KERN_WARNING
+ "%s: IIOCSETSET phone number too long, ignored\n",
+ cfg.name);
}
i--;
}
@@ -1165,7 +1109,8 @@
return 0;
}
-static int isdn_get_allcfg(char *dest)
+static int
+isdn_get_allcfg(char *dest)
{
isdn_net_ioctl_cfg cfg;
isdn_net_ioctl_phone phone;
@@ -1178,7 +1123,7 @@
cli();
p = dev->netdev;
while (p) {
- if ((ret = verify_area(VERIFY_WRITE, (void *) dest, sizeof(cfg) + 10))) {
+ if ((ret = verify_area(VERIFY_WRITE, (void *) dest, sizeof(cfg) + 200))) {
restore_flags(flags);
return ret;
}
@@ -1196,11 +1141,18 @@
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 & 4) ? 1 : 0;
- cfg.ihup = (p->local.hupflags & 8) ? 1 : 0;
- copy_to_user(dest, p->local.name, 10);
+ 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)) {
+ restore_flags(flags);
+ return -EFAULT;
+ }
dest += 10;
- copy_to_user(dest, (char *) &cfg, sizeof(cfg));
+ if (copy_to_user(dest, (char *) &cfg, sizeof(cfg))) {
+ restore_flags(flags);
+ return -EFAULT;
+ }
dest += sizeof(cfg);
strcpy(phone.name, p->local.name);
phone.outgoing = 0;
@@ -1216,51 +1168,63 @@
return ret;
} else
dest += ret;
+ put_user(0, dest);
p = p->next;
}
restore_flags(flags);
return 0;
}
-static int isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg)
+static int
+isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg)
{
uint minor = MINOR(inode->i_rdev);
isdn_ctrl c;
int drvidx;
int chidx;
int ret;
+ int i;
+ char *p;
char *s;
- char name[10];
- char bname[21];
- isdn_ioctl_struct iocts;
- isdn_net_ioctl_phone phone;
- isdn_net_ioctl_cfg cfg;
+ union iocpar {
+ char name[10];
+ char bname[22];
+ isdn_ioctl_struct iocts;
+ isdn_net_ioctl_phone phone;
+ isdn_net_ioctl_cfg cfg;
+ } iocpar;
+
+#define name iocpar.name
+#define bname iocpar.bname
+#define iocts iocpar.iocts
+#define phone iocpar.phone
+#define cfg iocpar.cfg
if (minor == ISDN_MINOR_STATUS) {
- switch (cmd) {
- case IIOCGETDVR:
- return(TTY_DV +
- (NET_DV << 8) +
- (INF_DV << 16));
- case IIOCGETCPS:
- if (arg) {
- ulong *p = (ulong *)arg;
- int i;
- if ((ret = verify_area(VERIFY_WRITE, (void *) arg,
- sizeof(ulong)*ISDN_MAX_CHANNELS*2)))
- return ret;
- for (i = 0;i<ISDN_MAX_CHANNELS;i++) {
- put_user(dev->ibytes[i],p++);
- put_user(dev->obytes[i],p++);
- }
- return 0;
- } else
- return -EINVAL;
- break;
- default:
- return -EINVAL;
- }
- }
+ switch (cmd) {
+ case IIOCGETDVR:
+ return (TTY_DV +
+ (NET_DV << 8) +
+ (INF_DV << 16));
+ case IIOCGETCPS:
+ if (arg) {
+ ulong *p = (ulong *) arg;
+ int i;
+ if ((ret = verify_area(VERIFY_WRITE, (void *) arg,
+ sizeof(ulong) * ISDN_MAX_CHANNELS * 2)))
+ return ret;
+ for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
+ put_user(dev->ibytes[i], p++);
+ put_user(dev->obytes[i], p++);
+ }
+ return 0;
+ } else
+ return -EINVAL;
+ break;
+ default:
+ return -EINVAL;
+ }
+ }
if (!dev->drivers)
return -ENODEV;
if (minor < ISDN_MINOR_CTRL) {
@@ -1275,336 +1239,329 @@
if (minor <= ISDN_MINOR_CTRLMAX) {
switch (cmd) {
#ifdef CONFIG_NETDEVICES
- case IIOCNETAIF:
- /* Add a network-interface */
- if (arg) {
- if ((ret = verify_area(VERIFY_READ, (void *) arg, sizeof(name))))
- return ret;
- copy_from_user(name, (char *) arg, sizeof(name));
- s = name;
- } else
- s = NULL;
- if ((s = isdn_net_new(s, NULL))) {
- if ((ret = verify_area(VERIFY_WRITE, (void *) arg, strlen(s) + 1)))
- return ret;
- copy_to_user((char *) arg, s, strlen(s) + 1);
- return 0;
- } else
- return -ENODEV;
- case IIOCNETASL:
- /* Add a slave to a network-interface */
- if (arg) {
- if ((ret = verify_area(VERIFY_READ, (void *) arg, sizeof(bname))))
- return ret;
- copy_from_user(bname, (char *) arg, sizeof(bname));
- } else
- return -EINVAL;
- if ((s = isdn_net_newslave(bname))) {
- if ((ret = verify_area(VERIFY_WRITE, (void *) arg, strlen(s) + 1)))
- return ret;
- copy_to_user((char *) arg, s, strlen(s) + 1);
- return 0;
- } else
- return -ENODEV;
- case IIOCNETDIF:
- /* Delete a network-interface */
- if (arg) {
- if ((ret = verify_area(VERIFY_READ, (void *) arg, sizeof(name))))
- return ret;
- copy_from_user(name, (char *) arg, sizeof(name));
- return isdn_net_rm(name);
- } else
- return -EINVAL;
- case IIOCNETSCF:
- /* Set configurable parameters of a network-interface */
- if (arg) {
- if ((ret = verify_area(VERIFY_READ, (void *) arg, sizeof(cfg))))
- return ret;
- copy_from_user((char *) &cfg, (char *) arg, sizeof(cfg));
- return isdn_net_setcfg(&cfg);
- } else
- return -EINVAL;
- case IIOCNETGCF:
- /* Get configurable parameters of a network-interface */
- if (arg) {
- if ((ret = verify_area(VERIFY_READ, (void *) arg, sizeof(cfg))))
- return ret;
- copy_from_user((char *) &cfg, (char *) arg, sizeof(cfg));
- if (!(ret = isdn_net_getcfg(&cfg))) {
- if ((ret = verify_area(VERIFY_WRITE, (void *) arg, sizeof(cfg))))
- return ret;
- copy_to_user((char *) arg, (char *) &cfg, sizeof(cfg));
- }
- return ret;
- } else
- return -EINVAL;
- case IIOCNETANM:
- /* Add a phone-number to a network-interface */
- if (arg) {
- if ((ret = verify_area(VERIFY_READ, (void *) arg, sizeof(phone))))
- return ret;
- copy_from_user((char *) &phone, (char *) arg, sizeof(phone));
- return isdn_net_addphone(&phone);
- } else
- return -EINVAL;
- case IIOCNETGNM:
- /* Get list of phone-numbers of a network-interface */
- if (arg) {
- if ((ret = verify_area(VERIFY_READ, (void *) arg, sizeof(phone))))
- return ret;
- copy_from_user((char *) &phone, (char *) arg, sizeof(phone));
- return isdn_net_getphones(&phone, (char *) arg);
- } else
- return -EINVAL;
- case IIOCNETDNM:
- /* Delete a phone-number of a network-interface */
- if (arg) {
- if ((ret = verify_area(VERIFY_READ, (void *) arg, sizeof(phone))))
- return ret;
- copy_from_user((char *) &phone, (char *) arg, sizeof(phone));
- return isdn_net_delphone(&phone);
- } else
- return -EINVAL;
- case IIOCNETDIL:
- /* Force dialing of a network-interface */
- if (arg) {
- if ((ret = verify_area(VERIFY_READ, (void *) arg, sizeof(name))))
- return ret;
- copy_from_user(name, (char *) arg, sizeof(name));
- return isdn_net_force_dial(name);
- } else
- return -EINVAL;
+ case IIOCNETAIF:
+ /* Add a network-interface */
+ if (arg) {
+ if ((ret = copy_from_user(name, (char *) arg, sizeof(name))))
+ return ret;
+ s = name;
+ } else
+ s = NULL;
+ if ((s = isdn_net_new(s, NULL))) {
+ if ((ret = copy_to_user((char *) arg, s, strlen(s) + 1)))
+ return ret;
+ return 0;
+ } else
+ return -ENODEV;
+ case IIOCNETASL:
+ /* Add a slave to a network-interface */
+ if (arg) {
+ if ((ret = copy_from_user(bname, (char *) arg, sizeof(bname) - 1)))
+ return ret;
+ } else
+ return -EINVAL;
+ if ((s = isdn_net_newslave(bname))) {
+ if ((ret = copy_to_user((char *) arg, s, strlen(s) + 1)))
+ return ret;
+ return 0;
+ } else
+ return -ENODEV;
+ case IIOCNETDIF:
+ /* Delete a network-interface */
+ if (arg) {
+ if ((ret = copy_from_user(name, (char *) arg, sizeof(name))))
+ return ret;
+ return isdn_net_rm(name);
+ } else
+ return -EINVAL;
+ case IIOCNETSCF:
+ /* Set configurable parameters of a network-interface */
+ if (arg) {
+ if ((ret = copy_from_user((char *) &cfg, (char *) arg, sizeof(cfg))))
+ return ret;
+ return isdn_net_setcfg(&cfg);
+ } else
+ return -EINVAL;
+ case IIOCNETGCF:
+ /* Get configurable parameters of a network-interface */
+ if (arg) {
+ if ((ret = copy_from_user((char *) &cfg, (char *) arg, sizeof(cfg))))
+ return ret;
+ if (!(ret = isdn_net_getcfg(&cfg))) {
+ if ((ret = copy_to_user((char *) arg, (char *) &cfg, sizeof(cfg))))
+ return ret;
+ }
+ return ret;
+ } else
+ return -EINVAL;
+ case IIOCNETANM:
+ /* Add a phone-number to a network-interface */
+ if (arg) {
+ if ((ret = copy_from_user((char *) &phone, (char *) arg, sizeof(phone))))
+ return ret;
+ return isdn_net_addphone(&phone);
+ } else
+ return -EINVAL;
+ case IIOCNETGNM:
+ /* Get list of phone-numbers of a network-interface */
+ if (arg) {
+ if ((ret = copy_from_user((char *) &phone, (char *) arg, sizeof(phone))))
+ return ret;
+ return isdn_net_getphones(&phone, (char *) arg);
+ } else
+ return -EINVAL;
+ case IIOCNETDNM:
+ /* Delete a phone-number of a network-interface */
+ if (arg) {
+ if ((ret = copy_from_user((char *) &phone, (char *) arg, sizeof(phone))))
+ return ret;
+ return isdn_net_delphone(&phone);
+ } else
+ return -EINVAL;
+ case IIOCNETDIL:
+ /* Force dialing of a network-interface */
+ if (arg) {
+ if ((ret = copy_from_user(name, (char *) arg, sizeof(name))))
+ return ret;
+ return isdn_net_force_dial(name);
+ } else
+ return -EINVAL;
#ifdef CONFIG_ISDN_PPP
- case IIOCNETALN:
- if(arg) {
- if ((ret = verify_area(VERIFY_READ,
- (void*)arg,
- sizeof(name))))
- return ret;
- } else
- return -EINVAL;
- copy_from_user(name,(char*)arg,sizeof(name));
- return isdn_ppp_dial_slave(name);
- case IIOCNETDLN:
- if(arg) {
- if ((ret = verify_area(VERIFY_READ,
- (void*)arg,
- sizeof(name))))
- return ret;
- } else
- return -EINVAL;
- copy_from_user(name,(char*)arg,sizeof(name));
- return isdn_ppp_hangup_slave(name);
-#endif
- case IIOCNETHUP:
- /* Force hangup of a network-interface */
- if (arg) {
- if ((ret = verify_area(VERIFY_READ, (void *) arg, sizeof(name))))
- return ret;
- copy_from_user(name, (char *) arg, sizeof(name));
- return isdn_net_force_hangup(name);
- } else
- return -EINVAL;
- break;
-#endif /* CONFIG_NETDEVICES */
- case IIOCSETVER:
- dev->net_verbose = arg;
- printk(KERN_INFO "isdn: Verbose-Level is %d\n", dev->net_verbose);
- return 0;
- case IIOCSETGST:
- if (arg)
- dev->global_flags |= ISDN_GLOBAL_STOPPED;
- else
- dev->global_flags &= ~ISDN_GLOBAL_STOPPED;
- printk(KERN_INFO "isdn: Global Mode %s\n",
- (dev->global_flags & ISDN_GLOBAL_STOPPED) ? "stopped" : "running");
- return 0;
- case IIOCSETBRJ:
- drvidx = -1;
- if (arg) {
- int i;
- char *p;
- if ((ret = verify_area(VERIFY_READ, (void *) arg,
- sizeof(isdn_ioctl_struct))))
- return ret;
- copy_from_user((char *) &iocts, (char *) arg,
- sizeof(isdn_ioctl_struct));
- if (strlen(iocts.drvid)) {
- if ((p = strchr(iocts.drvid, ',')))
- *p = 0;
- drvidx = -1;
- for (i = 0; i < ISDN_MAX_DRIVERS; i++)
- if (!(strcmp(dev->drvid[i], iocts.drvid))) {
- drvidx = i;
- break;
- }
- }
- }
- if (drvidx == -1)
- return -ENODEV;
- dev->drv[drvidx]->reject_bus = iocts.arg;
- return 0;
- case IIOCGETSET:
- /* Get complete setup (all network-interfaces and profile-
- settings of all tty-devices */
- if (arg)
- return (isdn_get_allcfg((char *) arg));
- else
- return -EINVAL;
- break;
- case IIOCSETSET:
- /* Set complete setup (all network-interfaces and profile-
- settings of all tty-devices */
- if (arg)
- return (isdn_set_allcfg((char *) arg));
- else
- return -EINVAL;
- break;
- case IIOCSIGPRF:
- dev->profd = current;
- return 0;
- break;
- case IIOCGETPRF:
- /* Get all Modem-Profiles */
- if (arg) {
- char *p = (char *) arg;
- int i;
-
- if ((ret = verify_area(VERIFY_WRITE, (void *) arg,
- (ISDN_MODEM_ANZREG + ISDN_MSNLEN)
- * ISDN_MAX_CHANNELS)))
- return ret;
-
- for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
- copy_to_user(p, dev->mdm.info[i].emu.profile,
- ISDN_MODEM_ANZREG);
- p += ISDN_MODEM_ANZREG;
- copy_to_user(p, dev->mdm.info[i].emu.pmsn, ISDN_MSNLEN);
- p += ISDN_MSNLEN;
- }
- return (ISDN_MODEM_ANZREG + ISDN_MSNLEN) * ISDN_MAX_CHANNELS;
- } else
- return -EINVAL;
- break;
- case IIOCSETPRF:
- /* Set all Modem-Profiles */
- if (arg) {
- char *p = (char *) arg;
- int i;
-
- if ((ret = verify_area(VERIFY_READ, (void *) arg,
- (ISDN_MODEM_ANZREG + ISDN_MSNLEN)
- * ISDN_MAX_CHANNELS)))
- return ret;
-
- for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
- copy_from_user(dev->mdm.info[i].emu.profile, p,
- ISDN_MODEM_ANZREG);
- p += ISDN_MODEM_ANZREG;
- copy_from_user(dev->mdm.info[i].emu.pmsn, p, ISDN_MSNLEN);
- p += ISDN_MSNLEN;
- }
- return 0;
- } else
- return -EINVAL;
- break;
- case IIOCSETMAP:
- case IIOCGETMAP:
- /* Set/Get MSN->EAZ-Mapping for a driver */
- if (arg) {
- int i;
- char *p;
- char nstring[255];
-
- if ((ret = verify_area(VERIFY_READ, (void *) arg,
- sizeof(isdn_ioctl_struct))))
- return ret;
- copy_from_user((char *) &iocts, (char *) arg, sizeof(isdn_ioctl_struct));
- if (strlen(iocts.drvid)) {
- drvidx = -1;
- for (i = 0; i < ISDN_MAX_DRIVERS; i++)
- if (!(strcmp(dev->drvid[i], iocts.drvid))) {
- drvidx = i;
- break;
- }
- } else
- drvidx = 0;
- if (drvidx == -1)
- return -ENODEV;
- if (cmd == IIOCSETMAP) {
- if ((ret = verify_area(VERIFY_READ, (void *) iocts.arg, 255)))
- return ret;
- copy_from_user(nstring, (char *) iocts.arg, 255);
- memset(dev->drv[drvidx]->msn2eaz, 0,
- sizeof(dev->drv[drvidx]->msn2eaz));
- p = strtok(nstring, ",");
- i = 0;
- while ((p) && (i < 10)) {
- strcpy(dev->drv[drvidx]->msn2eaz[i++], p);
- p = strtok(NULL, ",");
- }
- } else {
- p = nstring;
- for (i = 0; i < 10; i++)
- p += sprintf(p, "%s%s",
- strlen(dev->drv[drvidx]->msn2eaz[i]) ?
- dev->drv[drvidx]->msn2eaz[i] : "-",
- (i < 9) ? "," : "\0");
- if ((ret = verify_area(VERIFY_WRITE, (void *) iocts.arg,
- strlen(nstring) + 1)))
- return ret;
- copy_to_user((char *) iocts.arg, nstring, strlen(nstring) + 1);
- }
- return 0;
- } else
- return -EINVAL;
- case IIOCDBGVAR:
- if (arg) {
- if ((ret = verify_area(VERIFY_WRITE, (void *) arg, sizeof(ulong))))
- return ret;
- copy_to_user((char *) arg, (char *) &dev, sizeof(ulong));
- return 0;
- } else
- return -EINVAL;
- break;
- default:
- if ((cmd&IIOCDRVCTL)==IIOCDRVCTL)
- cmd = ((cmd>>_IOC_NRSHIFT)&_IOC_NRMASK)& ISDN_DRVIOCTL_MASK;
+ case IIOCNETALN:
+ if (!arg)
+ return -EINVAL;
+ if ((ret = copy_from_user(name, (char *) arg, sizeof(name))))
+ return ret;
+ return isdn_ppp_dial_slave(name);
+ case IIOCNETDLN:
+ if (!arg)
+ return -EINVAL;
+ if ((ret = copy_from_user(name, (char *) arg, sizeof(name))))
+ return ret;
+ return isdn_ppp_hangup_slave(name);
+#endif
+ case IIOCNETHUP:
+ /* 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);
+ break;
+#endif /* CONFIG_NETDEVICES */
+ case IIOCSETVER:
+ dev->net_verbose = arg;
+ printk(KERN_INFO "isdn: Verbose-Level is %d\n", dev->net_verbose);
+ return 0;
+ case IIOCSETGST:
+ if (arg)
+ dev->global_flags |= ISDN_GLOBAL_STOPPED;
+ else
+ dev->global_flags &= ~ISDN_GLOBAL_STOPPED;
+ printk(KERN_INFO "isdn: Global Mode %s\n",
+ (dev->global_flags & ISDN_GLOBAL_STOPPED) ? "stopped" : "running");
+ return 0;
+ case IIOCSETBRJ:
+ drvidx = -1;
+ if (arg) {
+ int i;
+ char *p;
+ if ((ret = copy_from_user((char *) &iocts, (char *) arg,
+ sizeof(isdn_ioctl_struct))))
+ return ret;
+ if (strlen(iocts.drvid)) {
+ if ((p = strchr(iocts.drvid, ',')))
+ *p = 0;
+ drvidx = -1;
+ for (i = 0; i < ISDN_MAX_DRIVERS; i++)
+ if (!(strcmp(dev->drvid[i], iocts.drvid))) {
+ drvidx = i;
+ break;
+ }
+ }
+ }
+ if (drvidx == -1)
+ return -ENODEV;
+ dev->drv[drvidx]->reject_bus = iocts.arg;
+ return 0;
+ case IIOCGETSET:
+ /* Get complete setup (all network-interfaces and profile-
+ settings of all tty-devices */
+ if (arg)
+ return (isdn_get_allcfg((char *) arg));
else
return -EINVAL;
- if (arg) {
- int i;
- char *p;
- if ((ret = verify_area(VERIFY_READ, (void *) arg,
- sizeof(isdn_ioctl_struct))))
- return ret;
- copy_from_user((char *) &iocts, (char *) arg, sizeof(isdn_ioctl_struct));
- if (strlen(iocts.drvid)) {
- if ((p = strchr(iocts.drvid, ',')))
- *p = 0;
- drvidx = -1;
- for (i = 0; i < ISDN_MAX_DRIVERS; i++)
- if (!(strcmp(dev->drvid[i], iocts.drvid))) {
- drvidx = i;
- break;
- }
- } else
- drvidx = 0;
- if (drvidx == -1)
- return -ENODEV;
- if ((ret = verify_area(VERIFY_WRITE, (void *) arg,
- sizeof(isdn_ioctl_struct))))
- return ret;
- c.driver = drvidx;
- c.command = ISDN_CMD_IOCTL;
- c.arg = cmd;
- memcpy(c.num, (char *) &iocts.arg, sizeof(ulong));
- ret = dev->drv[drvidx]->interface->command(&c);
- memcpy((char *) &iocts.arg, c.num, sizeof(ulong));
- copy_to_user((char *) arg, &iocts, sizeof(isdn_ioctl_struct));
- return ret;
- } else
- return -EINVAL;
+ break;
+ case IIOCSETSET:
+ /* Set complete setup (all network-interfaces and profile-
+ settings of all tty-devices */
+ if (arg)
+ return (isdn_set_allcfg((char *) arg));
+ else
+ return -EINVAL;
+ break;
+ case IIOCSIGPRF:
+ dev->profd = current;
+ return 0;
+ break;
+ case IIOCGETPRF:
+ /* Get all Modem-Profiles */
+ if (arg) {
+ char *p = (char *) arg;
+ int i;
+
+ if ((ret = verify_area(VERIFY_WRITE, (void *) arg,
+ (ISDN_MODEM_ANZREG + ISDN_MSNLEN)
+ * ISDN_MAX_CHANNELS)))
+ return ret;
+
+ for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
+ if (copy_to_user(p, dev->mdm.info[i].emu.profile,
+ ISDN_MODEM_ANZREG))
+ return -EFAULT;
+ p += ISDN_MODEM_ANZREG;
+ if (copy_to_user(p, dev->mdm.info[i].emu.pmsn, ISDN_MSNLEN))
+ return -EFAULT;
+ p += ISDN_MSNLEN;
+ }
+ return (ISDN_MODEM_ANZREG + ISDN_MSNLEN) * ISDN_MAX_CHANNELS;
+ } else
+ return -EINVAL;
+ break;
+ case IIOCSETPRF:
+ /* Set all Modem-Profiles */
+ if (arg) {
+ char *p = (char *) arg;
+ int i;
+
+ if ((ret = verify_area(VERIFY_READ, (void *) arg,
+ (ISDN_MODEM_ANZREG + ISDN_MSNLEN)
+ * ISDN_MAX_CHANNELS)))
+ return ret;
+
+ for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
+ if ((ret = copy_from_user(dev->mdm.info[i].emu.profile, p,
+ ISDN_MODEM_ANZREG)))
+ return ret;
+ p += ISDN_MODEM_ANZREG;
+ if ((ret = copy_from_user(dev->mdm.info[i].emu.pmsn, p, ISDN_MSNLEN)))
+ return ret;
+ p += ISDN_MSNLEN;
+ }
+ return 0;
+ } else
+ return -EINVAL;
+ break;
+ case IIOCSETMAP:
+ case IIOCGETMAP:
+ /* Set/Get MSN->EAZ-Mapping for a driver */
+ if (arg) {
+
+ if ((ret = copy_from_user((char *) &iocts,
+ (char *) arg,
+ sizeof(isdn_ioctl_struct))))
+ return ret;
+ if (strlen(iocts.drvid)) {
+ drvidx = -1;
+ for (i = 0; i < ISDN_MAX_DRIVERS; i++)
+ if (!(strcmp(dev->drvid[i], iocts.drvid))) {
+ drvidx = i;
+ break;
+ }
+ } else
+ drvidx = 0;
+ if (drvidx == -1)
+ return -ENODEV;
+ if (cmd == IIOCSETMAP) {
+ int loop = 1;
+
+ p = (char *) iocts.arg;
+ i = 0;
+ while (loop) {
+ int j = 0;
+
+ while (1) {
+ if ((ret = verify_area(VERIFY_READ, p, 1)))
+ return ret;
+ GET_USER(bname[j], p++);
+ switch (bname[j]) {
+ case '\0':
+ loop = 0;
+ /* Fall through */
+ case ',':
+ bname[j] = '\0';
+ strcpy(dev->drv[drvidx]->msn2eaz[i], bname);
+ j = ISDN_MSNLEN;
+ break;
+ default:
+ j++;
+ }
+ if (j >= ISDN_MSNLEN)
+ break;
+ }
+ if (++i > 9)
+ break;
+ }
+ } else {
+ p = (char *) iocts.arg;
+ for (i = 0; i < 10; i++) {
+ sprintf(bname, "%s%s",
+ strlen(dev->drv[drvidx]->msn2eaz[i]) ?
+ dev->drv[drvidx]->msn2eaz[i] : "-",
+ (i < 9) ? "," : "\0");
+ if ((ret = copy_to_user(p, bname, strlen(bname) + 1)))
+ return ret;
+ p += strlen(bname);
+ }
+ }
+ return 0;
+ } else
+ return -EINVAL;
+ case IIOCDBGVAR:
+ if (arg) {
+ if ((ret = copy_to_user((char *) arg, (char *) &dev, sizeof(ulong))))
+ return ret;
+ return 0;
+ } else
+ return -EINVAL;
+ break;
+ default:
+ if ((cmd & IIOCDRVCTL) == IIOCDRVCTL)
+ cmd = ((cmd >> _IOC_NRSHIFT) & _IOC_NRMASK) & ISDN_DRVIOCTL_MASK;
+ else
+ return -EINVAL;
+ if (arg) {
+ int i;
+ char *p;
+ if ((ret = copy_from_user((char *) &iocts, (char *) arg, sizeof(isdn_ioctl_struct))))
+ return ret;
+ if (strlen(iocts.drvid)) {
+ if ((p = strchr(iocts.drvid, ',')))
+ *p = 0;
+ drvidx = -1;
+ for (i = 0; i < ISDN_MAX_DRIVERS; i++)
+ if (!(strcmp(dev->drvid[i], iocts.drvid))) {
+ drvidx = i;
+ break;
+ }
+ } else
+ drvidx = 0;
+ if (drvidx == -1)
+ return -ENODEV;
+ if ((ret = verify_area(VERIFY_WRITE, (void *) arg,
+ sizeof(isdn_ioctl_struct))))
+ return ret;
+ c.driver = drvidx;
+ c.command = ISDN_CMD_IOCTL;
+ c.arg = cmd;
+ memcpy(c.parm.num, (char *) &iocts.arg, sizeof(ulong));
+ ret = dev->drv[drvidx]->interface->command(&c);
+ memcpy((char *) &iocts.arg, c.parm.num, sizeof(ulong));
+ if ((copy_to_user((char *) arg, &iocts, sizeof(isdn_ioctl_struct))))
+ return -EFAULT;
+ return ret;
+ } else
+ return -EINVAL;
}
}
#ifdef CONFIG_ISDN_PPP
@@ -1612,6 +1569,12 @@
return (isdn_ppp_ioctl(minor - ISDN_MINOR_PPP, file, cmd, arg));
#endif
return -ENODEV;
+
+#undef name
+#undef bname
+#undef iocts
+#undef phone
+#undef cfg
}
/*
@@ -1619,7 +1582,8 @@
* MOD_INC_USE_COUNT make sure that the driver memory is not freed
* while the device is in use.
*/
-static int isdn_open(struct inode *ino, struct file *filep)
+static int
+isdn_open(struct inode *ino, struct file *filep)
{
uint minor = MINOR(ino->i_rdev);
int drvidx;
@@ -1671,20 +1635,21 @@
if (minor <= ISDN_MINOR_PPPMAX) {
int ret;
if (!(ret = isdn_ppp_open(minor - ISDN_MINOR_PPP, filep)))
- MOD_INC_USE_COUNT;
+ MOD_INC_USE_COUNT;
return ret;
}
#endif
return -ENODEV;
}
-static void isdn_close(struct inode *ino, struct file *filep)
+static CLOSETYPE
+isdn_close(struct inode *ino, struct file *filep)
{
uint minor = MINOR(ino->i_rdev);
int drvidx;
isdn_ctrl c;
- MOD_DEC_USE_COUNT;
+ MOD_DEC_USE_COUNT;
if (minor == ISDN_MINOR_STATUS) {
infostruct *p = dev->infochain;
infostruct *q = NULL;
@@ -1694,38 +1659,40 @@
q->next = p->next;
else
dev->infochain = (infostruct *) (p->next);
- return;
+ kfree(p);
+ return CLOSEVAL;
}
q = p;
p = (infostruct *) (p->next);
}
printk(KERN_WARNING "isdn: No private data while closing isdnctrl\n");
- return;
+ return CLOSEVAL;
}
if (minor < ISDN_MINOR_CTRL) {
drvidx = isdn_minor2drv(minor);
if (drvidx < 0)
- return;
+ return CLOSEVAL;
c.command = ISDN_CMD_UNLOCK;
c.driver = drvidx;
(void) dev->drv[drvidx]->interface->command(&c);
- return;
+ return CLOSEVAL;
}
if (minor <= ISDN_MINOR_CTRLMAX) {
drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL);
if (drvidx < 0)
- return;
+ return CLOSEVAL;
if (dev->profd == current)
dev->profd = NULL;
c.command = ISDN_CMD_UNLOCK;
c.driver = drvidx;
(void) dev->drv[drvidx]->interface->command(&c);
- return;
+ return CLOSEVAL;
}
#ifdef CONFIG_ISDN_PPP
if (minor <= ISDN_MINOR_PPPMAX)
isdn_ppp_release(minor - ISDN_MINOR_PPP, filep);
#endif
+ return CLOSEVAL;
}
static struct file_operations isdn_fops =
@@ -1733,17 +1700,21 @@
isdn_lseek,
isdn_read,
isdn_write,
- NULL, /* isdn_readdir */
- isdn_select, /* isdn_select */
- isdn_ioctl, /* isdn_ioctl */
- NULL, /* isdn_mmap */
+ 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,
isdn_close,
- NULL /* fsync */
+ NULL /* fsync */
};
char *
- isdn_map_eaz2msn(char *msn, int di)
+isdn_map_eaz2msn(char *msn, int di)
{
driver *this = dev->drv[di];
int i;
@@ -1761,13 +1732,14 @@
* Find an unused ISDN-channel, whose feature-flags match the
* given L2- and L3-protocols.
*/
-int isdn_get_free_channel(int usage, int l2_proto, int l3_proto, int pre_dev
- ,int pre_chan)
+int
+isdn_get_free_channel(int usage, int l2_proto, int l3_proto, int pre_dev
+ ,int pre_chan)
{
int i;
ulong flags;
ulong features;
- isdn_ctrl cmd;
+ isdn_ctrl cmd;
save_flags(flags);
cli();
@@ -1785,10 +1757,10 @@
dev->usage[i] &= ISDN_USAGE_EXCLUSIVE;
dev->usage[i] |= usage;
isdn_info_update();
- cmd.driver = d;
- cmd.arg = 0;
- cmd.command = ISDN_CMD_LOCK;
- (void) dev->drv[d]->interface->command(&cmd);
+ cmd.driver = d;
+ cmd.arg = 0;
+ cmd.command = ISDN_CMD_LOCK;
+ (void) dev->drv[d]->interface->command(&cmd);
restore_flags(flags);
return i;
} else {
@@ -1796,10 +1768,10 @@
dev->usage[i] &= ISDN_USAGE_EXCLUSIVE;
dev->usage[i] |= usage;
isdn_info_update();
- cmd.driver = d;
- cmd.arg = 0;
- cmd.command = ISDN_CMD_LOCK;
- (void) dev->drv[d]->interface->command(&cmd);
+ cmd.driver = d;
+ cmd.arg = 0;
+ cmd.command = ISDN_CMD_LOCK;
+ (void) dev->drv[d]->interface->command(&cmd);
restore_flags(flags);
return i;
}
@@ -1814,7 +1786,8 @@
/*
* Set state of ISDN-channel to 'unused'
*/
-void isdn_free_channel(int di, int ch, int usage)
+void
+isdn_free_channel(int di, int ch, int usage)
{
int i;
ulong flags;
@@ -1828,15 +1801,15 @@
(dev->chanmap[i] == ch)) {
dev->usage[i] &= (ISDN_USAGE_NONE | ISDN_USAGE_EXCLUSIVE);
strcpy(dev->num[i], "???");
- dev->ibytes[i] = 0;
- dev->obytes[i] = 0;
+ dev->ibytes[i] = 0;
+ dev->obytes[i] = 0;
isdn_info_update();
- isdn_free_queue(&dev->drv[di]->rpqueue[ch]);
- cmd.driver = di;
- cmd.arg = ch;
- cmd.command = ISDN_CMD_UNLOCK;
- restore_flags(flags);
- (void) dev->drv[di]->interface->command(&cmd);
+ isdn_free_queue(&dev->drv[di]->rpqueue[ch]);
+ cmd.driver = di;
+ cmd.arg = ch;
+ cmd.command = ISDN_CMD_UNLOCK;
+ restore_flags(flags);
+ (void) dev->drv[di]->interface->command(&cmd);
return;
}
restore_flags(flags);
@@ -1845,7 +1818,8 @@
/*
* Cancel Exclusive-Flag for ISDN-channel
*/
-void isdn_unexclusive_channel(int di, int ch)
+void
+isdn_unexclusive_channel(int di, int ch)
{
int i;
ulong flags;
@@ -1873,55 +1847,57 @@
* len = Length of packet-data
*
*/
-void isdn_receive_callback(int drvidx, int chan, u_char *buf, int len)
+static void
+isdn_receive_callback(int drvidx, int chan, u_char * buf, int len)
{
- struct sk_buff *skb;
+ 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");
+ 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
*/
-int isdn_writebuf_stub(int drvidx, int chan, const u_char *buf, int len,
- int user)
+static int
+isdn_writebuf_stub(int drvidx, int chan, const u_char * buf, int len,
+ int user)
{
int ret;
- 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);
- skb->free = 1;
-
- 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, FREE_WRITE);
- }
- if (ret > 0)
- dev->obytes[isdn_dc2minor(drvidx,chan)] += ret;
- return ret;
+ 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);
+
+ ret = dev->drv[drvidx]->interface->writebuf_skb(drvidx,
+ chan, skb);
+ if (ret <= 0)
+ kfree_skb(skb, FREE_WRITE);
+ }
+ if (ret > 0)
+ dev->obytes[isdn_dc2minor(drvidx, chan)] += ret;
+ return ret;
}
/*
@@ -1932,32 +1908,36 @@
* Return: length of data on success, -ERRcode on failure.
*/
-int isdn_writebuf_skb_stub(int drvidx, int chan, struct sk_buff * skb)
+int
+isdn_writebuf_skb_stub(int drvidx, int chan, struct sk_buff *skb)
{
- int ret;
- int len = skb->len; /* skb pointer no longer valid after free */
+ int ret;
+ int len = skb->len; /* skb pointer no longer valid after free */
- if (dev->drv[drvidx]->interface->writebuf_skb)
+ if (dev->drv[drvidx]->interface->writebuf_skb)
ret = dev->drv[drvidx]->interface->
- writebuf_skb(drvidx, chan, skb);
+ writebuf_skb(drvidx, chan, skb);
else {
if ((ret = dev->drv[drvidx]->interface->
- writebuf(drvidx,chan,skb->data,skb->len,0)) == len)
- dev_kfree_skb(skb, FREE_WRITE);
- }
- if (ret > 0)
- dev->obytes[isdn_dc2minor(drvidx,chan)] += len;
- return ret;
+ writebuf(drvidx, chan, skb->data, skb->len, 0)) == len)
+ dev_kfree_skb(skb, FREE_WRITE);
+ }
+ if (ret > 0)
+ dev->obytes[isdn_dc2minor(drvidx, chan)] += len;
+ return ret;
}
/*
* Low-level-driver registration
*/
-int register_isdn(isdn_if * i)
+int
+register_isdn(isdn_if * i)
{
driver *d;
- int n, j, k;
+ int n,
+ j,
+ k;
ulong flags;
int drvidx;
@@ -1973,9 +1953,9 @@
return 0;
}
if ((!i->writebuf_skb) && (!i->writebuf)) {
- printk(KERN_WARNING "register_isdn: No write routine given.\n");
- return 0;
- }
+ printk(KERN_WARNING "register_isdn: No write routine given.\n");
+ return 0;
+ }
if (!(d = (driver *) kmalloc(sizeof(driver), GFP_KERNEL))) {
printk(KERN_WARNING "register_isdn: Could not alloc driver-struct\n");
return 0;
@@ -1994,17 +1974,17 @@
return 0;
}
memset((char *) d->rcvcount, 0, sizeof(int) * n);
- if (!(d->rpqueue =
- (struct sk_buff_head *) kmalloc(sizeof(struct sk_buff_head) * n, GFP_KERNEL))) {
- printk(KERN_WARNING "register_isdn: Could not alloc rpqueue\n");
- kfree(d->rcvcount);
- kfree(d->rcverr);
- kfree(d);
- return 0;
- }
- for (j = 0; j < n; j++) {
- skb_queue_head_init(&d->rpqueue[j]);
- }
+ if (!(d->rpqueue =
+ (struct sk_buff_head *) kmalloc(sizeof(struct sk_buff_head) * n, GFP_KERNEL))) {
+ printk(KERN_WARNING "register_isdn: Could not alloc rpqueue\n");
+ kfree(d->rcvcount);
+ kfree(d->rcverr);
+ kfree(d);
+ return 0;
+ }
+ for (j = 0; j < n; j++) {
+ skb_queue_head_init(&d->rpqueue[j]);
+ }
if (!(d->rcv_waitq = (struct wait_queue **)
kmalloc(sizeof(struct wait_queue *) * n, GFP_KERNEL))) {
printk(KERN_WARNING "register_isdn: Could not alloc rcv_waitq\n");
@@ -2038,17 +2018,17 @@
if (!dev->drv[drvidx])
break;
i->channels = drvidx;
-
+
i->rcvcallb_skb = isdn_receive_skb_callback;
- i->rcvcallb = isdn_receive_callback;
- i->statcallb = isdn_status_callback;
+ i->rcvcallb = isdn_receive_callback;
+ i->statcallb = isdn_status_callback;
if (!strlen(i->id))
sprintf(i->id, "line%d", drvidx);
save_flags(flags);
cli();
- for (j = 0; j < drvidx; j++)
- if (!strcmp(i->id,dev->drvid[j]))
- sprintf(i->id, "line%d", drvidx);
+ for (j = 0; j < drvidx; j++)
+ if (!strcmp(i->id, dev->drvid[j]))
+ sprintf(i->id, "line%d", drvidx);
for (j = 0; j < n; j++)
for (k = 0; k < ISDN_MAX_CHANNELS; k++)
if (dev->chanmap[k] < 0) {
@@ -2077,7 +2057,8 @@
#define isdn_init init_module
#endif
-static char *isdn_getrev(const char *revision)
+static char *
+isdn_getrev(const char *revision)
{
char *rev;
char *p;
@@ -2091,29 +2072,18 @@
return rev;
}
-static struct symbol_table isdn_syms = {
-#include <linux/symtab_begin.h>
- X(register_isdn),
-#include <linux/symtab_end.h>
-};
-
-static void isdn_export_syms(void)
-{
- register_symtab(&isdn_syms);
- has_exported = 1;
-}
-
/*
* Allocate and initialize all data, register modem-devices
*/
-int isdn_init(void)
+int
+isdn_init(void)
{
int i;
- char irev[50];
- char trev[50];
- char nrev[50];
- char prev[50];
- char arev[50];
+ char irev[50];
+ char trev[50];
+ char nrev[50];
+ char prev[50];
+ char arev[50];
sti();
if (!(dev = (isdn_dev *) kmalloc(sizeof(isdn_dev), GFP_KERNEL))) {
@@ -2121,10 +2091,8 @@
return -EIO;
}
memset((char *) dev, 0, sizeof(isdn_dev));
-#ifdef NEW_ISDN_TIMER_CTRL
- init_timer(&dev->timer);
- dev->timer.function = isdn_timer_funct;
-#endif
+ init_timer(&dev->timer);
+ dev->timer.function = isdn_timer_funct;
for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
dev->drvmap[i] = -1;
dev->chanmap[i] = -1;
@@ -2157,21 +2125,20 @@
kfree(dev);
return -EIO;
}
-#endif /* CONFIG_ISDN_PPP */
+#endif /* CONFIG_ISDN_PPP */
- if (!has_exported)
- isdn_export_syms();
+ 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);
+ 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));
+ printk("%s/", isdn_getrev(trev));
+ printk("%s/", isdn_getrev(nrev));
+ printk("%s/", isdn_getrev(prev));
+ printk("%s", isdn_getrev(arev));
#ifdef MODULE
printk(" loaded\n");
@@ -2187,7 +2154,8 @@
/*
* Unload module
*/
-void cleanup_module(void)
+void
+cleanup_module(void)
{
int flags;
int i;
@@ -2213,9 +2181,9 @@
return;
}
for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
- isdn_tty_cleanup_xmit(&dev->mdm.info[i]);
- kfree(dev->mdm.info[i].xmit_buf - 4);
- }
+ isdn_tty_cleanup_xmit(&dev->mdm.info[i]);
+ kfree(dev->mdm.info[i].xmit_buf - 4);
+ }
if (unregister_chrdev(ISDN_MAJOR, "isdn") != 0) {
printk(KERN_WARNING "isdn: controldevice busy, remove cancelled\n");
} else {
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov