summaryrefslogtreecommitdiff
path: root/drivers/isdn/i4l/isdn_common.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/isdn/i4l/isdn_common.c')
-rw-r--r--drivers/isdn/i4l/isdn_common.c2368
1 files changed, 0 insertions, 2368 deletions
diff --git a/drivers/isdn/i4l/isdn_common.c b/drivers/isdn/i4l/isdn_common.c
deleted file mode 100644
index 74ee00f5b310..000000000000
--- a/drivers/isdn/i4l/isdn_common.c
+++ /dev/null
@@ -1,2368 +0,0 @@
-/* $Id: isdn_common.c,v 1.1.2.3 2004/02/10 01:07:13 keil Exp $
- *
- * Linux ISDN subsystem, common used functions (linklevel).
- *
- * Copyright 1994-1999 by Fritz Elfert (fritz@isdn4linux.de)
- * Copyright 1995,96 Thinking Objects Software GmbH Wuerzburg
- * Copyright 1995,96 by Michael Hipp (Michael.Hipp@student.uni-tuebingen.de)
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/poll.h>
-#include <linux/slab.h>
-#include <linux/vmalloc.h>
-#include <linux/isdn.h>
-#include <linux/mutex.h>
-#include "isdn_common.h"
-#include "isdn_tty.h"
-#include "isdn_net.h"
-#include "isdn_ppp.h"
-#ifdef CONFIG_ISDN_AUDIO
-#include "isdn_audio.h"
-#endif
-#ifdef CONFIG_ISDN_DIVERSION_MODULE
-#define CONFIG_ISDN_DIVERSION
-#endif
-#ifdef CONFIG_ISDN_DIVERSION
-#include <linux/isdn_divertif.h>
-#endif /* CONFIG_ISDN_DIVERSION */
-#include "isdn_v110.h"
-
-/* Debugflags */
-#undef ISDN_DEBUG_STATCALLB
-
-MODULE_DESCRIPTION("ISDN4Linux: link layer");
-MODULE_AUTHOR("Fritz Elfert");
-MODULE_LICENSE("GPL");
-
-isdn_dev *dev;
-
-static DEFINE_MUTEX(isdn_mutex);
-static char *isdn_revision = "$Revision: 1.1.2.3 $";
-
-extern char *isdn_net_revision;
-#ifdef CONFIG_ISDN_PPP
-extern char *isdn_ppp_revision;
-#else
-static char *isdn_ppp_revision = ": none $";
-#endif
-#ifdef CONFIG_ISDN_AUDIO
-extern char *isdn_audio_revision;
-#else
-static char *isdn_audio_revision = ": none $";
-#endif
-extern char *isdn_v110_revision;
-
-#ifdef CONFIG_ISDN_DIVERSION
-static isdn_divert_if *divert_if; /* = NULL */
-#endif /* CONFIG_ISDN_DIVERSION */
-
-
-static int isdn_writebuf_stub(int, int, const u_char __user *, int);
-static void set_global_features(void);
-static int isdn_wildmat(char *s, char *p);
-static int isdn_add_channels(isdn_driver_t *d, int drvidx, int n, int adding);
-
-static inline void
-isdn_lock_driver(isdn_driver_t *drv)
-{
- try_module_get(drv->interface->owner);
- drv->locks++;
-}
-
-void
-isdn_lock_drivers(void)
-{
- int i;
-
- for (i = 0; i < ISDN_MAX_DRIVERS; i++) {
- if (!dev->drv[i])
- continue;
- isdn_lock_driver(dev->drv[i]);
- }
-}
-
-static inline void
-isdn_unlock_driver(isdn_driver_t *drv)
-{
- if (drv->locks > 0) {
- drv->locks--;
- module_put(drv->interface->owner);
- }
-}
-
-void
-isdn_unlock_drivers(void)
-{
- int i;
-
- for (i = 0; i < ISDN_MAX_DRIVERS; i++) {
- if (!dev->drv[i])
- continue;
- isdn_unlock_driver(dev->drv[i]);
- }
-}
-
-#if defined(ISDN_DEBUG_NET_DUMP) || defined(ISDN_DEBUG_MODEM_DUMP)
-void
-isdn_dumppkt(char *s, u_char *p, int len, int dumplen)
-{
- int dumpc;
-
- printk(KERN_DEBUG "%s(%d) ", s, len);
- for (dumpc = 0; (dumpc < dumplen) && (len); len--, dumpc++)
- printk(" %02x", *p++);
- printk("\n");
-}
-#endif
-
-/*
- * I picked the pattern-matching-functions from an old GNU-tar version (1.10)
- * It was originally written and put to PD by rs@mirror.TMC.COM (Rich Salz)
- */
-static int
-isdn_star(char *s, char *p)
-{
- while (isdn_wildmat(s, p)) {
- if (*++s == '\0')
- return (2);
- }
- return (0);
-}
-
-/*
- * Shell-type Pattern-matching for incoming caller-Ids
- * This function gets a string in s and checks, if it matches the pattern
- * given in p.
- *
- * Return:
- * 0 = match.
- * 1 = no match.
- * 2 = no match. Would eventually match, if s would be longer.
- *
- * Possible Patterns:
- *
- * '?' matches one character
- * '*' matches zero or more characters
- * [xyz] matches the set of characters in brackets.
- * [^xyz] matches any single character not in the set of characters
- */
-
-static int
-isdn_wildmat(char *s, char *p)
-{
- register int last;
- register int matched;
- register int reverse;
- register int nostar = 1;
-
- if (!(*s) && !(*p))
- return (1);
- for (; *p; s++, p++)
- switch (*p) {
- case '\\':
- /* Literal match with following character. */
- p++;
- /* fall through */
- default:
- if (*s != *p)
- return (*s == '\0') ? 2 : 1;
- continue;
- case '?':
- /* Match anything. */
- if (*s == '\0')
- return (2);
- continue;
- case '*':
- nostar = 0;
- /* Trailing star matches everything. */
- return (*++p ? isdn_star(s, p) : 0);
- case '[':
- /* [^....] means inverse character class. */
- if ((reverse = (p[1] == '^')))
- p++;
- for (last = 0, matched = 0; *++p && (*p != ']'); last = *p)
- /* This next line requires a good C compiler. */
- if (*p == '-' ? *s <= *++p && *s >= last : *s == *p)
- matched = 1;
- if (matched == reverse)
- return (1);
- continue;
- }
- return (*s == '\0') ? 0 : nostar;
-}
-
-int isdn_msncmp(const char *msn1, const char *msn2)
-{
- char TmpMsn1[ISDN_MSNLEN];
- char TmpMsn2[ISDN_MSNLEN];
- char *p;
-
- for (p = TmpMsn1; *msn1 && *msn1 != ':';) // Strip off a SPID
- *p++ = *msn1++;
- *p = '\0';
-
- for (p = TmpMsn2; *msn2 && *msn2 != ':';) // Strip off a SPID
- *p++ = *msn2++;
- *p = '\0';
-
- return isdn_wildmat(TmpMsn1, TmpMsn2);
-}
-
-int
-isdn_dc2minor(int di, int ch)
-{
- int i;
- for (i = 0; i < ISDN_MAX_CHANNELS; i++)
- if (dev->chanmap[i] == ch && dev->drvmap[i] == di)
- return i;
- return -1;
-}
-
-static int isdn_timer_cnt1 = 0;
-static int isdn_timer_cnt2 = 0;
-static int isdn_timer_cnt3 = 0;
-
-static void
-isdn_timer_funct(struct timer_list *unused)
-{
- int tf = dev->tflags;
- if (tf & ISDN_TIMER_FAST) {
- if (tf & ISDN_TIMER_MODEMREAD)
- isdn_tty_readmodem();
- if (tf & ISDN_TIMER_MODEMPLUS)
- isdn_tty_modem_escape();
- if (tf & ISDN_TIMER_MODEMXMIT)
- isdn_tty_modem_xmit();
- }
- if (tf & ISDN_TIMER_SLOW) {
- if (++isdn_timer_cnt1 >= ISDN_TIMER_02SEC) {
- isdn_timer_cnt1 = 0;
- 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 (++isdn_timer_cnt3 >= ISDN_TIMER_RINGING) {
- isdn_timer_cnt3 = 0;
- if (tf & ISDN_TIMER_MODEMRING)
- isdn_tty_modem_ring();
- }
- if (tf & ISDN_TIMER_CARRIER)
- isdn_tty_carrier_timeout();
- }
- }
- if (tf)
- mod_timer(&dev->timer, jiffies + ISDN_TIMER_RES);
-}
-
-void
-isdn_timer_ctrl(int tf, int onoff)
-{
- unsigned long flags;
- int old_tflags;
-
- spin_lock_irqsave(&dev->timerlock, flags);
- if ((tf & ISDN_TIMER_SLOW) && (!(dev->tflags & ISDN_TIMER_SLOW))) {
- /* If the slow-timer wasn't activated until now */
- isdn_timer_cnt1 = 0;
- isdn_timer_cnt2 = 0;
- }
- old_tflags = dev->tflags;
- if (onoff)
- dev->tflags |= tf;
- else
- dev->tflags &= ~tf;
- if (dev->tflags && !old_tflags)
- mod_timer(&dev->timer, jiffies + ISDN_TIMER_RES);
- spin_unlock_irqrestore(&dev->timerlock, 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)
-{
- int i;
-
- if ((i = isdn_dc2minor(di, channel)) == -1) {
- 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 */
- if (skb->len) {
- if (isdn_tty_rcv_skb(i, di, channel, skb))
- return;
- wake_up_interruptible(&dev->drv[di]->rcv_waitq[channel]);
- } else
- 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->driver == -1) {
- printk(KERN_WARNING "isdn_command command(%x) driver -1\n", cmd->command);
- return (1);
- }
- if (!dev->drv[cmd->driver]) {
- printk(KERN_WARNING "isdn_command command(%x) dev->drv[%d] NULL\n",
- cmd->command, cmd->driver);
- return (1);
- }
- if (!dev->drv[cmd->driver]->interface) {
- printk(KERN_WARNING "isdn_command command(%x) dev->drv[%d]->interface NULL\n",
- cmd->command, cmd->driver);
- return (1);
- }
- 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
-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.parm.num[0] = '\0';
- isdn_command(&cmd);
-}
-
-/*
- * Begin of a CAPI like LL<->HL interface, currently used only for
- * supplementary service (CAPI 2.0 part III)
- */
-#include <linux/isdn/capicmd.h>
-
-static int
-isdn_capi_rec_hl_msg(capi_msg *cm)
-{
- switch (cm->Command) {
- case CAPI_FACILITY:
- /* in the moment only handled in tty */
- return (isdn_tty_capi_facility(cm));
- default:
- return (-1);
- }
-}
-
-static int
-isdn_status_callback(isdn_ctrl *c)
-{
- int di;
- u_long flags;
- int i;
- int r;
- int retval = 0;
- isdn_ctrl cmd;
- isdn_net_dev *p;
-
- di = c->driver;
- i = isdn_dc2minor(di, c->arg);
- switch (c->command) {
- 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))
- return 0;
- if (isdn_v110_stat_callback(i, c))
- 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:
- dev->drv[di]->stavail += c->arg;
- wake_up_interruptible(&dev->drv[di]->st_waitq);
- break;
- case ISDN_STAT_RUN:
- dev->drv[di]->flags |= DRV_FLAG_RUNNING;
- for (i = 0; i < ISDN_MAX_CHANNELS; i++)
- if (dev->drvmap[i] == di)
- isdn_all_eaz(di, dev->chanmap[i]);
- set_global_features();
- break;
- case ISDN_STAT_STOP:
- dev->drv[di]->flags &= ~DRV_FLAG_RUNNING;
- 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->parm.num);
-#endif
- if (dev->global_flags & ISDN_GLOBAL_STOPPED) {
- cmd.driver = di;
- cmd.arg = c->arg;
- cmd.command = ISDN_CMD_HANGUP;
- isdn_command(&cmd);
- return 0;
- }
- /* Try to find a network-interface which will accept incoming call */
- r = ((c->command == ISDN_STAT_ICALLW) ? 0 : isdn_net_find_icall(di, c->arg, i, &c->parm.setup));
- switch (r) {
- case 0:
- /* No network-device replies.
- * Try ttyI's.
- * These return 0 on no match, 1 on match and
- * 3 on eventually match, if CID is longer.
- */
- if (c->command == ISDN_STAT_ICALL)
- if ((retval = isdn_tty_find_icall(di, c->arg, &c->parm.setup))) return (retval);
-#ifdef CONFIG_ISDN_DIVERSION
- if (divert_if)
- if ((retval = divert_if->stat_callback(c)))
- return (retval); /* processed */
-#endif /* CONFIG_ISDN_DIVERSION */
- if ((!retval) && (dev->drv[di]->flags & DRV_FLAG_REJBUS)) {
- /* No tty responding */
- cmd.driver = di;
- cmd.arg = c->arg;
- cmd.command = ISDN_CMD_HANGUP;
- isdn_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;
- for (p = dev->netdev; p; p = p->next)
- if (p->local->isdn_channel == cmd.arg)
- {
- strcpy(cmd.parm.setup.eazmsn, p->local->msn);
- isdn_command(&cmd);
- retval = 1;
- break;
- }
- 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;
- isdn_command(&cmd);
- if (r == 3)
- break;
- /* Fall through */
- case 4:
- /* ... then start callback. */
- isdn_net_dial();
- break;
- case 5:
- /* Number would eventually match, if longer */
- retval = 3;
- break;
- }
-#ifdef ISDN_DEBUG_STATCALLB
- printk(KERN_DEBUG "ICALL: ret=%d\n", retval);
-#endif
- 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->parm.num);
-#endif
- if (dev->global_flags & ISDN_GLOBAL_STOPPED)
- return 0;
- if (strcmp(c->parm.num, "0"))
- isdn_net_stat_callback(i, c);
- isdn_tty_stat_callback(i, c);
- break;
- case ISDN_STAT_CAUSE:
-#ifdef ISDN_DEBUG_STATCALLB
- printk(KERN_DEBUG "CAUSE: %ld %s\n", c->arg, c->parm.num);
-#endif
- printk(KERN_INFO "isdn: %s,ch%ld cause: %s\n",
- dev->drvid[di], c->arg, c->parm.num);
- isdn_tty_stat_callback(i, c);
-#ifdef CONFIG_ISDN_DIVERSION
- if (divert_if)
- divert_if->stat_callback(c);
-#endif /* CONFIG_ISDN_DIVERSION */
- break;
- case ISDN_STAT_DISPLAY:
-#ifdef ISDN_DEBUG_STATCALLB
- printk(KERN_DEBUG "DISPLAY: %ld %s\n", c->arg, c->parm.display);
-#endif
- isdn_tty_stat_callback(i, c);
-#ifdef CONFIG_ISDN_DIVERSION
- if (divert_if)
- divert_if->stat_callback(c);
-#endif /* CONFIG_ISDN_DIVERSION */
- break;
- case ISDN_STAT_DCONN:
- if (i < 0)
- return -1;
-#ifdef ISDN_DEBUG_STATCALLB
- printk(KERN_DEBUG "DCONN: %ld\n", c->arg);
-#endif
- 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))
- 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;
- isdn_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]->online &= ~(1 << (c->arg));
- isdn_info_update();
- /* Signal hangup to network-devices */
- if (isdn_net_stat_callback(i, c))
- break;
- isdn_v110_stat_callback(i, c);
- if (isdn_tty_stat_callback(i, c))
- break;
-#ifdef CONFIG_ISDN_DIVERSION
- if (divert_if)
- divert_if->stat_callback(c);
-#endif /* CONFIG_ISDN_DIVERSION */
- break;
- break;
- case ISDN_STAT_BCONN:
- if (i < 0)
- return -1;
-#ifdef ISDN_DEBUG_STATCALLB
- 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]->online |= (1 << (c->arg));
- isdn_info_update();
- if (isdn_net_stat_callback(i, c))
- break;
- isdn_v110_stat_callback(i, c);
- 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]->online &= ~(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;
- case ISDN_STAT_NODCH:
- if (i < 0)
- return -1;
-#ifdef ISDN_DEBUG_STATCALLB
- 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))
- break;
- if (isdn_tty_stat_callback(i, c))
- break;
- break;
- case ISDN_STAT_ADDCH:
- spin_lock_irqsave(&dev->lock, flags);
- if (isdn_add_channels(dev->drv[di], di, c->arg, 1)) {
- spin_unlock_irqrestore(&dev->lock, flags);
- return -1;
- }
- spin_unlock_irqrestore(&dev->lock, flags);
- isdn_info_update();
- break;
- case ISDN_STAT_DISCH:
- spin_lock_irqsave(&dev->lock, flags);
- for (i = 0; i < ISDN_MAX_CHANNELS; i++)
- if ((dev->drvmap[i] == di) &&
- (dev->chanmap[i] == c->arg)) {
- if (c->parm.num[0])
- dev->usage[i] &= ~ISDN_USAGE_DISABLED;
- else
- if (USG_NONE(dev->usage[i])) {
- dev->usage[i] |= ISDN_USAGE_DISABLED;
- }
- else
- retval = -1;
- break;
- }
- spin_unlock_irqrestore(&dev->lock, flags);
- isdn_info_update();
- break;
- case ISDN_STAT_UNLOAD:
- while (dev->drv[di]->locks > 0) {
- isdn_unlock_driver(dev->drv[di]);
- }
- spin_lock_irqsave(&dev->lock, flags);
- 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;
- dev->usage[i] &= ~ISDN_USAGE_DISABLED;
- }
- 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++)
- skb_queue_purge(&dev->drv[di]->rpqueue[i]);
- kfree(dev->drv[di]->rpqueue);
- kfree(dev->drv[di]->rcv_waitq);
- kfree(dev->drv[di]);
- dev->drv[di] = NULL;
- dev->drvid[di][0] = '\0';
- isdn_info_update();
- set_global_features();
- spin_unlock_irqrestore(&dev->lock, flags);
- return 0;
- case ISDN_STAT_L1ERR:
- break;
- case CAPI_PUT_MESSAGE:
- return (isdn_capi_rec_hl_msg(&c->parm.cmsg));
-#ifdef CONFIG_ISDN_TTY_FAX
- case ISDN_STAT_FAXIND:
- isdn_tty_stat_callback(i, c);
- break;
-#endif
-#ifdef CONFIG_ISDN_AUDIO
- case ISDN_STAT_AUDIO:
- isdn_tty_stat_callback(i, c);
- break;
-#endif
-#ifdef CONFIG_ISDN_DIVERSION
- case ISDN_STAT_PROT:
- case ISDN_STAT_REDIR:
- if (divert_if)
- return (divert_if->stat_callback(c));
-#endif /* CONFIG_ISDN_DIVERSION */
- /* fall through */
- default:
- return -1;
- }
- return 0;
-}
-
-/*
- * Get integer from char-pointer, set pointer to end of number
- */
-int
-isdn_getnum(char **p)
-{
- int v = -1;
-
- while (*p[0] >= '0' && *p[0] <= '9')
- v = ((v < 0) ? 0 : (v * 10)) + (int) ((*p[0]++) - '0');
- return v;
-}
-
-#define DLE 0x10
-
-/*
- * isdn_readbchan() tries to get data from the read-queue.
- * It MUST be called with interrupts off.
- *
- * Be aware that this is not an atomic operation when sleep != 0, even though
- * interrupts are turned off! Well, like that we are currently only called
- * on behalf of a read system call on raw device files (which are documented
- * to be dangerous and for debugging purpose only). The inode semaphore
- * takes care that this is not called for the same minor device number while
- * we are sleeping, but access is not serialized against simultaneous read()
- * from the corresponding ttyI device. Can other ugly events, like changes
- * of the mapping (di,ch)<->minor, happen during the sleep? --he
- */
-int
-isdn_readbchan(int di, int channel, u_char *buf, u_char *fp, int len, wait_queue_head_t *sleep)
-{
- int count;
- int count_pull;
- int count_put;
- int dflag;
- struct sk_buff *skb;
- u_char *cp;
-
- if (!dev->drv[di])
- return 0;
- if (skb_queue_empty(&dev->drv[di]->rpqueue[channel])) {
- if (sleep)
- wait_event_interruptible(*sleep,
- !skb_queue_empty(&dev->drv[di]->rpqueue[channel]));
- else
- return 0;
- }
- if (len > dev->drv[di]->rcvcount[channel])
- len = dev->drv[di]->rcvcount[channel];
- cp = buf;
- count = 0;
- while (len) {
- 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)) || (dev->drv[di]->DLEflag & (1 << channel))) {
- char *p = skb->data;
- unsigned long DLEmask = (1 << channel);
-
- dflag = 0;
- count_pull = count_put = 0;
- while ((count_pull < skb->len) && (len > 0)) {
- len--;
- if (dev->drv[di]->DLEflag & DLEmask) {
- *cp++ = DLE;
- dev->drv[di]->DLEflag &= ~DLEmask;
- } 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) > len) {
- count_pull = len;
- dflag = 0;
- }
- count_put = count_pull;
- skb_copy_from_linear_data(skb, cp, count_put);
- cp += count_put;
- len -= 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;
-#ifdef CONFIG_ISDN_AUDIO
- ISDN_AUDIO_SKB_LOCK(skb) = 0;
-#endif
- skb = skb_dequeue(&dev->drv[di]->rpqueue[channel]);
- dev_kfree_skb(skb);
- } 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);
-#ifdef CONFIG_ISDN_AUDIO
- ISDN_AUDIO_SKB_LOCK(skb) = 0;
-#endif
- }
- dev->drv[di]->rcvcount[channel] -= count_put;
- }
- return count;
-}
-
-/*
- * isdn_readbchan_tty() tries to get data from the read-queue.
- * It MUST be called with interrupts off.
- *
- * Be aware that this is not an atomic operation when sleep != 0, even though
- * interrupts are turned off! Well, like that we are currently only called
- * on behalf of a read system call on raw device files (which are documented
- * to be dangerous and for debugging purpose only). The inode semaphore
- * takes care that this is not called for the same minor device number while
- * we are sleeping, but access is not serialized against simultaneous read()
- * from the corresponding ttyI device. Can other ugly events, like changes
- * of the mapping (di,ch)<->minor, happen during the sleep? --he
- */
-int
-isdn_readbchan_tty(int di, int channel, struct tty_port *port, int cisco_hack)
-{
- int count;
- int count_pull;
- int count_put;
- int dflag;
- struct sk_buff *skb;
- char last = 0;
- int len;
-
- if (!dev->drv[di])
- return 0;
- if (skb_queue_empty(&dev->drv[di]->rpqueue[channel]))
- return 0;
-
- len = tty_buffer_request_room(port, dev->drv[di]->rcvcount[channel]);
- if (len == 0)
- return len;
-
- count = 0;
- while (len) {
- 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)) || (dev->drv[di]->DLEflag & (1 << channel))) {
- char *p = skb->data;
- unsigned long DLEmask = (1 << channel);
-
- dflag = 0;
- count_pull = count_put = 0;
- while ((count_pull < skb->len) && (len > 0)) {
- /* push every character but the last to the tty buffer directly */
- if (count_put)
- tty_insert_flip_char(port, last, TTY_NORMAL);
- len--;
- if (dev->drv[di]->DLEflag & DLEmask) {
- last = DLE;
- dev->drv[di]->DLEflag &= ~DLEmask;
- } else {
- last = *p;
- if (last == 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) > len) {
- count_pull = len;
- dflag = 0;
- }
- count_put = count_pull;
- if (count_put > 1)
- tty_insert_flip_string(port, skb->data, count_put - 1);
- last = skb->data[count_put - 1];
- len -= count_put;
-#ifdef CONFIG_ISDN_AUDIO
- }
-#endif
- count += count_put;
- if (dflag) {
- /* We got all the data in this buff.
- * Now we can dequeue it.
- */
- if (cisco_hack)
- tty_insert_flip_char(port, last, 0xFF);
- else
- tty_insert_flip_char(port, last, TTY_NORMAL);
-#ifdef CONFIG_ISDN_AUDIO
- ISDN_AUDIO_SKB_LOCK(skb) = 0;
-#endif
- skb = skb_dequeue(&dev->drv[di]->rpqueue[channel]);
- dev_kfree_skb(skb);
- } else {
- tty_insert_flip_char(port, last, TTY_NORMAL);
- /* 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)
-{
- return (dev->drvmap[minor]);
-}
-
-static inline int
-isdn_minor2chan(int minor)
-{
- return (dev->chanmap[minor]);
-}
-
-static char *
-isdn_statstr(void)
-{
- static char istatbuf[2048];
- char *p;
- int i;
-
- sprintf(istatbuf, "idmap:\t");
- p = istatbuf + strlen(istatbuf);
- for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
- sprintf(p, "%s ", (dev->drvmap[i] < 0) ? "-" : dev->drvid[dev->drvmap[i]]);
- p = istatbuf + strlen(istatbuf);
- }
- sprintf(p, "\nchmap:\t");
- p = istatbuf + strlen(istatbuf);
- for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
- sprintf(p, "%d ", dev->chanmap[i]);
- p = istatbuf + strlen(istatbuf);
- }
- sprintf(p, "\ndrmap:\t");
- p = istatbuf + strlen(istatbuf);
- for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
- sprintf(p, "%d ", dev->drvmap[i]);
- p = istatbuf + strlen(istatbuf);
- }
- sprintf(p, "\nusage:\t");
- p = istatbuf + strlen(istatbuf);
- for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
- sprintf(p, "%d ", dev->usage[i]);
- p = istatbuf + strlen(istatbuf);
- }
- sprintf(p, "\nflags:\t");
- p = istatbuf + strlen(istatbuf);
- for (i = 0; i < ISDN_MAX_DRIVERS; i++) {
- if (dev->drv[i]) {
- sprintf(p, "%ld ", dev->drv[i]->online);
- p = istatbuf + strlen(istatbuf);
- } else {
- sprintf(p, "? ");
- p = istatbuf + strlen(istatbuf);
- }
- }
- sprintf(p, "\nphone:\t");
- p = istatbuf + strlen(istatbuf);
- for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
- sprintf(p, "%s ", dev->num[i]);
- p = istatbuf + strlen(istatbuf);
- }
- sprintf(p, "\n");
- return istatbuf;
-}
-
-/* Module interface-code */
-
-void
-isdn_info_update(void)
-{
- infostruct *p = dev->infochain;
-
- while (p) {
- *(p->private) = 1;
- p = (infostruct *) p->next;
- }
- wake_up_interruptible(&(dev->info_waitq));
-}
-
-static ssize_t
-isdn_read(struct file *file, char __user *buf, size_t count, loff_t *off)
-{
- uint minor = iminor(file_inode(file));
- int len = 0;
- int drvidx;
- int chidx;
- int retval;
- char *p;
-
- mutex_lock(&isdn_mutex);
- if (minor == ISDN_MINOR_STATUS) {
- if (!file->private_data) {
- if (file->f_flags & O_NONBLOCK) {
- retval = -EAGAIN;
- goto out;
- }
- wait_event_interruptible(dev->info_waitq,
- file->private_data);
- }
- p = isdn_statstr();
- file->private_data = NULL;
- if ((len = strlen(p)) <= count) {
- if (copy_to_user(buf, p, len)) {
- retval = -EFAULT;
- goto out;
- }
- *off += len;
- retval = len;
- goto out;
- }
- retval = 0;
- goto out;
- }
- if (!dev->drivers) {
- retval = -ENODEV;
- goto out;
- }
- if (minor <= ISDN_MINOR_BMAX) {
- printk(KERN_WARNING "isdn_read minor %d obsolete!\n", minor);
- drvidx = isdn_minor2drv(minor);
- if (drvidx < 0) {
- retval = -ENODEV;
- goto out;
- }
- if (!(dev->drv[drvidx]->flags & DRV_FLAG_RUNNING)) {
- retval = -ENODEV;
- goto out;
- }
- chidx = isdn_minor2chan(minor);
- if (!(p = kmalloc(count, GFP_KERNEL))) {
- retval = -ENOMEM;
- goto out;
- }
- len = isdn_readbchan(drvidx, chidx, p, NULL, count,
- &dev->drv[drvidx]->rcv_waitq[chidx]);
- *off += len;
- if (copy_to_user(buf, p, len))
- len = -EFAULT;
- kfree(p);
- retval = len;
- goto out;
- }
- if (minor <= ISDN_MINOR_CTRLMAX) {
- drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL);
- if (drvidx < 0) {
- retval = -ENODEV;
- goto out;
- }
- if (!dev->drv[drvidx]->stavail) {
- if (file->f_flags & O_NONBLOCK) {
- retval = -EAGAIN;
- goto out;
- }
- wait_event_interruptible(dev->drv[drvidx]->st_waitq,
- dev->drv[drvidx]->stavail);
- }
- if (dev->drv[drvidx]->interface->readstat) {
- if (count > dev->drv[drvidx]->stavail)
- count = dev->drv[drvidx]->stavail;
- len = dev->drv[drvidx]->interface->readstat(buf, count,
- drvidx, isdn_minor2chan(minor - ISDN_MINOR_CTRL));
- if (len < 0) {
- retval = len;
- goto out;
- }
- } else {
- len = 0;
- }
- if (len)
- dev->drv[drvidx]->stavail -= len;
- else
- dev->drv[drvidx]->stavail = 0;
- *off += len;
- retval = len;
- goto out;
- }
-#ifdef CONFIG_ISDN_PPP
- if (minor <= ISDN_MINOR_PPPMAX) {
- retval = isdn_ppp_read(minor - ISDN_MINOR_PPP, file, buf, count);
- goto out;
- }
-#endif
- retval = -ENODEV;
-out:
- mutex_unlock(&isdn_mutex);
- return retval;
-}
-
-static ssize_t
-isdn_write(struct file *file, const char __user *buf, size_t count, loff_t *off)
-{
- uint minor = iminor(file_inode(file));
- int drvidx;
- int chidx;
- int retval;
-
- if (minor == ISDN_MINOR_STATUS)
- return -EPERM;
- if (!dev->drivers)
- return -ENODEV;
-
- mutex_lock(&isdn_mutex);
- if (minor <= ISDN_MINOR_BMAX) {
- printk(KERN_WARNING "isdn_write minor %d obsolete!\n", minor);
- drvidx = isdn_minor2drv(minor);
- if (drvidx < 0) {
- retval = -ENODEV;
- goto out;
- }
- if (!(dev->drv[drvidx]->flags & DRV_FLAG_RUNNING)) {
- retval = -ENODEV;
- goto out;
- }
- chidx = isdn_minor2chan(minor);
- wait_event_interruptible(dev->drv[drvidx]->snd_waitq[chidx],
- (retval = isdn_writebuf_stub(drvidx, chidx, buf, count)));
- goto out;
- }
- if (minor <= ISDN_MINOR_CTRLMAX) {
- drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL);
- if (drvidx < 0) {
- retval = -ENODEV;
- goto out;
- }
- /*
- * We want to use the isdnctrl device to load the firmware
- *