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. register_isdn
  34. isdn_getrev
  35. isdn_export_syms
  36. isdn_init
  37. cleanup_module

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

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