OpenCores
URL https://opencores.org/ocsvn/or1k_old/or1k_old/trunk

Subversion Repositories or1k_old

[/] [or1k_old/] [trunk/] [uclinux/] [uClinux-2.0.x/] [drivers/] [isdn/] [isdn_common.c] - Blame information for rev 1782

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 199 simons
/* $Id: isdn_common.c,v 1.1.1.1 2001-09-10 07:44:18 simons Exp $
2
 
3
 * Linux ISDN subsystem, common used functions (linklevel).
4
 *
5
 * Copyright 1994-1998  by Fritz Elfert (fritz@isdn4linux.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: not supported by cvs2svn $
24
 * Revision 1.1.1.1  2001/07/02 17:58:31  simons
25
 * Initial revision
26
 *
27
 * Revision 1.44.2.9  1998/11/06 00:07:25  fritz
28
 * Bugfix: loading additional driver while /dev/isdnctrl opened resulted in
29
 *         wrong module usage count after closing /dev/isdnctrl.
30
 *
31
 * Revision 1.44.2.8  1998/11/05 22:11:43  fritz
32
 * Changed mail-address.
33
 *
34
 * Revision 1.44.2.7  1998/11/04 17:22:40  fritz
35
 * Replaced broken lowlevel-driver locking.
36
 *
37
 * Revision 1.44.2.6  1998/11/03 14:30:56  fritz
38
 * Reduced stack usage in various functions.
39
 * Adapted statemachine to work with certified HiSax.
40
 * Some fixes in callback handling.
41
 *
42
 * Revision 1.44.2.5  1998/10/25 15:48:04  fritz
43
 * Misc bugfixes and adaptions to new HiSax
44
 *
45
 * Revision 1.44.2.4  1998/06/07 13:47:44  fritz
46
 * ABC cleanup
47
 *
48
 * Revision 1.44.2.2  1998/03/16 09:55:44  cal
49
 * Merged in TimRu-patches. Still needs validation in conjunction with ABC-patches.
50
 *
51
 * Revision 1.44.2.1  1998/03/07 23:35:03  detabc
52
 * added the abc-extension to the linux isdn-kernel
53
 * for kernel-version 2.0.xx
54
 * DO NOT USE FOR HIGHER KERNELS-VERSIONS
55
 * all source-lines are switched with the define  CONFIG_ISDN_WITH_ABC
56
 * (make config and answer ABC-Ext. Support (Compress,TCP-Keepalive ...) with yes
57
 *
58
 * you need also a modified isdnctrl-source the switch on the
59
 * features of the abc-extension
60
 *
61
 * please use carefully. more detail will be follow.
62
 * thanks
63
 *
64
 * Revision 1.44  1997/05/27 15:17:23  fritz
65
 * Added changes for recent 2.1.x kernels:
66
 *   changed return type of isdn_close
67
 *   queue_task_* -> queue_task
68
 *   clear/set_bit -> test_and_... where apropriate.
69
 *   changed type of hard_header_cache parameter.
70
 *
71
 * Revision 1.43  1997/03/31 14:09:43  fritz
72
 * Fixed memory leak in isdn_close().
73
 *
74
 * Revision 1.42  1997/03/30 16:51:08  calle
75
 * changed calls to copy_from_user/copy_to_user and removed verify_area
76
 * were possible.
77
 *
78
 * Revision 1.41  1997/03/24 22:54:41  fritz
79
 * Some small fixes in debug code.
80
 *
81
 * Revision 1.40  1997/03/08 08:13:51  fritz
82
 * Bugfix: IIOCSETMAP (Set mapping) was broken.
83
 *
84
 * Revision 1.39  1997/03/07 01:32:54  fritz
85
 * Added proper ifdef's for CONFIG_ISDN_AUDIO
86
 *
87
 * Revision 1.38  1997/03/05 21:15:02  fritz
88
 * Fix: reduced stack usage of isdn_ioctl() and isdn_set_allcfg()
89
 *
90
 * Revision 1.37  1997/03/02 14:29:18  fritz
91
 * More ttyI related cleanup.
92
 *
93
 * Revision 1.36  1997/02/28 02:32:40  fritz
94
 * Cleanup: Moved some tty related stuff from isdn_common.c
95
 *          to isdn_tty.c
96
 * Bugfix:  Bisync protocol did not behave like documented.
97
 *
98
 * Revision 1.35  1997/02/21 13:01:19  fritz
99
 * Changes CAUSE message output in kernel log.
100
 *
101
 * Revision 1.34  1997/02/10 20:12:43  fritz
102
 * Changed interface for reporting incoming calls.
103
 *
104
 * Revision 1.33  1997/02/10 10:05:42  fritz
105
 * More changes for Kernel 2.1.X
106
 * Symbol information moved to isdn_syms.c
107
 *
108
 * Revision 1.32  1997/02/03 22:55:26  fritz
109
 * Reformatted according CodingStyle.
110
 * Changed isdn_writebuf_stub static.
111
 * Slow down tty-RING counter.
112
 * skb->free stuff replaced by macro.
113
 * Bugfix in audio-skb locking.
114
 * Bugfix in HL-driver locking.
115
 *
116
 * Revision 1.31  1997/01/17 01:19:18  fritz
117
 * Applied chargeint patch.
118
 *
119
 * Revision 1.30  1997/01/14 01:27:47  fritz
120
 * Changed audio receive not to rely on skb->users and skb->lock.
121
 * Added ATI2 and related variables.
122
 * Started adding full-duplex audio capability.
123
 *
124
 * Revision 1.29  1997/01/12 23:33:03  fritz
125
 * Made isdn_all_eaz foolproof.
126
 *
127
 * Revision 1.28  1996/11/13 02:33:19  fritz
128
 * Fixed a race condition.
129
 *
130
 * Revision 1.27  1996/10/27 22:02:41  keil
131
 * return codes for ISDN_STAT_ICALL
132
 *
133
 * Revision 1.26  1996/10/23 11:59:40  fritz
134
 * More compatibility changes.
135
 *
136
 * Revision 1.25  1996/10/22 23:13:54  fritz
137
 * Changes for compatibility to 2.0.X and 2.1.X kernels.
138
 *
139
 * Revision 1.24  1996/10/11 14:02:03  fritz
140
 * Bugfix: call to isdn_ppp_timer_timeout() never compiled, because of
141
 *         typo in #ifdef.
142
 *
143
 * Revision 1.23  1996/06/25 18:35:38  fritz
144
 * Fixed bogus memory access in isdn_set_allcfg().
145
 *
146
 * Revision 1.22  1996/06/24 17:37:37  fritz
147
 * Bugfix: isdn_timer_ctrl() did restart timer, even if it
148
 *         was already running.
149
 *         lowlevel driver locking did use wrong parameters.
150
 *
151
 * Revision 1.21  1996/06/15 14:58:20  fritz
152
 * Added version signatures for data structures used
153
 * by userlevel programs.
154
 *
155
 * Revision 1.20  1996/06/12 16:01:49  fritz
156
 * Bugfix: Remote B-channel hangup sometimes did not result
157
 *         in a NO CARRIER on tty.
158
 *
159
 * Revision 1.19  1996/06/11 14:52:04  hipp
160
 * minor bugfix in isdn_writebuf_skb_stub()
161
 *
162
 * Revision 1.18  1996/06/06 14:51:51  fritz
163
 * Changed to support DTMF decoding on audio playback also.
164
 *
165
 * Revision 1.17  1996/06/05 02:24:10  fritz
166
 * Added DTMF decoder for audio mode.
167
 *
168
 * Revision 1.16  1996/06/03 20:09:05  fritz
169
 * Bugfix: called wrong function pointer for locking in
170
 *         isdn_get_free_channel().
171
 *
172
 * Revision 1.15  1996/05/31 01:10:54  fritz
173
 * Bugfixes:
174
 *   Lowlevel modules did not get locked correctly.
175
 *   Did show wrong revision when initializing.
176
 *   Minor fixes in ioctl code.
177
 *   sk_buff did not get freed, if error in writebuf_stub.
178
 *
179
 * Revision 1.14  1996/05/18 01:36:55  fritz
180
 * Added spelling corrections and some minor changes
181
 * to stay in sync with kernel.
182
 *
183
 * Revision 1.13  1996/05/17 15:43:30  fritz
184
 * Bugfix: decrement of rcvcount in readbchan() corrected.
185
 *
186
 * Revision 1.12  1996/05/17 03:55:43  fritz
187
 * Changed DLE handling for audio receive.
188
 * Some cleanup.
189
 * Added display of isdn_audio_revision.
190
 *
191
 * Revision 1.11  1996/05/11 21:51:32  fritz
192
 * Changed queue management to use sk_buffs.
193
 *
194
 * Revision 1.10  1996/05/10 08:49:16  fritz
195
 * Checkin before major changes of tty-code.
196
 *
197
 * Revision 1.9  1996/05/07 09:19:41  fritz
198
 * Adapted to changes in isdn_tty.c
199
 *
200
 * Revision 1.8  1996/05/06 11:34:51  hipp
201
 * fixed a few bugs
202
 *
203
 * Revision 1.7  1996/05/02 03:55:17  fritz
204
 * Bugfixes:
205
 *  - B-channel connect message for modem devices
206
 *    sometimes did not result in a CONNECT-message.
207
 *  - register_isdn did not check for driverId-conflicts.
208
 *
209
 * Revision 1.6  1996/04/30 20:57:21  fritz
210
 * Commit test
211
 *
212
 * Revision 1.5  1996/04/20 16:19:07  fritz
213
 * Changed slow timer handlers to increase accuracy.
214
 * Added statistic information for usage by xisdnload.
215
 * Fixed behaviour of isdnctrl-device on non-blocked io.
216
 * Fixed all io to go through generic writebuf-function without
217
 * bypassing. Same for incoming data.
218
 * Fixed bug: Last channel had been unusable.
219
 * Fixed kfree of tty xmit_buf on ppp initialization failure.
220
 *
221
 * Revision 1.4  1996/02/11 02:33:26  fritz
222
 * Fixed bug in main timer-dispatcher.
223
 * Bugfix: Lot of tty-callbacks got called regardless of the events already
224
 * been handled by network-devices.
225
 * Changed ioctl-names.
226
 *
227
 * Revision 1.3  1996/01/22 05:16:11  fritz
228
 * Changed ioctl-names.
229
 * Fixed bugs in isdn_open and isdn_close regarding PPP_MINOR.
230
 *
231
 * Revision 1.2  1996/01/21 16:52:40  fritz
232
 * Support for sk_buffs added, changed header-stuffing.
233
 *
234
 * Revision 1.1  1996/01/09 04:12:52  fritz
235
 * Initial revision
236
 *
237
 */
238
 
239
#include <linux/config.h>
240
#define __NO_VERSION__
241
#include <linux/module.h>
242
#include <linux/version.h>
243
#if (LINUX_VERSION_CODE >= 0x020117)
244
#include <asm/poll.h>
245
#endif
246
#include <linux/isdn.h>
247
#include "isdn_common.h"
248
#include "isdn_tty.h"
249
#include "isdn_net.h"
250
#include "isdn_ppp.h"
251
#ifdef CONFIG_ISDN_AUDIO
252
#include "isdn_audio.h"
253
#endif
254
#include "isdn_cards.h"
255
 
256
/* Debugflags */
257
#undef ISDN_DEBUG_STATCALLB
258
 
259
isdn_dev *dev = (isdn_dev *) 0;
260
 
261
static char *isdn_revision = "$Revision: 1.1.1.1 $";
262
 
263
extern char *isdn_net_revision;
264
extern char *isdn_tty_revision;
265
#ifdef CONFIG_ISDN_PPP
266
extern char *isdn_ppp_revision;
267
#else
268
static char *isdn_ppp_revision = ": none $";
269
#endif
270
#ifdef CONFIG_ISDN_AUDIO
271
extern char *isdn_audio_revision;
272
#else
273
static char *isdn_audio_revision = ": none $";
274
#endif
275
 
276
static int isdn_writebuf_stub(int, int, const u_char *, int, int);
277
 
278
void
279
isdn_MOD_INC_USE_COUNT(void)
280
{
281
        int i;
282
 
283
        MOD_INC_USE_COUNT;
284
        for (i = 0; i < dev->drivers; i++) {
285
                isdn_ctrl cmd;
286
 
287
                cmd.driver = i;
288
                cmd.arg = 0;
289
                cmd.command = ISDN_CMD_LOCK;
290
                isdn_command(&cmd);
291
                dev->drv[i]->locks++;
292
        }
293
}
294
 
295
void
296
isdn_MOD_DEC_USE_COUNT(void)
297
{
298
        int i;
299
 
300
        MOD_DEC_USE_COUNT;
301
        for (i = 0; i < dev->drivers; i++)
302
                if (dev->drv[i]->locks > 0) {
303
                        isdn_ctrl cmd;
304
 
305
                        cmd.driver = i;
306
                        cmd.arg = 0;
307
                        cmd.command = ISDN_CMD_UNLOCK;
308
                        isdn_command(&cmd);
309
                        dev->drv[i]->locks--;
310
                }
311
}
312
 
313
#if defined(ISDN_DEBUG_NET_DUMP) || defined(ISDN_DEBUG_MODEM_DUMP) || defined(CONFIG_ISDN_TIMEOUT_RULES)
314
void
315
isdn_dumppkt(char *s, u_char * p, int len, int dumplen)
316
{
317
        int dumpc;
318
 
319
        printk(KERN_DEBUG "%s(%d) ", s, len);
320
        for (dumpc = 0; (dumpc < dumplen) && (len); len--, dumpc++)
321
                printk(" %02x", *p++);
322
        printk("\n");
323
}
324
#endif
325
 
326
static __inline void
327
isdn_trash_skb(struct sk_buff *skb, int rw)
328
{
329
        SET_SKB_FREE(skb);
330
        kfree_skb(skb, rw);
331
}
332
 
333
static void
334
isdn_free_queue(struct sk_buff_head *queue)
335
{
336
        struct sk_buff *skb;
337
        unsigned long flags;
338
 
339
        save_flags(flags);
340
        cli();
341
        if (skb_queue_len(queue))
342
                while ((skb = skb_dequeue(queue)))
343
                        isdn_trash_skb(skb, FREE_READ);
344
        restore_flags(flags);
345
}
346
 
347
int
348
isdn_dc2minor(int di, int ch)
349
{
350
        int i;
351
        for (i = 0; i < ISDN_MAX_CHANNELS; i++)
352
                if (dev->chanmap[i] == ch && dev->drvmap[i] == di)
353
                        return i;
354
        return -1;
355
}
356
 
357
static int isdn_timer_cnt1 = 0;
358
static int isdn_timer_cnt2 = 0;
359
static int isdn_timer_cnt3 = 0;
360
 
361
static void
362
isdn_timer_funct(ulong dummy)
363
{
364
        int tf = dev->tflags;
365
 
366
        if (tf & ISDN_TIMER_FAST) {
367
                if (tf & ISDN_TIMER_MODEMREAD)
368
                        isdn_tty_readmodem();
369
                if (tf & ISDN_TIMER_MODEMPLUS)
370
                        isdn_tty_modem_escape();
371
                if (tf & ISDN_TIMER_MODEMXMIT)
372
                        isdn_tty_modem_xmit();
373
        }
374
        if (tf & ISDN_TIMER_SLOW) {
375
                if (++isdn_timer_cnt1 >= ISDN_TIMER_02SEC) {
376
                        isdn_timer_cnt1 = 0;
377
                        if (tf & ISDN_TIMER_NETDIAL)
378
                                isdn_net_dial();
379
                }
380
                if (++isdn_timer_cnt2 >= ISDN_TIMER_1SEC) {
381
                        isdn_timer_cnt2 = 0;
382
                        if (tf & ISDN_TIMER_NETHANGUP)
383
                                isdn_net_autohup();
384
                        if (++isdn_timer_cnt3 > ISDN_TIMER_RINGING) {
385
                                isdn_timer_cnt3 = 0;
386
                                if (tf & ISDN_TIMER_MODEMRING)
387
                                        isdn_tty_modem_ring();
388
                        }
389
#if (defined CONFIG_ISDN_PPP) && (defined CONFIG_ISDN_MPP)
390
                        if (tf & ISDN_TIMER_IPPP)
391
                                isdn_ppp_timer_timeout();
392
#endif
393
                }
394
        }
395
 
396
        if (tf) {
397
                int flags;
398
 
399
                save_flags(flags);
400
                cli();
401
                del_timer(&dev->timer);
402
                dev->timer.expires = jiffies + ISDN_TIMER_RES;
403
                add_timer(&dev->timer);
404
                restore_flags(flags);
405
        }
406
}
407
 
408
void
409
isdn_timer_ctrl(int tf, int onoff)
410
{
411
        int flags;
412
 
413
        save_flags(flags);
414
        cli();
415
        if ((tf & ISDN_TIMER_SLOW) && (!(dev->tflags & ISDN_TIMER_SLOW))) {
416
                /* If the slow-timer wasn't activated until now */
417
                isdn_timer_cnt1 = 0;
418
                isdn_timer_cnt2 = 0;
419
        }
420
        if (onoff)
421
                dev->tflags |= tf;
422
        else
423
                dev->tflags &= ~tf;
424
        if (dev->tflags) {
425
                if (!del_timer(&dev->timer))    /* del_timer is 1, when active */
426
                        dev->timer.expires = jiffies + ISDN_TIMER_RES;
427
                add_timer(&dev->timer);
428
        }
429
        restore_flags(flags);
430
}
431
 
432
/*
433
 * Receive a packet from B-Channel. (Called from low-level-module)
434
 */
435
static void
436
isdn_receive_skb_callback(int di, int channel, struct sk_buff *skb)
437
{
438
        int i;
439
 
440
        if ((i = isdn_dc2minor(di, channel)) == -1) {
441
                isdn_trash_skb(skb, FREE_READ);
442
                return;
443
        }
444
        /* Update statistics */
445
        dev->ibytes[i] += skb->len;
446
        /* First, try to deliver data to network-device */
447
        if (isdn_net_rcv_skb(i, skb))
448
                return;
449
        /* No network-device found, deliver to tty or raw-channel */
450
        SET_SKB_FREE(skb);
451
        if (skb->len) {
452
                if (isdn_tty_rcv_skb(i, di, channel, skb))
453
                        return;
454
                wake_up_interruptible(&dev->drv[di]->rcv_waitq[channel]);
455
        } else
456
                isdn_trash_skb(skb, FREE_READ);
457
}
458
 
459
/*
460
 * Intercept command from Linklevel to Lowlevel.
461
 */
462
int
463
isdn_command(isdn_ctrl *cmd)
464
{
465
        return dev->drv[cmd->driver]->interface->command(cmd);
466
}
467
 
468
void
469
isdn_all_eaz(int di, int ch)
470
{
471
        isdn_ctrl cmd;
472
 
473
        if (di < 0)
474
                return;
475
        cmd.driver = di;
476
        cmd.arg = ch;
477
        cmd.command = ISDN_CMD_SETEAZ;
478
        cmd.parm.num[0] = '\0';
479
        isdn_command(&cmd);
480
}
481
 
482
static int
483
isdn_status_callback(isdn_ctrl * c)
484
{
485
        int di;
486
        ulong flags;
487
        int i;
488
        int r;
489
        int retval = 0;
490
        isdn_ctrl cmd;
491
 
492
        di = c->driver;
493
        i = isdn_dc2minor(di, c->arg);
494
        switch (c->command) {
495
                case ISDN_STAT_BSENT:
496
                        if (i < 0)
497
                                return -1;
498
                        if (dev->global_flags & ISDN_GLOBAL_STOPPED)
499
                                return 0;
500
                        if (isdn_net_stat_callback(i, c))
501
                                return 0;
502
                        if (isdn_tty_stat_callback(i, c))
503
                                return 0;
504
                        wake_up_interruptible(&dev->drv[di]->snd_waitq[c->arg]);
505
                        break;
506
                case ISDN_STAT_STAVAIL:
507
                        save_flags(flags);
508
                        cli();
509
                        dev->drv[di]->stavail += c->arg;
510
                        restore_flags(flags);
511
                        wake_up_interruptible(&dev->drv[di]->st_waitq);
512
                        break;
513
                case ISDN_STAT_RUN:
514
                        dev->drv[di]->flags |= DRV_FLAG_RUNNING;
515
                        for (i = 0; i < ISDN_MAX_CHANNELS; i++)
516
                                if (dev->drvmap[i] == di)
517
                                        isdn_all_eaz(di, dev->chanmap[i]);
518
                        break;
519
                case ISDN_STAT_STOP:
520
                        dev->drv[di]->flags &= ~DRV_FLAG_RUNNING;
521
                        break;
522
                case ISDN_STAT_ICALL:
523
                        if (i < 0)
524
                                return -1;
525
#ifdef ISDN_DEBUG_STATCALLB
526
                        printk(KERN_DEBUG "ICALL (net): %d %ld %s\n", di, c->arg, c->parm.num);
527
#endif
528
                        if (dev->global_flags & ISDN_GLOBAL_STOPPED) {
529
                                cmd.driver = di;
530
                                cmd.arg = c->arg;
531
                                cmd.command = ISDN_CMD_HANGUP;
532
                                isdn_command(&cmd);
533
                                return 0;
534
                        }
535
                        /* Try to find a network-interface which will accept incoming call */
536
                        r = isdn_net_find_icall(di, c, i);
537
                        switch (r) {
538
                                case 0:
539
                                        /* No network-device replies.
540
                                         * Try ttyI's
541
                                         */
542
                                        if (isdn_tty_find_icall(di, c) >= 0)
543
                                                retval = 1;
544
                                        else if (dev->drv[di]->flags & DRV_FLAG_REJBUS) {
545
                                                cmd.driver = di;
546
                                                cmd.arg = c->arg;
547
                                                cmd.command = ISDN_CMD_HANGUP;
548
                                                isdn_command(&cmd);
549
                                                retval = 2;
550
                                        }
551
                                        break;
552
                                case 1:
553
                                        /* Schedule connection-setup */
554
                                        isdn_net_dial();
555
                                        cmd.driver = di;
556
                                        cmd.arg = c->arg;
557
                                        cmd.command = ISDN_CMD_ACCEPTD;
558
                                        isdn_command(&cmd);
559
                                        retval = 1;
560
                                        break;
561
                                case 2: /* For calling back, first reject incoming call ... */
562
                                case 3: /* Interface found, but down, reject call actively  */
563
                                        retval = 2;
564
                                        printk(KERN_INFO "isdn: Rejecting Call\n");
565
                                        cmd.driver = di;
566
                                        cmd.arg = c->arg;
567
                                        cmd.command = ISDN_CMD_HANGUP;
568
                                        isdn_command(&cmd);
569
                                        if (r == 3)
570
                                                break;
571
                                        /* Fall through */
572
                                case 4:
573
                                        /* ... then start callback. */
574
                                        isdn_net_dial();
575
                                        break;
576
                        }
577
                        return retval;
578
                        break;
579
                case ISDN_STAT_CINF:
580
                        if (i < 0)
581
                                return -1;
582
#ifdef ISDN_DEBUG_STATCALLB
583
                        printk(KERN_DEBUG "CINF: %ld %s\n", c->arg, c->parm.num);
584
#endif
585
                        if (dev->global_flags & ISDN_GLOBAL_STOPPED)
586
                                return 0;
587
                        if (strcmp(c->parm.num, "0"))
588
                                isdn_net_stat_callback(i, c);
589
                        break;
590
                case ISDN_STAT_CAUSE:
591
#ifdef ISDN_DEBUG_STATCALLB
592
                        printk(KERN_DEBUG "CAUSE: %ld %s\n", c->arg, c->parm.num);
593
#endif
594
                        printk(KERN_INFO "isdn: %s,ch%ld cause: %s\n",
595
                               dev->drvid[di], c->arg, c->parm.num);
596
                        isdn_tty_stat_callback(i, c);
597
                        break;
598
                case ISDN_STAT_DCONN:
599
                        if (i < 0)
600
                                return -1;
601
#ifdef ISDN_DEBUG_STATCALLB
602
                        printk(KERN_DEBUG "DCONN: %ld\n", c->arg);
603
#endif
604
                        if (dev->global_flags & ISDN_GLOBAL_STOPPED)
605
                                return 0;
606
                        /* Find any net-device, waiting for D-channel setup */
607
                        if (isdn_net_stat_callback(i, c))
608
                                break;
609
                        /* Find any ttyI, waiting for D-channel setup */
610
                        if (isdn_tty_stat_callback(i, c)) {
611
                                cmd.driver = di;
612
                                cmd.arg = c->arg;
613
                                cmd.command = ISDN_CMD_ACCEPTB;
614
                                isdn_command(&cmd);
615
                                break;
616
                        }
617
                        break;
618
                case ISDN_STAT_DHUP:
619
                        if (i < 0)
620
                                return -1;
621
#ifdef ISDN_DEBUG_STATCALLB
622
                        printk(KERN_DEBUG "DHUP: %ld\n", c->arg);
623
#endif
624
                        if (dev->global_flags & ISDN_GLOBAL_STOPPED)
625
                                return 0;
626
                        dev->drv[di]->online &= ~(1 << (c->arg));
627
                        isdn_info_update();
628
                        /* Signal hangup to network-devices */
629
                        if (isdn_net_stat_callback(i, c))
630
                                break;
631
                        if (isdn_tty_stat_callback(i, c))
632
                                break;
633
                        break;
634
                case ISDN_STAT_BCONN:
635
                        if (i < 0)
636
                                return -1;
637
#ifdef ISDN_DEBUG_STATCALLB
638
                        printk(KERN_DEBUG "BCONN: %ld\n", c->arg);
639
#endif
640
                        /* Signal B-channel-connect to network-devices */
641
                        if (dev->global_flags & ISDN_GLOBAL_STOPPED)
642
                                return 0;
643
                        dev->drv[di]->online |= (1 << (c->arg));
644
                        isdn_info_update();
645
                        if (isdn_net_stat_callback(i, c))
646
                                break;
647
                        if (isdn_tty_stat_callback(i, c))
648
                                break;
649
                        break;
650
                case ISDN_STAT_BHUP:
651
                        if (i < 0)
652
                                return -1;
653
#ifdef ISDN_DEBUG_STATCALLB
654
                        printk(KERN_DEBUG "BHUP: %ld\n", c->arg);
655
#endif
656
                        if (dev->global_flags & ISDN_GLOBAL_STOPPED)
657
                                return 0;
658
                        dev->drv[di]->online &= ~(1 << (c->arg));
659
                        isdn_info_update();
660
                        if (isdn_tty_stat_callback(i, c))
661
                                break;
662
                        break;
663
                case ISDN_STAT_NODCH:
664
                        if (i < 0)
665
                                return -1;
666
#ifdef ISDN_DEBUG_STATCALLB
667
                        printk(KERN_DEBUG "NODCH: %ld\n", c->arg);
668
#endif
669
                        if (dev->global_flags & ISDN_GLOBAL_STOPPED)
670
                                return 0;
671
                        if (isdn_net_stat_callback(i, c))
672
                                break;
673
                        if (isdn_tty_stat_callback(i, c))
674
                                break;
675
                        break;
676
                case ISDN_STAT_ADDCH:
677
                        break;
678
                case ISDN_STAT_UNLOAD:
679
                        save_flags(flags);
680
                        cli();
681
                        isdn_tty_stat_callback(i, c);
682
                        for (i = 0; i < ISDN_MAX_CHANNELS; i++)
683
                                if (dev->drvmap[i] == di) {
684
                                        dev->drvmap[i] = -1;
685
                                        dev->chanmap[i] = -1;
686
                                }
687
                        dev->drivers--;
688
                        dev->channels -= dev->drv[di]->channels;
689
                        kfree(dev->drv[di]->rcverr);
690
                        kfree(dev->drv[di]->rcvcount);
691
                        for (i = 0; i < dev->drv[di]->channels; i++)
692
                                isdn_free_queue(&dev->drv[di]->rpqueue[i]);
693
                        kfree(dev->drv[di]->rpqueue);
694
                        kfree(dev->drv[di]->rcv_waitq);
695
                        kfree(dev->drv[di]->snd_waitq);
696
                        kfree(dev->drv[di]);
697
                        dev->drv[di] = NULL;
698
                        dev->drvid[di][0] = '\0';
699
                        isdn_info_update();
700
                        restore_flags(flags);
701
                        return 0;
702
                default:
703
                        return -1;
704
        }
705
        return 0;
706
}
707
 
708
/*
709
 * Get integer from char-pointer, set pointer to end of number
710
 */
711
int
712
isdn_getnum(char **p)
713
{
714
        int v = -1;
715
 
716
        while (*p[0] >= '0' && *p[0] <= '9')
717
                v = ((v < 0) ? 0 : (v * 10)) + (int) ((*p[0]++) - '0');
718
        return v;
719
}
720
 
721
#define DLE 0x10
722
 
723
/*
724
 * isdn_readbchan() tries to get data from the read-queue.
725
 * It MUST be called with interrupts off.
726
 */
727
int
728
isdn_readbchan(int di, int channel, u_char * buf, u_char * fp, int len, int user)
729
{
730
        int left;
731
        int count;
732
        int count_pull;
733
        int count_put;
734
        int dflag;
735
        struct sk_buff *skb;
736
        u_char *cp;
737
 
738
        if (!dev->drv[di])
739
                return 0;
740
        if (skb_queue_empty(&dev->drv[di]->rpqueue[channel])) {
741
                if (user)
742
                        interruptible_sleep_on(&dev->drv[di]->rcv_waitq[channel]);
743
                else
744
                        return 0;
745
        }
746
        left = MIN(len, dev->drv[di]->rcvcount[channel]);
747
        cp = buf;
748
        count = 0;
749
        while (left) {
750
                if (!(skb = skb_peek(&dev->drv[di]->rpqueue[channel])))
751
                        break;
752
#ifdef CONFIG_ISDN_AUDIO
753
                if (ISDN_AUDIO_SKB_LOCK(skb))
754
                        break;
755
                ISDN_AUDIO_SKB_LOCK(skb) = 1;
756
                if (ISDN_AUDIO_SKB_DLECOUNT(skb)) {
757
                        char *p = skb->data;
758
                        unsigned long DLEmask = (1 << channel);
759
 
760
                        dflag = 0;
761
                        count_pull = count_put = 0;
762
                        while ((count_pull < skb->len) && (left-- > 0)) {
763
                                if (dev->drv[di]->DLEflag & DLEmask) {
764
                                        if (user)
765
                                                put_user(DLE, cp++);
766
                                        else
767
                                                *cp++ = DLE;
768
                                        dev->drv[di]->DLEflag &= ~DLEmask;
769
                                } else {
770
                                        if (user)
771
                                                put_user(*p, cp++);
772
                                        else
773
                                                *cp++ = *p;
774
                                        if (*p == DLE) {
775
                                                dev->drv[di]->DLEflag |= DLEmask;
776
                                                (ISDN_AUDIO_SKB_DLECOUNT(skb))--;
777
                                        }
778
                                        p++;
779
                                        count_pull++;
780
                                }
781
                                count_put++;
782
                        }
783
                        if (count_pull >= skb->len)
784
                                dflag = 1;
785
                } else {
786
#endif
787
                        /* No DLE's in buff, so simply copy it */
788
                        dflag = 1;
789
                        if ((count_pull = skb->len) > left) {
790
                                count_pull = left;
791
                                dflag = 0;
792
                        }
793
                        count_put = count_pull;
794
                        if (user)
795
                                copy_to_user(cp, skb->data, count_put);
796
                        else
797
                                memcpy(cp, skb->data, count_put);
798
                        cp += count_put;
799
                        left -= count_put;
800
#ifdef CONFIG_ISDN_AUDIO
801
                }
802
#endif
803
                count += count_put;
804
                if (fp) {
805
                        memset(fp, 0, count_put);
806
                        fp += count_put;
807
                }
808
                if (dflag) {
809
                        /* We got all the data in this buff.
810
                         * Now we can dequeue it.
811
                         */
812
                        if (fp)
813
                                *(fp - 1) = 0xff;
814
#ifdef CONFIG_ISDN_AUDIO
815
                        ISDN_AUDIO_SKB_LOCK(skb) = 0;
816
#endif
817
                        skb = skb_dequeue(&dev->drv[di]->rpqueue[channel]);
818
                        isdn_trash_skb(skb, FREE_READ);
819
                } else {
820
                        /* Not yet emptied this buff, so it
821
                         * must stay in the queue, for further calls
822
                         * but we pull off the data we got until now.
823
                         */
824
                        skb_pull(skb, count_pull);
825
#ifdef CONFIG_ISDN_AUDIO
826
                        ISDN_AUDIO_SKB_LOCK(skb) = 0;
827
#endif
828
                }
829
                dev->drv[di]->rcvcount[channel] -= count_put;
830
        }
831
        return count;
832
}
833
 
834
static __inline int
835
isdn_minor2drv(int minor)
836
{
837
        return (dev->drvmap[minor]);
838
}
839
 
840
static __inline int
841
isdn_minor2chan(int minor)
842
{
843
        return (dev->chanmap[minor]);
844
}
845
 
846
#define INF_DV 0x01             /* Data version for /dev/isdninfo */
847
 
848
static char *
849
isdn_statstr(void)
850
{
851
        static char istatbuf[2048];
852
        char *p;
853
        int i;
854
 
855
        sprintf(istatbuf, "idmap:\t");
856
        p = istatbuf + strlen(istatbuf);
857
        for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
858
                sprintf(p, "%s ", (dev->drvmap[i] < 0) ? "-" : dev->drvid[dev->drvmap[i]]);
859
                p = istatbuf + strlen(istatbuf);
860
        }
861
        sprintf(p, "\nchmap:\t");
862
        p = istatbuf + strlen(istatbuf);
863
        for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
864
                sprintf(p, "%d ", dev->chanmap[i]);
865
                p = istatbuf + strlen(istatbuf);
866
        }
867
        sprintf(p, "\ndrmap:\t");
868
        p = istatbuf + strlen(istatbuf);
869
        for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
870
                sprintf(p, "%d ", dev->drvmap[i]);
871
                p = istatbuf + strlen(istatbuf);
872
        }
873
        sprintf(p, "\nusage:\t");
874
        p = istatbuf + strlen(istatbuf);
875
        for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
876
                sprintf(p, "%d ", dev->usage[i]);
877
                p = istatbuf + strlen(istatbuf);
878
        }
879
        sprintf(p, "\nflags:\t");
880
        p = istatbuf + strlen(istatbuf);
881
        for (i = 0; i < ISDN_MAX_DRIVERS; i++) {
882
                if (dev->drv[i]) {
883
                        sprintf(p, "%ld ", dev->drv[i]->online);
884
                        p = istatbuf + strlen(istatbuf);
885
                } else {
886
                        sprintf(p, "? ");
887
                        p = istatbuf + strlen(istatbuf);
888
                }
889
        }
890
        sprintf(p, "\nphone:\t");
891
        p = istatbuf + strlen(istatbuf);
892
        for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
893
                sprintf(p, "%s ", dev->num[i]);
894
                p = istatbuf + strlen(istatbuf);
895
        }
896
        sprintf(p, "\n");
897
        return istatbuf;
898
}
899
 
900
/* Module interface-code */
901
 
902
void
903
isdn_info_update(void)
904
{
905
        infostruct *p = dev->infochain;
906
 
907
        while (p) {
908
                *(p->private) = 1;
909
                p = (infostruct *) p->next;
910
        }
911
        wake_up_interruptible(&(dev->info_waitq));
912
}
913
 
914
static RWTYPE
915
isdn_read(struct inode *inode, struct file *file, char *buf, RWARG count)
916
{
917
        uint minor = MINOR(inode->i_rdev);
918
        int len = 0;
919
        ulong flags;
920
        int drvidx;
921
        int chidx;
922
 
923
        if (minor == ISDN_MINOR_STATUS) {
924
                char *p;
925
                if (!file->private_data) {
926
                        if (file->f_flags & O_NONBLOCK)
927
                                return -EAGAIN;
928
                        interruptible_sleep_on(&(dev->info_waitq));
929
                }
930
                p = isdn_statstr();
931
                file->private_data = 0;
932
                if ((len = strlen(p)) <= count) {
933
                        if (copy_to_user(buf, p, len))
934
                                return -EFAULT;
935
                        file->f_pos += len;
936
                        return len;
937
                }
938
                return 0;
939
        }
940
        if (!dev->drivers)
941
                return -ENODEV;
942
        if (minor < ISDN_MINOR_CTRL) {
943
                drvidx = isdn_minor2drv(minor);
944
                if (drvidx < 0)
945
                        return -ENODEV;
946
                if (!(dev->drv[drvidx]->flags & DRV_FLAG_RUNNING))
947
                        return -ENODEV;
948
                chidx = isdn_minor2chan(minor);
949
                save_flags(flags);
950
                cli();
951
                len = isdn_readbchan(drvidx, chidx, buf, 0, count, 1);
952
                file->f_pos += len;
953
                restore_flags(flags);
954
                return len;
955
        }
956
        if (minor <= ISDN_MINOR_CTRLMAX) {
957
                drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL);
958
                if (drvidx < 0)
959
                        return -ENODEV;
960
                if (!dev->drv[drvidx]->stavail) {
961
                        if (file->f_flags & O_NONBLOCK)
962
                                return -EAGAIN;
963
                        interruptible_sleep_on(&(dev->drv[drvidx]->st_waitq));
964
                }
965
                if (dev->drv[drvidx]->interface->readstat)
966
                        len = dev->drv[drvidx]->interface->
967
                            readstat(buf, MIN(count, dev->drv[drvidx]->stavail),
968
                                     1, drvidx, isdn_minor2chan(minor));
969
                else
970
                        len = 0;
971
                save_flags(flags);
972
                cli();
973
                if (len)
974
                        dev->drv[drvidx]->stavail -= len;
975
                else
976
                        dev->drv[drvidx]->stavail = 0;
977
                restore_flags(flags);
978
                file->f_pos += len;
979
                return len;
980
        }
981
#ifdef CONFIG_ISDN_PPP
982
        if (minor <= ISDN_MINOR_PPPMAX)
983
                return (isdn_ppp_read(minor - ISDN_MINOR_PPP, file, buf, count));
984
#endif
985
        return -ENODEV;
986
}
987
 
988
static LSTYPE
989
isdn_lseek(struct inode *inode, struct file *file, LSARG offset, int orig)
990
{
991
        return -ESPIPE;
992
}
993
 
994
static RWTYPE
995
isdn_write(struct inode *inode, struct file *file, const char *buf, RWARG count)
996
{
997
        uint minor = MINOR(inode->i_rdev);
998
        int drvidx;
999
        int chidx;
1000
 
1001
        if (minor == ISDN_MINOR_STATUS)
1002
                return -EPERM;
1003
        if (!dev->drivers)
1004
                return -ENODEV;
1005
        if (minor < ISDN_MINOR_CTRL) {
1006
                drvidx = isdn_minor2drv(minor);
1007
                if (drvidx < 0)
1008
                        return -ENODEV;
1009
                if (!(dev->drv[drvidx]->flags & DRV_FLAG_RUNNING))
1010
                        return -ENODEV;
1011
                chidx = isdn_minor2chan(minor);
1012
                while (isdn_writebuf_stub(drvidx, chidx, buf, count, 1) != count)
1013
                        interruptible_sleep_on(&dev->drv[drvidx]->snd_waitq[chidx]);
1014
                return count;
1015
        }
1016
        if (minor <= ISDN_MINOR_CTRLMAX) {
1017
                drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL);
1018
                if (drvidx < 0)
1019
                        return -ENODEV;
1020
                /*
1021
                 * We want to use the isdnctrl device to load the firmware
1022
                 *
1023
                if (!(dev->drv[drvidx]->flags & DRV_FLAG_RUNNING))
1024
                 return -ENODEV;
1025
                 */
1026
                if (dev->drv[drvidx]->interface->writecmd)
1027
                        return (dev->drv[drvidx]->interface->
1028
                                writecmd(buf, count, 1, drvidx, isdn_minor2chan(minor)));
1029
                else
1030
                        return count;
1031
        }
1032
#ifdef CONFIG_ISDN_PPP
1033
        if (minor <= ISDN_MINOR_PPPMAX)
1034
                return (isdn_ppp_write(minor - ISDN_MINOR_PPP, file, buf, count));
1035
#endif
1036
        return -ENODEV;
1037
}
1038
 
1039
#if (LINUX_VERSION_CODE < 0x020117)
1040
static int
1041
isdn_select(struct inode *inode, struct file *file, int type, select_table * st)
1042
{
1043
        uint minor = MINOR(inode->i_rdev);
1044
        int drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL);
1045
 
1046
        if (minor == ISDN_MINOR_STATUS) {
1047
                if (file->private_data)
1048
                        return 1;
1049
                else {
1050
                        if (st)
1051
                                select_wait(&(dev->info_waitq), st);
1052
                        return 0;
1053
                }
1054
        }
1055
        if (minor >= ISDN_MINOR_CTRL && minor <= ISDN_MINOR_CTRLMAX) {
1056
                if (drvidx < 0)
1057
                        return -ENODEV;
1058
                if (dev->drv[drvidx]->stavail)
1059
                        return 1;
1060
                else {
1061
                        if (st)
1062
                                select_wait(&(dev->drv[drvidx]->st_waitq), st);
1063
                        return 0;
1064
                }
1065
                return 1;
1066
        }
1067
#ifdef CONFIG_ISDN_PPP
1068
        if (minor <= ISDN_MINOR_PPPMAX)
1069
                return (isdn_ppp_select(minor - ISDN_MINOR_PPP, file, type, st));
1070
#endif
1071
        return -ENODEV;
1072
}
1073
#else
1074
static unsigned int
1075
isdn_poll(struct file *file, poll_table * wait)
1076
{
1077
        unsigned int mask = 0;
1078
        unsigned int minor = MINOR(file->f_inode->i_rdev);
1079
        int drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL);
1080
 
1081
        if (minor == ISDN_MINOR_STATUS) {
1082
                poll_wait(&(dev->info_waitq), wait);
1083
                /* mask = POLLOUT | POLLWRNORM; */
1084
                if (file->private_data) {
1085
                        mask |= POLLIN | POLLRDNORM;
1086
                }
1087
                return mask;
1088
        }
1089
        if (minor >= ISDN_MINOR_CTRL && minor <= ISDN_MINOR_CTRLMAX) {
1090
                poll_wait(&(dev->drv[drvidx]->st_waitq), wait);
1091
                if (drvidx < 0) {
1092
                        printk(KERN_ERR "isdn_common: isdn_poll 1 -> what the hell\n");
1093
                        return POLLERR;
1094
                }
1095
                mask = POLLOUT | POLLWRNORM;
1096
                if (dev->drv[drvidx]->stavail) {
1097
                        mask |= POLLIN | POLLRDNORM;
1098
                }
1099
                return mask;
1100
        }
1101
#ifdef CONFIG_ISDN_PPP
1102
        if (minor <= ISDN_MINOR_PPPMAX)
1103
                return (isdn_ppp_poll(file, wait));
1104
#endif
1105
        printk(KERN_ERR "isdn_common: isdn_poll 2 -> what the hell\n");
1106
        return POLLERR;
1107
}
1108
#endif
1109
 
1110
typedef union {
1111
        char name[10];
1112
        char bname[22];
1113
        isdn_ioctl_struct iocts;
1114
        isdn_net_ioctl_phone phone;
1115
        isdn_net_ioctl_cfg cfg;
1116
} iocpar_t;
1117
 
1118
static int
1119
isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg)
1120
{
1121
        uint minor = MINOR(inode->i_rdev);
1122
        isdn_ctrl c;
1123
        int drvidx;
1124
        int chidx;
1125
        int ret;
1126
        int i;
1127
        char *p;
1128
        char *s;
1129
        iocpar_t *iocpar;
1130
 
1131
#define name  iocpar->name
1132
#define bname iocpar->bname
1133
#define iocts iocpar->iocts
1134
#define phone iocpar->phone
1135
#define cfg   iocpar->cfg
1136
 
1137
#define RETURN(r) ({ ret = r; kfree(iocpar); return ret; })
1138
 
1139
        if (minor == ISDN_MINOR_STATUS) {
1140
                switch (cmd) {
1141
                        case IIOCGETDVR:
1142
                                return (TTY_DV +
1143
                                        (NET_DV << 8) +
1144
                                        (INF_DV << 16));
1145
                        case IIOCGETCPS:
1146
                                if (arg) {
1147
                                        ulong *p = (ulong *) arg;
1148
                                        int i;
1149
                                        if ((ret = verify_area(VERIFY_WRITE, (void *) arg,
1150
                                                               sizeof(ulong) * ISDN_MAX_CHANNELS * 2)))
1151
                                                return ret;
1152
                                        for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
1153
                                                put_user(dev->ibytes[i], p++);
1154
                                                put_user(dev->obytes[i], p++);
1155
                                        }
1156
                                        return 0;
1157
                                } else
1158
                                        return -EINVAL;
1159
                                break;
1160
                        default:
1161
                                return -EINVAL;
1162
                }
1163
        }
1164
        if (!dev->drivers)
1165
                return -ENODEV;
1166
        if (minor < ISDN_MINOR_CTRL) {
1167
                drvidx = isdn_minor2drv(minor);
1168
                if (drvidx < 0)
1169
                        return -ENODEV;
1170
                chidx = isdn_minor2chan(minor);
1171
                if (!(dev->drv[drvidx]->flags & DRV_FLAG_RUNNING))
1172
                        return -ENODEV;
1173
                return 0;
1174
        }
1175
        if (minor <= ISDN_MINOR_CTRLMAX) {
1176
                if ((iocpar = (iocpar_t *)kmalloc(sizeof(iocpar_t), GFP_KERNEL)) == NULL) {
1177
                        printk(KERN_WARNING "isdn: Out of memory in isdn_ioctl\n");
1178
                        return -ENOMEM;
1179
                }
1180
                switch (cmd) {
1181
#ifdef CONFIG_NETDEVICES
1182
                        case IIOCNETAIF:
1183
                                /* Add a network-interface */
1184
                                if (arg) {
1185
                                        if ((ret = copy_from_user(name, (char *) arg, sizeof(name))))
1186
                                                RETURN(ret);
1187
                                        s = name;
1188
                                } else
1189
                                        s = NULL;
1190
                                if ((s = isdn_net_new(s, NULL))) {
1191
                                        if ((ret = copy_to_user((char *) arg, s, strlen(s) + 1)))
1192
                                                RETURN(ret);
1193
                                        RETURN(0);
1194
                                } else
1195
                                        RETURN(-ENODEV);
1196
                        case IIOCNETASL:
1197
                                /* Add a slave to a network-interface */
1198
                                if (arg) {
1199
                                        if ((ret = copy_from_user(bname, (char *) arg, sizeof(bname) - 1)))
1200
                                                RETURN(ret);
1201
                                } else
1202
                                        RETURN(-EINVAL);
1203
                                if ((s = isdn_net_newslave(bname))) {
1204
                                        if ((ret = copy_to_user((char *) arg, s, strlen(s) + 1)))
1205
                                                RETURN(ret);
1206
                                        RETURN(0);
1207
                                } else
1208
                                        RETURN(-ENODEV);
1209
                        case IIOCNETDIF:
1210
                                /* Delete a network-interface */
1211
                                if (arg) {
1212
                                        if ((ret = copy_from_user(name, (char *) arg, sizeof(name))))
1213
                                                RETURN(ret);
1214
                                        RETURN(isdn_net_rm(name));
1215
                                } else
1216
                                        RETURN(-EINVAL);
1217
                        case IIOCNETSCF:
1218
                                /* Set configurable parameters of a network-interface */
1219
                                if (arg) {
1220
                                        if ((ret = copy_from_user((char *) &cfg, (char *) arg, sizeof(cfg))))
1221
                                                RETURN(ret);
1222
                                        RETURN(isdn_net_setcfg(&cfg));
1223
                                } else
1224
                                        RETURN(-EINVAL);
1225
                        case IIOCNETGCF:
1226
                                /* Get configurable parameters of a network-interface */
1227
                                if (arg) {
1228
                                        if ((ret = copy_from_user((char *) &cfg, (char *) arg, sizeof(cfg))))
1229
                                                RETURN(ret);
1230
                                        if (!(ret = isdn_net_getcfg(&cfg))) {
1231
                                                if ((ret = copy_to_user((char *) arg, (char *) &cfg, sizeof(cfg))))
1232
                                                        RETURN(ret);
1233
                                        }
1234
                                        RETURN(ret);
1235
                                } else
1236
                                        RETURN(-EINVAL);
1237
                        case IIOCNETANM:
1238
                                /* Add a phone-number to a network-interface */
1239
                                if (arg) {
1240
                                        if ((ret = copy_from_user((char *) &phone, (char *) arg, sizeof(phone))))
1241
                                                RETURN(ret);
1242
                                        RETURN(isdn_net_addphone(&phone));
1243
                                } else
1244
                                        RETURN(-EINVAL);
1245
                        case IIOCNETGNM:
1246
                                /* Get list of phone-numbers of a network-interface */
1247
                                if (arg) {
1248
                                        if ((ret = copy_from_user((char *) &phone, (char *) arg, sizeof(phone))))
1249
                                                RETURN(ret);
1250
                                        RETURN(isdn_net_getphones(&phone, (char *) arg));
1251
                                } else
1252
                                        RETURN(-EINVAL);
1253
                        case IIOCNETDNM:
1254
                                /* Delete a phone-number of a network-interface */
1255
                                if (arg) {
1256
                                        if ((ret = copy_from_user((char *) &phone, (char *) arg, sizeof(phone))))
1257
                                                RETURN(ret);
1258
                                        RETURN(isdn_net_delphone(&phone));
1259
                                } else
1260
                                        RETURN(-EINVAL);
1261
                        case IIOCNETDIL:
1262
                                /* Force dialing of a network-interface */
1263
                                if (arg) {
1264
                                        if ((ret = copy_from_user(name, (char *) arg, sizeof(name))))
1265
                                                RETURN(ret);
1266
                                        RETURN(isdn_net_force_dial(name));
1267
                                } else
1268
                                        RETURN(-EINVAL);
1269
#ifdef CONFIG_ISDN_PPP
1270
                        case IIOCNETALN:
1271
                                if (!arg)
1272
                                        RETURN(-EINVAL);
1273
                                if ((ret = copy_from_user(name, (char *) arg, sizeof(name))))
1274
                                        RETURN(ret);
1275
                                RETURN(isdn_ppp_dial_slave(name));
1276
                        case IIOCNETDLN:
1277
                                if (!arg)
1278
                                        RETURN(-EINVAL);
1279
                                if ((ret = copy_from_user(name, (char *) arg, sizeof(name))))
1280
                                        RETURN(ret);
1281
                                RETURN(isdn_ppp_hangup_slave(name));
1282
#endif
1283
                        case IIOCNETHUP:
1284
                                /* Force hangup of a network-interface */
1285
                                if (!arg)
1286
                                        RETURN(-EINVAL);
1287
                                if ((ret = copy_from_user(name, (char *) arg, sizeof(name))))
1288
                                        RETURN(ret);
1289
                                RETURN(isdn_net_force_hangup(name));
1290
                                break;
1291
#endif                          /* CONFIG_NETDEVICES */
1292
                        case IIOCSETVER:
1293
                                dev->net_verbose = arg;
1294
                                printk(KERN_INFO "isdn: Verbose-Level is %d\n", dev->net_verbose);
1295
                                RETURN(0);
1296
                        case IIOCSETGST:
1297
                                if (arg)
1298
                                        dev->global_flags |= ISDN_GLOBAL_STOPPED;
1299
                                else
1300
                                        dev->global_flags &= ~ISDN_GLOBAL_STOPPED;
1301
                                printk(KERN_INFO "isdn: Global Mode %s\n",
1302
                                       (dev->global_flags & ISDN_GLOBAL_STOPPED) ? "stopped" : "running");
1303
                                RETURN(0);
1304
                        case IIOCSETBRJ:
1305
                                drvidx = -1;
1306
                                if (arg) {
1307
                                        int i;
1308
                                        char *p;
1309
                                        if ((ret = copy_from_user((char *) &iocts, (char *) arg,
1310
                                              sizeof(isdn_ioctl_struct))))
1311
                                                RETURN(ret);
1312
                                        if (strlen(iocts.drvid)) {
1313
                                                if ((p = strchr(iocts.drvid, ',')))
1314
                                                        *p = 0;
1315
                                                drvidx = -1;
1316
                                                for (i = 0; i < ISDN_MAX_DRIVERS; i++)
1317
                                                        if (!(strcmp(dev->drvid[i], iocts.drvid))) {
1318
                                                                drvidx = i;
1319
                                                                break;
1320
                                                        }
1321
                                        }
1322
                                }
1323
                                if (drvidx == -1)
1324
                                        RETURN(-ENODEV);
1325
                                if (iocts.arg)
1326
                                        dev->drv[drvidx]->flags |= DRV_FLAG_REJBUS;
1327
                                else
1328
                                        dev->drv[drvidx]->flags &= ~DRV_FLAG_REJBUS;
1329
                                RETURN(0);
1330
                        case IIOCSIGPRF:
1331
                                dev->profd = current;
1332
                                RETURN(0);
1333
                                break;
1334
                        case IIOCGETPRF:
1335
                                /* Get all Modem-Profiles */
1336
                                if (arg) {
1337
                                        char *p = (char *) arg;
1338
                                        int i;
1339
 
1340
                                        if ((ret = verify_area(VERIFY_WRITE, (void *) arg,
1341
                                        (ISDN_MODEM_ANZREG + ISDN_MSNLEN)
1342
                                                   * ISDN_MAX_CHANNELS)))
1343
                                                RETURN(ret);
1344
 
1345
                                        for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
1346
                                                if (copy_to_user(p, dev->mdm.info[i].emu.profile,
1347
                                                      ISDN_MODEM_ANZREG))
1348
                                                        RETURN(-EFAULT);
1349
                                                p += ISDN_MODEM_ANZREG;
1350
                                                if (copy_to_user(p, dev->mdm.info[i].emu.pmsn, ISDN_MSNLEN))
1351
                                                        RETURN(-EFAULT);
1352
                                                p += ISDN_MSNLEN;
1353
                                        }
1354
                                        RETURN((ISDN_MODEM_ANZREG + ISDN_MSNLEN) * ISDN_MAX_CHANNELS);
1355
                                } else
1356
                                        RETURN(-EINVAL);
1357
                                break;
1358
                        case IIOCSETPRF:
1359
                                /* Set all Modem-Profiles */
1360
                                if (arg) {
1361
                                        char *p = (char *) arg;
1362
                                        int i;
1363
 
1364
                                        if ((ret = verify_area(VERIFY_READ, (void *) arg,
1365
                                        (ISDN_MODEM_ANZREG + ISDN_MSNLEN)
1366
                                                   * ISDN_MAX_CHANNELS)))
1367
                                                RETURN(ret);
1368
 
1369
                                        for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
1370
                                                if ((ret = copy_from_user(dev->mdm.info[i].emu.profile, p,
1371
                                                      ISDN_MODEM_ANZREG)))
1372
                                                        RETURN(ret);
1373
                                                p += ISDN_MODEM_ANZREG;
1374
                                                if ((ret = copy_from_user(dev->mdm.info[i].emu.pmsn, p, ISDN_MSNLEN)))
1375
                                                        RETURN(ret);
1376
                                                p += ISDN_MSNLEN;
1377
                                        }
1378
                                        RETURN(0);
1379
                                } else
1380
                                        RETURN(-EINVAL);
1381
                                break;
1382
                        case IIOCSETMAP:
1383
                        case IIOCGETMAP:
1384
                                /* Set/Get MSN->EAZ-Mapping for a driver */
1385
                                if (arg) {
1386
 
1387
                                        if ((ret = copy_from_user((char *) &iocts,
1388
                                                            (char *) arg,
1389
                                             sizeof(isdn_ioctl_struct))))
1390
                                                RETURN(ret);
1391
                                        if (strlen(iocts.drvid)) {
1392
                                                drvidx = -1;
1393
                                                for (i = 0; i < ISDN_MAX_DRIVERS; i++)
1394
                                                        if (!(strcmp(dev->drvid[i], iocts.drvid))) {
1395
                                                                drvidx = i;
1396
                                                                break;
1397
                                                        }
1398
                                        } else
1399
                                                drvidx = 0;
1400
                                        if (drvidx == -1)
1401
                                                RETURN(-ENODEV);
1402
                                        if (cmd == IIOCSETMAP) {
1403
                                                int loop = 1;
1404
 
1405
                                                p = (char *) iocts.arg;
1406
                                                i = 0;
1407
                                                while (loop) {
1408
                                                        int j = 0;
1409
 
1410
                                                        while (1) {
1411
                                                                if ((ret = verify_area(VERIFY_READ, p, 1)))
1412
                                                                        RETURN(ret);
1413
                                                                GET_USER(bname[j], p++);
1414
                                                                switch (bname[j]) {
1415
                                                                        case '\0':
1416
                                                                                loop = 0;
1417
                                                                                /* Fall through */
1418
                                                                        case ',':
1419
                                                                                bname[j] = '\0';
1420
                                                                                strcpy(dev->drv[drvidx]->msn2eaz[i], bname);
1421
                                                                                j = ISDN_MSNLEN;
1422
                                                                                break;
1423
                                                                        default:
1424
                                                                                j++;
1425
                                                                }
1426
                                                                if (j >= ISDN_MSNLEN)
1427
                                                                        break;
1428
                                                        }
1429
                                                        if (++i > 9)
1430
                                                                break;
1431
                                                }
1432
                                        } else {
1433
                                                p = (char *) iocts.arg;
1434
                                                for (i = 0; i < 10; i++) {
1435
                                                        sprintf(bname, "%s%s",
1436
                                                                strlen(dev->drv[drvidx]->msn2eaz[i]) ?
1437
                                                                dev->drv[drvidx]->msn2eaz[i] : "-",
1438
                                                                (i < 9) ? "," : "\0");
1439
                                                        if ((ret = copy_to_user(p, bname, strlen(bname) + 1)))
1440
                                                                RETURN(ret);
1441
                                                        p += strlen(bname);
1442
                                                }
1443
                                        }
1444
                                        RETURN(0);
1445
                                } else
1446
                                        RETURN(-EINVAL);
1447
                        case IIOCDBGVAR:
1448
                                if (arg) {
1449
                                        if ((ret = copy_to_user((char *) arg, (char *) &dev, sizeof(ulong))))
1450
                                                RETURN(ret);
1451
                                        RETURN(0);
1452
                                } else
1453
                                        RETURN(-EINVAL);
1454
                                break;
1455
                        default:
1456
                                if ((cmd & IIOCDRVCTL) == IIOCDRVCTL)
1457
                                        cmd = ((cmd >> _IOC_NRSHIFT) & _IOC_NRMASK) & ISDN_DRVIOCTL_MASK;
1458
                                else
1459
                                        RETURN(-EINVAL);
1460
                                if (arg) {
1461
                                        int i;
1462
                                        char *p;
1463
                                        if ((ret = copy_from_user((char *) &iocts, (char *) arg, sizeof(isdn_ioctl_struct))))
1464
                                                RETURN(ret);
1465
                                        if (strlen(iocts.drvid)) {
1466
                                                if ((p = strchr(iocts.drvid, ',')))
1467
                                                        *p = 0;
1468
                                                drvidx = -1;
1469
                                                for (i = 0; i < ISDN_MAX_DRIVERS; i++)
1470
                                                        if (!(strcmp(dev->drvid[i], iocts.drvid))) {
1471
                                                                drvidx = i;
1472
                                                                break;
1473
                                                        }
1474
                                        } else
1475
                                                drvidx = 0;
1476
                                        if (drvidx == -1)
1477
                                                RETURN(-ENODEV);
1478
                                        if ((ret = verify_area(VERIFY_WRITE, (void *) arg,
1479
                                             sizeof(isdn_ioctl_struct))))
1480
                                                RETURN(ret);
1481
                                        c.driver = drvidx;
1482
                                        c.command = ISDN_CMD_IOCTL;
1483
                                        c.arg = cmd;
1484
                                        memcpy(c.parm.num, (char *) &iocts.arg, sizeof(ulong));
1485
                                        ret = isdn_command(&c);
1486
                                        memcpy((char *) &iocts.arg, c.parm.num, sizeof(ulong));
1487
                                        if ((copy_to_user((char *) arg, &iocts, sizeof(isdn_ioctl_struct))))
1488
                                                RETURN(-EFAULT);
1489
                                        RETURN(ret);
1490
                                } else
1491
                                        RETURN(-EINVAL);
1492
                }
1493
        }
1494
#ifdef CONFIG_ISDN_PPP
1495
        if (minor <= ISDN_MINOR_PPPMAX)
1496
                return (isdn_ppp_ioctl(minor - ISDN_MINOR_PPP, file, cmd, arg));
1497
#endif
1498
        return -ENODEV;
1499
 
1500
#undef name
1501
#undef bname
1502
#undef iocts
1503
#undef phone
1504
#undef cfg
1505
 
1506
#undef RETURN
1507
}
1508
 
1509
/*
1510
 * Open the device code.
1511
 * MOD_INC_USE_COUNT make sure that the driver memory is not freed
1512
 * while the device is in use.
1513
 */
1514
static int
1515
isdn_open(struct inode *ino, struct file *filep)
1516
{
1517
        uint minor = MINOR(ino->i_rdev);
1518
        int drvidx;
1519
        int chidx;
1520
 
1521
        if (minor == ISDN_MINOR_STATUS) {
1522
                infostruct *p;
1523
 
1524
                if ((p = (infostruct *) kmalloc(sizeof(infostruct), GFP_KERNEL))) {
1525
                        MOD_INC_USE_COUNT;
1526
                        p->next = (char *) dev->infochain;
1527
                        p->private = (char *) &(filep->private_data);
1528
                        dev->infochain = p;
1529
                        /* At opening we allow a single update */
1530
                        filep->private_data = (char *) 1;
1531
                        return 0;
1532
                } else
1533
                        return -ENOMEM;
1534
        }
1535
        if (!dev->channels)
1536
                return -ENODEV;
1537
        if (minor < ISDN_MINOR_CTRL) {
1538
                drvidx = isdn_minor2drv(minor);
1539
                if (drvidx < 0)
1540
                        return -ENODEV;
1541
                chidx = isdn_minor2chan(minor);
1542
                if (!(dev->drv[drvidx]->flags & DRV_FLAG_RUNNING))
1543
                        return -ENODEV;
1544
                if (!(dev->drv[drvidx]->online & (1 << chidx)))
1545
                        return -ENODEV;
1546
                isdn_MOD_INC_USE_COUNT();
1547
                return 0;
1548
        }
1549
        if (minor <= ISDN_MINOR_CTRLMAX) {
1550
                drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL);
1551
                if (drvidx < 0)
1552
                        return -ENODEV;
1553
                isdn_MOD_INC_USE_COUNT();
1554
                return 0;
1555
        }
1556
#ifdef CONFIG_ISDN_PPP
1557
        if (minor <= ISDN_MINOR_PPPMAX) {
1558
                int ret;
1559
                if (!(ret = isdn_ppp_open(minor - ISDN_MINOR_PPP, filep)))
1560
                        isdn_MOD_INC_USE_COUNT();
1561
                return ret;
1562
        }
1563
#endif
1564
        return -ENODEV;
1565
}
1566
 
1567
static CLOSETYPE
1568
isdn_close(struct inode *ino, struct file *filep)
1569
{
1570
        uint minor = MINOR(ino->i_rdev);
1571
 
1572
        if (minor == ISDN_MINOR_STATUS) {
1573
                infostruct *p = dev->infochain;
1574
                infostruct *q = NULL;
1575
 
1576
 
1577
                MOD_DEC_USE_COUNT;
1578
                while (p) {
1579
                        if (p->private == (char *) &(filep->private_data)) {
1580
                                if (q)
1581
                                        q->next = p->next;
1582
                                else
1583
                                        dev->infochain = (infostruct *) (p->next);
1584
                                kfree(p);
1585
                                return CLOSEVAL;
1586
                        }
1587
                        q = p;
1588
                        p = (infostruct *) (p->next);
1589
                }
1590
                printk(KERN_WARNING "isdn: No private data while closing isdnctrl\n");
1591
                return CLOSEVAL;
1592
        }
1593
        isdn_MOD_DEC_USE_COUNT();
1594
        if (minor < ISDN_MINOR_CTRL)
1595
                return CLOSEVAL;
1596
        if (minor <= ISDN_MINOR_CTRLMAX) {
1597
                if (dev->profd == current)
1598
                        dev->profd = NULL;
1599
                return CLOSEVAL;
1600
        }
1601
#ifdef CONFIG_ISDN_PPP
1602
        if (minor <= ISDN_MINOR_PPPMAX)
1603
                isdn_ppp_release(minor - ISDN_MINOR_PPP, filep);
1604
#endif
1605
        return CLOSEVAL;
1606
}
1607
 
1608
static struct file_operations isdn_fops =
1609
{
1610
        isdn_lseek,
1611
        isdn_read,
1612
        isdn_write,
1613
        NULL,                   /* isdn_readdir */
1614
#if (LINUX_VERSION_CODE < 0x020117)
1615
        isdn_select,            /* isdn_select */
1616
#else
1617
        isdn_poll,              /* isdn_poll */
1618
#endif
1619
        isdn_ioctl,             /* isdn_ioctl */
1620
        NULL,                   /* isdn_mmap */
1621
        isdn_open,
1622
        isdn_close,
1623
        NULL                    /* fsync */
1624
};
1625
 
1626
char *
1627
isdn_map_eaz2msn(char *msn, int di)
1628
{
1629
        driver *this = dev->drv[di];
1630
        int i;
1631
 
1632
        if (strlen(msn) == 1) {
1633
                i = msn[0] - '0';
1634
                if ((i >= 0) && (i <= 9))
1635
                        if (strlen(this->msn2eaz[i]))
1636
                                return (this->msn2eaz[i]);
1637
        }
1638
        return (msn);
1639
}
1640
 
1641
/*
1642
 * Find an unused ISDN-channel, whose feature-flags match the
1643
 * given L2- and L3-protocols.
1644
 */
1645
int
1646
isdn_get_free_channel(int usage, int l2_proto, int l3_proto, int pre_dev
1647
                      ,int pre_chan)
1648
{
1649
        int i;
1650
        ulong flags;
1651
        ulong features;
1652
 
1653
        save_flags(flags);
1654
        cli();
1655
        features = (1 << l2_proto) | (0x100 << l3_proto);
1656
        for (i = 0; i < ISDN_MAX_CHANNELS; i++)
1657
                if (USG_NONE(dev->usage[i]) &&
1658
                    (dev->drvmap[i] != -1)) {
1659
                        int d = dev->drvmap[i];
1660
                        if ((dev->usage[i] & ISDN_USAGE_EXCLUSIVE) &&
1661
                        ((pre_dev != d) || (pre_chan != dev->chanmap[i])))
1662
                                continue;
1663
                        if (dev->drv[d]->flags & DRV_FLAG_RUNNING) {
1664
                                if ((dev->drv[d]->interface->features & features) == features) {
1665
                                        if ((pre_dev < 0) || (pre_chan < 0)) {
1666
                                                dev->usage[i] &= ISDN_USAGE_EXCLUSIVE;
1667
                                                dev->usage[i] |= usage;
1668
                                                isdn_info_update();
1669
                                                restore_flags(flags);
1670
                                                return i;
1671
                                        } else {
1672
                                                if ((pre_dev == d) && (pre_chan == dev->chanmap[i])) {
1673
                                                        dev->usage[i] &= ISDN_USAGE_EXCLUSIVE;
1674
                                                        dev->usage[i] |= usage;
1675
                                                        isdn_info_update();
1676
                                                        restore_flags(flags);
1677
                                                        return i;
1678
                                                }
1679
                                        }
1680
                                }
1681
                        }
1682
                }
1683
        restore_flags(flags);
1684
        return -1;
1685
}
1686
 
1687
/*
1688
 * Set state of ISDN-channel to 'unused'
1689
 */
1690
void
1691
isdn_free_channel(int di, int ch, int usage)
1692
{
1693
        int i;
1694
        ulong flags;
1695
        isdn_ctrl cmd;
1696
 
1697
        save_flags(flags);
1698
        cli();
1699
        for (i = 0; i < ISDN_MAX_CHANNELS; i++)
1700
                if (((dev->usage[i] & ISDN_USAGE_MASK) == usage) &&
1701
                    (dev->drvmap[i] == di) &&
1702
                    (dev->chanmap[i] == ch)) {
1703
                        dev->usage[i] &= (ISDN_USAGE_NONE | ISDN_USAGE_EXCLUSIVE);
1704
                        strcpy(dev->num[i], "???");
1705
                        dev->ibytes[i] = 0;
1706
                        dev->obytes[i] = 0;
1707
                        isdn_info_update();
1708
                        isdn_free_queue(&dev->drv[di]->rpqueue[ch]);
1709
                        cmd.driver = di;
1710
                        cmd.arg = ch;
1711
                        cmd.command = ISDN_CMD_HANGUP;
1712
                        restore_flags(flags);
1713
                        isdn_command(&cmd);
1714
                        return;
1715
                }
1716
        printk(KERN_DEBUG "Unmatched free_channel d=%d c=%d u=%d\n", di, ch, usage);
1717
        restore_flags(flags);
1718
}
1719
 
1720
/*
1721
 * Cancel Exclusive-Flag for ISDN-channel
1722
 */
1723
void
1724
isdn_unexclusive_channel(int di, int ch)
1725
{
1726
        int i;
1727
        ulong flags;
1728
 
1729
        save_flags(flags);
1730
        cli();
1731
        for (i = 0; i < ISDN_MAX_CHANNELS; i++)
1732
                if ((dev->drvmap[i] == di) &&
1733
                    (dev->chanmap[i] == ch)) {
1734
                        dev->usage[i] &= ~ISDN_USAGE_EXCLUSIVE;
1735
                        isdn_info_update();
1736
                        restore_flags(flags);
1737
                        return;
1738
                }
1739
        restore_flags(flags);
1740
}
1741
 
1742
/*
1743
 * receive callback handler for drivers not supporting sk_buff's.
1744
 * Parameters:
1745
 *
1746
 * di      = Driver-Index.
1747
 * channel = Number of B-Channel (0...)
1748
 * buf     = pointer to packet-data
1749
 * len     = Length of packet-data
1750
 *
1751
 */
1752
static void
1753
isdn_receive_callback(int drvidx, int chan, u_char * buf, int len)
1754
{
1755
        struct sk_buff *skb;
1756
 
1757
        if (dev->global_flags & ISDN_GLOBAL_STOPPED)
1758
                return;
1759
        skb = dev_alloc_skb(len);
1760
        if (skb) {
1761
                memcpy(skb_put(skb, len), buf, len);
1762
                isdn_receive_skb_callback(drvidx, chan, skb);
1763
        } else
1764
                printk(KERN_WARNING "isdn: rcv alloc_skb failed, packet dropped.\n");
1765
}
1766
 
1767
/*
1768
 *  writebuf replacement for SKB_ABLE drivers
1769
 */
1770
static int
1771
isdn_writebuf_stub(int drvidx, int chan, const u_char * buf, int len,
1772
                   int user)
1773
{
1774
        int ret;
1775
 
1776
        if (dev->drv[drvidx]->interface->writebuf)
1777
                ret = dev->drv[drvidx]->interface->writebuf(drvidx, chan, buf,
1778
                                                            len, user);
1779
        else {
1780
                struct sk_buff *skb;
1781
 
1782
                skb = alloc_skb(dev->drv[drvidx]->interface->hl_hdrlen + len,
1783
                                GFP_ATOMIC);
1784
                if (skb == NULL)
1785
                        return 0;
1786
 
1787
                skb_reserve(skb, dev->drv[drvidx]->interface->hl_hdrlen);
1788
                SET_SKB_FREE(skb);
1789
 
1790
                if (user)
1791
                        copy_from_user(skb_put(skb, len), buf, len);
1792
                else
1793
                        memcpy(skb_put(skb, len), buf, len);
1794
 
1795
                ret = dev->drv[drvidx]->interface->writebuf_skb(drvidx,
1796
                                                              chan, skb);
1797
                if (ret <= 0)
1798
                        kfree_skb(skb, FREE_WRITE);
1799
        }
1800
        if (ret > 0)
1801
                dev->obytes[isdn_dc2minor(drvidx, chan)] += ret;
1802
        return ret;
1803
}
1804
 
1805
/*
1806
 * writebuf_skb replacement for NON SKB_ABLE drivers
1807
 * If lowlevel-device does not support supports skbufs, use
1808
 * standard send-routine, else sind directly.
1809
 *
1810
 * Return: length of data on success, -ERRcode on failure.
1811
 */
1812
 
1813
int
1814
isdn_writebuf_skb_stub(int drvidx, int chan, struct sk_buff *skb)
1815
{
1816
        int ret;
1817
        int len = skb->len;     /* skb pointer no longer valid after free */
1818
 
1819
        if (dev->drv[drvidx]->interface->writebuf_skb)
1820
                ret = dev->drv[drvidx]->interface->
1821
                    writebuf_skb(drvidx, chan, skb);
1822
        else {
1823
                if ((ret = dev->drv[drvidx]->interface->
1824
                  writebuf(drvidx, chan, skb->data, skb->len, 0)) == len)
1825
                        dev_kfree_skb(skb, FREE_WRITE);
1826
        }
1827
        if (ret > 0)
1828
                dev->obytes[isdn_dc2minor(drvidx, chan)] += len;
1829
        return ret;
1830
}
1831
 
1832
/*
1833
 * Low-level-driver registration
1834
 */
1835
 
1836
int
1837
register_isdn(isdn_if * i)
1838
{
1839
        driver *d;
1840
        int n,
1841
         j,
1842
         k;
1843
        ulong flags;
1844
        int drvidx;
1845
 
1846
        if (dev->drivers >= ISDN_MAX_DRIVERS) {
1847
                printk(KERN_WARNING "register_isdn: Max. %d drivers supported\n",
1848
                       ISDN_MAX_DRIVERS);
1849
                return 0;
1850
        }
1851
        n = i->channels;
1852
        if (dev->channels + n > ISDN_MAX_CHANNELS) {
1853
                printk(KERN_WARNING "register_isdn: Max. %d channels supported\n",
1854
                       ISDN_MAX_CHANNELS);
1855
                return 0;
1856
        }
1857
        if ((!i->writebuf_skb) && (!i->writebuf)) {
1858
                printk(KERN_WARNING "register_isdn: No write routine given.\n");
1859
                return 0;
1860
        }
1861
        if (!(d = (driver *) kmalloc(sizeof(driver), GFP_KERNEL))) {
1862
                printk(KERN_WARNING "register_isdn: Could not alloc driver-struct\n");
1863
                return 0;
1864
        }
1865
        memset((char *) d, 0, sizeof(driver));
1866
        if (!(d->rcverr = (int *) kmalloc(sizeof(int) * n, GFP_KERNEL))) {
1867
                printk(KERN_WARNING "register_isdn: Could not alloc rcverr\n");
1868
                kfree(d);
1869
                return 0;
1870
        }
1871
        memset((char *) d->rcverr, 0, sizeof(int) * n);
1872
        if (!(d->rcvcount = (int *) kmalloc(sizeof(int) * n, GFP_KERNEL))) {
1873
                printk(KERN_WARNING "register_isdn: Could not alloc rcvcount\n");
1874
                kfree(d->rcverr);
1875
                kfree(d);
1876
                return 0;
1877
        }
1878
        memset((char *) d->rcvcount, 0, sizeof(int) * n);
1879
        if (!(d->rpqueue =
1880
              (struct sk_buff_head *) kmalloc(sizeof(struct sk_buff_head) * n, GFP_KERNEL))) {
1881
                printk(KERN_WARNING "register_isdn: Could not alloc rpqueue\n");
1882
                kfree(d->rcvcount);
1883
                kfree(d->rcverr);
1884
                kfree(d);
1885
                return 0;
1886
        }
1887
        for (j = 0; j < n; j++) {
1888
                skb_queue_head_init(&d->rpqueue[j]);
1889
        }
1890
        if (!(d->rcv_waitq = (struct wait_queue **)
1891
              kmalloc(sizeof(struct wait_queue *) * n, GFP_KERNEL))) {
1892
                printk(KERN_WARNING "register_isdn: Could not alloc rcv_waitq\n");
1893
                kfree(d->rpqueue);
1894
                kfree(d->rcvcount);
1895
                kfree(d->rcverr);
1896
                kfree(d);
1897
                return 0;
1898
        }
1899
        memset((char *) d->rcv_waitq, 0, sizeof(struct wait_queue *) * n);
1900
        if (!(d->snd_waitq = (struct wait_queue **)
1901
              kmalloc(sizeof(struct wait_queue *) * n, GFP_KERNEL))) {
1902
                printk(KERN_WARNING "register_isdn: Could not alloc snd_waitq\n");
1903
                kfree(d->rcv_waitq);
1904
                kfree(d->rpqueue);
1905
                kfree(d->rcvcount);
1906
                kfree(d->rcverr);
1907
                kfree(d);
1908
                return 0;
1909
        }
1910
        memset((char *) d->snd_waitq, 0, sizeof(struct wait_queue *) * n);
1911
        d->channels = n;
1912
        d->maxbufsize = i->maxbufsize;
1913
        d->pktcount = 0;
1914
        d->stavail = 0;
1915
        d->flags = DRV_FLAG_LOADED;
1916
        d->online = 0;
1917
        d->interface = i;
1918
        for (drvidx = 0; drvidx < ISDN_MAX_DRIVERS; drvidx++)
1919
                if (!dev->drv[drvidx])
1920
                        break;
1921
        i->channels = drvidx;
1922
 
1923
        i->rcvcallb_skb = isdn_receive_skb_callback;
1924
        i->rcvcallb = isdn_receive_callback;
1925
        i->statcallb = isdn_status_callback;
1926
        if (!strlen(i->id))
1927
                sprintf(i->id, "line%d", drvidx);
1928
        save_flags(flags);
1929
        cli();
1930
        for (j = 0; j < drvidx; j++)
1931
                if (!strcmp(i->id, dev->drvid[j]))
1932
                        sprintf(i->id, "line%d", drvidx);
1933
        for (j = 0; j < n; j++)
1934
                for (k = 0; k < ISDN_MAX_CHANNELS; k++)
1935
                        if (dev->chanmap[k] < 0) {
1936
                                dev->chanmap[k] = j;
1937
                                dev->drvmap[k] = drvidx;
1938
                                break;
1939
                        }
1940
        dev->drv[drvidx] = d;
1941
        dev->channels += n;
1942
        strcpy(dev->drvid[drvidx], i->id);
1943
        isdn_info_update();
1944
        dev->drivers++;
1945
        restore_flags(flags);
1946
        return 1;
1947
}
1948
 
1949
/*
1950
 *****************************************************************************
1951
 * And now the modules code.
1952
 *****************************************************************************
1953
 */
1954
 
1955
extern int printk(const char *fmt,...);
1956
 
1957
#ifdef MODULE
1958
#define isdn_init init_module
1959
#endif
1960
 
1961
static char *
1962
isdn_getrev(const char *revision)
1963
{
1964
        char *rev;
1965
        char *p;
1966
 
1967
        if ((p = strchr(revision, ':'))) {
1968
                rev = p + 2;
1969
                p = strchr(rev, '$');
1970
                *--p = 0;
1971
        } else
1972
                rev = "???";
1973
        return rev;
1974
}
1975
 
1976
/*
1977
 * Allocate and initialize all data, register modem-devices
1978
 */
1979
int
1980
isdn_init(void)
1981
{
1982
        int i;
1983
        char irev[50];
1984
        char trev[50];
1985
        char nrev[50];
1986
        char prev[50];
1987
        char arev[50];
1988
 
1989
        sti();
1990
        if (!(dev = (isdn_dev *) kmalloc(sizeof(isdn_dev), GFP_KERNEL))) {
1991
                printk(KERN_WARNING "isdn: Could not allocate device-struct.\n");
1992
                return -EIO;
1993
        }
1994
        memset((char *) dev, 0, sizeof(isdn_dev));
1995
        init_timer(&dev->timer);
1996
        dev->timer.function = isdn_timer_funct;
1997
        for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
1998
                dev->drvmap[i] = -1;
1999
                dev->chanmap[i] = -1;
2000
                dev->m_idx[i] = -1;
2001
                strcpy(dev->num[i], "???");
2002
        }
2003
        if (register_chrdev(ISDN_MAJOR, "isdn", &isdn_fops)) {
2004
                printk(KERN_WARNING "isdn: Could not register control devices\n");
2005
                kfree(dev);
2006
                return -EIO;
2007
        }
2008
        if ((i = isdn_tty_modem_init()) < 0) {
2009
                printk(KERN_WARNING "isdn: Could not register tty devices\n");
2010
                if (i == -3)
2011
                        tty_unregister_driver(&dev->mdm.cua_modem);
2012
                if (i <= -2)
2013
                        tty_unregister_driver(&dev->mdm.tty_modem);
2014
                kfree(dev);
2015
                unregister_chrdev(ISDN_MAJOR, "isdn");
2016
                return -EIO;
2017
        }
2018
#ifdef CONFIG_ISDN_PPP
2019
        if (isdn_ppp_init() < 0) {
2020
                printk(KERN_WARNING "isdn: Could not create PPP-device-structs\n");
2021
                tty_unregister_driver(&dev->mdm.tty_modem);
2022
                tty_unregister_driver(&dev->mdm.cua_modem);
2023
                for (i = 0; i < ISDN_MAX_CHANNELS; i++)
2024
                        kfree(dev->mdm.info[i].xmit_buf - 4);
2025
                unregister_chrdev(ISDN_MAJOR, "isdn");
2026
                kfree(dev);
2027
                return -EIO;
2028
        }
2029
#endif                          /* CONFIG_ISDN_PPP */
2030
 
2031
        isdn_export_syms();
2032
 
2033
        strcpy(irev, isdn_revision);
2034
        strcpy(trev, isdn_tty_revision);
2035
        strcpy(nrev, isdn_net_revision);
2036
        strcpy(prev, isdn_ppp_revision);
2037
        strcpy(arev, isdn_audio_revision);
2038
        printk(KERN_NOTICE "ISDN subsystem Rev: %s/", isdn_getrev(irev));
2039
        printk("%s/", isdn_getrev(trev));
2040
        printk("%s/", isdn_getrev(nrev));
2041
        printk("%s/", isdn_getrev(prev));
2042
        printk("%s", isdn_getrev(arev));
2043
 
2044
#ifdef MODULE
2045
        printk(" loaded\n");
2046
#else
2047
        printk("\n");
2048
        isdn_cards_init();
2049
#endif
2050
        isdn_info_update();
2051
        return 0;
2052
}
2053
 
2054
#ifdef MODULE
2055
/*
2056
 * Unload module
2057
 */
2058
void
2059
cleanup_module(void)
2060
{
2061
        int flags;
2062
        int i;
2063
 
2064
#ifdef CONFIG_ISDN_PPP
2065
        isdn_ppp_cleanup();
2066
#endif
2067
        save_flags(flags);
2068
        cli();
2069
        if (isdn_net_rmall() < 0) {
2070
                printk(KERN_WARNING "isdn: net-device busy, remove cancelled\n");
2071
                restore_flags(flags);
2072
                return;
2073
        }
2074
        if (tty_unregister_driver(&dev->mdm.tty_modem)) {
2075
                printk(KERN_WARNING "isdn: ttyI-device busy, remove cancelled\n");
2076
                restore_flags(flags);
2077
                return;
2078
        }
2079
        if (tty_unregister_driver(&dev->mdm.cua_modem)) {
2080
                printk(KERN_WARNING "isdn: cui-device busy, remove cancelled\n");
2081
                restore_flags(flags);
2082
                return;
2083
        }
2084
        for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
2085
                isdn_tty_cleanup_xmit(&dev->mdm.info[i]);
2086
                kfree(dev->mdm.info[i].xmit_buf - 4);
2087
        }
2088
        if (unregister_chrdev(ISDN_MAJOR, "isdn") != 0) {
2089
                printk(KERN_WARNING "isdn: controldevice busy, remove cancelled\n");
2090
        } else {
2091
                del_timer(&dev->timer);
2092
                kfree(dev);
2093
                printk(KERN_NOTICE "ISDN-subsystem unloaded\n");
2094
        }
2095
        restore_flags(flags);
2096
}
2097
#endif

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.