root/drivers/isdn/isdn_common.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. isdn_MOD_INC_USE_COUNT
  2. isdn_MOD_DEC_USE_COUNT
  3. isdn_dumppkt
  4. isdn_new_buf
  5. isdn_free_queue
  6. isdn_dc2minor
  7. isdn_timer_funct
  8. isdn_timer_ctrl
  9. isdn_receive_callback
  10. isdn_all_eaz
  11. isdn_status_callback
  12. isdn_getnum
  13. isdn_readbchan
  14. isdn_minor2drv
  15. isdn_minor2chan
  16. isdn_statstr
  17. isdn_info_update
  18. isdn_read
  19. isdn_lseek
  20. isdn_write
  21. isdn_select
  22. isdn_set_allcfg
  23. isdn_get_allcfg
  24. isdn_ioctl
  25. isdn_open
  26. isdn_close
  27. isdn_map_eaz2msn
  28. isdn_get_free_channel
  29. isdn_free_channel
  30. isdn_unexclusive_channel
  31. isdn_receive_skb_callback
  32. isdn_writebuf_stub
  33. isdn_writebuf_skb_stub
  34. register_isdn
  35. isdn_getrev
  36. isdn_export_syms
  37. isdn_init
  38. cleanup_module

   1 /* $Id: isdn_common.c,v 1.5 1996/04/20 16:19:07 fritz Exp $
   2  *
   3  * Linux ISDN subsystem, common used functions (linklevel).
   4  *
   5  * Copyright 1994,95,96 by Fritz Elfert (fritz@wuemaus.franken.de)
   6  * Copyright 1995,96    Thinking Objects Software GmbH Wuerzburg
   7  * Copyright 1995,96    by Michael Hipp (Michael.Hipp@student.uni-tuebingen.de)
   8  * 
   9  * This program is free software; you can redistribute it and/or modify
  10  * it under the terms of the GNU General Public License as published by
  11  * the Free Software Foundation; either version 2, or (at your option)
  12  * any later version.
  13  *
  14  * This program is distributed in the hope that it will be useful,
  15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17  * GNU General Public License for more details.
  18  *
  19  * You should have received a copy of the GNU General Public License
  20  * along with this program; if not, write to the Free Software
  21  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
  22  *
  23  * $Log: isdn_common.c,v $
  24  * Revision 1.5  1996/04/20 16:19:07  fritz
  25  * Changed slow timer handlers to increase accuracy.
  26  * Added statistic information for usage by xisdnload.
  27  * Fixed behaviour of isdnctrl-device on non-blocked io.
  28  * Fixed all io to go through generic writebuf-function without
  29  * bypassing. Same for incoming data.
  30  * Fixed bug: Last channel had been unusable.
  31  * Fixed kfree of tty xmit_buf on ppp initialization failure.
  32  *
  33  * Revision 1.4  1996/02/11 02:33:26  fritz
  34  * Fixed bug in main timer-dispatcher.
  35  * Bugfix: Lot of tty-callbacks got called regardless of the events already
  36  * been handled by network-devices.
  37  * Changed ioctl-names.
  38  *
  39  * Revision 1.3  1996/01/22 05:16:11  fritz
  40  * Changed ioctl-names.
  41  * Fixed bugs in isdn_open and isdn_close regarding PPP_MINOR.
  42  *
  43  * Revision 1.2  1996/01/21 16:52:40  fritz
  44  * Support for sk_buffs added, changed header-stuffing.
  45  *
  46  * Revision 1.1  1996/01/09 04:12:52  fritz
  47  * Initial revision
  48  *
  49  */
  50 
  51 #ifndef STANDALONE
  52 #include <linux/config.h>
  53 #endif
  54 #include <linux/module.h>
  55 #include <linux/version.h>
  56 #ifndef __GENKSYMS__      /* Don't want genksyms report unneeded structs */
  57 #include <linux/isdn.h>
  58 #endif
  59 #include "isdn_common.h"
  60 #include "isdn_tty.h"
  61 #include "isdn_net.h"
  62 #include "isdn_ppp.h"
  63 #include "isdn_cards.h"
  64 
  65 
  66 
  67 /* Debugflags */
  68 #undef  ISDN_DEBUG_STATCALLB
  69 
  70 isdn_dev *dev = (isdn_dev *) 0;
  71 
  72 static int  has_exported = 0;
  73 static char *isdn_revision      = "$Revision: 1.5 $";
  74 
  75 extern char *isdn_net_revision;
  76 extern char *isdn_tty_revision;
  77 #ifdef CONFIG_ISDN_PPP
  78 extern char *isdn_ppp_revision;
  79 #else
  80 static char *isdn_ppp_revision = ": none $";
  81 #endif
  82 
  83 void isdn_MOD_INC_USE_COUNT(void)
     /* [previous][next][first][last][top][bottom][index][help] */
  84 {
  85         MOD_INC_USE_COUNT;
  86 }
  87 
  88 void isdn_MOD_DEC_USE_COUNT(void)
     /* [previous][next][first][last][top][bottom][index][help] */
  89 {
  90         MOD_DEC_USE_COUNT;
  91 }
  92 
  93 #if defined(ISDN_DEBUG_NET_DUMP) || defined(ISDN_DEBUG_MODEM_DUMP)
  94 void isdn_dumppkt(char *s, u_char * p, int len, int dumplen)
     /* [previous][next][first][last][top][bottom][index][help] */
  95 {
  96         int dumpc;
  97 
  98         printk(KERN_DEBUG "%s(%d) ", s, len);
  99         for (dumpc = 0; (dumpc < dumplen) && (len); len--, dumpc++)
 100                 printk(" %02x", *p++);
 101         printk("\n");
 102 }
 103 #endif
 104 
 105 /* Try to allocate a new buffer, link it into queue. */
 106 u_char *
 107  isdn_new_buf(pqueue ** queue, int length)
     /* [previous][next][first][last][top][bottom][index][help] */
 108 {
 109         pqueue *p;
 110         pqueue *q;
 111 
 112         if ((p = *queue)) {
 113                 while (p) {
 114                         q = p;
 115                         p = (pqueue *) p->next;
 116                 }
 117                 p = (pqueue *) kmalloc(sizeof(pqueue) + length, GFP_ATOMIC);
 118                 q->next = (u_char *) p;
 119         } else
 120                 p = *queue = (pqueue *) kmalloc(sizeof(pqueue) + length, GFP_ATOMIC);
 121         if (p) {
 122                 p->size = sizeof(pqueue) + length;
 123                 p->length = length;
 124                 p->next = NULL;
 125                 p->rptr = p->buffer;
 126                 return p->buffer;
 127         } else {
 128                 return (u_char *) NULL;
 129         }
 130 }
 131 
 132 static void isdn_free_queue(pqueue ** queue)
     /* [previous][next][first][last][top][bottom][index][help] */
 133 {
 134         pqueue *p;
 135         pqueue *q;
 136 
 137         p = *queue;
 138         while (p) {
 139                 q = p;
 140                 p = (pqueue *) p->next;
 141                 kfree_s(q, q->size);
 142         }
 143         *queue = (pqueue *) 0;
 144 }
 145 
 146 int isdn_dc2minor(int di, int ch)
     /* [previous][next][first][last][top][bottom][index][help] */
 147 {
 148         int i;
 149         for (i = 0; i < ISDN_MAX_CHANNELS; i++)
 150                 if (dev->chanmap[i] == ch && dev->drvmap[i] == di)
 151                         return i;
 152         return -1;
 153 }
 154 
 155 static int isdn_timer_cnt1 = 0;
 156 static int isdn_timer_cnt2 = 0;
 157 
 158 static void isdn_timer_funct(ulong dummy)
     /* [previous][next][first][last][top][bottom][index][help] */
 159 {
 160         int tf = dev->tflags;
 161 
 162         if (tf & ISDN_TIMER_FAST) {
 163                 if (tf & ISDN_TIMER_MODEMREAD)
 164                         isdn_tty_readmodem();
 165                 if (tf & ISDN_TIMER_MODEMPLUS)
 166                         isdn_tty_modem_escape();
 167                 if (tf & ISDN_TIMER_MODEMXMIT)
 168                         isdn_tty_modem_xmit();
 169         }
 170         if (tf & ISDN_TIMER_SLOW) {
 171                 if (++isdn_timer_cnt1 >= ISDN_TIMER_02SEC) {
 172                         isdn_timer_cnt1 = 0;
 173                         if (tf & ISDN_TIMER_NETDIAL)
 174                                 isdn_net_dial();
 175                 }
 176                 if (++isdn_timer_cnt2 >= ISDN_TIMER_1SEC) {
 177                         isdn_timer_cnt2 = 0;
 178                         if (tf & ISDN_TIMER_NETHANGUP)
 179                                 isdn_net_autohup();
 180                         if (tf & ISDN_TIMER_MODEMRING)
 181                                 isdn_tty_modem_ring();
 182 #if (defined CONFIG_ISDN_PPP ) && (defined ISDN_CONFIG_MPP)
 183                         if (tf & ISDN_TIMER_IPPP)
 184                                 isdn_ppp_timer_timeout();
 185 #endif
 186                 }
 187         }
 188         if (tf) {
 189                 int flags;
 190 
 191                 save_flags(flags);
 192                 cli();
 193                 del_timer(&dev->timer);
 194                 dev->timer.function = isdn_timer_funct;
 195                 dev->timer.expires = jiffies + ISDN_TIMER_RES;
 196                 add_timer(&dev->timer);
 197                 restore_flags(flags);
 198         }
 199 }
 200 
 201 void isdn_timer_ctrl(int tf, int onoff)
     /* [previous][next][first][last][top][bottom][index][help] */
 202 {
 203         int flags;
 204 
 205         save_flags(flags);
 206         cli();
 207         if ((tf & ISDN_TIMER_SLOW) && (!(dev->tflags & ISDN_TIMER_SLOW))) {
 208                 /* If the slow-timer wasn't activated until now */
 209                 isdn_timer_cnt1 = 0;
 210                 isdn_timer_cnt2 = 0;
 211         }
 212         if (onoff)
 213                 dev->tflags |= tf;
 214         else
 215                 dev->tflags &= ~tf;
 216         if (dev->tflags) {
 217                 del_timer(&dev->timer);
 218                 dev->timer.function = isdn_timer_funct;
 219                 dev->timer.expires = jiffies + ISDN_TIMER_RES;
 220                 add_timer(&dev->timer);
 221         }
 222         restore_flags(flags);
 223 }
 224 
 225 /* Receive a packet from B-Channel. (Called from low-level-module)
 226  * Parameters:
 227  *
 228  * di      = Driver-Index.
 229  * channel = Number of B-Channel (0...)
 230  * buf     = pointer to packet-data
 231  * len     = Length of packet-data
 232  *
 233  */
 234 static void isdn_receive_callback(int di, int channel, u_char * buf, int len)
     /* [previous][next][first][last][top][bottom][index][help] */
 235 {
 236         ulong flags;
 237         char *p;
 238         int i;
 239         int midx;
 240 
 241         if (dev->global_flags & ISDN_GLOBAL_STOPPED)
 242                 return;
 243         if ((i = isdn_dc2minor(di,channel))==-1)
 244                 return;
 245         /* Update statistics */
 246         dev->ibytes[i] += len;
 247         /* First, try to deliver data to network-device */
 248         if (isdn_net_receive_callback(i, buf, len))
 249                 return;
 250         /* No network-device found, deliver to tty or raw-channel */
 251         if (len) {
 252                 save_flags(flags);
 253                 cli();
 254                 midx = dev->m_idx[i];
 255                 if (dev->mdm.atmodem[midx].mdmreg[13] & 2)
 256                         /* T.70 decoding: Simply throw away the T.70 header (4 bytes) */
 257                         if ((buf[0] == 1) && ((buf[1] == 0) || (buf[1] == 1))) {
 258 #ifdef ISDN_DEBUG_MODEM_DUMP
 259                                 isdn_dumppkt("T70strip1:", buf, len, len);
 260 #endif
 261                                 buf += 4;
 262                                 len -= 4;
 263 #ifdef ISDN_DEBUG_MODEM_DUMP
 264                                 isdn_dumppkt("T70strip2:", buf, len, len);
 265 #endif
 266                         }
 267                 /* Try to deliver directly via tty-flip-buf if queue is empty */
 268                 if (!dev->drv[di]->rpqueue[channel])
 269                         if (isdn_tty_try_read(midx, buf, len)) {
 270                                 restore_flags(flags);
 271                                 return;
 272                         }
 273                 /* Direct deliver failed or queue wasn't empty.
 274                  * Queue up for later dequeueing via timer-irq.
 275                  */
 276                 p = isdn_new_buf(&dev->drv[di]->rpqueue[channel], len);
 277                 if (!p) {
 278                         printk(KERN_WARNING "isdn: malloc of rcvbuf failed, dropping.\n");
 279                         dev->drv[di]->rcverr[channel]++;
 280                         restore_flags(flags);
 281                         return;
 282                 } else {
 283                         memcpy(p, buf, len);
 284                         dev->drv[di]->rcvcount[channel] += len;
 285                 }
 286                 /* Schedule dequeuing */
 287                 if ((dev->modempoll) && (midx >= 0)) {
 288                         if (dev->mdm.rcvsched[midx])
 289                                 isdn_timer_ctrl(ISDN_TIMER_MODEMREAD, 1);
 290                 }
 291                 wake_up_interruptible(&dev->drv[di]->rcv_waitq[channel]);
 292                 restore_flags(flags);
 293         }
 294 }
 295 
 296 void isdn_all_eaz(int di, int ch)
     /* [previous][next][first][last][top][bottom][index][help] */
 297 {
 298         isdn_ctrl cmd;
 299 
 300         cmd.driver = di;
 301         cmd.arg = ch;
 302         cmd.command = ISDN_CMD_SETEAZ;
 303         cmd.num[0] = '\0';
 304         (void) dev->drv[di]->interface->command(&cmd);
 305 }
 306 
 307 static int isdn_status_callback(isdn_ctrl * c)
     /* [previous][next][first][last][top][bottom][index][help] */
 308 {
 309         int di;
 310         int mi;
 311         ulong flags;
 312         int i;
 313         int r;
 314         isdn_ctrl cmd;
 315 
 316         di = c->driver;
 317         i = isdn_dc2minor(di, c->arg);
 318         switch (c->command) {
 319                 case ISDN_STAT_BSENT:
 320                         if (i<0)
 321                                 return -1;
 322                         if (dev->global_flags & ISDN_GLOBAL_STOPPED)
 323                                 return 0;
 324                         if (isdn_net_stat_callback(i, c->command))
 325                                 return 0;
 326 #if FUTURE
 327                         isdn_tty_bsent(di, c->arg);
 328 #endif
 329                         wake_up_interruptible(&dev->drv[di]->snd_waitq[c->arg]);
 330                         break;
 331                 case ISDN_STAT_STAVAIL:
 332                         save_flags(flags);
 333                         cli();
 334                         dev->drv[di]->stavail += c->arg;
 335                         restore_flags(flags);
 336                         wake_up_interruptible(&dev->drv[di]->st_waitq);
 337                         break;
 338                 case ISDN_STAT_RUN:
 339                         dev->drv[di]->running = 1;
 340                         for (i = 0; i < ISDN_MAX_CHANNELS; i++)
 341                                 if (dev->drvmap[i] == di)
 342                                         isdn_all_eaz(di, dev->chanmap[i]);
 343                         break;
 344                 case ISDN_STAT_STOP:
 345                         dev->drv[di]->running = 0;
 346                         break;
 347                 case ISDN_STAT_ICALL:
 348                         if (i<0)
 349                                 return -1;
 350 #ifdef ISDN_DEBUG_STATCALLB
 351                         printk(KERN_DEBUG "ICALL (net): %d %ld %s\n", di, c->arg, c->num);
 352 #endif
 353                         if (dev->global_flags & ISDN_GLOBAL_STOPPED) {
 354                                 cmd.driver = di;
 355                                 cmd.arg = c->arg;
 356                                 cmd.command = ISDN_CMD_HANGUP;
 357                                 dev->drv[di]->interface->command(&cmd);
 358                                 return 0;
 359                         }
 360 
 361                         /* Try to find a network-interface which will accept incoming call */
 362                         r = isdn_net_find_icall(di, c->arg, i, c->num);
 363                         switch (r) {
 364                                 case 0:
 365                                         /* No network-device replies. Schedule RING-message to
 366                                          * tty and set RI-bit of modem-status.
 367                                          */
 368                                         if ((mi = isdn_tty_find_icall(di, c->arg, c->num)) >= 0) {
 369                                                 dev->mdm.msr[mi] |= UART_MSR_RI;
 370                                                 isdn_tty_modem_result(2, &dev->mdm.info[mi]);
 371                                                 isdn_timer_ctrl(ISDN_TIMER_MODEMRING, 1);
 372                                         } else if (dev->drv[di]->reject_bus) {
 373                                                 cmd.driver = di;
 374                                                 cmd.arg = c->arg;
 375                                                 cmd.command = ISDN_CMD_HANGUP;
 376                                                 dev->drv[di]->interface->command(&cmd);
 377                                         }
 378                                         break;
 379                                 case 1:
 380                                         /* Schedule connection-setup */
 381                                         isdn_net_dial();
 382                                         cmd.driver = di;
 383                                         cmd.arg = c->arg;
 384                                         cmd.command = ISDN_CMD_ACCEPTD;
 385                                         dev->drv[di]->interface->command(&cmd);
 386                                         break;
 387                                 case 2: /* For calling back, first reject incoming call ... */
 388                                 case 3: /* Interface found, but down, reject call actively  */
 389                                         printk(KERN_INFO "isdn: Rejecting Call\n");
 390                                         cmd.driver = di;
 391                                         cmd.arg = c->arg;
 392                                         cmd.command = ISDN_CMD_HANGUP;
 393                                         dev->drv[di]->interface->command(&cmd);
 394                                         if (r == 3)
 395                                                 break;
 396                                         /* Fall through */
 397                                 case 4:
 398                                         /* ... then start callback. */
 399                                         isdn_net_dial();
 400                         }
 401                         return 0;
 402                         break;
 403                 case ISDN_STAT_CINF:
 404                         if (i<0)
 405                                 return -1;
 406 #ifdef ISDN_DEBUG_STATCALLB
 407                         printk(KERN_DEBUG "CINF: %ld %s\n", c->arg, c->num);
 408 #endif
 409                         if (dev->global_flags & ISDN_GLOBAL_STOPPED)
 410                                 return 0;
 411                         if (strcmp(c->num, "0"))
 412                                 isdn_net_stat_callback(i, c->command);
 413                         break;
 414                 case ISDN_STAT_CAUSE:
 415 #ifdef ISDN_DEBUG_STATCALLB
 416                         printk(KERN_DEBUG "CAUSE: %ld %s\n", c->arg, c->num);
 417 #endif
 418                         printk(KERN_INFO "isdn: cause: %s\n", c->num);
 419                         break;
 420                 case ISDN_STAT_DCONN:
 421                         if (i<0)
 422                                 return -1;
 423 #ifdef ISDN_DEBUG_STATCALLB
 424                         printk(KERN_DEBUG "DCONN: %ld\n", c->arg);
 425 #endif
 426                         if (dev->global_flags & ISDN_GLOBAL_STOPPED)
 427                                 return 0;
 428                         /* Find any network-device, waiting for D-channel setup */
 429                         if (isdn_net_stat_callback(i, c->command))
 430                                 break;
 431                         if ((mi = dev->m_idx[i]) >= 0)
 432                                 /* If any tty has just dialed-out, setup B-Channel */
 433                                 if (dev->mdm.info[mi].flags &
 434                                     (ISDN_ASYNC_NORMAL_ACTIVE | ISDN_ASYNC_CALLOUT_ACTIVE)) {
 435                                         if (dev->mdm.dialing[mi] == 1) {
 436                                                 dev->mdm.dialing[mi] = 2;
 437                                                 cmd.driver = di;
 438                                                 cmd.arg = c->arg;
 439                                                 cmd.command = ISDN_CMD_ACCEPTB;
 440                                                 dev->drv[di]->interface->command(&cmd);
 441                                                 return 0;
 442                                         }
 443                                 }
 444                         break;
 445                 case ISDN_STAT_DHUP:
 446                         if (i<0)
 447                                 return -1;
 448 #ifdef ISDN_DEBUG_STATCALLB
 449                         printk(KERN_DEBUG "DHUP: %ld\n", c->arg);
 450 #endif
 451                         if (dev->global_flags & ISDN_GLOBAL_STOPPED)
 452                                 return 0;
 453                         dev->drv[di]->flags &= ~(1 << (c->arg));
 454                         isdn_info_update();
 455                         /* Signal hangup to network-devices */
 456                         if (isdn_net_stat_callback(i, c->command))
 457                                 break;
 458                         if ((mi = dev->m_idx[i]) >= 0) {
 459                                 /* Signal hangup to tty-device */
 460                                 if (dev->mdm.info[mi].flags &
 461                                     (ISDN_ASYNC_NORMAL_ACTIVE | ISDN_ASYNC_CALLOUT_ACTIVE)) {
 462                                         if (dev->mdm.dialing[mi] == 1) {
 463                                                 dev->mdm.dialing[mi] = 0;
 464                                                 isdn_tty_modem_result(7, &dev->mdm.info[mi]);
 465                                         }
 466                                         if (dev->mdm.online[mi])
 467                                                 isdn_tty_modem_result(3, &dev->mdm.info[mi]);
 468 #ifdef ISDN_DEBUG_MODEM_HUP
 469                                         printk(KERN_DEBUG "Mhup in ISDN_STAT_DHUP\n");
 470 #endif
 471                                         isdn_tty_modem_hup(&dev->mdm.info[mi]);
 472                                         dev->mdm.msr[mi] &= ~(UART_MSR_DCD | UART_MSR_RI);
 473                                         return 0;
 474                                 }
 475                         }
 476                         break;
 477                 case ISDN_STAT_BCONN:
 478                         if (i<0)
 479                                 return -1;
 480 #ifdef ISDN_DEBUG_STATCALLB
 481                         printk(KERN_DEBUG "BCONN: %ld\n", c->arg);
 482 #endif
 483                         /* Signal B-channel-connect to network-devices */
 484                         if (dev->global_flags & ISDN_GLOBAL_STOPPED)
 485                                 return 0;
 486                         dev->drv[di]->flags |= (1 << (c->arg));
 487                         isdn_info_update();
 488                         if (isdn_net_stat_callback(i, c->command))
 489                                 break;
 490                         if ((mi = dev->m_idx[i]) >= 0) {
 491                                 /* Schedule CONNECT-Message to any tty, waiting for it and
 492                                  * set DCD-bit of it's modem-status.
 493                                  */
 494                                 if (dev->mdm.info[mi].flags &
 495                                     (ISDN_ASYNC_NORMAL_ACTIVE | ISDN_ASYNC_CALLOUT_ACTIVE)) {
 496                                         dev->mdm.msr[mi] |= UART_MSR_DCD;
 497                                         if (dev->mdm.dialing[mi])
 498                                                 dev->mdm.dialing[mi] = 0;
 499                                         dev->mdm.rcvsched[mi] = 1;
 500                                         isdn_tty_modem_result(5, &dev->mdm.info[mi]);
 501                                 }
 502                         }
 503                         break;
 504                 case ISDN_STAT_BHUP:
 505                         if (i<0)
 506                                 return -1;
 507 #ifdef ISDN_DEBUG_STATCALLB
 508                         printk(KERN_DEBUG "BHUP: %ld\n", c->arg);
 509 #endif
 510                         if (dev->global_flags & ISDN_GLOBAL_STOPPED)
 511                                 return 0;
 512                         dev->drv[di]->flags &= ~(1 << (c->arg));
 513                         isdn_info_update();
 514                         if ((mi = dev->m_idx[i]) >= 0) {
 515                                 /* Signal hangup to tty-device, schedule NO CARRIER-message */
 516                                 if (dev->mdm.info[mi].flags &
 517                                     (ISDN_ASYNC_NORMAL_ACTIVE | ISDN_ASYNC_CALLOUT_ACTIVE)) {
 518                                         dev->mdm.msr[mi] &= ~(UART_MSR_DCD | UART_MSR_RI);
 519                                         if (dev->mdm.online[mi])
 520                                                 isdn_tty_modem_result(3, &dev->mdm.info[mi]);
 521 #ifdef ISDN_DEBUG_MODEM_HUP
 522                                         printk(KERN_DEBUG "Mhup in ISDN_STAT_BHUP\n");
 523 #endif
 524                                         isdn_tty_modem_hup(&dev->mdm.info[mi]);
 525                                 }
 526                         }
 527                         break;
 528                 case ISDN_STAT_NODCH:
 529                         if (i<0)
 530                                 return -1;
 531 #ifdef ISDN_DEBUG_STATCALLB
 532                         printk(KERN_DEBUG "NODCH: %ld\n", c->arg);
 533 #endif
 534                         if (dev->global_flags & ISDN_GLOBAL_STOPPED)
 535                                 return 0;
 536                         if (isdn_net_stat_callback(i, c->command))
 537                                 break;
 538                         if ((mi = dev->m_idx[i]) >= 0) {
 539                                 if (dev->mdm.info[mi].flags &
 540                                     (ISDN_ASYNC_NORMAL_ACTIVE | ISDN_ASYNC_CALLOUT_ACTIVE)) {
 541                                         if (dev->mdm.dialing[mi]) {
 542                                                 dev->mdm.dialing[mi] = 0;
 543                                                 isdn_tty_modem_result(6, &dev->mdm.info[mi]);
 544                                         }
 545                                         dev->mdm.msr[mi] &= ~UART_MSR_DCD;
 546                                         if (dev->mdm.online[mi]) {
 547                                                 isdn_tty_modem_result(3, &dev->mdm.info[mi]);
 548                                                 dev->mdm.online[mi] = 0;
 549                                         }
 550                                 }
 551                         }
 552                         break;
 553                 case ISDN_STAT_ADDCH:
 554                         break;
 555                 case ISDN_STAT_UNLOAD:
 556                         save_flags(flags);
 557                         cli();
 558                         for (i = 0; i < ISDN_MAX_CHANNELS; i++)
 559                                 if (dev->drvmap[i] == di) {
 560                                         dev->drvmap[i] = -1;
 561                                         dev->chanmap[i] = -1;
 562                                         dev->mdm.info[i].isdn_driver = -1;
 563                                         dev->mdm.info[i].isdn_channel = -1;
 564                                         isdn_info_update();
 565                                 }
 566                         dev->drivers--;
 567                         dev->channels -= dev->drv[di]->channels;
 568                         kfree(dev->drv[di]->rcverr);
 569                         kfree(dev->drv[di]->rcvcount);
 570                         for (i = 0; i < dev->drv[di]->channels; i++)
 571                                 isdn_free_queue(&dev->drv[di]->rpqueue[i]);
 572                         kfree(dev->drv[di]->rcv_waitq);
 573                         kfree(dev->drv[di]->snd_waitq);
 574                         kfree(dev->drv[di]);
 575                         dev->drv[di] = NULL;
 576                         dev->drvid[di][0] = '\0';
 577                         isdn_info_update();
 578                         restore_flags(flags);
 579                         return 0;
 580                 default:
 581                         return -1;
 582         }
 583         return 0;
 584 }
 585 
 586 /*
 587  * Get integer from char-pointer, set pointer to end of number
 588  */
 589 int isdn_getnum(char **p)
     /* [previous][next][first][last][top][bottom][index][help] */
 590 {
 591         int v = -1;
 592 
 593         while (*p[0] >= '0' && *p[0] <= '9')
 594                 v = ((v < 0) ? 0 : (v * 10)) + (int) ((*p[0]++) - '0');
 595         return v;
 596 }
 597 
 598 int isdn_readbchan(int di, int channel, u_char * buf, u_char * fp, int len, int user)
     /* [previous][next][first][last][top][bottom][index][help] */
 599 {
 600         int avail;
 601         int left;
 602         int count;
 603         int copy_l;
 604         int dflag;
 605         int flags;
 606         pqueue *p;
 607         u_char *cp;
 608 
 609         if (!dev->drv[di]->rpqueue[channel]) {
 610                 if (user)
 611                         interruptible_sleep_on(&dev->drv[di]->rcv_waitq[channel]);
 612                 else
 613                         return 0;
 614         }
 615         if (!dev->drv[di])
 616                 return 0;
 617         save_flags(flags);
 618         cli();
 619         avail = dev->drv[di]->rcvcount[channel];
 620         restore_flags(flags);
 621         left = MIN(len, avail);
 622         cp = buf;
 623         count = 0;
 624         while (left) {
 625                 if ((copy_l = dev->drv[di]->rpqueue[channel]->length) > left) {
 626                         copy_l = left;
 627                         dflag = 0;
 628                 } else
 629                         dflag = 1;
 630                 p = dev->drv[di]->rpqueue[channel];
 631                 if (user)
 632                         memcpy_tofs(cp, p->rptr, copy_l);
 633                 else
 634                         memcpy(cp, p->rptr, copy_l);
 635                 if (fp) {
 636                         memset(fp, 0, copy_l);
 637                         fp += copy_l;
 638                 }
 639                 left -= copy_l;
 640                 count += copy_l;
 641                 cp += copy_l;
 642                 if (dflag) {
 643                         if (fp)
 644                                 *(fp - 1) = 0xff;
 645                         save_flags(flags);
 646                         cli();
 647                         dev->drv[di]->rpqueue[channel] = (pqueue *) p->next;
 648                         kfree_s(p, p->size);
 649                         restore_flags(flags);
 650                 } else {
 651                         p->rptr += copy_l;
 652                         p->length -= copy_l;
 653                 }
 654                 save_flags(flags);
 655                 cli();
 656                 dev->drv[di]->rcvcount[channel] -= copy_l;
 657                 restore_flags(flags);
 658         }
 659         return count;
 660 }
 661 
 662 static __inline int isdn_minor2drv(int minor)
     /* [previous][next][first][last][top][bottom][index][help] */
 663 {
 664         return (dev->drvmap[minor]);
 665 }
 666 
 667 static __inline int isdn_minor2chan(int minor)
     /* [previous][next][first][last][top][bottom][index][help] */
 668 {
 669         return (dev->chanmap[minor]);
 670 }
 671 
 672 static char *
 673  isdn_statstr(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 674 {
 675         static char istatbuf[2048];
 676         char *p;
 677         int i;
 678 
 679         sprintf(istatbuf, "idmap:\t");
 680         p = istatbuf + strlen(istatbuf);
 681         for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
 682                 sprintf(p, "%s ", (dev->drvmap[i] < 0) ? "-" : dev->drvid[dev->drvmap[i]]);
 683                 p = istatbuf + strlen(istatbuf);
 684         }
 685         sprintf(p, "\nchmap:\t");
 686         p = istatbuf + strlen(istatbuf);
 687         for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
 688                 sprintf(p, "%d ", dev->chanmap[i]);
 689                 p = istatbuf + strlen(istatbuf);
 690         }
 691         sprintf(p, "\ndrmap:\t");
 692         p = istatbuf + strlen(istatbuf);
 693         for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
 694                 sprintf(p, "%d ", dev->drvmap[i]);
 695                 p = istatbuf + strlen(istatbuf);
 696         }
 697         sprintf(p, "\nusage:\t");
 698         p = istatbuf + strlen(istatbuf);
 699         for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
 700                 sprintf(p, "%d ", dev->usage[i]);
 701                 p = istatbuf + strlen(istatbuf);
 702         }
 703         sprintf(p, "\nflags:\t");
 704         p = istatbuf + strlen(istatbuf);
 705         for (i = 0; i < ISDN_MAX_DRIVERS; i++) {
 706                 if (dev->drv[i]) {
 707                         sprintf(p, "%ld ", dev->drv[i]->flags);
 708                         p = istatbuf + strlen(istatbuf);
 709                 } else {
 710                         sprintf(p, "? ");
 711                         p = istatbuf + strlen(istatbuf);
 712                 }
 713         }
 714         sprintf(p, "\nphone:\t");
 715         p = istatbuf + strlen(istatbuf);
 716         for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
 717                 sprintf(p, "%s ", dev->num[i]);
 718                 p = istatbuf + strlen(istatbuf);
 719         }
 720         sprintf(p, "\n");
 721         return istatbuf;
 722 }
 723 
 724 /* Module interface-code */
 725 
 726 void isdn_info_update(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 727 {
 728         infostruct *p = dev->infochain;
 729 
 730         while (p) {
 731                 *(p->private) = 1;
 732                 p = (infostruct *) p->next;
 733         }
 734         wake_up_interruptible(&(dev->info_waitq));
 735 }
 736 
 737 static int isdn_read(struct inode *inode, struct file *file, char *buf, int count)
     /* [previous][next][first][last][top][bottom][index][help] */
 738 {
 739         uint minor = MINOR(inode->i_rdev);
 740         int len = 0;
 741         ulong flags;
 742         int drvidx;
 743         int chidx;
 744 
 745         if (minor == ISDN_MINOR_STATUS) {
 746                 char *p;
 747                 if (!file->private_data) {
 748                         if (file->f_flags & O_NONBLOCK)
 749                                 return -EAGAIN;
 750                         interruptible_sleep_on(&(dev->info_waitq));
 751                 }
 752                 save_flags(flags);
 753                 p = isdn_statstr();
 754                 restore_flags(flags);
 755                 file->private_data = 0;
 756                 if ((len = strlen(p)) <= count) {
 757                         memcpy_tofs(buf, p, len);
 758                         file->f_pos += len;
 759                         return len;
 760                 }
 761                 return 0;
 762         }
 763         if (!dev->drivers)
 764                 return -ENODEV;
 765         if (minor < ISDN_MINOR_CTRL) {
 766                 drvidx = isdn_minor2drv(minor);
 767                 if (drvidx < 0)
 768                         return -ENODEV;
 769                 if (!dev->drv[drvidx]->running)
 770                         return -ENODEV;
 771                 chidx = isdn_minor2chan(minor);
 772                 len = isdn_readbchan(drvidx, chidx, buf, 0, count, 1);
 773                 file->f_pos += len;
 774                 return len;
 775         }
 776         if (minor <= ISDN_MINOR_CTRLMAX) {
 777                 drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL);
 778                 if (drvidx < 0)
 779                         return -ENODEV;
 780                 if (!dev->drv[drvidx]->stavail) {
 781                         if (file->f_flags & O_NONBLOCK)
 782                                 return -EAGAIN;
 783                         interruptible_sleep_on(&(dev->drv[drvidx]->st_waitq));
 784                 }
 785                 if (dev->drv[drvidx]->interface->readstat)
 786                         len = dev->drv[drvidx]->interface->
 787                             readstat(buf, MIN(count, dev->drv[drvidx]->stavail), 1);
 788                 else
 789                         len = 0;
 790                 save_flags(flags);
 791                 cli();
 792                 if (len)
 793                         dev->drv[drvidx]->stavail -= len;
 794                 else
 795                         dev->drv[drvidx]->stavail = 0;
 796                 restore_flags(flags);
 797                 file->f_pos += len;
 798                 return len;
 799         }
 800 #ifdef CONFIG_ISDN_PPP
 801         if (minor <= ISDN_MINOR_PPPMAX)
 802                 return (isdn_ppp_read(minor - ISDN_MINOR_PPP, file, buf, count));
 803 #endif
 804         return -ENODEV;
 805 }
 806 
 807 static int isdn_lseek(struct inode *inode, struct file *file, off_t offset, int orig)
     /* [previous][next][first][last][top][bottom][index][help] */
 808 {
 809         return -ESPIPE;
 810 }
 811 
 812 static int isdn_write(struct inode *inode, struct file *file, const char *buf, int count)
     /* [previous][next][first][last][top][bottom][index][help] */
 813 {
 814         uint minor = MINOR(inode->i_rdev);
 815         int drvidx;
 816         int chidx;
 817 
 818         if (minor == ISDN_MINOR_STATUS)
 819                 return -EPERM;
 820         if (!dev->drivers)
 821                 return -ENODEV;
 822         if (minor < ISDN_MINOR_CTRL) {
 823                 drvidx = isdn_minor2drv(minor);
 824                 if (drvidx < 0)
 825                         return -ENODEV;
 826                 if (!dev->drv[drvidx]->running)
 827                         return -ENODEV;
 828                 chidx = isdn_minor2chan(minor);
 829                 dev->obytes[minor] += count;
 830                 while (isdn_writebuf_stub(drvidx, chidx, buf, count, 1) != count)
 831                         interruptible_sleep_on(&dev->drv[drvidx]->snd_waitq[chidx]);
 832                 return count;
 833         }
 834         if (minor <= ISDN_MINOR_CTRLMAX) {
 835                 drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL);
 836                 if (drvidx < 0)
 837                         return -ENODEV;
 838                 /*
 839                  * We want to use the isdnctrl device to load the firmware
 840                  *
 841                  if (!dev->drv[drvidx]->running)
 842                  return -ENODEV;
 843                  */
 844                 if (dev->drv[drvidx]->interface->writecmd)
 845                         return (dev->drv[drvidx]->interface->writecmd(buf, count, 1));
 846                 else
 847                         return count;
 848         }
 849 #ifdef CONFIG_ISDN_PPP
 850         if (minor <= ISDN_MINOR_PPPMAX)
 851                 return (isdn_ppp_write(minor - ISDN_MINOR_PPP, file, buf, count));
 852 #endif
 853         return -ENODEV;
 854 }
 855 
 856 static int isdn_select(struct inode *inode, struct file *file, int type, select_table * st)
     /* [previous][next][first][last][top][bottom][index][help] */
 857 {
 858         uint minor = MINOR(inode->i_rdev);
 859 
 860         if (minor == ISDN_MINOR_STATUS) {
 861                 if (file->private_data)
 862                         return 1;
 863                 else {
 864                         if (st)
 865                                 select_wait(&(dev->info_waitq), st);
 866                         return 0;
 867                 }
 868         }
 869         if (minor <= ISDN_MINOR_CTRLMAX)
 870                 return 1;
 871 #ifdef CONFIG_ISDN_PPP
 872         if (minor <= ISDN_MINOR_PPPMAX)
 873                 return (isdn_ppp_select(minor - ISDN_MINOR_PPP, file, type, st));
 874 #endif
 875         return -ENODEV;
 876 }
 877 
 878 static int isdn_set_allcfg(char *src)
     /* [previous][next][first][last][top][bottom][index][help] */
 879 {
 880         int ret;
 881         int i;
 882         ulong flags;
 883         char buf[1024];
 884         isdn_net_ioctl_cfg cfg;
 885         isdn_net_ioctl_phone phone;
 886 
 887         if ((ret = isdn_net_rmall()))
 888                 return ret;
 889         save_flags(flags);
 890         cli();
 891         if ((ret = verify_area(VERIFY_READ, (void *) src, sizeof(int)))) {
 892                 restore_flags(flags);
 893                 return ret;
 894         }
 895         memcpy_tofs((char *) &i, src, sizeof(int));
 896         while (i) {
 897                 char *c;
 898                 char *c2;
 899 
 900                 if ((ret = verify_area(VERIFY_READ, (void *) src, sizeof(cfg)))) {
 901                         restore_flags(flags);
 902                         return ret;
 903                 }
 904                 memcpy_tofs((char *) &cfg, src, sizeof(cfg));
 905                 src += sizeof(cfg);
 906                 if (!isdn_net_new(cfg.name, NULL)) {
 907                         restore_flags(flags);
 908                         return -EIO;
 909                 }
 910                 if ((ret = isdn_net_setcfg(&cfg))) {
 911                         restore_flags(flags);
 912                         return ret;
 913                 }
 914                 if ((ret = verify_area(VERIFY_READ, (void *) src, sizeof(buf)))) {
 915                         restore_flags(flags);
 916                         return ret;
 917                 }
 918                 memcpy_fromfs(buf, src, sizeof(buf));
 919                 src += sizeof(buf);
 920                 c = buf;
 921                 while (*c) {
 922                         if ((c2 = strchr(c, ' ')))
 923                                 *c2++ = '\0';
 924                         strcpy(phone.phone, c);
 925                         strcpy(phone.name, cfg.name);
 926                         phone.outgoing = 0;
 927                         if ((ret = isdn_net_addphone(&phone))) {
 928                                 restore_flags(flags);
 929                                 return ret;
 930                         }
 931                         if (c2)
 932                                 c = c2;
 933                         else
 934                                 c += strlen(c);
 935                 }
 936                 if ((ret = verify_area(VERIFY_READ, (void *) src, sizeof(buf)))) {
 937                         restore_flags(flags);
 938                         return ret;
 939                 }
 940                 memcpy_fromfs(buf, src, sizeof(buf));
 941                 src += sizeof(buf);
 942                 c = buf;
 943                 while (*c) {
 944                         if ((c2 = strchr(c, ' ')))
 945                                 *c2++ = '\0';
 946                         strcpy(phone.phone, c);
 947                         strcpy(phone.name, cfg.name);
 948                         phone.outgoing = 1;
 949                         if ((ret = isdn_net_addphone(&phone))) {
 950                                 restore_flags(flags);
 951                                 return ret;
 952                         }
 953                         if (c2)
 954                                 c = c2;
 955                         else
 956                                 c += strlen(c);
 957                 }
 958                 i--;
 959         }
 960         restore_flags(flags);
 961         return 0;
 962 }
 963 
 964 static int isdn_get_allcfg(char *dest)
     /* [previous][next][first][last][top][bottom][index][help] */
 965 {
 966         isdn_net_ioctl_cfg cfg;
 967         isdn_net_ioctl_phone phone;
 968         isdn_net_dev *p;
 969         ulong flags;
 970         int ret;
 971 
 972         /* Walk through netdev-chain */
 973         save_flags(flags);
 974         cli();
 975         p = dev->netdev;
 976         while (p) {
 977                 if ((ret = verify_area(VERIFY_WRITE, (void *) dest, sizeof(cfg) + 10))) {
 978                         restore_flags(flags);
 979                         return ret;
 980                 }
 981                 strcpy(cfg.eaz, p->local.msn);
 982                 cfg.exclusive = p->local.exclusive;
 983                 if (p->local.pre_device >= 0) {
 984                         sprintf(cfg.drvid, "%s,%d", dev->drvid[p->local.pre_device],
 985                                 p->local.pre_channel);
 986                 } else
 987                         cfg.drvid[0] = '\0';
 988                 cfg.onhtime = p->local.onhtime;
 989                 cfg.charge = p->local.charge;
 990                 cfg.l2_proto = p->local.l2_proto;
 991                 cfg.l3_proto = p->local.l3_proto;
 992                 cfg.p_encap = p->local.p_encap;
 993                 cfg.secure = (p->local.flags & ISDN_NET_SECURE) ? 1 : 0;
 994                 cfg.callback = (p->local.flags & ISDN_NET_CALLBACK) ? 1 : 0;
 995                 cfg.chargehup = (p->local.hupflags & 4) ? 1 : 0;
 996                 cfg.ihup = (p->local.hupflags & 8) ? 1 : 0;
 997                 memcpy_tofs(dest, p->local.name, 10);
 998                 dest += 10;
 999                 memcpy_tofs(dest, (char *) &cfg, sizeof(cfg));
1000                 dest += sizeof(cfg);
1001                 strcpy(phone.name, p->local.name);
1002                 phone.outgoing = 0;
1003                 if ((ret = isdn_net_getphones(&phone, dest)) < 0) {
1004                         restore_flags(flags);
1005                         return ret;
1006                 } else
1007                         dest += ret;
1008                 strcpy(phone.name, p->local.name);
1009                 phone.outgoing = 1;
1010                 if ((ret = isdn_net_getphones(&phone, dest)) < 0) {
1011                         restore_flags(flags);
1012                         return ret;
1013                 } else
1014                         dest += ret;
1015                 p = p->next;
1016         }
1017         restore_flags(flags);
1018         return 0;
1019 }
1020 
1021 static int isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg)
     /* [previous][next][first][last][top][bottom][index][help] */
1022 {
1023         uint minor = MINOR(inode->i_rdev);
1024         isdn_ctrl c;
1025         int drvidx;
1026         int chidx;
1027         int ret;
1028         char *s;
1029         char name[10];
1030         char bname[21];
1031         isdn_ioctl_struct iocts;
1032         isdn_net_ioctl_phone phone;
1033         isdn_net_ioctl_cfg cfg;
1034 
1035         if (minor == ISDN_MINOR_STATUS) {
1036                 switch (cmd) {
1037                         case IIOCGETCPS:
1038                                 if (arg) {
1039                                         ulong *p = (ulong *)arg;
1040                                         int i;
1041                                         if ((ret = verify_area(VERIFY_WRITE, (void *) arg,
1042                                                                sizeof(ulong)*ISDN_MAX_CHANNELS*2)))
1043                                                 return ret;
1044                                         for (i = 0;i<ISDN_MAX_CHANNELS;i++) {
1045                                                 put_fs_long(dev->ibytes[i],p++);
1046                                                 put_fs_long(dev->obytes[i],p++);
1047                                         }
1048                                         return 0;
1049                                 } else
1050                                         return -EINVAL;
1051                                 break;
1052                         default:
1053                                 return -EINVAL;
1054                 }
1055         }
1056         if (!dev->drivers)
1057                 return -ENODEV;
1058         if (minor < ISDN_MINOR_CTRL) {
1059                 drvidx = isdn_minor2drv(minor);
1060                 if (drvidx < 0)
1061                         return -ENODEV;
1062                 chidx = isdn_minor2chan(minor);
1063                 if (!dev->drv[drvidx]->running)
1064                         return -ENODEV;
1065                 return 0;
1066         }
1067         if (minor <= ISDN_MINOR_CTRLMAX) {
1068                 switch (cmd) {
1069 #ifdef CONFIG_NETDEVICES
1070                         case IIOCNETAIF:
1071                                 /* Add a network-interface */
1072                                 if (arg) {
1073                                         if ((ret = verify_area(VERIFY_READ, (void *) arg, sizeof(name))))
1074                                                 return ret;
1075                                         memcpy_fromfs(name, (char *) arg, sizeof(name));
1076                                         s = name;
1077                                 } else
1078                                         s = NULL;
1079                                 if ((s = isdn_net_new(s, NULL))) {
1080                                         if ((ret = verify_area(VERIFY_WRITE, (void *) arg, strlen(s) + 1)))
1081                                                 return ret;
1082                                         memcpy_tofs((char *) arg, s, strlen(s) + 1);
1083                                         return 0;
1084                                 } else
1085                                         return -ENODEV;
1086                         case IIOCNETASL:
1087                                 /* Add a slave to a network-interface */
1088                                 if (arg) {
1089                                         if ((ret = verify_area(VERIFY_READ, (void *) arg, sizeof(bname))))
1090                                                 return ret;
1091                                         memcpy_fromfs(bname, (char *) arg, sizeof(bname));
1092                                 } else
1093                                         return -EINVAL;
1094                                 if ((s = isdn_net_newslave(bname))) {
1095                                         if ((ret = verify_area(VERIFY_WRITE, (void *) arg, strlen(s) + 1)))
1096                                                 return ret;
1097                                         memcpy_tofs((char *) arg, s, strlen(s) + 1);
1098                                         return 0;
1099                                 } else
1100                                         return -ENODEV;
1101                         case IIOCNETDIF:
1102                                 /* Delete a network-interface */
1103                                 if (arg) {
1104                                         if ((ret = verify_area(VERIFY_READ, (void *) arg, sizeof(name))))
1105                                                 return ret;
1106                                         memcpy_fromfs(name, (char *) arg, sizeof(name));
1107                                         return isdn_net_rm(name);
1108                                 } else
1109                                         return -EINVAL;
1110                         case IIOCNETSCF:
1111                                 /* Set configurable parameters of a network-interface */
1112                                 if (arg) {
1113                                         if ((ret = verify_area(VERIFY_READ, (void *) arg, sizeof(cfg))))
1114                                                 return ret;
1115                                         memcpy_fromfs((char *) &cfg, (char *) arg, sizeof(cfg));
1116                                         return isdn_net_setcfg(&cfg);
1117                                 } else
1118                                         return -EINVAL;
1119                         case IIOCNETGCF:
1120                                 /* Get configurable parameters of a network-interface */
1121                                 if (arg) {
1122                                         if ((ret = verify_area(VERIFY_READ, (void *) arg, sizeof(cfg))))
1123                                                 return ret;
1124                                         memcpy_fromfs((char *) &cfg, (char *) arg, sizeof(cfg));
1125                                         if (!(ret = isdn_net_getcfg(&cfg))) {
1126                                                 if ((ret = verify_area(VERIFY_WRITE, (void *) arg, sizeof(cfg))))
1127                                                         return ret;
1128                                                 memcpy_tofs((char *) arg, (char *) &cfg, sizeof(cfg));
1129                                         }
1130                                         return ret;
1131                                 } else
1132                                         return -EINVAL;
1133                         case IIOCNETANM:
1134                                 /* Add a phone-number to a network-interface */
1135                                 if (arg) {
1136                                         if ((ret = verify_area(VERIFY_READ, (void *) arg, sizeof(phone))))
1137                                                 return ret;
1138                                         memcpy_fromfs((char *) &phone, (char *) arg, sizeof(phone));
1139                                         return isdn_net_addphone(&phone);
1140                                 } else
1141                                         return -EINVAL;
1142                         case IIOCNETGNM:
1143                                 /* Get list of phone-numbers of a network-interface */
1144                                 if (arg) {
1145                                         if ((ret = verify_area(VERIFY_READ, (void *) arg, sizeof(phone))))
1146                                                 return ret;
1147                                         memcpy_fromfs((char *) &phone, (char *) arg, sizeof(phone));
1148                                         return isdn_net_getphones(&phone, (char *) arg);
1149                                 } else
1150                                         return -EINVAL;
1151                         case IIOCNETDNM:
1152                                 /* Delete a phone-number of a network-interface */
1153                                 if (arg) {
1154                                         memcpy_fromfs((char *) &phone, (char *) arg, sizeof(phone));
1155                                         if ((ret = verify_area(VERIFY_READ, (void *) arg, sizeof(phone))))
1156                                                 return ret;
1157                                         return isdn_net_delphone(&phone);
1158                                 } else
1159                                         return -EINVAL;
1160                         case IIOCNETDIL:
1161                                 /* Force dialing of a network-interface */
1162                                 if (arg) {
1163                                         if ((ret = verify_area(VERIFY_READ, (void *) arg, sizeof(name))))
1164                                                 return ret;
1165                                         memcpy_fromfs(name, (char *) arg, sizeof(name));
1166                                         return isdn_net_force_dial(name);
1167                                 } else
1168                                         return -EINVAL;
1169 #ifdef CONFIG_ISDN_PPP
1170                         case IIOCNETALN:
1171                                 if(arg) {
1172                                         if ((ret = verify_area(VERIFY_READ,
1173                                                                (void*)arg,
1174                                                                sizeof(name))))
1175                                                 return ret;
1176                                 } else
1177                                         return -EINVAL;
1178                                 memcpy_fromfs(name,(char*)arg,sizeof(name));
1179                                 return isdn_ppp_dial_slave(name);
1180                         case IIOCNETDLN:
1181                                 /* remove one link from bundle; removed for i4l 0.7.1  */
1182                                 return 2;
1183 #endif
1184                         case IIOCNETHUP:
1185                                 /* Force hangup of a network-interface */
1186                                 if (arg) {
1187                                         if ((ret = verify_area(VERIFY_READ, (void *) arg, sizeof(name))))
1188                                                 return ret;
1189                                         memcpy_fromfs(name, (char *) arg, sizeof(name));
1190                                         return isdn_net_force_hangup(name);
1191                                 } else
1192                                         return -EINVAL;
1193                                 break;
1194 #endif                          /* CONFIG_NETDEVICES */
1195                         case IIOCSETVER:
1196                                 dev->net_verbose = arg;
1197                                 printk(KERN_INFO "isdn: Verbose-Level is %d\n", dev->net_verbose);
1198                                 return 0;
1199                         case IIOCSETGST:
1200                                 if (arg)
1201                                         dev->global_flags |= ISDN_GLOBAL_STOPPED;
1202                                 else
1203                                         dev->global_flags &= ~ISDN_GLOBAL_STOPPED;
1204                                 printk(KERN_INFO "isdn: Global Mode %s\n",
1205                                        (dev->global_flags & ISDN_GLOBAL_STOPPED) ? "stopped" : "running");
1206                                 return 0;
1207                         case IIOCSETBRJ:
1208                                 drvidx = -1;
1209                                 if (arg) {
1210                                         int i;
1211                                         char *p;
1212                                         if ((ret = verify_area(VERIFY_READ, (void *) arg,
1213                                                                sizeof(isdn_ioctl_struct))))
1214                                                 return ret;
1215                                         memcpy_fromfs((char *) &iocts, (char *) arg, sizeof(isdn_ioctl_struct));
1216                                         if (strlen(iocts.drvid)) {
1217                                                 if ((p = strchr(iocts.drvid, ',')))
1218                                                         *p = 0;
1219                                                 drvidx = -1;
1220                                                 for (i = 0; i < ISDN_MAX_DRIVERS; i++)
1221                                                         if (!(strcmp(dev->drvid[i], iocts.drvid))) {
1222                                                                 drvidx = i;
1223                                                                 break;
1224                                                         }
1225                                         }
1226                                 }
1227                                 if (drvidx == -1)
1228                                         return -ENODEV;
1229                                 dev->drv[drvidx]->reject_bus = iocts.arg;
1230                                 return 0;
1231                         case IIOCGETSET:
1232                                 /* Get complete setup (all network-interfaces and profile-
1233                                    settings of all tty-devices */
1234                                 if (arg)
1235                                         return (isdn_get_allcfg((char *) arg));
1236                                 else
1237                                         return -EINVAL;
1238                                 break;
1239                         case IIOCSETSET:
1240                                 /* Set complete setup (all network-interfaces and profile-
1241                                    settings of all tty-devices */
1242                                 if (arg)
1243                                         return (isdn_set_allcfg((char *) arg));
1244                                 else
1245                                         return -EINVAL;
1246                                 break;
1247                         case IIOCSIGPRF:
1248                                 dev->profd = current;
1249                                 return 0;
1250                                 break;
1251                         case IIOCGETPRF:
1252                                 /* Get all Modem-Profiles */
1253                                 if (arg) {
1254                                         char *p = (char *) arg;
1255                                         int i;
1256                                         
1257                                         if ((ret = verify_area(VERIFY_WRITE, (void *) arg,
1258                                                                (ISDN_MODEM_ANZREG + ISDN_MSNLEN)
1259                                                                * ISDN_MAX_CHANNELS)))
1260                                                 return ret;
1261                                         
1262                                         for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
1263                                                 memcpy_tofs(p, dev->mdm.atmodem[i].profile, ISDN_MODEM_ANZREG);
1264                                                 p += ISDN_MODEM_ANZREG;
1265                                                 memcpy_tofs(p, dev->mdm.atmodem[i].pmsn, ISDN_MSNLEN);
1266                                                 p += ISDN_MSNLEN;
1267                                         }
1268                                         return (ISDN_MODEM_ANZREG + ISDN_MSNLEN) * ISDN_MAX_CHANNELS;
1269                                 } else
1270                                         return -EINVAL;
1271                                 break;
1272                         case IIOCSETPRF:
1273                                 /* Set all Modem-Profiles */
1274                                 if (arg) {
1275                                         char *p = (char *) arg;
1276                                         int i;
1277                                         
1278                                         if ((ret = verify_area(VERIFY_READ, (void *) arg,
1279                                                                (ISDN_MODEM_ANZREG + ISDN_MSNLEN)
1280                                                                * ISDN_MAX_CHANNELS)))
1281                                                 return ret;
1282                                         
1283                                         for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
1284                                                 memcpy_fromfs(dev->mdm.atmodem[i].profile, p, ISDN_MODEM_ANZREG);
1285                                                 p += ISDN_MODEM_ANZREG;
1286                                                 memcpy_fromfs(dev->mdm.atmodem[i].pmsn, p, ISDN_MSNLEN);
1287                                                 p += ISDN_MSNLEN;
1288                                         }
1289                                         return 0;
1290                                 } else
1291                                         return -EINVAL;
1292                                 break;
1293                         case IIOCSETMAP:
1294                         case IIOCGETMAP:
1295                                 /* Set/Get MSN->EAZ-Mapping for a driver */
1296                                 if (arg) {
1297                                         int i;
1298                                         char *p;
1299                                         char nstring[255];
1300                                         
1301                                         if ((ret = verify_area(VERIFY_READ, (void *) arg,
1302                                                                sizeof(isdn_ioctl_struct))))
1303                                                 return ret;
1304                                         memcpy_fromfs((char *) &iocts, (char *) arg, sizeof(isdn_ioctl_struct));
1305                                         if (strlen(iocts.drvid)) {
1306                                                 drvidx = -1;
1307                                                 for (i = 0; i < ISDN_MAX_DRIVERS; i++)
1308                                                         if (!(strcmp(dev->drvid[i], iocts.drvid))) {
1309                                                                 drvidx = i;
1310                                                                 break;
1311                                                         }
1312                                         } else
1313                                                 drvidx = 0;
1314                                         if (drvidx == -1)
1315                                                 return -ENODEV;
1316                                         if (cmd == IIOCSETMAP) {
1317                                                 if ((ret = verify_area(VERIFY_READ, (void *) iocts.arg, 255)))
1318                                                         return ret;
1319                                                 memcpy_fromfs(nstring, (char *) iocts.arg, 255);
1320                                                 memset(dev->drv[drvidx]->msn2eaz, 0,
1321                                                        sizeof(dev->drv[drvidx]->msn2eaz));
1322                                                 p = strtok(nstring, ",");
1323                                                 i = 0;
1324                                                 while ((p) && (i < 10)) {
1325                                                         strcpy(dev->drv[drvidx]->msn2eaz[i++], p);
1326                                                         p = strtok(NULL, ",");
1327                                                 }
1328                                         } else {
1329                                                 p = nstring;
1330                                                 for (i = 0; i < 10; i++)
1331                                                         p += sprintf(p, "%s%s",
1332                                                                      strlen(dev->drv[drvidx]->msn2eaz[i]) ?
1333                                                                      dev->drv[drvidx]->msn2eaz[i] : "-",
1334                                                                      (i < 9) ? "," : "\0");
1335                                                 if ((ret = verify_area(VERIFY_WRITE, (void *) iocts.arg,
1336                                                                        strlen(nstring) + 1)))
1337                                                         return ret;
1338                                                 memcpy_tofs((char *) iocts.arg, nstring, strlen(nstring) + 1);
1339                                         }
1340                                         return 0;
1341                                 } else
1342                                         return -EINVAL;
1343                         case IIOCDBGVAR:
1344                                 if (arg) {
1345                                         if ((ret = verify_area(VERIFY_WRITE, (void *) arg, sizeof(ulong))))
1346                                                 return ret;
1347                                         memcpy_tofs((char *) arg, (char *) &dev, sizeof(ulong));
1348                                         return 0;
1349                                 } else
1350                                         return -EINVAL;
1351                                 break;
1352                         default:
1353                                 if ((cmd&IIOCDRVCTL)==IIOCDRVCTL)
1354                                         cmd = ((cmd>>_IOC_NRSHIFT)&_IOC_NRMASK)& ISDN_DRVIOCTL_MASK;
1355                                 else
1356                                         return -EINVAL;
1357                                 if (arg) {
1358                                         int i;
1359                                         char *p;
1360                                         if ((ret = verify_area(VERIFY_READ, (void *) arg,
1361                                                                sizeof(isdn_ioctl_struct))))
1362                                                 return ret;
1363                                         memcpy_fromfs((char *) &iocts, (char *) arg, sizeof(isdn_ioctl_struct));
1364                                         if (strlen(iocts.drvid)) {
1365                                                 if ((p = strchr(iocts.drvid, ',')))
1366                                                         *p = 0;
1367                                                 drvidx = -1;
1368                                                 for (i = 0; i < ISDN_MAX_DRIVERS; i++)
1369                                                         if (!(strcmp(dev->drvid[i], iocts.drvid))) {
1370                                                                 drvidx = i;
1371                                                                 break;
1372                                                         }
1373                                         } else
1374                                                 drvidx = 0;
1375                                         if (drvidx == -1)
1376                                                 return -ENODEV;
1377                                         if ((ret = verify_area(VERIFY_WRITE, (void *) arg,
1378                                                                sizeof(isdn_ioctl_struct))))
1379                                                 return ret;
1380                                         c.driver = drvidx;
1381                                         c.command = ISDN_CMD_IOCTL;
1382                                         c.arg = cmd;
1383                                         memcpy(c.num, (char *) &iocts.arg, sizeof(ulong));
1384                                         ret = dev->drv[drvidx]->interface->command(&c);
1385                                         memcpy((char *) &iocts.arg, c.num, sizeof(ulong));
1386                                         memcpy_tofs((char *) arg, &iocts, sizeof(isdn_ioctl_struct));
1387                                         return ret;
1388                                 } else
1389                                         return -EINVAL;
1390                 }
1391         }
1392 #ifdef CONFIG_ISDN_PPP
1393         if (minor <= ISDN_MINOR_PPPMAX)
1394                 return (isdn_ppp_ioctl(minor - ISDN_MINOR_PPP, file, cmd, arg));
1395 #endif
1396         return -ENODEV;
1397 }
1398 
1399 /*
1400  * Open the device code.
1401  * MOD_INC_USE_COUNT make sure that the driver memory is not freed
1402  * while the device is in use.
1403  */
1404 static int isdn_open(struct inode *ino, struct file *filep)
     /* [previous][next][first][last][top][bottom][index][help] */
1405 {
1406         uint minor = MINOR(ino->i_rdev);
1407         int drvidx;
1408         int chidx;
1409         isdn_ctrl c;
1410 
1411         if (minor == ISDN_MINOR_STATUS) {
1412                 infostruct *p;
1413                 if ((p = (infostruct *) kmalloc(sizeof(infostruct), GFP_KERNEL))) {
1414                         MOD_INC_USE_COUNT;
1415                         p->next = (char *) dev->infochain;
1416                         p->private = (char *) &(filep->private_data);
1417                         dev->infochain = p;
1418                         /* At opening we allow a single update */
1419                         filep->private_data = (char *) 1;
1420                         return 0;
1421                 } else
1422                         return -ENOMEM;
1423         }
1424         if (!dev->channels)
1425                 return -ENODEV;
1426         if (minor < ISDN_MINOR_CTRL) {
1427                 drvidx = isdn_minor2drv(minor);
1428                 if (drvidx < 0)
1429                         return -ENODEV;
1430                 chidx = isdn_minor2chan(minor);
1431                 if (!dev->drv[drvidx]->running)
1432                         return -ENODEV;
1433                 if (!(dev->drv[drvidx]->flags & (1 << chidx)))
1434                         return -ENODEV;
1435                 c.command = ISDN_CMD_LOCK;
1436                 c.driver = drvidx;
1437                 (void) dev->drv[drvidx]->interface->command(&c);
1438                 MOD_INC_USE_COUNT;
1439                 return 0;
1440         }
1441         if (minor <= ISDN_MINOR_CTRLMAX) {
1442                 drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL);
1443                 if (drvidx < 0)
1444                         return -ENODEV;
1445                 c.command = ISDN_CMD_LOCK;
1446                 c.driver = drvidx;
1447                 MOD_INC_USE_COUNT;
1448                 (void) dev->drv[drvidx]->interface->command(&c);
1449                 return 0;
1450         }
1451 #ifdef CONFIG_ISDN_PPP
1452         if (minor <= ISDN_MINOR_PPPMAX) {
1453                 int ret;
1454                 if (!(ret = isdn_ppp_open(minor - ISDN_MINOR_PPP, filep)))
1455                         MOD_INC_USE_COUNT;
1456                 return ret;
1457         }
1458 #endif
1459         return -ENODEV;
1460 }
1461 
1462 static void isdn_close(struct inode *ino, struct file *filep)
     /* [previous][next][first][last][top][bottom][index][help] */
1463 {
1464         uint minor = MINOR(ino->i_rdev);
1465         int drvidx;
1466         isdn_ctrl c;
1467 
1468         if (minor == ISDN_MINOR_STATUS) {
1469                 infostruct *p = dev->infochain;
1470                 infostruct *q = NULL;
1471                 MOD_DEC_USE_COUNT;
1472                 while (p) {
1473                         if (p->private == (char *) &(filep->private_data)) {
1474                                 if (q)
1475                                         q->next = p->next;
1476                                 else
1477                                         dev->infochain = (infostruct *) (p->next);
1478                                 return;
1479                         }
1480                         q = p;
1481                         p = (infostruct *) (p->next);
1482                 }
1483                 printk(KERN_WARNING "isdn: No private data while closing isdnctrl\n");
1484                 return;
1485         }
1486         if (!dev->channels)
1487                 return;
1488         MOD_DEC_USE_COUNT;
1489         if (minor < ISDN_MINOR_CTRL) {
1490                 drvidx = isdn_minor2drv(minor);
1491                 if (drvidx < 0)
1492                         return;
1493                 c.command = ISDN_CMD_UNLOCK;
1494                 c.driver = drvidx;
1495                 (void) dev->drv[drvidx]->interface->command(&c);
1496                 return;
1497         }
1498         if (minor <= ISDN_MINOR_CTRLMAX) {
1499                 drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL);
1500                 if (drvidx < 0)
1501                         return;
1502                 if (dev->profd == current)
1503                         dev->profd = NULL;
1504                 c.command = ISDN_CMD_UNLOCK;
1505                 c.driver = drvidx;
1506                 (void) dev->drv[drvidx]->interface->command(&c);
1507                 return;
1508         }
1509 #ifdef CONFIG_ISDN_PPP
1510         if (minor <= ISDN_MINOR_PPPMAX)
1511                 isdn_ppp_release(minor - ISDN_MINOR_PPP, filep);
1512 #endif
1513 }
1514 
1515 static struct file_operations isdn_fops =
1516 {
1517         isdn_lseek,
1518         isdn_read,
1519         isdn_write,
1520         NULL,                   /* isdn_readdir */
1521         isdn_select,            /* isdn_select */
1522         isdn_ioctl,             /* isdn_ioctl */
1523         NULL,                   /* isdn_mmap */
1524         isdn_open,
1525         isdn_close,
1526         NULL                    /* fsync */
1527 };
1528 
1529 char *
1530  isdn_map_eaz2msn(char *msn, int di)
     /* [previous][next][first][last][top][bottom][index][help] */
1531 {
1532         driver *this = dev->drv[di];
1533         int i;
1534 
1535         if (strlen(msn) == 1) {
1536                 i = msn[0] - '0';
1537                 if ((i >= 0) && (i <= 9))
1538                         if (strlen(this->msn2eaz[i]))
1539                                 return (this->msn2eaz[i]);
1540         }
1541         return (msn);
1542 }
1543 
1544 /*
1545  * Find an unused ISDN-channel, whose feature-flags match the
1546  * given L2- and L3-protocols.
1547  */
1548 int isdn_get_free_channel(int usage, int l2_proto, int l3_proto, int pre_dev
     /* [previous][next][first][last][top][bottom][index][help] */
1549                      ,int pre_chan)
1550 {
1551         int i;
1552         ulong flags;
1553         ulong features;
1554 
1555         save_flags(flags);
1556         cli();
1557         features = (1 << l2_proto) | (0x100 << l3_proto);
1558         for (i = 0; i < ISDN_MAX_CHANNELS; i++)
1559                 if (USG_NONE(dev->usage[i]) &&
1560                     (dev->drvmap[i] != -1)) {
1561                         int d = dev->drvmap[i];
1562                         if ((dev->usage[i] & ISDN_USAGE_EXCLUSIVE) &&
1563                         ((pre_dev != d) || (pre_chan != dev->chanmap[i])))
1564                                 continue;
1565                         if ((dev->drv[d]->running)) {
1566                                 if ((dev->drv[d]->interface->features & features) == features) {
1567                                         if ((pre_dev < 0) || (pre_chan < 0)) {
1568                                                 dev->usage[i] &= ISDN_USAGE_EXCLUSIVE;
1569                                                 dev->usage[i] |= usage;
1570                                                 isdn_info_update();
1571                                                 restore_flags(flags);
1572                                                 return i;
1573                                         } else {
1574                                                 if ((pre_dev == d) && (pre_chan == dev->chanmap[i])) {
1575                                                         dev->usage[i] &= ISDN_USAGE_EXCLUSIVE;
1576                                                         dev->usage[i] |= usage;
1577                                                         isdn_info_update();
1578                                                         restore_flags(flags);
1579                                                         return i;
1580                                                 }
1581                                         }
1582                                 }
1583                         }
1584                 }
1585         restore_flags(flags);
1586         return -1;
1587 }
1588 
1589 /*
1590  * Set state of ISDN-channel to 'unused'
1591  */
1592 void isdn_free_channel(int di, int ch, int usage)
     /* [previous][next][first][last][top][bottom][index][help] */
1593 {
1594         int i;
1595         ulong flags;
1596 
1597         save_flags(flags);
1598         cli();
1599         for (i = 0; i < ISDN_MAX_CHANNELS; i++)
1600                 if (((dev->usage[i] & ISDN_USAGE_MASK) == usage) &&
1601                     (dev->drvmap[i] == di) &&
1602                     (dev->chanmap[i] == ch)) {
1603                         dev->usage[i] &= (ISDN_USAGE_NONE | ISDN_USAGE_EXCLUSIVE);
1604                         strcpy(dev->num[i], "???");
1605                         dev->ibytes[i] = 0;
1606                         dev->obytes[i] = 0;
1607                         isdn_info_update();
1608                         restore_flags(flags);
1609                         return;
1610                 }
1611         restore_flags(flags);
1612 }
1613 
1614 /*
1615  * Cancel Exclusive-Flag for ISDN-channel
1616  */
1617 void isdn_unexclusive_channel(int di, int ch)
     /* [previous][next][first][last][top][bottom][index][help] */
1618 {
1619         int i;
1620         ulong flags;
1621 
1622         save_flags(flags);
1623         cli();
1624         for (i = 0; i < ISDN_MAX_CHANNELS; i++)
1625                 if ((dev->drvmap[i] == di) &&
1626                     (dev->chanmap[i] == ch)) {
1627                         dev->usage[i] &= ~ISDN_USAGE_EXCLUSIVE;
1628                         isdn_info_update();
1629                         restore_flags(flags);
1630                         return;
1631                 }
1632         restore_flags(flags);
1633 }
1634 
1635 /*
1636  *  receive callback handler for drivers supporting sk_buff's.
1637  */
1638 
1639 void isdn_receive_skb_callback(int drvidx, int chan, struct sk_buff *skb) 
     /* [previous][next][first][last][top][bottom][index][help] */
1640 {
1641         int i, len;
1642 
1643         if (dev->global_flags & ISDN_GLOBAL_STOPPED)
1644                 return;
1645         if ((i = isdn_dc2minor(drvidx,chan))==-1)
1646                 return;
1647         len = skb->len;
1648         if (isdn_net_rcv_skb(i, skb) == 0) {
1649                 isdn_receive_callback(drvidx, chan, skb->data, skb->len);
1650                 skb->free = 1;
1651                 kfree_skb(skb, FREE_READ);
1652         } else
1653                 /* Update statistics */
1654                 dev->ibytes[i] += len;
1655 }
1656 
1657 /*
1658  *  writebuf replacement for SKB_ABLE drivers
1659  */
1660 
1661 int isdn_writebuf_stub(int drvidx, int chan, const u_char *buf, int len, 
     /* [previous][next][first][last][top][bottom][index][help] */
1662                        int user)
1663 {
1664         if (dev->drv[drvidx]->interface->writebuf)
1665           return dev->drv[drvidx]->interface->writebuf(drvidx, chan, buf,
1666                                                        len, user);
1667         else {
1668           struct sk_buff * skb;
1669 
1670           skb = alloc_skb(dev->drv[drvidx]->interface->hl_hdrlen + len, GFP_ATOMIC);
1671           if (skb == NULL)
1672                   return 0;
1673 
1674           skb_reserve(skb, dev->drv[drvidx]->interface->hl_hdrlen);
1675           skb->free = 1;
1676 
1677           if (user)
1678                   memcpy_fromfs(skb_put(skb, len), buf, len);
1679           else
1680                   memcpy(skb_put(skb, len), buf, len);
1681 
1682           return dev->drv[drvidx]->interface->writebuf_skb(drvidx, chan, skb);
1683         }
1684 }
1685 
1686 /*
1687  * writebuf_skb replacement for NON SKB_ABLE drivers
1688  * If lowlevel-device does not support supports skbufs, use
1689  * standard send-routine, else sind directly.
1690  *
1691  * Return: length of data on success, -ERRcode on failure.
1692  */
1693 
1694 int isdn_writebuf_skb_stub(int drvidx, int chan, struct sk_buff * skb)
     /* [previous][next][first][last][top][bottom][index][help] */
1695 {
1696         int ret;
1697 
1698         if (dev->drv[drvidx]->interface->writebuf_skb) 
1699                 ret = dev->drv[drvidx]->interface->
1700                         writebuf_skb(drvidx, chan, skb);
1701         else {        
1702                 if ((ret = dev->drv[drvidx]->interface->
1703                      writebuf(drvidx,chan,skb->data,skb->len,0))==skb->len)
1704                         dev_kfree_skb(skb, FREE_WRITE);
1705         }
1706         return ret;
1707 }
1708 
1709 /*
1710  * Low-level-driver registration
1711  */
1712 
1713 int register_isdn(isdn_if * i)
     /* [previous][next][first][last][top][bottom][index][help] */
1714 {
1715         driver *d;
1716         int n, j, k;
1717         ulong flags;
1718         int drvidx;
1719 
1720         if (dev->drivers >= ISDN_MAX_DRIVERS) {
1721                 printk(KERN_WARNING "register_isdn: Max. %d drivers supported\n",
1722                        ISDN_MAX_DRIVERS);
1723                 return 0;
1724         }
1725         n = i->channels;
1726         if (dev->channels + n > ISDN_MAX_CHANNELS) {
1727                 printk(KERN_WARNING "register_isdn: Max. %d channels supported\n",
1728                        ISDN_MAX_CHANNELS);
1729                 return 0;
1730         }
1731         if ((!i->writebuf_skb) && (!i->writebuf)) {
1732                 printk(KERN_WARNING "register_isdn: No write routine given.\n");
1733                 return 0;
1734         }
1735         if (!(d = (driver *) kmalloc(sizeof(driver), GFP_KERNEL))) {
1736                 printk(KERN_WARNING "register_isdn: Could not alloc driver-struct\n");
1737                 return 0;
1738         }
1739         memset((char *) d, 0, sizeof(driver));
1740         if (!(d->rcverr = (int *) kmalloc(sizeof(int) * n, GFP_KERNEL))) {
1741                 printk(KERN_WARNING "register_isdn: Could not alloc rcverr\n");
1742                 kfree(d);
1743                 return 0;
1744         }
1745         memset((char *) d->rcverr, 0, sizeof(int) * n);
1746         if (!(d->rcvcount = (int *) kmalloc(sizeof(int) * n, GFP_KERNEL))) {
1747                 printk(KERN_WARNING "register_isdn: Could not alloc rcvcount\n");
1748                 kfree(d->rcverr);
1749                 kfree(d);
1750                 return 0;
1751         }
1752         memset((char *) d->rcvcount, 0, sizeof(int) * n);
1753         if (!(d->rpqueue = (pqueue **) kmalloc(sizeof(pqueue *) * n, GFP_KERNEL))) {
1754                 printk(KERN_WARNING "register_isdn: Could not alloc rpqueue\n");
1755                 kfree(d->rcvcount);
1756                 kfree(d->rcverr);
1757                 kfree(d);
1758                 return 0;
1759         }
1760         memset((char *) d->rpqueue, 0, sizeof(pqueue *) * n);
1761         if (!(d->rcv_waitq = (struct wait_queue **)
1762               kmalloc(sizeof(struct wait_queue *) * n, GFP_KERNEL))) {
1763                 printk(KERN_WARNING "register_isdn: Could not alloc rcv_waitq\n");
1764                 kfree(d->rpqueue);
1765                 kfree(d->rcvcount);
1766                 kfree(d->rcverr);
1767                 kfree(d);
1768                 return 0;
1769         }
1770         memset((char *) d->rcv_waitq, 0, sizeof(struct wait_queue *) * n);
1771         if (!(d->snd_waitq = (struct wait_queue **)
1772               kmalloc(sizeof(struct wait_queue *) * n, GFP_KERNEL))) {
1773                 printk(KERN_WARNING "register_isdn: Could not alloc snd_waitq\n");
1774                 kfree(d->rcv_waitq);
1775                 kfree(d->rpqueue);
1776                 kfree(d->rcvcount);
1777                 kfree(d->rcverr);
1778                 kfree(d);
1779                 return 0;
1780         }
1781         memset((char *) d->snd_waitq, 0, sizeof(struct wait_queue *) * n);
1782         d->channels = n;
1783         d->loaded = 1;
1784         d->maxbufsize = i->maxbufsize;
1785         d->pktcount = 0;
1786         d->stavail = 0;
1787         d->running = 0;
1788         d->flags = 0;
1789         d->interface = i;
1790         for (drvidx = 0; drvidx < ISDN_MAX_DRIVERS; drvidx++)
1791                 if (!dev->drv[drvidx])
1792                         break;
1793         i->channels = drvidx;
1794  
1795         i->rcvcallb_skb = isdn_receive_skb_callback;
1796         i->rcvcallb     = isdn_receive_callback;
1797         i->statcallb    = isdn_status_callback;
1798         if (!strlen(i->id))
1799                 sprintf(i->id, "line%d", drvidx);
1800         save_flags(flags);
1801         cli();
1802         for (j = 0; j < n; j++)
1803                 for (k = 0; k < ISDN_MAX_CHANNELS; k++)
1804                         if (dev->chanmap[k] < 0) {
1805                                 dev->chanmap[k] = j;
1806                                 dev->drvmap[k] = drvidx;
1807                                 break;
1808                         }
1809         dev->drv[drvidx] = d;
1810         dev->channels += n;
1811         strcpy(dev->drvid[drvidx], i->id);
1812         isdn_info_update();
1813         dev->drivers++;
1814         restore_flags(flags);
1815         return 1;
1816 }
1817 
1818 /*
1819  *****************************************************************************
1820  * And now the modules code.
1821  *****************************************************************************
1822  */
1823 
1824 extern int printk(const char *fmt,...);
1825 
1826 #ifdef MODULE
1827 #define isdn_init init_module
1828 #endif
1829 
1830 static char *isdn_getrev(const char *revision)
     /* [previous][next][first][last][top][bottom][index][help] */
1831 {
1832         static char rev[20];
1833         char *p;
1834 
1835         if ((p = strchr(revision, ':'))) {
1836                 strcpy(rev, p + 2);
1837                 p = strchr(rev, '$');
1838                 *--p = 0;
1839         } else
1840                 strcpy(rev, "???");
1841         return rev;
1842 }
1843 
1844 static struct symbol_table isdn_syms = {
1845 #include <linux/symtab_begin.h>
1846         X(register_isdn),
1847 #include <linux/symtab_end.h>
1848 };
1849 
1850 static void isdn_export_syms(void)
     /* [previous][next][first][last][top][bottom][index][help] */
1851 {
1852         register_symtab(&isdn_syms);
1853         has_exported = 1;
1854 }
1855 
1856 /*
1857  * Allocate and initialize all data, register modem-devices
1858  */
1859 int isdn_init(void)
     /* [previous][next][first][last][top][bottom][index][help] */
1860 {
1861         int i;
1862 
1863         sti();
1864         if (!(dev = (isdn_dev *) kmalloc(sizeof(isdn_dev), GFP_KERNEL))) {
1865                 printk(KERN_WARNING "isdn: Could not allocate device-struct.\n");
1866                 return -EIO;
1867         }
1868         memset((char *) dev, 0, sizeof(isdn_dev));
1869         for (i = 0; i < ISDN_MAX_CHANNELS; i++)
1870                 dev->drvmap[i] = -1;
1871         for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
1872                 dev->chanmap[i] = -1;
1873                 dev->m_idx[i] = -1;
1874                 strcpy(dev->num[i], "???");
1875         }
1876         if (register_chrdev(ISDN_MAJOR, "isdn", &isdn_fops)) {
1877                 printk(KERN_WARNING "isdn: Could not register control devices\n");
1878                 kfree(dev);
1879                 return -EIO;
1880         }
1881         if ((i = isdn_tty_modem_init()) < 0) {
1882                 printk(KERN_WARNING "isdn: Could not register tty devices\n");
1883                 if (i == -3)
1884                         tty_unregister_driver(&dev->mdm.cua_modem);
1885                 if (i <= -2)
1886                         tty_unregister_driver(&dev->mdm.tty_modem);
1887                 kfree(dev);
1888                 unregister_chrdev(ISDN_MAJOR, "isdn");
1889                 return -EIO;
1890         }
1891 #ifdef CONFIG_ISDN_PPP
1892         if (isdn_ppp_init() < 0) {
1893                 printk(KERN_WARNING "isdn: Could not create PPP-device-structs\n");
1894                 tty_unregister_driver(&dev->mdm.tty_modem);
1895                 tty_unregister_driver(&dev->mdm.cua_modem);
1896                 for (i = 0; i < ISDN_MAX_CHANNELS; i++)
1897                         kfree(dev->mdm.info[i].xmit_buf - 4);
1898                 unregister_chrdev(ISDN_MAJOR, "isdn");
1899                 kfree(dev);
1900                 return -EIO;
1901         }
1902 #endif                          /* CONFIG_ISDN_PPP */
1903 
1904         if (!has_exported)
1905                 isdn_export_syms();
1906 
1907         printk(KERN_NOTICE "ISDN subsystem Rev: %s/%s/%s/%s",
1908                isdn_getrev(isdn_revision),
1909                isdn_getrev(isdn_tty_revision),
1910                isdn_getrev(isdn_net_revision),
1911                isdn_getrev(isdn_ppp_revision));
1912 
1913 #ifdef MODULE
1914         printk(" loaded\n");
1915 #else
1916         printk("\n");
1917         isdn_cards_init();
1918 #endif
1919         isdn_info_update();
1920         return 0;
1921 }
1922 
1923 #ifdef MODULE
1924 /*
1925  * Unload module
1926  */
1927 void cleanup_module(void)
     /* [previous][next][first][last][top][bottom][index][help] */
1928 {
1929         int flags;
1930         int i;
1931 
1932 #ifdef CONFIG_ISDN_PPP
1933         isdn_ppp_cleanup();
1934 #endif
1935         save_flags(flags);
1936         cli();
1937         if (isdn_net_rmall() < 0) {
1938                 printk(KERN_WARNING "isdn: net-device busy, remove cancelled\n");
1939                 restore_flags(flags);
1940                 return;
1941         }
1942         if (tty_unregister_driver(&dev->mdm.tty_modem)) {
1943                 printk(KERN_WARNING "isdn: ttyI-device busy, remove cancelled\n");
1944                 restore_flags(flags);
1945                 return;
1946         }
1947         if (tty_unregister_driver(&dev->mdm.cua_modem)) {
1948                 printk(KERN_WARNING "isdn: cui-device busy, remove cancelled\n");
1949                 restore_flags(flags);
1950                 return;
1951         }
1952         for (i = 0; i < ISDN_MAX_CHANNELS; i++)
1953                 kfree(dev->mdm.info[i].xmit_buf - 4);
1954         if (unregister_chrdev(ISDN_MAJOR, "isdn") != 0) {
1955                 printk(KERN_WARNING "isdn: controldevice busy, remove cancelled\n");
1956         } else {
1957                 del_timer(&dev->timer);
1958                 kfree(dev);
1959                 printk(KERN_NOTICE "ISDN-subsystem unloaded\n");
1960         }
1961         restore_flags(flags);
1962 }
1963 #endif

/* [previous][next][first][last][top][bottom][index][help] */