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

Subversion Repositories test_project

[/] [test_project/] [trunk/] [linux_sd_driver/] [drivers/] [isdn/] [capi/] [capidrv.c] - Blame information for rev 62

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 62 marcus.erl
/* $Id: capidrv.c,v 1.1.2.2 2004/01/12 23:17:24 keil Exp $
2
 *
3
 * ISDN4Linux Driver, using capi20 interface (kernelcapi)
4
 *
5
 * Copyright 1997 by Carsten Paeth <calle@calle.de>
6
 *
7
 * This software may be used and distributed according to the terms
8
 * of the GNU General Public License, incorporated herein by reference.
9
 *
10
 */
11
 
12
#include <linux/module.h>
13
#include <linux/errno.h>
14
#include <linux/kernel.h>
15
#include <linux/major.h>
16
#include <linux/slab.h>
17
#include <linux/fcntl.h>
18
#include <linux/fs.h>
19
#include <linux/signal.h>
20
#include <linux/mm.h>
21
#include <linux/timer.h>
22
#include <linux/wait.h>
23
#include <linux/skbuff.h>
24
#include <linux/isdn.h>
25
#include <linux/isdnif.h>
26
#include <linux/proc_fs.h>
27
#include <linux/capi.h>
28
#include <linux/kernelcapi.h>
29
#include <linux/ctype.h>
30
#include <linux/init.h>
31
#include <linux/moduleparam.h>
32
 
33
#include <linux/isdn/capiutil.h>
34
#include <linux/isdn/capicmd.h>
35
#include "capidrv.h"
36
 
37
static char *revision = "$Revision: 1.1.2.2 $";
38
static int debugmode = 0;
39
 
40
MODULE_DESCRIPTION("CAPI4Linux: Interface to ISDN4Linux");
41
MODULE_AUTHOR("Carsten Paeth");
42
MODULE_LICENSE("GPL");
43
module_param(debugmode, uint, 0);
44
 
45
/* -------- type definitions ----------------------------------------- */
46
 
47
 
48
struct capidrv_contr {
49
 
50
        struct capidrv_contr *next;
51
        struct module *owner;
52
        u32 contrnr;
53
        char name[20];
54
 
55
        /*
56
         * for isdn4linux
57
         */
58
        isdn_if interface;
59
        int myid;
60
 
61
        /*
62
         * LISTEN state
63
         */
64
        int state;
65
        u32 cipmask;
66
        u32 cipmask2;
67
        struct timer_list listentimer;
68
 
69
        /*
70
         * ID of capi message sent
71
         */
72
        u16 msgid;
73
 
74
        /*
75
         * B-Channels
76
         */
77
        int nbchan;
78
        struct capidrv_bchan {
79
                struct capidrv_contr *contr;
80
                u8 msn[ISDN_MSNLEN];
81
                int l2;
82
                int l3;
83
                u8 num[ISDN_MSNLEN];
84
                u8 mynum[ISDN_MSNLEN];
85
                int si1;
86
                int si2;
87
                int incoming;
88
                int disconnecting;
89
                struct capidrv_plci {
90
                        struct capidrv_plci *next;
91
                        u32 plci;
92
                        u32 ncci;       /* ncci for CONNECT_ACTIVE_IND */
93
                        u16 msgid;      /* to identfy CONNECT_CONF */
94
                        int chan;
95
                        int state;
96
                        int leasedline;
97
                        struct capidrv_ncci {
98
                                struct capidrv_ncci *next;
99
                                struct capidrv_plci *plcip;
100
                                u32 ncci;
101
                                u16 msgid;      /* to identfy CONNECT_B3_CONF */
102
                                int chan;
103
                                int state;
104
                                int oldstate;
105
                                /* */
106
                                u16 datahandle;
107
                                struct ncci_datahandle_queue {
108
                                    struct ncci_datahandle_queue *next;
109
                                    u16                         datahandle;
110
                                    int                           len;
111
                                } *ackqueue;
112
                        } *ncci_list;
113
                } *plcip;
114
                struct capidrv_ncci *nccip;
115
        } *bchans;
116
 
117
        struct capidrv_plci *plci_list;
118
 
119
        /* for q931 data */
120
        u8  q931_buf[4096];
121
        u8 *q931_read;
122
        u8 *q931_write;
123
        u8 *q931_end;
124
};
125
 
126
 
127
struct capidrv_data {
128
        struct capi20_appl ap;
129
        int ncontr;
130
        struct capidrv_contr *contr_list;
131
};
132
 
133
typedef struct capidrv_plci capidrv_plci;
134
typedef struct capidrv_ncci capidrv_ncci;
135
typedef struct capidrv_contr capidrv_contr;
136
typedef struct capidrv_data capidrv_data;
137
typedef struct capidrv_bchan capidrv_bchan;
138
 
139
/* -------- data definitions ----------------------------------------- */
140
 
141
static capidrv_data global;
142
static DEFINE_SPINLOCK(global_lock);
143
 
144
static void handle_dtrace_data(capidrv_contr *card,
145
        int send, int level2, u8 *data, u16 len);
146
 
147
/* -------- convert functions ---------------------------------------- */
148
 
149
static inline u32 b1prot(int l2, int l3)
150
{
151
        switch (l2) {
152
        case ISDN_PROTO_L2_X75I:
153
        case ISDN_PROTO_L2_X75UI:
154
        case ISDN_PROTO_L2_X75BUI:
155
                return 0;
156
        case ISDN_PROTO_L2_HDLC:
157
        default:
158
                return 0;
159
        case ISDN_PROTO_L2_TRANS:
160
                return 1;
161
        case ISDN_PROTO_L2_V11096:
162
        case ISDN_PROTO_L2_V11019:
163
        case ISDN_PROTO_L2_V11038:
164
                return 2;
165
        case ISDN_PROTO_L2_FAX:
166
                return 4;
167
        case ISDN_PROTO_L2_MODEM:
168
                return 8;
169
        }
170
}
171
 
172
static inline u32 b2prot(int l2, int l3)
173
{
174
        switch (l2) {
175
        case ISDN_PROTO_L2_X75I:
176
        case ISDN_PROTO_L2_X75UI:
177
        case ISDN_PROTO_L2_X75BUI:
178
        default:
179
                return 0;
180
        case ISDN_PROTO_L2_HDLC:
181
        case ISDN_PROTO_L2_TRANS:
182
        case ISDN_PROTO_L2_V11096:
183
        case ISDN_PROTO_L2_V11019:
184
        case ISDN_PROTO_L2_V11038:
185
        case ISDN_PROTO_L2_MODEM:
186
                return 1;
187
        case ISDN_PROTO_L2_FAX:
188
                return 4;
189
        }
190
}
191
 
192
static inline u32 b3prot(int l2, int l3)
193
{
194
        switch (l2) {
195
        case ISDN_PROTO_L2_X75I:
196
        case ISDN_PROTO_L2_X75UI:
197
        case ISDN_PROTO_L2_X75BUI:
198
        case ISDN_PROTO_L2_HDLC:
199
        case ISDN_PROTO_L2_TRANS:
200
        case ISDN_PROTO_L2_V11096:
201
        case ISDN_PROTO_L2_V11019:
202
        case ISDN_PROTO_L2_V11038:
203
        case ISDN_PROTO_L2_MODEM:
204
        default:
205
                return 0;
206
        case ISDN_PROTO_L2_FAX:
207
                return 4;
208
        }
209
}
210
 
211
static _cstruct b1config_async_v110(u16 rate)
212
{
213
        /* CAPI-Spec "B1 Configuration" */
214
        static unsigned char buf[9];
215
        buf[0] = 8; /* len */
216
        /* maximum bitrate */
217
        buf[1] = rate & 0xff; buf[2] = (rate >> 8) & 0xff;
218
        buf[3] = 8; buf[4] = 0; /* 8 bits per character */
219
        buf[5] = 0; buf[6] = 0; /* parity none */
220
        buf[7] = 0; buf[8] = 0; /* 1 stop bit */
221
        return buf;
222
}
223
 
224
static _cstruct b1config(int l2, int l3)
225
{
226
        switch (l2) {
227
        case ISDN_PROTO_L2_X75I:
228
        case ISDN_PROTO_L2_X75UI:
229
        case ISDN_PROTO_L2_X75BUI:
230
        case ISDN_PROTO_L2_HDLC:
231
        case ISDN_PROTO_L2_TRANS:
232
        default:
233
                return NULL;
234
        case ISDN_PROTO_L2_V11096:
235
            return b1config_async_v110(9600);
236
        case ISDN_PROTO_L2_V11019:
237
            return b1config_async_v110(19200);
238
        case ISDN_PROTO_L2_V11038:
239
            return b1config_async_v110(38400);
240
        }
241
}
242
 
243
static inline u16 si2cip(u8 si1, u8 si2)
244
{
245
        static const u8 cip[17][5] =
246
        {
247
        /*  0  1  2  3  4  */
248
                {0, 0, 0, 0, 0},     /*0 */
249
                {16, 16, 4, 26, 16},    /*1 */
250
                {17, 17, 17, 4, 4},     /*2 */
251
                {2, 2, 2, 2, 2},        /*3 */
252
                {18, 18, 18, 18, 18},   /*4 */
253
                {2, 2, 2, 2, 2},        /*5 */
254
                {0, 0, 0, 0, 0},     /*6 */
255
                {2, 2, 2, 2, 2},        /*7 */
256
                {2, 2, 2, 2, 2},        /*8 */
257
                {21, 21, 21, 21, 21},   /*9 */
258
                {19, 19, 19, 19, 19},   /*10 */
259
                {0, 0, 0, 0, 0},     /*11 */
260
                {0, 0, 0, 0, 0},     /*12 */
261
                {0, 0, 0, 0, 0},     /*13 */
262
                {0, 0, 0, 0, 0},     /*14 */
263
                {22, 22, 22, 22, 22},   /*15 */
264
                {27, 27, 27, 28, 27}    /*16 */
265
        };
266
        if (si1 > 16)
267
                si1 = 0;
268
        if (si2 > 4)
269
                si2 = 0;
270
 
271
        return (u16) cip[si1][si2];
272
}
273
 
274
static inline u8 cip2si1(u16 cipval)
275
{
276
        static const u8 si[32] =
277
        {7, 1, 7, 7, 1, 1, 7, 7,        /*0-7 */
278
         7, 1, 0, 0, 0, 0, 0, 0,      /*8-15 */
279
         1, 2, 4, 10, 9, 9, 15, 7,      /*16-23 */
280
         7, 7, 1, 16, 16, 0, 0, 0};        /*24-31 */
281
 
282
        if (cipval > 31)
283
                cipval = 0;      /* .... */
284
        return si[cipval];
285
}
286
 
287
static inline u8 cip2si2(u16 cipval)
288
{
289
        static const u8 si[32] =
290
        {0, 0, 0, 0, 2, 3, 0, 0,      /*0-7 */
291
         0, 3, 0, 0, 0, 0, 0, 0,       /*8-15 */
292
         1, 2, 0, 0, 9, 0, 0, 0,     /*16-23 */
293
         0, 0, 3, 2, 3, 0, 0, 0};    /*24-31 */
294
 
295
        if (cipval > 31)
296
                cipval = 0;      /* .... */
297
        return si[cipval];
298
}
299
 
300
 
301
/* -------- controller management ------------------------------------- */
302
 
303
static inline capidrv_contr *findcontrbydriverid(int driverid)
304
{
305
        unsigned long flags;
306
        capidrv_contr *p;
307
 
308
        spin_lock_irqsave(&global_lock, flags);
309
        for (p = global.contr_list; p; p = p->next)
310
                if (p->myid == driverid)
311
                        break;
312
        spin_unlock_irqrestore(&global_lock, flags);
313
        return p;
314
}
315
 
316
static capidrv_contr *findcontrbynumber(u32 contr)
317
{
318
        unsigned long flags;
319
        capidrv_contr *p = global.contr_list;
320
 
321
        spin_lock_irqsave(&global_lock, flags);
322
        for (p = global.contr_list; p; p = p->next)
323
                if (p->contrnr == contr)
324
                        break;
325
        spin_unlock_irqrestore(&global_lock, flags);
326
        return p;
327
}
328
 
329
 
330
/* -------- plci management ------------------------------------------ */
331
 
332
static capidrv_plci *new_plci(capidrv_contr * card, int chan)
333
{
334
        capidrv_plci *plcip;
335
 
336
        plcip = kzalloc(sizeof(capidrv_plci), GFP_ATOMIC);
337
 
338
        if (plcip == 0)
339
                return NULL;
340
 
341
        plcip->state = ST_PLCI_NONE;
342
        plcip->plci = 0;
343
        plcip->msgid = 0;
344
        plcip->chan = chan;
345
        plcip->next = card->plci_list;
346
        card->plci_list = plcip;
347
        card->bchans[chan].plcip = plcip;
348
 
349
        return plcip;
350
}
351
 
352
static capidrv_plci *find_plci_by_plci(capidrv_contr * card, u32 plci)
353
{
354
        capidrv_plci *p;
355
        for (p = card->plci_list; p; p = p->next)
356
                if (p->plci == plci)
357
                        return p;
358
        return NULL;
359
}
360
 
361
static capidrv_plci *find_plci_by_msgid(capidrv_contr * card, u16 msgid)
362
{
363
        capidrv_plci *p;
364
        for (p = card->plci_list; p; p = p->next)
365
                if (p->msgid == msgid)
366
                        return p;
367
        return NULL;
368
}
369
 
370
static capidrv_plci *find_plci_by_ncci(capidrv_contr * card, u32 ncci)
371
{
372
        capidrv_plci *p;
373
        for (p = card->plci_list; p; p = p->next)
374
                if (p->plci == (ncci & 0xffff))
375
                        return p;
376
        return NULL;
377
}
378
 
379
static void free_plci(capidrv_contr * card, capidrv_plci * plcip)
380
{
381
        capidrv_plci **pp;
382
 
383
        for (pp = &card->plci_list; *pp; pp = &(*pp)->next) {
384
                if (*pp == plcip) {
385
                        *pp = (*pp)->next;
386
                        card->bchans[plcip->chan].plcip = NULL;
387
                        card->bchans[plcip->chan].disconnecting = 0;
388
                        card->bchans[plcip->chan].incoming = 0;
389
                        kfree(plcip);
390
                        return;
391
                }
392
        }
393
        printk(KERN_ERR "capidrv-%d: free_plci %p (0x%x) not found, Huh?\n",
394
               card->contrnr, plcip, plcip->plci);
395
}
396
 
397
/* -------- ncci management ------------------------------------------ */
398
 
399
static inline capidrv_ncci *new_ncci(capidrv_contr * card,
400
                                     capidrv_plci * plcip,
401
                                     u32 ncci)
402
{
403
        capidrv_ncci *nccip;
404
 
405
        nccip = kzalloc(sizeof(capidrv_ncci), GFP_ATOMIC);
406
 
407
        if (nccip == 0)
408
                return NULL;
409
 
410
        nccip->ncci = ncci;
411
        nccip->state = ST_NCCI_NONE;
412
        nccip->plcip = plcip;
413
        nccip->chan = plcip->chan;
414
        nccip->datahandle = 0;
415
 
416
        nccip->next = plcip->ncci_list;
417
        plcip->ncci_list = nccip;
418
 
419
        card->bchans[plcip->chan].nccip = nccip;
420
 
421
        return nccip;
422
}
423
 
424
static inline capidrv_ncci *find_ncci(capidrv_contr * card, u32 ncci)
425
{
426
        capidrv_plci *plcip;
427
        capidrv_ncci *p;
428
 
429
        if ((plcip = find_plci_by_ncci(card, ncci)) == 0)
430
                return NULL;
431
 
432
        for (p = plcip->ncci_list; p; p = p->next)
433
                if (p->ncci == ncci)
434
                        return p;
435
        return NULL;
436
}
437
 
438
static inline capidrv_ncci *find_ncci_by_msgid(capidrv_contr * card,
439
                                               u32 ncci, u16 msgid)
440
{
441
        capidrv_plci *plcip;
442
        capidrv_ncci *p;
443
 
444
        if ((plcip = find_plci_by_ncci(card, ncci)) == 0)
445
                return NULL;
446
 
447
        for (p = plcip->ncci_list; p; p = p->next)
448
                if (p->msgid == msgid)
449
                        return p;
450
        return NULL;
451
}
452
 
453
static void free_ncci(capidrv_contr * card, struct capidrv_ncci *nccip)
454
{
455
        struct capidrv_ncci **pp;
456
 
457
        for (pp = &(nccip->plcip->ncci_list); *pp; pp = &(*pp)->next) {
458
                if (*pp == nccip) {
459
                        *pp = (*pp)->next;
460
                        break;
461
                }
462
        }
463
        card->bchans[nccip->chan].nccip = NULL;
464
        kfree(nccip);
465
}
466
 
467
static int capidrv_add_ack(struct capidrv_ncci *nccip,
468
                           u16 datahandle, int len)
469
{
470
        struct ncci_datahandle_queue *n, **pp;
471
 
472
        n = (struct ncci_datahandle_queue *)
473
                kmalloc(sizeof(struct ncci_datahandle_queue), GFP_ATOMIC);
474
        if (!n) {
475
           printk(KERN_ERR "capidrv: kmalloc ncci_datahandle failed\n");
476
           return -1;
477
        }
478
        n->next = NULL;
479
        n->datahandle = datahandle;
480
        n->len = len;
481
        for (pp = &nccip->ackqueue; *pp; pp = &(*pp)->next) ;
482
        *pp = n;
483
        return 0;
484
}
485
 
486
static int capidrv_del_ack(struct capidrv_ncci *nccip, u16 datahandle)
487
{
488
        struct ncci_datahandle_queue **pp, *p;
489
        int len;
490
 
491
        for (pp = &nccip->ackqueue; *pp; pp = &(*pp)->next) {
492
                if ((*pp)->datahandle == datahandle) {
493
                        p = *pp;
494
                        len = p->len;
495
                        *pp = (*pp)->next;
496
                        kfree(p);
497
                        return len;
498
                }
499
        }
500
        return -1;
501
}
502
 
503
/* -------- convert and send capi message ---------------------------- */
504
 
505
static void send_message(capidrv_contr * card, _cmsg * cmsg)
506
{
507
        struct sk_buff *skb;
508
        size_t len;
509
 
510
        capi_cmsg2message(cmsg, cmsg->buf);
511
        len = CAPIMSG_LEN(cmsg->buf);
512
        skb = alloc_skb(len, GFP_ATOMIC);
513
        if (!skb) {
514
                printk(KERN_ERR "capidrv::send_message: can't allocate mem\n");
515
                return;
516
        }
517
        memcpy(skb_put(skb, len), cmsg->buf, len);
518
        if (capi20_put_message(&global.ap, skb) != CAPI_NOERROR)
519
                kfree_skb(skb);
520
}
521
 
522
/* -------- state machine -------------------------------------------- */
523
 
524
struct listenstatechange {
525
        int actstate;
526
        int nextstate;
527
        int event;
528
};
529
 
530
static struct listenstatechange listentable[] =
531
{
532
  {ST_LISTEN_NONE, ST_LISTEN_WAIT_CONF, EV_LISTEN_REQ},
533
  {ST_LISTEN_ACTIVE, ST_LISTEN_ACTIVE_WAIT_CONF, EV_LISTEN_REQ},
534
  {ST_LISTEN_WAIT_CONF, ST_LISTEN_NONE, EV_LISTEN_CONF_ERROR},
535
  {ST_LISTEN_ACTIVE_WAIT_CONF, ST_LISTEN_ACTIVE, EV_LISTEN_CONF_ERROR},
536
  {ST_LISTEN_WAIT_CONF, ST_LISTEN_NONE, EV_LISTEN_CONF_EMPTY},
537
  {ST_LISTEN_ACTIVE_WAIT_CONF, ST_LISTEN_NONE, EV_LISTEN_CONF_EMPTY},
538
  {ST_LISTEN_WAIT_CONF, ST_LISTEN_ACTIVE, EV_LISTEN_CONF_OK},
539
  {ST_LISTEN_ACTIVE_WAIT_CONF, ST_LISTEN_ACTIVE, EV_LISTEN_CONF_OK},
540
  {},
541
};
542
 
543
static void listen_change_state(capidrv_contr * card, int event)
544
{
545
        struct listenstatechange *p = listentable;
546
        while (p->event) {
547
                if (card->state == p->actstate && p->event == event) {
548
                        if (debugmode)
549
                                printk(KERN_DEBUG "capidrv-%d: listen_change_state %d -> %d\n",
550
                                       card->contrnr, card->state, p->nextstate);
551
                        card->state = p->nextstate;
552
                        return;
553
                }
554
                p++;
555
        }
556
        printk(KERN_ERR "capidrv-%d: listen_change_state state=%d event=%d ????\n",
557
               card->contrnr, card->state, event);
558
 
559
}
560
 
561
/* ------------------------------------------------------------------ */
562
 
563
static void p0(capidrv_contr * card, capidrv_plci * plci)
564
{
565
        isdn_ctrl cmd;
566
 
567
        card->bchans[plci->chan].contr = NULL;
568
        cmd.command = ISDN_STAT_DHUP;
569
        cmd.driver = card->myid;
570
        cmd.arg = plci->chan;
571
        card->interface.statcallb(&cmd);
572
        free_plci(card, plci);
573
}
574
 
575
/* ------------------------------------------------------------------ */
576
 
577
struct plcistatechange {
578
        int actstate;
579
        int nextstate;
580
        int event;
581
        void (*changefunc) (capidrv_contr * card, capidrv_plci * plci);
582
};
583
 
584
static struct plcistatechange plcitable[] =
585
{
586
  /* P-0 */
587
  {ST_PLCI_NONE, ST_PLCI_OUTGOING, EV_PLCI_CONNECT_REQ, NULL},
588
  {ST_PLCI_NONE, ST_PLCI_ALLOCATED, EV_PLCI_FACILITY_IND_UP, NULL},
589
  {ST_PLCI_NONE, ST_PLCI_INCOMING, EV_PLCI_CONNECT_IND, NULL},
590
  {ST_PLCI_NONE, ST_PLCI_RESUMEING, EV_PLCI_RESUME_REQ, NULL},
591
  /* P-0.1 */
592
  {ST_PLCI_OUTGOING, ST_PLCI_NONE, EV_PLCI_CONNECT_CONF_ERROR, p0},
593
  {ST_PLCI_OUTGOING, ST_PLCI_ALLOCATED, EV_PLCI_CONNECT_CONF_OK, NULL},
594
  /* P-1 */
595
  {ST_PLCI_ALLOCATED, ST_PLCI_ACTIVE, EV_PLCI_CONNECT_ACTIVE_IND, NULL},
596
  {ST_PLCI_ALLOCATED, ST_PLCI_DISCONNECTING, EV_PLCI_DISCONNECT_REQ, NULL},
597
  {ST_PLCI_ALLOCATED, ST_PLCI_DISCONNECTING, EV_PLCI_FACILITY_IND_DOWN, NULL},
598
  {ST_PLCI_ALLOCATED, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, NULL},
599
  /* P-ACT */
600
  {ST_PLCI_ACTIVE, ST_PLCI_DISCONNECTING, EV_PLCI_DISCONNECT_REQ, NULL},
601
  {ST_PLCI_ACTIVE, ST_PLCI_DISCONNECTING, EV_PLCI_FACILITY_IND_DOWN, NULL},
602
  {ST_PLCI_ACTIVE, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, NULL},
603
  {ST_PLCI_ACTIVE, ST_PLCI_HELD, EV_PLCI_HOLD_IND, NULL},
604
  {ST_PLCI_ACTIVE, ST_PLCI_DISCONNECTING, EV_PLCI_SUSPEND_IND, NULL},
605
  /* P-2 */
606
  {ST_PLCI_INCOMING, ST_PLCI_DISCONNECTING, EV_PLCI_CONNECT_REJECT, NULL},
607
  {ST_PLCI_INCOMING, ST_PLCI_FACILITY_IND, EV_PLCI_FACILITY_IND_UP, NULL},
608
  {ST_PLCI_INCOMING, ST_PLCI_ACCEPTING, EV_PLCI_CONNECT_RESP, NULL},
609
  {ST_PLCI_INCOMING, ST_PLCI_DISCONNECTING, EV_PLCI_DISCONNECT_REQ, NULL},
610
  {ST_PLCI_INCOMING, ST_PLCI_DISCONNECTING, EV_PLCI_FACILITY_IND_DOWN, NULL},
611
  {ST_PLCI_INCOMING, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, NULL},
612
  {ST_PLCI_INCOMING, ST_PLCI_DISCONNECTING, EV_PLCI_CD_IND, NULL},
613
  /* P-3 */
614
  {ST_PLCI_FACILITY_IND, ST_PLCI_DISCONNECTING, EV_PLCI_CONNECT_REJECT, NULL},
615
  {ST_PLCI_FACILITY_IND, ST_PLCI_ACCEPTING, EV_PLCI_CONNECT_ACTIVE_IND, NULL},
616
  {ST_PLCI_FACILITY_IND, ST_PLCI_DISCONNECTING, EV_PLCI_DISCONNECT_REQ, NULL},
617
  {ST_PLCI_FACILITY_IND, ST_PLCI_DISCONNECTING, EV_PLCI_FACILITY_IND_DOWN, NULL},
618
  {ST_PLCI_FACILITY_IND, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, NULL},
619
  /* P-4 */
620
  {ST_PLCI_ACCEPTING, ST_PLCI_ACTIVE, EV_PLCI_CONNECT_ACTIVE_IND, NULL},
621
  {ST_PLCI_ACCEPTING, ST_PLCI_DISCONNECTING, EV_PLCI_DISCONNECT_REQ, NULL},
622
  {ST_PLCI_ACCEPTING, ST_PLCI_DISCONNECTING, EV_PLCI_FACILITY_IND_DOWN, NULL},
623
  {ST_PLCI_ACCEPTING, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, NULL},
624
  /* P-5 */
625
  {ST_PLCI_DISCONNECTING, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, NULL},
626
  /* P-6 */
627
  {ST_PLCI_DISCONNECTED, ST_PLCI_NONE, EV_PLCI_DISCONNECT_RESP, p0},
628
  /* P-0.Res */
629
  {ST_PLCI_RESUMEING, ST_PLCI_NONE, EV_PLCI_RESUME_CONF_ERROR, p0},
630
  {ST_PLCI_RESUMEING, ST_PLCI_RESUME, EV_PLCI_RESUME_CONF_OK, NULL},
631
  /* P-RES */
632
  {ST_PLCI_RESUME, ST_PLCI_ACTIVE, EV_PLCI_RESUME_IND, NULL},
633
  /* P-HELD */
634
  {ST_PLCI_HELD, ST_PLCI_ACTIVE, EV_PLCI_RETRIEVE_IND, NULL},
635
  {},
636
};
637
 
638
static void plci_change_state(capidrv_contr * card, capidrv_plci * plci, int event)
639
{
640
        struct plcistatechange *p = plcitable;
641
        while (p->event) {
642
                if (plci->state == p->actstate && p->event == event) {
643
                        if (debugmode)
644
                                printk(KERN_DEBUG "capidrv-%d: plci_change_state:0x%x %d -> %d\n",
645
                                  card->contrnr, plci->plci, plci->state, p->nextstate);
646
                        plci->state = p->nextstate;
647
                        if (p->changefunc)
648
                                p->changefunc(card, plci);
649
                        return;
650
                }
651
                p++;
652
        }
653
        printk(KERN_ERR "capidrv-%d: plci_change_state:0x%x state=%d event=%d ????\n",
654
               card->contrnr, plci->plci, plci->state, event);
655
}
656
 
657
/* ------------------------------------------------------------------ */
658
 
659
static _cmsg cmsg;
660
 
661
static void n0(capidrv_contr * card, capidrv_ncci * ncci)
662
{
663
        isdn_ctrl cmd;
664
 
665
        capi_fill_DISCONNECT_REQ(&cmsg,
666
                                 global.ap.applid,
667
                                 card->msgid++,
668
                                 ncci->plcip->plci,
669
                                 NULL,  /* BChannelinformation */
670
                                 NULL,  /* Keypadfacility */
671
                                 NULL,  /* Useruserdata */   /* $$$$ */
672
                                 NULL   /* Facilitydataarray */
673
        );
674
        send_message(card, &cmsg);
675
        plci_change_state(card, ncci->plcip, EV_PLCI_DISCONNECT_REQ);
676
 
677
        cmd.command = ISDN_STAT_BHUP;
678
        cmd.driver = card->myid;
679
        cmd.arg = ncci->chan;
680
        card->interface.statcallb(&cmd);
681
        free_ncci(card, ncci);
682
}
683
 
684
/* ------------------------------------------------------------------ */
685
 
686
struct nccistatechange {
687
        int actstate;
688
        int nextstate;
689
        int event;
690
        void (*changefunc) (capidrv_contr * card, capidrv_ncci * ncci);
691
};
692
 
693
static struct nccistatechange nccitable[] =
694
{
695
  /* N-0 */
696
  {ST_NCCI_NONE, ST_NCCI_OUTGOING, EV_NCCI_CONNECT_B3_REQ, NULL},
697
  {ST_NCCI_NONE, ST_NCCI_INCOMING, EV_NCCI_CONNECT_B3_IND, NULL},
698
  /* N-0.1 */
699
  {ST_NCCI_OUTGOING, ST_NCCI_ALLOCATED, EV_NCCI_CONNECT_B3_CONF_OK, NULL},
700
  {ST_NCCI_OUTGOING, ST_NCCI_NONE, EV_NCCI_CONNECT_B3_CONF_ERROR, n0},
701
  /* N-1 */
702
  {ST_NCCI_INCOMING, ST_NCCI_DISCONNECTING, EV_NCCI_CONNECT_B3_REJECT, NULL},
703
  {ST_NCCI_INCOMING, ST_NCCI_ALLOCATED, EV_NCCI_CONNECT_B3_RESP, NULL},
704
  {ST_NCCI_INCOMING, ST_NCCI_DISCONNECTED, EV_NCCI_DISCONNECT_B3_IND, NULL},
705
  {ST_NCCI_INCOMING, ST_NCCI_DISCONNECTING, EV_NCCI_DISCONNECT_B3_REQ, NULL},
706
  /* N-2 */
707
  {ST_NCCI_ALLOCATED, ST_NCCI_ACTIVE, EV_NCCI_CONNECT_B3_ACTIVE_IND, NULL},
708
  {ST_NCCI_ALLOCATED, ST_NCCI_DISCONNECTED, EV_NCCI_DISCONNECT_B3_IND, NULL},
709
  {ST_NCCI_ALLOCATED, ST_NCCI_DISCONNECTING, EV_NCCI_DISCONNECT_B3_REQ, NULL},
710
  /* N-ACT */
711
  {ST_NCCI_ACTIVE, ST_NCCI_ACTIVE, EV_NCCI_RESET_B3_IND, NULL},
712
  {ST_NCCI_ACTIVE, ST_NCCI_RESETING, EV_NCCI_RESET_B3_REQ, NULL},
713
  {ST_NCCI_ACTIVE, ST_NCCI_DISCONNECTED, EV_NCCI_DISCONNECT_B3_IND, NULL},
714
  {ST_NCCI_ACTIVE, ST_NCCI_DISCONNECTING, EV_NCCI_DISCONNECT_B3_REQ, NULL},
715
  /* N-3 */
716
  {ST_NCCI_RESETING, ST_NCCI_ACTIVE, EV_NCCI_RESET_B3_IND, NULL},
717
  {ST_NCCI_RESETING, ST_NCCI_DISCONNECTED, EV_NCCI_DISCONNECT_B3_IND, NULL},
718
  {ST_NCCI_RESETING, ST_NCCI_DISCONNECTING, EV_NCCI_DISCONNECT_B3_REQ, NULL},
719
  /* N-4 */
720
  {ST_NCCI_DISCONNECTING, ST_NCCI_DISCONNECTED, EV_NCCI_DISCONNECT_B3_IND, NULL},
721
  {ST_NCCI_DISCONNECTING, ST_NCCI_PREVIOUS, EV_NCCI_DISCONNECT_B3_CONF_ERROR,NULL},
722
  /* N-5 */
723
  {ST_NCCI_DISCONNECTED, ST_NCCI_NONE, EV_NCCI_DISCONNECT_B3_RESP, n0},
724
  {},
725
};
726
 
727
static void ncci_change_state(capidrv_contr * card, capidrv_ncci * ncci, int event)
728
{
729
        struct nccistatechange *p = nccitable;
730
        while (p->event) {
731
                if (ncci->state == p->actstate && p->event == event) {
732
                        if (debugmode)
733
                                printk(KERN_DEBUG "capidrv-%d: ncci_change_state:0x%x %d -> %d\n",
734
                                  card->contrnr, ncci->ncci, ncci->state, p->nextstate);
735
                        if (p->nextstate == ST_NCCI_PREVIOUS) {
736
                                ncci->state = ncci->oldstate;
737
                                ncci->oldstate = p->actstate;
738
                        } else {
739
                                ncci->oldstate = p->actstate;
740
                                ncci->state = p->nextstate;
741
                        }
742
                        if (p->changefunc)
743
                                p->changefunc(card, ncci);
744
                        return;
745
                }
746
                p++;
747
        }
748
        printk(KERN_ERR "capidrv-%d: ncci_change_state:0x%x state=%d event=%d ????\n",
749
               card->contrnr, ncci->ncci, ncci->state, event);
750
}
751
 
752
/* ------------------------------------------------------------------- */
753
 
754
static inline int new_bchan(capidrv_contr * card)
755
{
756
        int i;
757
        for (i = 0; i < card->nbchan; i++) {
758
                if (card->bchans[i].plcip == 0) {
759
                        card->bchans[i].disconnecting = 0;
760
                        return i;
761
                }
762
        }
763
        return -1;
764
}
765
 
766
/* ------------------------------------------------------------------- */
767
 
768
static void handle_controller(_cmsg * cmsg)
769
{
770
        capidrv_contr *card = findcontrbynumber(cmsg->adr.adrController & 0x7f);
771
 
772
        if (!card) {
773
                printk(KERN_ERR "capidrv: %s from unknown controller 0x%x\n",
774
                       capi_cmd2str(cmsg->Command, cmsg->Subcommand),
775
                       cmsg->adr.adrController & 0x7f);
776
                return;
777
        }
778
        switch (CAPICMD(cmsg->Command, cmsg->Subcommand)) {
779
 
780
        case CAPI_LISTEN_CONF:  /* Controller */
781
                if (debugmode)
782
                        printk(KERN_DEBUG "capidrv-%d: listenconf Info=0x%4x (%s) cipmask=0x%x\n",
783
                               card->contrnr, cmsg->Info, capi_info2str(cmsg->Info), card->cipmask);
784
                if (cmsg->Info) {
785
                        listen_change_state(card, EV_LISTEN_CONF_ERROR);
786
                } else if (card->cipmask == 0) {
787
                        listen_change_state(card, EV_LISTEN_CONF_EMPTY);
788
                } else {
789
                        listen_change_state(card, EV_LISTEN_CONF_OK);
790
                }
791
                break;
792
 
793
        case CAPI_MANUFACTURER_IND:     /* Controller */
794
                if (   cmsg->ManuID == 0x214D5641
795
                    && cmsg->Class == 0
796
                    && cmsg->Function == 1) {
797
                   u8  *data = cmsg->ManuData+3;
798
                   u16  len = cmsg->ManuData[0];
799
                   u16 layer;
800
                   int direction;
801
                   if (len == 255) {
802
                      len = (cmsg->ManuData[1] | (cmsg->ManuData[2] << 8));
803
                      data += 2;
804
                   }
805
                   len -= 2;
806
                   layer = ((*(data-1)) << 8) | *(data-2);
807
                   if (layer & 0x300)
808
                        direction = (layer & 0x200) ? 0 : 1;
809
                   else direction = (layer & 0x800) ? 0 : 1;
810
                   if (layer & 0x0C00) {
811
                        if ((layer & 0xff) == 0x80) {
812
                           handle_dtrace_data(card, direction, 1, data, len);
813
                           break;
814
                        }
815
                   } else if ((layer & 0xff) < 0x80) {
816
                      handle_dtrace_data(card, direction, 0, data, len);
817
                      break;
818
                   }
819
                   printk(KERN_INFO "capidrv-%d: %s from controller 0x%x layer 0x%x, ignored\n",
820
                        card->contrnr,
821
                        capi_cmd2str(cmsg->Command, cmsg->Subcommand),
822
                        cmsg->adr.adrController, layer);
823
                   break;
824
                }
825
                goto ignored;
826
        case CAPI_MANUFACTURER_CONF:    /* Controller */
827
                if (cmsg->ManuID == 0x214D5641) {
828
                   char *s = NULL;
829
                   switch (cmsg->Class) {
830
                      case 0: break;
831
                      case 1: s = "unknown class"; break;
832
                      case 2: s = "unknown function"; break;
833
                      default: s = "unkown error"; break;
834
                   }
835
                   if (s)
836
                   printk(KERN_INFO "capidrv-%d: %s from controller 0x%x function %d: %s\n",
837
                        card->contrnr,
838
                        capi_cmd2str(cmsg->Command, cmsg->Subcommand),
839
                        cmsg->adr.adrController,
840
                        cmsg->Function, s);
841
                   break;
842
                }
843
                goto ignored;
844
        case CAPI_FACILITY_IND: /* Controller/plci/ncci */
845
                goto ignored;
846
        case CAPI_FACILITY_CONF:        /* Controller/plci/ncci */
847
                goto ignored;
848
        case CAPI_INFO_IND:     /* Controller/plci */
849
                goto ignored;
850
        case CAPI_INFO_CONF:    /* Controller/plci */
851
                goto ignored;
852
 
853
        default:
854
                printk(KERN_ERR "capidrv-%d: got %s from controller 0x%x ???",
855
                       card->contrnr,
856
                       capi_cmd2str(cmsg->Command, cmsg->Subcommand),
857
                       cmsg->adr.adrController);
858
        }
859
        return;
860
 
861
      ignored:
862
        printk(KERN_INFO "capidrv-%d: %s from controller 0x%x ignored\n",
863
               card->contrnr,
864
               capi_cmd2str(cmsg->Command, cmsg->Subcommand),
865
               cmsg->adr.adrController);
866
}
867
 
868
static void handle_incoming_call(capidrv_contr * card, _cmsg * cmsg)
869
{
870
        capidrv_plci *plcip;
871
        capidrv_bchan *bchan;
872
        isdn_ctrl cmd;
873
        int chan;
874
 
875
        if ((chan = new_bchan(card)) == -1) {
876
                printk(KERN_ERR "capidrv-%d: incoming call on not existing bchan ?\n", card->contrnr);
877
                return;
878
        }
879
        bchan = &card->bchans[chan];
880
        if ((plcip = new_plci(card, chan)) == 0) {
881
                printk(KERN_ERR "capidrv-%d: incoming call: no memory, sorry.\n", card->contrnr);
882
                return;
883
        }
884
        bchan->incoming = 1;
885
        plcip->plci = cmsg->adr.adrPLCI;
886
        plci_change_state(card, plcip, EV_PLCI_CONNECT_IND);
887
 
888
        cmd.command = ISDN_STAT_ICALL;
889
        cmd.driver = card->myid;
890
        cmd.arg = chan;
891
        memset(&cmd.parm.setup, 0, sizeof(cmd.parm.setup));
892
        strncpy(cmd.parm.setup.phone,
893
                cmsg->CallingPartyNumber + 3,
894
                cmsg->CallingPartyNumber[0] - 2);
895
        strncpy(cmd.parm.setup.eazmsn,
896
                cmsg->CalledPartyNumber + 2,
897
                cmsg->CalledPartyNumber[0] - 1);
898
        cmd.parm.setup.si1 = cip2si1(cmsg->CIPValue);
899
        cmd.parm.setup.si2 = cip2si2(cmsg->CIPValue);
900
        cmd.parm.setup.plan = cmsg->CallingPartyNumber[1];
901
        cmd.parm.setup.screen = cmsg->CallingPartyNumber[2];
902
 
903
        printk(KERN_INFO "capidrv-%d: incoming call %s,%d,%d,%s\n",
904
                        card->contrnr,
905
                        cmd.parm.setup.phone,
906
                        cmd.parm.setup.si1,
907
                        cmd.parm.setup.si2,
908
                        cmd.parm.setup.eazmsn);
909
 
910
        if (cmd.parm.setup.si1 == 1 && cmd.parm.setup.si2 != 0) {
911
                printk(KERN_INFO "capidrv-%d: patching si2=%d to 0 for VBOX\n",
912
                        card->contrnr,
913
                        cmd.parm.setup.si2);
914
                cmd.parm.setup.si2 = 0;
915
        }
916
 
917
        switch (card->interface.statcallb(&cmd)) {
918
        case 0:
919
        case 3:
920
                /* No device matching this call.
921
                 * and isdn_common.c has send a HANGUP command
922
                 * which is ignored in state ST_PLCI_INCOMING,
923
                 * so we send RESP to ignore the call
924
                 */
925
                capi_cmsg_answer(cmsg);
926
                cmsg->Reject = 1;       /* ignore */
927
                send_message(card, cmsg);
928
                plci_change_state(card, plcip, EV_PLCI_CONNECT_REJECT);
929
                printk(KERN_INFO "capidrv-%d: incoming call %s,%d,%d,%s ignored\n",
930
                        card->contrnr,
931
                        cmd.parm.setup.phone,
932
                        cmd.parm.setup.si1,
933
                        cmd.parm.setup.si2,
934
                        cmd.parm.setup.eazmsn);
935
                break;
936
        case 1:
937
                /* At least one device matching this call (RING on ttyI)
938
                 * HL-driver may send ALERTING on the D-channel in this
939
                 * case.
940
                 * really means: RING on ttyI or a net interface
941
                 * accepted this call already.
942
                 *
943
                 * If the call was accepted, state has already changed,
944
                 * and CONNECT_RESP already sent.
945
                 */
946
                if (plcip->state == ST_PLCI_INCOMING) {
947
                        printk(KERN_INFO "capidrv-%d: incoming call %s,%d,%d,%s tty alerting\n",
948
                                card->contrnr,
949
                                cmd.parm.setup.phone,
950
                                cmd.parm.setup.si1,
951
                                cmd.parm.setup.si2,
952
                                cmd.parm.setup.eazmsn);
953
                        capi_fill_ALERT_REQ(cmsg,
954
                                            global.ap.applid,
955
                                            card->msgid++,
956
                                            plcip->plci,        /* adr */
957
                                            NULL,/* BChannelinformation */
958
                                            NULL,/* Keypadfacility */
959
                                            NULL,/* Useruserdata */
960
                                            NULL /* Facilitydataarray */
961
                        );
962
                        plcip->msgid = cmsg->Messagenumber;
963
                        send_message(card, cmsg);
964
                } else {
965
                        printk(KERN_INFO "capidrv-%d: incoming call %s,%d,%d,%s on netdev\n",
966
                                card->contrnr,
967
                                cmd.parm.setup.phone,
968
                                cmd.parm.setup.si1,
969
                                cmd.parm.setup.si2,
970
                                cmd.parm.setup.eazmsn);
971
                }
972
                break;
973
 
974
        case 2:         /* Call will be rejected. */
975
                capi_cmsg_answer(cmsg);
976
                cmsg->Reject = 2;       /* reject call, normal call clearing */
977
                send_message(card, cmsg);
978
                plci_change_state(card, plcip, EV_PLCI_CONNECT_REJECT);
979
                break;
980
 
981
        default:
982
                /* An error happened. (Invalid parameters for example.) */
983
                capi_cmsg_answer(cmsg);
984
                cmsg->Reject = 8;       /* reject call,
985
                                           destination out of order */
986
                send_message(card, cmsg);
987
                plci_change_state(card, plcip, EV_PLCI_CONNECT_REJECT);
988
                break;
989
        }
990
        return;
991
}
992
 
993
static void handle_plci(_cmsg * cmsg)
994
{
995
        capidrv_contr *card = findcontrbynumber(cmsg->adr.adrController & 0x7f);
996
        capidrv_plci *plcip;
997
        isdn_ctrl cmd;
998
        _cdebbuf *cdb;
999
 
1000
        if (!card) {
1001
                printk(KERN_ERR "capidrv: %s from unknown controller 0x%x\n",
1002
                       capi_cmd2str(cmsg->Command, cmsg->Subcommand),
1003
                       cmsg->adr.adrController & 0x7f);
1004
                return;
1005
        }
1006
        switch (CAPICMD(cmsg->Command, cmsg->Subcommand)) {
1007
 
1008
        case CAPI_DISCONNECT_IND:       /* plci */
1009
                if (cmsg->Reason) {
1010
                        printk(KERN_INFO "capidrv-%d: %s reason 0x%x (%s) for plci 0x%x\n",
1011
                           card->contrnr,
1012
                           capi_cmd2str(cmsg->Command, cmsg->Subcommand),
1013
                               cmsg->Reason, capi_info2str(cmsg->Reason), cmsg->adr.adrPLCI);
1014
                }
1015
                if (!(plcip = find_plci_by_plci(card, cmsg->adr.adrPLCI))) {
1016
                        capi_cmsg_answer(cmsg);
1017
                        send_message(card, cmsg);
1018
                        goto notfound;
1019
                }
1020
                card->bchans[plcip->chan].disconnecting = 1;
1021
                plci_change_state(card, plcip, EV_PLCI_DISCONNECT_IND);
1022
                capi_cmsg_answer(cmsg);
1023
                send_message(card, cmsg);
1024
                plci_change_state(card, plcip, EV_PLCI_DISCONNECT_RESP);
1025
                break;
1026
 
1027
        case CAPI_DISCONNECT_CONF:      /* plci */
1028
                if (cmsg->Info) {
1029
                        printk(KERN_INFO "capidrv-%d: %s info 0x%x (%s) for plci 0x%x\n",
1030
                           card->contrnr,
1031
                           capi_cmd2str(cmsg->Command, cmsg->Subcommand),
1032
                               cmsg->Info, capi_info2str(cmsg->Info),
1033
                               cmsg->adr.adrPLCI);
1034
                }
1035
                if (!(plcip = find_plci_by_plci(card, cmsg->adr.adrPLCI)))
1036
                        goto notfound;
1037
 
1038
                card->bchans[plcip->chan].disconnecting = 1;
1039
                break;
1040
 
1041
        case CAPI_ALERT_CONF:   /* plci */
1042
                if (cmsg->Info) {
1043
                        printk(KERN_INFO "capidrv-%d: %s info 0x%x (%s) for plci 0x%x\n",
1044
                           card->contrnr,
1045
                           capi_cmd2str(cmsg->Command, cmsg->Subcommand),
1046
                               cmsg->Info, capi_info2str(cmsg->Info),
1047
                               cmsg->adr.adrPLCI);
1048
                }
1049
                break;
1050
 
1051
        case CAPI_CONNECT_IND:  /* plci */
1052
                handle_incoming_call(card, cmsg);
1053
                break;
1054
 
1055
        case CAPI_CONNECT_CONF: /* plci */
1056
                if (cmsg->Info) {
1057
                        printk(KERN_INFO "capidrv-%d: %s info 0x%x (%s) for plci 0x%x\n",
1058
                           card->contrnr,
1059
                           capi_cmd2str(cmsg->Command, cmsg->Subcommand),
1060
                               cmsg->Info, capi_info2str(cmsg->Info),
1061
                               cmsg->adr.adrPLCI);
1062
                }
1063
                if (!(plcip = find_plci_by_msgid(card, cmsg->Messagenumber)))
1064
                        goto notfound;
1065
 
1066
                plcip->plci = cmsg->adr.adrPLCI;
1067
                if (cmsg->Info) {
1068
                        plci_change_state(card, plcip, EV_PLCI_CONNECT_CONF_ERROR);
1069
                } else {
1070
                        plci_change_state(card, plcip, EV_PLCI_CONNECT_CONF_OK);
1071
                }
1072
                break;
1073
 
1074
        case CAPI_CONNECT_ACTIVE_IND:   /* plci */
1075
 
1076
                if (!(plcip = find_plci_by_plci(card, cmsg->adr.adrPLCI)))
1077
                        goto notfound;
1078
 
1079
                if (card->bchans[plcip->chan].incoming) {
1080
                        capi_cmsg_answer(cmsg);
1081
                        send_message(card, cmsg);
1082
                        plci_change_state(card, plcip, EV_PLCI_CONNECT_ACTIVE_IND);
1083
                } else {
1084
                        capidrv_ncci *nccip;
1085
                        capi_cmsg_answer(cmsg);
1086
                        send_message(card, cmsg);
1087
 
1088
                        nccip = new_ncci(card, plcip, cmsg->adr.adrPLCI);
1089
 
1090
                        if (!nccip) {
1091
                                printk(KERN_ERR "capidrv-%d: no mem for ncci, sorry\n", card->contrnr);
1092
                                break;  /* $$$$ */
1093
                        }
1094
                        capi_fill_CONNECT_B3_REQ(cmsg,
1095
                                                 global.ap.applid,
1096
                                                 card->msgid++,
1097
                                                 plcip->plci,   /* adr */
1098
                                                 NULL   /* NCPI */
1099
                        );
1100
                        nccip->msgid = cmsg->Messagenumber;
1101
                        send_message(card, cmsg);
1102
                        cmd.command = ISDN_STAT_DCONN;
1103
                        cmd.driver = card->myid;
1104
                        cmd.arg = plcip->chan;
1105
                        card->interface.statcallb(&cmd);
1106
                        plci_change_state(card, plcip, EV_PLCI_CONNECT_ACTIVE_IND);
1107
                        ncci_change_state(card, nccip, EV_NCCI_CONNECT_B3_REQ);
1108
                }
1109
                break;
1110
 
1111
        case CAPI_INFO_IND:     /* Controller/plci */
1112
 
1113
                if (!(plcip = find_plci_by_plci(card, cmsg->adr.adrPLCI)))
1114
                        goto notfound;
1115
 
1116
                if (cmsg->InfoNumber == 0x4000) {
1117
                        if (cmsg->InfoElement[0] == 4) {
1118
                                cmd.command = ISDN_STAT_CINF;
1119
                                cmd.driver = card->myid;
1120
                                cmd.arg = plcip->chan;
1121
                                sprintf(cmd.parm.num, "%lu",
1122
                                        (unsigned long)
1123
                                        ((u32) cmsg->InfoElement[1]
1124
                                  | ((u32) (cmsg->InfoElement[2]) << 8)
1125
                                 | ((u32) (cmsg->InfoElement[3]) << 16)
1126
                                         | ((u32) (cmsg->InfoElement[4]) << 24)));
1127
                                card->interface.statcallb(&cmd);
1128
                                break;
1129
                        }
1130
                }
1131
                cdb = capi_cmsg2str(cmsg);
1132
                if (cdb) {
1133
                        printk(KERN_WARNING "capidrv-%d: %s\n",
1134
                                card->contrnr, cdb->buf);
1135
                        cdebbuf_free(cdb);
1136
                } else
1137
                        printk(KERN_WARNING "capidrv-%d: CAPI_INFO_IND InfoNumber %x not handled\n",
1138
                                card->contrnr, cmsg->InfoNumber);
1139
 
1140
                break;
1141
 
1142
        case CAPI_CONNECT_ACTIVE_CONF:          /* plci */
1143
                goto ignored;
1144
        case CAPI_SELECT_B_PROTOCOL_CONF:       /* plci */
1145
                goto ignored;
1146
        case CAPI_FACILITY_IND: /* Controller/plci/ncci */
1147
                goto ignored;
1148
        case CAPI_FACILITY_CONF:        /* Controller/plci/ncci */
1149
                goto ignored;
1150
 
1151
        case CAPI_INFO_CONF:    /* Controller/plci */
1152
                goto ignored;
1153
 
1154
        default:
1155
                printk(KERN_ERR "capidrv-%d: got %s for plci 0x%x ???",
1156
                       card->contrnr,
1157
                       capi_cmd2str(cmsg->Command, cmsg->Subcommand),
1158
                       cmsg->adr.adrPLCI);
1159
        }
1160
        return;
1161
      ignored:
1162
        printk(KERN_INFO "capidrv-%d: %s for plci 0x%x ignored\n",
1163
               card->contrnr,
1164
               capi_cmd2str(cmsg->Command, cmsg->Subcommand),
1165
               cmsg->adr.adrPLCI);
1166
        return;
1167
      notfound:
1168
        printk(KERN_ERR "capidrv-%d: %s: plci 0x%x not found\n",
1169
               card->contrnr,
1170
               capi_cmd2str(cmsg->Command, cmsg->Subcommand),
1171
               cmsg->adr.adrPLCI);
1172
        return;
1173
}
1174
 
1175
static void handle_ncci(_cmsg * cmsg)
1176
{
1177
        capidrv_contr *card = findcontrbynumber(cmsg->adr.adrController & 0x7f);
1178
        capidrv_plci *plcip;
1179
        capidrv_ncci *nccip;
1180
        isdn_ctrl cmd;
1181
        int len;
1182
 
1183
        if (!card) {
1184
                printk(KERN_ERR "capidrv: %s from unknown controller 0x%x\n",
1185
                       capi_cmd2str(cmsg->Command, cmsg->Subcommand),
1186
                       cmsg->adr.adrController & 0x7f);
1187
                return;
1188
        }
1189
        switch (CAPICMD(cmsg->Command, cmsg->Subcommand)) {
1190
 
1191
        case CAPI_CONNECT_B3_ACTIVE_IND:        /* ncci */
1192
                if (!(nccip = find_ncci(card, cmsg->adr.adrNCCI)))
1193
                        goto notfound;
1194
 
1195
                capi_cmsg_answer(cmsg);
1196
                send_message(card, cmsg);
1197
                ncci_change_state(card, nccip, EV_NCCI_CONNECT_B3_ACTIVE_IND);
1198
 
1199
                cmd.command = ISDN_STAT_BCONN;
1200
                cmd.driver = card->myid;
1201
                cmd.arg = nccip->chan;
1202
                card->interface.statcallb(&cmd);
1203
 
1204
                printk(KERN_INFO "capidrv-%d: chan %d up with ncci 0x%x\n",
1205
                       card->contrnr, nccip->chan, nccip->ncci);
1206
                break;
1207
 
1208
        case CAPI_CONNECT_B3_ACTIVE_CONF:       /* ncci */
1209
                goto ignored;
1210
 
1211
        case CAPI_CONNECT_B3_IND:       /* ncci */
1212
 
1213
                plcip = find_plci_by_ncci(card, cmsg->adr.adrNCCI);
1214
                if (plcip) {
1215
                        nccip = new_ncci(card, plcip, cmsg->adr.adrNCCI);
1216
                        if (nccip) {
1217
                                ncci_change_state(card, nccip, EV_NCCI_CONNECT_B3_IND);
1218
                                capi_fill_CONNECT_B3_RESP(cmsg,
1219
                                                          global.ap.applid,
1220
                                                          card->msgid++,
1221
                                                          nccip->ncci,  /* adr */
1222
                                                          0,     /* Reject */
1223
                                                          NULL  /* NCPI */
1224
                                );
1225
                                send_message(card, cmsg);
1226
                                ncci_change_state(card, nccip, EV_NCCI_CONNECT_B3_RESP);
1227
                                break;
1228
                        }
1229
                        printk(KERN_ERR "capidrv-%d: no mem for ncci, sorry\n",                                                 card->contrnr);
1230
                } else {
1231
                        printk(KERN_ERR "capidrv-%d: %s: plci for ncci 0x%x not found\n",
1232
                           card->contrnr,
1233
                           capi_cmd2str(cmsg->Command, cmsg->Subcommand),
1234
                               cmsg->adr.adrNCCI);
1235
                }
1236
                capi_fill_CONNECT_B3_RESP(cmsg,
1237
                                          global.ap.applid,
1238
                                          card->msgid++,
1239
                                          cmsg->adr.adrNCCI,
1240
                                          2,    /* Reject */
1241
                                          NULL  /* NCPI */
1242
                );
1243
                send_message(card, cmsg);
1244
                break;
1245
 
1246
        case CAPI_CONNECT_B3_CONF:      /* ncci */
1247
 
1248
                if (!(nccip = find_ncci_by_msgid(card,
1249
                                                 cmsg->adr.adrNCCI,
1250
                                                 cmsg->Messagenumber)))
1251
                        goto notfound;
1252
 
1253
                nccip->ncci = cmsg->adr.adrNCCI;
1254
                if (cmsg->Info) {
1255
                        printk(KERN_INFO "capidrv-%d: %s info 0x%x (%s) for ncci 0x%x\n",
1256
                           card->contrnr,
1257
                           capi_cmd2str(cmsg->Command, cmsg->Subcommand),
1258
                               cmsg->Info, capi_info2str(cmsg->Info),
1259
                               cmsg->adr.adrNCCI);
1260
                }
1261
 
1262
                if (cmsg->Info)
1263
                        ncci_change_state(card, nccip, EV_NCCI_CONNECT_B3_CONF_ERROR);
1264
                else
1265
                        ncci_change_state(card, nccip, EV_NCCI_CONNECT_B3_CONF_OK);
1266
                break;
1267
 
1268
        case CAPI_CONNECT_B3_T90_ACTIVE_IND:    /* ncci */
1269
                capi_cmsg_answer(cmsg);
1270
                send_message(card, cmsg);
1271
                break;
1272
 
1273
        case CAPI_DATA_B3_IND:  /* ncci */
1274
                /* handled in handle_data() */
1275
                goto ignored;
1276
 
1277
        case CAPI_DATA_B3_CONF: /* ncci */
1278
                if (cmsg->Info) {
1279
                        printk(KERN_WARNING "CAPI_DATA_B3_CONF: Info %x - %s\n",
1280
                                cmsg->Info, capi_info2str(cmsg->Info));
1281
                }
1282
                if (!(nccip = find_ncci(card, cmsg->adr.adrNCCI)))
1283
                        goto notfound;
1284
 
1285
                len = capidrv_del_ack(nccip, cmsg->DataHandle);
1286
                if (len < 0)
1287
                        break;
1288
                cmd.command = ISDN_STAT_BSENT;
1289
                cmd.driver = card->myid;
1290
                cmd.arg = nccip->chan;
1291
                cmd.parm.length = len;
1292
                card->interface.statcallb(&cmd);
1293
                break;
1294
 
1295
        case CAPI_DISCONNECT_B3_IND:    /* ncci */
1296
                if (!(nccip = find_ncci(card, cmsg->adr.adrNCCI)))
1297
                        goto notfound;
1298
 
1299
                card->bchans[nccip->chan].disconnecting = 1;
1300
                ncci_change_state(card, nccip, EV_NCCI_DISCONNECT_B3_IND);
1301
                capi_cmsg_answer(cmsg);
1302
                send_message(card, cmsg);
1303
                ncci_change_state(card, nccip, EV_NCCI_DISCONNECT_B3_RESP);
1304
                break;
1305
 
1306
        case CAPI_DISCONNECT_B3_CONF:   /* ncci */
1307
                if (!(nccip = find_ncci(card, cmsg->adr.adrNCCI)))
1308
                        goto notfound;
1309
                if (cmsg->Info) {
1310
                        printk(KERN_INFO "capidrv-%d: %s info 0x%x (%s) for ncci 0x%x\n",
1311
                           card->contrnr,
1312
                           capi_cmd2str(cmsg->Command, cmsg->Subcommand),
1313
                               cmsg->Info, capi_info2str(cmsg->Info),
1314
                               cmsg->adr.adrNCCI);
1315
                        ncci_change_state(card, nccip, EV_NCCI_DISCONNECT_B3_CONF_ERROR);
1316
                }
1317
                break;
1318
 
1319
        case CAPI_RESET_B3_IND: /* ncci */
1320
                if (!(nccip = find_ncci(card, cmsg->adr.adrNCCI)))
1321
                        goto notfound;
1322
                ncci_change_state(card, nccip, EV_NCCI_RESET_B3_IND);
1323
                capi_cmsg_answer(cmsg);
1324
                send_message(card, cmsg);
1325
                break;
1326
 
1327
        case CAPI_RESET_B3_CONF:        /* ncci */
1328
                goto ignored;   /* $$$$ */
1329
 
1330
        case CAPI_FACILITY_IND: /* Controller/plci/ncci */
1331
                goto ignored;
1332
        case CAPI_FACILITY_CONF:        /* Controller/plci/ncci */
1333
                goto ignored;
1334
 
1335
        default:
1336
                printk(KERN_ERR "capidrv-%d: got %s for ncci 0x%x ???",
1337
                       card->contrnr,
1338
                       capi_cmd2str(cmsg->Command, cmsg->Subcommand),
1339
                       cmsg->adr.adrNCCI);
1340
        }
1341
        return;
1342
      ignored:
1343
        printk(KERN_INFO "capidrv-%d: %s for ncci 0x%x ignored\n",
1344
               card->contrnr,
1345
               capi_cmd2str(cmsg->Command, cmsg->Subcommand),
1346
               cmsg->adr.adrNCCI);
1347
        return;
1348
      notfound:
1349
        printk(KERN_ERR "capidrv-%d: %s: ncci 0x%x not found\n",
1350
               card->contrnr,
1351
               capi_cmd2str(cmsg->Command, cmsg->Subcommand),
1352
               cmsg->adr.adrNCCI);
1353
}
1354
 
1355
 
1356
static void handle_data(_cmsg * cmsg, struct sk_buff *skb)
1357
{
1358
        capidrv_contr *card = findcontrbynumber(cmsg->adr.adrController & 0x7f);
1359
        capidrv_ncci *nccip;
1360
 
1361
        if (!card) {
1362
                printk(KERN_ERR "capidrv: %s from unknown controller 0x%x\n",
1363
                       capi_cmd2str(cmsg->Command, cmsg->Subcommand),
1364
                       cmsg->adr.adrController & 0x7f);
1365
                kfree_skb(skb);
1366
                return;
1367
        }
1368
        if (!(nccip = find_ncci(card, cmsg->adr.adrNCCI))) {
1369
                printk(KERN_ERR "capidrv-%d: %s: ncci 0x%x not found\n",
1370
                       card->contrnr,
1371
                       capi_cmd2str(cmsg->Command, cmsg->Subcommand),
1372
                       cmsg->adr.adrNCCI);
1373
                kfree_skb(skb);
1374
                return;
1375
        }
1376
        (void) skb_pull(skb, CAPIMSG_LEN(skb->data));
1377
        card->interface.rcvcallb_skb(card->myid, nccip->chan, skb);
1378
        capi_cmsg_answer(cmsg);
1379
        send_message(card, cmsg);
1380
}
1381
 
1382
static _cmsg s_cmsg;
1383
 
1384
static void capidrv_recv_message(struct capi20_appl *ap, struct sk_buff *skb)
1385
{
1386
        capi_message2cmsg(&s_cmsg, skb->data);
1387
        if (debugmode > 3) {
1388
                _cdebbuf *cdb = capi_cmsg2str(&s_cmsg);
1389
 
1390
                if (cdb) {
1391
                        printk(KERN_DEBUG "%s: applid=%d %s\n", __FUNCTION__,
1392
                                ap->applid, cdb->buf);
1393
                        cdebbuf_free(cdb);
1394
                } else
1395
                        printk(KERN_DEBUG "%s: applid=%d %s not traced\n",
1396
                                __FUNCTION__, ap->applid,
1397
                                capi_cmd2str(s_cmsg.Command, s_cmsg.Subcommand));
1398
        }
1399
        if (s_cmsg.Command == CAPI_DATA_B3
1400
            && s_cmsg.Subcommand == CAPI_IND) {
1401
                handle_data(&s_cmsg, skb);
1402
                return;
1403
        }
1404
        if ((s_cmsg.adr.adrController & 0xffffff00) == 0)
1405
                handle_controller(&s_cmsg);
1406
        else if ((s_cmsg.adr.adrPLCI & 0xffff0000) == 0)
1407
                handle_plci(&s_cmsg);
1408
        else
1409
                handle_ncci(&s_cmsg);
1410
        /*
1411
         * data of skb used in s_cmsg,
1412
         * free data when s_cmsg is not used again
1413
         * thanks to Lars Heete <hel@admin.de>
1414
         */
1415
        kfree_skb(skb);
1416
}
1417
 
1418
/* ------------------------------------------------------------------- */
1419
 
1420
#define PUTBYTE_TO_STATUS(card, byte) \
1421
        do { \
1422
                *(card)->q931_write++ = (byte); \
1423
                if ((card)->q931_write > (card)->q931_end) \
1424
                        (card)->q931_write = (card)->q931_buf; \
1425
        } while (0)
1426
 
1427
static void handle_dtrace_data(capidrv_contr *card,
1428
                             int send, int level2, u8 *data, u16 len)
1429
{
1430
        u8 *p, *end;
1431
        isdn_ctrl cmd;
1432
 
1433
        if (!len) {
1434
                printk(KERN_DEBUG "capidrv-%d: avmb1_q931_data: len == %d\n",
1435
                                card->contrnr, len);
1436
                return;
1437
        }
1438
 
1439
        if (level2) {
1440
                PUTBYTE_TO_STATUS(card, 'D');
1441
                PUTBYTE_TO_STATUS(card, '2');
1442
                PUTBYTE_TO_STATUS(card, send ? '>' : '<');
1443
                PUTBYTE_TO_STATUS(card, ':');
1444
        } else {
1445
                PUTBYTE_TO_STATUS(card, 'D');
1446
                PUTBYTE_TO_STATUS(card, '3');
1447
                PUTBYTE_TO_STATUS(card, send ? '>' : '<');
1448
                PUTBYTE_TO_STATUS(card, ':');
1449
        }
1450
 
1451
        for (p = data, end = data+len; p < end; p++) {
1452
                u8 w;
1453
                PUTBYTE_TO_STATUS(card, ' ');
1454
                w = (*p >> 4) & 0xf;
1455
                PUTBYTE_TO_STATUS(card, (w < 10) ? '0'+w : 'A'-10+w);
1456
                w = *p & 0xf;
1457
                PUTBYTE_TO_STATUS(card, (w < 10) ? '0'+w : 'A'-10+w);
1458
        }
1459
        PUTBYTE_TO_STATUS(card, '\n');
1460
 
1461
        cmd.command = ISDN_STAT_STAVAIL;
1462
        cmd.driver = card->myid;
1463
        cmd.arg = len*3+5;
1464
        card->interface.statcallb(&cmd);
1465
}
1466
 
1467
/* ------------------------------------------------------------------- */
1468
 
1469
static _cmsg cmdcmsg;
1470
 
1471
static int capidrv_ioctl(isdn_ctrl * c, capidrv_contr * card)
1472
{
1473
        switch (c->arg) {
1474
        case 1:
1475
                debugmode = (int)(*((unsigned int *)c->parm.num));
1476
                printk(KERN_DEBUG "capidrv-%d: debugmode=%d\n",
1477
                                card->contrnr, debugmode);
1478
                return 0;
1479
        default:
1480
                printk(KERN_DEBUG "capidrv-%d: capidrv_ioctl(%ld) called ??\n",
1481
                                card->contrnr, c->arg);
1482
                return -EINVAL;
1483
        }
1484
        return -EINVAL;
1485
}
1486
 
1487
/*
1488
 * Handle leased lines (CAPI-Bundling)
1489
 */
1490
 
1491
struct internal_bchannelinfo {
1492
   unsigned short channelalloc;
1493
   unsigned short operation;
1494
   unsigned char  cmask[31];
1495
};
1496
 
1497
static int decodeFVteln(char *teln, unsigned long *bmaskp, int *activep)
1498
{
1499
        unsigned long bmask = 0;
1500
        int active = !0;
1501
        char *s;
1502
        int i;
1503
 
1504
        if (strncmp(teln, "FV:", 3) != 0)
1505
                return 1;
1506
        s = teln + 3;
1507
        while (*s && *s == ' ') s++;
1508
        if (!*s) return -2;
1509
        if (*s == 'p' || *s == 'P') {
1510
                active = 0;
1511
                s++;
1512
        }
1513
        if (*s == 'a' || *s == 'A') {
1514
                active = !0;
1515
                s++;
1516
        }
1517
        while (*s) {
1518
                int digit1 = 0;
1519
                int digit2 = 0;
1520
                if (!isdigit(*s)) return -3;
1521
                while (isdigit(*s)) { digit1 = digit1*10 + (*s - '0'); s++; }
1522
                if (digit1 <= 0 && digit1 > 30) return -4;
1523
                if (*s == 0 || *s == ',' || *s == ' ') {
1524
                        bmask |= (1 << digit1);
1525
                        digit1 = 0;
1526
                        if (*s) s++;
1527
                        continue;
1528
                }
1529
                if (*s != '-') return -5;
1530
                s++;
1531
                if (!isdigit(*s)) return -3;
1532
                while (isdigit(*s)) { digit2 = digit2*10 + (*s - '0'); s++; }
1533
                if (digit2 <= 0 && digit2 > 30) return -4;
1534
                if (*s == 0 || *s == ',' || *s == ' ') {
1535
                        if (digit1 > digit2)
1536
                                for (i = digit2; i <= digit1 ; i++)
1537
                                        bmask |= (1 << i);
1538
                        else
1539
                                for (i = digit1; i <= digit2 ; i++)
1540
                                        bmask |= (1 << i);
1541
                        digit1 = digit2 = 0;
1542
                        if (*s) s++;
1543
                        continue;
1544
                }
1545
                return -6;
1546
        }
1547
        if (activep) *activep = active;
1548
        if (bmaskp) *bmaskp = bmask;
1549
        return 0;
1550
}
1551
 
1552
static int FVteln2capi20(char *teln, u8 AdditionalInfo[1+2+2+31])
1553
{
1554
        unsigned long bmask;
1555
        int active;
1556
        int rc, i;
1557
 
1558
        rc = decodeFVteln(teln, &bmask, &active);
1559
        if (rc) return rc;
1560
        /* Length */
1561
        AdditionalInfo[0] = 2+2+31;
1562
        /* Channel: 3 => use channel allocation */
1563
        AdditionalInfo[1] = 3; AdditionalInfo[2] = 0;
1564
        /* Operation: 0 => DTE mode, 1 => DCE mode */
1565
        if (active) {
1566
                AdditionalInfo[3] = 0; AdditionalInfo[4] = 0;
1567
        } else {
1568
                AdditionalInfo[3] = 1; AdditionalInfo[4] = 0;
1569
        }
1570
        /* Channel mask array */
1571
        AdditionalInfo[5] = 0; /* no D-Channel */
1572
        for (i=1; i <= 30; i++)
1573
                AdditionalInfo[5+i] = (bmask & (1 << i)) ? 0xff : 0;
1574
        return 0;
1575
}
1576
 
1577
static int capidrv_command(isdn_ctrl * c, capidrv_contr * card)
1578
{
1579
        isdn_ctrl cmd;
1580
        struct capidrv_bchan *bchan;
1581
        struct capidrv_plci *plcip;
1582
        u8 AdditionalInfo[1+2+2+31];
1583
        int rc, isleasedline = 0;
1584
 
1585
        if (c->command == ISDN_CMD_IOCTL)
1586
                return capidrv_ioctl(c, card);
1587
 
1588
        switch (c->command) {
1589
        case ISDN_CMD_DIAL:{
1590
                        u8 calling[ISDN_MSNLEN + 3];
1591
                        u8 called[ISDN_MSNLEN + 2];
1592
 
1593
                        if (debugmode)
1594
                                printk(KERN_DEBUG "capidrv-%d: ISDN_CMD_DIAL(ch=%ld,\"%s,%d,%d,%s\")\n",
1595
                                        card->contrnr,
1596
                                        c->arg,
1597
                                        c->parm.setup.phone,
1598
                                        c->parm.setup.si1,
1599
                                        c->parm.setup.si2,
1600
                                        c->parm.setup.eazmsn);
1601
 
1602
                        bchan = &card->bchans[c->arg % card->nbchan];
1603
 
1604
                        if (bchan->plcip) {
1605
                                printk(KERN_ERR "capidrv-%d: dail ch=%ld,\"%s,%d,%d,%s\" in use (plci=0x%x)\n",
1606
                                        card->contrnr,
1607
                                        c->arg,
1608
                                        c->parm.setup.phone,
1609
                                        c->parm.setup.si1,
1610
                                        c->parm.setup.si2,
1611
                                        c->parm.setup.eazmsn,
1612
                                        bchan->plcip->plci);
1613
                                return 0;
1614
                        }
1615
                        bchan->si1 = c->parm.setup.si1;
1616
                        bchan->si2 = c->parm.setup.si2;
1617
 
1618
                        strncpy(bchan->num, c->parm.setup.phone, sizeof(bchan->num));
1619
                        strncpy(bchan->mynum, c->parm.setup.eazmsn, sizeof(bchan->mynum));
1620
                        rc = FVteln2capi20(bchan->num, AdditionalInfo);
1621
                        isleasedline = (rc == 0);
1622
                        if (rc < 0)
1623
                                printk(KERN_ERR "capidrv-%d: WARNING: invalid leased linedefinition \"%s\"\n", card->contrnr, bchan->num);
1624
 
1625
                        if (isleasedline) {
1626
                                calling[0] = 0;
1627
                                called[0] = 0;
1628
                                if (debugmode)
1629
                                        printk(KERN_DEBUG "capidrv-%d: connecting leased line\n", card->contrnr);
1630
                        } else {
1631
                                calling[0] = strlen(bchan->mynum) + 2;
1632
                                calling[1] = 0;
1633
                                calling[2] = 0x80;
1634
                                strncpy(calling + 3, bchan->mynum, ISDN_MSNLEN);
1635
                                called[0] = strlen(bchan->num) + 1;
1636
                                called[1] = 0x80;
1637
                                strncpy(called + 2, bchan->num, ISDN_MSNLEN);
1638
                        }
1639
 
1640
                        capi_fill_CONNECT_REQ(&cmdcmsg,
1641
                                              global.ap.applid,
1642
                                              card->msgid++,
1643
                                              card->contrnr,    /* adr */
1644
                                          si2cip(bchan->si1, bchan->si2),       /* cipvalue */
1645
                                              called,   /* CalledPartyNumber */
1646
                                              calling,  /* CallingPartyNumber */
1647
                                              NULL,     /* CalledPartySubaddress */
1648
                                              NULL,     /* CallingPartySubaddress */
1649
                                            b1prot(bchan->l2, bchan->l3),       /* B1protocol */
1650
                                            b2prot(bchan->l2, bchan->l3),       /* B2protocol */
1651
                                            b3prot(bchan->l2, bchan->l3),       /* B3protocol */
1652
                                            b1config(bchan->l2, bchan->l3),     /* B1configuration */
1653
                                              NULL,     /* B2configuration */
1654
                                              NULL,     /* B3configuration */
1655
                                              NULL,     /* BC */
1656
                                              NULL,     /* LLC */
1657
                                              NULL,     /* HLC */
1658
                                              /* BChannelinformation */
1659
                                              isleasedline ? AdditionalInfo : NULL,
1660
                                              NULL,     /* Keypadfacility */
1661
                                              NULL,     /* Useruserdata */
1662
                                              NULL      /* Facilitydataarray */
1663
                            );
1664
                        if ((plcip = new_plci(card, (c->arg % card->nbchan))) == 0) {
1665
                                cmd.command = ISDN_STAT_DHUP;
1666
                                cmd.driver = card->myid;
1667
                                cmd.arg = (c->arg % card->nbchan);
1668
                                card->interface.statcallb(&cmd);
1669
                                return -1;
1670
                        }
1671
                        plcip->msgid = cmdcmsg.Messagenumber;
1672
                        plcip->leasedline = isleasedline;
1673
                        plci_change_state(card, plcip, EV_PLCI_CONNECT_REQ);
1674
                        send_message(card, &cmdcmsg);
1675
                        return 0;
1676
                }
1677
 
1678
        case ISDN_CMD_ACCEPTD:
1679
 
1680
                bchan = &card->bchans[c->arg % card->nbchan];
1681
                if (debugmode)
1682
                        printk(KERN_DEBUG "capidrv-%d: ISDN_CMD_ACCEPTD(ch=%ld) l2=%d l3=%d\n",
1683
                               card->contrnr,
1684
                               c->arg, bchan->l2, bchan->l3);
1685
 
1686
                capi_fill_CONNECT_RESP(&cmdcmsg,
1687
                                       global.ap.applid,
1688
                                       card->msgid++,
1689
                                       bchan->plcip->plci,      /* adr */
1690
                                       0,        /* Reject */
1691
                                       b1prot(bchan->l2, bchan->l3),    /* B1protocol */
1692
                                       b2prot(bchan->l2, bchan->l3),    /* B2protocol */
1693
                                       b3prot(bchan->l2, bchan->l3),    /* B3protocol */
1694
                                       b1config(bchan->l2, bchan->l3),  /* B1configuration */
1695
                                       NULL,    /* B2configuration */
1696
                                       NULL,    /* B3configuration */
1697
                                       NULL,    /* ConnectedNumber */
1698
                                       NULL,    /* ConnectedSubaddress */
1699
                                       NULL,    /* LLC */
1700
                                       NULL,    /* BChannelinformation */
1701
                                       NULL,    /* Keypadfacility */
1702
                                       NULL,    /* Useruserdata */
1703
                                       NULL     /* Facilitydataarray */
1704
                );
1705
                capi_cmsg2message(&cmdcmsg, cmdcmsg.buf);
1706
                plci_change_state(card, bchan->plcip, EV_PLCI_CONNECT_RESP);
1707
                send_message(card, &cmdcmsg);
1708
                return 0;
1709
 
1710
        case ISDN_CMD_ACCEPTB:
1711
                if (debugmode)
1712
                        printk(KERN_DEBUG "capidrv-%d: ISDN_CMD_ACCEPTB(ch=%ld)\n",
1713
                               card->contrnr,
1714
                               c->arg);
1715
                return -ENOSYS;
1716
 
1717
        case ISDN_CMD_HANGUP:
1718
                if (debugmode)
1719
                        printk(KERN_DEBUG "capidrv-%d: ISDN_CMD_HANGUP(ch=%ld)\n",
1720
                               card->contrnr,
1721
                               c->arg);
1722
                bchan = &card->bchans[c->arg % card->nbchan];
1723
 
1724
                if (bchan->disconnecting) {
1725
                        if (debugmode)
1726
                                printk(KERN_DEBUG "capidrv-%d: chan %ld already disconnecting ...\n",
1727
                                       card->contrnr,
1728
                                       c->arg);
1729
                        return 0;
1730
                }
1731
                if (bchan->nccip) {
1732
                        bchan->disconnecting = 1;
1733
                        capi_fill_DISCONNECT_B3_REQ(&cmdcmsg,
1734
                                                    global.ap.applid,
1735
                                                    card->msgid++,
1736
                                                    bchan->nccip->ncci,
1737
                                                    NULL        /* NCPI */
1738
                        );
1739
                        ncci_change_state(card, bchan->nccip, EV_NCCI_DISCONNECT_B3_REQ);
1740
                        send_message(card, &cmdcmsg);
1741
                        return 0;
1742
                } else if (bchan->plcip) {
1743
                        if (bchan->plcip->state == ST_PLCI_INCOMING) {
1744
                                /*
1745
                                 * just ignore, we a called from
1746
                                 * isdn_status_callback(),
1747
                                 * which will return 0 or 2, this is handled
1748
                                 * by the CONNECT_IND handler
1749
                                 */
1750
                                bchan->disconnecting = 1;
1751
                                return 0;
1752
                        } else if (bchan->plcip->plci) {
1753
                                bchan->disconnecting = 1;
1754
                                capi_fill_DISCONNECT_REQ(&cmdcmsg,
1755
                                                         global.ap.applid,
1756
                                                         card->msgid++,
1757
                                                      bchan->plcip->plci,
1758
                                                         NULL,  /* BChannelinformation */
1759
                                                         NULL,  /* Keypadfacility */
1760
                                                         NULL,  /* Useruserdata */
1761
                                                         NULL   /* Facilitydataarray */
1762
                                );
1763
                                plci_change_state(card, bchan->plcip, EV_PLCI_DISCONNECT_REQ);
1764
                                send_message(card, &cmdcmsg);
1765
                                return 0;
1766
                        } else {
1767
                                printk(KERN_ERR "capidrv-%d: chan %ld disconnect request while waiting for CONNECT_CONF\n",
1768
                                       card->contrnr,
1769
                                       c->arg);
1770
                                return -EINVAL;
1771
                        }
1772
                }
1773
                printk(KERN_ERR "capidrv-%d: chan %ld disconnect request on free channel\n",
1774
                                       card->contrnr,
1775
                                       c->arg);
1776
                return -EINVAL;
1777
/* ready */
1778
 
1779
        case ISDN_CMD_SETL2:
1780
                if (debugmode)
1781
                        printk(KERN_DEBUG "capidrv-%d: set L2 on chan %ld to %ld\n",
1782
                               card->contrnr,
1783
                               (c->arg & 0xff), (c->arg >> 8));
1784
                bchan = &card->bchans[(c->arg & 0xff) % card->nbchan];
1785
                bchan->l2 = (c->arg >> 8);
1786
                return 0;
1787
 
1788
        case ISDN_CMD_SETL3:
1789
                if (debugmode)
1790
                        printk(KERN_DEBUG "capidrv-%d: set L3 on chan %ld to %ld\n",
1791
                               card->contrnr,
1792
                               (c->arg & 0xff), (c->arg >> 8));
1793
                bchan = &card->bchans[(c->arg & 0xff) % card->nbchan];
1794
                bchan->l3 = (c->arg >> 8);
1795
                return 0;
1796
 
1797
        case ISDN_CMD_SETEAZ:
1798
                if (debugmode)
1799
                        printk(KERN_DEBUG "capidrv-%d: set EAZ \"%s\" on chan %ld\n",
1800
                               card->contrnr,
1801
                               c->parm.num, c->arg);
1802
                bchan = &card->bchans[c->arg % card->nbchan];
1803
                strncpy(bchan->msn, c->parm.num, ISDN_MSNLEN);
1804
                return 0;
1805
 
1806
        case ISDN_CMD_CLREAZ:
1807
                if (debugmode)
1808
                        printk(KERN_DEBUG "capidrv-%d: clearing EAZ on chan %ld\n",
1809
                                        card->contrnr, c->arg);
1810
                bchan = &card->bchans[c->arg % card->nbchan];
1811
                bchan->msn[0] = 0;
1812
                return 0;
1813
 
1814
        default:
1815
                printk(KERN_ERR "capidrv-%d: ISDN_CMD_%d, Huh?\n",
1816
                                        card->contrnr, c->command);
1817
                return -EINVAL;
1818
        }
1819
        return 0;
1820
}
1821
 
1822
static int if_command(isdn_ctrl * c)
1823
{
1824
        capidrv_contr *card = findcontrbydriverid(c->driver);
1825
 
1826
        if (card)
1827
                return capidrv_command(c, card);
1828
 
1829
        printk(KERN_ERR
1830
             "capidrv: if_command %d called with invalid driverId %d!\n",
1831
                                                c->command, c->driver);
1832
        return -ENODEV;
1833
}
1834
 
1835
static _cmsg sendcmsg;
1836
 
1837
static int if_sendbuf(int id, int channel, int doack, struct sk_buff *skb)
1838
{
1839
        capidrv_contr *card = findcontrbydriverid(id);
1840
        capidrv_bchan *bchan;
1841
        capidrv_ncci *nccip;
1842
        int len = skb->len;
1843
        int msglen;
1844
        u16 errcode;
1845
        u16 datahandle;
1846
        u32 data;
1847
 
1848
        if (!card) {
1849
                printk(KERN_ERR "capidrv: if_sendbuf called with invalid driverId %d!\n",
1850
                       id);
1851
                return 0;
1852
        }
1853
        if (debugmode > 4)
1854
                printk(KERN_DEBUG "capidrv-%d: sendbuf len=%d skb=%p doack=%d\n",
1855
                                        card->contrnr, len, skb, doack);
1856
        bchan = &card->bchans[channel % card->nbchan];
1857
        nccip = bchan->nccip;
1858
        if (!nccip || nccip->state != ST_NCCI_ACTIVE) {
1859
                printk(KERN_ERR "capidrv-%d: if_sendbuf: %s:%d: chan not up!\n",
1860
                       card->contrnr, card->name, channel);
1861
                return 0;
1862
        }
1863
        datahandle = nccip->datahandle;
1864
 
1865
        /*
1866
         * Here we copy pointer skb->data into the 32-bit 'Data' field.
1867
         * The 'Data' field is not used in practice in linux kernel
1868
         * (neither in 32 or 64 bit), but should have some value,
1869
         * since a CAPI message trace will display it.
1870
         *
1871
         * The correct value in the 32 bit case is the address of the
1872
         * data, in 64 bit it makes no sense, we use 0 there.
1873
         */
1874
 
1875
#ifdef CONFIG_64BIT
1876
        data = 0;
1877
#else
1878
        data = (unsigned long) skb->data;
1879
#endif
1880
 
1881
        capi_fill_DATA_B3_REQ(&sendcmsg, global.ap.applid, card->msgid++,
1882
                              nccip->ncci,      /* adr */
1883
                              data,             /* Data */
1884
                              skb->len,         /* DataLength */
1885
                              datahandle,       /* DataHandle */
1886
 
1887
            );
1888
 
1889
        if (capidrv_add_ack(nccip, datahandle, doack ? (int)skb->len : -1) < 0)
1890
           return 0;
1891
 
1892
        capi_cmsg2message(&sendcmsg, sendcmsg.buf);
1893
        msglen = CAPIMSG_LEN(sendcmsg.buf);
1894
        if (skb_headroom(skb) < msglen) {
1895
                struct sk_buff *nskb = skb_realloc_headroom(skb, msglen);
1896
                if (!nskb) {
1897
                        printk(KERN_ERR "capidrv-%d: if_sendbuf: no memory\n",
1898
                                card->contrnr);
1899
                        (void)capidrv_del_ack(nccip, datahandle);
1900
                        return 0;
1901
                }
1902
                printk(KERN_DEBUG "capidrv-%d: only %d bytes headroom, need %d\n",
1903
                       card->contrnr, skb_headroom(skb), msglen);
1904
                memcpy(skb_push(nskb, msglen), sendcmsg.buf, msglen);
1905
                errcode = capi20_put_message(&global.ap, nskb);
1906
                if (errcode == CAPI_NOERROR) {
1907
                        dev_kfree_skb(skb);
1908
                        nccip->datahandle++;
1909
                        return len;
1910
                }
1911
                if (debugmode > 3)
1912
                        printk(KERN_DEBUG "capidrv-%d: sendbuf putmsg ret(%x) - %s\n",
1913
                                card->contrnr, errcode, capi_info2str(errcode));
1914
                (void)capidrv_del_ack(nccip, datahandle);
1915
                dev_kfree_skb(nskb);
1916
                return errcode == CAPI_SENDQUEUEFULL ? 0 : -1;
1917
        } else {
1918
                memcpy(skb_push(skb, msglen), sendcmsg.buf, msglen);
1919
                errcode = capi20_put_message(&global.ap, skb);
1920
                if (errcode == CAPI_NOERROR) {
1921
                        nccip->datahandle++;
1922
                        return len;
1923
                }
1924
                if (debugmode > 3)
1925
                        printk(KERN_DEBUG "capidrv-%d: sendbuf putmsg ret(%x) - %s\n",
1926
                                card->contrnr, errcode, capi_info2str(errcode));
1927
                skb_pull(skb, msglen);
1928
                (void)capidrv_del_ack(nccip, datahandle);
1929
                return errcode == CAPI_SENDQUEUEFULL ? 0 : -1;
1930
        }
1931
}
1932
 
1933
static int if_readstat(u8 __user *buf, int len, int id, int channel)
1934
{
1935
        capidrv_contr *card = findcontrbydriverid(id);
1936
        int count;
1937
        u8 __user *p;
1938
 
1939
        if (!card) {
1940
                printk(KERN_ERR "capidrv: if_readstat called with invalid driverId %d!\n",
1941
                       id);
1942
                return -ENODEV;
1943
        }
1944
 
1945
        for (p=buf, count=0; count < len; p++, count++) {
1946
                if (put_user(*card->q931_read++, p))
1947
                        return -EFAULT;
1948
                if (card->q931_read > card->q931_end)
1949
                        card->q931_read = card->q931_buf;
1950
        }
1951
        return count;
1952
 
1953
}
1954
 
1955
static void enable_dchannel_trace(capidrv_contr *card)
1956
{
1957
        u8 manufacturer[CAPI_MANUFACTURER_LEN];
1958
        capi_version version;
1959
        u16 contr = card->contrnr;
1960
        u16 errcode;
1961
        u16 avmversion[3];
1962
 
1963
        errcode = capi20_get_manufacturer(contr, manufacturer);
1964
        if (errcode != CAPI_NOERROR) {
1965
           printk(KERN_ERR "%s: can't get manufacturer (0x%x)\n",
1966
                        card->name, errcode);
1967
           return;
1968
        }
1969
        if (strstr(manufacturer, "AVM") == 0) {
1970
           printk(KERN_ERR "%s: not from AVM, no d-channel trace possible (%s)\n",
1971
                        card->name, manufacturer);
1972
           return;
1973
        }
1974
        errcode = capi20_get_version(contr, &version);
1975
        if (errcode != CAPI_NOERROR) {
1976
           printk(KERN_ERR "%s: can't get version (0x%x)\n",
1977
                        card->name, errcode);
1978
           return;
1979
        }
1980
        avmversion[0] = (version.majormanuversion >> 4) & 0x0f;
1981
        avmversion[1] = (version.majormanuversion << 4) & 0xf0;
1982
        avmversion[1] |= (version.minormanuversion >> 4) & 0x0f;
1983
        avmversion[2] |= version.minormanuversion & 0x0f;
1984
 
1985
        if (avmversion[0] > 3 || (avmversion[0] == 3 && avmversion[1] > 5)) {
1986
                printk(KERN_INFO "%s: D2 trace enabled\n", card->name);
1987
                capi_fill_MANUFACTURER_REQ(&cmdcmsg, global.ap.applid,
1988
                                           card->msgid++,
1989
                                           contr,
1990
                                           0x214D5641,  /* ManuID */
1991
                                           0,           /* Class */
1992
                                           1,           /* Function */
1993
                                           (_cstruct)"\004\200\014\000\000");
1994
        } else {
1995
                printk(KERN_INFO "%s: D3 trace enabled\n", card->name);
1996
                capi_fill_MANUFACTURER_REQ(&cmdcmsg, global.ap.applid,
1997
                                           card->msgid++,
1998
                                           contr,
1999
                                           0x214D5641,  /* ManuID */
2000
                                           0,           /* Class */
2001
                                           1,           /* Function */
2002
                                           (_cstruct)"\004\002\003\000\000");
2003
        }
2004
        send_message(card, &cmdcmsg);
2005
}
2006
 
2007
 
2008
static void send_listen(capidrv_contr *card)
2009
{
2010
        capi_fill_LISTEN_REQ(&cmdcmsg, global.ap.applid,
2011
                             card->msgid++,
2012
                             card->contrnr, /* controller */
2013
                             1 << 6,    /* Infomask */
2014
                             card->cipmask,
2015
                             card->cipmask2,
2016
                             NULL, NULL);
2017
        send_message(card, &cmdcmsg);
2018
        listen_change_state(card, EV_LISTEN_REQ);
2019
}
2020
 
2021
static void listentimerfunc(unsigned long x)
2022
{
2023
        capidrv_contr *card = (capidrv_contr *)x;
2024
        if (card->state != ST_LISTEN_NONE && card->state != ST_LISTEN_ACTIVE)
2025
                printk(KERN_ERR "%s: controller dead ??\n", card->name);
2026
        send_listen(card);
2027
        mod_timer(&card->listentimer, jiffies + 60*HZ);
2028
}
2029
 
2030
 
2031
static int capidrv_addcontr(u16 contr, struct capi_profile *profp)
2032
{
2033
        capidrv_contr *card;
2034
        unsigned long flags;
2035
        isdn_ctrl cmd;
2036
        char id[20];
2037
        int i;
2038
 
2039
        sprintf(id, "capidrv-%d", contr);
2040
        if (!try_module_get(THIS_MODULE)) {
2041
                printk(KERN_WARNING "capidrv: (%s) Could not reserve module\n", id);
2042
                return -1;
2043
        }
2044
        if (!(card = kzalloc(sizeof(capidrv_contr), GFP_ATOMIC))) {
2045
                printk(KERN_WARNING
2046
                 "capidrv: (%s) Could not allocate contr-struct.\n", id);
2047
                return -1;
2048
        }
2049
        card->owner = THIS_MODULE;
2050
        init_timer(&card->listentimer);
2051
        strcpy(card->name, id);
2052
        card->contrnr = contr;
2053
        card->nbchan = profp->nbchannel;
2054
        card->bchans = kmalloc(sizeof(capidrv_bchan) * card->nbchan, GFP_ATOMIC);
2055
        if (!card->bchans) {
2056
                printk(KERN_WARNING
2057
                "capidrv: (%s) Could not allocate bchan-structs.\n", id);
2058
                module_put(card->owner);
2059
                kfree(card);
2060
                return -1;
2061
        }
2062
        card->interface.channels = profp->nbchannel;
2063
        card->interface.maxbufsize = 2048;
2064
        card->interface.command = if_command;
2065
        card->interface.writebuf_skb = if_sendbuf;
2066
        card->interface.writecmd = NULL;
2067
        card->interface.readstat = if_readstat;
2068
        card->interface.features = ISDN_FEATURE_L2_HDLC |
2069
                                   ISDN_FEATURE_L2_TRANS |
2070
                                   ISDN_FEATURE_L3_TRANS |
2071
                                   ISDN_FEATURE_P_UNKNOWN |
2072
                                   ISDN_FEATURE_L2_X75I |
2073
                                   ISDN_FEATURE_L2_X75UI |
2074
                                   ISDN_FEATURE_L2_X75BUI;
2075
        if (profp->support1 & (1<<2))
2076
                card->interface.features |= ISDN_FEATURE_L2_V11096 |
2077
                                            ISDN_FEATURE_L2_V11019 |
2078
                                            ISDN_FEATURE_L2_V11038;
2079
        if (profp->support1 & (1<<8))
2080
                card->interface.features |= ISDN_FEATURE_L2_MODEM;
2081
        card->interface.hl_hdrlen = 22; /* len of DATA_B3_REQ */
2082
        strncpy(card->interface.id, id, sizeof(card->interface.id) - 1);
2083
 
2084
 
2085
        card->q931_read = card->q931_buf;
2086
        card->q931_write = card->q931_buf;
2087
        card->q931_end = card->q931_buf + sizeof(card->q931_buf) - 1;
2088
 
2089
        if (!register_isdn(&card->interface)) {
2090
                printk(KERN_ERR "capidrv: Unable to register contr %s\n", id);
2091
                kfree(card->bchans);
2092
                module_put(card->owner);
2093
                kfree(card);
2094
                return -1;
2095
        }
2096
        card->myid = card->interface.channels;
2097
        memset(card->bchans, 0, sizeof(capidrv_bchan) * card->nbchan);
2098
        for (i = 0; i < card->nbchan; i++) {
2099
                card->bchans[i].contr = card;
2100
        }
2101
 
2102
        spin_lock_irqsave(&global_lock, flags);
2103
        card->next = global.contr_list;
2104
        global.contr_list = card;
2105
        global.ncontr++;
2106
        spin_unlock_irqrestore(&global_lock, flags);
2107
 
2108
        cmd.command = ISDN_STAT_RUN;
2109
        cmd.driver = card->myid;
2110
        card->interface.statcallb(&cmd);
2111
 
2112
        card->cipmask = 0x1FFF03FF;     /* any */
2113
        card->cipmask2 = 0;
2114
 
2115
        card->listentimer.data = (unsigned long)card;
2116
        card->listentimer.function = listentimerfunc;
2117
        send_listen(card);
2118
        mod_timer(&card->listentimer, jiffies + 60*HZ);
2119
 
2120
        printk(KERN_INFO "%s: now up (%d B channels)\n",
2121
                card->name, card->nbchan);
2122
 
2123
        enable_dchannel_trace(card);
2124
 
2125
        return 0;
2126
}
2127
 
2128
static int capidrv_delcontr(u16 contr)
2129
{
2130
        capidrv_contr **pp, *card;
2131
        unsigned long flags;
2132
        isdn_ctrl cmd;
2133
 
2134
        spin_lock_irqsave(&global_lock, flags);
2135
        for (card = global.contr_list; card; card = card->next) {
2136
                if (card->contrnr == contr)
2137
                        break;
2138
        }
2139
        if (!card) {
2140
                spin_unlock_irqrestore(&global_lock, flags);
2141
                printk(KERN_ERR "capidrv: delcontr: no contr %u\n", contr);
2142
                return -1;
2143
        }
2144
 
2145
        /* FIXME: maybe a race condition the card should be removed
2146
         * here from global list /kkeil
2147
         */
2148
        spin_unlock_irqrestore(&global_lock, flags);
2149
 
2150
        del_timer(&card->listentimer);
2151
 
2152
        if (debugmode)
2153
                printk(KERN_DEBUG "capidrv-%d: id=%d unloading\n",
2154
                                        card->contrnr, card->myid);
2155
 
2156
        cmd.command = ISDN_STAT_STOP;
2157
        cmd.driver = card->myid;
2158
        card->interface.statcallb(&cmd);
2159
 
2160
        while (card->nbchan) {
2161
 
2162
                cmd.command = ISDN_STAT_DISCH;
2163
                cmd.driver = card->myid;
2164
                cmd.arg = card->nbchan-1;
2165
                cmd.parm.num[0] = 0;
2166
                if (debugmode)
2167
                        printk(KERN_DEBUG "capidrv-%d: id=%d disable chan=%ld\n",
2168
                                        card->contrnr, card->myid, cmd.arg);
2169
                card->interface.statcallb(&cmd);
2170
 
2171
                if (card->bchans[card->nbchan-1].nccip)
2172
                        free_ncci(card, card->bchans[card->nbchan-1].nccip);
2173
                if (card->bchans[card->nbchan-1].plcip)
2174
                        free_plci(card, card->bchans[card->nbchan-1].plcip);
2175
                if (card->plci_list)
2176
                        printk(KERN_ERR "capidrv: bug in free_plci()\n");
2177
                card->nbchan--;
2178
        }
2179
        kfree(card->bchans);
2180
        card->bchans = NULL;
2181
 
2182
        if (debugmode)
2183
                printk(KERN_DEBUG "capidrv-%d: id=%d isdn unload\n",
2184
                                        card->contrnr, card->myid);
2185
 
2186
        cmd.command = ISDN_STAT_UNLOAD;
2187
        cmd.driver = card->myid;
2188
        card->interface.statcallb(&cmd);
2189
 
2190
        if (debugmode)
2191
                printk(KERN_DEBUG "capidrv-%d: id=%d remove contr from list\n",
2192
                                        card->contrnr, card->myid);
2193
 
2194
        spin_lock_irqsave(&global_lock, flags);
2195
        for (pp = &global.contr_list; *pp; pp = &(*pp)->next) {
2196
                if (*pp == card) {
2197
                        *pp = (*pp)->next;
2198
                        card->next = NULL;
2199
                        global.ncontr--;
2200
                        break;
2201
                }
2202
        }
2203
        spin_unlock_irqrestore(&global_lock, flags);
2204
 
2205
        module_put(card->owner);
2206
        printk(KERN_INFO "%s: now down.\n", card->name);
2207
        kfree(card);
2208
        return 0;
2209
}
2210
 
2211
 
2212
static void lower_callback(unsigned int cmd, u32 contr, void *data)
2213
{
2214
 
2215
        switch (cmd) {
2216
        case KCI_CONTRUP:
2217
                printk(KERN_INFO "capidrv: controller %hu up\n", contr);
2218
                (void) capidrv_addcontr(contr, (capi_profile *) data);
2219
                break;
2220
        case KCI_CONTRDOWN:
2221
                printk(KERN_INFO "capidrv: controller %hu down\n", contr);
2222
                (void) capidrv_delcontr(contr);
2223
                break;
2224
        }
2225
}
2226
 
2227
/*
2228
 * /proc/capi/capidrv:
2229
 * nrecvctlpkt nrecvdatapkt nsendctlpkt nsenddatapkt
2230
 */
2231
static int proc_capidrv_read_proc(char *page, char **start, off_t off,
2232
                                       int count, int *eof, void *data)
2233
{
2234
        int len = 0;
2235
 
2236
        len += sprintf(page+len, "%lu %lu %lu %lu\n",
2237
                        global.ap.nrecvctlpkt,
2238
                        global.ap.nrecvdatapkt,
2239
                        global.ap.nsentctlpkt,
2240
                        global.ap.nsentdatapkt);
2241
        if (off+count >= len)
2242
           *eof = 1;
2243
        if (len < off)
2244
           return 0;
2245
        *start = page + off;
2246
        return ((count < len-off) ? count : len-off);
2247
}
2248
 
2249
static struct procfsentries {
2250
  char *name;
2251
  mode_t mode;
2252
  int (*read_proc)(char *page, char **start, off_t off,
2253
                                       int count, int *eof, void *data);
2254
  struct proc_dir_entry *procent;
2255
} procfsentries[] = {
2256
   /* { "capi",           S_IFDIR, 0 }, */
2257
   { "capi/capidrv",      0       , proc_capidrv_read_proc },
2258
};
2259
 
2260
static void __init proc_init(void)
2261
{
2262
    int nelem = ARRAY_SIZE(procfsentries);
2263
    int i;
2264
 
2265
    for (i=0; i < nelem; i++) {
2266
        struct procfsentries *p = procfsentries + i;
2267
        p->procent = create_proc_entry(p->name, p->mode, NULL);
2268
        if (p->procent) p->procent->read_proc = p->read_proc;
2269
    }
2270
}
2271
 
2272
static void __exit proc_exit(void)
2273
{
2274
    int nelem = ARRAY_SIZE(procfsentries);
2275
    int i;
2276
 
2277
    for (i=nelem-1; i >= 0; i--) {
2278
        struct procfsentries *p = procfsentries + i;
2279
        if (p->procent) {
2280
           remove_proc_entry(p->name, NULL);
2281
           p->procent = NULL;
2282
        }
2283
    }
2284
}
2285
 
2286
static int __init capidrv_init(void)
2287
{
2288
        capi_profile profile;
2289
        char rev[32];
2290
        char *p;
2291
        u32 ncontr, contr;
2292
        u16 errcode;
2293
 
2294
        if ((p = strchr(revision, ':')) != 0 && p[1]) {
2295
                strncpy(rev, p + 2, sizeof(rev));
2296
                rev[sizeof(rev)-1] = 0;
2297
                if ((p = strchr(rev, '$')) != 0 && p > rev)
2298
                   *(p-1) = 0;
2299
        } else
2300
                strcpy(rev, "1.0");
2301
 
2302
        global.ap.rparam.level3cnt = -2;  /* number of bchannels twice */
2303
        global.ap.rparam.datablkcnt = 16;
2304
        global.ap.rparam.datablklen = 2048;
2305
 
2306
        global.ap.recv_message = capidrv_recv_message;
2307
        errcode = capi20_register(&global.ap);
2308
        if (errcode) {
2309
                return -EIO;
2310
        }
2311
 
2312
        capi20_set_callback(&global.ap, lower_callback);
2313
 
2314
        errcode = capi20_get_profile(0, &profile);
2315
        if (errcode != CAPI_NOERROR) {
2316
                capi20_release(&global.ap);
2317
                return -EIO;
2318
        }
2319
 
2320
        ncontr = profile.ncontroller;
2321
        for (contr = 1; contr <= ncontr; contr++) {
2322
                errcode = capi20_get_profile(contr, &profile);
2323
                if (errcode != CAPI_NOERROR)
2324
                        continue;
2325
                (void) capidrv_addcontr(contr, &profile);
2326
        }
2327
        proc_init();
2328
 
2329
        printk(KERN_NOTICE "capidrv: Rev %s: loaded\n", rev);
2330
        return 0;
2331
}
2332
 
2333
static void __exit capidrv_exit(void)
2334
{
2335
        char rev[10];
2336
        char *p;
2337
 
2338
        if ((p = strchr(revision, ':')) != 0) {
2339
                strcpy(rev, p + 1);
2340
                p = strchr(rev, '$');
2341
                *p = 0;
2342
        } else {
2343
                strcpy(rev, " ??? ");
2344
        }
2345
 
2346
        capi20_release(&global.ap);
2347
 
2348
        proc_exit();
2349
 
2350
        printk(KERN_NOTICE "capidrv: Rev%s: unloaded\n", rev);
2351
}
2352
 
2353
module_init(capidrv_init);
2354
module_exit(capidrv_exit);

powered by: WebSVN 2.1.0

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