Linux 2.4.0-test7-pre6
[davej-history.git] / drivers / isdn / avmb1 / capidrv.c
blob58b2eb9c66311b2440457feaf74a2da05c665c76
1 /*
2 * $Id: capidrv.c,v 1.36 2000/06/26 15:13:41 keil 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.36 2000/06/26 15:13:41 keil
10 * features should be or'ed
12 * Revision 1.35 2000/06/19 15:11:25 keil
13 * avoid use of freed structs
14 * changes from 2.4.0-ac21
16 * Revision 1.34 2000/06/19 13:13:55 calle
17 * Added Modemsupport!
19 * Revision 1.33 2000/05/06 00:52:36 kai
20 * merged changes from kernel tree
21 * fixed timer and net_device->name breakage
23 * Revision 1.32 2000/04/07 15:19:58 calle
24 * remove warnings
26 * Revision 1.31 2000/04/06 15:01:25 calle
27 * Bugfix: crash in capidrv.c when reseting a capi controller.
28 * - changed code order on remove of controller.
29 * - using tq_schedule for notifier in kcapi.c.
30 * - now using spin_lock_irqsave() and spin_unlock_irqrestore().
31 * strange: sometimes even MP hang on unload of isdn.o ...
33 * Revision 1.30 2000/03/03 15:50:42 calle
34 * - kernel CAPI:
35 * - Changed parameter "param" in capi_signal from __u32 to void *.
36 * - rewrote notifier handling in kcapi.c
37 * - new notifier NCCI_UP and NCCI_DOWN
38 * - User CAPI:
39 * - /dev/capi20 is now a cloning device.
40 * - middleware extentions prepared.
41 * - capidrv.c
42 * - locking of list operations and module count updates.
44 * Revision 1.29 1999/12/06 17:13:06 calle
45 * Added controller watchdog.
47 * Revision 1.28 1999/11/05 16:22:37 calle
48 * Bugfix: Missing break in switch on ISDN_CMD_HANGUP.
50 * Revision 1.27 1999/09/16 15:13:04 calle
51 * forgot to change paramter type of contr for lower_callback ...
53 * Revision 1.26 1999/08/06 07:41:16 calle
54 * Added the "vbox patch". if (si1 == 1) si2 = 0;
56 * Revision 1.25 1999/08/04 10:10:11 calle
57 * Bugfix: corrected /proc functions, added structure for new AVM cards.
59 * Revision 1.24 1999/07/20 06:48:02 calle
60 * Bugfix: firmware version check for D2 trace was too restrictiv.
62 * Revision 1.23 1999/07/09 15:05:44 keil
63 * compat.h is now isdn_compat.h
65 * Revision 1.22 1999/07/06 07:24:14 calle
66 * Bugfix: call to kfree_skb in capidrv_signal was too early,
67 * thanks to Lars Heete <hel@admin.de>.
69 * Revision 1.21 1999/07/01 15:26:34 calle
70 * complete new version (I love it):
71 * + new hardware independed "capi_driver" interface that will make it easy to:
72 * - support other controllers with CAPI-2.0 (i.e. USB Controller)
73 * - write a CAPI-2.0 for the passive cards
74 * - support serial link CAPI-2.0 boxes.
75 * + wrote "capi_driver" for all supported cards.
76 * + "capi_driver" (supported cards) now have to be configured with
77 * make menuconfig, in the past all supported cards where included
78 * at once.
79 * + new and better informations in /proc/capi/
80 * + new ioctl to switch trace of capi messages per controller
81 * using "avmcapictrl trace [contr] on|off|...."
82 * + complete testcircle with all supported cards and also the
83 * PCMCIA cards (now patch for pcmcia-cs-3.0.13 needed) done.
85 * Revision 1.20 1999/07/01 08:22:59 keil
86 * compatibility macros now in <linux/isdn_compat.h>
88 * Revision 1.19 1999/06/29 16:16:54 calle
89 * Let ISDN_CMD_UNLOAD work with open isdn devices without crash again.
90 * Also right unlocking (ISDN_CMD_UNLOCK) is done now.
91 * isdnlog should check returncode of read(2) calls.
93 * Revision 1.18 1999/06/21 15:24:15 calle
94 * extend information in /proc.
96 * Revision 1.17 1999/06/10 16:53:55 calle
97 * Removing of module b1pci will now remove card from lower level.
99 * Revision 1.16 1999/05/31 11:50:33 calle
100 * Bugfix: In if_sendbuf, skb_push'ed DATA_B3 header was not skb_pull'ed
101 * on failure, result in data block with DATA_B3 header transmitted
103 * Revision 1.15 1999/05/25 21:26:16 calle
104 * Include CAPI-Channelallocation (leased lines) from the 2.0 tree.
106 * Revision 1.14 1999/05/22 07:55:06 calle
107 * Added *V110* to AVM B1 driver.
109 * Revision 1.13 1998/06/26 15:12:55 fritz
110 * Added handling of STAT_ICALL with incomplete CPN.
111 * Added AT&L for ttyI emulator.
112 * Added more locking stuff in tty_write.
114 * Revision 1.12 1998/03/29 16:06:03 calle
115 * changes from 2.0 tree merged.
117 * Revision 1.3.2.10 1998/03/20 14:38:24 calle
118 * capidrv: prepared state machines for suspend/resume/hold
119 * capidrv: fix bug in state machine if B1/T1 is out of nccis
120 * b1capi: changed some errno returns.
121 * b1capi: detect if you try to add same T1 to different io address.
122 * b1capi: change number of nccis depending on number of channels.
123 * b1lli: cosmetics
125 * Revision 1.3.2.9 1998/03/20 09:01:12 calle
126 * Changes capi_register handling to get full support for 30 bchannels.
128 * Revision 1.3.2.8 1998/03/18 17:51:28 calle
129 * added controller number to error messages
131 * Revision 1.3.2.7 1998/02/27 15:40:47 calle
132 * T1 running with slow link. bugfix in capi_release.
134 * Revision 1.11 1998/02/13 07:09:15 calle
135 * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb()
137 * Revision 1.10 1998/02/02 19:52:23 calle
138 * Fixed vbox (audio) acceptb.
140 * Revision 1.9 1998/01/31 11:14:45 calle
141 * merged changes to 2.0 tree, prepare 2.1.82 to work.
143 * Revision 1.8 1997/11/04 06:12:09 calle
144 * capi.c: new read/write in file_ops since 2.1.60
145 * capidrv.c: prepared isdnlog interface for d2-trace in newer firmware.
146 * capiutil.c: needs config.h (CONFIG_ISDN_DRV_AVMB1_VERBOSE_REASON)
147 * compat.h: added #define LinuxVersionCode
149 * Revision 1.7 1997/10/11 10:36:34 calle
150 * Added isdnlog support. patch to isdnlog needed.
152 * Revision 1.6 1997/10/11 10:25:55 calle
153 * New interface for lowlevel drivers. BSENT with nr. of bytes sent,
154 * allow sending without ACK.
156 * Revision 1.5 1997/10/01 09:21:16 fritz
157 * Removed old compatibility stuff for 2.0.X kernels.
158 * From now on, this code is for 2.1.X ONLY!
159 * Old stuff is still in the separate branch.
161 * Revision 1.4 1997/07/13 12:22:43 calle
162 * bug fix for more than one controller in connect_req.
163 * debugoutput now with contrnr.
165 * Revision 1.3 1997/05/18 09:24:15 calle
166 * added verbose disconnect reason reporting to avmb1.
167 * some fixes in capi20 interface.
168 * changed info messages for B1-PCI
170 * Revision 1.2 1997/03/05 21:19:59 fritz
171 * Removed include of config.h (mkdep stated this is unneded).
173 * Revision 1.1 1997/03/04 21:50:31 calle
174 * Frirst version in isdn4linux
176 * Revision 2.2 1997/02/12 09:31:39 calle
177 * new version
179 * Revision 1.1 1997/01/31 10:32:20 calle
180 * Initial revision
184 #include <linux/module.h>
185 #include <linux/errno.h>
186 #include <linux/kernel.h>
187 #include <linux/major.h>
188 #include <linux/sched.h>
189 #include <linux/malloc.h>
190 #include <linux/fcntl.h>
191 #include <linux/fs.h>
192 #include <linux/signal.h>
193 #include <linux/mm.h>
194 #include <linux/timer.h>
195 #include <linux/wait.h>
196 #include <linux/skbuff.h>
197 #include <linux/isdn.h>
198 #include <linux/isdnif.h>
199 #include <linux/proc_fs.h>
200 #include <linux/capi.h>
201 #include <linux/kernelcapi.h>
202 #include <linux/ctype.h>
203 #include <asm/segment.h>
205 #include "capiutil.h"
206 #include "capicmd.h"
207 #include "capidrv.h"
209 static char *revision = "$Revision: 1.36 $";
210 static int debugmode = 0;
212 MODULE_AUTHOR("Carsten Paeth <calle@calle.in-berlin.de>");
213 MODULE_PARM(debugmode, "i");
215 /* -------- type definitions ----------------------------------------- */
218 struct capidrv_contr {
220 struct capidrv_contr *next;
222 __u32 contrnr;
223 char name[20];
226 * for isdn4linux
228 isdn_if interface;
229 int myid;
232 * LISTEN state
234 int state;
235 __u32 cipmask;
236 __u32 cipmask2;
237 struct timer_list listentimer;
240 * ID of capi message sent
242 __u16 msgid;
245 * B-Channels
247 int nbchan;
248 struct capidrv_bchan {
249 struct capidrv_contr *contr;
250 __u8 msn[ISDN_MSNLEN];
251 int l2;
252 int l3;
253 __u8 num[ISDN_MSNLEN];
254 __u8 mynum[ISDN_MSNLEN];
255 int si1;
256 int si2;
257 int incoming;
258 int disconnecting;
259 struct capidrv_plci {
260 struct capidrv_plci *next;
261 __u32 plci;
262 __u32 ncci; /* ncci for CONNECT_ACTIVE_IND */
263 __u16 msgid; /* to identfy CONNECT_CONF */
264 int chan;
265 int state;
266 int leasedline;
267 struct capidrv_ncci {
268 struct capidrv_ncci *next;
269 struct capidrv_plci *plcip;
270 __u32 ncci;
271 __u16 msgid; /* to identfy CONNECT_B3_CONF */
272 int chan;
273 int state;
274 int oldstate;
275 /* */
276 __u16 datahandle;
277 struct ncci_datahandle_queue {
278 struct ncci_datahandle_queue *next;
279 __u16 datahandle;
280 int len;
281 } *ackqueue;
282 } *ncci_list;
283 } *plcip;
284 struct capidrv_ncci *nccip;
285 } *bchans;
287 struct capidrv_plci *plci_list;
289 /* for q931 data */
290 __u8 q931_buf[4096];
291 __u8 *q931_read;
292 __u8 *q931_write;
293 __u8 *q931_end;
297 struct capidrv_data {
298 __u16 appid;
299 int ncontr;
300 struct capidrv_contr *contr_list;
302 /* statistic */
303 unsigned long nrecvctlpkt;
304 unsigned long nrecvdatapkt;
305 unsigned long nsentctlpkt;
306 unsigned long nsentdatapkt;
309 typedef struct capidrv_plci capidrv_plci;
310 typedef struct capidrv_ncci capidrv_ncci;
311 typedef struct capidrv_contr capidrv_contr;
312 typedef struct capidrv_data capidrv_data;
313 typedef struct capidrv_bchan capidrv_bchan;
315 /* -------- data definitions ----------------------------------------- */
317 static capidrv_data global;
318 static spinlock_t global_lock = SPIN_LOCK_UNLOCKED;
319 static struct capi_interface *capifuncs;
321 static void handle_dtrace_data(capidrv_contr *card,
322 int send, int level2, __u8 *data, __u16 len);
324 /* -------- convert functions ---------------------------------------- */
326 static inline __u32 b1prot(int l2, int l3)
328 switch (l2) {
329 case ISDN_PROTO_L2_X75I:
330 case ISDN_PROTO_L2_X75UI:
331 case ISDN_PROTO_L2_X75BUI:
332 return 0;
333 case ISDN_PROTO_L2_HDLC:
334 default:
335 return 0;
336 case ISDN_PROTO_L2_TRANS:
337 return 1;
338 case ISDN_PROTO_L2_V11096:
339 case ISDN_PROTO_L2_V11019:
340 case ISDN_PROTO_L2_V11038:
341 return 2;
342 case ISDN_PROTO_L2_FAX:
343 return 4;
344 case ISDN_PROTO_L2_MODEM:
345 return 8;
349 static inline __u32 b2prot(int l2, int l3)
351 switch (l2) {
352 case ISDN_PROTO_L2_X75I:
353 case ISDN_PROTO_L2_X75UI:
354 case ISDN_PROTO_L2_X75BUI:
355 default:
356 return 0;
357 case ISDN_PROTO_L2_HDLC:
358 case ISDN_PROTO_L2_TRANS:
359 case ISDN_PROTO_L2_V11096:
360 case ISDN_PROTO_L2_V11019:
361 case ISDN_PROTO_L2_V11038:
362 case ISDN_PROTO_L2_MODEM:
363 return 1;
364 case ISDN_PROTO_L2_FAX:
365 return 4;
369 static inline __u32 b3prot(int l2, int l3)
371 switch (l2) {
372 case ISDN_PROTO_L2_X75I:
373 case ISDN_PROTO_L2_X75UI:
374 case ISDN_PROTO_L2_X75BUI:
375 case ISDN_PROTO_L2_HDLC:
376 case ISDN_PROTO_L2_TRANS:
377 case ISDN_PROTO_L2_V11096:
378 case ISDN_PROTO_L2_V11019:
379 case ISDN_PROTO_L2_V11038:
380 case ISDN_PROTO_L2_MODEM:
381 default:
382 return 0;
383 case ISDN_PROTO_L2_FAX:
384 return 4;
388 static _cstruct b1config_sync_v110(__u16 rate)
390 /* CAPI-Spec "B1 Configuration" */
391 static unsigned char buf[9];
392 buf[0] = 8; /* len */
393 /* maximum bitrate */
394 buf[1] = rate & 0xff; buf[2] = (rate >> 8) & 0xff;
395 buf[3] = buf[4] = 0; /* reserved, bits per character */
396 buf[5] = buf[6] = 0; /* reserved, parity */
397 buf[7] = buf[9] = 0; /* reserved, stop bits */
398 return buf;
401 static _cstruct b1config(int l2, int l3)
403 switch (l2) {
404 case ISDN_PROTO_L2_X75I:
405 case ISDN_PROTO_L2_X75UI:
406 case ISDN_PROTO_L2_X75BUI:
407 case ISDN_PROTO_L2_HDLC:
408 case ISDN_PROTO_L2_TRANS:
409 default:
410 return 0;
411 case ISDN_PROTO_L2_V11096:
412 return b1config_sync_v110(9600);
413 case ISDN_PROTO_L2_V11019:
414 return b1config_sync_v110(19200);
415 case ISDN_PROTO_L2_V11038:
416 return b1config_sync_v110(38400);
420 static inline __u16 si2cip(__u8 si1, __u8 si2)
422 static const __u8 cip[17][5] =
424 /* 0 1 2 3 4 */
425 {0, 0, 0, 0, 0}, /*0 */
426 {16, 16, 4, 26, 16}, /*1 */
427 {17, 17, 17, 4, 4}, /*2 */
428 {2, 2, 2, 2, 2}, /*3 */
429 {18, 18, 18, 18, 18}, /*4 */
430 {2, 2, 2, 2, 2}, /*5 */
431 {0, 0, 0, 0, 0}, /*6 */
432 {2, 2, 2, 2, 2}, /*7 */
433 {2, 2, 2, 2, 2}, /*8 */
434 {21, 21, 21, 21, 21}, /*9 */
435 {19, 19, 19, 19, 19}, /*10 */
436 {0, 0, 0, 0, 0}, /*11 */
437 {0, 0, 0, 0, 0}, /*12 */
438 {0, 0, 0, 0, 0}, /*13 */
439 {0, 0, 0, 0, 0}, /*14 */
440 {22, 22, 22, 22, 22}, /*15 */
441 {27, 27, 27, 28, 27} /*16 */
443 if (si1 > 16)
444 si1 = 0;
445 if (si2 > 4)
446 si2 = 0;
448 return (__u16) cip[si1][si2];
451 static inline __u8 cip2si1(__u16 cipval)
453 static const __u8 si[32] =
454 {7, 1, 7, 7, 1, 1, 7, 7, /*0-7 */
455 7, 1, 0, 0, 0, 0, 0, 0, /*8-15 */
456 1, 2, 4, 10, 9, 9, 15, 7, /*16-23 */
457 7, 7, 1, 16, 16, 0, 0, 0}; /*24-31 */
459 if (cipval > 31)
460 cipval = 0; /* .... */
461 return si[cipval];
464 static inline __u8 cip2si2(__u16 cipval)
466 static const __u8 si[32] =
467 {0, 0, 0, 0, 2, 3, 0, 0, /*0-7 */
468 0, 3, 0, 0, 0, 0, 0, 0, /*8-15 */
469 1, 2, 0, 0, 9, 0, 0, 0, /*16-23 */
470 0, 0, 3, 2, 3, 0, 0, 0}; /*24-31 */
472 if (cipval > 31)
473 cipval = 0; /* .... */
474 return si[cipval];
478 /* -------- controller managment ------------------------------------- */
480 static inline capidrv_contr *findcontrbydriverid(int driverid)
482 unsigned long flags;
483 capidrv_contr *p;
485 spin_lock_irqsave(&global_lock, flags);
486 for (p = global.contr_list; p; p = p->next)
487 if (p->myid == driverid)
488 break;
489 spin_unlock_irqrestore(&global_lock, flags);
490 return p;
493 static capidrv_contr *findcontrbynumber(__u32 contr)
495 unsigned long flags;
496 capidrv_contr *p = global.contr_list;
498 spin_lock_irqsave(&global_lock, flags);
499 for (p = global.contr_list; p; p = p->next)
500 if (p->contrnr == contr)
501 break;
502 spin_unlock_irqrestore(&global_lock, flags);
503 return p;
507 /* -------- plci management ------------------------------------------ */
509 static capidrv_plci *new_plci(capidrv_contr * card, int chan)
511 capidrv_plci *plcip;
513 plcip = (capidrv_plci *) kmalloc(sizeof(capidrv_plci), GFP_ATOMIC);
515 if (plcip == 0)
516 return 0;
518 memset(plcip, 0, sizeof(capidrv_plci));
519 plcip->state = ST_PLCI_NONE;
520 plcip->plci = 0;
521 plcip->msgid = 0;
522 plcip->chan = chan;
523 plcip->next = card->plci_list;
524 card->plci_list = plcip;
525 card->bchans[chan].plcip = plcip;
527 return plcip;
530 static capidrv_plci *find_plci_by_plci(capidrv_contr * card, __u32 plci)
532 capidrv_plci *p;
533 for (p = card->plci_list; p; p = p->next)
534 if (p->plci == plci)
535 return p;
536 return 0;
539 static capidrv_plci *find_plci_by_msgid(capidrv_contr * card, __u16 msgid)
541 capidrv_plci *p;
542 for (p = card->plci_list; p; p = p->next)
543 if (p->msgid == msgid)
544 return p;
545 return 0;
548 static capidrv_plci *find_plci_by_ncci(capidrv_contr * card, __u32 ncci)
550 capidrv_plci *p;
551 for (p = card->plci_list; p; p = p->next)
552 if (p->plci == (ncci & 0xffff))
553 return p;
554 return 0;
557 static void free_plci(capidrv_contr * card, capidrv_plci * plcip)
559 capidrv_plci **pp;
561 for (pp = &card->plci_list; *pp; pp = &(*pp)->next) {
562 if (*pp == plcip) {
563 *pp = (*pp)->next;
564 card->bchans[plcip->chan].plcip = 0;
565 card->bchans[plcip->chan].disconnecting = 0;
566 card->bchans[plcip->chan].incoming = 0;
567 kfree(plcip);
568 return;
571 printk(KERN_ERR "capidrv-%d: free_plci %p (0x%x) not found, Huh?\n",
572 card->contrnr, plcip, plcip->plci);
575 /* -------- ncci management ------------------------------------------ */
577 static inline capidrv_ncci *new_ncci(capidrv_contr * card,
578 capidrv_plci * plcip,
579 __u32 ncci)
581 capidrv_ncci *nccip;
583 nccip = (capidrv_ncci *) kmalloc(sizeof(capidrv_ncci), GFP_ATOMIC);
585 if (nccip == 0)
586 return 0;
588 memset(nccip, 0, sizeof(capidrv_ncci));
589 nccip->ncci = ncci;
590 nccip->state = ST_NCCI_NONE;
591 nccip->plcip = plcip;
592 nccip->chan = plcip->chan;
593 nccip->datahandle = 0;
595 nccip->next = plcip->ncci_list;
596 plcip->ncci_list = nccip;
598 card->bchans[plcip->chan].nccip = nccip;
600 return nccip;
603 static inline capidrv_ncci *find_ncci(capidrv_contr * card, __u32 ncci)
605 capidrv_plci *plcip;
606 capidrv_ncci *p;
608 if ((plcip = find_plci_by_ncci(card, ncci)) == 0)
609 return 0;
611 for (p = plcip->ncci_list; p; p = p->next)
612 if (p->ncci == ncci)
613 return p;
614 return 0;
617 static inline capidrv_ncci *find_ncci_by_msgid(capidrv_contr * card,
618 __u32 ncci, __u16 msgid)
620 capidrv_plci *plcip;
621 capidrv_ncci *p;
623 if ((plcip = find_plci_by_ncci(card, ncci)) == 0)
624 return 0;
626 for (p = plcip->ncci_list; p; p = p->next)
627 if (p->msgid == msgid)
628 return p;
629 return 0;
632 static void free_ncci(capidrv_contr * card, struct capidrv_ncci *nccip)
634 struct capidrv_ncci **pp;
636 for (pp = &(nccip->plcip->ncci_list); *pp; pp = &(*pp)->next) {
637 if (*pp == nccip) {
638 *pp = (*pp)->next;
639 break;
642 card->bchans[nccip->chan].nccip = 0;
643 kfree(nccip);
646 static int capidrv_add_ack(struct capidrv_ncci *nccip,
647 __u16 datahandle, int len)
649 struct ncci_datahandle_queue *n, **pp;
651 n = (struct ncci_datahandle_queue *)
652 kmalloc(sizeof(struct ncci_datahandle_queue), GFP_ATOMIC);
653 if (!n) {
654 printk(KERN_ERR "capidrv: kmalloc ncci_datahandle failed\n");
655 return -1;
657 n->next = 0;
658 n->datahandle = datahandle;
659 n->len = len;
660 for (pp = &nccip->ackqueue; *pp; pp = &(*pp)->next) ;
661 *pp = n;
662 return 0;
665 static int capidrv_del_ack(struct capidrv_ncci *nccip, __u16 datahandle)
667 struct ncci_datahandle_queue **pp, *p;
668 int len;
670 for (pp = &nccip->ackqueue; *pp; pp = &(*pp)->next) {
671 if ((*pp)->datahandle == datahandle) {
672 p = *pp;
673 len = p->len;
674 *pp = (*pp)->next;
675 kfree(p);
676 return len;
679 return -1;
682 /* -------- convert and send capi message ---------------------------- */
684 static void send_message(capidrv_contr * card, _cmsg * cmsg)
686 struct sk_buff *skb;
687 size_t len;
688 capi_cmsg2message(cmsg, cmsg->buf);
689 len = CAPIMSG_LEN(cmsg->buf);
690 skb = alloc_skb(len, GFP_ATOMIC);
691 memcpy(skb_put(skb, len), cmsg->buf, len);
692 (*capifuncs->capi_put_message) (global.appid, skb);
693 global.nsentctlpkt++;
696 /* -------- state machine -------------------------------------------- */
698 struct listenstatechange {
699 int actstate;
700 int nextstate;
701 int event;
704 static struct listenstatechange listentable[] =
706 {ST_LISTEN_NONE, ST_LISTEN_WAIT_CONF, EV_LISTEN_REQ},
707 {ST_LISTEN_ACTIVE, ST_LISTEN_ACTIVE_WAIT_CONF, EV_LISTEN_REQ},
708 {ST_LISTEN_WAIT_CONF, ST_LISTEN_NONE, EV_LISTEN_CONF_ERROR},
709 {ST_LISTEN_ACTIVE_WAIT_CONF, ST_LISTEN_ACTIVE, EV_LISTEN_CONF_ERROR},
710 {ST_LISTEN_WAIT_CONF, ST_LISTEN_NONE, EV_LISTEN_CONF_EMPTY},
711 {ST_LISTEN_ACTIVE_WAIT_CONF, ST_LISTEN_NONE, EV_LISTEN_CONF_EMPTY},
712 {ST_LISTEN_WAIT_CONF, ST_LISTEN_ACTIVE, EV_LISTEN_CONF_OK},
713 {ST_LISTEN_ACTIVE_WAIT_CONF, ST_LISTEN_ACTIVE, EV_LISTEN_CONF_OK},
717 static void listen_change_state(capidrv_contr * card, int event)
719 struct listenstatechange *p = listentable;
720 while (p->event) {
721 if (card->state == p->actstate && p->event == event) {
722 if (debugmode)
723 printk(KERN_DEBUG "capidrv-%d: listen_change_state %d -> %d\n",
724 card->contrnr, card->state, p->nextstate);
725 card->state = p->nextstate;
726 return;
728 p++;
730 printk(KERN_ERR "capidrv-%d: listen_change_state state=%d event=%d ????\n",
731 card->contrnr, card->state, event);
735 /* ------------------------------------------------------------------ */
737 static void p0(capidrv_contr * card, capidrv_plci * plci)
739 isdn_ctrl cmd;
741 card->bchans[plci->chan].contr = 0;
742 cmd.command = ISDN_STAT_DHUP;
743 cmd.driver = card->myid;
744 cmd.arg = plci->chan;
745 card->interface.statcallb(&cmd);
746 free_plci(card, plci);
749 /* ------------------------------------------------------------------ */
751 struct plcistatechange {
752 int actstate;
753 int nextstate;
754 int event;
755 void (*changefunc) (capidrv_contr * card, capidrv_plci * plci);
758 static struct plcistatechange plcitable[] =
760 /* P-0 */
761 {ST_PLCI_NONE, ST_PLCI_OUTGOING, EV_PLCI_CONNECT_REQ, 0},
762 {ST_PLCI_NONE, ST_PLCI_ALLOCATED, EV_PLCI_FACILITY_IND_UP, 0},
763 {ST_PLCI_NONE, ST_PLCI_INCOMING, EV_PLCI_CONNECT_IND, 0},
764 {ST_PLCI_NONE, ST_PLCI_RESUMEING, EV_PLCI_RESUME_REQ, 0},
765 /* P-0.1 */
766 {ST_PLCI_OUTGOING, ST_PLCI_NONE, EV_PLCI_CONNECT_CONF_ERROR, p0},
767 {ST_PLCI_OUTGOING, ST_PLCI_ALLOCATED, EV_PLCI_CONNECT_CONF_OK, 0},
768 /* P-1 */
769 {ST_PLCI_ALLOCATED, ST_PLCI_ACTIVE, EV_PLCI_CONNECT_ACTIVE_IND, 0},
770 {ST_PLCI_ALLOCATED, ST_PLCI_DISCONNECTING, EV_PLCI_DISCONNECT_REQ, 0},
771 {ST_PLCI_ALLOCATED, ST_PLCI_DISCONNECTING, EV_PLCI_FACILITY_IND_DOWN, 0},
772 {ST_PLCI_ALLOCATED, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, 0},
773 /* P-ACT */
774 {ST_PLCI_ACTIVE, ST_PLCI_DISCONNECTING, EV_PLCI_DISCONNECT_REQ, 0},
775 {ST_PLCI_ACTIVE, ST_PLCI_DISCONNECTING, EV_PLCI_FACILITY_IND_DOWN, 0},
776 {ST_PLCI_ACTIVE, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, 0},
777 {ST_PLCI_ACTIVE, ST_PLCI_HELD, EV_PLCI_HOLD_IND, 0},
778 {ST_PLCI_ACTIVE, ST_PLCI_DISCONNECTING, EV_PLCI_SUSPEND_IND, 0},
779 /* P-2 */
780 {ST_PLCI_INCOMING, ST_PLCI_DISCONNECTING, EV_PLCI_CONNECT_REJECT, 0},
781 {ST_PLCI_INCOMING, ST_PLCI_FACILITY_IND, EV_PLCI_FACILITY_IND_UP, 0},
782 {ST_PLCI_INCOMING, ST_PLCI_ACCEPTING, EV_PLCI_CONNECT_RESP, 0},
783 {ST_PLCI_INCOMING, ST_PLCI_DISCONNECTING, EV_PLCI_DISCONNECT_REQ, 0},
784 {ST_PLCI_INCOMING, ST_PLCI_DISCONNECTING, EV_PLCI_FACILITY_IND_DOWN, 0},
785 {ST_PLCI_INCOMING, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, 0},
786 {ST_PLCI_INCOMING, ST_PLCI_DISCONNECTING, EV_PLCI_CD_IND, 0},
787 /* P-3 */
788 {ST_PLCI_FACILITY_IND, ST_PLCI_DISCONNECTING, EV_PLCI_CONNECT_REJECT, 0},
789 {ST_PLCI_FACILITY_IND, ST_PLCI_ACCEPTING, EV_PLCI_CONNECT_ACTIVE_IND, 0},
790 {ST_PLCI_FACILITY_IND, ST_PLCI_DISCONNECTING, EV_PLCI_DISCONNECT_REQ, 0},
791 {ST_PLCI_FACILITY_IND, ST_PLCI_DISCONNECTING, EV_PLCI_FACILITY_IND_DOWN, 0},
792 {ST_PLCI_FACILITY_IND, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, 0},
793 /* P-4 */
794 {ST_PLCI_ACCEPTING, ST_PLCI_ACTIVE, EV_PLCI_CONNECT_ACTIVE_IND, 0},
795 {ST_PLCI_ACCEPTING, ST_PLCI_DISCONNECTING, EV_PLCI_DISCONNECT_REQ, 0},
796 {ST_PLCI_ACCEPTING, ST_PLCI_DISCONNECTING, EV_PLCI_FACILITY_IND_DOWN, 0},
797 {ST_PLCI_ACCEPTING, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, 0},
798 /* P-5 */
799 {ST_PLCI_DISCONNECTING, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, 0},
800 /* P-6 */
801 {ST_PLCI_DISCONNECTED, ST_PLCI_NONE, EV_PLCI_DISCONNECT_RESP, p0},
802 /* P-0.Res */
803 {ST_PLCI_RESUMEING, ST_PLCI_NONE, EV_PLCI_RESUME_CONF_ERROR, p0},
804 {ST_PLCI_RESUMEING, ST_PLCI_RESUME, EV_PLCI_RESUME_CONF_OK, 0},
805 /* P-RES */
806 {ST_PLCI_RESUME, ST_PLCI_ACTIVE, EV_PLCI_RESUME_IND, 0},
807 /* P-HELD */
808 {ST_PLCI_HELD, ST_PLCI_ACTIVE, EV_PLCI_RETRIEVE_IND, 0},
812 static void plci_change_state(capidrv_contr * card, capidrv_plci * plci, int event)
814 struct plcistatechange *p = plcitable;
815 while (p->event) {
816 if (plci->state == p->actstate && p->event == event) {
817 if (debugmode)
818 printk(KERN_DEBUG "capidrv-%d: plci_change_state:0x%x %d -> %d\n",
819 card->contrnr, plci->plci, plci->state, p->nextstate);
820 plci->state = p->nextstate;
821 if (p->changefunc)
822 p->changefunc(card, plci);
823 return;
825 p++;
827 printk(KERN_ERR "capidrv-%d: plci_change_state:0x%x state=%d event=%d ????\n",
828 card->contrnr, plci->plci, plci->state, event);
831 /* ------------------------------------------------------------------ */
833 static _cmsg cmsg;
835 static void n0(capidrv_contr * card, capidrv_ncci * ncci)
837 isdn_ctrl cmd;
839 capi_fill_DISCONNECT_REQ(&cmsg,
840 global.appid,
841 card->msgid++,
842 ncci->plcip->plci,
843 0, /* BChannelinformation */
844 0, /* Keypadfacility */
845 0, /* Useruserdata */ /* $$$$ */
846 0 /* Facilitydataarray */
848 send_message(card, &cmsg);
849 plci_change_state(card, ncci->plcip, EV_PLCI_DISCONNECT_REQ);
851 cmd.command = ISDN_STAT_BHUP;
852 cmd.driver = card->myid;
853 cmd.arg = ncci->chan;
854 card->interface.statcallb(&cmd);
855 free_ncci(card, ncci);
858 /* ------------------------------------------------------------------ */
860 struct nccistatechange {
861 int actstate;
862 int nextstate;
863 int event;
864 void (*changefunc) (capidrv_contr * card, capidrv_ncci * ncci);
867 static struct nccistatechange nccitable[] =
869 /* N-0 */
870 {ST_NCCI_NONE, ST_NCCI_OUTGOING, EV_NCCI_CONNECT_B3_REQ, 0},
871 {ST_NCCI_NONE, ST_NCCI_INCOMING, EV_NCCI_CONNECT_B3_IND, 0},
872 /* N-0.1 */
873 {ST_NCCI_OUTGOING, ST_NCCI_ALLOCATED, EV_NCCI_CONNECT_B3_CONF_OK, 0},
874 {ST_NCCI_OUTGOING, ST_NCCI_NONE, EV_NCCI_CONNECT_B3_CONF_ERROR, n0},
875 /* N-1 */
876 {ST_NCCI_INCOMING, ST_NCCI_DISCONNECTING, EV_NCCI_CONNECT_B3_REJECT, 0},
877 {ST_NCCI_INCOMING, ST_NCCI_ALLOCATED, EV_NCCI_CONNECT_B3_RESP, 0},
878 {ST_NCCI_INCOMING, ST_NCCI_DISCONNECTED, EV_NCCI_DISCONNECT_B3_IND, 0},
879 {ST_NCCI_INCOMING, ST_NCCI_DISCONNECTING, EV_NCCI_DISCONNECT_B3_REQ, 0},
880 /* N-2 */
881 {ST_NCCI_ALLOCATED, ST_NCCI_ACTIVE, EV_NCCI_CONNECT_B3_ACTIVE_IND, 0},
882 {ST_NCCI_ALLOCATED, ST_NCCI_DISCONNECTED, EV_NCCI_DISCONNECT_B3_IND, 0},
883 {ST_NCCI_ALLOCATED, ST_NCCI_DISCONNECTING, EV_NCCI_DISCONNECT_B3_REQ, 0},
884 /* N-ACT */
885 {ST_NCCI_ACTIVE, ST_NCCI_ACTIVE, EV_NCCI_RESET_B3_IND, 0},
886 {ST_NCCI_ACTIVE, ST_NCCI_RESETING, EV_NCCI_RESET_B3_REQ, 0},
887 {ST_NCCI_ACTIVE, ST_NCCI_DISCONNECTED, EV_NCCI_DISCONNECT_B3_IND, 0},
888 {ST_NCCI_ACTIVE, ST_NCCI_DISCONNECTING, EV_NCCI_DISCONNECT_B3_REQ, 0},
889 /* N-3 */
890 {ST_NCCI_RESETING, ST_NCCI_ACTIVE, EV_NCCI_RESET_B3_IND, 0},
891 {ST_NCCI_RESETING, ST_NCCI_DISCONNECTED, EV_NCCI_DISCONNECT_B3_IND, 0},
892 {ST_NCCI_RESETING, ST_NCCI_DISCONNECTING, EV_NCCI_DISCONNECT_B3_REQ, 0},
893 /* N-4 */
894 {ST_NCCI_DISCONNECTING, ST_NCCI_DISCONNECTED, EV_NCCI_DISCONNECT_B3_IND, 0},
895 {ST_NCCI_DISCONNECTING, ST_NCCI_PREVIOUS, EV_NCCI_DISCONNECT_B3_CONF_ERROR,0},
896 /* N-5 */
897 {ST_NCCI_DISCONNECTED, ST_NCCI_NONE, EV_NCCI_DISCONNECT_B3_RESP, n0},
901 static void ncci_change_state(capidrv_contr * card, capidrv_ncci * ncci, int event)
903 struct nccistatechange *p = nccitable;
904 while (p->event) {
905 if (ncci->state == p->actstate && p->event == event) {
906 if (debugmode)
907 printk(KERN_DEBUG "capidrv-%d: ncci_change_state:0x%x %d -> %d\n",
908 card->contrnr, ncci->ncci, ncci->state, p->nextstate);
909 if (p->nextstate == ST_NCCI_PREVIOUS) {
910 ncci->state = ncci->oldstate;
911 ncci->oldstate = p->actstate;
912 } else {
913 ncci->oldstate = p->actstate;
914 ncci->state = p->nextstate;
916 if (p->changefunc)
917 p->changefunc(card, ncci);
918 return;
920 p++;
922 printk(KERN_ERR "capidrv-%d: ncci_change_state:0x%x state=%d event=%d ????\n",
923 card->contrnr, ncci->ncci, ncci->state, event);
926 /* ------------------------------------------------------------------- */
928 static inline int new_bchan(capidrv_contr * card)
930 int i;
931 for (i = 0; i < card->nbchan; i++) {
932 if (card->bchans[i].plcip == 0) {
933 card->bchans[i].disconnecting = 0;
934 return i;
937 return -1;
940 /* ------------------------------------------------------------------- */
942 static void handle_controller(_cmsg * cmsg)
944 capidrv_contr *card = findcontrbynumber(cmsg->adr.adrController & 0x7f);
946 if (!card) {
947 printk(KERN_ERR "capidrv: %s from unknown controller 0x%x\n",
948 capi_cmd2str(cmsg->Command, cmsg->Subcommand),
949 cmsg->adr.adrController & 0x7f);
950 return;
952 switch (CAPICMD(cmsg->Command, cmsg->Subcommand)) {
954 case CAPI_LISTEN_CONF: /* Controller */
955 if (debugmode)
956 printk(KERN_DEBUG "capidrv-%d: listenconf Info=0x%4x (%s) cipmask=0x%x\n",
957 card->contrnr, cmsg->Info, capi_info2str(cmsg->Info), card->cipmask);
958 if (cmsg->Info) {
959 listen_change_state(card, EV_LISTEN_CONF_ERROR);
960 } else if (card->cipmask == 0) {
961 listen_change_state(card, EV_LISTEN_CONF_EMPTY);
962 } else {
963 listen_change_state(card, EV_LISTEN_CONF_OK);
965 break;
967 case CAPI_MANUFACTURER_IND: /* Controller */
968 if ( cmsg->ManuID == 0x214D5641
969 && cmsg->Class == 0
970 && cmsg->Function == 1) {
971 __u8 *data = cmsg->ManuData+3;
972 __u16 len = cmsg->ManuData[0];
973 __u16 layer;
974 int direction;
975 if (len == 255) {
976 len = (cmsg->ManuData[1] | (cmsg->ManuData[2] << 8));
977 data += 2;
979 len -= 2;
980 layer = ((*(data-1)) << 8) | *(data-2);
981 if (layer & 0x300)
982 direction = (layer & 0x200) ? 0 : 1;
983 else direction = (layer & 0x800) ? 0 : 1;
984 if (layer & 0x0C00) {
985 if ((layer & 0xff) == 0x80) {
986 handle_dtrace_data(card, direction, 1, data, len);
987 break;
989 } else if ((layer & 0xff) < 0x80) {
990 handle_dtrace_data(card, direction, 0, data, len);
991 break;
993 printk(KERN_INFO "capidrv-%d: %s from controller 0x%x layer 0x%x, ignored\n",
994 card->contrnr,
995 capi_cmd2str(cmsg->Command, cmsg->Subcommand),
996 cmsg->adr.adrController, layer);
997 break;
999 goto ignored;
1000 case CAPI_MANUFACTURER_CONF: /* Controller */
1001 if (cmsg->ManuID == 0x214D5641) {
1002 char *s = 0;
1003 switch (cmsg->Class) {
1004 case 0: break;
1005 case 1: s = "unknown class"; break;
1006 case 2: s = "unknown function"; break;
1007 default: s = "unkown error"; break;
1009 if (s)
1010 printk(KERN_INFO "capidrv-%d: %s from controller 0x%x function %d: %s\n",
1011 card->contrnr,
1012 capi_cmd2str(cmsg->Command, cmsg->Subcommand),
1013 cmsg->adr.adrController,
1014 cmsg->Function, s);
1015 break;
1017 goto ignored;
1018 case CAPI_FACILITY_IND: /* Controller/plci/ncci */
1019 goto ignored;
1020 case CAPI_FACILITY_CONF: /* Controller/plci/ncci */
1021 goto ignored;
1022 case CAPI_INFO_IND: /* Controller/plci */
1023 goto ignored;
1024 case CAPI_INFO_CONF: /* Controller/plci */
1025 goto ignored;
1027 default:
1028 printk(KERN_ERR "capidrv-%d: got %s from controller 0x%x ???",
1029 card->contrnr,
1030 capi_cmd2str(cmsg->Command, cmsg->Subcommand),
1031 cmsg->adr.adrController);
1033 return;
1035 ignored:
1036 printk(KERN_INFO "capidrv-%d: %s from controller 0x%x ignored\n",
1037 card->contrnr,
1038 capi_cmd2str(cmsg->Command, cmsg->Subcommand),
1039 cmsg->adr.adrController);
1042 static void handle_incoming_call(capidrv_contr * card, _cmsg * cmsg)
1044 capidrv_plci *plcip;
1045 capidrv_bchan *bchan;
1046 isdn_ctrl cmd;
1047 int chan;
1049 if ((chan = new_bchan(card)) == -1) {
1050 printk(KERN_ERR "capidrv-%d: incoming call on not existing bchan ?\n", card->contrnr);
1051 return;
1053 bchan = &card->bchans[chan];
1054 if ((plcip = new_plci(card, chan)) == 0) {
1055 printk(KERN_ERR "capidrv-%d: incoming call: no memory, sorry.\n", card->contrnr);
1056 return;
1058 bchan->incoming = 1;
1059 plcip->plci = cmsg->adr.adrPLCI;
1060 plci_change_state(card, plcip, EV_PLCI_CONNECT_IND);
1062 cmd.command = ISDN_STAT_ICALL;
1063 cmd.driver = card->myid;
1064 cmd.arg = chan;
1065 memset(&cmd.parm.setup, 0, sizeof(cmd.parm.setup));
1066 strncpy(cmd.parm.setup.phone,
1067 cmsg->CallingPartyNumber + 3,
1068 cmsg->CallingPartyNumber[0] - 2);
1069 strncpy(cmd.parm.setup.eazmsn,
1070 cmsg->CalledPartyNumber + 2,
1071 cmsg->CalledPartyNumber[0] - 1);
1072 cmd.parm.setup.si1 = cip2si1(cmsg->CIPValue);
1073 cmd.parm.setup.si2 = cip2si2(cmsg->CIPValue);
1074 cmd.parm.setup.plan = cmsg->CallingPartyNumber[1];
1075 cmd.parm.setup.screen = cmsg->CallingPartyNumber[2];
1077 printk(KERN_INFO "capidrv-%d: incoming call %s,%d,%d,%s\n",
1078 card->contrnr,
1079 cmd.parm.setup.phone,
1080 cmd.parm.setup.si1,
1081 cmd.parm.setup.si2,
1082 cmd.parm.setup.eazmsn);
1084 if (cmd.parm.setup.si1 == 1 && cmd.parm.setup.si2 != 0) {
1085 printk(KERN_INFO "capidrv-%d: patching si2=%d to 0 for VBOX\n",
1086 card->contrnr,
1087 cmd.parm.setup.si2);
1088 cmd.parm.setup.si2 = 0;
1091 switch (card->interface.statcallb(&cmd)) {
1092 case 0:
1093 case 3:
1094 /* No device matching this call.
1095 * and isdn_common.c has send a HANGUP command
1096 * which is ignored in state ST_PLCI_INCOMING,
1097 * so we send RESP to ignore the call
1099 capi_cmsg_answer(cmsg);
1100 cmsg->Reject = 1; /* ignore */
1101 send_message(card, cmsg);
1102 plci_change_state(card, plcip, EV_PLCI_CONNECT_REJECT);
1103 printk(KERN_INFO "capidrv-%d: incoming call %s,%d,%d,%s ignored\n",
1104 card->contrnr,
1105 cmd.parm.setup.phone,
1106 cmd.parm.setup.si1,
1107 cmd.parm.setup.si2,
1108 cmd.parm.setup.eazmsn);
1109 break;
1110 case 1:
1111 /* At least one device matching this call (RING on ttyI)
1112 * HL-driver may send ALERTING on the D-channel in this
1113 * case.
1114 * really means: RING on ttyI or a net interface
1115 * accepted this call already.
1117 * If the call was accepted, state has already changed,
1118 * and CONNECT_RESP already sent.
1120 if (plcip->state == ST_PLCI_INCOMING) {
1121 printk(KERN_INFO "capidrv-%d: incoming call %s,%d,%d,%s tty alerting\n",
1122 card->contrnr,
1123 cmd.parm.setup.phone,
1124 cmd.parm.setup.si1,
1125 cmd.parm.setup.si2,
1126 cmd.parm.setup.eazmsn);
1127 capi_fill_ALERT_REQ(cmsg,
1128 global.appid,
1129 card->msgid++,
1130 plcip->plci, /* adr */
1131 0, /* BChannelinformation */
1132 0, /* Keypadfacility */
1133 0, /* Useruserdata */
1134 0 /* Facilitydataarray */
1136 plcip->msgid = cmsg->Messagenumber;
1137 send_message(card, cmsg);
1138 } else {
1139 printk(KERN_INFO "capidrv-%d: incoming call %s,%d,%d,%s on netdev\n",
1140 card->contrnr,
1141 cmd.parm.setup.phone,
1142 cmd.parm.setup.si1,
1143 cmd.parm.setup.si2,
1144 cmd.parm.setup.eazmsn);
1146 break;
1148 case 2: /* Call will be rejected. */
1149 capi_cmsg_answer(cmsg);
1150 cmsg->Reject = 2; /* reject call, normal call clearing */
1151 send_message(card, cmsg);
1152 plci_change_state(card, plcip, EV_PLCI_CONNECT_REJECT);
1153 break;
1155 default:
1156 /* An error happened. (Invalid parameters for example.) */
1157 capi_cmsg_answer(cmsg);
1158 cmsg->Reject = 8; /* reject call,
1159 destination out of order */
1160 send_message(card, cmsg);
1161 plci_change_state(card, plcip, EV_PLCI_CONNECT_REJECT);
1162 break;
1164 return;
1167 static void handle_plci(_cmsg * cmsg)
1169 capidrv_contr *card = findcontrbynumber(cmsg->adr.adrController & 0x7f);
1170 capidrv_plci *plcip;
1171 isdn_ctrl cmd;
1173 if (!card) {
1174 printk(KERN_ERR "capidrv: %s from unknown controller 0x%x\n",
1175 capi_cmd2str(cmsg->Command, cmsg->Subcommand),
1176 cmsg->adr.adrController & 0x7f);
1177 return;
1179 switch (CAPICMD(cmsg->Command, cmsg->Subcommand)) {
1181 case CAPI_DISCONNECT_IND: /* plci */
1182 if (cmsg->Reason) {
1183 printk(KERN_INFO "capidrv-%d: %s reason 0x%x (%s) for plci 0x%x\n",
1184 card->contrnr,
1185 capi_cmd2str(cmsg->Command, cmsg->Subcommand),
1186 cmsg->Reason, capi_info2str(cmsg->Reason), cmsg->adr.adrPLCI);
1188 if (!(plcip = find_plci_by_plci(card, cmsg->adr.adrPLCI))) {
1189 capi_cmsg_answer(cmsg);
1190 send_message(card, cmsg);
1191 goto notfound;
1193 card->bchans[plcip->chan].disconnecting = 1;
1194 plci_change_state(card, plcip, EV_PLCI_DISCONNECT_IND);
1195 capi_cmsg_answer(cmsg);
1196 send_message(card, cmsg);
1197 plci_change_state(card, plcip, EV_PLCI_DISCONNECT_RESP);
1198 break;
1200 case CAPI_DISCONNECT_CONF: /* plci */
1201 if (cmsg->Info) {
1202 printk(KERN_INFO "capidrv-%d: %s info 0x%x (%s) for plci 0x%x\n",
1203 card->contrnr,
1204 capi_cmd2str(cmsg->Command, cmsg->Subcommand),
1205 cmsg->Info, capi_info2str(cmsg->Info),
1206 cmsg->adr.adrPLCI);
1208 if (!(plcip = find_plci_by_plci(card, cmsg->adr.adrPLCI)))
1209 goto notfound;
1211 card->bchans[plcip->chan].disconnecting = 1;
1212 break;
1214 case CAPI_ALERT_CONF: /* plci */
1215 if (cmsg->Info) {
1216 printk(KERN_INFO "capidrv-%d: %s info 0x%x (%s) for plci 0x%x\n",
1217 card->contrnr,
1218 capi_cmd2str(cmsg->Command, cmsg->Subcommand),
1219 cmsg->Info, capi_info2str(cmsg->Info),
1220 cmsg->adr.adrPLCI);
1222 break;
1224 case CAPI_CONNECT_IND: /* plci */
1225 handle_incoming_call(card, cmsg);
1226 break;
1228 case CAPI_CONNECT_CONF: /* plci */
1229 if (cmsg->Info) {
1230 printk(KERN_INFO "capidrv-%d: %s info 0x%x (%s) for plci 0x%x\n",
1231 card->contrnr,
1232 capi_cmd2str(cmsg->Command, cmsg->Subcommand),
1233 cmsg->Info, capi_info2str(cmsg->Info),
1234 cmsg->adr.adrPLCI);
1236 if (!(plcip = find_plci_by_msgid(card, cmsg->Messagenumber)))
1237 goto notfound;
1239 plcip->plci = cmsg->adr.adrPLCI;
1240 if (cmsg->Info) {
1241 plci_change_state(card, plcip, EV_PLCI_CONNECT_CONF_ERROR);
1242 } else {
1243 plci_change_state(card, plcip, EV_PLCI_CONNECT_CONF_OK);
1245 break;
1247 case CAPI_CONNECT_ACTIVE_IND: /* plci */
1249 if (!(plcip = find_plci_by_plci(card, cmsg->adr.adrPLCI)))
1250 goto notfound;
1252 if (card->bchans[plcip->chan].incoming) {
1253 capi_cmsg_answer(cmsg);
1254 send_message(card, cmsg);
1255 plci_change_state(card, plcip, EV_PLCI_CONNECT_ACTIVE_IND);
1256 } else {
1257 capidrv_ncci *nccip;
1258 capi_cmsg_answer(cmsg);
1259 send_message(card, cmsg);
1261 nccip = new_ncci(card, plcip, cmsg->adr.adrPLCI);
1263 if (!nccip) {
1264 printk(KERN_ERR "capidrv-%d: no mem for ncci, sorry\n", card->contrnr);
1265 break; /* $$$$ */
1267 capi_fill_CONNECT_B3_REQ(cmsg,
1268 global.appid,
1269 card->msgid++,
1270 plcip->plci, /* adr */
1271 0 /* NCPI */
1273 nccip->msgid = cmsg->Messagenumber;
1274 send_message(card, cmsg);
1275 cmd.command = ISDN_STAT_DCONN;
1276 cmd.driver = card->myid;
1277 cmd.arg = plcip->chan;
1278 card->interface.statcallb(&cmd);
1279 plci_change_state(card, plcip, EV_PLCI_CONNECT_ACTIVE_IND);
1280 ncci_change_state(card, nccip, EV_NCCI_CONNECT_B3_REQ);
1282 break;
1284 case CAPI_INFO_IND: /* Controller/plci */
1286 if (!(plcip = find_plci_by_plci(card, cmsg->adr.adrPLCI)))
1287 goto notfound;
1289 if (cmsg->InfoNumber == 0x4000) {
1290 if (cmsg->InfoElement[0] == 4) {
1291 cmd.command = ISDN_STAT_CINF;
1292 cmd.driver = card->myid;
1293 cmd.arg = plcip->chan;
1294 sprintf(cmd.parm.num, "%lu",
1295 (unsigned long)
1296 ((__u32) cmsg->InfoElement[1]
1297 | ((__u32) (cmsg->InfoElement[2]) << 8)
1298 | ((__u32) (cmsg->InfoElement[3]) << 16)
1299 | ((__u32) (cmsg->InfoElement[4]) << 24)));
1300 card->interface.statcallb(&cmd);
1301 break;
1304 printk(KERN_ERR "capidrv-%d: %s\n",
1305 card->contrnr, capi_cmsg2str(cmsg));
1306 break;
1308 case CAPI_CONNECT_ACTIVE_CONF: /* plci */
1309 goto ignored;
1310 case CAPI_SELECT_B_PROTOCOL_CONF: /* plci */
1311 goto ignored;
1312 case CAPI_FACILITY_IND: /* Controller/plci/ncci */
1313 goto ignored;
1314 case CAPI_FACILITY_CONF: /* Controller/plci/ncci */
1315 goto ignored;
1317 case CAPI_INFO_CONF: /* Controller/plci */
1318 goto ignored;
1320 default:
1321 printk(KERN_ERR "capidrv-%d: got %s for plci 0x%x ???",
1322 card->contrnr,
1323 capi_cmd2str(cmsg->Command, cmsg->Subcommand),
1324 cmsg->adr.adrPLCI);
1326 return;
1327 ignored:
1328 printk(KERN_INFO "capidrv-%d: %s for plci 0x%x ignored\n",
1329 card->contrnr,
1330 capi_cmd2str(cmsg->Command, cmsg->Subcommand),
1331 cmsg->adr.adrPLCI);
1332 return;
1333 notfound:
1334 printk(KERN_ERR "capidrv-%d: %s: plci 0x%x not found\n",
1335 card->contrnr,
1336 capi_cmd2str(cmsg->Command, cmsg->Subcommand),
1337 cmsg->adr.adrPLCI);
1338 return;
1341 static void handle_ncci(_cmsg * cmsg)
1343 capidrv_contr *card = findcontrbynumber(cmsg->adr.adrController & 0x7f);
1344 capidrv_plci *plcip;
1345 capidrv_ncci *nccip;
1346 isdn_ctrl cmd;
1347 int len;
1349 if (!card) {
1350 printk(KERN_ERR "capidrv: %s from unknown controller 0x%x\n",
1351 capi_cmd2str(cmsg->Command, cmsg->Subcommand),
1352 cmsg->adr.adrController & 0x7f);
1353 return;
1355 switch (CAPICMD(cmsg->Command, cmsg->Subcommand)) {
1357 case CAPI_CONNECT_B3_ACTIVE_IND: /* ncci */
1358 if (!(nccip = find_ncci(card, cmsg->adr.adrNCCI)))
1359 goto notfound;
1361 capi_cmsg_answer(cmsg);
1362 send_message(card, cmsg);
1363 ncci_change_state(card, nccip, EV_NCCI_CONNECT_B3_ACTIVE_IND);
1365 cmd.command = ISDN_STAT_BCONN;
1366 cmd.driver = card->myid;
1367 cmd.arg = nccip->chan;
1368 card->interface.statcallb(&cmd);
1370 printk(KERN_INFO "capidrv-%d: chan %d up with ncci 0x%x\n",
1371 card->contrnr, nccip->chan, nccip->ncci);
1372 break;
1374 case CAPI_CONNECT_B3_ACTIVE_CONF: /* ncci */
1375 goto ignored;
1377 case CAPI_CONNECT_B3_IND: /* ncci */
1379 plcip = find_plci_by_ncci(card, cmsg->adr.adrNCCI);
1380 if (plcip) {
1381 nccip = new_ncci(card, plcip, cmsg->adr.adrNCCI);
1382 if (nccip) {
1383 ncci_change_state(card, nccip, EV_NCCI_CONNECT_B3_IND);
1384 capi_fill_CONNECT_B3_RESP(cmsg,
1385 global.appid,
1386 card->msgid++,
1387 nccip->ncci, /* adr */
1388 0, /* Reject */
1389 0 /* NCPI */
1391 send_message(card, cmsg);
1392 ncci_change_state(card, nccip, EV_NCCI_CONNECT_B3_RESP);
1393 break;
1395 printk(KERN_ERR "capidrv-%d: no mem for ncci, sorry\n", card->contrnr);
1396 } else {
1397 printk(KERN_ERR "capidrv-%d: %s: plci for ncci 0x%x not found\n",
1398 card->contrnr,
1399 capi_cmd2str(cmsg->Command, cmsg->Subcommand),
1400 cmsg->adr.adrNCCI);
1402 capi_fill_CONNECT_B3_RESP(cmsg,
1403 global.appid,
1404 card->msgid++,
1405 cmsg->adr.adrNCCI,
1406 2, /* Reject */
1407 0 /* NCPI */
1409 send_message(card, cmsg);
1410 break;
1412 case CAPI_CONNECT_B3_CONF: /* ncci */
1414 if (!(nccip = find_ncci_by_msgid(card,
1415 cmsg->adr.adrNCCI,
1416 cmsg->Messagenumber)))
1417 goto notfound;
1419 nccip->ncci = cmsg->adr.adrNCCI;
1420 if (cmsg->Info) {
1421 printk(KERN_INFO "capidrv-%d: %s info 0x%x (%s) for ncci 0x%x\n",
1422 card->contrnr,
1423 capi_cmd2str(cmsg->Command, cmsg->Subcommand),
1424 cmsg->Info, capi_info2str(cmsg->Info),
1425 cmsg->adr.adrNCCI);
1428 if (cmsg->Info)
1429 ncci_change_state(card, nccip, EV_NCCI_CONNECT_B3_CONF_ERROR);
1430 else
1431 ncci_change_state(card, nccip, EV_NCCI_CONNECT_B3_CONF_OK);
1432 break;
1434 case CAPI_CONNECT_B3_T90_ACTIVE_IND: /* ncci */
1435 capi_cmsg_answer(cmsg);
1436 send_message(card, cmsg);
1437 break;
1439 case CAPI_DATA_B3_IND: /* ncci */
1440 /* handled in handle_data() */
1441 goto ignored;
1443 case CAPI_DATA_B3_CONF: /* ncci */
1444 if (!(nccip = find_ncci(card, cmsg->adr.adrNCCI)))
1445 goto notfound;
1447 len = capidrv_del_ack(nccip, cmsg->DataHandle);
1448 if (len < 0)
1449 break;
1450 cmd.command = ISDN_STAT_BSENT;
1451 cmd.driver = card->myid;
1452 cmd.arg = nccip->chan;
1453 cmd.parm.length = len;
1454 card->interface.statcallb(&cmd);
1455 break;
1457 case CAPI_DISCONNECT_B3_IND: /* ncci */
1458 if (!(nccip = find_ncci(card, cmsg->adr.adrNCCI)))
1459 goto notfound;
1461 card->bchans[nccip->chan].disconnecting = 1;
1462 ncci_change_state(card, nccip, EV_NCCI_DISCONNECT_B3_IND);
1463 capi_cmsg_answer(cmsg);
1464 send_message(card, cmsg);
1465 ncci_change_state(card, nccip, EV_NCCI_DISCONNECT_B3_RESP);
1466 break;
1468 case CAPI_DISCONNECT_B3_CONF: /* ncci */
1469 if (!(nccip = find_ncci(card, cmsg->adr.adrNCCI)))
1470 goto notfound;
1471 if (cmsg->Info) {
1472 printk(KERN_INFO "capidrv-%d: %s info 0x%x (%s) for ncci 0x%x\n",
1473 card->contrnr,
1474 capi_cmd2str(cmsg->Command, cmsg->Subcommand),
1475 cmsg->Info, capi_info2str(cmsg->Info),
1476 cmsg->adr.adrNCCI);
1477 ncci_change_state(card, nccip, EV_NCCI_DISCONNECT_B3_CONF_ERROR);
1479 break;
1481 case CAPI_RESET_B3_IND: /* ncci */
1482 if (!(nccip = find_ncci(card, cmsg->adr.adrNCCI)))
1483 goto notfound;
1484 ncci_change_state(card, nccip, EV_NCCI_RESET_B3_IND);
1485 capi_cmsg_answer(cmsg);
1486 send_message(card, cmsg);
1487 break;
1489 case CAPI_RESET_B3_CONF: /* ncci */
1490 goto ignored; /* $$$$ */
1492 case CAPI_FACILITY_IND: /* Controller/plci/ncci */
1493 goto ignored;
1494 case CAPI_FACILITY_CONF: /* Controller/plci/ncci */
1495 goto ignored;
1497 default:
1498 printk(KERN_ERR "capidrv-%d: got %s for ncci 0x%x ???",
1499 card->contrnr,
1500 capi_cmd2str(cmsg->Command, cmsg->Subcommand),
1501 cmsg->adr.adrNCCI);
1503 return;
1504 ignored:
1505 printk(KERN_INFO "capidrv-%d: %s for ncci 0x%x ignored\n",
1506 card->contrnr,
1507 capi_cmd2str(cmsg->Command, cmsg->Subcommand),
1508 cmsg->adr.adrNCCI);
1509 return;
1510 notfound:
1511 printk(KERN_ERR "capidrv-%d: %s: ncci 0x%x not found\n",
1512 card->contrnr,
1513 capi_cmd2str(cmsg->Command, cmsg->Subcommand),
1514 cmsg->adr.adrNCCI);
1518 static void handle_data(_cmsg * cmsg, struct sk_buff *skb)
1520 capidrv_contr *card = findcontrbynumber(cmsg->adr.adrController & 0x7f);
1521 capidrv_ncci *nccip;
1523 if (!card) {
1524 printk(KERN_ERR "capidrv: %s from unknown controller 0x%x\n",
1525 capi_cmd2str(cmsg->Command, cmsg->Subcommand),
1526 cmsg->adr.adrController & 0x7f);
1527 kfree_skb(skb);
1528 return;
1530 if (!(nccip = find_ncci(card, cmsg->adr.adrNCCI))) {
1531 printk(KERN_ERR "capidrv-%d: %s: ncci 0x%x not found\n",
1532 card->contrnr,
1533 capi_cmd2str(cmsg->Command, cmsg->Subcommand),
1534 cmsg->adr.adrNCCI);
1535 kfree_skb(skb);
1536 return;
1538 (void) skb_pull(skb, CAPIMSG_LEN(skb->data));
1539 card->interface.rcvcallb_skb(card->myid, nccip->chan, skb);
1540 capi_cmsg_answer(cmsg);
1541 send_message(card, cmsg);
1544 static _cmsg s_cmsg;
1546 static void capidrv_signal(__u16 applid, void *dummy)
1548 struct sk_buff *skb = 0;
1550 while ((*capifuncs->capi_get_message) (global.appid, &skb) == CAPI_NOERROR) {
1551 capi_message2cmsg(&s_cmsg, skb->data);
1552 if (debugmode > 2)
1553 printk(KERN_DEBUG "capidrv_signal: applid=%d %s\n",
1554 applid, capi_cmsg2str(&s_cmsg));
1556 if (s_cmsg.Command == CAPI_DATA_B3
1557 && s_cmsg.Subcommand == CAPI_IND) {
1558 handle_data(&s_cmsg, skb);
1559 global.nrecvdatapkt++;
1560 continue;
1562 if ((s_cmsg.adr.adrController & 0xffffff00) == 0)
1563 handle_controller(&s_cmsg);
1564 else if ((s_cmsg.adr.adrPLCI & 0xffff0000) == 0)
1565 handle_plci(&s_cmsg);
1566 else
1567 handle_ncci(&s_cmsg);
1569 * data of skb used in s_cmsg,
1570 * free data when s_cmsg is not used again
1571 * thanks to Lars Heete <hel@admin.de>
1573 kfree_skb(skb);
1574 global.nrecvctlpkt++;
1578 /* ------------------------------------------------------------------- */
1580 #define PUTBYTE_TO_STATUS(card, byte) \
1581 do { \
1582 *(card)->q931_write++ = (byte); \
1583 if ((card)->q931_write > (card)->q931_end) \
1584 (card)->q931_write = (card)->q931_buf; \
1585 } while (0)
1587 static void handle_dtrace_data(capidrv_contr *card,
1588 int send, int level2, __u8 *data, __u16 len)
1590 __u8 *p, *end;
1591 isdn_ctrl cmd;
1593 if (!len) {
1594 printk(KERN_DEBUG "capidrv-%d: avmb1_q931_data: len == %d\n",
1595 card->contrnr, len);
1596 return;
1599 if (level2) {
1600 PUTBYTE_TO_STATUS(card, 'D');
1601 PUTBYTE_TO_STATUS(card, '2');
1602 PUTBYTE_TO_STATUS(card, send ? '>' : '<');
1603 PUTBYTE_TO_STATUS(card, ':');
1604 } else {
1605 PUTBYTE_TO_STATUS(card, 'D');
1606 PUTBYTE_TO_STATUS(card, '3');
1607 PUTBYTE_TO_STATUS(card, send ? '>' : '<');
1608 PUTBYTE_TO_STATUS(card, ':');
1611 for (p = data, end = data+len; p < end; p++) {
1612 __u8 w;
1613 PUTBYTE_TO_STATUS(card, ' ');
1614 w = (*p >> 4) & 0xf;
1615 PUTBYTE_TO_STATUS(card, (w < 10) ? '0'+w : 'A'-10+w);
1616 w = *p & 0xf;
1617 PUTBYTE_TO_STATUS(card, (w < 10) ? '0'+w : 'A'-10+w);
1619 PUTBYTE_TO_STATUS(card, '\n');
1621 cmd.command = ISDN_STAT_STAVAIL;
1622 cmd.driver = card->myid;
1623 cmd.arg = len*3+5;
1624 card->interface.statcallb(&cmd);
1627 /* ------------------------------------------------------------------- */
1629 static _cmsg cmdcmsg;
1631 static int capidrv_ioctl(isdn_ctrl * c, capidrv_contr * card)
1633 switch (c->arg) {
1634 case 1:
1635 debugmode = (int)(*((unsigned int *)c->parm.num));
1636 printk(KERN_DEBUG "capidrv-%d: debugmode=%d\n",
1637 card->contrnr, debugmode);
1638 return 0;
1639 default:
1640 printk(KERN_DEBUG "capidrv-%d: capidrv_ioctl(%ld) called ??\n",
1641 card->contrnr, c->arg);
1642 return -EINVAL;
1644 return -EINVAL;
1648 * Handle leased lines (CAPI-Bundling)
1651 struct internal_bchannelinfo {
1652 unsigned short channelalloc;
1653 unsigned short operation;
1654 unsigned char cmask[31];
1657 static int decodeFVteln(char *teln, unsigned long *bmaskp, int *activep)
1659 unsigned long bmask = 0;
1660 int active = !0;
1661 char *s;
1662 int i;
1664 if (strncmp(teln, "FV:", 3) != 0)
1665 return 1;
1666 s = teln + 3;
1667 while (*s && *s == ' ') s++;
1668 if (!*s) return -2;
1669 if (*s == 'p' || *s == 'P') {
1670 active = 0;
1671 s++;
1673 if (*s == 'a' || *s == 'A') {
1674 active = !0;
1675 s++;
1677 while (*s) {
1678 int digit1 = 0;
1679 int digit2 = 0;
1680 if (!isdigit(*s)) return -3;
1681 while (isdigit(*s)) { digit1 = digit1*10 + (*s - '0'); s++; }
1682 if (digit1 <= 0 && digit1 > 30) return -4;
1683 if (*s == 0 || *s == ',' || *s == ' ') {
1684 bmask |= (1 << digit1);
1685 digit1 = 0;
1686 if (*s) s++;
1687 continue;
1689 if (*s != '-') return -5;
1690 s++;
1691 if (!isdigit(*s)) return -3;
1692 while (isdigit(*s)) { digit2 = digit2*10 + (*s - '0'); s++; }
1693 if (digit2 <= 0 && digit2 > 30) return -4;
1694 if (*s == 0 || *s == ',' || *s == ' ') {
1695 if (digit1 > digit2)
1696 for (i = digit2; i <= digit1 ; i++)
1697 bmask |= (1 << i);
1698 else
1699 for (i = digit1; i <= digit2 ; i++)
1700 bmask |= (1 << i);
1701 digit1 = digit2 = 0;
1702 if (*s) s++;
1703 continue;
1705 return -6;
1707 if (activep) *activep = active;
1708 if (bmaskp) *bmaskp = bmask;
1709 return 0;
1712 static int FVteln2capi20(char *teln, __u8 AdditionalInfo[1+2+2+31])
1714 unsigned long bmask;
1715 int active;
1716 int rc, i;
1718 rc = decodeFVteln(teln, &bmask, &active);
1719 if (rc) return rc;
1720 /* Length */
1721 AdditionalInfo[0] = 2+2+31;
1722 /* Channel: 3 => use channel allocation */
1723 AdditionalInfo[1] = 3; AdditionalInfo[2] = 0;
1724 /* Operation: 0 => DTE mode, 1 => DCE mode */
1725 if (active) {
1726 AdditionalInfo[3] = 0; AdditionalInfo[4] = 0;
1727 } else {
1728 AdditionalInfo[3] = 1; AdditionalInfo[4] = 0;
1730 /* Channel mask array */
1731 AdditionalInfo[5] = 0; /* no D-Channel */
1732 for (i=1; i <= 30; i++)
1733 AdditionalInfo[5+i] = (bmask & (1 << i)) ? 0xff : 0;
1734 return 0;
1737 static int capidrv_command(isdn_ctrl * c, capidrv_contr * card)
1739 isdn_ctrl cmd;
1740 struct capidrv_bchan *bchan;
1741 struct capidrv_plci *plcip;
1742 __u8 AdditionalInfo[1+2+2+31];
1743 int rc, isleasedline = 0;
1745 if (c->command == ISDN_CMD_IOCTL)
1746 return capidrv_ioctl(c, card);
1748 switch (c->command) {
1749 case ISDN_CMD_DIAL:{
1750 __u8 calling[ISDN_MSNLEN + 3];
1751 __u8 called[ISDN_MSNLEN + 2];
1753 if (debugmode)
1754 printk(KERN_DEBUG "capidrv-%d: ISDN_CMD_DIAL(ch=%ld,\"%s,%d,%d,%s\")\n",
1755 card->contrnr,
1756 c->arg,
1757 c->parm.setup.phone,
1758 c->parm.setup.si1,
1759 c->parm.setup.si2,
1760 c->parm.setup.eazmsn);
1762 bchan = &card->bchans[c->arg % card->nbchan];
1764 if (bchan->plcip) {
1765 printk(KERN_ERR "capidrv-%d: dail ch=%ld,\"%s,%d,%d,%s\" in use (plci=0x%x)\n",
1766 card->contrnr,
1767 c->arg,
1768 c->parm.setup.phone,
1769 c->parm.setup.si1,
1770 c->parm.setup.si2,
1771 c->parm.setup.eazmsn,
1772 bchan->plcip->plci);
1773 return 0;
1775 bchan->si1 = c->parm.setup.si1;
1776 bchan->si2 = c->parm.setup.si2;
1778 strncpy(bchan->num, c->parm.setup.phone, sizeof(bchan->num));
1779 strncpy(bchan->mynum, c->parm.setup.eazmsn, sizeof(bchan->mynum));
1780 rc = FVteln2capi20(bchan->num, AdditionalInfo);
1781 isleasedline = (rc == 0);
1782 if (rc < 0)
1783 printk(KERN_ERR "capidrv-%d: WARNING: illegal leased linedefinition \"%s\"\n", card->contrnr, bchan->num);
1785 if (isleasedline) {
1786 calling[0] = 0;
1787 called[0] = 0;
1788 if (debugmode)
1789 printk(KERN_DEBUG "capidrv-%d: connecting leased line\n", card->contrnr);
1790 } else {
1791 calling[0] = strlen(bchan->mynum) + 2;
1792 calling[1] = 0;
1793 calling[2] = 0x80;
1794 strncpy(calling + 3, bchan->mynum, ISDN_MSNLEN);
1795 called[0] = strlen(bchan->num) + 1;
1796 called[1] = 0x80;
1797 strncpy(called + 2, bchan->num, ISDN_MSNLEN);
1800 capi_fill_CONNECT_REQ(&cmdcmsg,
1801 global.appid,
1802 card->msgid++,
1803 card->contrnr, /* adr */
1804 si2cip(bchan->si1, bchan->si2), /* cipvalue */
1805 called, /* CalledPartyNumber */
1806 calling, /* CallingPartyNumber */
1807 0, /* CalledPartySubaddress */
1808 0, /* CallingPartySubaddress */
1809 b1prot(bchan->l2, bchan->l3), /* B1protocol */
1810 b2prot(bchan->l2, bchan->l3), /* B2protocol */
1811 b3prot(bchan->l2, bchan->l3), /* B3protocol */
1812 b1config(bchan->l2, bchan->l3), /* B1configuration */
1813 0, /* B2configuration */
1814 0, /* B3configuration */
1815 0, /* BC */
1816 0, /* LLC */
1817 0, /* HLC */
1818 /* BChannelinformation */
1819 isleasedline ? AdditionalInfo : 0,
1820 0, /* Keypadfacility */
1821 0, /* Useruserdata */
1822 0 /* Facilitydataarray */
1824 if ((plcip = new_plci(card, (c->arg % card->nbchan))) == 0) {
1825 cmd.command = ISDN_STAT_DHUP;
1826 cmd.driver = card->myid;
1827 cmd.arg = (c->arg % card->nbchan);
1828 card->interface.statcallb(&cmd);
1829 return -1;
1831 plcip->msgid = cmdcmsg.Messagenumber;
1832 plcip->leasedline = isleasedline;
1833 plci_change_state(card, plcip, EV_PLCI_CONNECT_REQ);
1834 send_message(card, &cmdcmsg);
1835 return 0;
1838 case ISDN_CMD_ACCEPTD:
1840 bchan = &card->bchans[c->arg % card->nbchan];
1841 if (debugmode)
1842 printk(KERN_DEBUG "capidrv-%d: ISDN_CMD_ACCEPTD(ch=%ld) l2=%d l3=%d\n",
1843 card->contrnr,
1844 c->arg, bchan->l2, bchan->l3);
1846 capi_fill_CONNECT_RESP(&cmdcmsg,
1847 global.appid,
1848 card->msgid++,
1849 bchan->plcip->plci, /* adr */
1850 0, /* Reject */
1851 b1prot(bchan->l2, bchan->l3), /* B1protocol */
1852 b2prot(bchan->l2, bchan->l3), /* B2protocol */
1853 b3prot(bchan->l2, bchan->l3), /* B3protocol */
1854 b1config(bchan->l2, bchan->l3), /* B1configuration */
1855 0, /* B2configuration */
1856 0, /* B3configuration */
1857 0, /* ConnectedNumber */
1858 0, /* ConnectedSubaddress */
1859 0, /* LLC */
1860 0, /* BChannelinformation */
1861 0, /* Keypadfacility */
1862 0, /* Useruserdata */
1863 0 /* Facilitydataarray */
1865 capi_cmsg2message(&cmdcmsg, cmdcmsg.buf);
1866 plci_change_state(card, bchan->plcip, EV_PLCI_CONNECT_RESP);
1867 send_message(card, &cmdcmsg);
1868 return 0;
1870 case ISDN_CMD_ACCEPTB:
1871 if (debugmode)
1872 printk(KERN_DEBUG "capidrv-%d: ISDN_CMD_ACCEPTB(ch=%ld)\n",
1873 card->contrnr,
1874 c->arg);
1875 return -ENOSYS;
1877 case ISDN_CMD_HANGUP:
1878 if (debugmode)
1879 printk(KERN_DEBUG "capidrv-%d: ISDN_CMD_HANGUP(ch=%ld)\n",
1880 card->contrnr,
1881 c->arg);
1882 bchan = &card->bchans[c->arg % card->nbchan];
1884 if (bchan->disconnecting) {
1885 if (debugmode)
1886 printk(KERN_DEBUG "capidrv-%d: chan %ld already disconnecting ...\n",
1887 card->contrnr,
1888 c->arg);
1889 return 0;
1891 if (bchan->nccip) {
1892 bchan->disconnecting = 1;
1893 capi_fill_DISCONNECT_B3_REQ(&cmdcmsg,
1894 global.appid,
1895 card->msgid++,
1896 bchan->nccip->ncci,
1897 0 /* NCPI */
1899 ncci_change_state(card, bchan->nccip, EV_NCCI_DISCONNECT_B3_REQ);
1900 send_message(card, &cmdcmsg);
1901 return 0;
1902 } else if (bchan->plcip) {
1903 if (bchan->plcip->state == ST_PLCI_INCOMING) {
1905 * just ignore, we a called from
1906 * isdn_status_callback(),
1907 * which will return 0 or 2, this is handled
1908 * by the CONNECT_IND handler
1910 bchan->disconnecting = 1;
1911 return 0;
1912 } else if (bchan->plcip->plci) {
1913 bchan->disconnecting = 1;
1914 capi_fill_DISCONNECT_REQ(&cmdcmsg,
1915 global.appid,
1916 card->msgid++,
1917 bchan->plcip->plci,
1918 0, /* BChannelinformation */
1919 0, /* Keypadfacility */
1920 0, /* Useruserdata */
1921 0 /* Facilitydataarray */
1923 plci_change_state(card, bchan->plcip, EV_PLCI_DISCONNECT_REQ);
1924 send_message(card, &cmdcmsg);
1925 return 0;
1926 } else {
1927 printk(KERN_ERR "capidrv-%d: chan %ld disconnect request while waiting for CONNECT_CONF\n",
1928 card->contrnr,
1929 c->arg);
1930 return -EINVAL;
1933 printk(KERN_ERR "capidrv-%d: chan %ld disconnect request on free channel\n",
1934 card->contrnr,
1935 c->arg);
1936 return -EINVAL;
1937 /* ready */
1939 case ISDN_CMD_SETL2:
1940 if (debugmode)
1941 printk(KERN_DEBUG "capidrv-%d: set L2 on chan %ld to %ld\n",
1942 card->contrnr,
1943 (c->arg & 0xff), (c->arg >> 8));
1944 bchan = &card->bchans[(c->arg & 0xff) % card->nbchan];
1945 bchan->l2 = (c->arg >> 8);
1946 return 0;
1948 case ISDN_CMD_SETL3:
1949 if (debugmode)
1950 printk(KERN_DEBUG "capidrv-%d: set L3 on chan %ld to %ld\n",
1951 card->contrnr,
1952 (c->arg & 0xff), (c->arg >> 8));
1953 bchan = &card->bchans[(c->arg & 0xff) % card->nbchan];
1954 bchan->l3 = (c->arg >> 8);
1955 return 0;
1957 case ISDN_CMD_SETEAZ:
1958 if (debugmode)
1959 printk(KERN_DEBUG "capidrv-%d: set EAZ \"%s\" on chan %ld\n",
1960 card->contrnr,
1961 c->parm.num, c->arg);
1962 bchan = &card->bchans[c->arg % card->nbchan];
1963 strncpy(bchan->msn, c->parm.num, ISDN_MSNLEN);
1964 return 0;
1966 case ISDN_CMD_CLREAZ:
1967 if (debugmode)
1968 printk(KERN_DEBUG "capidrv-%d: clearing EAZ on chan %ld\n",
1969 card->contrnr, c->arg);
1970 bchan = &card->bchans[c->arg % card->nbchan];
1971 bchan->msn[0] = 0;
1972 return 0;
1974 case ISDN_CMD_LOCK:
1975 if (debugmode > 1)
1976 printk(KERN_DEBUG "capidrv-%d: ISDN_CMD_LOCK (%ld)\n", card->contrnr, c->arg);
1977 MOD_INC_USE_COUNT;
1978 break;
1980 case ISDN_CMD_UNLOCK:
1981 if (debugmode > 1)
1982 printk(KERN_DEBUG "capidrv-%d: ISDN_CMD_UNLOCK (%ld)\n",
1983 card->contrnr, c->arg);
1984 MOD_DEC_USE_COUNT;
1985 break;
1987 /* never called */
1988 case ISDN_CMD_GETL2:
1989 if (debugmode)
1990 printk(KERN_DEBUG "capidrv-%d: ISDN_CMD_GETL2\n",
1991 card->contrnr);
1992 return -ENODEV;
1993 case ISDN_CMD_GETL3:
1994 if (debugmode)
1995 printk(KERN_DEBUG "capidrv-%d: ISDN_CMD_GETL3\n",
1996 card->contrnr);
1997 return -ENODEV;
1998 case ISDN_CMD_GETEAZ:
1999 if (debugmode)
2000 printk(KERN_DEBUG "capidrv-%d: ISDN_CMD_GETEAZ\n",
2001 card->contrnr);
2002 return -ENODEV;
2003 case ISDN_CMD_SETSIL:
2004 if (debugmode)
2005 printk(KERN_DEBUG "capidrv-%d: ISDN_CMD_SETSIL\n",
2006 card->contrnr);
2007 return -ENODEV;
2008 case ISDN_CMD_GETSIL:
2009 if (debugmode)
2010 printk(KERN_DEBUG "capidrv-%d: ISDN_CMD_GETSIL\n",
2011 card->contrnr);
2012 return -ENODEV;
2013 default:
2014 printk(KERN_ERR "capidrv-%d: ISDN_CMD_%d, Huh?\n",
2015 card->contrnr, c->command);
2016 return -EINVAL;
2018 return 0;
2021 static int if_command(isdn_ctrl * c)
2023 capidrv_contr *card = findcontrbydriverid(c->driver);
2025 if (card)
2026 return capidrv_command(c, card);
2028 printk(KERN_ERR
2029 "capidrv: if_command %d called with invalid driverId %d!\n",
2030 c->command, c->driver);
2031 return -ENODEV;
2034 static _cmsg sendcmsg;
2036 static int if_sendbuf(int id, int channel, int doack, struct sk_buff *skb)
2038 capidrv_contr *card = findcontrbydriverid(id);
2039 capidrv_bchan *bchan;
2040 capidrv_ncci *nccip;
2041 int len = skb->len;
2042 size_t msglen;
2043 __u16 errcode;
2044 __u16 datahandle;
2046 if (!card) {
2047 printk(KERN_ERR "capidrv-%d: if_sendbuf called with invalid driverId %d!\n",
2048 card->contrnr, id);
2049 return 0;
2051 if (debugmode > 1)
2052 printk(KERN_DEBUG "capidrv-%d: sendbuf len=%d skb=%p doack=%d\n",
2053 card->contrnr, len, skb, doack);
2054 bchan = &card->bchans[channel % card->nbchan];
2055 nccip = bchan->nccip;
2056 if (!nccip || nccip->state != ST_NCCI_ACTIVE) {
2057 printk(KERN_ERR "capidrv-%d: if_sendbuf: %s:%d: chan not up!\n",
2058 card->contrnr, card->name, channel);
2059 return 0;
2061 datahandle = nccip->datahandle;
2062 capi_fill_DATA_B3_REQ(&sendcmsg, global.appid, card->msgid++,
2063 nccip->ncci, /* adr */
2064 (__u32) skb->data, /* Data */
2065 skb->len, /* DataLength */
2066 datahandle, /* DataHandle */
2067 0 /* Flags */
2070 if (capidrv_add_ack(nccip, datahandle, doack ? skb->len : -1) < 0)
2071 return 0;
2073 capi_cmsg2message(&sendcmsg, sendcmsg.buf);
2074 msglen = CAPIMSG_LEN(sendcmsg.buf);
2075 if (skb_headroom(skb) < msglen) {
2076 struct sk_buff *nskb = skb_realloc_headroom(skb, msglen);
2077 if (!nskb) {
2078 printk(KERN_ERR "capidrv-%d: if_sendbuf: no memory\n",
2079 card->contrnr);
2080 (void)capidrv_del_ack(nccip, datahandle);
2081 return 0;
2083 printk(KERN_DEBUG "capidrv-%d: only %d bytes headroom, need %d\n",
2084 card->contrnr, skb_headroom(skb), msglen);
2085 memcpy(skb_push(nskb, msglen), sendcmsg.buf, msglen);
2086 errcode = (*capifuncs->capi_put_message) (global.appid, nskb);
2087 if (errcode == CAPI_NOERROR) {
2088 dev_kfree_skb(skb);
2089 nccip->datahandle++;
2090 global.nsentdatapkt++;
2091 return len;
2093 (void)capidrv_del_ack(nccip, datahandle);
2094 dev_kfree_skb(nskb);
2095 return errcode == CAPI_SENDQUEUEFULL ? 0 : -1;
2096 } else {
2097 memcpy(skb_push(skb, msglen), sendcmsg.buf, msglen);
2098 errcode = (*capifuncs->capi_put_message) (global.appid, skb);
2099 if (errcode == CAPI_NOERROR) {
2100 nccip->datahandle++;
2101 global.nsentdatapkt++;
2102 return len;
2104 skb_pull(skb, msglen);
2105 (void)capidrv_del_ack(nccip, datahandle);
2106 return errcode == CAPI_SENDQUEUEFULL ? 0 : -1;
2110 static int if_readstat(__u8 *buf, int len, int user, int id, int channel)
2112 capidrv_contr *card = findcontrbydriverid(id);
2113 int count;
2114 __u8 *p;
2116 if (!card) {
2117 printk(KERN_ERR "capidrv-%d: if_readstat called with invalid driverId %d!\n",
2118 card->contrnr, id);
2119 return -ENODEV;
2122 for (p=buf, count=0; count < len; p++, count++) {
2123 if (user)
2124 put_user(*card->q931_read++, p);
2125 else
2126 *p = *card->q931_read++;
2127 if (card->q931_read > card->q931_end)
2128 card->q931_read = card->q931_buf;
2130 return count;
2134 static void enable_dchannel_trace(capidrv_contr *card)
2136 __u8 manufacturer[CAPI_MANUFACTURER_LEN];
2137 capi_version version;
2138 __u16 contr = card->contrnr;
2139 __u16 errcode;
2140 __u16 avmversion[3];
2142 errcode = (*capifuncs->capi_get_manufacturer)(contr, manufacturer);
2143 if (errcode != CAPI_NOERROR) {
2144 printk(KERN_ERR "%s: can't get manufacturer (0x%x)\n",
2145 card->name, errcode);
2146 return;
2148 if (strstr(manufacturer, "AVM") == 0) {
2149 printk(KERN_ERR "%s: not from AVM, no d-channel trace possible (%s)\n",
2150 card->name, manufacturer);
2151 return;
2153 errcode = (*capifuncs->capi_get_version)(contr, &version);
2154 if (errcode != CAPI_NOERROR) {
2155 printk(KERN_ERR "%s: can't get version (0x%x)\n",
2156 card->name, errcode);
2157 return;
2159 avmversion[0] = (version.majormanuversion >> 4) & 0x0f;
2160 avmversion[1] = (version.majormanuversion << 4) & 0xf0;
2161 avmversion[1] |= (version.minormanuversion >> 4) & 0x0f;
2162 avmversion[2] |= version.minormanuversion & 0x0f;
2164 if (avmversion[0] > 3 || (avmversion[0] == 3 && avmversion[1] > 5)) {
2165 printk(KERN_INFO "%s: D2 trace enabled\n", card->name);
2166 capi_fill_MANUFACTURER_REQ(&cmdcmsg, global.appid,
2167 card->msgid++,
2168 contr,
2169 0x214D5641, /* ManuID */
2170 0, /* Class */
2171 1, /* Function */
2172 (_cstruct)"\004\200\014\000\000");
2173 } else {
2174 printk(KERN_INFO "%s: D3 trace enabled\n", card->name);
2175 capi_fill_MANUFACTURER_REQ(&cmdcmsg, global.appid,
2176 card->msgid++,
2177 contr,
2178 0x214D5641, /* ManuID */
2179 0, /* Class */
2180 1, /* Function */
2181 (_cstruct)"\004\002\003\000\000");
2183 send_message(card, &cmdcmsg);
2187 static void send_listen(capidrv_contr *card)
2189 capi_fill_LISTEN_REQ(&cmdcmsg, global.appid,
2190 card->msgid++,
2191 card->contrnr, /* controller */
2192 1 << 6, /* Infomask */
2193 card->cipmask,
2194 card->cipmask2,
2195 0, 0);
2196 send_message(card, &cmdcmsg);
2197 listen_change_state(card, EV_LISTEN_REQ);
2200 static void listentimerfunc(unsigned long x)
2202 capidrv_contr *card = (capidrv_contr *)x;
2203 if (card->state != ST_LISTEN_NONE && card->state != ST_LISTEN_ACTIVE)
2204 printk(KERN_ERR "%s: controller dead ??\n", card->name);
2205 send_listen(card);
2206 mod_timer(&card->listentimer, jiffies + 60*HZ);
2210 static int capidrv_addcontr(__u16 contr, struct capi_profile *profp)
2212 capidrv_contr *card;
2213 long flags;
2214 isdn_ctrl cmd;
2215 char id[20];
2216 int i;
2218 MOD_INC_USE_COUNT;
2220 sprintf(id, "capidrv-%d", contr);
2221 if (!(card = (capidrv_contr *) kmalloc(sizeof(capidrv_contr), GFP_ATOMIC))) {
2222 printk(KERN_WARNING
2223 "capidrv: (%s) Could not allocate contr-struct.\n", id);
2224 MOD_DEC_USE_COUNT;
2225 return -1;
2227 memset(card, 0, sizeof(capidrv_contr));
2228 init_timer(&card->listentimer);
2229 strcpy(card->name, id);
2230 card->contrnr = contr;
2231 card->nbchan = profp->nbchannel;
2232 card->bchans = (capidrv_bchan *) kmalloc(sizeof(capidrv_bchan) * card->nbchan, GFP_ATOMIC);
2233 if (!card->bchans) {
2234 printk(KERN_WARNING
2235 "capidrv: (%s) Could not allocate bchan-structs.\n", id);
2236 kfree(card);
2237 MOD_DEC_USE_COUNT;
2238 return -1;
2240 card->interface.channels = profp->nbchannel;
2241 card->interface.maxbufsize = 2048;
2242 card->interface.command = if_command;
2243 card->interface.writebuf_skb = if_sendbuf;
2244 card->interface.writecmd = 0;
2245 card->interface.readstat = if_readstat;
2246 card->interface.features = ISDN_FEATURE_L2_HDLC |
2247 ISDN_FEATURE_L2_TRANS |
2248 ISDN_FEATURE_L3_TRANS |
2249 ISDN_FEATURE_P_UNKNOWN |
2250 ISDN_FEATURE_L2_X75I |
2251 ISDN_FEATURE_L2_X75UI |
2252 ISDN_FEATURE_L2_X75BUI;
2253 if (profp->support1 & (1<<2))
2254 card->interface.features |= ISDN_FEATURE_L2_V11096 |
2255 ISDN_FEATURE_L2_V11019 |
2256 ISDN_FEATURE_L2_V11038;
2257 if (profp->support1 & (1<<8))
2258 card->interface.features |= ISDN_FEATURE_L2_MODEM;
2259 card->interface.hl_hdrlen = 22; /* len of DATA_B3_REQ */
2260 strncpy(card->interface.id, id, sizeof(card->interface.id) - 1);
2263 card->q931_read = card->q931_buf;
2264 card->q931_write = card->q931_buf;
2265 card->q931_end = card->q931_buf + sizeof(card->q931_buf) - 1;
2267 if (!register_isdn(&card->interface)) {
2268 printk(KERN_ERR "capidrv: Unable to register contr %s\n", id);
2269 kfree(card->bchans);
2270 kfree(card);
2271 MOD_DEC_USE_COUNT;
2272 return -1;
2274 card->myid = card->interface.channels;
2276 spin_lock_irqsave(&global_lock, flags);
2277 card->next = global.contr_list;
2278 global.contr_list = card;
2279 global.ncontr++;
2280 spin_unlock_irqrestore(&global_lock, flags);
2282 memset(card->bchans, 0, sizeof(capidrv_bchan) * card->nbchan);
2283 for (i = 0; i < card->nbchan; i++) {
2284 card->bchans[i].contr = card;
2287 cmd.command = ISDN_STAT_RUN;
2288 cmd.driver = card->myid;
2289 card->interface.statcallb(&cmd);
2291 card->cipmask = 0x1FFF03FF; /* any */
2292 card->cipmask2 = 0;
2294 send_listen(card);
2296 card->listentimer.data = (unsigned long)card;
2297 card->listentimer.function = listentimerfunc;
2298 mod_timer(&card->listentimer, jiffies + 60*HZ);
2300 printk(KERN_INFO "%s: now up (%d B channels)\n",
2301 card->name, card->nbchan);
2303 enable_dchannel_trace(card);
2305 return 0;
2308 static int capidrv_delcontr(__u16 contr)
2310 capidrv_contr **pp, *card;
2311 unsigned long flags;
2312 isdn_ctrl cmd;
2314 spin_lock_irqsave(&global_lock, flags);
2315 for (card = global.contr_list; card; card = card->next) {
2316 if (card->contrnr == contr)
2317 break;
2319 if (!card) {
2320 spin_unlock_irqrestore(&global_lock, flags);
2321 printk(KERN_ERR "capidrv: delcontr: no contr %u\n", contr);
2322 return -1;
2324 spin_unlock_irqrestore(&global_lock, flags);
2326 del_timer(&card->listentimer);
2328 if (debugmode)
2329 printk(KERN_DEBUG "capidrv-%d: id=%d unloading\n",
2330 card->contrnr, card->myid);
2332 cmd.command = ISDN_STAT_STOP;
2333 cmd.driver = card->myid;
2334 card->interface.statcallb(&cmd);
2336 while (card->nbchan) {
2338 cmd.command = ISDN_STAT_DISCH;
2339 cmd.driver = card->myid;
2340 cmd.arg = card->nbchan-1;
2341 cmd.parm.num[0] = 0;
2342 if (debugmode)
2343 printk(KERN_DEBUG "capidrv-%d: id=%d disable chan=%ld\n",
2344 card->contrnr, card->myid, cmd.arg);
2345 card->interface.statcallb(&cmd);
2347 if (card->bchans[card->nbchan-1].nccip)
2348 free_ncci(card, card->bchans[card->nbchan-1].nccip);
2349 if (card->bchans[card->nbchan-1].plcip)
2350 free_plci(card, card->bchans[card->nbchan-1].plcip);
2351 if (card->plci_list)
2352 printk(KERN_ERR "capidrv: bug in free_plci()\n");
2353 card->nbchan--;
2355 kfree(card->bchans);
2356 card->bchans = 0;
2358 if (debugmode)
2359 printk(KERN_DEBUG "capidrv-%d: id=%d isdn unload\n",
2360 card->contrnr, card->myid);
2362 cmd.command = ISDN_STAT_UNLOAD;
2363 cmd.driver = card->myid;
2364 card->interface.statcallb(&cmd);
2366 if (debugmode)
2367 printk(KERN_DEBUG "capidrv-%d: id=%d remove contr from list\n",
2368 card->contrnr, card->myid);
2370 spin_lock_irqsave(&global_lock, flags);
2371 for (pp = &global.contr_list; *pp; pp = &(*pp)->next) {
2372 if (*pp == card) {
2373 *pp = (*pp)->next;
2374 card->next = 0;
2375 global.ncontr--;
2376 break;
2379 spin_unlock_irqrestore(&global_lock, flags);
2381 printk(KERN_INFO "%s: now down.\n", card->name);
2383 kfree(card);
2385 MOD_DEC_USE_COUNT;
2387 return 0;
2391 static void lower_callback(unsigned int cmd, __u32 contr, void *data)
2394 switch (cmd) {
2395 case KCI_CONTRUP:
2396 printk(KERN_INFO "capidrv: controller %hu up\n", contr);
2397 (void) capidrv_addcontr(contr, (capi_profile *) data);
2398 break;
2399 case KCI_CONTRDOWN:
2400 printk(KERN_INFO "capidrv: controller %hu down\n", contr);
2401 (void) capidrv_delcontr(contr);
2402 break;
2407 * /proc/capi/capidrv:
2408 * nrecvctlpkt nrecvdatapkt nsendctlpkt nsenddatapkt
2410 static int proc_capidrv_read_proc(char *page, char **start, off_t off,
2411 int count, int *eof, void *data)
2413 int len = 0;
2415 len += sprintf(page+len, "%lu %lu %lu %lu\n",
2416 global.nrecvctlpkt,
2417 global.nrecvdatapkt,
2418 global.nsentctlpkt,
2419 global.nsentdatapkt);
2420 if (off+count >= len)
2421 *eof = 1;
2422 if (len < off)
2423 return 0;
2424 *start = page + off;
2425 return ((count < len-off) ? count : len-off);
2428 static struct procfsentries {
2429 char *name;
2430 mode_t mode;
2431 int (*read_proc)(char *page, char **start, off_t off,
2432 int count, int *eof, void *data);
2433 struct proc_dir_entry *procent;
2434 } procfsentries[] = {
2435 /* { "capi", S_IFDIR, 0 }, */
2436 { "capi/capidrv", 0 , proc_capidrv_read_proc },
2439 static void proc_init(void)
2441 int nelem = sizeof(procfsentries)/sizeof(procfsentries[0]);
2442 int i;
2444 for (i=0; i < nelem; i++) {
2445 struct procfsentries *p = procfsentries + i;
2446 p->procent = create_proc_entry(p->name, p->mode, 0);
2447 if (p->procent) p->procent->read_proc = p->read_proc;
2451 static void proc_exit(void)
2453 int nelem = sizeof(procfsentries)/sizeof(procfsentries[0]);
2454 int i;
2456 for (i=nelem-1; i >= 0; i--) {
2457 struct procfsentries *p = procfsentries + i;
2458 if (p->procent) {
2459 remove_proc_entry(p->name, 0);
2460 p->procent = 0;
2465 static struct capi_interface_user cuser = {
2466 "capidrv",
2467 lower_callback
2470 #ifdef MODULE
2471 #define capidrv_init init_module
2472 #endif
2474 int capidrv_init(void)
2476 struct capi_register_params rparam;
2477 capi_profile profile;
2478 char rev[10];
2479 char *p;
2480 __u32 ncontr, contr;
2481 __u16 errcode;
2483 MOD_INC_USE_COUNT;
2485 capifuncs = attach_capi_interface(&cuser);
2487 if (!capifuncs) {
2488 MOD_DEC_USE_COUNT;
2489 return -EIO;
2492 if ((p = strchr(revision, ':'))) {
2493 strcpy(rev, p + 1);
2494 p = strchr(rev, '$');
2495 *p = 0;
2496 } else
2497 strcpy(rev, " ??? ");
2499 rparam.level3cnt = -2; /* number of bchannels twice */
2500 rparam.datablkcnt = 16;
2501 rparam.datablklen = 2048;
2502 errcode = (*capifuncs->capi_register) (&rparam, &global.appid);
2503 if (errcode) {
2504 detach_capi_interface(&cuser);
2505 MOD_DEC_USE_COUNT;
2506 return -EIO;
2509 errcode = (*capifuncs->capi_get_profile) (0, &profile);
2510 if (errcode != CAPI_NOERROR) {
2511 (void) (*capifuncs->capi_release) (global.appid);
2512 detach_capi_interface(&cuser);
2513 MOD_DEC_USE_COUNT;
2514 return -EIO;
2517 (void) (*capifuncs->capi_set_signal) (global.appid, capidrv_signal, 0);
2519 ncontr = profile.ncontroller;
2520 for (contr = 1; contr <= ncontr; contr++) {
2521 errcode = (*capifuncs->capi_get_profile) (contr, &profile);
2522 if (errcode != CAPI_NOERROR)
2523 continue;
2524 (void) capidrv_addcontr(contr, &profile);
2526 proc_init();
2528 printk(KERN_NOTICE "capidrv: Rev%s: loaded\n", rev);
2529 MOD_DEC_USE_COUNT;
2531 return 0;
2534 #ifdef MODULE
2535 void cleanup_module(void)
2537 char rev[10];
2538 char *p;
2540 if ((p = strchr(revision, ':')) != 0) {
2541 strcpy(rev, p + 1);
2542 p = strchr(rev, '$');
2543 *p = 0;
2544 } else {
2545 strcpy(rev, " ??? ");
2548 (void) (*capifuncs->capi_release) (global.appid);
2550 detach_capi_interface(&cuser);
2552 proc_exit();
2554 printk(KERN_NOTICE "capidrv: Rev%s: unloaded\n", rev);
2557 #endif