1 /* $Id: capidrv.c,v 1.1.4.1 2001/11/20 14:19:34 kai Exp $
3 * ISDN4Linux Driver, using capi20 interface (kernelcapi)
5 * Copyright 1997 by Carsten Paeth <calle@calle.de>
7 * This software may be used and distributed according to the terms
8 * of the GNU General Public License, incorporated herein by reference.
12 #include <linux/module.h>
13 #include <linux/errno.h>
14 #include <linux/kernel.h>
15 #include <linux/major.h>
16 #include <linux/sched.h>
17 #include <linux/slab.h>
18 #include <linux/fcntl.h>
20 #include <linux/signal.h>
22 #include <linux/timer.h>
23 #include <linux/wait.h>
24 #include <linux/skbuff.h>
25 #include <linux/isdn.h>
26 #include <linux/isdnif.h>
27 #include <linux/proc_fs.h>
28 #include <linux/capi.h>
29 #include <linux/kernelcapi.h>
30 #include <linux/ctype.h>
31 #include <linux/init.h>
32 #include <asm/segment.h>
38 static char *revision = "$Revision: 1.1.4.1 $";
39 static int debugmode = 0;
41 MODULE_DESCRIPTION("CAPI4Linux: Interface to ISDN4Linux");
42 MODULE_AUTHOR("Carsten Paeth");
43 MODULE_LICENSE("GPL");
44 MODULE_PARM(debugmode, "i");
46 /* -------- type definitions ----------------------------------------- */
49 struct capidrv_contr {
51 struct capidrv_contr *next;
68 struct timer_list listentimer;
71 * ID of capi message sent
79 struct capidrv_bchan {
80 struct capidrv_contr *contr;
81 __u8 msn[ISDN_MSNLEN];
84 __u8 num[ISDN_MSNLEN];
85 __u8 mynum[ISDN_MSNLEN];
91 struct capidrv_plci *next;
93 __u32 ncci; /* ncci for CONNECT_ACTIVE_IND */
94 __u16 msgid; /* to identfy CONNECT_CONF */
99 struct capidrv_ncci *next;
100 struct capidrv_plci *plcip;
102 __u16 msgid; /* to identfy CONNECT_B3_CONF */
109 struct ncci_datahandle_queue {
110 struct ncci_datahandle_queue *next;
116 struct capidrv_ncci *nccip;
119 struct capidrv_plci *plci_list;
129 struct capidrv_data {
132 struct capidrv_contr *contr_list;
135 unsigned long nrecvctlpkt;
136 unsigned long nrecvdatapkt;
137 unsigned long nsentctlpkt;
138 unsigned long nsentdatapkt;
141 typedef struct capidrv_plci capidrv_plci;
142 typedef struct capidrv_ncci capidrv_ncci;
143 typedef struct capidrv_contr capidrv_contr;
144 typedef struct capidrv_data capidrv_data;
145 typedef struct capidrv_bchan capidrv_bchan;
147 /* -------- data definitions ----------------------------------------- */
149 static capidrv_data global;
150 static spinlock_t global_lock = SPIN_LOCK_UNLOCKED;
151 static struct capi_interface *capifuncs;
153 static void handle_dtrace_data(capidrv_contr *card,
154 int send, int level2, __u8 *data, __u16 len);
156 /* -------- convert functions ---------------------------------------- */
158 static inline __u32 b1prot(int l2, int l3)
161 case ISDN_PROTO_L2_X75I:
162 case ISDN_PROTO_L2_X75UI:
163 case ISDN_PROTO_L2_X75BUI:
165 case ISDN_PROTO_L2_HDLC:
168 case ISDN_PROTO_L2_TRANS:
170 case ISDN_PROTO_L2_V11096:
171 case ISDN_PROTO_L2_V11019:
172 case ISDN_PROTO_L2_V11038:
174 case ISDN_PROTO_L2_FAX:
176 case ISDN_PROTO_L2_MODEM:
181 static inline __u32 b2prot(int l2, int l3)
184 case ISDN_PROTO_L2_X75I:
185 case ISDN_PROTO_L2_X75UI:
186 case ISDN_PROTO_L2_X75BUI:
189 case ISDN_PROTO_L2_HDLC:
190 case ISDN_PROTO_L2_TRANS:
191 case ISDN_PROTO_L2_V11096:
192 case ISDN_PROTO_L2_V11019:
193 case ISDN_PROTO_L2_V11038:
194 case ISDN_PROTO_L2_MODEM:
196 case ISDN_PROTO_L2_FAX:
201 static inline __u32 b3prot(int l2, int l3)
204 case ISDN_PROTO_L2_X75I:
205 case ISDN_PROTO_L2_X75UI:
206 case ISDN_PROTO_L2_X75BUI:
207 case ISDN_PROTO_L2_HDLC:
208 case ISDN_PROTO_L2_TRANS:
209 case ISDN_PROTO_L2_V11096:
210 case ISDN_PROTO_L2_V11019:
211 case ISDN_PROTO_L2_V11038:
212 case ISDN_PROTO_L2_MODEM:
215 case ISDN_PROTO_L2_FAX:
220 static _cstruct b1config_async_v110(__u16 rate)
222 /* CAPI-Spec "B1 Configuration" */
223 static unsigned char buf[9];
224 buf[0] = 8; /* len */
225 /* maximum bitrate */
226 buf[1] = rate & 0xff; buf[2] = (rate >> 8) & 0xff;
227 buf[3] = 8; buf[4] = 0; /* 8 bits per character */
228 buf[5] = 0; buf[6] = 0; /* parity none */
229 buf[7] = 0; buf[8] = 0; /* 1 stop bit */
233 static _cstruct b1config(int l2, int l3)
236 case ISDN_PROTO_L2_X75I:
237 case ISDN_PROTO_L2_X75UI:
238 case ISDN_PROTO_L2_X75BUI:
239 case ISDN_PROTO_L2_HDLC:
240 case ISDN_PROTO_L2_TRANS:
243 case ISDN_PROTO_L2_V11096:
244 return b1config_async_v110(9600);
245 case ISDN_PROTO_L2_V11019:
246 return b1config_async_v110(19200);
247 case ISDN_PROTO_L2_V11038:
248 return b1config_async_v110(38400);
252 static inline __u16 si2cip(__u8 si1, __u8 si2)
254 static const __u8 cip[17][5] =
257 {0, 0, 0, 0, 0}, /*0 */
258 {16, 16, 4, 26, 16}, /*1 */
259 {17, 17, 17, 4, 4}, /*2 */
260 {2, 2, 2, 2, 2}, /*3 */
261 {18, 18, 18, 18, 18}, /*4 */
262 {2, 2, 2, 2, 2}, /*5 */
263 {0, 0, 0, 0, 0}, /*6 */
264 {2, 2, 2, 2, 2}, /*7 */
265 {2, 2, 2, 2, 2}, /*8 */
266 {21, 21, 21, 21, 21}, /*9 */
267 {19, 19, 19, 19, 19}, /*10 */
268 {0, 0, 0, 0, 0}, /*11 */
269 {0, 0, 0, 0, 0}, /*12 */
270 {0, 0, 0, 0, 0}, /*13 */
271 {0, 0, 0, 0, 0}, /*14 */
272 {22, 22, 22, 22, 22}, /*15 */
273 {27, 27, 27, 28, 27} /*16 */
280 return (__u16) cip[si1][si2];
283 static inline __u8 cip2si1(__u16 cipval)
285 static const __u8 si[32] =
286 {7, 1, 7, 7, 1, 1, 7, 7, /*0-7 */
287 7, 1, 0, 0, 0, 0, 0, 0, /*8-15 */
288 1, 2, 4, 10, 9, 9, 15, 7, /*16-23 */
289 7, 7, 1, 16, 16, 0, 0, 0}; /*24-31 */
292 cipval = 0; /* .... */
296 static inline __u8 cip2si2(__u16 cipval)
298 static const __u8 si[32] =
299 {0, 0, 0, 0, 2, 3, 0, 0, /*0-7 */
300 0, 3, 0, 0, 0, 0, 0, 0, /*8-15 */
301 1, 2, 0, 0, 9, 0, 0, 0, /*16-23 */
302 0, 0, 3, 2, 3, 0, 0, 0}; /*24-31 */
305 cipval = 0; /* .... */
310 /* -------- controller management ------------------------------------- */
312 static inline capidrv_contr *findcontrbydriverid(int driverid)
317 spin_lock_irqsave(&global_lock, flags);
318 for (p = global.contr_list; p; p = p->next)
319 if (p->myid == driverid)
321 spin_unlock_irqrestore(&global_lock, flags);
325 static capidrv_contr *findcontrbynumber(__u32 contr)
328 capidrv_contr *p = global.contr_list;
330 spin_lock_irqsave(&global_lock, flags);
331 for (p = global.contr_list; p; p = p->next)
332 if (p->contrnr == contr)
334 spin_unlock_irqrestore(&global_lock, flags);
339 /* -------- plci management ------------------------------------------ */
341 static capidrv_plci *new_plci(capidrv_contr * card, int chan)
345 plcip = (capidrv_plci *) kmalloc(sizeof(capidrv_plci), GFP_ATOMIC);
350 memset(plcip, 0, sizeof(capidrv_plci));
351 plcip->state = ST_PLCI_NONE;
355 plcip->next = card->plci_list;
356 card->plci_list = plcip;
357 card->bchans[chan].plcip = plcip;
362 static capidrv_plci *find_plci_by_plci(capidrv_contr * card, __u32 plci)
365 for (p = card->plci_list; p; p = p->next)
371 static capidrv_plci *find_plci_by_msgid(capidrv_contr * card, __u16 msgid)
374 for (p = card->plci_list; p; p = p->next)
375 if (p->msgid == msgid)
380 static capidrv_plci *find_plci_by_ncci(capidrv_contr * card, __u32 ncci)
383 for (p = card->plci_list; p; p = p->next)
384 if (p->plci == (ncci & 0xffff))
389 static void free_plci(capidrv_contr * card, capidrv_plci * plcip)
393 for (pp = &card->plci_list; *pp; pp = &(*pp)->next) {
396 card->bchans[plcip->chan].plcip = 0;
397 card->bchans[plcip->chan].disconnecting = 0;
398 card->bchans[plcip->chan].incoming = 0;
403 printk(KERN_ERR "capidrv-%d: free_plci %p (0x%x) not found, Huh?\n",
404 card->contrnr, plcip, plcip->plci);
407 /* -------- ncci management ------------------------------------------ */
409 static inline capidrv_ncci *new_ncci(capidrv_contr * card,
410 capidrv_plci * plcip,
415 nccip = (capidrv_ncci *) kmalloc(sizeof(capidrv_ncci), GFP_ATOMIC);
420 memset(nccip, 0, sizeof(capidrv_ncci));
422 nccip->state = ST_NCCI_NONE;
423 nccip->plcip = plcip;
424 nccip->chan = plcip->chan;
425 nccip->datahandle = 0;
426 nccip->lock = SPIN_LOCK_UNLOCKED;
428 nccip->next = plcip->ncci_list;
429 plcip->ncci_list = nccip;
431 card->bchans[plcip->chan].nccip = nccip;
436 static inline capidrv_ncci *find_ncci(capidrv_contr * card, __u32 ncci)
441 if ((plcip = find_plci_by_ncci(card, ncci)) == 0)
444 for (p = plcip->ncci_list; p; p = p->next)
450 static inline capidrv_ncci *find_ncci_by_msgid(capidrv_contr * card,
451 __u32 ncci, __u16 msgid)
456 if ((plcip = find_plci_by_ncci(card, ncci)) == 0)
459 for (p = plcip->ncci_list; p; p = p->next)
460 if (p->msgid == msgid)
465 static void free_ncci(capidrv_contr * card, struct capidrv_ncci *nccip)
467 struct capidrv_ncci **pp;
469 for (pp = &(nccip->plcip->ncci_list); *pp; pp = &(*pp)->next) {
475 card->bchans[nccip->chan].nccip = 0;
479 static int capidrv_add_ack(struct capidrv_ncci *nccip,
480 __u16 datahandle, int len)
482 struct ncci_datahandle_queue *n, **pp;
485 n = (struct ncci_datahandle_queue *)
486 kmalloc(sizeof(struct ncci_datahandle_queue), GFP_ATOMIC);
488 printk(KERN_ERR "capidrv: kmalloc ncci_datahandle failed\n");
492 n->datahandle = datahandle;
494 spin_lock_irqsave(&nccip->lock, flags);
495 for (pp = &nccip->ackqueue; *pp; pp = &(*pp)->next) ;
497 spin_unlock_irqrestore(&nccip->lock, flags);
501 static int capidrv_del_ack(struct capidrv_ncci *nccip, __u16 datahandle)
503 struct ncci_datahandle_queue **pp, *p;
507 spin_lock_irqsave(&nccip->lock, flags);
508 for (pp = &nccip->ackqueue; *pp; pp = &(*pp)->next) {
509 if ((*pp)->datahandle == datahandle) {
513 spin_unlock_irqrestore(&nccip->lock, flags);
518 spin_unlock_irqrestore(&nccip->lock, flags);
522 /* -------- convert and send capi message ---------------------------- */
524 static void send_message(capidrv_contr * card, _cmsg * cmsg)
530 capi_cmsg2message(cmsg, cmsg->buf);
531 len = CAPIMSG_LEN(cmsg->buf);
532 skb = alloc_skb(len, GFP_ATOMIC);
534 printk(KERN_ERR "no skb len(%d) memory\n", len);
537 memcpy(skb_put(skb, len), cmsg->buf, len);
538 err = (*capifuncs->capi_put_message) (global.appid, skb);
540 printk(KERN_WARNING "%s: capi_put_message error: %04x\n",
545 global.nsentctlpkt++;
548 /* -------- state machine -------------------------------------------- */
550 struct listenstatechange {
556 static struct listenstatechange listentable[] =
558 {ST_LISTEN_NONE, ST_LISTEN_WAIT_CONF, EV_LISTEN_REQ},
559 {ST_LISTEN_ACTIVE, ST_LISTEN_ACTIVE_WAIT_CONF, EV_LISTEN_REQ},
560 {ST_LISTEN_WAIT_CONF, ST_LISTEN_NONE, EV_LISTEN_CONF_ERROR},
561 {ST_LISTEN_ACTIVE_WAIT_CONF, ST_LISTEN_ACTIVE, EV_LISTEN_CONF_ERROR},
562 {ST_LISTEN_WAIT_CONF, ST_LISTEN_NONE, EV_LISTEN_CONF_EMPTY},
563 {ST_LISTEN_ACTIVE_WAIT_CONF, ST_LISTEN_NONE, EV_LISTEN_CONF_EMPTY},
564 {ST_LISTEN_WAIT_CONF, ST_LISTEN_ACTIVE, EV_LISTEN_CONF_OK},
565 {ST_LISTEN_ACTIVE_WAIT_CONF, ST_LISTEN_ACTIVE, EV_LISTEN_CONF_OK},
569 static void listen_change_state(capidrv_contr * card, int event)
571 struct listenstatechange *p = listentable;
573 if (card->state == p->actstate && p->event == event) {
575 printk(KERN_DEBUG "capidrv-%d: listen_change_state %d -> %d\n",
576 card->contrnr, card->state, p->nextstate);
577 card->state = p->nextstate;
582 printk(KERN_ERR "capidrv-%d: listen_change_state state=%d event=%d ????\n",
583 card->contrnr, card->state, event);
587 /* ------------------------------------------------------------------ */
589 static void p0(capidrv_contr * card, capidrv_plci * plci)
593 card->bchans[plci->chan].contr = 0;
594 cmd.command = ISDN_STAT_DHUP;
595 cmd.driver = card->myid;
596 cmd.arg = plci->chan;
597 card->interface.statcallb(&cmd);
598 free_plci(card, plci);
601 /* ------------------------------------------------------------------ */
603 struct plcistatechange {
607 void (*changefunc) (capidrv_contr * card, capidrv_plci * plci);
610 static struct plcistatechange plcitable[] =
613 {ST_PLCI_NONE, ST_PLCI_OUTGOING, EV_PLCI_CONNECT_REQ, 0},
614 {ST_PLCI_NONE, ST_PLCI_ALLOCATED, EV_PLCI_FACILITY_IND_UP, 0},
615 {ST_PLCI_NONE, ST_PLCI_INCOMING, EV_PLCI_CONNECT_IND, 0},
616 {ST_PLCI_NONE, ST_PLCI_RESUMEING, EV_PLCI_RESUME_REQ, 0},
618 {ST_PLCI_OUTGOING, ST_PLCI_NONE, EV_PLCI_CONNECT_CONF_ERROR, p0},
619 {ST_PLCI_OUTGOING, ST_PLCI_ALLOCATED, EV_PLCI_CONNECT_CONF_OK, 0},
621 {ST_PLCI_ALLOCATED, ST_PLCI_ACTIVE, EV_PLCI_CONNECT_ACTIVE_IND, 0},
622 {ST_PLCI_ALLOCATED, ST_PLCI_DISCONNECTING, EV_PLCI_DISCONNECT_REQ, 0},
623 {ST_PLCI_ALLOCATED, ST_PLCI_DISCONNECTING, EV_PLCI_FACILITY_IND_DOWN, 0},
624 {ST_PLCI_ALLOCATED, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, 0},
626 {ST_PLCI_ACTIVE, ST_PLCI_DISCONNECTING, EV_PLCI_DISCONNECT_REQ, 0},
627 {ST_PLCI_ACTIVE, ST_PLCI_DISCONNECTING, EV_PLCI_FACILITY_IND_DOWN, 0},
628 {ST_PLCI_ACTIVE, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, 0},
629 {ST_PLCI_ACTIVE, ST_PLCI_HELD, EV_PLCI_HOLD_IND, 0},
630 {ST_PLCI_ACTIVE, ST_PLCI_DISCONNECTING, EV_PLCI_SUSPEND_IND, 0},
632 {ST_PLCI_INCOMING, ST_PLCI_DISCONNECTING, EV_PLCI_CONNECT_REJECT, 0},
633 {ST_PLCI_INCOMING, ST_PLCI_FACILITY_IND, EV_PLCI_FACILITY_IND_UP, 0},
634 {ST_PLCI_INCOMING, ST_PLCI_ACCEPTING, EV_PLCI_CONNECT_RESP, 0},
635 {ST_PLCI_INCOMING, ST_PLCI_DISCONNECTING, EV_PLCI_DISCONNECT_REQ, 0},
636 {ST_PLCI_INCOMING, ST_PLCI_DISCONNECTING, EV_PLCI_FACILITY_IND_DOWN, 0},
637 {ST_PLCI_INCOMING, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, 0},
638 {ST_PLCI_INCOMING, ST_PLCI_DISCONNECTING, EV_PLCI_CD_IND, 0},
640 {ST_PLCI_FACILITY_IND, ST_PLCI_DISCONNECTING, EV_PLCI_CONNECT_REJECT, 0},
641 {ST_PLCI_FACILITY_IND, ST_PLCI_ACCEPTING, EV_PLCI_CONNECT_ACTIVE_IND, 0},
642 {ST_PLCI_FACILITY_IND, ST_PLCI_DISCONNECTING, EV_PLCI_DISCONNECT_REQ, 0},
643 {ST_PLCI_FACILITY_IND, ST_PLCI_DISCONNECTING, EV_PLCI_FACILITY_IND_DOWN, 0},
644 {ST_PLCI_FACILITY_IND, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, 0},
646 {ST_PLCI_ACCEPTING, ST_PLCI_ACTIVE, EV_PLCI_CONNECT_ACTIVE_IND, 0},
647 {ST_PLCI_ACCEPTING, ST_PLCI_DISCONNECTING, EV_PLCI_DISCONNECT_REQ, 0},
648 {ST_PLCI_ACCEPTING, ST_PLCI_DISCONNECTING, EV_PLCI_FACILITY_IND_DOWN, 0},
649 {ST_PLCI_ACCEPTING, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, 0},
651 {ST_PLCI_DISCONNECTING, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, 0},
653 {ST_PLCI_DISCONNECTED, ST_PLCI_NONE, EV_PLCI_DISCONNECT_RESP, p0},
655 {ST_PLCI_RESUMEING, ST_PLCI_NONE, EV_PLCI_RESUME_CONF_ERROR, p0},
656 {ST_PLCI_RESUMEING, ST_PLCI_RESUME, EV_PLCI_RESUME_CONF_OK, 0},
658 {ST_PLCI_RESUME, ST_PLCI_ACTIVE, EV_PLCI_RESUME_IND, 0},
660 {ST_PLCI_HELD, ST_PLCI_ACTIVE, EV_PLCI_RETRIEVE_IND, 0},
664 static void plci_change_state(capidrv_contr * card, capidrv_plci * plci, int event)
666 struct plcistatechange *p = plcitable;
668 if (plci->state == p->actstate && p->event == event) {
670 printk(KERN_DEBUG "capidrv-%d: plci_change_state:0x%x %d -> %d\n",
671 card->contrnr, plci->plci, plci->state, p->nextstate);
672 plci->state = p->nextstate;
674 p->changefunc(card, plci);
679 printk(KERN_ERR "capidrv-%d: plci_change_state:0x%x state=%d event=%d ????\n",
680 card->contrnr, plci->plci, plci->state, event);
683 /* ------------------------------------------------------------------ */
687 static void n0(capidrv_contr * card, capidrv_ncci * ncci)
691 capi_fill_DISCONNECT_REQ(&cmsg,
695 0, /* BChannelinformation */
696 0, /* Keypadfacility */
697 0, /* Useruserdata */ /* $$$$ */
698 0 /* Facilitydataarray */
700 send_message(card, &cmsg);
701 plci_change_state(card, ncci->plcip, EV_PLCI_DISCONNECT_REQ);
703 cmd.command = ISDN_STAT_BHUP;
704 cmd.driver = card->myid;
705 cmd.arg = ncci->chan;
706 card->interface.statcallb(&cmd);
707 free_ncci(card, ncci);
710 /* ------------------------------------------------------------------ */
712 struct nccistatechange {
716 void (*changefunc) (capidrv_contr * card, capidrv_ncci * ncci);
719 static struct nccistatechange nccitable[] =
722 {ST_NCCI_NONE, ST_NCCI_OUTGOING, EV_NCCI_CONNECT_B3_REQ, 0},
723 {ST_NCCI_NONE, ST_NCCI_INCOMING, EV_NCCI_CONNECT_B3_IND, 0},
725 {ST_NCCI_OUTGOING, ST_NCCI_ALLOCATED, EV_NCCI_CONNECT_B3_CONF_OK, 0},
726 {ST_NCCI_OUTGOING, ST_NCCI_NONE, EV_NCCI_CONNECT_B3_CONF_ERROR, n0},
728 {ST_NCCI_INCOMING, ST_NCCI_DISCONNECTING, EV_NCCI_CONNECT_B3_REJECT, 0},
729 {ST_NCCI_INCOMING, ST_NCCI_ALLOCATED, EV_NCCI_CONNECT_B3_RESP, 0},
730 {ST_NCCI_INCOMING, ST_NCCI_DISCONNECTED, EV_NCCI_DISCONNECT_B3_IND, 0},
731 {ST_NCCI_INCOMING, ST_NCCI_DISCONNECTING, EV_NCCI_DISCONNECT_B3_REQ, 0},
733 {ST_NCCI_ALLOCATED, ST_NCCI_ACTIVE, EV_NCCI_CONNECT_B3_ACTIVE_IND, 0},
734 {ST_NCCI_ALLOCATED, ST_NCCI_DISCONNECTED, EV_NCCI_DISCONNECT_B3_IND, 0},
735 {ST_NCCI_ALLOCATED, ST_NCCI_DISCONNECTING, EV_NCCI_DISCONNECT_B3_REQ, 0},
737 {ST_NCCI_ACTIVE, ST_NCCI_ACTIVE, EV_NCCI_RESET_B3_IND, 0},
738 {ST_NCCI_ACTIVE, ST_NCCI_RESETING, EV_NCCI_RESET_B3_REQ, 0},
739 {ST_NCCI_ACTIVE, ST_NCCI_DISCONNECTED, EV_NCCI_DISCONNECT_B3_IND, 0},
740 {ST_NCCI_ACTIVE, ST_NCCI_DISCONNECTING, EV_NCCI_DISCONNECT_B3_REQ, 0},
742 {ST_NCCI_RESETING, ST_NCCI_ACTIVE, EV_NCCI_RESET_B3_IND, 0},
743 {ST_NCCI_RESETING, ST_NCCI_DISCONNECTED, EV_NCCI_DISCONNECT_B3_IND, 0},
744 {ST_NCCI_RESETING, ST_NCCI_DISCONNECTING, EV_NCCI_DISCONNECT_B3_REQ, 0},
746 {ST_NCCI_DISCONNECTING, ST_NCCI_DISCONNECTED, EV_NCCI_DISCONNECT_B3_IND, 0},
747 {ST_NCCI_DISCONNECTING, ST_NCCI_PREVIOUS, EV_NCCI_DISCONNECT_B3_CONF_ERROR,0},
749 {ST_NCCI_DISCONNECTED, ST_NCCI_NONE, EV_NCCI_DISCONNECT_B3_RESP, n0},
753 static void ncci_change_state(capidrv_contr * card, capidrv_ncci * ncci, int event)
755 struct nccistatechange *p = nccitable;
757 if (ncci->state == p->actstate && p->event == event) {
759 printk(KERN_DEBUG "capidrv-%d: ncci_change_state:0x%x %d -> %d\n",
760 card->contrnr, ncci->ncci, ncci->state, p->nextstate);
761 if (p->nextstate == ST_NCCI_PREVIOUS) {
762 ncci->state = ncci->oldstate;
763 ncci->oldstate = p->actstate;
765 ncci->oldstate = p->actstate;
766 ncci->state = p->nextstate;
769 p->changefunc(card, ncci);
774 printk(KERN_ERR "capidrv-%d: ncci_change_state:0x%x state=%d event=%d ????\n",
775 card->contrnr, ncci->ncci, ncci->state, event);
778 /* ------------------------------------------------------------------- */
780 static inline int new_bchan(capidrv_contr * card)
783 for (i = 0; i < card->nbchan; i++) {
784 if (card->bchans[i].plcip == 0) {
785 card->bchans[i].disconnecting = 0;
792 /* ------------------------------------------------------------------- */
794 static void handle_controller(_cmsg * cmsg)
796 capidrv_contr *card = findcontrbynumber(cmsg->adr.adrController & 0x7f);
799 printk(KERN_ERR "capidrv: %s from unknown controller 0x%x\n",
800 capi_cmd2str(cmsg->Command, cmsg->Subcommand),
801 cmsg->adr.adrController & 0x7f);
804 switch (CAPICMD(cmsg->Command, cmsg->Subcommand)) {
806 case CAPI_LISTEN_CONF: /* Controller */
808 printk(KERN_DEBUG "capidrv-%d: listenconf Info=0x%4x (%s) cipmask=0x%x\n",
809 card->contrnr, cmsg->Info, capi_info2str(cmsg->Info), card->cipmask);
811 listen_change_state(card, EV_LISTEN_CONF_ERROR);
812 } else if (card->cipmask == 0) {
813 listen_change_state(card, EV_LISTEN_CONF_EMPTY);
815 listen_change_state(card, EV_LISTEN_CONF_OK);
819 case CAPI_MANUFACTURER_IND: /* Controller */
820 if ( cmsg->ManuID == 0x214D5641
822 && cmsg->Function == 1) {
823 __u8 *data = cmsg->ManuData+3;
824 __u16 len = cmsg->ManuData[0];
828 len = (cmsg->ManuData[1] | (cmsg->ManuData[2] << 8));
832 layer = ((*(data-1)) << 8) | *(data-2);
834 direction = (layer & 0x200) ? 0 : 1;
835 else direction = (layer & 0x800) ? 0 : 1;
836 if (layer & 0x0C00) {
837 if ((layer & 0xff) == 0x80) {
838 handle_dtrace_data(card, direction, 1, data, len);
841 } else if ((layer & 0xff) < 0x80) {
842 handle_dtrace_data(card, direction, 0, data, len);
845 printk(KERN_INFO "capidrv-%d: %s from controller 0x%x layer 0x%x, ignored\n",
847 capi_cmd2str(cmsg->Command, cmsg->Subcommand),
848 cmsg->adr.adrController, layer);
852 case CAPI_MANUFACTURER_CONF: /* Controller */
853 if (cmsg->ManuID == 0x214D5641) {
855 switch (cmsg->Class) {
857 case 1: s = "unknown class"; break;
858 case 2: s = "unknown function"; break;
859 default: s = "unkown error"; break;
862 printk(KERN_INFO "capidrv-%d: %s from controller 0x%x function %d: %s\n",
864 capi_cmd2str(cmsg->Command, cmsg->Subcommand),
865 cmsg->adr.adrController,
870 case CAPI_FACILITY_IND: /* Controller/plci/ncci */
872 case CAPI_FACILITY_CONF: /* Controller/plci/ncci */
874 case CAPI_INFO_IND: /* Controller/plci */
876 case CAPI_INFO_CONF: /* Controller/plci */
880 printk(KERN_ERR "capidrv-%d: got %s from controller 0x%x ???",
882 capi_cmd2str(cmsg->Command, cmsg->Subcommand),
883 cmsg->adr.adrController);
888 printk(KERN_INFO "capidrv-%d: %s from controller 0x%x ignored\n",
890 capi_cmd2str(cmsg->Command, cmsg->Subcommand),
891 cmsg->adr.adrController);
894 static void handle_incoming_call(capidrv_contr * card, _cmsg * cmsg)
897 capidrv_bchan *bchan;
901 if ((chan = new_bchan(card)) == -1) {
902 printk(KERN_ERR "capidrv-%d: incoming call on not existing bchan ?\n", card->contrnr);
905 bchan = &card->bchans[chan];
906 if ((plcip = new_plci(card, chan)) == 0) {
907 printk(KERN_ERR "capidrv-%d: incoming call: no memory, sorry.\n", card->contrnr);
911 plcip->plci = cmsg->adr.adrPLCI;
912 plci_change_state(card, plcip, EV_PLCI_CONNECT_IND);
914 cmd.command = ISDN_STAT_ICALL;
915 cmd.driver = card->myid;
917 memset(&cmd.parm.setup, 0, sizeof(cmd.parm.setup));
918 strncpy(cmd.parm.setup.phone,
919 cmsg->CallingPartyNumber + 3,
920 cmsg->CallingPartyNumber[0] - 2);
921 strncpy(cmd.parm.setup.eazmsn,
922 cmsg->CalledPartyNumber + 2,
923 cmsg->CalledPartyNumber[0] - 1);
924 cmd.parm.setup.si1 = cip2si1(cmsg->CIPValue);
925 cmd.parm.setup.si2 = cip2si2(cmsg->CIPValue);
926 cmd.parm.setup.plan = cmsg->CallingPartyNumber[1];
927 cmd.parm.setup.screen = cmsg->CallingPartyNumber[2];
929 printk(KERN_INFO "capidrv-%d: incoming call %s,%d,%d,%s\n",
931 cmd.parm.setup.phone,
934 cmd.parm.setup.eazmsn);
936 if (cmd.parm.setup.si1 == 1 && cmd.parm.setup.si2 != 0) {
937 printk(KERN_INFO "capidrv-%d: patching si2=%d to 0 for VBOX\n",
940 cmd.parm.setup.si2 = 0;
943 switch (card->interface.statcallb(&cmd)) {
946 /* No device matching this call.
947 * and isdn_common.c has send a HANGUP command
948 * which is ignored in state ST_PLCI_INCOMING,
949 * so we send RESP to ignore the call
951 capi_cmsg_answer(cmsg);
952 cmsg->Reject = 1; /* ignore */
953 send_message(card, cmsg);
954 plci_change_state(card, plcip, EV_PLCI_CONNECT_REJECT);
955 printk(KERN_INFO "capidrv-%d: incoming call %s,%d,%d,%s ignored\n",
957 cmd.parm.setup.phone,
960 cmd.parm.setup.eazmsn);
963 /* At least one device matching this call (RING on ttyI)
964 * HL-driver may send ALERTING on the D-channel in this
966 * really means: RING on ttyI or a net interface
967 * accepted this call already.
969 * If the call was accepted, state has already changed,
970 * and CONNECT_RESP already sent.
972 if (plcip->state == ST_PLCI_INCOMING) {
973 printk(KERN_INFO "capidrv-%d: incoming call %s,%d,%d,%s tty alerting\n",
975 cmd.parm.setup.phone,
978 cmd.parm.setup.eazmsn);
979 capi_fill_ALERT_REQ(cmsg,
982 plcip->plci, /* adr */
983 0, /* BChannelinformation */
984 0, /* Keypadfacility */
985 0, /* Useruserdata */
986 0 /* Facilitydataarray */
988 plcip->msgid = cmsg->Messagenumber;
989 send_message(card, cmsg);
991 printk(KERN_INFO "capidrv-%d: incoming call %s,%d,%d,%s on netdev\n",
993 cmd.parm.setup.phone,
996 cmd.parm.setup.eazmsn);
1000 case 2: /* Call will be rejected. */
1001 capi_cmsg_answer(cmsg);
1002 cmsg->Reject = 2; /* reject call, normal call clearing */
1003 send_message(card, cmsg);
1004 plci_change_state(card, plcip, EV_PLCI_CONNECT_REJECT);
1008 /* An error happened. (Invalid parameters for example.) */
1009 capi_cmsg_answer(cmsg);
1010 cmsg->Reject = 8; /* reject call,
1011 destination out of order */
1012 send_message(card, cmsg);
1013 plci_change_state(card, plcip, EV_PLCI_CONNECT_REJECT);
1019 static void handle_plci(_cmsg * cmsg)
1021 capidrv_contr *card = findcontrbynumber(cmsg->adr.adrController & 0x7f);
1022 capidrv_plci *plcip;
1026 printk(KERN_ERR "capidrv: %s from unknown controller 0x%x\n",
1027 capi_cmd2str(cmsg->Command, cmsg->Subcommand),
1028 cmsg->adr.adrController & 0x7f);
1031 switch (CAPICMD(cmsg->Command, cmsg->Subcommand)) {
1033 case CAPI_DISCONNECT_IND: /* plci */
1035 printk(KERN_INFO "capidrv-%d: %s reason 0x%x (%s) for plci 0x%x\n",
1037 capi_cmd2str(cmsg->Command, cmsg->Subcommand),
1038 cmsg->Reason, capi_info2str(cmsg->Reason), cmsg->adr.adrPLCI);
1040 if (!(plcip = find_plci_by_plci(card, cmsg->adr.adrPLCI))) {
1041 capi_cmsg_answer(cmsg);
1042 send_message(card, cmsg);
1045 card->bchans[plcip->chan].disconnecting = 1;
1046 plci_change_state(card, plcip, EV_PLCI_DISCONNECT_IND);
1047 capi_cmsg_answer(cmsg);
1048 send_message(card, cmsg);
1049 plci_change_state(card, plcip, EV_PLCI_DISCONNECT_RESP);
1052 case CAPI_DISCONNECT_CONF: /* plci */
1054 printk(KERN_INFO "capidrv-%d: %s info 0x%x (%s) for plci 0x%x\n",
1056 capi_cmd2str(cmsg->Command, cmsg->Subcommand),
1057 cmsg->Info, capi_info2str(cmsg->Info),
1060 if (!(plcip = find_plci_by_plci(card, cmsg->adr.adrPLCI)))
1063 card->bchans[plcip->chan].disconnecting = 1;
1066 case CAPI_ALERT_CONF: /* plci */
1068 printk(KERN_INFO "capidrv-%d: %s info 0x%x (%s) for plci 0x%x\n",
1070 capi_cmd2str(cmsg->Command, cmsg->Subcommand),
1071 cmsg->Info, capi_info2str(cmsg->Info),
1076 case CAPI_CONNECT_IND: /* plci */
1077 handle_incoming_call(card, cmsg);
1080 case CAPI_CONNECT_CONF: /* plci */
1082 printk(KERN_INFO "capidrv-%d: %s info 0x%x (%s) for plci 0x%x\n",
1084 capi_cmd2str(cmsg->Command, cmsg->Subcommand),
1085 cmsg->Info, capi_info2str(cmsg->Info),
1088 if (!(plcip = find_plci_by_msgid(card, cmsg->Messagenumber)))
1091 plcip->plci = cmsg->adr.adrPLCI;
1093 plci_change_state(card, plcip, EV_PLCI_CONNECT_CONF_ERROR);
1095 plci_change_state(card, plcip, EV_PLCI_CONNECT_CONF_OK);
1099 case CAPI_CONNECT_ACTIVE_IND: /* plci */
1101 if (!(plcip = find_plci_by_plci(card, cmsg->adr.adrPLCI)))
1104 if (card->bchans[plcip->chan].incoming) {
1105 capi_cmsg_answer(cmsg);
1106 send_message(card, cmsg);
1107 plci_change_state(card, plcip, EV_PLCI_CONNECT_ACTIVE_IND);
1109 capidrv_ncci *nccip;
1110 capi_cmsg_answer(cmsg);
1111 send_message(card, cmsg);
1113 nccip = new_ncci(card, plcip, cmsg->adr.adrPLCI);
1116 printk(KERN_ERR "capidrv-%d: no mem for ncci, sorry\n", card->contrnr);
1119 capi_fill_CONNECT_B3_REQ(cmsg,
1122 plcip->plci, /* adr */
1125 nccip->msgid = cmsg->Messagenumber;
1126 send_message(card, cmsg);
1127 cmd.command = ISDN_STAT_DCONN;
1128 cmd.driver = card->myid;
1129 cmd.arg = plcip->chan;
1130 card->interface.statcallb(&cmd);
1131 plci_change_state(card, plcip, EV_PLCI_CONNECT_ACTIVE_IND);
1132 ncci_change_state(card, nccip, EV_NCCI_CONNECT_B3_REQ);
1136 case CAPI_INFO_IND: /* Controller/plci */
1138 if (!(plcip = find_plci_by_plci(card, cmsg->adr.adrPLCI)))
1141 if (cmsg->InfoNumber == 0x4000) {
1142 if (cmsg->InfoElement[0] == 4) {
1143 cmd.command = ISDN_STAT_CINF;
1144 cmd.driver = card->myid;
1145 cmd.arg = plcip->chan;
1146 sprintf(cmd.parm.num, "%lu",
1148 ((__u32) cmsg->InfoElement[1]
1149 | ((__u32) (cmsg->InfoElement[2]) << 8)
1150 | ((__u32) (cmsg->InfoElement[3]) << 16)
1151 | ((__u32) (cmsg->InfoElement[4]) << 24)));
1152 card->interface.statcallb(&cmd);
1156 printk(KERN_ERR "capidrv-%d: %s\n",
1157 card->contrnr, capi_cmsg2str(cmsg));
1160 case CAPI_CONNECT_ACTIVE_CONF: /* plci */
1162 case CAPI_SELECT_B_PROTOCOL_CONF: /* plci */
1164 case CAPI_FACILITY_IND: /* Controller/plci/ncci */
1166 case CAPI_FACILITY_CONF: /* Controller/plci/ncci */
1169 case CAPI_INFO_CONF: /* Controller/plci */
1173 printk(KERN_ERR "capidrv-%d: got %s for plci 0x%x ???",
1175 capi_cmd2str(cmsg->Command, cmsg->Subcommand),
1180 printk(KERN_INFO "capidrv-%d: %s for plci 0x%x ignored\n",
1182 capi_cmd2str(cmsg->Command, cmsg->Subcommand),
1186 printk(KERN_ERR "capidrv-%d: %s: plci 0x%x not found\n",
1188 capi_cmd2str(cmsg->Command, cmsg->Subcommand),
1193 static void handle_ncci(_cmsg * cmsg)
1195 capidrv_contr *card = findcontrbynumber(cmsg->adr.adrController & 0x7f);
1196 capidrv_plci *plcip;
1197 capidrv_ncci *nccip;
1202 printk(KERN_ERR "capidrv: %s from unknown controller 0x%x\n",
1203 capi_cmd2str(cmsg->Command, cmsg->Subcommand),
1204 cmsg->adr.adrController & 0x7f);
1207 switch (CAPICMD(cmsg->Command, cmsg->Subcommand)) {
1209 case CAPI_CONNECT_B3_ACTIVE_IND: /* ncci */
1210 if (!(nccip = find_ncci(card, cmsg->adr.adrNCCI)))
1213 capi_cmsg_answer(cmsg);
1214 send_message(card, cmsg);
1215 ncci_change_state(card, nccip, EV_NCCI_CONNECT_B3_ACTIVE_IND);
1217 cmd.command = ISDN_STAT_BCONN;
1218 cmd.driver = card->myid;
1219 cmd.arg = nccip->chan;
1220 card->interface.statcallb(&cmd);
1222 printk(KERN_INFO "capidrv-%d: chan %d up with ncci 0x%x\n",
1223 card->contrnr, nccip->chan, nccip->ncci);
1226 case CAPI_CONNECT_B3_ACTIVE_CONF: /* ncci */
1229 case CAPI_CONNECT_B3_IND: /* ncci */
1231 plcip = find_plci_by_ncci(card, cmsg->adr.adrNCCI);
1233 nccip = new_ncci(card, plcip, cmsg->adr.adrNCCI);
1235 ncci_change_state(card, nccip, EV_NCCI_CONNECT_B3_IND);
1236 capi_fill_CONNECT_B3_RESP(cmsg,
1239 nccip->ncci, /* adr */
1243 send_message(card, cmsg);
1244 ncci_change_state(card, nccip, EV_NCCI_CONNECT_B3_RESP);
1247 printk(KERN_ERR "capidrv-%d: no mem for ncci, sorry\n", card->contrnr);
1249 printk(KERN_ERR "capidrv-%d: %s: plci for ncci 0x%x not found\n",
1251 capi_cmd2str(cmsg->Command, cmsg->Subcommand),
1254 capi_fill_CONNECT_B3_RESP(cmsg,
1261 send_message(card, cmsg);
1264 case CAPI_CONNECT_B3_CONF: /* ncci */
1266 if (!(nccip = find_ncci_by_msgid(card,
1268 cmsg->Messagenumber)))
1271 nccip->ncci = cmsg->adr.adrNCCI;
1273 printk(KERN_INFO "capidrv-%d: %s info 0x%x (%s) for ncci 0x%x\n",
1275 capi_cmd2str(cmsg->Command, cmsg->Subcommand),
1276 cmsg->Info, capi_info2str(cmsg->Info),
1281 ncci_change_state(card, nccip, EV_NCCI_CONNECT_B3_CONF_ERROR);
1283 ncci_change_state(card, nccip, EV_NCCI_CONNECT_B3_CONF_OK);
1286 case CAPI_CONNECT_B3_T90_ACTIVE_IND: /* ncci */
1287 capi_cmsg_answer(cmsg);
1288 send_message(card, cmsg);
1291 case CAPI_DATA_B3_IND: /* ncci */
1292 /* handled in handle_data() */
1295 case CAPI_DATA_B3_CONF: /* ncci */
1296 if (!(nccip = find_ncci(card, cmsg->adr.adrNCCI)))
1299 len = capidrv_del_ack(nccip, cmsg->DataHandle);
1302 cmd.command = ISDN_STAT_BSENT;
1303 cmd.driver = card->myid;
1304 cmd.arg = nccip->chan;
1305 cmd.parm.length = len;
1306 card->interface.statcallb(&cmd);
1309 case CAPI_DISCONNECT_B3_IND: /* ncci */
1310 if (!(nccip = find_ncci(card, cmsg->adr.adrNCCI)))
1313 card->bchans[nccip->chan].disconnecting = 1;
1314 ncci_change_state(card, nccip, EV_NCCI_DISCONNECT_B3_IND);
1315 capi_cmsg_answer(cmsg);
1316 send_message(card, cmsg);
1317 ncci_change_state(card, nccip, EV_NCCI_DISCONNECT_B3_RESP);
1320 case CAPI_DISCONNECT_B3_CONF: /* ncci */
1321 if (!(nccip = find_ncci(card, cmsg->adr.adrNCCI)))
1324 printk(KERN_INFO "capidrv-%d: %s info 0x%x (%s) for ncci 0x%x\n",
1326 capi_cmd2str(cmsg->Command, cmsg->Subcommand),
1327 cmsg->Info, capi_info2str(cmsg->Info),
1329 ncci_change_state(card, nccip, EV_NCCI_DISCONNECT_B3_CONF_ERROR);
1333 case CAPI_RESET_B3_IND: /* ncci */
1334 if (!(nccip = find_ncci(card, cmsg->adr.adrNCCI)))
1336 ncci_change_state(card, nccip, EV_NCCI_RESET_B3_IND);
1337 capi_cmsg_answer(cmsg);
1338 send_message(card, cmsg);
1341 case CAPI_RESET_B3_CONF: /* ncci */
1342 goto ignored; /* $$$$ */
1344 case CAPI_FACILITY_IND: /* Controller/plci/ncci */
1346 case CAPI_FACILITY_CONF: /* Controller/plci/ncci */
1350 printk(KERN_ERR "capidrv-%d: got %s for ncci 0x%x ???",
1352 capi_cmd2str(cmsg->Command, cmsg->Subcommand),
1357 printk(KERN_INFO "capidrv-%d: %s for ncci 0x%x ignored\n",
1359 capi_cmd2str(cmsg->Command, cmsg->Subcommand),
1363 printk(KERN_ERR "capidrv-%d: %s: ncci 0x%x not found\n",
1365 capi_cmd2str(cmsg->Command, cmsg->Subcommand),
1370 static void handle_data(_cmsg * cmsg, struct sk_buff *skb)
1372 capidrv_contr *card = findcontrbynumber(cmsg->adr.adrController & 0x7f);
1373 capidrv_ncci *nccip;
1376 printk(KERN_ERR "capidrv: %s from unknown controller 0x%x\n",
1377 capi_cmd2str(cmsg->Command, cmsg->Subcommand),
1378 cmsg->adr.adrController & 0x7f);
1382 if (!(nccip = find_ncci(card, cmsg->adr.adrNCCI))) {
1383 printk(KERN_ERR "capidrv-%d: %s: ncci 0x%x not found\n",
1385 capi_cmd2str(cmsg->Command, cmsg->Subcommand),
1390 (void) skb_pull(skb, CAPIMSG_LEN(skb->data));
1391 card->interface.rcvcallb_skb(card->myid, nccip->chan, skb);
1392 capi_cmsg_answer(cmsg);
1393 send_message(card, cmsg);
1396 static _cmsg s_cmsg;
1398 static void capidrv_signal(__u16 applid, void *dummy)
1400 struct sk_buff *skb = 0;
1402 while ((*capifuncs->capi_get_message) (global.appid, &skb) == CAPI_NOERROR) {
1403 capi_message2cmsg(&s_cmsg, skb->data);
1405 printk(KERN_DEBUG "capidrv_signal: applid=%d %s\n",
1406 applid, capi_cmsg2str(&s_cmsg));
1408 if (s_cmsg.Command == CAPI_DATA_B3
1409 && s_cmsg.Subcommand == CAPI_IND) {
1410 handle_data(&s_cmsg, skb);
1411 global.nrecvdatapkt++;
1414 if ((s_cmsg.adr.adrController & 0xffffff00) == 0)
1415 handle_controller(&s_cmsg);
1416 else if ((s_cmsg.adr.adrPLCI & 0xffff0000) == 0)
1417 handle_plci(&s_cmsg);
1419 handle_ncci(&s_cmsg);
1421 * data of skb used in s_cmsg,
1422 * free data when s_cmsg is not used again
1423 * thanks to Lars Heete <hel@admin.de>
1426 global.nrecvctlpkt++;
1430 /* ------------------------------------------------------------------- */
1432 #define PUTBYTE_TO_STATUS(card, byte) \
1434 *(card)->q931_write++ = (byte); \
1435 if ((card)->q931_write > (card)->q931_end) \
1436 (card)->q931_write = (card)->q931_buf; \
1439 static void handle_dtrace_data(capidrv_contr *card,
1440 int send, int level2, __u8 *data, __u16 len)
1446 printk(KERN_DEBUG "capidrv-%d: avmb1_q931_data: len == %d\n",
1447 card->contrnr, len);
1452 PUTBYTE_TO_STATUS(card, 'D');
1453 PUTBYTE_TO_STATUS(card, '2');
1454 PUTBYTE_TO_STATUS(card, send ? '>' : '<');
1455 PUTBYTE_TO_STATUS(card, ':');
1457 PUTBYTE_TO_STATUS(card, 'D');
1458 PUTBYTE_TO_STATUS(card, '3');
1459 PUTBYTE_TO_STATUS(card, send ? '>' : '<');
1460 PUTBYTE_TO_STATUS(card, ':');
1463 for (p = data, end = data+len; p < end; p++) {
1465 PUTBYTE_TO_STATUS(card, ' ');
1466 w = (*p >> 4) & 0xf;
1467 PUTBYTE_TO_STATUS(card, (w < 10) ? '0'+w : 'A'-10+w);
1469 PUTBYTE_TO_STATUS(card, (w < 10) ? '0'+w : 'A'-10+w);
1471 PUTBYTE_TO_STATUS(card, '\n');
1473 cmd.command = ISDN_STAT_STAVAIL;
1474 cmd.driver = card->myid;
1476 card->interface.statcallb(&cmd);
1479 /* ------------------------------------------------------------------- */
1481 static _cmsg cmdcmsg;
1483 static int capidrv_ioctl(isdn_ctrl * c, capidrv_contr * card)
1487 debugmode = (int)(*((unsigned int *)c->parm.num));
1488 printk(KERN_DEBUG "capidrv-%d: debugmode=%d\n",
1489 card->contrnr, debugmode);
1492 printk(KERN_DEBUG "capidrv-%d: capidrv_ioctl(%ld) called ??\n",
1493 card->contrnr, c->arg);
1500 * Handle leased lines (CAPI-Bundling)
1503 struct internal_bchannelinfo {
1504 unsigned short channelalloc;
1505 unsigned short operation;
1506 unsigned char cmask[31];
1509 static int decodeFVteln(char *teln, unsigned long *bmaskp, int *activep)
1511 unsigned long bmask = 0;
1516 if (strncmp(teln, "FV:", 3) != 0)
1519 while (*s && *s == ' ') s++;
1521 if (*s == 'p' || *s == 'P') {
1525 if (*s == 'a' || *s == 'A') {
1532 if (!isdigit(*s)) return -3;
1533 while (isdigit(*s)) { digit1 = digit1*10 + (*s - '0'); s++; }
1534 if (digit1 <= 0 && digit1 > 30) return -4;
1535 if (*s == 0 || *s == ',' || *s == ' ') {
1536 bmask |= (1 << digit1);
1541 if (*s != '-') return -5;
1543 if (!isdigit(*s)) return -3;
1544 while (isdigit(*s)) { digit2 = digit2*10 + (*s - '0'); s++; }
1545 if (digit2 <= 0 && digit2 > 30) return -4;
1546 if (*s == 0 || *s == ',' || *s == ' ') {
1547 if (digit1 > digit2)
1548 for (i = digit2; i <= digit1 ; i++)
1551 for (i = digit1; i <= digit2 ; i++)
1553 digit1 = digit2 = 0;
1559 if (activep) *activep = active;
1560 if (bmaskp) *bmaskp = bmask;
1564 static int FVteln2capi20(char *teln, __u8 AdditionalInfo[1+2+2+31])
1566 unsigned long bmask;
1570 rc = decodeFVteln(teln, &bmask, &active);
1573 AdditionalInfo[0] = 2+2+31;
1574 /* Channel: 3 => use channel allocation */
1575 AdditionalInfo[1] = 3; AdditionalInfo[2] = 0;
1576 /* Operation: 0 => DTE mode, 1 => DCE mode */
1578 AdditionalInfo[3] = 0; AdditionalInfo[4] = 0;
1580 AdditionalInfo[3] = 1; AdditionalInfo[4] = 0;
1582 /* Channel mask array */
1583 AdditionalInfo[5] = 0; /* no D-Channel */
1584 for (i=1; i <= 30; i++)
1585 AdditionalInfo[5+i] = (bmask & (1 << i)) ? 0xff : 0;
1589 static int capidrv_command(isdn_ctrl * c, capidrv_contr * card)
1592 struct capidrv_bchan *bchan;
1593 struct capidrv_plci *plcip;
1594 __u8 AdditionalInfo[1+2+2+31];
1595 int rc, isleasedline = 0;
1597 if (c->command == ISDN_CMD_IOCTL)
1598 return capidrv_ioctl(c, card);
1600 switch (c->command) {
1601 case ISDN_CMD_DIAL:{
1602 __u8 calling[ISDN_MSNLEN + 3];
1603 __u8 called[ISDN_MSNLEN + 2];
1606 printk(KERN_DEBUG "capidrv-%d: ISDN_CMD_DIAL(ch=%ld,\"%s,%d,%d,%s\")\n",
1609 c->parm.setup.phone,
1612 c->parm.setup.eazmsn);
1614 bchan = &card->bchans[c->arg % card->nbchan];
1617 printk(KERN_ERR "capidrv-%d: dail ch=%ld,\"%s,%d,%d,%s\" in use (plci=0x%x)\n",
1620 c->parm.setup.phone,
1623 c->parm.setup.eazmsn,
1624 bchan->plcip->plci);
1627 bchan->si1 = c->parm.setup.si1;
1628 bchan->si2 = c->parm.setup.si2;
1630 strncpy(bchan->num, c->parm.setup.phone, sizeof(bchan->num));
1631 strncpy(bchan->mynum, c->parm.setup.eazmsn, sizeof(bchan->mynum));
1632 rc = FVteln2capi20(bchan->num, AdditionalInfo);
1633 isleasedline = (rc == 0);
1635 printk(KERN_ERR "capidrv-%d: WARNING: illegal leased linedefinition \"%s\"\n", card->contrnr, bchan->num);
1641 printk(KERN_DEBUG "capidrv-%d: connecting leased line\n", card->contrnr);
1643 calling[0] = strlen(bchan->mynum) + 2;
1646 strncpy(calling + 3, bchan->mynum, ISDN_MSNLEN);
1647 called[0] = strlen(bchan->num) + 1;
1649 strncpy(called + 2, bchan->num, ISDN_MSNLEN);
1652 capi_fill_CONNECT_REQ(&cmdcmsg,
1655 card->contrnr, /* adr */
1656 si2cip(bchan->si1, bchan->si2), /* cipvalue */
1657 called, /* CalledPartyNumber */
1658 calling, /* CallingPartyNumber */
1659 0, /* CalledPartySubaddress */
1660 0, /* CallingPartySubaddress */
1661 b1prot(bchan->l2, bchan->l3), /* B1protocol */
1662 b2prot(bchan->l2, bchan->l3), /* B2protocol */
1663 b3prot(bchan->l2, bchan->l3), /* B3protocol */
1664 b1config(bchan->l2, bchan->l3), /* B1configuration */
1665 0, /* B2configuration */
1666 0, /* B3configuration */
1670 /* BChannelinformation */
1671 isleasedline ? AdditionalInfo : 0,
1672 0, /* Keypadfacility */
1673 0, /* Useruserdata */
1674 0 /* Facilitydataarray */
1676 if ((plcip = new_plci(card, (c->arg % card->nbchan))) == 0) {
1677 cmd.command = ISDN_STAT_DHUP;
1678 cmd.driver = card->myid;
1679 cmd.arg = (c->arg % card->nbchan);
1680 card->interface.statcallb(&cmd);
1683 plcip->msgid = cmdcmsg.Messagenumber;
1684 plcip->leasedline = isleasedline;
1685 plci_change_state(card, plcip, EV_PLCI_CONNECT_REQ);
1686 send_message(card, &cmdcmsg);
1690 case ISDN_CMD_ACCEPTD:
1692 bchan = &card->bchans[c->arg % card->nbchan];
1694 printk(KERN_DEBUG "capidrv-%d: ISDN_CMD_ACCEPTD(ch=%ld) l2=%d l3=%d\n",
1696 c->arg, bchan->l2, bchan->l3);
1698 capi_fill_CONNECT_RESP(&cmdcmsg,
1701 bchan->plcip->plci, /* adr */
1703 b1prot(bchan->l2, bchan->l3), /* B1protocol */
1704 b2prot(bchan->l2, bchan->l3), /* B2protocol */
1705 b3prot(bchan->l2, bchan->l3), /* B3protocol */
1706 b1config(bchan->l2, bchan->l3), /* B1configuration */
1707 0, /* B2configuration */
1708 0, /* B3configuration */
1709 0, /* ConnectedNumber */
1710 0, /* ConnectedSubaddress */
1712 0, /* BChannelinformation */
1713 0, /* Keypadfacility */
1714 0, /* Useruserdata */
1715 0 /* Facilitydataarray */
1717 capi_cmsg2message(&cmdcmsg, cmdcmsg.buf);
1718 plci_change_state(card, bchan->plcip, EV_PLCI_CONNECT_RESP);
1719 send_message(card, &cmdcmsg);
1722 case ISDN_CMD_ACCEPTB:
1724 printk(KERN_DEBUG "capidrv-%d: ISDN_CMD_ACCEPTB(ch=%ld)\n",
1729 case ISDN_CMD_HANGUP:
1731 printk(KERN_DEBUG "capidrv-%d: ISDN_CMD_HANGUP(ch=%ld)\n",
1734 bchan = &card->bchans[c->arg % card->nbchan];
1736 if (bchan->disconnecting) {
1738 printk(KERN_DEBUG "capidrv-%d: chan %ld already disconnecting ...\n",
1744 bchan->disconnecting = 1;
1745 capi_fill_DISCONNECT_B3_REQ(&cmdcmsg,
1751 ncci_change_state(card, bchan->nccip, EV_NCCI_DISCONNECT_B3_REQ);
1752 send_message(card, &cmdcmsg);
1754 } else if (bchan->plcip) {
1755 if (bchan->plcip->state == ST_PLCI_INCOMING) {
1757 * just ignore, we a called from
1758 * isdn_status_callback(),
1759 * which will return 0 or 2, this is handled
1760 * by the CONNECT_IND handler
1762 bchan->disconnecting = 1;
1764 } else if (bchan->plcip->plci) {
1765 bchan->disconnecting = 1;
1766 capi_fill_DISCONNECT_REQ(&cmdcmsg,
1770 0, /* BChannelinformation */
1771 0, /* Keypadfacility */
1772 0, /* Useruserdata */
1773 0 /* Facilitydataarray */
1775 plci_change_state(card, bchan->plcip, EV_PLCI_DISCONNECT_REQ);
1776 send_message(card, &cmdcmsg);
1779 printk(KERN_ERR "capidrv-%d: chan %ld disconnect request while waiting for CONNECT_CONF\n",
1785 printk(KERN_ERR "capidrv-%d: chan %ld disconnect request on free channel\n",
1791 case ISDN_CMD_SETL2:
1793 printk(KERN_DEBUG "capidrv-%d: set L2 on chan %ld to %ld\n",
1795 (c->arg & 0xff), (c->arg >> 8));
1796 bchan = &card->bchans[(c->arg & 0xff) % card->nbchan];
1797 bchan->l2 = (c->arg >> 8);
1800 case ISDN_CMD_SETL3:
1802 printk(KERN_DEBUG "capidrv-%d: set L3 on chan %ld to %ld\n",
1804 (c->arg & 0xff), (c->arg >> 8));
1805 bchan = &card->bchans[(c->arg & 0xff) % card->nbchan];
1806 bchan->l3 = (c->arg >> 8);
1809 case ISDN_CMD_SETEAZ:
1811 printk(KERN_DEBUG "capidrv-%d: set EAZ \"%s\" on chan %ld\n",
1813 c->parm.num, c->arg);
1814 bchan = &card->bchans[c->arg % card->nbchan];
1815 strncpy(bchan->msn, c->parm.num, ISDN_MSNLEN);
1818 case ISDN_CMD_CLREAZ:
1820 printk(KERN_DEBUG "capidrv-%d: clearing EAZ on chan %ld\n",
1821 card->contrnr, c->arg);
1822 bchan = &card->bchans[c->arg % card->nbchan];
1828 printk(KERN_DEBUG "capidrv-%d: ISDN_CMD_LOCK (%ld)\n", card->contrnr, c->arg);
1832 case ISDN_CMD_UNLOCK:
1834 printk(KERN_DEBUG "capidrv-%d: ISDN_CMD_UNLOCK (%ld)\n",
1835 card->contrnr, c->arg);
1840 case ISDN_CMD_GETL2:
1842 printk(KERN_DEBUG "capidrv-%d: ISDN_CMD_GETL2\n",
1845 case ISDN_CMD_GETL3:
1847 printk(KERN_DEBUG "capidrv-%d: ISDN_CMD_GETL3\n",
1850 case ISDN_CMD_GETEAZ:
1852 printk(KERN_DEBUG "capidrv-%d: ISDN_CMD_GETEAZ\n",
1855 case ISDN_CMD_SETSIL:
1857 printk(KERN_DEBUG "capidrv-%d: ISDN_CMD_SETSIL\n",
1860 case ISDN_CMD_GETSIL:
1862 printk(KERN_DEBUG "capidrv-%d: ISDN_CMD_GETSIL\n",
1866 printk(KERN_ERR "capidrv-%d: ISDN_CMD_%d, Huh?\n",
1867 card->contrnr, c->command);
1873 static int if_command(isdn_ctrl * c)
1875 capidrv_contr *card = findcontrbydriverid(c->driver);
1878 return capidrv_command(c, card);
1881 "capidrv: if_command %d called with invalid driverId %d!\n",
1882 c->command, c->driver);
1886 static _cmsg sendcmsg;
1888 static int if_sendbuf(int id, int channel, int doack, struct sk_buff *skb)
1890 capidrv_contr *card = findcontrbydriverid(id);
1891 capidrv_bchan *bchan;
1892 capidrv_ncci *nccip;
1899 printk(KERN_ERR "capidrv: if_sendbuf called with invalid driverId %d!\n",
1904 printk(KERN_DEBUG "capidrv-%d: sendbuf len=%d skb=%p doack=%d\n",
1905 card->contrnr, len, skb, doack);
1906 bchan = &card->bchans[channel % card->nbchan];
1907 nccip = bchan->nccip;
1908 if (!nccip || nccip->state != ST_NCCI_ACTIVE) {
1909 printk(KERN_ERR "capidrv-%d: if_sendbuf: %s:%d: chan not up!\n",
1910 card->contrnr, card->name, channel);
1913 datahandle = nccip->datahandle;
1914 capi_fill_DATA_B3_REQ(&sendcmsg, global.appid, card->msgid++,
1915 nccip->ncci, /* adr */
1916 (__u32) skb->data, /* Data */
1917 skb->len, /* DataLength */
1918 datahandle, /* DataHandle */
1922 if (capidrv_add_ack(nccip, datahandle, doack ? skb->len : -1) < 0)
1925 capi_cmsg2message(&sendcmsg, sendcmsg.buf);
1926 msglen = CAPIMSG_LEN(sendcmsg.buf);
1927 if (skb_headroom(skb) < msglen) {
1928 struct sk_buff *nskb = skb_realloc_headroom(skb, msglen);
1930 printk(KERN_ERR "capidrv-%d: if_sendbuf: no memory\n",
1932 (void)capidrv_del_ack(nccip, datahandle);
1935 printk(KERN_DEBUG "capidrv-%d: only %d bytes headroom, need %d\n",
1936 card->contrnr, skb_headroom(skb), msglen);
1937 memcpy(skb_push(nskb, msglen), sendcmsg.buf, msglen);
1938 errcode = (*capifuncs->capi_put_message) (global.appid, nskb);
1939 if (errcode == CAPI_NOERROR) {
1941 nccip->datahandle++;
1942 global.nsentdatapkt++;
1945 (void)capidrv_del_ack(nccip, datahandle);
1946 dev_kfree_skb(nskb);
1947 return errcode == CAPI_SENDQUEUEFULL ? 0 : -1;
1949 memcpy(skb_push(skb, msglen), sendcmsg.buf, msglen);
1950 errcode = (*capifuncs->capi_put_message) (global.appid, skb);
1951 if (errcode == CAPI_NOERROR) {
1952 nccip->datahandle++;
1953 global.nsentdatapkt++;
1956 skb_pull(skb, msglen);
1957 (void)capidrv_del_ack(nccip, datahandle);
1958 return errcode == CAPI_SENDQUEUEFULL ? 0 : -1;
1962 static int if_readstat(__u8 *buf, int len, int user, int id, int channel)
1964 capidrv_contr *card = findcontrbydriverid(id);
1969 printk(KERN_ERR "capidrv: if_readstat called with invalid driverId %d!\n",
1974 for (p=buf, count=0; count < len; p++, count++) {
1976 put_user(*card->q931_read++, p);
1978 *p = *card->q931_read++;
1979 if (card->q931_read > card->q931_end)
1980 card->q931_read = card->q931_buf;
1986 static void enable_dchannel_trace(capidrv_contr *card)
1988 __u8 manufacturer[CAPI_MANUFACTURER_LEN];
1989 capi_version version;
1990 __u16 contr = card->contrnr;
1992 __u16 avmversion[3];
1994 errcode = (*capifuncs->capi_get_manufacturer)(contr, manufacturer);
1995 if (errcode != CAPI_NOERROR) {
1996 printk(KERN_ERR "%s: can't get manufacturer (0x%x)\n",
1997 card->name, errcode);
2000 if (strstr(manufacturer, "AVM") == 0) {
2001 printk(KERN_ERR "%s: not from AVM, no d-channel trace possible (%s)\n",
2002 card->name, manufacturer);
2005 errcode = (*capifuncs->capi_get_version)(contr, &version);
2006 if (errcode != CAPI_NOERROR) {
2007 printk(KERN_ERR "%s: can't get version (0x%x)\n",
2008 card->name, errcode);
2011 avmversion[0] = (version.majormanuversion >> 4) & 0x0f;
2012 avmversion[1] = (version.majormanuversion << 4) & 0xf0;
2013 avmversion[1] |= (version.minormanuversion >> 4) & 0x0f;
2014 avmversion[2] |= version.minormanuversion & 0x0f;
2016 if (avmversion[0] > 3 || (avmversion[0] == 3 && avmversion[1] > 5)) {
2017 printk(KERN_INFO "%s: D2 trace enabled\n", card->name);
2018 capi_fill_MANUFACTURER_REQ(&cmdcmsg, global.appid,
2021 0x214D5641, /* ManuID */
2024 (_cstruct)"\004\200\014\000\000");
2026 printk(KERN_INFO "%s: D3 trace enabled\n", card->name);
2027 capi_fill_MANUFACTURER_REQ(&cmdcmsg, global.appid,
2030 0x214D5641, /* ManuID */
2033 (_cstruct)"\004\002\003\000\000");
2035 send_message(card, &cmdcmsg);
2039 static void send_listen(capidrv_contr *card)
2041 capi_fill_LISTEN_REQ(&cmdcmsg, global.appid,
2043 card->contrnr, /* controller */
2044 1 << 6, /* Infomask */
2048 send_message(card, &cmdcmsg);
2049 listen_change_state(card, EV_LISTEN_REQ);
2052 static void listentimerfunc(unsigned long x)
2054 capidrv_contr *card = (capidrv_contr *)x;
2055 if (card->state != ST_LISTEN_NONE && card->state != ST_LISTEN_ACTIVE)
2056 printk(KERN_ERR "%s: controller dead ??\n", card->name);
2058 mod_timer(&card->listentimer, jiffies + 60*HZ);
2062 static int capidrv_addcontr(__u16 contr, struct capi_profile *profp)
2064 capidrv_contr *card;
2072 sprintf(id, "capidrv-%d", contr);
2073 if (!(card = (capidrv_contr *) kmalloc(sizeof(capidrv_contr), GFP_ATOMIC))) {
2075 "capidrv: (%s) Could not allocate contr-struct.\n", id);
2079 memset(card, 0, sizeof(capidrv_contr));
2080 init_timer(&card->listentimer);
2081 strcpy(card->name, id);
2082 card->contrnr = contr;
2083 card->nbchan = profp->nbchannel;
2084 card->bchans = (capidrv_bchan *) kmalloc(sizeof(capidrv_bchan) * card->nbchan, GFP_ATOMIC);
2085 if (!card->bchans) {
2087 "capidrv: (%s) Could not allocate bchan-structs.\n", id);
2092 card->interface.channels = profp->nbchannel;
2093 card->interface.maxbufsize = 2048;
2094 card->interface.command = if_command;
2095 card->interface.writebuf_skb = if_sendbuf;
2096 card->interface.writecmd = 0;
2097 card->interface.readstat = if_readstat;
2098 card->interface.features = ISDN_FEATURE_L2_HDLC |
2099 ISDN_FEATURE_L2_TRANS |
2100 ISDN_FEATURE_L3_TRANS |
2101 ISDN_FEATURE_P_UNKNOWN |
2102 ISDN_FEATURE_L2_X75I |
2103 ISDN_FEATURE_L2_X75UI |
2104 ISDN_FEATURE_L2_X75BUI;
2105 if (profp->support1 & (1<<2))
2106 card->interface.features |= ISDN_FEATURE_L2_V11096 |
2107 ISDN_FEATURE_L2_V11019 |
2108 ISDN_FEATURE_L2_V11038;
2109 if (profp->support1 & (1<<8))
2110 card->interface.features |= ISDN_FEATURE_L2_MODEM;
2111 card->interface.hl_hdrlen = 22; /* len of DATA_B3_REQ */
2112 strncpy(card->interface.id, id, sizeof(card->interface.id) - 1);
2115 card->q931_read = card->q931_buf;
2116 card->q931_write = card->q931_buf;
2117 card->q931_end = card->q931_buf + sizeof(card->q931_buf) - 1;
2119 if (!register_isdn(&card->interface)) {
2120 printk(KERN_ERR "capidrv: Unable to register contr %s\n", id);
2121 kfree(card->bchans);
2126 card->myid = card->interface.channels;
2128 spin_lock_irqsave(&global_lock, flags);
2129 card->next = global.contr_list;
2130 global.contr_list = card;
2132 spin_unlock_irqrestore(&global_lock, flags);
2134 memset(card->bchans, 0, sizeof(capidrv_bchan) * card->nbchan);
2135 for (i = 0; i < card->nbchan; i++) {
2136 card->bchans[i].contr = card;
2139 cmd.command = ISDN_STAT_RUN;
2140 cmd.driver = card->myid;
2141 card->interface.statcallb(&cmd);
2143 card->cipmask = 0x1FFF03FF; /* any */
2148 card->listentimer.data = (unsigned long)card;
2149 card->listentimer.function = listentimerfunc;
2150 mod_timer(&card->listentimer, jiffies + 60*HZ);
2152 printk(KERN_INFO "%s: now up (%d B channels)\n",
2153 card->name, card->nbchan);
2155 enable_dchannel_trace(card);
2160 static int capidrv_delcontr(__u16 contr)
2162 capidrv_contr **pp, *card;
2163 unsigned long flags;
2166 spin_lock_irqsave(&global_lock, flags);
2167 for (card = global.contr_list; card; card = card->next) {
2168 if (card->contrnr == contr)
2172 spin_unlock_irqrestore(&global_lock, flags);
2173 printk(KERN_ERR "capidrv: delcontr: no contr %u\n", contr);
2176 spin_unlock_irqrestore(&global_lock, flags);
2178 del_timer(&card->listentimer);
2181 printk(KERN_DEBUG "capidrv-%d: id=%d unloading\n",
2182 card->contrnr, card->myid);
2184 cmd.command = ISDN_STAT_STOP;
2185 cmd.driver = card->myid;
2186 card->interface.statcallb(&cmd);
2188 while (card->nbchan) {
2190 cmd.command = ISDN_STAT_DISCH;
2191 cmd.driver = card->myid;
2192 cmd.arg = card->nbchan-1;
2193 cmd.parm.num[0] = 0;
2195 printk(KERN_DEBUG "capidrv-%d: id=%d disable chan=%ld\n",
2196 card->contrnr, card->myid, cmd.arg);
2197 card->interface.statcallb(&cmd);
2199 if (card->bchans[card->nbchan-1].nccip)
2200 free_ncci(card, card->bchans[card->nbchan-1].nccip);
2201 if (card->bchans[card->nbchan-1].plcip)
2202 free_plci(card, card->bchans[card->nbchan-1].plcip);
2205 if (card->plci_list)
2206 printk(KERN_ERR "capidrv: bug in free_plci()\n");
2207 kfree(card->bchans);
2211 printk(KERN_DEBUG "capidrv-%d: id=%d isdn unload\n",
2212 card->contrnr, card->myid);
2214 cmd.command = ISDN_STAT_UNLOAD;
2215 cmd.driver = card->myid;
2216 card->interface.statcallb(&cmd);
2219 printk(KERN_DEBUG "capidrv-%d: id=%d remove contr from list\n",
2220 card->contrnr, card->myid);
2222 spin_lock_irqsave(&global_lock, flags);
2223 for (pp = &global.contr_list; *pp; pp = &(*pp)->next) {
2231 spin_unlock_irqrestore(&global_lock, flags);
2233 printk(KERN_INFO "%s: now down.\n", card->name);
2243 static void lower_callback(unsigned int cmd, __u32 contr, void *data)
2248 printk(KERN_INFO "capidrv: controller %hu up\n", contr);
2249 (void) capidrv_addcontr(contr, (capi_profile *) data);
2252 printk(KERN_INFO "capidrv: controller %hu down\n", contr);
2253 (void) capidrv_delcontr(contr);
2259 * /proc/capi/capidrv:
2260 * nrecvctlpkt nrecvdatapkt nsendctlpkt nsenddatapkt
2262 static int proc_capidrv_read_proc(char *page, char **start, off_t off,
2263 int count, int *eof, void *data)
2267 len += sprintf(page+len, "%lu %lu %lu %lu\n",
2269 global.nrecvdatapkt,
2271 global.nsentdatapkt);
2272 if (off+count >= len)
2276 *start = page + off;
2277 return ((count < len-off) ? count : len-off);
2280 static struct procfsentries {
2283 int (*read_proc)(char *page, char **start, off_t off,
2284 int count, int *eof, void *data);
2285 struct proc_dir_entry *procent;
2286 } procfsentries[] = {
2287 /* { "capi", S_IFDIR, 0 }, */
2288 { "capi/capidrv", 0 , proc_capidrv_read_proc },
2291 static void __init proc_init(void)
2293 int nelem = sizeof(procfsentries)/sizeof(procfsentries[0]);
2296 for (i=0; i < nelem; i++) {
2297 struct procfsentries *p = procfsentries + i;
2298 p->procent = create_proc_entry(p->name, p->mode, 0);
2299 if (p->procent) p->procent->read_proc = p->read_proc;
2303 static void __exit proc_exit(void)
2305 int nelem = sizeof(procfsentries)/sizeof(procfsentries[0]);
2308 for (i=nelem-1; i >= 0; i--) {
2309 struct procfsentries *p = procfsentries + i;
2311 remove_proc_entry(p->name, 0);
2317 static struct capi_interface_user cuser = {
2319 callback: lower_callback
2322 static int __init capidrv_init(void)
2324 struct capi_register_params rparam;
2325 capi_profile profile;
2328 __u32 ncontr, contr;
2333 capifuncs = attach_capi_interface(&cuser);
2340 if ((p = strchr(revision, ':')) != 0 && p[1]) {
2341 strncpy(rev, p + 2, sizeof(rev));
2342 rev[sizeof(rev)-1] = 0;
2343 if ((p = strchr(rev, '$')) != 0 && p > rev)
2348 rparam.level3cnt = -2; /* number of bchannels twice */
2349 rparam.datablkcnt = 16;
2350 rparam.datablklen = 2048;
2351 errcode = (*capifuncs->capi_register) (&rparam, &global.appid);
2353 detach_capi_interface(&cuser);
2358 errcode = (*capifuncs->capi_get_profile) (0, &profile);
2359 if (errcode != CAPI_NOERROR) {
2360 (void) (*capifuncs->capi_release) (global.appid);
2361 detach_capi_interface(&cuser);
2366 (void) (*capifuncs->capi_set_signal) (global.appid, capidrv_signal, 0);
2368 ncontr = profile.ncontroller;
2369 for (contr = 1; contr <= ncontr; contr++) {
2370 errcode = (*capifuncs->capi_get_profile) (contr, &profile);
2371 if (errcode != CAPI_NOERROR)
2373 (void) capidrv_addcontr(contr, &profile);
2377 printk(KERN_NOTICE "capidrv: Rev %s: loaded\n", rev);
2383 static void __exit capidrv_exit(void)
2388 if ((p = strchr(revision, ':')) != 0) {
2390 p = strchr(rev, '$');
2393 strcpy(rev, " ??? ");
2396 (void) (*capifuncs->capi_release) (global.appid);
2398 detach_capi_interface(&cuser);
2402 printk(KERN_NOTICE "capidrv: Rev%s: unloaded\n", rev);
2405 module_init(capidrv_init);
2406 module_exit(capidrv_exit);