patch-1.3.93 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: 347
- Date:
Sun Apr 21 11:56:14 1996
- Orig file:
v1.3.92/linux/drivers/isdn/isdn_common.c
- Orig date:
Mon Feb 26 11:58:05 1996
diff -u --recursive --new-file v1.3.92/linux/drivers/isdn/isdn_common.c linux/drivers/isdn/isdn_common.c
@@ -1,4 +1,4 @@
-/* $Id: isdn_common.c,v 1.4 1996/02/11 02:33:26 fritz Exp fritz $
+/* $Id: isdn_common.c,v 1.5 1996/04/20 16:19:07 fritz Exp $
*
* Linux ISDN subsystem, common used functions (linklevel).
*
@@ -21,6 +21,15 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: isdn_common.c,v $
+ * Revision 1.5 1996/04/20 16:19:07 fritz
+ * Changed slow timer handlers to increase accuracy.
+ * Added statistic information for usage by xisdnload.
+ * Fixed behaviour of isdnctrl-device on non-blocked io.
+ * Fixed all io to go through generic writebuf-function without
+ * bypassing. Same for incoming data.
+ * Fixed bug: Last channel had been unusable.
+ * Fixed kfree of tty xmit_buf on ppp initialization failure.
+ *
* Revision 1.4 1996/02/11 02:33:26 fritz
* Fixed bug in main timer-dispatcher.
* Bugfix: Lot of tty-callbacks got called regardless of the events already
@@ -61,7 +70,7 @@
isdn_dev *dev = (isdn_dev *) 0;
static int has_exported = 0;
-static char *isdn_revision = "$Revision: 1.4 $";
+static char *isdn_revision = "$Revision: 1.5 $";
extern char *isdn_net_revision;
extern char *isdn_tty_revision;
@@ -159,12 +168,12 @@
isdn_tty_modem_xmit();
}
if (tf & ISDN_TIMER_SLOW) {
- if (++isdn_timer_cnt1 > ISDN_TIMER_02SEC) {
+ 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) {
+ if (++isdn_timer_cnt2 >= ISDN_TIMER_1SEC) {
isdn_timer_cnt2 = 0;
if (tf & ISDN_TIMER_NETHANGUP)
isdn_net_autohup();
@@ -233,6 +242,8 @@
return;
if ((i = isdn_dc2minor(di,channel))==-1)
return;
+ /* Update statistics */
+ dev->ibytes[i] += len;
/* First, try to deliver data to network-device */
if (isdn_net_receive_callback(i, buf, len))
return;
@@ -375,14 +386,17 @@
break;
case 2: /* For calling back, first reject incoming call ... */
case 3: /* Interface found, but down, reject call actively */
+ 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 == 2)
- /* ... then start dialing. */
- isdn_net_dial();
- break;
+ if (r == 3)
+ break;
+ /* Fall through */
+ case 4:
+ /* ... then start callback. */
+ isdn_net_dial();
}
return 0;
break;
@@ -730,8 +744,11 @@
if (minor == ISDN_MINOR_STATUS) {
char *p;
- if (!file->private_data)
+ if (!file->private_data) {
+ if (file->f_flags & O_NONBLOCK)
+ return -EAGAIN;
interruptible_sleep_on(&(dev->info_waitq));
+ }
save_flags(flags);
p = isdn_statstr();
restore_flags(flags);
@@ -760,8 +777,11 @@
drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL);
if (drvidx < 0)
return -ENODEV;
- if (!dev->drv[drvidx]->stavail)
+ if (!dev->drv[drvidx]->stavail) {
+ 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), 1);
@@ -769,7 +789,10 @@
len = 0;
save_flags(flags);
cli();
- dev->drv[drvidx]->stavail -= len;
+ if (len)
+ dev->drv[drvidx]->stavail -= len;
+ else
+ dev->drv[drvidx]->stavail = 0;
restore_flags(flags);
file->f_pos += len;
return len;
@@ -803,7 +826,8 @@
if (!dev->drv[drvidx]->running)
return -ENODEV;
chidx = isdn_minor2chan(minor);
- while (dev->drv[drvidx]->interface->writebuf(drvidx, chidx, buf, count, 1) != count)
+ dev->obytes[minor] += count;
+ while (isdn_writebuf_stub(drvidx, chidx, buf, count, 1) != count)
interruptible_sleep_on(&dev->drv[drvidx]->snd_waitq[chidx]);
return count;
}
@@ -1008,8 +1032,27 @@
isdn_net_ioctl_phone phone;
isdn_net_ioctl_cfg cfg;
- if (minor == ISDN_MINOR_STATUS)
- return -EPERM;
+ if (minor == ISDN_MINOR_STATUS) {
+ switch (cmd) {
+ 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_fs_long(dev->ibytes[i],p++);
+ put_fs_long(dev->obytes[i],p++);
+ }
+ return 0;
+ } else
+ return -EINVAL;
+ break;
+ default:
+ return -EINVAL;
+ }
+ }
if (!dev->drivers)
return -ENODEV;
if (minor < ISDN_MINOR_CTRL) {
@@ -1367,7 +1410,6 @@
if (minor == ISDN_MINOR_STATUS) {
infostruct *p;
-
if ((p = (infostruct *) kmalloc(sizeof(infostruct), GFP_KERNEL))) {
MOD_INC_USE_COUNT;
p->next = (char *) dev->infochain;
@@ -1423,12 +1465,10 @@
int drvidx;
isdn_ctrl c;
- if (!dev->channels)
- return;
- MOD_DEC_USE_COUNT;
if (minor == ISDN_MINOR_STATUS) {
infostruct *p = dev->infochain;
infostruct *q = NULL;
+ MOD_DEC_USE_COUNT;
while (p) {
if (p->private == (char *) &(filep->private_data)) {
if (q)
@@ -1441,7 +1481,11 @@
p = (infostruct *) (p->next);
}
printk(KERN_WARNING "isdn: No private data while closing isdnctrl\n");
+ return;
}
+ if (!dev->channels)
+ return;
+ MOD_DEC_USE_COUNT;
if (minor < ISDN_MINOR_CTRL) {
drvidx = isdn_minor2drv(minor);
if (drvidx < 0)
@@ -1463,9 +1507,8 @@
return;
}
#ifdef CONFIG_ISDN_PPP
- if (minor <= ISDN_MINOR_PPPMAX) {
+ if (minor <= ISDN_MINOR_PPPMAX)
isdn_ppp_release(minor - ISDN_MINOR_PPP, filep);
- }
#endif
}
@@ -1559,6 +1602,8 @@
(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;
isdn_info_update();
restore_flags(flags);
return;
@@ -1593,17 +1638,20 @@
void isdn_receive_skb_callback(int drvidx, int chan, struct sk_buff *skb)
{
- int i;
+ int i, len;
if (dev->global_flags & ISDN_GLOBAL_STOPPED)
return;
if ((i = isdn_dc2minor(drvidx,chan))==-1)
return;
+ len = skb->len;
if (isdn_net_rcv_skb(i, skb) == 0) {
isdn_receive_callback(drvidx, chan, skb->data, skb->len);
skb->free = 1;
kfree_skb(skb, FREE_READ);
- }
+ } else
+ /* Update statistics */
+ dev->ibytes[i] += len;
}
/*
@@ -1613,28 +1661,55 @@
int isdn_writebuf_stub(int drvidx, int chan, const u_char *buf, int len,
int user)
{
- struct sk_buff * skb;
-
- skb = alloc_skb(dev->drv[drvidx]->interface->hl_hdrlen + len, GFP_ATOMIC);
- if (skb == NULL)
- return 0;
+ if (dev->drv[drvidx]->interface->writebuf)
+ return 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)
+ memcpy_fromfs(skb_put(skb, len), buf, len);
+ else
+ memcpy(skb_put(skb, len), buf, len);
+
+ return dev->drv[drvidx]->interface->writebuf_skb(drvidx, chan, skb);
+ }
+}
- skb_reserve(skb, dev->drv[drvidx]->interface->hl_hdrlen);
- skb->free = 1;
+/*
+ * writebuf_skb replacement for NON SKB_ABLE drivers
+ * If lowlevel-device does not support supports skbufs, use
+ * standard send-routine, else sind directly.
+ *
+ * Return: length of data on success, -ERRcode on failure.
+ */
- if (user)
- memcpy_fromfs(skb_put(skb, len), buf, len);
- else
- memcpy(skb_put(skb, len), buf, len);
+int isdn_writebuf_skb_stub(int drvidx, int chan, struct sk_buff * skb)
+{
+ int ret;
- return dev->drv[drvidx]->interface->writebuf_skb(drvidx, chan, skb);
+ if (dev->drv[drvidx]->interface->writebuf_skb)
+ ret = dev->drv[drvidx]->interface->
+ writebuf_skb(drvidx, chan, skb);
+ else {
+ if ((ret = dev->drv[drvidx]->interface->
+ writebuf(drvidx,chan,skb->data,skb->len,0))==skb->len)
+ dev_kfree_skb(skb, FREE_WRITE);
+ }
+ return ret;
}
-
+
/*
* Low-level-driver registration
*/
-
int register_isdn(isdn_if * i)
{
driver *d;
@@ -1648,11 +1723,15 @@
return 0;
}
n = i->channels;
- if (dev->channels + n >= ISDN_MAX_CHANNELS) {
+ if (dev->channels + n > ISDN_MAX_CHANNELS) {
printk(KERN_WARNING "register_isdn: Max. %d channels supported\n",
ISDN_MAX_CHANNELS);
return 0;
}
+ if ((!i->writebuf_skb) && (!i->writebuf)) {
+ 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;
@@ -1712,9 +1791,6 @@
if (!dev->drv[drvidx])
break;
i->channels = drvidx;
-
- if (i->writebuf_skb && (!i->writebuf))
- i->writebuf = isdn_writebuf_stub;
i->rcvcallb_skb = isdn_receive_skb_callback;
i->rcvcallb = isdn_receive_callback;
@@ -1790,7 +1866,7 @@
return -EIO;
}
memset((char *) dev, 0, sizeof(isdn_dev));
- for (i = 0; i < ISDN_MAX_DRIVERS; i++)
+ for (i = 0; i < ISDN_MAX_CHANNELS; i++)
dev->drvmap[i] = -1;
for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
dev->chanmap[i] = -1;
@@ -1818,7 +1894,7 @@
tty_unregister_driver(&dev->mdm.tty_modem);
tty_unregister_driver(&dev->mdm.cua_modem);
for (i = 0; i < ISDN_MAX_CHANNELS; i++)
- kfree(dev->mdm.info[i].xmit_buf);
+ kfree(dev->mdm.info[i].xmit_buf - 4);
unregister_chrdev(ISDN_MAJOR, "isdn");
kfree(dev);
return -EIO;
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov
with Sam's (original) version of this