* add p cc
[mascara-docs.git] / i386 / linux / linux-2.3.21 / drivers / isdn / avmb1 / capidrv.c
blobfb83e52a6e066e3a1c37152053b5f0eb675b5f93
1 /*
2 * $Id: capidrv.c,v 1.26 1999/08/06 07:41:16 calle Exp $
4 * ISDN4Linux Driver, using capi20 interface (kernelcapi)
6 * Copyright 1997 by Carsten Paeth (calle@calle.in-berlin.de)
8 * $Log: capidrv.c,v $
9 * Revision 1.26 1999/08/06 07:41:16 calle
10 * Added the "vbox patch". if (si1 == 1) si2 = 0;
12 * Revision 1.25 1999/08/04 10:10:11 calle
13 * Bugfix: corrected /proc functions, added structure for new AVM cards.
15 * Revision 1.24 1999/07/20 06:48:02 calle
16 * Bugfix: firmware version check for D2 trace was too restrictiv.
18 * Revision 1.23 1999/07/09 15:05:44 keil
19 * compat.h is now isdn_compat.h
21 * Revision 1.22 1999/07/06 07:24:14 calle
22 * Bugfix: call to kfree_skb in capidrv_signal was too early,
23 * thanks to Lars Heete <hel@admin.de>.
25 * Revision 1.21 1999/07/01 15:26:34 calle
26 * complete new version (I love it):
27 * + new hardware independed "capi_driver" interface that will make it easy to:
28 * - support other controllers with CAPI-2.0 (i.e. USB Controller)
29 * - write a CAPI-2.0 for the passive cards
30 * - support serial link CAPI-2.0 boxes.
31 * + wrote "capi_driver" for all supported cards.
32 * + "capi_driver" (supported cards) now have to be configured with
33 * make menuconfig, in the past all supported cards where included
34 * at once.
35 * + new and better informations in /proc/capi/
36 * + new ioctl to switch trace of capi messages per controller
37 * using "avmcapictrl trace [contr] on|off|...."
38 * + complete testcircle with all supported cards and also the
39 * PCMCIA cards (now patch for pcmcia-cs-3.0.13 needed) done.
41 * Revision 1.20 1999/07/01 08:22:59 keil
42 * compatibility macros now in <linux/isdn_compat.h>
44 * Revision 1.19 1999/06/29 16:16:54 calle
45 * Let ISDN_CMD_UNLOAD work with open isdn devices without crash again.
46 * Also right unlocking (ISDN_CMD_UNLOCK) is done now.
47 * isdnlog should check returncode of read(2) calls.
49 * Revision 1.18 1999/06/21 15:24:15 calle
50 * extend information in /proc.
52 * Revision 1.17 1999/06/10 16:53:55 calle
53 * Removing of module b1pci will now remove card from lower level.
55 * Revision 1.16 1999/05/31 11:50:33 calle
56 * Bugfix: In if_sendbuf, skb_push'ed DATA_B3 header was not skb_pull'ed
57 * on failure, result in data block with DATA_B3 header transmitted
59 * Revision 1.15 1999/05/25 21:26:16 calle
60 * Include CAPI-Channelallocation (leased lines) from the 2.0 tree.
62 * Revision 1.14 1999/05/22 07:55:06 calle
63 * Added *V110* to AVM B1 driver.
65 * Revision 1.13 1998/06/26 15:12:55 fritz
66 * Added handling of STAT_ICALL with incomplete CPN.
67 * Added AT&L for ttyI emulator.
68 * Added more locking stuff in tty_write.
70 * Revision 1.12 1998/03/29 16:06:03 calle
71 * changes from 2.0 tree merged.
73 * Revision 1.3.2.10 1998/03/20 14:38:24 calle
74 * capidrv: prepared state machines for suspend/resume/hold
75 * capidrv: fix bug in state machine if B1/T1 is out of nccis
76 * b1capi: changed some errno returns.
77 * b1capi: detect if you try to add same T1 to different io address.
78 * b1capi: change number of nccis depending on number of channels.
79 * b1lli: cosmetics
81 * Revision 1.3.2.9 1998/03/20 09:01:12 calle
82 * Changes capi_register handling to get full support for 30 bchannels.
84 * Revision 1.3.2.8 1998/03/18 17:51:28 calle
85 * added controller number to error messages
87 * Revision 1.3.2.7 1998/02/27 15:40:47 calle
88 * T1 running with slow link. bugfix in capi_release.
90 * Revision 1.11 1998/02/13 07:09:15 calle
91 * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb()
93 * Revision 1.10 1998/02/02 19:52:23 calle
94 * Fixed vbox (audio) acceptb.
96 * Revision 1.9 1998/01/31 11:14:45 calle
97 * merged changes to 2.0 tree, prepare 2.1.82 to work.
99 * Revision 1.8 1997/11/04 06:12:09 calle
100 * capi.c: new read/write in file_ops since 2.1.60
101 * capidrv.c: prepared isdnlog interface for d2-trace in newer firmware.
102 * capiutil.c: needs config.h (CONFIG_ISDN_DRV_AVMB1_VERBOSE_REASON)
103 * compat.h: added #define LinuxVersionCode
105 * Revision 1.7 1997/10/11 10:36:34 calle
106 * Added isdnlog support. patch to isdnlog needed.
108 * Revision 1.6 1997/10/11 10:25:55 calle
109 * New interface for lowlevel drivers. BSENT with nr. of bytes sent,
110 * allow sending without ACK.
112 * Revision 1.5 1997/10/01 09:21:16 fritz
113 * Removed old compatibility stuff for 2.0.X kernels.
114 * From now on, this code is for 2.1.X ONLY!
115 * Old stuff is still in the separate branch.
117 * Revision 1.4 1997/07/13 12:22:43 calle
118 * bug fix for more than one controller in connect_req.
119 * debugoutput now with contrnr.
121 * Revision 1.3 1997/05/18 09:24:15 calle
122 * added verbose disconnect reason reporting to avmb1.
123 * some fixes in capi20 interface.
124 * changed info messages for B1-PCI
126 * Revision 1.2 1997/03/05 21:19:59 fritz
127 * Removed include of config.h (mkdep stated this is unneded).
129 * Revision 1.1 1997/03/04 21:50:31 calle
130 * Frirst version in isdn4linux
132 * Revision 2.2 1997/02/12 09:31:39 calle
133 * new version
135 * Revision 1.1 1997/01/31 10:32:20 calle
136 * Initial revision
140 #include <linux/module.h>
141 #include <linux/errno.h>
142 #include <linux/kernel.h>
143 #include <linux/major.h>
144 #include <linux/sched.h>
145 #include <linux/malloc.h>
146 #include <linux/fcntl.h>
147 #include <linux/fs.h>
148 #include <linux/signal.h>
149 #include <linux/mm.h>
150 #include <linux/timer.h>
151 #include <linux/wait.h>
152 #include <linux/skbuff.h>
153 #include <linux/isdn.h>
154 #include <linux/isdnif.h>
155 #include <linux/proc_fs.h>
156 #include <linux/capi.h>
157 #include <linux/kernelcapi.h>
158 #include <linux/ctype.h>
159 #include <asm/segment.h>
161 #include <linux/isdn_compat.h>
162 #include "capiutil.h"
163 #include "capicmd.h"
164 #include "capidrv.h"
166 static char *revision = "$Revision: 1.26 $";
167 int debugmode = 0;
169 MODULE_AUTHOR("Carsten Paeth <calle@calle.in-berlin.de>");
170 MODULE_PARM(debugmode, "i");
172 /* -------- type definitions ----------------------------------------- */
175 struct capidrv_contr {
177 struct capidrv_contr *next;
179 __u32 contrnr;
180 char name[20];
183 * for isdn4linux
185 isdn_if interface;
186 int myid;
189 * LISTEN state
191 int state;
192 __u32 cipmask;
193 __u32 cipmask2;
196 * ID of capi message sent
198 __u16 msgid;
201 * B-Channels
203 int nbchan;
204 struct capidrv_bchan {
205 struct capidrv_contr *contr;
206 __u8 msn[ISDN_MSNLEN];
207 int l2;
208 int l3;
209 __u8 num[ISDN_MSNLEN];
210 __u8 mynum[ISDN_MSNLEN];
211 int si1;
212 int si2;
213 int incoming;
214 int disconnecting;
215 struct capidrv_plci {
216 struct capidrv_plci *next;
217 __u32 plci;
218 __u32 ncci; /* ncci for CONNECT_ACTIVE_IND */
219 __u16 msgid; /* to identfy CONNECT_CONF */
220 int chan;
221 int state;
222 int leasedline;
223 struct capidrv_ncci {
224 struct capidrv_ncci *next;
225 struct capidrv_plci *plcip;
226 __u32 ncci;
227 __u16 msgid; /* to identfy CONNECT_B3_CONF */
228 int chan;
229 int state;
230 int oldstate;
231 /* */
232 __u16 datahandle;
233 struct ncci_datahandle_queue {
234 struct ncci_datahandle_queue *next;
235 __u16 datahandle;
236 int len;
237 } *ackqueue;
238 } *ncci_list;
239 } *plcip;
240 struct capidrv_ncci *nccip;
241 } *bchans;
243 struct capidrv_plci *plci_list;
245 /* for q931 data */
246 __u8 q931_buf[4096];
247 __u8 *q931_read;
248 __u8 *q931_write;
249 __u8 *q931_end;
253 struct capidrv_data {
254 __u16 appid;
255 int ncontr;
256 struct capidrv_contr *contr_list;
258 /* statistic */
259 unsigned long nrecvctlpkt;
260 unsigned long nrecvdatapkt;
261 unsigned long nsentctlpkt;
262 unsigned long nsentdatapkt;
265 typedef struct capidrv_plci capidrv_plci;
266 typedef struct capidrv_ncci capidrv_ncci;
267 typedef struct capidrv_contr capidrv_contr;
268 typedef struct capidrv_data capidrv_data;
269 typedef struct capidrv_bchan capidrv_bchan;
271 /* -------- data definitions ----------------------------------------- */
273 static capidrv_data global;
274 static struct capi_interface *capifuncs;
276 static void handle_dtrace_data(capidrv_contr *card,
277 int send, int level2, __u8 *data, __u16 len);
279 /* -------- convert functions ---------------------------------------- */
281 static inline __u32 b1prot(int l2, int l3)
283 switch (l2) {
284 case ISDN_PROTO_L2_X75I:
285 case ISDN_PROTO_L2_X75UI:
286 case ISDN_PROTO_L2_X75BUI:
287 return 0;
288 case ISDN_PROTO_L2_HDLC:
289 default:
290 return 0;
291 case ISDN_PROTO_L2_TRANS:
292 return 1;
293 case ISDN_PROTO_L2_V11096:
294 case ISDN_PROTO_L2_V11019:
295 case ISDN_PROTO_L2_V11038:
296 return 2;
297 case ISDN_PROTO_L2_FAX:
298 return 4;
302 static inline __u32 b2prot(int l2, int l3)
304 switch (l2) {
305 case ISDN_PROTO_L2_X75I:
306 case ISDN_PROTO_L2_X75UI:
307 case ISDN_PROTO_L2_X75BUI:
308 default:
309 return 0;
310 case ISDN_PROTO_L2_HDLC:
311 case ISDN_PROTO_L2_TRANS:
312 case ISDN_PROTO_L2_V11096:
313 case ISDN_PROTO_L2_V11019:
314 case ISDN_PROTO_L2_V11038:
315 return 1;
316 case ISDN_PROTO_L2_FAX:
317 return 4;
321 static inline __u32 b3prot(int l2, int l3)
323 switch (l2) {
324 case ISDN_PROTO_L2_X75I:
325 case ISDN_PROTO_L2_X75UI:
326 case ISDN_PROTO_L2_X75BUI:
327 case ISDN_PROTO_L2_HDLC:
328 case ISDN_PROTO_L2_TRANS:
329 case ISDN_PROTO_L2_V11096:
330 case ISDN_PROTO_L2_V11019:
331 case ISDN_PROTO_L2_V11038:
332 default:
333 return 0;
334 case ISDN_PROTO_L2_FAX:
335 return 4;
339 static _cstruct b1config_sync_v110(__u16 rate)
341 /* CAPI-Spec "B1 Configuration" */
342 static unsigned char buf[9];
343 buf[0] = 8; /* len */
344 /* maximum bitrate */
345 buf[1] = rate & 0xff; buf[2] = (rate >> 8) & 0xff;
346 buf[3] = buf[4] = 0; /* reserved, bits per character */
347 buf[5] = buf[6] = 0; /* reserved, parity */
348 buf[7] = buf[9] = 0; /* reserved, stop bits */
349 return buf;
352 static _cstruct b1config(int l2, int l3)
354 switch (l2) {
355 case ISDN_PROTO_L2_X75I:
356 case ISDN_PROTO_L2_X75UI:
357 case ISDN_PROTO_L2_X75BUI:
358 case ISDN_PROTO_L2_HDLC:
359 case ISDN_PROTO_L2_TRANS:
360 default:
361 return 0;
362 case ISDN_PROTO_L2_V11096:
363 return b1config_sync_v110(9600);
364 case ISDN_PROTO_L2_V11019:
365 return b1config_sync_v110(19200);
366 case ISDN_PROTO_L2_V11038:
367 return b1config_sync_v110(38400);
371 static inline __u16 si2cip(__u8 si1, __u8 si2)
373 static const __u8 cip[17][5] =
375 /* 0 1 2 3 4 */
376 {0, 0, 0, 0, 0}, /*0 */
377 {16, 16, 4, 26, 16}, /*1 */
378 {17, 17, 17, 4, 4}, /*2 */
379 {2, 2, 2, 2, 2}, /*3 */
380 {18, 18, 18, 18, 18}, /*4 */
381 {2, 2, 2, 2, 2}, /*5 */
382 {0, 0, 0, 0, 0}, /*6 */
383 {2, 2, 2, 2, 2}, /*7 */
384 {2, 2, 2, 2, 2}, /*8 */
385 {21, 21, 21, 21, 21}, /*9 */
386 {19, 19, 19, 19, 19}, /*10 */
387 {0, 0, 0, 0, 0}, /*11 */
388 {0, 0, 0, 0, 0}, /*12 */
389 {0, 0, 0, 0, 0}, /*13 */
390 {0, 0, 0, 0, 0}, /*14 */
391 {22, 22, 22, 22, 22}, /*15 */
392 {27, 27, 27, 28, 27} /*16 */
394 if (si1 > 16)
395 si1 = 0;
396 if (si2 > 4)
397 si2 = 0;
399 return (__u16) cip[si1][si2];
402 static inline __u8 cip2si1(__u16 cipval)
404 static const __u8 si[32] =
405 {7, 1, 7, 7, 1, 1, 7, 7, /*0-7 */
406 7, 1, 0, 0, 0, 0, 0, 0, /*8-15 */
407 1, 2, 4, 10, 9, 9, 15, 7, /*16-23 */
408 7, 7, 1, 16, 16, 0, 0, 0}; /*24-31 */
410 if (cipval > 31)
411 cipval = 0; /* .... */
412 return si[cipval];
415 static inline __u8 cip2si2(__u16 cipval)
417 static const __u8 si[32] =
418 {0, 0, 0, 0, 2, 3, 0, 0, /*0-7 */
419 0, 3, 0, 0, 0, 0, 0, 0, /*8-15 */
420 1, 2, 0, 0, 9, 0, 0, 0, /*16-23 */
421 0, 0, 3, 2, 3, 0, 0, 0}; /*24-31 */
423 if (cipval > 31)
424 cipval = 0; /* .... */
425 return si[cipval];
429 /* -------- controller managment ------------------------------------- */
431 static inline capidrv_contr *findcontrbydriverid(int driverid)
433 capidrv_contr *p = global.contr_list;
435 while (p) {
436 if (p->myid == driverid)
437 return p;
438 p = p->next;
440 return (capidrv_contr *) 0;
443 static capidrv_contr *findcontrbynumber(__u32 contr)
445 capidrv_contr *p = global.contr_list;
447 while (p) {
448 if (p->contrnr == contr)
449 return p;
450 p = p->next;
452 return (capidrv_contr *) 0;
456 /* -------- plci management ------------------------------------------ */
458 static capidrv_plci *new_plci(capidrv_contr * card, int chan)
460 capidrv_plci *plcip;
462 plcip = (capidrv_plci *) kmalloc(sizeof(capidrv_plci), GFP_ATOMIC);
464 if (plcip == 0)
465 return 0;
467 memset(plcip, 0, sizeof(capidrv_plci));
468 plcip->state = ST_PLCI_NONE;
469 plcip->plci = 0;
470 plcip->msgid = 0;
471 plcip->chan = chan;
472 plcip->next = card->plci_list;
473 card->plci_list = plcip;
474 card->bchans[chan].plcip = plcip;
476 return plcip;
479 static capidrv_plci *find_plci_by_plci(capidrv_contr * card, __u32 plci)
481 capidrv_plci *p;
482 for (p = card->plci_list; p; p = p->next)
483 if (p->plci == plci)
484 return p;
485 return 0;
488 static capidrv_plci *find_plci_by_msgid(capidrv_contr * card, __u16 msgid)
490 capidrv_plci *p;
491 for (p = card->plci_list; p; p = p->next)
492 if (p->msgid == msgid)
493 return p;
494 return 0;
497 static capidrv_plci *find_plci_by_ncci(capidrv_contr * card, __u32 ncci)
499 capidrv_plci *p;
500 for (p = card->plci_list; p; p = p->next)
501 if (p->plci == (ncci & 0xffff))
502 return p;
503 return 0;
506 static void free_plci(capidrv_contr * card, capidrv_plci * plcip)
508 capidrv_plci **pp;
510 for (pp = &card->plci_list; *pp; pp = &(*pp)->next) {
511 if (*pp == plcip) {
512 *pp = (*pp)->next;
513 card->bchans[plcip->chan].plcip = 0;
514 card->bchans[plcip->chan].disconnecting = 0;
515 card->bchans[plcip->chan].incoming = 0;
516 kfree(plcip);
517 return;
520 printk(KERN_ERR "capidrv-%d: free_plci %p (0x%x) not found, Huh?\n",
521 card->contrnr, plcip, plcip->plci);
524 /* -------- ncci management ------------------------------------------ */
526 static inline capidrv_ncci *new_ncci(capidrv_contr * card,
527 capidrv_plci * plcip,
528 __u32 ncci)
530 capidrv_ncci *nccip;
532 nccip = (capidrv_ncci *) kmalloc(sizeof(capidrv_ncci), GFP_ATOMIC);
534 if (nccip == 0)
535 return 0;
537 memset(nccip, 0, sizeof(capidrv_ncci));
538 nccip->ncci = ncci;
539 nccip->state = ST_NCCI_NONE;
540 nccip->plcip = plcip;
541 nccip->chan = plcip->chan;
542 nccip->datahandle = 0;
544 nccip->next = plcip->ncci_list;
545 plcip->ncci_list = nccip;
547 card->bchans[plcip->chan].nccip = nccip;
549 return nccip;
552 static inline capidrv_ncci *find_ncci(capidrv_contr * card, __u32 ncci)
554 capidrv_plci *plcip;
555 capidrv_ncci *p;
557 if ((plcip = find_plci_by_ncci(card, ncci)) == 0)
558 return 0;
560 for (p = plcip->ncci_list; p; p = p->next)
561 if (p->ncci == ncci)
562 return p;
563 return 0;
566 static inline capidrv_ncci *find_ncci_by_msgid(capidrv_contr * card,
567 __u32 ncci, __u16 msgid)
569 capidrv_plci *plcip;
570 capidrv_ncci *p;
572 if ((plcip = find_plci_by_ncci(card, ncci)) == 0)
573 return 0;
575 for (p = plcip->ncci_list; p; p = p->next)
576 if (p->msgid == msgid)
577 return p;
578 return 0;
581 static void free_ncci(capidrv_contr * card, struct capidrv_ncci *nccip)
583 struct capidrv_ncci **pp;
585 for (pp = &(nccip->plcip->ncci_list); *pp; pp = &(*pp)->next) {
586 if (*pp == nccip) {
587 *pp = (*pp)->next;
588 break;
591 card->bchans[nccip->chan].nccip = 0;
592 kfree(nccip);
595 static int capidrv_add_ack(struct capidrv_ncci *nccip,
596 __u16 datahandle, int len)
598 struct ncci_datahandle_queue *n, **pp;
600 n = (struct ncci_datahandle_queue *)
601 kmalloc(sizeof(struct ncci_datahandle_queue), GFP_ATOMIC);
602 if (!n) {
603 printk(KERN_ERR "capidrv: kmalloc ncci_datahandle failed\n");
604 return -1;
606 n->next = 0;
607 n->datahandle = datahandle;
608 n->len = len;
609 for (pp = &nccip->ackqueue; *pp; pp = &(*pp)->next) ;
610 *pp = n;
611 return 0;
614 static int capidrv_del_ack(struct capidrv_ncci *nccip, __u16 datahandle)
616 struct ncci_datahandle_queue **pp, *p;
617 int len;
619 for (pp = &nccip->ackqueue; *pp; pp = &(*pp)->next) {
620 if ((*pp)->datahandle == datahandle) {
621 p = *pp;
622 len = p->len;
623 *pp = (*pp)->next;
624 kfree(p);
625 return len;
628 return -1;
631 /* -------- convert and send capi message ---------------------------- */
633 static void send_message(capidrv_contr * card, _cmsg * cmsg)
635 struct sk_buff *skb;
636 size_t len;
637 capi_cmsg2message(cmsg, cmsg->buf);
638 len = CAPIMSG_LEN(cmsg->buf);
639 skb = alloc_skb(len, GFP_ATOMIC);
640 memcpy(skb_put(skb, len), cmsg->buf, len);
641 (*capifuncs->capi_put_message) (global.appid, skb);
642 global.nsentctlpkt++;
645 /* -------- state machine -------------------------------------------- */
647 struct listenstatechange {
648 int actstate;
649 int nextstate;
650 int event;
653 static struct listenstatechange listentable[] =
655 {ST_LISTEN_NONE, ST_LISTEN_WAIT_CONF, EV_LISTEN_REQ},
656 {ST_LISTEN_ACTIVE, ST_LISTEN_ACTIVE_WAIT_CONF, EV_LISTEN_REQ},
657 {ST_LISTEN_WAIT_CONF, ST_LISTEN_NONE, EV_LISTEN_CONF_ERROR},
658 {ST_LISTEN_ACTIVE_WAIT_CONF, ST_LISTEN_ACTIVE, EV_LISTEN_CONF_ERROR},
659 {ST_LISTEN_WAIT_CONF, ST_LISTEN_NONE, EV_LISTEN_CONF_EMPTY},
660 {ST_LISTEN_ACTIVE_WAIT_CONF, ST_LISTEN_NONE, EV_LISTEN_CONF_EMPTY},
661 {ST_LISTEN_WAIT_CONF, ST_LISTEN_ACTIVE, EV_LISTEN_CONF_OK},
662 {ST_LISTEN_ACTIVE_WAIT_CONF, ST_LISTEN_ACTIVE, EV_LISTEN_CONF_OK},
666 static void listen_change_state(capidrv_contr * card, int event)
668 struct listenstatechange *p = listentable;
669 while (p->event) {
670 if (card->state == p->actstate && p->event == event) {
671 if (debugmode)
672 printk(KERN_DEBUG "capidrv-%d: listen_change_state %d -> %d\n",
673 card->contrnr, card->state, p->nextstate);
674 card->state = p->nextstate;
675 return;
677 p++;
679 printk(KERN_ERR "capidrv-%d: listen_change_state state=%d event=%d ????\n",
680 card->contrnr, card->state, event);
684 /* ------------------------------------------------------------------ */
686 static void p0(capidrv_contr * card, capidrv_plci * plci)
688 isdn_ctrl cmd;
690 card->bchans[plci->chan].contr = 0;
691 cmd.command = ISDN_STAT_DHUP;
692 cmd.driver = card->myid;
693 cmd.arg = plci->chan;
694 card->interface.statcallb(&cmd);
695 free_plci(card, plci);
698 /* ------------------------------------------------------------------ */
700 struct plcistatechange {
701 int actstate;
702 int nextstate;
703 int event;
704 void (*changefunc) (capidrv_contr * card, capidrv_plci * plci);
707 static struct plcistatechange plcitable[] =
709 /* P-0 */
710 {ST_PLCI_NONE, ST_PLCI_OUTGOING, EV_PLCI_CONNECT_REQ, 0},
711 {ST_PLCI_NONE, ST_PLCI_ALLOCATED, EV_PLCI_FACILITY_IND_UP, 0},
712 {ST_PLCI_NONE, ST_PLCI_INCOMING, EV_PLCI_CONNECT_IND, 0},
713 {ST_PLCI_NONE, ST_PLCI_RESUMEING, EV_PLCI_RESUME_REQ, 0},
714 /* P-0.1 */
715 {ST_PLCI_OUTGOING, ST_PLCI_NONE, EV_PLCI_CONNECT_CONF_ERROR, p0},
716 {ST_PLCI_OUTGOING, ST_PLCI_ALLOCATED, EV_PLCI_CONNECT_CONF_OK, 0},
717 {ST_PLCI_OUTGOING, ST_PLCI_DISCONNECTING, EV_PLCI_DISCONNECT_REQ, 0},
718 {ST_PLCI_OUTGOING, ST_PLCI_DISCONNECTING, EV_PLCI_FACILITY_IND_DOWN, 0},
719 /* P-1 */
720 {ST_PLCI_ALLOCATED, ST_PLCI_ACTIVE, EV_PLCI_CONNECT_ACTIVE_IND, 0},
721 {ST_PLCI_ALLOCATED, ST_PLCI_DISCONNECTING, EV_PLCI_DISCONNECT_REQ, 0},
722 {ST_PLCI_ALLOCATED, ST_PLCI_DISCONNECTING, EV_PLCI_FACILITY_IND_DOWN, 0},
723 {ST_PLCI_ALLOCATED, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, 0},
724 /* P-ACT */
725 {ST_PLCI_ACTIVE, ST_PLCI_DISCONNECTING, EV_PLCI_DISCONNECT_REQ, 0},
726 {ST_PLCI_ACTIVE, ST_PLCI_DISCONNECTING, EV_PLCI_FACILITY_IND_DOWN, 0},
727 {ST_PLCI_ACTIVE, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, 0},
728 {ST_PLCI_ACTIVE, ST_PLCI_HELD, EV_PLCI_HOLD_IND, 0},
729 {ST_PLCI_ACTIVE, ST_PLCI_DISCONNECTING, EV_PLCI_SUSPEND_IND, 0},
730 /* P-2 */
731 {ST_PLCI_INCOMING, ST_PLCI_DISCONNECTING, EV_PLCI_CONNECT_REJECT, 0},
732 {ST_PLCI_INCOMING, ST_PLCI_FACILITY_IND, EV_PLCI_FACILITY_IND_UP, 0},
733 {ST_PLCI_INCOMING, ST_PLCI_ACCEPTING, EV_PLCI_CONNECT_RESP, 0},
734 {ST_PLCI_INCOMING, ST_PLCI_DISCONNECTING, EV_PLCI_DISCONNECT_REQ, 0},
735 {ST_PLCI_INCOMING, ST_PLCI_DISCONNECTING, EV_PLCI_FACILITY_IND_DOWN, 0},
736 {ST_PLCI_INCOMING, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, 0},
737 {ST_PLCI_INCOMING, ST_PLCI_DISCONNECTING, EV_PLCI_CD_IND, 0},
738 /* P-3 */
739 {ST_PLCI_FACILITY_IND, ST_PLCI_DISCONNECTING, EV_PLCI_CONNECT_REJECT, 0},
740 {ST_PLCI_FACILITY_IND, ST_PLCI_ACCEPTING, EV_PLCI_CONNECT_ACTIVE_IND, 0},
741 {ST_PLCI_FACILITY_IND, ST_PLCI_DISCONNECTING, EV_PLCI_DISCONNECT_REQ, 0},
742 {ST_PLCI_FACILITY_IND, ST_PLCI_DISCONNECTING, EV_PLCI_FACILITY_IND_DOWN, 0},
743 {ST_PLCI_FACILITY_IND, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, 0},
744 /* P-4 */
745 {ST_PLCI_ACCEPTING, ST_PLCI_ACTIVE, EV_PLCI_CONNECT_ACTIVE_IND, 0},
746 {ST_PLCI_ACCEPTING, ST_PLCI_DISCONNECTING, EV_PLCI_DISCONNECT_REQ, 0},
747 {ST_PLCI_ACCEPTING, ST_PLCI_DISCONNECTING, EV_PLCI_FACILITY_IND_DOWN, 0},
748 {ST_PLCI_ACCEPTING, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, 0},
749 /* P-5 */
750 {ST_PLCI_DISCONNECTING, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, 0},
751 /* P-6 */
752 {ST_PLCI_DISCONNECTED, ST_PLCI_NONE, EV_PLCI_DISCONNECT_RESP, p0},
753 /* P-0.Res */
754 {ST_PLCI_RESUMEING, ST_PLCI_NONE, EV_PLCI_RESUME_CONF_ERROR, p0},
755 {ST_PLCI_RESUMEING, ST_PLCI_RESUME, EV_PLCI_RESUME_CONF_OK, 0},
756 /* P-RES */
757 {ST_PLCI_RESUME, ST_PLCI_ACTIVE, EV_PLCI_RESUME_IND, 0},
758 /* P-HELD */
759 {ST_PLCI_HELD, ST_PLCI_ACTIVE, EV_PLCI_RETRIEVE_IND, 0},
763 static void plci_change_state(capidrv_contr * card, capidrv_plci * plci, int event)
765 struct plcistatechange *p = plcitable;
766 while (p->event) {
767 if (plci->state == p->actstate && p->event == event) {
768 if (debugmode)
769 printk(KERN_DEBUG "capidrv-%d: plci_change_state:0x%x %d -> %d\n",
770 card->contrnr, plci->plci, plci->state, p->nextstate);
771 plci->state = p->nextstate;
772 if (p->changefunc)
773 p->changefunc(card, plci);
774 return;
776 p++;
778 printk(KERN_ERR "capidrv-%d: plci_change_state:0x%x state=%d event=%d ????\n",
779 card->contrnr, plci->plci, plci->state, event);
782 /* ------------------------------------------------------------------ */
784 static _cmsg cmsg;
786 static void n0(capidrv_contr * card, capidrv_ncci * ncci)
788 isdn_ctrl cmd;
790 capi_fill_DISCONNECT_REQ(&cmsg,
791 global.appid,
792 card->msgid++,
793 ncci->plcip->plci,
794 0, /* BChannelinformation */
795 0, /* Keypadfacility */
796 0, /* Useruserdata */ /* $$$$ */
797 0 /* Facilitydataarray */
799 send_message(card, &cmsg);
800 plci_change_state(card, ncci->plcip, EV_PLCI_DISCONNECT_REQ);
802 cmd.command = ISDN_STAT_BHUP;
803 cmd.driver = card->myid;
804 cmd.arg = ncci->chan;
805 card->interface.statcallb(&cmd);
806 free_ncci(card, ncci);
809 /* ------------------------------------------------------------------ */
811 struct nccistatechange {
812 int actstate;
813 int nextstate;
814 int event;
815 void (*changefunc) (capidrv_contr * card, capidrv_ncci * ncci);
818 static struct nccistatechange nccitable[] =
820 /* N-0 */
821 {ST_NCCI_NONE, ST_NCCI_OUTGOING, EV_NCCI_CONNECT_B3_REQ, 0},
822 {ST_NCCI_NONE, ST_NCCI_INCOMING, EV_NCCI_CONNECT_B3_IND, 0},
823 /* N-0.1 */
824 {ST_NCCI_OUTGOING, ST_NCCI_ALLOCATED, EV_NCCI_CONNECT_B3_CONF_OK, 0},
825 {ST_NCCI_OUTGOING, ST_NCCI_NONE, EV_NCCI_CONNECT_B3_CONF_ERROR, n0},
826 /* N-1 */
827 {ST_NCCI_INCOMING, ST_NCCI_DISCONNECTING, EV_NCCI_CONNECT_B3_REJECT, 0},
828 {ST_NCCI_INCOMING, ST_NCCI_ALLOCATED, EV_NCCI_CONNECT_B3_RESP, 0},
829 {ST_NCCI_INCOMING, ST_NCCI_DISCONNECTED, EV_NCCI_DISCONNECT_B3_IND, 0},
830 {ST_NCCI_INCOMING, ST_NCCI_DISCONNECTING, EV_NCCI_DISCONNECT_B3_REQ, 0},
831 /* N-2 */
832 {ST_NCCI_ALLOCATED, ST_NCCI_ACTIVE, EV_NCCI_CONNECT_B3_ACTIVE_IND, 0},
833 {ST_NCCI_ALLOCATED, ST_NCCI_DISCONNECTED, EV_NCCI_DISCONNECT_B3_IND, 0},
834 {ST_NCCI_ALLOCATED, ST_NCCI_DISCONNECTING, EV_NCCI_DISCONNECT_B3_REQ, 0},
835 /* N-ACT */
836 {ST_NCCI_ACTIVE, ST_NCCI_ACTIVE, EV_NCCI_RESET_B3_IND, 0},
837 {ST_NCCI_ACTIVE, ST_NCCI_RESETING, EV_NCCI_RESET_B3_REQ, 0},
838 {ST_NCCI_ACTIVE, ST_NCCI_DISCONNECTED, EV_NCCI_DISCONNECT_B3_IND, 0},
839 {ST_NCCI_ACTIVE, ST_NCCI_DISCONNECTING, EV_NCCI_DISCONNECT_B3_REQ, 0},
840 /* N-3 */
841 {ST_NCCI_RESETING, ST_NCCI_ACTIVE, EV_NCCI_RESET_B3_IND, 0},
842 {ST_NCCI_RESETING, ST_NCCI_DISCONNECTED, EV_NCCI_DISCONNECT_B3_IND, 0},
843 {ST_NCCI_RESETING, ST_NCCI_DISCONNECTING, EV_NCCI_DISCONNECT_B3_REQ, 0},
844 /* N-4 */
845 {ST_NCCI_DISCONNECTING, ST_NCCI_DISCONNECTED, EV_NCCI_DISCONNECT_B3_IND, 0},
846 {ST_NCCI_DISCONNECTING, ST_NCCI_PREVIOUS, EV_NCCI_DISCONNECT_B3_CONF_ERROR,0},
847 /* N-5 */
848 {ST_NCCI_DISCONNECTED, ST_NCCI_NONE, EV_NCCI_DISCONNECT_B3_RESP, n0},
852 static void ncci_change_state(capidrv_contr * card, capidrv_ncci * ncci, int event)
854 struct nccistatechange *p = nccitable;
855 while (p->event) {
856 if (ncci->state == p->actstate && p->event == event) {
857 if (debugmode)
858 printk(KERN_DEBUG "capidrv-%d: ncci_change_state:0x%x %d -> %d\n",
859 card->contrnr, ncci->ncci, ncci->state, p->nextstate);
860 if (p->nextstate == ST_NCCI_PREVIOUS) {
861 ncci->state = ncci->oldstate;
862 ncci->oldstate = p->actstate;
863 } else {
864 ncci->oldstate = p->actstate;
865 ncci->state = p->nextstate;
867 if (p->changefunc)
868 p->changefunc(card, ncci);
869 return;
871 p++;
873 printk(KERN_ERR "capidrv-%d: ncci_change_state:0x%x state=%d event=%d ????\n",
874 card->contrnr, ncci->ncci, ncci->state, event);
877 /* ------------------------------------------------------------------- */
879 static inline int new_bchan(capidrv_contr * card)
881 int i;
882 for (i = 0; i < card->nbchan; i++) {
883 if (card->bchans[i].plcip == 0) {
884 card->bchans[i].disconnecting = 0;
885 return i;
888 return -1;
891 /* ------------------------------------------------------------------- */
893 static void handle_controller(_cmsg * cmsg)
895 capidrv_contr *card = findcontrbynumber(cmsg->adr.adrController & 0x7f);
897 if (!card) {
898 printk(KERN_ERR "capidrv: %s from unknown controller 0x%x\n",
899 capi_cmd2str(cmsg->Command, cmsg->Subcommand),
900 cmsg->adr.adrController & 0x7f);
901 return;
903 switch (CAPICMD(cmsg->Command, cmsg->Subcommand)) {
905 case CAPI_LISTEN_CONF: /* Controller */
906 if (debugmode)
907 printk(KERN_DEBUG "capidrv-%d: listenconf Info=0x%4x (%s) cipmask=0x%x\n",
908 card->contrnr, cmsg->Info, capi_info2str(cmsg->Info), card->cipmask);
909 if (cmsg->Info) {
910 listen_change_state(card, EV_LISTEN_CONF_ERROR);
911 } else if (card->cipmask == 0) {
912 listen_change_state(card, EV_LISTEN_CONF_EMPTY);
913 } else {
914 listen_change_state(card, EV_LISTEN_CONF_OK);
916 break;
918 case CAPI_MANUFACTURER_IND: /* Controller */
919 if ( cmsg->ManuID == 0x214D5641
920 && cmsg->Class == 0
921 && cmsg->Function == 1) {
922 __u8 *data = cmsg->ManuData+3;
923 __u16 len = cmsg->ManuData[0];
924 __u16 layer;
925 int direction;
926 if (len == 255) {
927 len = (cmsg->ManuData[1] | (cmsg->ManuData[2] << 8));
928 data += 2;
930 len -= 2;
931 layer = ((*(data-1)) << 8) | *(data-2);
932 if (layer & 0x300)
933 direction = (layer & 0x200) ? 0 : 1;
934 else direction = (layer & 0x800) ? 0 : 1;
935 if (layer & 0x0C00) {
936 if ((layer & 0xff) == 0x80) {
937 handle_dtrace_data(card, direction, 1, data, len);
938 break;
940 } else if ((layer & 0xff) < 0x80) {
941 handle_dtrace_data(card, direction, 0, data, len);
942 break;
944 printk(KERN_INFO "capidrv-%d: %s from controller 0x%x layer 0x%x, ignored\n",
945 card->contrnr,
946 capi_cmd2str(cmsg->Command, cmsg->Subcommand),
947 cmsg->adr.adrController, layer);
948 break;
950 goto ignored;
951 case CAPI_MANUFACTURER_CONF: /* Controller */
952 if (cmsg->ManuID == 0x214D5641) {
953 char *s = 0;
954 switch (cmsg->Class) {
955 case 0: break;
956 case 1: s = "unknown class"; break;
957 case 2: s = "unknown function"; break;
958 default: s = "unkown error"; break;
960 if (s)
961 printk(KERN_INFO "capidrv-%d: %s from controller 0x%x function %d: %s\n",
962 card->contrnr,
963 capi_cmd2str(cmsg->Command, cmsg->Subcommand),
964 cmsg->adr.adrController,
965 cmsg->Function, s);
966 break;
968 goto ignored;
969 case CAPI_FACILITY_IND: /* Controller/plci/ncci */
970 goto ignored;
971 case CAPI_FACILITY_CONF: /* Controller/plci/ncci */
972 goto ignored;
973 case CAPI_INFO_IND: /* Controller/plci */
974 goto ignored;
975 case CAPI_INFO_CONF: /* Controller/plci */
976 goto ignored;
978 default:
979 printk(KERN_ERR "capidrv-%d: got %s from controller 0x%x ???",
980 card->contrnr,
981 capi_cmd2str(cmsg->Command, cmsg->Subcommand),
982 cmsg->adr.adrController);
984 return;
986 ignored:
987 printk(KERN_INFO "capidrv-%d: %s from controller 0x%x ignored\n",
988 card->contrnr,
989 capi_cmd2str(cmsg->Command, cmsg->Subcommand),
990 cmsg->adr.adrController);
993 static void handle_incoming_call(capidrv_contr * card, _cmsg * cmsg)
995 capidrv_plci *plcip;
996 capidrv_bchan *bchan;
997 isdn_ctrl cmd;
998 int chan;
1000 if ((chan = new_bchan(card)) == -1) {
1001 printk(KERN_ERR "capidrv-%d: incoming call on not existing bchan ?\n", card->contrnr);
1002 return;
1004 bchan = &card->bchans[chan];
1005 if ((plcip = new_plci(card, chan)) == 0) {
1006 printk(KERN_ERR "capidrv-%d: incoming call: no memory, sorry.\n", card->contrnr);
1007 return;
1009 bchan->incoming = 1;
1010 plcip->plci = cmsg->adr.adrPLCI;
1011 plci_change_state(card, plcip, EV_PLCI_CONNECT_IND);
1013 cmd.command = ISDN_STAT_ICALL;
1014 cmd.driver = card->myid;
1015 cmd.arg = chan;
1016 memset(&cmd.parm.setup, 0, sizeof(cmd.parm.setup));
1017 strncpy(cmd.parm.setup.phone,
1018 cmsg->CallingPartyNumber + 3,
1019 cmsg->CallingPartyNumber[0] - 2);
1020 strncpy(cmd.parm.setup.eazmsn,
1021 cmsg->CalledPartyNumber + 2,
1022 cmsg->CalledPartyNumber[0] - 1);
1023 cmd.parm.setup.si1 = cip2si1(cmsg->CIPValue);
1024 cmd.parm.setup.si2 = cip2si2(cmsg->CIPValue);
1025 cmd.parm.setup.plan = cmsg->CallingPartyNumber[1];
1026 cmd.parm.setup.screen = cmsg->CallingPartyNumber[2];
1028 printk(KERN_INFO "capidrv-%d: incoming call %s,%d,%d,%s\n",
1029 card->contrnr,
1030 cmd.parm.setup.phone,
1031 cmd.parm.setup.si1,
1032 cmd.parm.setup.si2,
1033 cmd.parm.setup.eazmsn);
1035 if (cmd.parm.setup.si1 == 1 && cmd.parm.setup.si2 != 0) {
1036 printk(KERN_INFO "capidrv-%d: patching si2=%d to 0 for VBOX\n",
1037 card->contrnr,
1038 cmd.parm.setup.si2);
1039 cmd.parm.setup.si2 = 0;
1042 switch (card->interface.statcallb(&cmd)) {
1043 case 0:
1044 case 3:
1045 /* No device matching this call.
1046 * and isdn_common.c has send a HANGUP command
1047 * which is ignored in state ST_PLCI_INCOMING,
1048 * so we send RESP to ignore the call
1050 capi_cmsg_answer(cmsg);
1051 cmsg->Reject = 1; /* ignore */
1052 send_message(card, cmsg);
1053 plci_change_state(card, plcip, EV_PLCI_CONNECT_REJECT);
1054 printk(KERN_INFO "capidrv-%d: incoming call %s,%d,%d,%s ignored\n",
1055 card->contrnr,
1056 cmd.parm.setup.phone,
1057 cmd.parm.setup.si1,
1058 cmd.parm.setup.si2,
1059 cmd.parm.setup.eazmsn);
1060 break;
1061 case 1:
1062 /* At least one device matching this call (RING on ttyI)
1063 * HL-driver may send ALERTING on the D-channel in this
1064 * case.
1065 * really means: RING on ttyI or a net interface
1066 * accepted this call already.
1068 * If the call was accepted, state has already changed,
1069 * and CONNECT_RESP already sent.
1071 if (plcip->state == ST_PLCI_INCOMING) {
1072 printk(KERN_INFO "capidrv-%d: incoming call %s,%d,%d,%s tty alerting\n",
1073 card->contrnr,
1074 cmd.parm.setup.phone,
1075 cmd.parm.setup.si1,
1076 cmd.parm.setup.si2,
1077 cmd.parm.setup.eazmsn);
1078 capi_fill_ALERT_REQ(cmsg,
1079 global.appid,
1080 card->msgid++,
1081 plcip->plci, /* adr */
1082 0, /* BChannelinformation */
1083 0, /* Keypadfacility */
1084 0, /* Useruserdata */
1085 0 /* Facilitydataarray */
1087 plcip->msgid = cmsg->Messagenumber;
1088 send_message(card, cmsg);
1089 } else {
1090 printk(KERN_INFO "capidrv-%d: incoming call %s,%d,%d,%s on netdev\n",
1091 card->contrnr,
1092 cmd.parm.setup.phone,
1093 cmd.parm.setup.si1,
1094 cmd.parm.setup.si2,
1095 cmd.parm.setup.eazmsn);
1097 break;
1099 case 2: /* Call will be rejected. */
1100 capi_cmsg_answer(cmsg);
1101 cmsg->Reject = 2; /* reject call, normal call clearing */
1102 send_message(card, cmsg);
1103 plci_change_state(card, plcip, EV_PLCI_CONNECT_REJECT);
1104 break;
1106 default:
1107 /* An error happened. (Invalid parameters for example.) */
1108 capi_cmsg_answer(cmsg);
1109 cmsg->Reject = 8; /* reject call,
1110 destination out of order */
1111 send_message(card, cmsg);
1112 plci_change_state(card, plcip, EV_PLCI_CONNECT_REJECT);
1113 break;
1115 return;
1118 static void handle_plci(_cmsg * cmsg)
1120 capidrv_contr *card = findcontrbynumber(cmsg->adr.adrController & 0x7f);
1121 capidrv_plci *plcip;
1122 isdn_ctrl cmd;
1124 if (!card) {
1125 printk(KERN_ERR "capidrv: %s from unknown controller 0x%x\n",
1126 capi_cmd2str(cmsg->Command, cmsg->Subcommand),
1127 cmsg->adr.adrController & 0x7f);
1128 return;
1130 switch (CAPICMD(cmsg->Command, cmsg->Subcommand)) {
1132 case CAPI_DISCONNECT_IND: /* plci */
1133 if (cmsg->Reason) {
1134 printk(KERN_INFO "capidrv-%d: %s reason 0x%x (%s) for plci 0x%x\n",
1135 card->contrnr,
1136 capi_cmd2str(cmsg->Command, cmsg->Subcommand),
1137 cmsg->Reason, capi_info2str(cmsg->Reason), cmsg->adr.adrPLCI);
1139 if (!(plcip = find_plci_by_plci(card, cmsg->adr.adrPLCI))) {
1140 capi_cmsg_answer(cmsg);
1141 send_message(card, cmsg);
1142 goto notfound;
1144 card->bchans[plcip->chan].disconnecting = 1;
1145 plci_change_state(card, plcip, EV_PLCI_DISCONNECT_IND);
1146 capi_cmsg_answer(cmsg);
1147 send_message(card, cmsg);
1148 plci_change_state(card, plcip, EV_PLCI_DISCONNECT_RESP);
1149 break;
1151 case CAPI_DISCONNECT_CONF: /* plci */
1152 if (cmsg->Info) {
1153 printk(KERN_INFO "capidrv-%d: %s info 0x%x (%s) for plci 0x%x\n",
1154 card->contrnr,
1155 capi_cmd2str(cmsg->Command, cmsg->Subcommand),
1156 cmsg->Info, capi_info2str(cmsg->Info),
1157 cmsg->adr.adrPLCI);
1159 if (!(plcip = find_plci_by_plci(card, cmsg->adr.adrPLCI)))
1160 goto notfound;
1162 card->bchans[plcip->chan].disconnecting = 1;
1163 break;
1165 case CAPI_ALERT_CONF: /* plci */
1166 if (cmsg->Info) {
1167 printk(KERN_INFO "capidrv-%d: %s info 0x%x (%s) for plci 0x%x\n",
1168 card->contrnr,
1169 capi_cmd2str(cmsg->Command, cmsg->Subcommand),
1170 cmsg->Info, capi_info2str(cmsg->Info),
1171 cmsg->adr.adrPLCI);
1173 break;
1175 case CAPI_CONNECT_IND: /* plci */
1176 handle_incoming_call(card, cmsg);
1177 break;
1179 case CAPI_CONNECT_CONF: /* plci */
1180 if (cmsg->Info) {
1181 printk(KERN_INFO "capidrv-%d: %s info 0x%x (%s) for plci 0x%x\n",
1182 card->contrnr,
1183 capi_cmd2str(cmsg->Command, cmsg->Subcommand),
1184 cmsg->Info, capi_info2str(cmsg->Info),
1185 cmsg->adr.adrPLCI);
1187 if (!(plcip = find_plci_by_msgid(card, cmsg->Messagenumber)))
1188 goto notfound;
1190 plcip->plci = cmsg->adr.adrPLCI;
1191 if (cmsg->Info) {
1192 plci_change_state(card, plcip, EV_PLCI_CONNECT_CONF_ERROR);
1193 } else {
1194 plci_change_state(card, plcip, EV_PLCI_CONNECT_CONF_OK);
1196 break;
1198 case CAPI_CONNECT_ACTIVE_IND: /* plci */
1200 if (!(plcip = find_plci_by_plci(card, cmsg->adr.adrPLCI)))
1201 goto notfound;
1203 if (card->bchans[plcip->chan].incoming) {
1204 capi_cmsg_answer(cmsg);
1205 send_message(card, cmsg);
1206 plci_change_state(card, plcip, EV_PLCI_CONNECT_ACTIVE_IND);
1207 } else {
1208 capidrv_ncci *nccip;
1209 capi_cmsg_answer(cmsg);
1210 send_message(card, cmsg);
1212 nccip = new_ncci(card, plcip, cmsg->adr.adrPLCI);
1214 if (!nccip) {
1215 printk(KERN_ERR "capidrv-%d: no mem for ncci, sorry\n", card->contrnr);
1216 break; /* $$$$ */
1218 capi_fill_CONNECT_B3_REQ(cmsg,
1219 global.appid,
1220 card->msgid++,
1221 plcip->plci, /* adr */
1222 0 /* NCPI */
1224 nccip->msgid = cmsg->Messagenumber;
1225 send_message(card, cmsg);
1226 cmd.command = ISDN_STAT_DCONN;
1227 cmd.driver = card->myid;
1228 cmd.arg = plcip->chan;
1229 card->interface.statcallb(&cmd);
1230 plci_change_state(card, plcip, EV_PLCI_CONNECT_ACTIVE_IND);
1231 ncci_change_state(card, nccip, EV_NCCI_CONNECT_B3_REQ);
1233 break;
1235 case CAPI_INFO_IND: /* Controller/plci */
1237 if (!(plcip = find_plci_by_plci(card, cmsg->adr.adrPLCI)))
1238 goto notfound;
1240 if (cmsg->InfoNumber == 0x4000) {
1241 if (cmsg->InfoElement[0] == 4) {
1242 cmd.command = ISDN_STAT_CINF;
1243 cmd.driver = card->myid;
1244 cmd.arg = plcip->chan;
1245 sprintf(cmd.parm.num, "%lu",
1246 (unsigned long)
1247 ((__u32) cmsg->InfoElement[1]
1248 | ((__u32) (cmsg->InfoElement[2]) << 8)
1249 | ((__u32) (cmsg->InfoElement[3]) << 16)
1250 | ((__u32) (cmsg->InfoElement[4]) << 24)));
1251 card->interface.statcallb(&cmd);
1252 break;
1255 printk(KERN_ERR "capidrv-%d: %s\n",
1256 card->contrnr, capi_cmsg2str(cmsg));
1257 break;
1259 case CAPI_CONNECT_ACTIVE_CONF: /* plci */
1260 goto ignored;
1261 case CAPI_SELECT_B_PROTOCOL_CONF: /* plci */
1262 goto ignored;
1263 case CAPI_FACILITY_IND: /* Controller/plci/ncci */
1264 goto ignored;
1265 case CAPI_FACILITY_CONF: /* Controller/plci/ncci */
1266 goto ignored;
1268 case CAPI_INFO_CONF: /* Controller/plci */
1269 goto ignored;
1271 default:
1272 printk(KERN_ERR "capidrv-%d: got %s for plci 0x%x ???",
1273 card->contrnr,
1274 capi_cmd2str(cmsg->Command, cmsg->Subcommand),
1275 cmsg->adr.adrPLCI);
1277 return;
1278 ignored:
1279 printk(KERN_INFO "capidrv-%d: %s for plci 0x%x ignored\n",
1280 card->contrnr,
1281 capi_cmd2str(cmsg->Command, cmsg->Subcommand),
1282 cmsg->adr.adrPLCI);
1283 return;
1284 notfound:
1285 printk(KERN_ERR "capidrv-%d: %s: plci 0x%x not found\n",
1286 card->contrnr,
1287 capi_cmd2str(cmsg->Command, cmsg->Subcommand),
1288 cmsg->adr.adrPLCI);
1289 return;
1292 static void handle_ncci(_cmsg * cmsg)
1294 capidrv_contr *card = findcontrbynumber(cmsg->adr.adrController & 0x7f);
1295 capidrv_plci *plcip;
1296 capidrv_ncci *nccip;
1297 isdn_ctrl cmd;
1298 int len;
1300 if (!card) {
1301 printk(KERN_ERR "capidrv: %s from unknown controller 0x%x\n",
1302 capi_cmd2str(cmsg->Command, cmsg->Subcommand),
1303 cmsg->adr.adrController & 0x7f);
1304 return;
1306 switch (CAPICMD(cmsg->Command, cmsg->Subcommand)) {
1308 case CAPI_CONNECT_B3_ACTIVE_IND: /* ncci */
1309 if (!(nccip = find_ncci(card, cmsg->adr.adrNCCI)))
1310 goto notfound;
1312 capi_cmsg_answer(cmsg);
1313 send_message(card, cmsg);
1314 ncci_change_state(card, nccip, EV_NCCI_CONNECT_B3_ACTIVE_IND);
1316 cmd.command = ISDN_STAT_BCONN;
1317 cmd.driver = card->myid;
1318 cmd.arg = nccip->chan;
1319 card->interface.statcallb(&cmd);
1321 printk(KERN_INFO "capidrv-%d: chan %d up with ncci 0x%x\n",
1322 card->contrnr, nccip->chan, nccip->ncci);
1323 break;
1325 case CAPI_CONNECT_B3_ACTIVE_CONF: /* ncci */
1326 goto ignored;
1328 case CAPI_CONNECT_B3_IND: /* ncci */
1330 plcip = find_plci_by_ncci(card, cmsg->adr.adrNCCI);
1331 if (plcip) {
1332 nccip = new_ncci(card, plcip, cmsg->adr.adrNCCI);
1333 if (nccip) {
1334 ncci_change_state(card, nccip, EV_NCCI_CONNECT_B3_IND);
1335 capi_fill_CONNECT_B3_RESP(cmsg,
1336 global.appid,
1337 card->msgid++,
1338 nccip->ncci, /* adr */
1339 0, /* Reject */
1340 0 /* NCPI */
1342 send_message(card, cmsg);
1343 ncci_change_state(card, nccip, EV_NCCI_CONNECT_B3_RESP);
1344 break;
1346 printk(KERN_ERR "capidrv-%d: no mem for ncci, sorry\n", card->contrnr);
1347 } else {
1348 printk(KERN_ERR "capidrv-%d: %s: plci for ncci 0x%x not found\n",
1349 card->contrnr,
1350 capi_cmd2str(cmsg->Command, cmsg->Subcommand),
1351 cmsg->adr.adrNCCI);
1353 capi_fill_CONNECT_B3_RESP(cmsg,
1354 global.appid,
1355 card->msgid++,
1356 cmsg->adr.adrNCCI,
1357 2, /* Reject */
1358 0 /* NCPI */
1360 send_message(card, cmsg);
1361 break;
1363 case CAPI_CONNECT_B3_CONF: /* ncci */
1365 if (!(nccip = find_ncci_by_msgid(card,
1366 cmsg->adr.adrNCCI,
1367 cmsg->Messagenumber)))
1368 goto notfound;
1370 nccip->ncci = cmsg->adr.adrNCCI;
1371 if (cmsg->Info) {
1372 printk(KERN_INFO "capidrv-%d: %s info 0x%x (%s) for ncci 0x%x\n",
1373 card->contrnr,
1374 capi_cmd2str(cmsg->Command, cmsg->Subcommand),
1375 cmsg->Info, capi_info2str(cmsg->Info),
1376 cmsg->adr.adrNCCI);
1379 if (cmsg->Info)
1380 ncci_change_state(card, nccip, EV_NCCI_CONNECT_B3_CONF_ERROR);
1381 else
1382 ncci_change_state(card, nccip, EV_NCCI_CONNECT_B3_CONF_OK);
1383 break;
1385 case CAPI_CONNECT_B3_T90_ACTIVE_IND: /* ncci */
1386 capi_cmsg_answer(cmsg);
1387 send_message(card, cmsg);
1388 break;
1390 case CAPI_DATA_B3_IND: /* ncci */
1391 /* handled in handle_data() */
1392 goto ignored;
1394 case CAPI_DATA_B3_CONF: /* ncci */
1395 if (!(nccip = find_ncci(card, cmsg->adr.adrNCCI)))
1396 goto notfound;
1398 len = capidrv_del_ack(nccip, cmsg->DataHandle);
1399 if (len < 0)
1400 break;
1401 cmd.command = ISDN_STAT_BSENT;
1402 cmd.driver = card->myid;
1403 cmd.arg = nccip->chan;
1404 cmd.parm.length = len;
1405 card->interface.statcallb(&cmd);
1406 break;
1408 case CAPI_DISCONNECT_B3_IND: /* ncci */
1409 if (!(nccip = find_ncci(card, cmsg->adr.adrNCCI)))
1410 goto notfound;
1412 card->bchans[nccip->chan].disconnecting = 1;
1413 ncci_change_state(card, nccip, EV_NCCI_DISCONNECT_B3_IND);
1414 capi_cmsg_answer(cmsg);
1415 send_message(card, cmsg);
1416 ncci_change_state(card, nccip, EV_NCCI_DISCONNECT_B3_RESP);
1417 break;
1419 case CAPI_DISCONNECT_B3_CONF: /* ncci */
1420 if (!(nccip = find_ncci(card, cmsg->adr.adrNCCI)))
1421 goto notfound;
1422 if (cmsg->Info) {
1423 printk(KERN_INFO "capidrv-%d: %s info 0x%x (%s) for ncci 0x%x\n",
1424 card->contrnr,
1425 capi_cmd2str(cmsg->Command, cmsg->Subcommand),
1426 cmsg->Info, capi_info2str(cmsg->Info),
1427 cmsg->adr.adrNCCI);
1428 ncci_change_state(card, nccip, EV_NCCI_DISCONNECT_B3_CONF_ERROR);
1430 break;
1432 case CAPI_RESET_B3_IND: /* ncci */
1433 if (!(nccip = find_ncci(card, cmsg->adr.adrNCCI)))
1434 goto notfound;
1435 ncci_change_state(card, nccip, EV_NCCI_RESET_B3_IND);
1436 capi_cmsg_answer(cmsg);
1437 send_message(card, cmsg);
1438 break;
1440 case CAPI_RESET_B3_CONF: /* ncci */
1441 goto ignored; /* $$$$ */
1443 case CAPI_FACILITY_IND: /* Controller/plci/ncci */
1444 goto ignored;
1445 case CAPI_FACILITY_CONF: /* Controller/plci/ncci */
1446 goto ignored;
1448 default:
1449 printk(KERN_ERR "capidrv-%d: got %s for ncci 0x%x ???",
1450 card->contrnr,
1451 capi_cmd2str(cmsg->Command, cmsg->Subcommand),
1452 cmsg->adr.adrNCCI);
1454 return;
1455 ignored:
1456 printk(KERN_INFO "capidrv-%d: %s for ncci 0x%x ignored\n",
1457 card->contrnr,
1458 capi_cmd2str(cmsg->Command, cmsg->Subcommand),
1459 cmsg->adr.adrNCCI);
1460 return;
1461 notfound:
1462 printk(KERN_ERR "capidrv-%d: %s: ncci 0x%x not found\n",
1463 card->contrnr,
1464 capi_cmd2str(cmsg->Command, cmsg->Subcommand),
1465 cmsg->adr.adrNCCI);
1469 static void handle_data(_cmsg * cmsg, struct sk_buff *skb)
1471 capidrv_contr *card = findcontrbynumber(cmsg->adr.adrController & 0x7f);
1472 capidrv_ncci *nccip;
1474 if (!card) {
1475 printk(KERN_ERR "capidrv: %s from unknown controller 0x%x\n",
1476 capi_cmd2str(cmsg->Command, cmsg->Subcommand),
1477 cmsg->adr.adrController & 0x7f);
1478 kfree_skb(skb);
1479 return;
1481 if (!(nccip = find_ncci(card, cmsg->adr.adrNCCI))) {
1482 printk(KERN_ERR "capidrv-%d: %s: ncci 0x%x not found\n",
1483 card->contrnr,
1484 capi_cmd2str(cmsg->Command, cmsg->Subcommand),
1485 cmsg->adr.adrNCCI);
1486 kfree_skb(skb);
1487 return;
1489 (void) skb_pull(skb, CAPIMSG_LEN(skb->data));
1490 card->interface.rcvcallb_skb(card->myid, nccip->chan, skb);
1491 capi_cmsg_answer(cmsg);
1492 send_message(card, cmsg);
1495 static _cmsg s_cmsg;
1497 static void capidrv_signal(__u16 applid, __u32 dummy)
1499 struct sk_buff *skb = 0;
1501 while ((*capifuncs->capi_get_message) (global.appid, &skb) == CAPI_NOERROR) {
1502 capi_message2cmsg(&s_cmsg, skb->data);
1503 if (debugmode > 2)
1504 printk(KERN_DEBUG "capidrv_signal: applid=%d %s\n",
1505 applid, capi_cmsg2str(&s_cmsg));
1507 if (s_cmsg.Command == CAPI_DATA_B3
1508 && s_cmsg.Subcommand == CAPI_IND) {
1509 handle_data(&s_cmsg, skb);
1510 global.nrecvdatapkt++;
1511 continue;
1513 if ((s_cmsg.adr.adrController & 0xffffff00) == 0)
1514 handle_controller(&s_cmsg);
1515 else if ((s_cmsg.adr.adrPLCI & 0xffff0000) == 0)
1516 handle_plci(&s_cmsg);
1517 else
1518 handle_ncci(&s_cmsg);
1520 * data of skb used in s_cmsg,
1521 * free data when s_cmsg is not used again
1522 * thanks to Lars Heete <hel@admin.de>
1524 kfree_skb(skb);
1525 global.nrecvctlpkt++;
1529 /* ------------------------------------------------------------------- */
1531 #define PUTBYTE_TO_STATUS(card, byte) \
1532 do { \
1533 *(card)->q931_write++ = (byte); \
1534 if ((card)->q931_write > (card)->q931_end) \
1535 (card)->q931_write = (card)->q931_buf; \
1536 } while (0)
1538 static void handle_dtrace_data(capidrv_contr *card,
1539 int send, int level2, __u8 *data, __u16 len)
1541 long flags;
1542 __u8 *p, *end;
1543 isdn_ctrl cmd;
1545 if (!len) {
1546 printk(KERN_DEBUG "capidrv-%d: avmb1_q931_data: len == %d\n",
1547 card->contrnr, len);
1548 return;
1551 save_flags(flags);
1552 cli();
1554 if (level2) {
1555 PUTBYTE_TO_STATUS(card, 'D');
1556 PUTBYTE_TO_STATUS(card, '2');
1557 PUTBYTE_TO_STATUS(card, send ? '>' : '<');
1558 PUTBYTE_TO_STATUS(card, ':');
1559 } else {
1560 PUTBYTE_TO_STATUS(card, 'D');
1561 PUTBYTE_TO_STATUS(card, '3');
1562 PUTBYTE_TO_STATUS(card, send ? '>' : '<');
1563 PUTBYTE_TO_STATUS(card, ':');
1566 for (p = data, end = data+len; p < end; p++) {
1567 __u8 w;
1568 PUTBYTE_TO_STATUS(card, ' ');
1569 w = (*p >> 4) & 0xf;
1570 PUTBYTE_TO_STATUS(card, (w < 10) ? '0'+w : 'A'-10+w);
1571 w = *p & 0xf;
1572 PUTBYTE_TO_STATUS(card, (w < 10) ? '0'+w : 'A'-10+w);
1574 PUTBYTE_TO_STATUS(card, '\n');
1576 restore_flags(flags);
1578 cmd.command = ISDN_STAT_STAVAIL;
1579 cmd.driver = card->myid;
1580 cmd.arg = len*3+5;
1581 card->interface.statcallb(&cmd);
1584 /* ------------------------------------------------------------------- */
1586 static _cmsg cmdcmsg;
1588 static int capidrv_ioctl(isdn_ctrl * c, capidrv_contr * card)
1590 switch (c->arg) {
1591 case 1:
1592 debugmode = (int)(*((unsigned int *)c->parm.num));
1593 printk(KERN_DEBUG "capidrv-%d: debugmode=%d\n",
1594 card->contrnr, debugmode);
1595 return 0;
1596 default:
1597 printk(KERN_DEBUG "capidrv-%d: capidrv_ioctl(%ld) called ??\n",
1598 card->contrnr, c->arg);
1599 return -EINVAL;
1601 return -EINVAL;
1605 * Handle leased lines (CAPI-Bundling)
1608 struct internal_bchannelinfo {
1609 unsigned short channelalloc;
1610 unsigned short operation;
1611 unsigned char cmask[31];
1614 static int decodeFVteln(char *teln, unsigned long *bmaskp, int *activep)
1616 unsigned long bmask = 0;
1617 int active = !0;
1618 char *s;
1619 int i;
1621 if (strncmp(teln, "FV:", 3) != 0)
1622 return 1;
1623 s = teln + 3;
1624 while (*s && *s == ' ') s++;
1625 if (!*s) return -2;
1626 if (*s == 'p' || *s == 'P') {
1627 active = 0;
1628 s++;
1630 if (*s == 'a' || *s == 'A') {
1631 active = !0;
1632 s++;
1634 while (*s) {
1635 int digit1 = 0;
1636 int digit2 = 0;
1637 if (!isdigit(*s)) return -3;
1638 while (isdigit(*s)) { digit1 = digit1*10 + (*s - '0'); s++; }
1639 if (digit1 <= 0 && digit1 > 30) return -4;
1640 if (*s == 0 || *s == ',' || *s == ' ') {
1641 bmask |= (1 << digit1);
1642 digit1 = 0;
1643 if (*s) s++;
1644 continue;
1646 if (*s != '-') return -5;
1647 s++;
1648 if (!isdigit(*s)) return -3;
1649 while (isdigit(*s)) { digit2 = digit2*10 + (*s - '0'); s++; }
1650 if (digit2 <= 0 && digit2 > 30) return -4;
1651 if (*s == 0 || *s == ',' || *s == ' ') {
1652 if (digit1 > digit2)
1653 for (i = digit2; i <= digit1 ; i++)
1654 bmask |= (1 << i);
1655 else
1656 for (i = digit1; i <= digit2 ; i++)
1657 bmask |= (1 << i);
1658 digit1 = digit2 = 0;
1659 if (*s) s++;
1660 continue;
1662 return -6;
1664 if (activep) *activep = active;
1665 if (bmaskp) *bmaskp = bmask;
1666 return 0;
1669 static int FVteln2capi20(char *teln, __u8 AdditionalInfo[1+2+2+31])
1671 unsigned long bmask;
1672 int active;
1673 int rc, i;
1675 rc = decodeFVteln(teln, &bmask, &active);
1676 if (rc) return rc;
1677 /* Length */
1678 AdditionalInfo[0] = 2+2+31;
1679 /* Channel: 3 => use channel allocation */
1680 AdditionalInfo[1] = 3; AdditionalInfo[2] = 0;
1681 /* Operation: 0 => DTE mode, 1 => DCE mode */
1682 if (active) {
1683 AdditionalInfo[3] = 0; AdditionalInfo[4] = 0;
1684 } else {
1685 AdditionalInfo[3] = 1; AdditionalInfo[4] = 0;
1687 /* Channel mask array */
1688 AdditionalInfo[5] = 0; /* no D-Channel */
1689 for (i=1; i <= 30; i++)
1690 AdditionalInfo[5+i] = (bmask & (1 << i)) ? 0xff : 0;
1691 return 0;
1694 static int capidrv_command(isdn_ctrl * c, capidrv_contr * card)
1696 isdn_ctrl cmd;
1697 struct capidrv_bchan *bchan;
1698 struct capidrv_plci *plcip;
1699 __u8 AdditionalInfo[1+2+2+31];
1700 int rc, isleasedline = 0;
1702 if (c->command == ISDN_CMD_IOCTL)
1703 return capidrv_ioctl(c, card);
1705 switch (c->command) {
1706 case ISDN_CMD_DIAL:{
1707 __u8 calling[ISDN_MSNLEN + 3];
1708 __u8 called[ISDN_MSNLEN + 2];
1710 if (debugmode)
1711 printk(KERN_DEBUG "capidrv-%d: ISDN_CMD_DIAL(ch=%ld,\"%s,%d,%d,%s\")\n",
1712 card->contrnr,
1713 c->arg,
1714 c->parm.setup.phone,
1715 c->parm.setup.si1,
1716 c->parm.setup.si2,
1717 c->parm.setup.eazmsn);
1719 bchan = &card->bchans[c->arg % card->nbchan];
1721 if (bchan->plcip) {
1722 printk(KERN_ERR "capidrv-%d: dail ch=%ld,\"%s,%d,%d,%s\" in use (plci=0x%x)\n",
1723 card->contrnr,
1724 c->arg,
1725 c->parm.setup.phone,
1726 c->parm.setup.si1,
1727 c->parm.setup.si2,
1728 c->parm.setup.eazmsn,
1729 bchan->plcip->plci);
1730 return 0;
1732 bchan->si1 = c->parm.setup.si1;
1733 bchan->si2 = c->parm.setup.si2;
1735 strncpy(bchan->num, c->parm.setup.phone, sizeof(bchan->num));
1736 strncpy(bchan->mynum, c->parm.setup.eazmsn, sizeof(bchan->mynum));
1737 rc = FVteln2capi20(bchan->num, AdditionalInfo);
1738 isleasedline = (rc == 0);
1739 if (rc < 0)
1740 printk(KERN_ERR "capidrv-%d: WARNING: illegal leased linedefinition \"%s\"\n", card->contrnr, bchan->num);
1742 if (isleasedline) {
1743 calling[0] = 0;
1744 called[0] = 0;
1745 if (debugmode)
1746 printk(KERN_DEBUG "capidrv-%d: connecting leased line\n", card->contrnr);
1747 } else {
1748 calling[0] = strlen(bchan->mynum) + 2;
1749 calling[1] = 0;
1750 calling[2] = 0x80;
1751 strncpy(calling + 3, bchan->mynum, ISDN_MSNLEN);
1752 called[0] = strlen(bchan->num) + 1;
1753 called[1] = 0x80;
1754 strncpy(called + 2, bchan->num, ISDN_MSNLEN);
1757 capi_fill_CONNECT_REQ(&cmdcmsg,
1758 global.appid,
1759 card->msgid++,
1760 card->contrnr, /* adr */
1761 si2cip(bchan->si1, bchan->si2), /* cipvalue */
1762 called, /* CalledPartyNumber */
1763 calling, /* CallingPartyNumber */
1764 0, /* CalledPartySubaddress */
1765 0, /* CallingPartySubaddress */
1766 b1prot(bchan->l2, bchan->l3), /* B1protocol */
1767 b2prot(bchan->l2, bchan->l3), /* B2protocol */
1768 b3prot(bchan->l2, bchan->l3), /* B3protocol */
1769 b1config(bchan->l2, bchan->l3), /* B1configuration */
1770 0, /* B2configuration */
1771 0, /* B3configuration */
1772 0, /* BC */
1773 0, /* LLC */
1774 0, /* HLC */
1775 /* BChannelinformation */
1776 isleasedline ? AdditionalInfo : 0,
1777 0, /* Keypadfacility */
1778 0, /* Useruserdata */
1779 0 /* Facilitydataarray */
1781 if ((plcip = new_plci(card, (c->arg % card->nbchan))) == 0) {
1782 cmd.command = ISDN_STAT_DHUP;
1783 cmd.driver = card->myid;
1784 cmd.arg = (c->arg % card->nbchan);
1785 card->interface.statcallb(&cmd);
1786 return -1;
1788 plcip->msgid = cmdcmsg.Messagenumber;
1789 plcip->leasedline = isleasedline;
1790 plci_change_state(card, plcip, EV_PLCI_CONNECT_REQ);
1791 send_message(card, &cmdcmsg);
1792 return 0;
1795 case ISDN_CMD_ACCEPTD:
1797 bchan = &card->bchans[c->arg % card->nbchan];
1798 if (debugmode)
1799 printk(KERN_DEBUG "capidrv-%d: ISDN_CMD_ACCEPTD(ch=%ld) l2=%d l3=%d\n",
1800 card->contrnr,
1801 c->arg, bchan->l2, bchan->l3);
1803 capi_fill_CONNECT_RESP(&cmdcmsg,
1804 global.appid,
1805 card->msgid++,
1806 bchan->plcip->plci, /* adr */
1807 0, /* Reject */
1808 b1prot(bchan->l2, bchan->l3), /* B1protocol */
1809 b2prot(bchan->l2, bchan->l3), /* B2protocol */
1810 b3prot(bchan->l2, bchan->l3), /* B3protocol */
1811 b1config(bchan->l2, bchan->l3), /* B1configuration */
1812 0, /* B2configuration */
1813 0, /* B3configuration */
1814 0, /* ConnectedNumber */
1815 0, /* ConnectedSubaddress */
1816 0, /* LLC */
1817 0, /* BChannelinformation */
1818 0, /* Keypadfacility */
1819 0, /* Useruserdata */
1820 0 /* Facilitydataarray */
1822 capi_cmsg2message(&cmdcmsg, cmdcmsg.buf);
1823 plci_change_state(card, bchan->plcip, EV_PLCI_CONNECT_RESP);
1824 send_message(card, &cmdcmsg);
1825 return 0;
1827 case ISDN_CMD_ACCEPTB:
1828 if (debugmode)
1829 printk(KERN_DEBUG "capidrv-%d: ISDN_CMD_ACCEPTB(ch=%ld)\n",
1830 card->contrnr,
1831 c->arg);
1832 return -ENOSYS;
1834 case ISDN_CMD_HANGUP:
1835 if (debugmode)
1836 printk(KERN_DEBUG "capidrv-%d: ISDN_CMD_HANGUP(ch=%ld)\n",
1837 card->contrnr,
1838 c->arg);
1839 bchan = &card->bchans[c->arg % card->nbchan];
1841 if (bchan->disconnecting) {
1842 if (debugmode)
1843 printk(KERN_DEBUG "capidrv-%d: chan %ld already disconnecting ...\n",
1844 card->contrnr,
1845 c->arg);
1846 return 0;
1848 if (bchan->nccip) {
1849 bchan->disconnecting = 1;
1850 capi_fill_DISCONNECT_B3_REQ(&cmdcmsg,
1851 global.appid,
1852 card->msgid++,
1853 bchan->nccip->ncci,
1854 0 /* NCPI */
1856 ncci_change_state(card, bchan->nccip, EV_NCCI_DISCONNECT_B3_REQ);
1857 send_message(card, &cmdcmsg);
1858 } else if (bchan->plcip) {
1859 bchan->disconnecting = 1;
1860 if (bchan->plcip->state == ST_PLCI_INCOMING) {
1861 /* just ignore, we a called from isdn_status_callback(),
1862 * which will return 0 or 2, this is handled by the
1863 * CONNECT_IND handler
1865 } else {
1866 capi_fill_DISCONNECT_REQ(&cmdcmsg,
1867 global.appid,
1868 card->msgid++,
1869 bchan->plcip->plci,
1870 0, /* BChannelinformation */
1871 0, /* Keypadfacility */
1872 0, /* Useruserdata */
1873 0 /* Facilitydataarray */
1875 plci_change_state(card, bchan->plcip, EV_PLCI_DISCONNECT_REQ);
1876 send_message(card, &cmdcmsg);
1879 /* ready */
1881 case ISDN_CMD_SETL2:
1882 if (debugmode)
1883 printk(KERN_DEBUG "capidrv-%d: set L2 on chan %ld to %ld\n",
1884 card->contrnr,
1885 (c->arg & 0xff), (c->arg >> 8));
1886 bchan = &card->bchans[(c->arg & 0xff) % card->nbchan];
1887 bchan->l2 = (c->arg >> 8);
1888 return 0;
1890 case ISDN_CMD_SETL3:
1891 if (debugmode)
1892 printk(KERN_DEBUG "capidrv-%d: set L3 on chan %ld to %ld\n",
1893 card->contrnr,
1894 (c->arg & 0xff), (c->arg >> 8));
1895 bchan = &card->bchans[(c->arg & 0xff) % card->nbchan];
1896 bchan->l3 = (c->arg >> 8);
1897 return 0;
1899 case ISDN_CMD_SETEAZ:
1900 if (debugmode)
1901 printk(KERN_DEBUG "capidrv-%d: set EAZ \"%s\" on chan %ld\n",
1902 card->contrnr,
1903 c->parm.num, c->arg);
1904 bchan = &card->bchans[c->arg % card->nbchan];
1905 strncpy(bchan->msn, c->parm.num, ISDN_MSNLEN);
1906 return 0;
1908 case ISDN_CMD_CLREAZ:
1909 if (debugmode)
1910 printk(KERN_DEBUG "capidrv-%d: clearing EAZ on chan %ld\n",
1911 card->contrnr, c->arg);
1912 bchan = &card->bchans[c->arg % card->nbchan];
1913 bchan->msn[0] = 0;
1914 return 0;
1916 case ISDN_CMD_LOCK:
1917 if (debugmode > 1)
1918 printk(KERN_DEBUG "capidrv-%d: ISDN_CMD_LOCK (%ld)\n", card->contrnr, c->arg);
1919 MOD_INC_USE_COUNT;
1920 break;
1922 case ISDN_CMD_UNLOCK:
1923 if (debugmode > 1)
1924 printk(KERN_DEBUG "capidrv-%d: ISDN_CMD_UNLOCK (%ld)\n",
1925 card->contrnr, c->arg);
1926 MOD_DEC_USE_COUNT;
1927 break;
1929 /* never called */
1930 case ISDN_CMD_GETL2:
1931 if (debugmode)
1932 printk(KERN_DEBUG "capidrv-%d: ISDN_CMD_GETL2\n",
1933 card->contrnr);
1934 return -ENODEV;
1935 case ISDN_CMD_GETL3:
1936 if (debugmode)
1937 printk(KERN_DEBUG "capidrv-%d: ISDN_CMD_GETL3\n",
1938 card->contrnr);
1939 return -ENODEV;
1940 case ISDN_CMD_GETEAZ:
1941 if (debugmode)
1942 printk(KERN_DEBUG "capidrv-%d: ISDN_CMD_GETEAZ\n",
1943 card->contrnr);
1944 return -ENODEV;
1945 case ISDN_CMD_SETSIL:
1946 if (debugmode)
1947 printk(KERN_DEBUG "capidrv-%d: ISDN_CMD_SETSIL\n",
1948 card->contrnr);
1949 return -ENODEV;
1950 case ISDN_CMD_GETSIL:
1951 if (debugmode)
1952 printk(KERN_DEBUG "capidrv-%d: ISDN_CMD_GETSIL\n",
1953 card->contrnr);
1954 return -ENODEV;
1955 default:
1956 printk(KERN_ERR "capidrv-%d: ISDN_CMD_%d, Huh?\n",
1957 card->contrnr, c->command);
1958 return -EINVAL;
1960 return 0;
1963 static int if_command(isdn_ctrl * c)
1965 capidrv_contr *card = findcontrbydriverid(c->driver);
1967 if (card)
1968 return capidrv_command(c, card);
1970 printk(KERN_ERR
1971 "capidrv-%d: if_command %d called with invalid driverId %d!\n",
1972 card->contrnr, c->command, c->driver);
1973 return -ENODEV;
1976 static _cmsg sendcmsg;
1978 static int if_sendbuf(int id, int channel, int doack, struct sk_buff *skb)
1980 capidrv_contr *card = findcontrbydriverid(id);
1981 capidrv_bchan *bchan;
1982 capidrv_ncci *nccip;
1983 int len = skb->len;
1984 size_t msglen;
1985 __u16 errcode;
1986 __u16 datahandle;
1988 if (!card) {
1989 printk(KERN_ERR "capidrv-%d: if_sendbuf called with invalid driverId %d!\n",
1990 card->contrnr, id);
1991 return 0;
1993 if (debugmode > 1)
1994 printk(KERN_DEBUG "capidrv-%d: sendbuf len=%d skb=%p doack=%d\n",
1995 card->contrnr, len, skb, doack);
1996 bchan = &card->bchans[channel % card->nbchan];
1997 nccip = bchan->nccip;
1998 if (!nccip || nccip->state != ST_NCCI_ACTIVE) {
1999 printk(KERN_ERR "capidrv-%d: if_sendbuf: %s:%d: chan not up!\n",
2000 card->contrnr, card->name, channel);
2001 return 0;
2003 datahandle = nccip->datahandle;
2004 capi_fill_DATA_B3_REQ(&sendcmsg, global.appid, card->msgid++,
2005 nccip->ncci, /* adr */
2006 (__u32) skb->data, /* Data */
2007 skb->len, /* DataLength */
2008 datahandle, /* DataHandle */
2009 0 /* Flags */
2012 if (capidrv_add_ack(nccip, datahandle, doack ? skb->len : -1) < 0)
2013 return 0;
2015 capi_cmsg2message(&sendcmsg, sendcmsg.buf);
2016 msglen = CAPIMSG_LEN(sendcmsg.buf);
2017 if (skb_headroom(skb) < msglen) {
2018 struct sk_buff *nskb = skb_realloc_headroom(skb, msglen);
2019 if (!nskb) {
2020 printk(KERN_ERR "capidrv-%d: if_sendbuf: no memory\n",
2021 card->contrnr);
2022 (void)capidrv_del_ack(nccip, datahandle);
2023 return 0;
2025 #if 1
2026 printk(KERN_DEBUG "capidrv-%d: only %d bytes headroom, need %d\n",
2027 card->contrnr, skb_headroom(skb), msglen);
2028 #endif
2029 memcpy(skb_push(nskb, msglen), sendcmsg.buf, msglen);
2030 errcode = (*capifuncs->capi_put_message) (global.appid, nskb);
2031 if (errcode == CAPI_NOERROR) {
2032 dev_kfree_skb(skb);
2033 nccip->datahandle++;
2034 global.nsentdatapkt++;
2035 return len;
2037 (void)capidrv_del_ack(nccip, datahandle);
2038 dev_kfree_skb(nskb);
2039 return errcode == CAPI_SENDQUEUEFULL ? 0 : -1;
2040 } else {
2041 memcpy(skb_push(skb, msglen), sendcmsg.buf, msglen);
2042 errcode = (*capifuncs->capi_put_message) (global.appid, skb);
2043 if (errcode == CAPI_NOERROR) {
2044 nccip->datahandle++;
2045 global.nsentdatapkt++;
2046 return len;
2048 skb_pull(skb, msglen);
2049 (void)capidrv_del_ack(nccip, datahandle);
2050 return errcode == CAPI_SENDQUEUEFULL ? 0 : -1;
2054 static int if_readstat(__u8 *buf, int len, int user, int id, int channel)
2056 capidrv_contr *card = findcontrbydriverid(id);
2057 int count;
2058 __u8 *p;
2060 if (!card) {
2061 printk(KERN_ERR "capidrv-%d: if_readstat called with invalid driverId %d!\n",
2062 card->contrnr, id);
2063 return -ENODEV;
2066 for (p=buf, count=0; count < len; p++, count++) {
2067 if (user)
2068 put_user(*card->q931_read++, p);
2069 else
2070 *p = *card->q931_read++;
2071 if (card->q931_read > card->q931_end)
2072 card->q931_read = card->q931_buf;
2074 return count;
2078 static void enable_dchannel_trace(capidrv_contr *card)
2080 __u8 manufacturer[CAPI_MANUFACTURER_LEN];
2081 capi_version version;
2082 __u16 contr = card->contrnr;
2083 __u16 errcode;
2084 __u16 avmversion[3];
2086 errcode = (*capifuncs->capi_get_manufacturer)(contr, manufacturer);
2087 if (errcode != CAPI_NOERROR) {
2088 printk(KERN_ERR "%s: can't get manufacturer (0x%x)\n",
2089 card->name, errcode);
2090 return;
2092 if (strstr(manufacturer, "AVM") == 0) {
2093 printk(KERN_ERR "%s: not from AVM, no d-channel trace possible (%s)\n",
2094 card->name, manufacturer);
2095 return;
2097 errcode = (*capifuncs->capi_get_version)(contr, &version);
2098 if (errcode != CAPI_NOERROR) {
2099 printk(KERN_ERR "%s: can't get version (0x%x)\n",
2100 card->name, errcode);
2101 return;
2103 avmversion[0] = (version.majormanuversion >> 4) & 0x0f;
2104 avmversion[1] = (version.majormanuversion << 4) & 0xf0;
2105 avmversion[1] |= (version.minormanuversion >> 4) & 0x0f;
2106 avmversion[2] |= version.minormanuversion & 0x0f;
2108 if (avmversion[0] > 3 || (avmversion[0] == 3 && avmversion[1] > 5)) {
2109 printk(KERN_INFO "%s: D2 trace enabled\n", card->name);
2110 capi_fill_MANUFACTURER_REQ(&cmdcmsg, global.appid,
2111 card->msgid++,
2112 contr,
2113 0x214D5641, /* ManuID */
2114 0, /* Class */
2115 1, /* Function */
2116 (_cstruct)"\004\200\014\000\000");
2117 } else {
2118 printk(KERN_INFO "%s: D3 trace enabled\n", card->name);
2119 capi_fill_MANUFACTURER_REQ(&cmdcmsg, global.appid,
2120 card->msgid++,
2121 contr,
2122 0x214D5641, /* ManuID */
2123 0, /* Class */
2124 1, /* Function */
2125 (_cstruct)"\004\002\003\000\000");
2127 send_message(card, &cmdcmsg);
2130 static void disable_dchannel_trace(capidrv_contr *card)
2132 __u8 manufacturer[CAPI_MANUFACTURER_LEN];
2133 capi_version version;
2134 __u16 contr = card->contrnr;
2135 __u16 errcode;
2136 __u16 avmversion[3];
2138 errcode = (*capifuncs->capi_get_manufacturer)(contr, manufacturer);
2139 if (errcode != CAPI_NOERROR) {
2140 printk(KERN_ERR "%s: can't get manufacturer (0x%x)\n",
2141 card->name, errcode);
2142 return;
2144 if (strstr(manufacturer, "AVM") == 0) {
2145 printk(KERN_ERR "%s: not from AVM, no d-channel trace possible (%s)\n",
2146 card->name, manufacturer);
2147 return;
2149 errcode = (*capifuncs->capi_get_version)(contr, &version);
2150 if (errcode != CAPI_NOERROR) {
2151 printk(KERN_ERR "%s: can't get version (0x%x)\n",
2152 card->name, errcode);
2153 return;
2155 avmversion[0] = (version.majormanuversion >> 4) & 0x0f;
2156 avmversion[1] = (version.majormanuversion << 4) & 0xf0;
2157 avmversion[1] |= (version.minormanuversion >> 4) & 0x0f;
2158 avmversion[2] |= version.minormanuversion & 0x0f;
2160 if (avmversion[0] > 3 || (avmversion[0] == 3 && avmversion[1] > 5)) {
2161 printk(KERN_INFO "%s: D2 trace disabled\n", card->name);
2162 } else {
2163 printk(KERN_INFO "%s: D3 trace disabled\n", card->name);
2165 capi_fill_MANUFACTURER_REQ(&cmdcmsg, global.appid,
2166 card->msgid++,
2167 contr,
2168 0x214D5641, /* ManuID */
2169 0, /* Class */
2170 1, /* Function */
2171 (_cstruct)"\004\000\000\000\000");
2172 send_message(card, &cmdcmsg);
2175 static int capidrv_addcontr(__u16 contr, struct capi_profile *profp)
2177 capidrv_contr *card;
2178 isdn_ctrl cmd;
2179 char id[20];
2180 int i;
2182 sprintf(id, "capidrv-%d", contr);
2183 if (!(card = (capidrv_contr *) kmalloc(sizeof(capidrv_contr), GFP_ATOMIC))) {
2184 printk(KERN_WARNING
2185 "capidrv: (%s) Could not allocate contr-struct.\n", id);
2186 return -1;
2188 memset(card, 0, sizeof(capidrv_contr));
2189 strcpy(card->name, id);
2190 card->contrnr = contr;
2191 card->nbchan = profp->nbchannel;
2192 card->bchans = (capidrv_bchan *) kmalloc(sizeof(capidrv_bchan) * card->nbchan, GFP_ATOMIC);
2193 if (!card->bchans) {
2194 printk(KERN_WARNING
2195 "capidrv: (%s) Could not allocate bchan-structs.\n", id);
2196 kfree(card);
2197 return -1;
2199 card->interface.channels = profp->nbchannel;
2200 card->interface.maxbufsize = 2048;
2201 card->interface.command = if_command;
2202 card->interface.writebuf_skb = if_sendbuf;
2203 card->interface.writecmd = 0;
2204 card->interface.readstat = if_readstat;
2205 card->interface.features = ISDN_FEATURE_L2_X75I |
2206 ISDN_FEATURE_L2_X75UI |
2207 ISDN_FEATURE_L2_X75BUI |
2208 ISDN_FEATURE_L2_HDLC |
2209 ISDN_FEATURE_L2_TRANS |
2210 ISDN_FEATURE_L3_TRANS |
2211 ISDN_FEATURE_L2_V11096 |
2212 ISDN_FEATURE_L2_V11019 |
2213 ISDN_FEATURE_L2_V11038 |
2214 #if 0
2215 ISDN_FEATURE_L2_FAX |
2216 ISDN_FEATURE_L3_FAX |
2217 #endif
2218 ISDN_FEATURE_P_UNKNOWN;
2219 card->interface.hl_hdrlen = 22; /* len of DATA_B3_REQ */
2220 strncpy(card->interface.id, id, sizeof(card->interface.id) - 1);
2221 card->next = global.contr_list;
2222 global.contr_list = card;
2223 global.ncontr++;
2224 card->q931_read = card->q931_buf;
2225 card->q931_write = card->q931_buf;
2226 card->q931_end = card->q931_buf + sizeof(card->q931_buf) - 1;
2228 if (!register_isdn(&card->interface)) {
2229 global.contr_list = global.contr_list->next;
2230 printk(KERN_ERR "capidrv: Unable to register contr %s\n", id);
2231 kfree(card->bchans);
2232 kfree(card);
2233 return -1;
2235 card->myid = card->interface.channels;
2237 memset(card->bchans, 0, sizeof(capidrv_bchan) * card->nbchan);
2238 for (i = 0; i < card->nbchan; i++) {
2239 card->bchans[i].contr = card;
2242 cmd.driver = card->myid;
2243 cmd.command = ISDN_STAT_RUN;
2244 card->interface.statcallb(&cmd);
2246 card->cipmask = 0x1FFF03FF; /* any */
2247 card->cipmask2 = 0;
2249 capi_fill_LISTEN_REQ(&cmdcmsg, global.appid,
2250 card->msgid++,
2251 contr, /* controller */
2252 1 << 6, /* Infomask */
2253 card->cipmask,
2254 card->cipmask2,
2255 0, 0);
2256 send_message(card, &cmdcmsg);
2257 listen_change_state(card, EV_LISTEN_REQ);
2259 printk(KERN_INFO "%s: now up (%d B channels)\n",
2260 card->name, card->nbchan);
2262 enable_dchannel_trace(card);
2264 return 0;
2267 static int capidrv_delcontr(__u16 contr)
2269 capidrv_contr **pp, *card;
2270 isdn_ctrl cmd;
2271 int i;
2273 for (pp = &global.contr_list; *pp; pp = &(*pp)->next) {
2274 if ((*pp)->contrnr == contr)
2275 break;
2277 if (!*pp) {
2278 printk(KERN_ERR "capidrv: delcontr: no contr %u\n", contr);
2279 return -1;
2281 card = *pp;
2283 if (debugmode)
2284 printk(KERN_DEBUG "capidrv-%d: id=%d unloading\n",
2285 card->contrnr, card->myid);
2287 cmd.command = ISDN_STAT_UNLOAD;
2288 cmd.driver = card->myid;
2289 card->interface.statcallb(&cmd);
2291 *pp = (*pp)->next;
2292 global.ncontr--;
2294 for (i = 0; i < card->nbchan; i++) {
2295 if (card->bchans[i].nccip)
2296 free_ncci(card, card->bchans[i].nccip);
2297 if (card->bchans[i].plcip)
2298 free_plci(card, card->bchans[i].plcip);
2299 if (card->plci_list)
2300 printk(KERN_ERR "capidrv: bug in free_plci()\n");
2302 kfree(card->bchans);
2304 printk(KERN_INFO "%s: now down.\n", card->name);
2306 kfree(card);
2308 return 0;
2312 static void lower_callback(unsigned int cmd, __u16 contr, void *data)
2315 switch (cmd) {
2316 case KCI_CONTRUP:
2317 printk(KERN_INFO "capidrv: controller %hu up\n", contr);
2318 (void) capidrv_addcontr(contr, (capi_profile *) data);
2319 break;
2320 case KCI_CONTRDOWN:
2321 printk(KERN_INFO "capidrv: controller %hu down\n", contr);
2322 (void) capidrv_delcontr(contr);
2323 break;
2328 * /proc/capi/capidrv:
2329 * nrecvctlpkt nrecvdatapkt nsendctlpkt nsenddatapkt
2331 static int proc_capidrv_read_proc(char *page, char **start, off_t off,
2332 int count, int *eof, void *data)
2334 int len = 0;
2336 len += sprintf(page+len, "%lu %lu %lu %lu\n",
2337 global.nrecvctlpkt,
2338 global.nrecvdatapkt,
2339 global.nsentctlpkt,
2340 global.nsentdatapkt);
2341 if (off+count >= len)
2342 *eof = 1;
2343 if (len < off)
2344 return 0;
2345 *start = page + off;
2346 return ((count < len-off) ? count : len-off);
2349 static struct procfsentries {
2350 char *name;
2351 mode_t mode;
2352 int (*read_proc)(char *page, char **start, off_t off,
2353 int count, int *eof, void *data);
2354 struct proc_dir_entry *procent;
2355 } procfsentries[] = {
2356 /* { "capi", S_IFDIR, 0 }, */
2357 { "capi/capidrv", 0 , proc_capidrv_read_proc },
2360 static void proc_init(void)
2362 int nelem = sizeof(procfsentries)/sizeof(procfsentries[0]);
2363 int i;
2365 for (i=0; i < nelem; i++) {
2366 struct procfsentries *p = procfsentries + i;
2367 p->procent = create_proc_entry(p->name, p->mode, 0);
2368 if (p->procent) p->procent->read_proc = p->read_proc;
2372 static void proc_exit(void)
2374 int nelem = sizeof(procfsentries)/sizeof(procfsentries[0]);
2375 int i;
2377 for (i=nelem-1; i >= 0; i--) {
2378 struct procfsentries *p = procfsentries + i;
2379 if (p->procent) {
2380 remove_proc_entry(p->name, 0);
2381 p->procent = 0;
2386 static struct capi_interface_user cuser = {
2387 "capidrv",
2388 lower_callback
2391 #ifdef MODULE
2392 #define capidrv_init init_module
2393 #endif
2395 int capidrv_init(void)
2397 struct capi_register_params rparam;
2398 capi_profile profile;
2399 char rev[10];
2400 char *p;
2401 __u32 ncontr, contr;
2402 __u16 errcode;
2404 capifuncs = attach_capi_interface(&cuser);
2406 if (!capifuncs)
2407 return -EIO;
2409 if ((p = strchr(revision, ':'))) {
2410 strcpy(rev, p + 1);
2411 p = strchr(rev, '$');
2412 *p = 0;
2413 } else
2414 strcpy(rev, " ??? ");
2416 rparam.level3cnt = -2; /* number of bchannels twice */
2417 rparam.datablkcnt = 16;
2418 rparam.datablklen = 2048;
2419 errcode = (*capifuncs->capi_register) (&rparam, &global.appid);
2420 if (errcode) {
2421 detach_capi_interface(&cuser);
2422 return -EIO;
2425 errcode = (*capifuncs->capi_get_profile) (0, &profile);
2426 if (errcode != CAPI_NOERROR) {
2427 (void) (*capifuncs->capi_release) (global.appid);
2428 detach_capi_interface(&cuser);
2429 return -EIO;
2432 (void) (*capifuncs->capi_set_signal) (global.appid, capidrv_signal, 0);
2434 ncontr = profile.ncontroller;
2435 for (contr = 1; contr <= ncontr; contr++) {
2436 errcode = (*capifuncs->capi_get_profile) (contr, &profile);
2437 if (errcode != CAPI_NOERROR)
2438 continue;
2439 (void) capidrv_addcontr(contr, &profile);
2441 proc_init();
2443 return 0;
2446 #ifdef MODULE
2447 void cleanup_module(void)
2449 capidrv_contr *card, *next;
2450 char rev[10];
2451 char *p;
2453 if ((p = strchr(revision, ':'))) {
2454 strcpy(rev, p + 1);
2455 p = strchr(rev, '$');
2456 *p = 0;
2457 } else {
2458 strcpy(rev, " ??? ");
2461 for (card = global.contr_list; card; card = next) {
2462 next = card->next;
2463 disable_dchannel_trace(card);
2464 capidrv_delcontr(card->contrnr);
2467 (void) (*capifuncs->capi_release) (global.appid);
2468 detach_capi_interface(&cuser);
2469 proc_exit();
2471 printk(KERN_NOTICE "capidrv: Rev%s: unloaded\n", rev);
2474 #endif