aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/isdn/capi
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 18:20:36 -0400
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 18:20:36 -0400
commit1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch)
tree0bba044c4ce775e45a88a51686b5d9f90697ea9d /drivers/isdn/capi
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history, even though we have it. We can create a separate "historical" git archive of that later if we want to, and in the meantime it's about 3.2GB when imported into git - space that would just make the early git days unnecessarily complicated, when we don't have a lot of good infrastructure for it. Let it rip!
Diffstat (limited to 'drivers/isdn/capi')
-rw-r--r--drivers/isdn/capi/Kconfig53
-rw-r--r--drivers/isdn/capi/Makefile15
-rw-r--r--drivers/isdn/capi/capi.c1554
-rw-r--r--drivers/isdn/capi/capidrv.c2315
-rw-r--r--drivers/isdn/capi/capidrv.h140
-rw-r--r--drivers/isdn/capi/capifs.c212
-rw-r--r--drivers/isdn/capi/capifs.h11
-rw-r--r--drivers/isdn/capi/capilib.c200
-rw-r--r--drivers/isdn/capi/capiutil.c859
-rw-r--r--drivers/isdn/capi/kcapi.c991
-rw-r--r--drivers/isdn/capi/kcapi.h49
-rw-r--r--drivers/isdn/capi/kcapi_proc.c336
12 files changed, 6735 insertions, 0 deletions
diff --git a/drivers/isdn/capi/Kconfig b/drivers/isdn/capi/Kconfig
new file mode 100644
index 000000000000..8b6c9a431ffa
--- /dev/null
+++ b/drivers/isdn/capi/Kconfig
@@ -0,0 +1,53 @@
1#
2# Config.in for the CAPI subsystem
3#
4config ISDN_DRV_AVMB1_VERBOSE_REASON
5 bool "Verbose reason code reporting (kernel size +=7K)"
6 depends on ISDN_CAPI
7 help
8 If you say Y here, the AVM B1 driver will give verbose reasons for
9 disconnecting. This will increase the size of the kernel by 7 KB. If
10 unsure, say Y.
11
12config ISDN_CAPI_MIDDLEWARE
13 bool "CAPI2.0 Middleware support (EXPERIMENTAL)"
14 depends on ISDN_CAPI && EXPERIMENTAL
15 help
16 This option will enhance the capabilities of the /dev/capi20
17 interface. It will provide a means of moving a data connection,
18 established via the usual /dev/capi20 interface to a special tty
19 device. If you want to use pppd with pppdcapiplugin to dial up to
20 your ISP, say Y here.
21
22config ISDN_CAPI_CAPI20
23 tristate "CAPI2.0 /dev/capi support"
24 depends on ISDN_CAPI
25 help
26 This option will provide the CAPI 2.0 interface to userspace
27 applications via /dev/capi20. Applications should use the
28 standardized libcapi20 to access this functionality. You should say
29 Y/M here.
30
31config ISDN_CAPI_CAPIFS_BOOL
32 bool "CAPI2.0 filesystem support"
33 depends on ISDN_CAPI_MIDDLEWARE && ISDN_CAPI_CAPI20
34
35config ISDN_CAPI_CAPIFS
36 tristate
37 depends on ISDN_CAPI_CAPIFS_BOOL
38 default ISDN_CAPI_CAPI20
39 help
40 This option provides a special file system, similar to /dev/pts with
41 device nodes for the special ttys established by using the
42 middleware extension above. If you want to use pppd with
43 pppdcapiplugin to dial up to your ISP, say Y here.
44
45config ISDN_CAPI_CAPIDRV
46 tristate "CAPI2.0 capidrv interface support"
47 depends on ISDN_CAPI && ISDN_I4L
48 help
49 This option provides the glue code to hook up CAPI driven cards to
50 the legacy isdn4linux link layer. If you have a card which is
51 supported by a CAPI driver, but still want to use old features like
52 ippp interfaces or ttyI emulation, say Y/M here.
53
diff --git a/drivers/isdn/capi/Makefile b/drivers/isdn/capi/Makefile
new file mode 100644
index 000000000000..57123e3e4978
--- /dev/null
+++ b/drivers/isdn/capi/Makefile
@@ -0,0 +1,15 @@
1# Makefile for the CAPI subsystem.
2
3# Ordering constraints: kernelcapi.o first
4
5# Each configuration option enables a list of files.
6
7obj-$(CONFIG_ISDN_CAPI) += kernelcapi.o
8obj-$(CONFIG_ISDN_CAPI_CAPI20) += capi.o
9obj-$(CONFIG_ISDN_CAPI_CAPIDRV) += capidrv.o
10obj-$(CONFIG_ISDN_CAPI_CAPIFS) += capifs.o
11
12# Multipart objects.
13
14kernelcapi-y := kcapi.o capiutil.o capilib.o
15kernelcapi-$(CONFIG_PROC_FS) += kcapi_proc.o
diff --git a/drivers/isdn/capi/capi.c b/drivers/isdn/capi/capi.c
new file mode 100644
index 000000000000..06163538bb20
--- /dev/null
+++ b/drivers/isdn/capi/capi.c
@@ -0,0 +1,1554 @@
1/* $Id: capi.c,v 1.1.2.7 2004/04/28 09:48:59 armin Exp $
2 *
3 * CAPI 2.0 Interface for Linux
4 *
5 * Copyright 1996 by Carsten Paeth <calle@calle.de>
6 *
7 * This software may be used and distributed according to the terms
8 * of the GNU General Public License, incorporated herein by reference.
9 *
10 */
11
12#include <linux/config.h>
13#include <linux/module.h>
14#include <linux/errno.h>
15#include <linux/kernel.h>
16#include <linux/major.h>
17#include <linux/sched.h>
18#include <linux/slab.h>
19#include <linux/fcntl.h>
20#include <linux/fs.h>
21#include <linux/signal.h>
22#include <linux/mm.h>
23#include <linux/smp_lock.h>
24#include <linux/timer.h>
25#include <linux/wait.h>
26#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
27#include <linux/tty.h>
28#ifdef CONFIG_PPP
29#include <linux/netdevice.h>
30#include <linux/ppp_defs.h>
31#include <linux/if_ppp.h>
32#endif /* CONFIG_PPP */
33#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
34#include <linux/skbuff.h>
35#include <linux/proc_fs.h>
36#include <linux/poll.h>
37#include <linux/capi.h>
38#include <linux/kernelcapi.h>
39#include <linux/init.h>
40#include <linux/device.h>
41#include <linux/moduleparam.h>
42#include <linux/devfs_fs_kernel.h>
43#include <linux/isdn/capiutil.h>
44#include <linux/isdn/capicmd.h>
45#if defined(CONFIG_ISDN_CAPI_CAPIFS) || defined(CONFIG_ISDN_CAPI_CAPIFS_MODULE)
46#include "capifs.h"
47#endif
48
49static char *revision = "$Revision: 1.1.2.7 $";
50
51MODULE_DESCRIPTION("CAPI4Linux: Userspace /dev/capi20 interface");
52MODULE_AUTHOR("Carsten Paeth");
53MODULE_LICENSE("GPL");
54
55#undef _DEBUG_REFCOUNT /* alloc/free and open/close debug */
56#undef _DEBUG_TTYFUNCS /* call to tty_driver */
57#undef _DEBUG_DATAFLOW /* data flow */
58
59/* -------- driver information -------------------------------------- */
60
61static struct class_simple *capi_class;
62
63int capi_major = 68; /* allocated */
64#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
65#define CAPINC_NR_PORTS 32
66#define CAPINC_MAX_PORTS 256
67int capi_ttymajor = 191;
68int capi_ttyminors = CAPINC_NR_PORTS;
69#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
70
71module_param_named(major, capi_major, uint, 0);
72#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
73module_param_named(ttymajor, capi_ttymajor, uint, 0);
74module_param_named(ttyminors, capi_ttyminors, uint, 0);
75#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
76
77/* -------- defines ------------------------------------------------- */
78
79#define CAPINC_MAX_RECVQUEUE 10
80#define CAPINC_MAX_SENDQUEUE 10
81#define CAPI_MAX_BLKSIZE 2048
82
83/* -------- data structures ----------------------------------------- */
84
85struct capidev;
86struct capincci;
87#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
88struct capiminor;
89
90struct capiminor {
91 struct list_head list;
92 struct capincci *nccip;
93 unsigned int minor;
94
95 struct capi20_appl *ap;
96 u32 ncci;
97 u16 datahandle;
98 u16 msgid;
99
100 struct tty_struct *tty;
101 int ttyinstop;
102 int ttyoutstop;
103 struct sk_buff *ttyskb;
104 atomic_t ttyopencount;
105
106 struct sk_buff_head inqueue;
107 int inbytes;
108 struct sk_buff_head outqueue;
109 int outbytes;
110
111 /* transmit path */
112 struct datahandle_queue {
113 struct datahandle_queue *next;
114 u16 datahandle;
115 } *ackqueue;
116 int nack;
117
118};
119#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
120
121struct capincci {
122 struct capincci *next;
123 u32 ncci;
124 struct capidev *cdev;
125#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
126 struct capiminor *minorp;
127#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
128};
129
130struct capidev {
131 struct list_head list;
132 struct capi20_appl ap;
133 u16 errcode;
134 unsigned userflags;
135
136 struct sk_buff_head recvqueue;
137 wait_queue_head_t recvwait;
138
139 struct capincci *nccis;
140
141 struct semaphore ncci_list_sem;
142};
143
144/* -------- global variables ---------------------------------------- */
145
146static DEFINE_RWLOCK(capidev_list_lock);
147static LIST_HEAD(capidev_list);
148
149#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
150static DEFINE_RWLOCK(capiminor_list_lock);
151static LIST_HEAD(capiminor_list);
152#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
153
154#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
155/* -------- datahandles --------------------------------------------- */
156
157static int capincci_add_ack(struct capiminor *mp, u16 datahandle)
158{
159 struct datahandle_queue *n, **pp;
160
161 n = kmalloc(sizeof(*n), GFP_ATOMIC);
162 if (!n) {
163 printk(KERN_ERR "capi: alloc datahandle failed\n");
164 return -1;
165 }
166 n->next = NULL;
167 n->datahandle = datahandle;
168 for (pp = &mp->ackqueue; *pp; pp = &(*pp)->next) ;
169 *pp = n;
170 mp->nack++;
171 return 0;
172}
173
174static int capiminor_del_ack(struct capiminor *mp, u16 datahandle)
175{
176 struct datahandle_queue **pp, *p;
177
178 for (pp = &mp->ackqueue; *pp; pp = &(*pp)->next) {
179 if ((*pp)->datahandle == datahandle) {
180 p = *pp;
181 *pp = (*pp)->next;
182 kfree(p);
183 mp->nack--;
184 return 0;
185 }
186 }
187 return -1;
188}
189
190static void capiminor_del_all_ack(struct capiminor *mp)
191{
192 struct datahandle_queue **pp, *p;
193
194 pp = &mp->ackqueue;
195 while (*pp) {
196 p = *pp;
197 *pp = (*pp)->next;
198 kfree(p);
199 mp->nack--;
200 }
201}
202
203
204/* -------- struct capiminor ---------------------------------------- */
205
206static struct capiminor *capiminor_alloc(struct capi20_appl *ap, u32 ncci)
207{
208 struct capiminor *mp, *p;
209 unsigned int minor = 0;
210 unsigned long flags;
211
212 mp = kmalloc(sizeof(*mp), GFP_ATOMIC);
213 if (!mp) {
214 printk(KERN_ERR "capi: can't alloc capiminor\n");
215 return NULL;
216 }
217
218 memset(mp, 0, sizeof(struct capiminor));
219 mp->ap = ap;
220 mp->ncci = ncci;
221 mp->msgid = 0;
222 atomic_set(&mp->ttyopencount,0);
223
224 skb_queue_head_init(&mp->inqueue);
225 skb_queue_head_init(&mp->outqueue);
226
227 /* Allocate the least unused minor number.
228 */
229 write_lock_irqsave(&capiminor_list_lock, flags);
230 if (list_empty(&capiminor_list))
231 list_add(&mp->list, &capiminor_list);
232 else {
233 list_for_each_entry(p, &capiminor_list, list) {
234 if (p->minor > minor)
235 break;
236 minor++;
237 }
238
239 if (minor < capi_ttyminors) {
240 mp->minor = minor;
241 list_add(&mp->list, p->list.prev);
242 }
243 }
244 write_unlock_irqrestore(&capiminor_list_lock, flags);
245
246 if (!(minor < capi_ttyminors)) {
247 printk(KERN_NOTICE "capi: out of minors\n");
248 kfree(mp);
249 return NULL;
250 }
251
252 return mp;
253}
254
255static void capiminor_free(struct capiminor *mp)
256{
257 unsigned long flags;
258
259 write_lock_irqsave(&capiminor_list_lock, flags);
260 list_del(&mp->list);
261 write_unlock_irqrestore(&capiminor_list_lock, flags);
262
263 if (mp->ttyskb) kfree_skb(mp->ttyskb);
264 mp->ttyskb = NULL;
265 skb_queue_purge(&mp->inqueue);
266 skb_queue_purge(&mp->outqueue);
267 capiminor_del_all_ack(mp);
268 kfree(mp);
269}
270
271struct capiminor *capiminor_find(unsigned int minor)
272{
273 struct list_head *l;
274 struct capiminor *p = NULL;
275
276 read_lock(&capiminor_list_lock);
277 list_for_each(l, &capiminor_list) {
278 p = list_entry(l, struct capiminor, list);
279 if (p->minor == minor)
280 break;
281 }
282 read_unlock(&capiminor_list_lock);
283 if (l == &capiminor_list)
284 return NULL;
285
286 return p;
287}
288#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
289
290/* -------- struct capincci ----------------------------------------- */
291
292static struct capincci *capincci_alloc(struct capidev *cdev, u32 ncci)
293{
294 struct capincci *np, **pp;
295#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
296 struct capiminor *mp = NULL;
297#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
298
299 np = kmalloc(sizeof(*np), GFP_ATOMIC);
300 if (!np)
301 return NULL;
302 memset(np, 0, sizeof(struct capincci));
303 np->ncci = ncci;
304 np->cdev = cdev;
305#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
306 mp = NULL;
307 if (cdev->userflags & CAPIFLAG_HIGHJACKING)
308 mp = np->minorp = capiminor_alloc(&cdev->ap, ncci);
309 if (mp) {
310 mp->nccip = np;
311#ifdef _DEBUG_REFCOUNT
312 printk(KERN_DEBUG "set mp->nccip\n");
313#endif
314#if defined(CONFIG_ISDN_CAPI_CAPIFS) || defined(CONFIG_ISDN_CAPI_CAPIFS_MODULE)
315 capifs_new_ncci(mp->minor, MKDEV(capi_ttymajor, mp->minor));
316#endif
317 }
318#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
319 for (pp=&cdev->nccis; *pp; pp = &(*pp)->next)
320 ;
321 *pp = np;
322 return np;
323}
324
325static void capincci_free(struct capidev *cdev, u32 ncci)
326{
327 struct capincci *np, **pp;
328#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
329 struct capiminor *mp;
330#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
331
332 pp=&cdev->nccis;
333 while (*pp) {
334 np = *pp;
335 if (ncci == 0xffffffff || np->ncci == ncci) {
336 *pp = (*pp)->next;
337#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
338 if ((mp = np->minorp) != 0) {
339#if defined(CONFIG_ISDN_CAPI_CAPIFS) || defined(CONFIG_ISDN_CAPI_CAPIFS_MODULE)
340 capifs_free_ncci(mp->minor);
341#endif
342 if (mp->tty) {
343 mp->nccip = NULL;
344#ifdef _DEBUG_REFCOUNT
345 printk(KERN_DEBUG "reset mp->nccip\n");
346#endif
347 tty_hangup(mp->tty);
348 } else {
349 capiminor_free(mp);
350 }
351 }
352#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
353 kfree(np);
354 if (*pp == 0) return;
355 } else {
356 pp = &(*pp)->next;
357 }
358 }
359}
360
361static struct capincci *capincci_find(struct capidev *cdev, u32 ncci)
362{
363 struct capincci *p;
364
365 for (p=cdev->nccis; p ; p = p->next) {
366 if (p->ncci == ncci)
367 break;
368 }
369 return p;
370}
371
372/* -------- struct capidev ------------------------------------------ */
373
374static struct capidev *capidev_alloc(void)
375{
376 struct capidev *cdev;
377 unsigned long flags;
378
379 cdev = kmalloc(sizeof(*cdev), GFP_KERNEL);
380 if (!cdev)
381 return NULL;
382 memset(cdev, 0, sizeof(struct capidev));
383
384 init_MUTEX(&cdev->ncci_list_sem);
385 skb_queue_head_init(&cdev->recvqueue);
386 init_waitqueue_head(&cdev->recvwait);
387 write_lock_irqsave(&capidev_list_lock, flags);
388 list_add_tail(&cdev->list, &capidev_list);
389 write_unlock_irqrestore(&capidev_list_lock, flags);
390 return cdev;
391}
392
393static void capidev_free(struct capidev *cdev)
394{
395 unsigned long flags;
396
397 if (cdev->ap.applid) {
398 capi20_release(&cdev->ap);
399 cdev->ap.applid = 0;
400 }
401 skb_queue_purge(&cdev->recvqueue);
402
403 down(&cdev->ncci_list_sem);
404 capincci_free(cdev, 0xffffffff);
405 up(&cdev->ncci_list_sem);
406
407 write_lock_irqsave(&capidev_list_lock, flags);
408 list_del(&cdev->list);
409 write_unlock_irqrestore(&capidev_list_lock, flags);
410 kfree(cdev);
411}
412
413#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
414/* -------- handle data queue --------------------------------------- */
415
416static struct sk_buff *
417gen_data_b3_resp_for(struct capiminor *mp, struct sk_buff *skb)
418{
419 struct sk_buff *nskb;
420 nskb = alloc_skb(CAPI_DATA_B3_RESP_LEN, GFP_ATOMIC);
421 if (nskb) {
422 u16 datahandle = CAPIMSG_U16(skb->data,CAPIMSG_BASELEN+4+4+2);
423 unsigned char *s = skb_put(nskb, CAPI_DATA_B3_RESP_LEN);
424 capimsg_setu16(s, 0, CAPI_DATA_B3_RESP_LEN);
425 capimsg_setu16(s, 2, mp->ap->applid);
426 capimsg_setu8 (s, 4, CAPI_DATA_B3);
427 capimsg_setu8 (s, 5, CAPI_RESP);
428 capimsg_setu16(s, 6, mp->msgid++);
429 capimsg_setu32(s, 8, mp->ncci);
430 capimsg_setu16(s, 12, datahandle);
431 }
432 return nskb;
433}
434
435static int handle_recv_skb(struct capiminor *mp, struct sk_buff *skb)
436{
437 struct sk_buff *nskb;
438 int datalen;
439 u16 errcode, datahandle;
440 struct tty_ldisc *ld;
441
442 datalen = skb->len - CAPIMSG_LEN(skb->data);
443 if (mp->tty == NULL)
444 {
445#ifdef _DEBUG_DATAFLOW
446 printk(KERN_DEBUG "capi: currently no receiver\n");
447#endif
448 return -1;
449 }
450
451 ld = tty_ldisc_ref(mp->tty);
452 if (ld == NULL)
453 return -1;
454 if (ld->receive_buf == NULL) {
455#if defined(_DEBUG_DATAFLOW) || defined(_DEBUG_TTYFUNCS)
456 printk(KERN_DEBUG "capi: ldisc has no receive_buf function\n");
457#endif
458 goto bad;
459 }
460 if (mp->ttyinstop) {
461#if defined(_DEBUG_DATAFLOW) || defined(_DEBUG_TTYFUNCS)
462 printk(KERN_DEBUG "capi: recv tty throttled\n");
463#endif
464 goto bad;
465 }
466 if (ld->receive_room &&
467 ld->receive_room(mp->tty) < datalen) {
468#if defined(_DEBUG_DATAFLOW) || defined(_DEBUG_TTYFUNCS)
469 printk(KERN_DEBUG "capi: no room in tty\n");
470#endif
471 goto bad;
472 }
473 if ((nskb = gen_data_b3_resp_for(mp, skb)) == 0) {
474 printk(KERN_ERR "capi: gen_data_b3_resp failed\n");
475 goto bad;
476 }
477 datahandle = CAPIMSG_U16(skb->data,CAPIMSG_BASELEN+4);
478 errcode = capi20_put_message(mp->ap, nskb);
479 if (errcode != CAPI_NOERROR) {
480 printk(KERN_ERR "capi: send DATA_B3_RESP failed=%x\n",
481 errcode);
482 kfree_skb(nskb);
483 goto bad;
484 }
485 (void)skb_pull(skb, CAPIMSG_LEN(skb->data));
486#ifdef _DEBUG_DATAFLOW
487 printk(KERN_DEBUG "capi: DATA_B3_RESP %u len=%d => ldisc\n",
488 datahandle, skb->len);
489#endif
490 ld->receive_buf(mp->tty, skb->data, NULL, skb->len);
491 kfree_skb(skb);
492 tty_ldisc_deref(ld);
493 return 0;
494bad:
495 tty_ldisc_deref(ld);
496 return -1;
497}
498
499static void handle_minor_recv(struct capiminor *mp)
500{
501 struct sk_buff *skb;
502 while ((skb = skb_dequeue(&mp->inqueue)) != 0) {
503 unsigned int len = skb->len;
504 mp->inbytes -= len;
505 if (handle_recv_skb(mp, skb) < 0) {
506 skb_queue_head(&mp->inqueue, skb);
507 mp->inbytes += len;
508 return;
509 }
510 }
511}
512
513static int handle_minor_send(struct capiminor *mp)
514{
515 struct sk_buff *skb;
516 u16 len;
517 int count = 0;
518 u16 errcode;
519 u16 datahandle;
520
521 if (mp->tty && mp->ttyoutstop) {
522#if defined(_DEBUG_DATAFLOW) || defined(_DEBUG_TTYFUNCS)
523 printk(KERN_DEBUG "capi: send: tty stopped\n");
524#endif
525 return 0;
526 }
527
528 while ((skb = skb_dequeue(&mp->outqueue)) != 0) {
529 datahandle = mp->datahandle;
530 len = (u16)skb->len;
531 skb_push(skb, CAPI_DATA_B3_REQ_LEN);
532 memset(skb->data, 0, CAPI_DATA_B3_REQ_LEN);
533 capimsg_setu16(skb->data, 0, CAPI_DATA_B3_REQ_LEN);
534 capimsg_setu16(skb->data, 2, mp->ap->applid);
535 capimsg_setu8 (skb->data, 4, CAPI_DATA_B3);
536 capimsg_setu8 (skb->data, 5, CAPI_REQ);
537 capimsg_setu16(skb->data, 6, mp->msgid++);
538 capimsg_setu32(skb->data, 8, mp->ncci); /* NCCI */
539 capimsg_setu32(skb->data, 12, (u32) skb->data); /* Data32 */
540 capimsg_setu16(skb->data, 16, len); /* Data length */
541 capimsg_setu16(skb->data, 18, datahandle);
542 capimsg_setu16(skb->data, 20, 0); /* Flags */
543
544 if (capincci_add_ack(mp, datahandle) < 0) {
545 skb_pull(skb, CAPI_DATA_B3_REQ_LEN);
546 skb_queue_head(&mp->outqueue, skb);
547 return count;
548 }
549 errcode = capi20_put_message(mp->ap, skb);
550 if (errcode == CAPI_NOERROR) {
551 mp->datahandle++;
552 count++;
553 mp->outbytes -= len;
554#ifdef _DEBUG_DATAFLOW
555 printk(KERN_DEBUG "capi: DATA_B3_REQ %u len=%u\n",
556 datahandle, len);
557#endif
558 continue;
559 }
560 capiminor_del_ack(mp, datahandle);
561
562 if (errcode == CAPI_SENDQUEUEFULL) {
563 skb_pull(skb, CAPI_DATA_B3_REQ_LEN);
564 skb_queue_head(&mp->outqueue, skb);
565 break;
566 }
567
568 /* ups, drop packet */
569 printk(KERN_ERR "capi: put_message = %x\n", errcode);
570 mp->outbytes -= len;
571 kfree_skb(skb);
572 }
573 return count;
574}
575
576#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
577/* -------- function called by lower level -------------------------- */
578
579static void capi_recv_message(struct capi20_appl *ap, struct sk_buff *skb)
580{
581 struct capidev *cdev = ap->private;
582#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
583 struct capiminor *mp;
584 u16 datahandle;
585#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
586 struct capincci *np;
587 u32 ncci;
588
589 if (CAPIMSG_CMD(skb->data) == CAPI_CONNECT_B3_CONF) {
590 u16 info = CAPIMSG_U16(skb->data, 12); // Info field
591 if (info == 0) {
592 down(&cdev->ncci_list_sem);
593 capincci_alloc(cdev, CAPIMSG_NCCI(skb->data));
594 up(&cdev->ncci_list_sem);
595 }
596 }
597 if (CAPIMSG_CMD(skb->data) == CAPI_CONNECT_B3_IND) {
598 down(&cdev->ncci_list_sem);
599 capincci_alloc(cdev, CAPIMSG_NCCI(skb->data));
600 up(&cdev->ncci_list_sem);
601 }
602 if (CAPIMSG_COMMAND(skb->data) != CAPI_DATA_B3) {
603 skb_queue_tail(&cdev->recvqueue, skb);
604 wake_up_interruptible(&cdev->recvwait);
605 return;
606 }
607 ncci = CAPIMSG_CONTROL(skb->data);
608 for (np = cdev->nccis; np && np->ncci != ncci; np = np->next)
609 ;
610 if (!np) {
611 printk(KERN_ERR "BUG: capi_signal: ncci not found\n");
612 skb_queue_tail(&cdev->recvqueue, skb);
613 wake_up_interruptible(&cdev->recvwait);
614 return;
615 }
616#ifndef CONFIG_ISDN_CAPI_MIDDLEWARE
617 skb_queue_tail(&cdev->recvqueue, skb);
618 wake_up_interruptible(&cdev->recvwait);
619#else /* CONFIG_ISDN_CAPI_MIDDLEWARE */
620 mp = np->minorp;
621 if (!mp) {
622 skb_queue_tail(&cdev->recvqueue, skb);
623 wake_up_interruptible(&cdev->recvwait);
624 return;
625 }
626
627
628 if (CAPIMSG_SUBCOMMAND(skb->data) == CAPI_IND) {
629
630 datahandle = CAPIMSG_U16(skb->data, CAPIMSG_BASELEN+4+4+2);
631#ifdef _DEBUG_DATAFLOW
632 printk(KERN_DEBUG "capi_signal: DATA_B3_IND %u len=%d\n",
633 datahandle, skb->len-CAPIMSG_LEN(skb->data));
634#endif
635 skb_queue_tail(&mp->inqueue, skb);
636 mp->inbytes += skb->len;
637 handle_minor_recv(mp);
638
639 } else if (CAPIMSG_SUBCOMMAND(skb->data) == CAPI_CONF) {
640
641 datahandle = CAPIMSG_U16(skb->data, CAPIMSG_BASELEN+4);
642#ifdef _DEBUG_DATAFLOW
643 printk(KERN_DEBUG "capi_signal: DATA_B3_CONF %u 0x%x\n",
644 datahandle,
645 CAPIMSG_U16(skb->data, CAPIMSG_BASELEN+4+2));
646#endif
647 kfree_skb(skb);
648 (void)capiminor_del_ack(mp, datahandle);
649 if (mp->tty)
650 tty_wakeup(mp->tty);
651 (void)handle_minor_send(mp);
652
653 } else {
654 /* ups, let capi application handle it :-) */
655 skb_queue_tail(&cdev->recvqueue, skb);
656 wake_up_interruptible(&cdev->recvwait);
657 }
658#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
659}
660
661/* -------- file_operations for capidev ----------------------------- */
662
663static ssize_t
664capi_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
665{
666 struct capidev *cdev = (struct capidev *)file->private_data;
667 struct sk_buff *skb;
668 size_t copied;
669
670 if (!cdev->ap.applid)
671 return -ENODEV;
672
673 if ((skb = skb_dequeue(&cdev->recvqueue)) == 0) {
674
675 if (file->f_flags & O_NONBLOCK)
676 return -EAGAIN;
677
678 for (;;) {
679 interruptible_sleep_on(&cdev->recvwait);
680 if ((skb = skb_dequeue(&cdev->recvqueue)) != 0)
681 break;
682 if (signal_pending(current))
683 break;
684 }
685 if (skb == 0)
686 return -ERESTARTNOHAND;
687 }
688 if (skb->len > count) {
689 skb_queue_head(&cdev->recvqueue, skb);
690 return -EMSGSIZE;
691 }
692 if (copy_to_user(buf, skb->data, skb->len)) {
693 skb_queue_head(&cdev->recvqueue, skb);
694 return -EFAULT;
695 }
696 copied = skb->len;
697
698 kfree_skb(skb);
699
700 return copied;
701}
702
703static ssize_t
704capi_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
705{
706 struct capidev *cdev = (struct capidev *)file->private_data;
707 struct sk_buff *skb;
708 u16 mlen;
709
710 if (!cdev->ap.applid)
711 return -ENODEV;
712
713 skb = alloc_skb(count, GFP_USER);
714 if (!skb)
715 return -ENOMEM;
716
717 if (copy_from_user(skb_put(skb, count), buf, count)) {
718 kfree_skb(skb);
719 return -EFAULT;
720 }
721 mlen = CAPIMSG_LEN(skb->data);
722 if (CAPIMSG_CMD(skb->data) == CAPI_DATA_B3_REQ) {
723 if ((size_t)(mlen + CAPIMSG_DATALEN(skb->data)) != count) {
724 kfree_skb(skb);
725 return -EINVAL;
726 }
727 } else {
728 if (mlen != count) {
729 kfree_skb(skb);
730 return -EINVAL;
731 }
732 }
733 CAPIMSG_SETAPPID(skb->data, cdev->ap.applid);
734
735 if (CAPIMSG_CMD(skb->data) == CAPI_DISCONNECT_B3_RESP) {
736 down(&cdev->ncci_list_sem);
737 capincci_free(cdev, CAPIMSG_NCCI(skb->data));
738 up(&cdev->ncci_list_sem);
739 }
740
741 cdev->errcode = capi20_put_message(&cdev->ap, skb);
742
743 if (cdev->errcode) {
744 kfree_skb(skb);
745 return -EIO;
746 }
747 return count;
748}
749
750static unsigned int
751capi_poll(struct file *file, poll_table * wait)
752{
753 struct capidev *cdev = (struct capidev *)file->private_data;
754 unsigned int mask = 0;
755
756 if (!cdev->ap.applid)
757 return POLLERR;
758
759 poll_wait(file, &(cdev->recvwait), wait);
760 mask = POLLOUT | POLLWRNORM;
761 if (!skb_queue_empty(&cdev->recvqueue))
762 mask |= POLLIN | POLLRDNORM;
763 return mask;
764}
765
766static int
767capi_ioctl(struct inode *inode, struct file *file,
768 unsigned int cmd, unsigned long arg)
769{
770 struct capidev *cdev = file->private_data;
771 struct capi20_appl *ap = &cdev->ap;
772 capi_ioctl_struct data;
773 int retval = -EINVAL;
774 void __user *argp = (void __user *)arg;
775
776 switch (cmd) {
777 case CAPI_REGISTER:
778 {
779 if (ap->applid)
780 return -EEXIST;
781
782 if (copy_from_user(&cdev->ap.rparam, argp,
783 sizeof(struct capi_register_params)))
784 return -EFAULT;
785
786 cdev->ap.private = cdev;
787 cdev->ap.recv_message = capi_recv_message;
788 cdev->errcode = capi20_register(ap);
789 if (cdev->errcode) {
790 ap->applid = 0;
791 return -EIO;
792 }
793 }
794 return (int)ap->applid;
795
796 case CAPI_GET_VERSION:
797 {
798 if (copy_from_user(&data.contr, argp,
799 sizeof(data.contr)))
800 return -EFAULT;
801 cdev->errcode = capi20_get_version(data.contr, &data.version);
802 if (cdev->errcode)
803 return -EIO;
804 if (copy_to_user(argp, &data.version,
805 sizeof(data.version)))
806 return -EFAULT;
807 }
808 return 0;
809
810 case CAPI_GET_SERIAL:
811 {
812 if (copy_from_user(&data.contr, argp,
813 sizeof(data.contr)))
814 return -EFAULT;
815 cdev->errcode = capi20_get_serial (data.contr, data.serial);
816 if (cdev->errcode)
817 return -EIO;
818 if (copy_to_user(argp, data.serial,
819 sizeof(data.serial)))
820 return -EFAULT;
821 }
822 return 0;
823 case CAPI_GET_PROFILE:
824 {
825 if (copy_from_user(&data.contr, argp,
826 sizeof(data.contr)))
827 return -EFAULT;
828
829 if (data.contr == 0) {
830 cdev->errcode = capi20_get_profile(data.contr, &data.profile);
831 if (cdev->errcode)
832 return -EIO;
833
834 retval = copy_to_user(argp,
835 &data.profile.ncontroller,
836 sizeof(data.profile.ncontroller));
837
838 } else {
839 cdev->errcode = capi20_get_profile(data.contr, &data.profile);
840 if (cdev->errcode)
841 return -EIO;
842
843 retval = copy_to_user(argp, &data.profile,
844 sizeof(data.profile));
845 }
846 if (retval)
847 return -EFAULT;
848 }
849 return 0;
850
851 case CAPI_GET_MANUFACTURER:
852 {
853 if (copy_from_user(&data.contr, argp,
854 sizeof(data.contr)))
855 return -EFAULT;
856 cdev->errcode = capi20_get_manufacturer(data.contr, data.manufacturer);
857 if (cdev->errcode)
858 return -EIO;
859
860 if (copy_to_user(argp, data.manufacturer,
861 sizeof(data.manufacturer)))
862 return -EFAULT;
863
864 }
865 return 0;
866 case CAPI_GET_ERRCODE:
867 data.errcode = cdev->errcode;
868 cdev->errcode = CAPI_NOERROR;
869 if (arg) {
870 if (copy_to_user(argp, &data.errcode,
871 sizeof(data.errcode)))
872 return -EFAULT;
873 }
874 return data.errcode;
875
876 case CAPI_INSTALLED:
877 if (capi20_isinstalled() == CAPI_NOERROR)
878 return 0;
879 return -ENXIO;
880
881 case CAPI_MANUFACTURER_CMD:
882 {
883 struct capi_manufacturer_cmd mcmd;
884 if (!capable(CAP_SYS_ADMIN))
885 return -EPERM;
886 if (copy_from_user(&mcmd, argp, sizeof(mcmd)))
887 return -EFAULT;
888 return capi20_manufacturer(mcmd.cmd, mcmd.data);
889 }
890 return 0;
891
892 case CAPI_SET_FLAGS:
893 case CAPI_CLR_FLAGS:
894 {
895 unsigned userflags;
896 if (copy_from_user(&userflags, argp,
897 sizeof(userflags)))
898 return -EFAULT;
899 if (cmd == CAPI_SET_FLAGS)
900 cdev->userflags |= userflags;
901 else
902 cdev->userflags &= ~userflags;
903 }
904 return 0;
905
906 case CAPI_GET_FLAGS:
907 if (copy_to_user(argp, &cdev->userflags,
908 sizeof(cdev->userflags)))
909 return -EFAULT;
910 return 0;
911
912 case CAPI_NCCI_OPENCOUNT:
913 {
914 struct capincci *nccip;
915#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
916 struct capiminor *mp;
917#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
918 unsigned ncci;
919 int count = 0;
920 if (copy_from_user(&ncci, argp, sizeof(ncci)))
921 return -EFAULT;
922
923 down(&cdev->ncci_list_sem);
924 if ((nccip = capincci_find(cdev, (u32) ncci)) == 0) {
925 up(&cdev->ncci_list_sem);
926 return 0;
927 }
928#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
929 if ((mp = nccip->minorp) != 0) {
930 count += atomic_read(&mp->ttyopencount);
931 }
932#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
933 up(&cdev->ncci_list_sem);
934 return count;
935 }
936 return 0;
937
938#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
939 case CAPI_NCCI_GETUNIT:
940 {
941 struct capincci *nccip;
942 struct capiminor *mp;
943 unsigned ncci;
944 int unit = 0;
945 if (copy_from_user(&ncci, argp,
946 sizeof(ncci)))
947 return -EFAULT;
948 down(&cdev->ncci_list_sem);
949 nccip = capincci_find(cdev, (u32) ncci);
950 if (!nccip || (mp = nccip->minorp) == 0) {
951 up(&cdev->ncci_list_sem);
952 return -ESRCH;
953 }
954 unit = mp->minor;
955 up(&cdev->ncci_list_sem);
956 return unit;
957 }
958 return 0;
959#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
960 }
961 return -EINVAL;
962}
963
964static int
965capi_open(struct inode *inode, struct file *file)
966{
967 if (file->private_data)
968 return -EEXIST;
969
970 if ((file->private_data = capidev_alloc()) == 0)
971 return -ENOMEM;
972
973 return nonseekable_open(inode, file);
974}
975
976static int
977capi_release(struct inode *inode, struct file *file)
978{
979 struct capidev *cdev = (struct capidev *)file->private_data;
980
981 capidev_free(cdev);
982 file->private_data = NULL;
983
984 return 0;
985}
986
987static struct file_operations capi_fops =
988{
989 .owner = THIS_MODULE,
990 .llseek = no_llseek,
991 .read = capi_read,
992 .write = capi_write,
993 .poll = capi_poll,
994 .ioctl = capi_ioctl,
995 .open = capi_open,
996 .release = capi_release,
997};
998
999#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
1000/* -------- tty_operations for capincci ----------------------------- */
1001
1002static int capinc_tty_open(struct tty_struct * tty, struct file * file)
1003{
1004 struct capiminor *mp;
1005
1006 if ((mp = capiminor_find(iminor(file->f_dentry->d_inode))) == 0)
1007 return -ENXIO;
1008 if (mp->nccip == 0)
1009 return -ENXIO;
1010
1011 tty->driver_data = (void *)mp;
1012
1013 if (atomic_read(&mp->ttyopencount) == 0)
1014 mp->tty = tty;
1015 atomic_inc(&mp->ttyopencount);
1016#ifdef _DEBUG_REFCOUNT
1017 printk(KERN_DEBUG "capinc_tty_open ocount=%d\n", atomic_read(&mp->ttyopencount));
1018#endif
1019 handle_minor_recv(mp);
1020 return 0;
1021}
1022
1023static void capinc_tty_close(struct tty_struct * tty, struct file * file)
1024{
1025 struct capiminor *mp;
1026
1027 mp = (struct capiminor *)tty->driver_data;
1028 if (mp) {
1029 if (atomic_dec_and_test(&mp->ttyopencount)) {
1030#ifdef _DEBUG_REFCOUNT
1031 printk(KERN_DEBUG "capinc_tty_close lastclose\n");
1032#endif
1033 tty->driver_data = NULL;
1034 mp->tty = NULL;
1035 }
1036#ifdef _DEBUG_REFCOUNT
1037 printk(KERN_DEBUG "capinc_tty_close ocount=%d\n", atomic_read(&mp->ttyopencount));
1038#endif
1039 if (mp->nccip == 0)
1040 capiminor_free(mp);
1041 }
1042
1043#ifdef _DEBUG_REFCOUNT
1044 printk(KERN_DEBUG "capinc_tty_close\n");
1045#endif
1046}
1047
1048static int capinc_tty_write(struct tty_struct * tty,
1049 const unsigned char *buf, int count)
1050{
1051 struct capiminor *mp = (struct capiminor *)tty->driver_data;
1052 struct sk_buff *skb;
1053
1054#ifdef _DEBUG_TTYFUNCS
1055 printk(KERN_DEBUG "capinc_tty_write(count=%d)\n", count);
1056#endif
1057
1058 if (!mp || !mp->nccip) {
1059#ifdef _DEBUG_TTYFUNCS
1060 printk(KERN_DEBUG "capinc_tty_write: mp or mp->ncci NULL\n");
1061#endif
1062 return 0;
1063 }
1064
1065 skb = mp->ttyskb;
1066 if (skb) {
1067 mp->ttyskb = NULL;
1068 skb_queue_tail(&mp->outqueue, skb);
1069 mp->outbytes += skb->len;
1070 }
1071
1072 skb = alloc_skb(CAPI_DATA_B3_REQ_LEN+count, GFP_ATOMIC);
1073 if (!skb) {
1074 printk(KERN_ERR "capinc_tty_write: alloc_skb failed\n");
1075 return -ENOMEM;
1076 }
1077
1078 skb_reserve(skb, CAPI_DATA_B3_REQ_LEN);
1079 memcpy(skb_put(skb, count), buf, count);
1080
1081 skb_queue_tail(&mp->outqueue, skb);
1082 mp->outbytes += skb->len;
1083 (void)handle_minor_send(mp);
1084 (void)handle_minor_recv(mp);
1085 return count;
1086}
1087
1088static void capinc_tty_put_char(struct tty_struct *tty, unsigned char ch)
1089{
1090 struct capiminor *mp = (struct capiminor *)tty->driver_data;
1091 struct sk_buff *skb;
1092
1093#ifdef _DEBUG_TTYFUNCS
1094 printk(KERN_DEBUG "capinc_put_char(%u)\n", ch);
1095#endif
1096
1097 if (!mp || !mp->nccip) {
1098#ifdef _DEBUG_TTYFUNCS
1099 printk(KERN_DEBUG "capinc_tty_put_char: mp or mp->ncci NULL\n");
1100#endif
1101 return;
1102 }
1103
1104 skb = mp->ttyskb;
1105 if (skb) {
1106 if (skb_tailroom(skb) > 0) {
1107 *(skb_put(skb, 1)) = ch;
1108 return;
1109 }
1110 mp->ttyskb = NULL;
1111 skb_queue_tail(&mp->outqueue, skb);
1112 mp->outbytes += skb->len;
1113 (void)handle_minor_send(mp);
1114 }
1115 skb = alloc_skb(CAPI_DATA_B3_REQ_LEN+CAPI_MAX_BLKSIZE, GFP_ATOMIC);
1116 if (skb) {
1117 skb_reserve(skb, CAPI_DATA_B3_REQ_LEN);
1118 *(skb_put(skb, 1)) = ch;
1119 mp->ttyskb = skb;
1120 } else {
1121 printk(KERN_ERR "capinc_put_char: char %u lost\n", ch);
1122 }
1123}
1124
1125static void capinc_tty_flush_chars(struct tty_struct *tty)
1126{
1127 struct capiminor *mp = (struct capiminor *)tty->driver_data;
1128 struct sk_buff *skb;
1129
1130#ifdef _DEBUG_TTYFUNCS
1131 printk(KERN_DEBUG "capinc_tty_flush_chars\n");
1132#endif
1133
1134 if (!mp || !mp->nccip) {
1135#ifdef _DEBUG_TTYFUNCS
1136 printk(KERN_DEBUG "capinc_tty_flush_chars: mp or mp->ncci NULL\n");
1137#endif
1138 return;
1139 }
1140
1141 skb = mp->ttyskb;
1142 if (skb) {
1143 mp->ttyskb = NULL;
1144 skb_queue_tail(&mp->outqueue, skb);
1145 mp->outbytes += skb->len;
1146 (void)handle_minor_send(mp);
1147 }
1148 (void)handle_minor_recv(mp);
1149}
1150
1151static int capinc_tty_write_room(struct tty_struct *tty)
1152{
1153 struct capiminor *mp = (struct capiminor *)tty->driver_data;
1154 int room;
1155 if (!mp || !mp->nccip) {
1156#ifdef _DEBUG_TTYFUNCS
1157 printk(KERN_DEBUG "capinc_tty_write_room: mp or mp->ncci NULL\n");
1158#endif
1159 return 0;
1160 }
1161 room = CAPINC_MAX_SENDQUEUE-skb_queue_len(&mp->outqueue);
1162 room *= CAPI_MAX_BLKSIZE;
1163#ifdef _DEBUG_TTYFUNCS
1164 printk(KERN_DEBUG "capinc_tty_write_room = %d\n", room);
1165#endif
1166 return room;
1167}
1168
1169int capinc_tty_chars_in_buffer(struct tty_struct *tty)
1170{
1171 struct capiminor *mp = (struct capiminor *)tty->driver_data;
1172 if (!mp || !mp->nccip) {
1173#ifdef _DEBUG_TTYFUNCS
1174 printk(KERN_DEBUG "capinc_tty_chars_in_buffer: mp or mp->ncci NULL\n");
1175#endif
1176 return 0;
1177 }
1178#ifdef _DEBUG_TTYFUNCS
1179 printk(KERN_DEBUG "capinc_tty_chars_in_buffer = %d nack=%d sq=%d rq=%d\n",
1180 mp->outbytes, mp->nack,
1181 skb_queue_len(&mp->outqueue),
1182 skb_queue_len(&mp->inqueue));
1183#endif
1184 return mp->outbytes;
1185}
1186
1187static int capinc_tty_ioctl(struct tty_struct *tty, struct file * file,
1188 unsigned int cmd, unsigned long arg)
1189{
1190 int error = 0;
1191 switch (cmd) {
1192 default:
1193 error = n_tty_ioctl (tty, file, cmd, arg);
1194 break;
1195 }
1196 return error;
1197}
1198
1199static void capinc_tty_set_termios(struct tty_struct *tty, struct termios * old)
1200{
1201#ifdef _DEBUG_TTYFUNCS
1202 printk(KERN_DEBUG "capinc_tty_set_termios\n");
1203#endif
1204}
1205
1206static void capinc_tty_throttle(struct tty_struct * tty)
1207{
1208 struct capiminor *mp = (struct capiminor *)tty->driver_data;
1209#ifdef _DEBUG_TTYFUNCS
1210 printk(KERN_DEBUG "capinc_tty_throttle\n");
1211#endif
1212 if (mp)
1213 mp->ttyinstop = 1;
1214}
1215
1216static void capinc_tty_unthrottle(struct tty_struct * tty)
1217{
1218 struct capiminor *mp = (struct capiminor *)tty->driver_data;
1219#ifdef _DEBUG_TTYFUNCS
1220 printk(KERN_DEBUG "capinc_tty_unthrottle\n");
1221#endif
1222 if (mp) {
1223 mp->ttyinstop = 0;
1224 handle_minor_recv(mp);
1225 }
1226}
1227
1228static void capinc_tty_stop(struct tty_struct *tty)
1229{
1230 struct capiminor *mp = (struct capiminor *)tty->driver_data;
1231#ifdef _DEBUG_TTYFUNCS
1232 printk(KERN_DEBUG "capinc_tty_stop\n");
1233#endif
1234 if (mp) {
1235 mp->ttyoutstop = 1;
1236 }
1237}
1238
1239static void capinc_tty_start(struct tty_struct *tty)
1240{
1241 struct capiminor *mp = (struct capiminor *)tty->driver_data;
1242#ifdef _DEBUG_TTYFUNCS
1243 printk(KERN_DEBUG "capinc_tty_start\n");
1244#endif
1245 if (mp) {
1246 mp->ttyoutstop = 0;
1247 (void)handle_minor_send(mp);
1248 }
1249}
1250
1251static void capinc_tty_hangup(struct tty_struct *tty)
1252{
1253#ifdef _DEBUG_TTYFUNCS
1254 printk(KERN_DEBUG "capinc_tty_hangup\n");
1255#endif
1256}
1257
1258static void capinc_tty_break_ctl(struct tty_struct *tty, int state)
1259{
1260#ifdef _DEBUG_TTYFUNCS
1261 printk(KERN_DEBUG "capinc_tty_break_ctl(%d)\n", state);
1262#endif
1263}
1264
1265static void capinc_tty_flush_buffer(struct tty_struct *tty)
1266{
1267#ifdef _DEBUG_TTYFUNCS
1268 printk(KERN_DEBUG "capinc_tty_flush_buffer\n");
1269#endif
1270}
1271
1272static void capinc_tty_set_ldisc(struct tty_struct *tty)
1273{
1274#ifdef _DEBUG_TTYFUNCS
1275 printk(KERN_DEBUG "capinc_tty_set_ldisc\n");
1276#endif
1277}
1278
1279static void capinc_tty_send_xchar(struct tty_struct *tty, char ch)
1280{
1281#ifdef _DEBUG_TTYFUNCS
1282 printk(KERN_DEBUG "capinc_tty_send_xchar(%d)\n", ch);
1283#endif
1284}
1285
1286static int capinc_tty_read_proc(char *page, char **start, off_t off,
1287 int count, int *eof, void *data)
1288{
1289 return 0;
1290}
1291
1292static struct tty_driver *capinc_tty_driver;
1293
1294static struct tty_operations capinc_ops = {
1295 .open = capinc_tty_open,
1296 .close = capinc_tty_close,
1297 .write = capinc_tty_write,
1298 .put_char = capinc_tty_put_char,
1299 .flush_chars = capinc_tty_flush_chars,
1300 .write_room = capinc_tty_write_room,
1301 .chars_in_buffer = capinc_tty_chars_in_buffer,
1302 .ioctl = capinc_tty_ioctl,
1303 .set_termios = capinc_tty_set_termios,
1304 .throttle = capinc_tty_throttle,
1305 .unthrottle = capinc_tty_unthrottle,
1306 .stop = capinc_tty_stop,
1307 .start = capinc_tty_start,
1308 .hangup = capinc_tty_hangup,
1309 .break_ctl = capinc_tty_break_ctl,
1310 .flush_buffer = capinc_tty_flush_buffer,
1311 .set_ldisc = capinc_tty_set_ldisc,
1312 .send_xchar = capinc_tty_send_xchar,
1313 .read_proc = capinc_tty_read_proc,
1314};
1315
1316static int capinc_tty_init(void)
1317{
1318 struct tty_driver *drv;
1319
1320 if (capi_ttyminors > CAPINC_MAX_PORTS)
1321 capi_ttyminors = CAPINC_MAX_PORTS;
1322 if (capi_ttyminors <= 0)
1323 capi_ttyminors = CAPINC_NR_PORTS;
1324
1325 drv = alloc_tty_driver(capi_ttyminors);
1326 if (!drv)
1327 return -ENOMEM;
1328
1329 drv->owner = THIS_MODULE;
1330 drv->driver_name = "capi_nc";
1331 drv->devfs_name = "capi/";
1332 drv->name = "capi";
1333 drv->major = capi_ttymajor;
1334 drv->minor_start = 0;
1335 drv->type = TTY_DRIVER_TYPE_SERIAL;
1336 drv->subtype = SERIAL_TYPE_NORMAL;
1337 drv->init_termios = tty_std_termios;
1338 drv->init_termios.c_iflag = ICRNL;
1339 drv->init_termios.c_oflag = OPOST | ONLCR;
1340 drv->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
1341 drv->init_termios.c_lflag = 0;
1342 drv->flags = TTY_DRIVER_REAL_RAW|TTY_DRIVER_RESET_TERMIOS;
1343 tty_set_operations(drv, &capinc_ops);
1344 if (tty_register_driver(drv)) {
1345 put_tty_driver(drv);
1346 printk(KERN_ERR "Couldn't register capi_nc driver\n");
1347 return -1;
1348 }
1349 capinc_tty_driver = drv;
1350 return 0;
1351}
1352
1353static void capinc_tty_exit(void)
1354{
1355 struct tty_driver *drv = capinc_tty_driver;
1356 int retval;
1357 if ((retval = tty_unregister_driver(drv)))
1358 printk(KERN_ERR "capi: failed to unregister capi_nc driver (%d)\n", retval);
1359 put_tty_driver(drv);
1360}
1361
1362#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
1363
1364/* -------- /proc functions ----------------------------------------- */
1365
1366/*
1367 * /proc/capi/capi20:
1368 * minor applid nrecvctlpkt nrecvdatapkt nsendctlpkt nsenddatapkt
1369 */
1370static int proc_capidev_read_proc(char *page, char **start, off_t off,
1371 int count, int *eof, void *data)
1372{
1373 struct capidev *cdev;
1374 struct list_head *l;
1375 int len = 0;
1376
1377 read_lock(&capidev_list_lock);
1378 list_for_each(l, &capidev_list) {
1379 cdev = list_entry(l, struct capidev, list);
1380 len += sprintf(page+len, "0 %d %lu %lu %lu %lu\n",
1381 cdev->ap.applid,
1382 cdev->ap.nrecvctlpkt,
1383 cdev->ap.nrecvdatapkt,
1384 cdev->ap.nsentctlpkt,
1385 cdev->ap.nsentdatapkt);
1386 if (len <= off) {
1387 off -= len;
1388 len = 0;
1389 } else {
1390 if (len-off > count)
1391 goto endloop;
1392 }
1393 }
1394
1395endloop:
1396 read_unlock(&capidev_list_lock);
1397 if (len < count)
1398 *eof = 1;
1399 if (len > count) len = count;
1400 if (len < 0) len = 0;
1401 return len;
1402}
1403
1404/*
1405 * /proc/capi/capi20ncci:
1406 * applid ncci
1407 */
1408static int proc_capincci_read_proc(char *page, char **start, off_t off,
1409 int count, int *eof, void *data)
1410{
1411 struct capidev *cdev;
1412 struct capincci *np;
1413 struct list_head *l;
1414 int len = 0;
1415
1416 read_lock(&capidev_list_lock);
1417 list_for_each(l, &capidev_list) {
1418 cdev = list_entry(l, struct capidev, list);
1419 for (np=cdev->nccis; np; np = np->next) {
1420 len += sprintf(page+len, "%d 0x%x\n",
1421 cdev->ap.applid,
1422 np->ncci);
1423 if (len <= off) {
1424 off -= len;
1425 len = 0;
1426 } else {
1427 if (len-off > count)
1428 goto endloop;
1429 }
1430 }
1431 }
1432endloop:
1433 read_unlock(&capidev_list_lock);
1434 *start = page+off;
1435 if (len < count)
1436 *eof = 1;
1437 if (len>count) len = count;
1438 if (len<0) len = 0;
1439 return len;
1440}
1441
1442static struct procfsentries {
1443 char *name;
1444 mode_t mode;
1445 int (*read_proc)(char *page, char **start, off_t off,
1446 int count, int *eof, void *data);
1447 struct proc_dir_entry *procent;
1448} procfsentries[] = {
1449 /* { "capi", S_IFDIR, 0 }, */
1450 { "capi/capi20", 0 , proc_capidev_read_proc },
1451 { "capi/capi20ncci", 0 , proc_capincci_read_proc },
1452};
1453
1454static void __init proc_init(void)
1455{
1456 int nelem = sizeof(procfsentries)/sizeof(procfsentries[0]);
1457 int i;
1458
1459 for (i=0; i < nelem; i++) {
1460 struct procfsentries *p = procfsentries + i;
1461 p->procent = create_proc_entry(p->name, p->mode, NULL);
1462 if (p->procent) p->procent->read_proc = p->read_proc;
1463 }
1464}
1465
1466static void __exit proc_exit(void)
1467{
1468 int nelem = sizeof(procfsentries)/sizeof(procfsentries[0]);
1469 int i;
1470
1471 for (i=nelem-1; i >= 0; i--) {
1472 struct procfsentries *p = procfsentries + i;
1473 if (p->procent) {
1474 remove_proc_entry(p->name, NULL);
1475 p->procent = NULL;
1476 }
1477 }
1478}
1479
1480/* -------- init function and module interface ---------------------- */
1481
1482
1483static char rev[32];
1484
1485static int __init capi_init(void)
1486{
1487 char *p;
1488 char *compileinfo;
1489
1490 if ((p = strchr(revision, ':')) != 0 && p[1]) {
1491 strlcpy(rev, p + 2, sizeof(rev));
1492 if ((p = strchr(rev, '$')) != 0 && p > rev)
1493 *(p-1) = 0;
1494 } else
1495 strcpy(rev, "1.0");
1496
1497 if (register_chrdev(capi_major, "capi20", &capi_fops)) {
1498 printk(KERN_ERR "capi20: unable to get major %d\n", capi_major);
1499 return -EIO;
1500 }
1501
1502 capi_class = class_simple_create(THIS_MODULE, "capi");
1503 if (IS_ERR(capi_class)) {
1504 unregister_chrdev(capi_major, "capi20");
1505 return PTR_ERR(capi_class);
1506 }
1507
1508 class_simple_device_add(capi_class, MKDEV(capi_major, 0), NULL, "capi");
1509 devfs_mk_cdev(MKDEV(capi_major, 0), S_IFCHR | S_IRUSR | S_IWUSR,
1510 "isdn/capi20");
1511
1512#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
1513 if (capinc_tty_init() < 0) {
1514 class_simple_device_remove(MKDEV(capi_major, 0));
1515 class_simple_destroy(capi_class);
1516 unregister_chrdev(capi_major, "capi20");
1517 return -ENOMEM;
1518 }
1519#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
1520
1521 proc_init();
1522
1523#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
1524#if defined(CONFIG_ISDN_CAPI_CAPIFS) || defined(CONFIG_ISDN_CAPI_CAPIFS_MODULE)
1525 compileinfo = " (middleware+capifs)";
1526#else
1527 compileinfo = " (no capifs)";
1528#endif
1529#else
1530 compileinfo = " (no middleware)";
1531#endif
1532 printk(KERN_NOTICE "capi20: Rev %s: started up with major %d%s\n",
1533 rev, capi_major, compileinfo);
1534
1535 return 0;
1536}
1537
1538static void __exit capi_exit(void)
1539{
1540 proc_exit();
1541
1542 class_simple_device_remove(MKDEV(capi_major, 0));
1543 class_simple_destroy(capi_class);
1544 unregister_chrdev(capi_major, "capi20");
1545 devfs_remove("isdn/capi20");
1546
1547#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
1548 capinc_tty_exit();
1549#endif
1550 printk(KERN_NOTICE "capi: Rev %s: unloaded\n", rev);
1551}
1552
1553module_init(capi_init);
1554module_exit(capi_exit);
diff --git a/drivers/isdn/capi/capidrv.c b/drivers/isdn/capi/capidrv.c
new file mode 100644
index 000000000000..d10c8b82e6aa
--- /dev/null
+++ b/drivers/isdn/capi/capidrv.c
@@ -0,0 +1,2315 @@
1/* $Id: capidrv.c,v 1.1.2.2 2004/01/12 23:17:24 keil Exp $
2 *
3 * ISDN4Linux Driver, using capi20 interface (kernelcapi)
4 *
5 * Copyright 1997 by Carsten Paeth <calle@calle.de>
6 *
7 * This software may be used and distributed according to the terms
8 * of the GNU General Public License, incorporated herein by reference.
9 *
10 */
11
12#include <linux/module.h>
13#include <linux/errno.h>
14#include <linux/kernel.h>
15#include <linux/major.h>
16#include <linux/sched.h>
17#include <linux/slab.h>
18#include <linux/fcntl.h>
19#include <linux/fs.h>
20#include <linux/signal.h>
21#include <linux/mm.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 <linux/moduleparam.h>
33
34#include <linux/isdn/capiutil.h>
35#include <linux/isdn/capicmd.h>
36#include "capidrv.h"
37
38static char *revision = "$Revision: 1.1.2.2 $";
39static int debugmode = 0;
40
41MODULE_DESCRIPTION("CAPI4Linux: Interface to ISDN4Linux");
42MODULE_AUTHOR("Carsten Paeth");
43MODULE_LICENSE("GPL");
44module_param(debugmode, uint, 0);
45
46/* -------- type definitions ----------------------------------------- */
47
48
49struct capidrv_contr {
50
51 struct capidrv_contr *next;
52 struct module *owner;
53 u32 contrnr;
54 char name[20];
55
56 /*
57 * for isdn4linux
58 */
59 isdn_if interface;
60 int myid;
61
62 /*
63 * LISTEN state
64 */
65 int state;
66 u32 cipmask;
67 u32 cipmask2;
68 struct timer_list listentimer;
69
70 /*
71 * ID of capi message sent
72 */
73 u16 msgid;
74
75 /*
76 * B-Channels
77 */
78 int nbchan;
79 struct capidrv_bchan {
80 struct capidrv_contr *contr;
81 u8 msn[ISDN_MSNLEN];
82 int l2;
83 int l3;
84 u8 num[ISDN_MSNLEN];
85 u8 mynum[ISDN_MSNLEN];
86 int si1;
87 int si2;
88 int incoming;
89 int disconnecting;
90 struct capidrv_plci {
91 struct capidrv_plci *next;
92 u32 plci;
93 u32 ncci; /* ncci for CONNECT_ACTIVE_IND */
94 u16 msgid; /* to identfy CONNECT_CONF */
95 int chan;
96 int state;
97 int leasedline;
98 struct capidrv_ncci {
99 struct capidrv_ncci *next;
100 struct capidrv_plci *plcip;
101 u32 ncci;
102 u16 msgid; /* to identfy CONNECT_B3_CONF */
103 int chan;
104 int state;
105 int oldstate;
106 /* */
107 u16 datahandle;
108 struct ncci_datahandle_queue {
109 struct ncci_datahandle_queue *next;
110 u16 datahandle;
111 int len;
112 } *ackqueue;
113 } *ncci_list;
114 } *plcip;
115 struct capidrv_ncci *nccip;
116 } *bchans;
117
118 struct capidrv_plci *plci_list;
119
120 /* for q931 data */
121 u8 q931_buf[4096];
122 u8 *q931_read;
123 u8 *q931_write;
124 u8 *q931_end;
125};
126
127
128struct capidrv_data {
129 struct capi20_appl ap;
130 int ncontr;
131 struct capidrv_contr *contr_list;
132};
133
134typedef struct capidrv_plci capidrv_plci;
135typedef struct capidrv_ncci capidrv_ncci;
136typedef struct capidrv_contr capidrv_contr;
137typedef struct capidrv_data capidrv_data;
138typedef struct capidrv_bchan capidrv_bchan;
139
140/* -------- data definitions ----------------------------------------- */
141
142static capidrv_data global;
143static DEFINE_SPINLOCK(global_lock);
144
145static void handle_dtrace_data(capidrv_contr *card,
146 int send, int level2, u8 *data, u16 len);
147
148/* -------- convert functions ---------------------------------------- */
149
150static inline u32 b1prot(int l2, int l3)
151{
152 switch (l2) {
153 case ISDN_PROTO_L2_X75I:
154 case ISDN_PROTO_L2_X75UI:
155 case ISDN_PROTO_L2_X75BUI:
156 return 0;
157 case ISDN_PROTO_L2_HDLC:
158 default:
159 return 0;
160 case ISDN_PROTO_L2_TRANS:
161 return 1;
162 case ISDN_PROTO_L2_V11096:
163 case ISDN_PROTO_L2_V11019:
164 case ISDN_PROTO_L2_V11038:
165 return 2;
166 case ISDN_PROTO_L2_FAX:
167 return 4;
168 case ISDN_PROTO_L2_MODEM:
169 return 8;
170 }
171}
172
173static inline u32 b2prot(int l2, int l3)
174{
175 switch (l2) {
176 case ISDN_PROTO_L2_X75I:
177 case ISDN_PROTO_L2_X75UI:
178 case ISDN_PROTO_L2_X75BUI:
179 default:
180 return 0;
181 case ISDN_PROTO_L2_HDLC:
182 case ISDN_PROTO_L2_TRANS:
183 case ISDN_PROTO_L2_V11096:
184 case ISDN_PROTO_L2_V11019:
185 case ISDN_PROTO_L2_V11038:
186 case ISDN_PROTO_L2_MODEM:
187 return 1;
188 case ISDN_PROTO_L2_FAX:
189 return 4;
190 }
191}
192
193static inline u32 b3prot(int l2, int l3)
194{
195 switch (l2) {
196 case ISDN_PROTO_L2_X75I:
197 case ISDN_PROTO_L2_X75UI:
198 case ISDN_PROTO_L2_X75BUI:
199 case ISDN_PROTO_L2_HDLC:
200 case ISDN_PROTO_L2_TRANS:
201 case ISDN_PROTO_L2_V11096:
202 case ISDN_PROTO_L2_V11019:
203 case ISDN_PROTO_L2_V11038:
204 case ISDN_PROTO_L2_MODEM:
205 default:
206 return 0;
207 case ISDN_PROTO_L2_FAX:
208 return 4;
209 }
210}
211
212static _cstruct b1config_async_v110(u16 rate)
213{
214 /* CAPI-Spec "B1 Configuration" */
215 static unsigned char buf[9];
216 buf[0] = 8; /* len */
217 /* maximum bitrate */
218 buf[1] = rate & 0xff; buf[2] = (rate >> 8) & 0xff;
219 buf[3] = 8; buf[4] = 0; /* 8 bits per character */
220 buf[5] = 0; buf[6] = 0; /* parity none */
221 buf[7] = 0; buf[8] = 0; /* 1 stop bit */
222 return buf;
223}
224
225static _cstruct b1config(int l2, int l3)
226{
227 switch (l2) {
228 case ISDN_PROTO_L2_X75I:
229 case ISDN_PROTO_L2_X75UI:
230 case ISDN_PROTO_L2_X75BUI:
231 case ISDN_PROTO_L2_HDLC:
232 case ISDN_PROTO_L2_TRANS:
233 default:
234 return NULL;
235 case ISDN_PROTO_L2_V11096:
236 return b1config_async_v110(9600);
237 case ISDN_PROTO_L2_V11019:
238 return b1config_async_v110(19200);
239 case ISDN_PROTO_L2_V11038:
240 return b1config_async_v110(38400);
241 }
242}
243
244static inline u16 si2cip(u8 si1, u8 si2)
245{
246 static const u8 cip[17][5] =
247 {
248 /* 0 1 2 3 4 */
249 {0, 0, 0, 0, 0}, /*0 */
250 {16, 16, 4, 26, 16}, /*1 */
251 {17, 17, 17, 4, 4}, /*2 */
252 {2, 2, 2, 2, 2}, /*3 */
253 {18, 18, 18, 18, 18}, /*4 */
254 {2, 2, 2, 2, 2}, /*5 */
255 {0, 0, 0, 0, 0}, /*6 */
256 {2, 2, 2, 2, 2}, /*7 */
257 {2, 2, 2, 2, 2}, /*8 */
258 {21, 21, 21, 21, 21}, /*9 */
259 {19, 19, 19, 19, 19}, /*10 */
260 {0, 0, 0, 0, 0}, /*11 */
261 {0, 0, 0, 0, 0}, /*12 */
262 {0, 0, 0, 0, 0}, /*13 */
263 {0, 0, 0, 0, 0}, /*14 */
264 {22, 22, 22, 22, 22}, /*15 */
265 {27, 27, 27, 28, 27} /*16 */
266 };
267 if (si1 > 16)
268 si1 = 0;
269 if (si2 > 4)
270 si2 = 0;
271
272 return (u16) cip[si1][si2];
273}
274
275static inline u8 cip2si1(u16 cipval)
276{
277 static const u8 si[32] =
278 {7, 1, 7, 7, 1, 1, 7, 7, /*0-7 */
279 7, 1, 0, 0, 0, 0, 0, 0, /*8-15 */
280 1, 2, 4, 10, 9, 9, 15, 7, /*16-23 */
281 7, 7, 1, 16, 16, 0, 0, 0}; /*24-31 */
282
283 if (cipval > 31)
284 cipval = 0; /* .... */
285 return si[cipval];
286}
287
288static inline u8 cip2si2(u16 cipval)
289{
290 static const u8 si[32] =
291 {0, 0, 0, 0, 2, 3, 0, 0, /*0-7 */
292 0, 3, 0, 0, 0, 0, 0, 0, /*8-15 */
293 1, 2, 0, 0, 9, 0, 0, 0, /*16-23 */
294 0, 0, 3, 2, 3, 0, 0, 0}; /*24-31 */
295
296 if (cipval > 31)
297 cipval = 0; /* .... */
298 return si[cipval];
299}
300
301
302/* -------- controller management ------------------------------------- */
303
304static inline capidrv_contr *findcontrbydriverid(int driverid)
305{
306 unsigned long flags;
307 capidrv_contr *p;
308
309 spin_lock_irqsave(&global_lock, flags);
310 for (p = global.contr_list; p; p = p->next)
311 if (p->myid == driverid)
312 break;
313 spin_unlock_irqrestore(&global_lock, flags);
314 return p;
315}
316
317static capidrv_contr *findcontrbynumber(u32 contr)
318{
319 unsigned long flags;
320 capidrv_contr *p = global.contr_list;
321
322 spin_lock_irqsave(&global_lock, flags);
323 for (p = global.contr_list; p; p = p->next)
324 if (p->contrnr == contr)
325 break;
326 spin_unlock_irqrestore(&global_lock, flags);
327 return p;
328}
329
330
331/* -------- plci management ------------------------------------------ */
332
333static capidrv_plci *new_plci(capidrv_contr * card, int chan)
334{
335 capidrv_plci *plcip;
336
337 plcip = (capidrv_plci *) kmalloc(sizeof(capidrv_plci), GFP_ATOMIC);
338
339 if (plcip == 0)
340 return NULL;
341
342 memset(plcip, 0, sizeof(capidrv_plci));
343 plcip->state = ST_PLCI_NONE;
344 plcip->plci = 0;
345 plcip->msgid = 0;
346 plcip->chan = chan;
347 plcip->next = card->plci_list;
348 card->plci_list = plcip;
349 card->bchans[chan].plcip = plcip;
350
351 return plcip;
352}
353
354static capidrv_plci *find_plci_by_plci(capidrv_contr * card, u32 plci)
355{
356 capidrv_plci *p;
357 for (p = card->plci_list; p; p = p->next)
358 if (p->plci == plci)
359 return p;
360 return NULL;
361}
362
363static capidrv_plci *find_plci_by_msgid(capidrv_contr * card, u16 msgid)
364{
365 capidrv_plci *p;
366 for (p = card->plci_list; p; p = p->next)
367 if (p->msgid == msgid)
368 return p;
369 return NULL;
370}
371
372static capidrv_plci *find_plci_by_ncci(capidrv_contr * card, u32 ncci)
373{
374 capidrv_plci *p;
375 for (p = card->plci_list; p; p = p->next)
376 if (p->plci == (ncci & 0xffff))
377 return p;
378 return NULL;
379}
380
381static void free_plci(capidrv_contr * card, capidrv_plci * plcip)
382{
383 capidrv_plci **pp;
384
385 for (pp = &card->plci_list; *pp; pp = &(*pp)->next) {
386 if (*pp == plcip) {
387 *pp = (*pp)->next;
388 card->bchans[plcip->chan].plcip = NULL;
389 card->bchans[plcip->chan].disconnecting = 0;
390 card->bchans[plcip->chan].incoming = 0;
391 kfree(plcip);
392 return;
393 }
394 }
395 printk(KERN_ERR "capidrv-%d: free_plci %p (0x%x) not found, Huh?\n",
396 card->contrnr, plcip, plcip->plci);
397}
398
399/* -------- ncci management ------------------------------------------ */
400
401static inline capidrv_ncci *new_ncci(capidrv_contr * card,
402 capidrv_plci * plcip,
403 u32 ncci)
404{
405 capidrv_ncci *nccip;
406
407 nccip = (capidrv_ncci *) kmalloc(sizeof(capidrv_ncci), GFP_ATOMIC);
408
409 if (nccip == 0)
410 return NULL;
411
412 memset(nccip, 0, sizeof(capidrv_ncci));
413 nccip->ncci = ncci;
414 nccip->state = ST_NCCI_NONE;
415 nccip->plcip = plcip;
416 nccip->chan = plcip->chan;
417 nccip->datahandle = 0;
418
419 nccip->next = plcip->ncci_list;
420 plcip->ncci_list = nccip;
421
422 card->bchans[plcip->chan].nccip = nccip;
423
424 return nccip;
425}
426
427static inline capidrv_ncci *find_ncci(capidrv_contr * card, u32 ncci)
428{
429 capidrv_plci *plcip;
430 capidrv_ncci *p;
431
432 if ((plcip = find_plci_by_ncci(card, ncci)) == 0)
433 return NULL;
434
435 for (p = plcip->ncci_list; p; p = p->next)
436 if (p->ncci == ncci)
437 return p;
438 return NULL;
439}
440
441static inline capidrv_ncci *find_ncci_by_msgid(capidrv_contr * card,
442 u32 ncci, u16 msgid)
443{
444 capidrv_plci *plcip;
445 capidrv_ncci *p;
446
447 if ((plcip = find_plci_by_ncci(card, ncci)) == 0)
448 return NULL;
449
450 for (p = plcip->ncci_list; p; p = p->next)
451 if (p->msgid == msgid)
452 return p;
453 return NULL;
454}
455
456static void free_ncci(capidrv_contr * card, struct capidrv_ncci *nccip)
457{
458 struct capidrv_ncci **pp;
459
460 for (pp = &(nccip->plcip->ncci_list); *pp; pp = &(*pp)->next) {
461 if (*pp == nccip) {
462 *pp = (*pp)->next;
463 break;
464 }
465 }
466 card->bchans[nccip->chan].nccip = NULL;
467 kfree(nccip);
468}
469
470static int capidrv_add_ack(struct capidrv_ncci *nccip,
471 u16 datahandle, int len)
472{
473 struct ncci_datahandle_queue *n, **pp;
474
475 n = (struct ncci_datahandle_queue *)
476 kmalloc(sizeof(struct ncci_datahandle_queue), GFP_ATOMIC);
477 if (!n) {
478 printk(KERN_ERR "capidrv: kmalloc ncci_datahandle failed\n");
479 return -1;
480 }
481 n->next = NULL;
482 n->datahandle = datahandle;
483 n->len = len;
484 for (pp = &nccip->ackqueue; *pp; pp = &(*pp)->next) ;
485 *pp = n;
486 return 0;
487}
488
489static int capidrv_del_ack(struct capidrv_ncci *nccip, u16 datahandle)
490{
491 struct ncci_datahandle_queue **pp, *p;
492 int len;
493
494 for (pp = &nccip->ackqueue; *pp; pp = &(*pp)->next) {
495 if ((*pp)->datahandle == datahandle) {
496 p = *pp;
497 len = p->len;
498 *pp = (*pp)->next;
499 kfree(p);
500 return len;
501 }
502 }
503 return -1;
504}
505
506/* -------- convert and send capi message ---------------------------- */
507
508static void send_message(capidrv_contr * card, _cmsg * cmsg)
509{
510 struct sk_buff *skb;
511 size_t len;
512 capi_cmsg2message(cmsg, cmsg->buf);
513 len = CAPIMSG_LEN(cmsg->buf);
514 skb = alloc_skb(len, GFP_ATOMIC);
515 memcpy(skb_put(skb, len), cmsg->buf, len);
516 if (capi20_put_message(&global.ap, skb) != CAPI_NOERROR)
517 kfree_skb(skb);
518}
519
520/* -------- state machine -------------------------------------------- */
521
522struct listenstatechange {
523 int actstate;
524 int nextstate;
525 int event;
526};
527
528static struct listenstatechange listentable[] =
529{
530 {ST_LISTEN_NONE, ST_LISTEN_WAIT_CONF, EV_LISTEN_REQ},
531 {ST_LISTEN_ACTIVE, ST_LISTEN_ACTIVE_WAIT_CONF, EV_LISTEN_REQ},
532 {ST_LISTEN_WAIT_CONF, ST_LISTEN_NONE, EV_LISTEN_CONF_ERROR},
533 {ST_LISTEN_ACTIVE_WAIT_CONF, ST_LISTEN_ACTIVE, EV_LISTEN_CONF_ERROR},
534 {ST_LISTEN_WAIT_CONF, ST_LISTEN_NONE, EV_LISTEN_CONF_EMPTY},
535 {ST_LISTEN_ACTIVE_WAIT_CONF, ST_LISTEN_NONE, EV_LISTEN_CONF_EMPTY},
536 {ST_LISTEN_WAIT_CONF, ST_LISTEN_ACTIVE, EV_LISTEN_CONF_OK},
537 {ST_LISTEN_ACTIVE_WAIT_CONF, ST_LISTEN_ACTIVE, EV_LISTEN_CONF_OK},
538 {},
539};
540
541static void listen_change_state(capidrv_contr * card, int event)
542{
543 struct listenstatechange *p = listentable;
544 while (p->event) {
545 if (card->state == p->actstate && p->event == event) {
546 if (debugmode)
547 printk(KERN_DEBUG "capidrv-%d: listen_change_state %d -> %d\n",
548 card->contrnr, card->state, p->nextstate);
549 card->state = p->nextstate;
550 return;
551 }
552 p++;
553 }
554 printk(KERN_ERR "capidrv-%d: listen_change_state state=%d event=%d ????\n",
555 card->contrnr, card->state, event);
556
557}
558
559/* ------------------------------------------------------------------ */
560
561static void p0(capidrv_contr * card, capidrv_plci * plci)
562{
563 isdn_ctrl cmd;
564
565 card->bchans[plci->chan].contr = NULL;
566 cmd.command = ISDN_STAT_DHUP;
567 cmd.driver = card->myid;
568 cmd.arg = plci->chan;
569 card->interface.statcallb(&cmd);
570 free_plci(card, plci);
571}
572
573/* ------------------------------------------------------------------ */
574
575struct plcistatechange {
576 int actstate;
577 int nextstate;
578 int event;
579 void (*changefunc) (capidrv_contr * card, capidrv_plci * plci);
580};
581
582static struct plcistatechange plcitable[] =
583{
584 /* P-0 */
585 {ST_PLCI_NONE, ST_PLCI_OUTGOING, EV_PLCI_CONNECT_REQ, NULL},
586 {ST_PLCI_NONE, ST_PLCI_ALLOCATED, EV_PLCI_FACILITY_IND_UP, NULL},
587 {ST_PLCI_NONE, ST_PLCI_INCOMING, EV_PLCI_CONNECT_IND, NULL},
588 {ST_PLCI_NONE, ST_PLCI_RESUMEING, EV_PLCI_RESUME_REQ, NULL},
589 /* P-0.1 */
590 {ST_PLCI_OUTGOING, ST_PLCI_NONE, EV_PLCI_CONNECT_CONF_ERROR, p0},
591 {ST_PLCI_OUTGOING, ST_PLCI_ALLOCATED, EV_PLCI_CONNECT_CONF_OK, NULL},
592 /* P-1 */
593 {ST_PLCI_ALLOCATED, ST_PLCI_ACTIVE, EV_PLCI_CONNECT_ACTIVE_IND, NULL},
594 {ST_PLCI_ALLOCATED, ST_PLCI_DISCONNECTING, EV_PLCI_DISCONNECT_REQ, NULL},
595 {ST_PLCI_ALLOCATED, ST_PLCI_DISCONNECTING, EV_PLCI_FACILITY_IND_DOWN, NULL},
596 {ST_PLCI_ALLOCATED, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, NULL},
597 /* P-ACT */
598 {ST_PLCI_ACTIVE, ST_PLCI_DISCONNECTING, EV_PLCI_DISCONNECT_REQ, NULL},
599 {ST_PLCI_ACTIVE, ST_PLCI_DISCONNECTING, EV_PLCI_FACILITY_IND_DOWN, NULL},
600 {ST_PLCI_ACTIVE, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, NULL},
601 {ST_PLCI_ACTIVE, ST_PLCI_HELD, EV_PLCI_HOLD_IND, NULL},
602 {ST_PLCI_ACTIVE, ST_PLCI_DISCONNECTING, EV_PLCI_SUSPEND_IND, NULL},
603 /* P-2 */
604 {ST_PLCI_INCOMING, ST_PLCI_DISCONNECTING, EV_PLCI_CONNECT_REJECT, NULL},
605 {ST_PLCI_INCOMING, ST_PLCI_FACILITY_IND, EV_PLCI_FACILITY_IND_UP, NULL},
606 {ST_PLCI_INCOMING, ST_PLCI_ACCEPTING, EV_PLCI_CONNECT_RESP, NULL},
607 {ST_PLCI_INCOMING, ST_PLCI_DISCONNECTING, EV_PLCI_DISCONNECT_REQ, NULL},
608 {ST_PLCI_INCOMING, ST_PLCI_DISCONNECTING, EV_PLCI_FACILITY_IND_DOWN, NULL},
609 {ST_PLCI_INCOMING, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, NULL},
610 {ST_PLCI_INCOMING, ST_PLCI_DISCONNECTING, EV_PLCI_CD_IND, NULL},
611 /* P-3 */
612 {ST_PLCI_FACILITY_IND, ST_PLCI_DISCONNECTING, EV_PLCI_CONNECT_REJECT, NULL},
613 {ST_PLCI_FACILITY_IND, ST_PLCI_ACCEPTING, EV_PLCI_CONNECT_ACTIVE_IND, NULL},
614 {ST_PLCI_FACILITY_IND, ST_PLCI_DISCONNECTING, EV_PLCI_DISCONNECT_REQ, NULL},
615 {ST_PLCI_FACILITY_IND, ST_PLCI_DISCONNECTING, EV_PLCI_FACILITY_IND_DOWN, NULL},
616 {ST_PLCI_FACILITY_IND, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, NULL},
617 /* P-4 */
618 {ST_PLCI_ACCEPTING, ST_PLCI_ACTIVE, EV_PLCI_CONNECT_ACTIVE_IND, NULL},
619 {ST_PLCI_ACCEPTING, ST_PLCI_DISCONNECTING, EV_PLCI_DISCONNECT_REQ, NULL},
620 {ST_PLCI_ACCEPTING, ST_PLCI_DISCONNECTING, EV_PLCI_FACILITY_IND_DOWN, NULL},
621 {ST_PLCI_ACCEPTING, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, NULL},
622 /* P-5 */
623 {ST_PLCI_DISCONNECTING, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, NULL},
624 /* P-6 */
625 {ST_PLCI_DISCONNECTED, ST_PLCI_NONE, EV_PLCI_DISCONNECT_RESP, p0},
626 /* P-0.Res */
627 {ST_PLCI_RESUMEING, ST_PLCI_NONE, EV_PLCI_RESUME_CONF_ERROR, p0},
628 {ST_PLCI_RESUMEING, ST_PLCI_RESUME, EV_PLCI_RESUME_CONF_OK, NULL},
629 /* P-RES */
630 {ST_PLCI_RESUME, ST_PLCI_ACTIVE, EV_PLCI_RESUME_IND, NULL},
631 /* P-HELD */
632 {ST_PLCI_HELD, ST_PLCI_ACTIVE, EV_PLCI_RETRIEVE_IND, NULL},
633 {},
634};
635
636static void plci_change_state(capidrv_contr * card, capidrv_plci * plci, int event)
637{
638 struct plcistatechange *p = plcitable;
639 while (p->event) {
640 if (plci->state == p->actstate && p->event == event) {
641 if (debugmode)
642 printk(KERN_DEBUG "capidrv-%d: plci_change_state:0x%x %d -> %d\n",
643 card->contrnr, plci->plci, plci->state, p->nextstate);
644 plci->state = p->nextstate;
645 if (p->changefunc)
646 p->changefunc(card, plci);
647 return;
648 }
649 p++;
650 }
651 printk(KERN_ERR "capidrv-%d: plci_change_state:0x%x state=%d event=%d ????\n",
652 card->contrnr, plci->plci, plci->state, event);
653}
654
655/* ------------------------------------------------------------------ */
656
657static _cmsg cmsg;
658
659static void n0(capidrv_contr * card, capidrv_ncci * ncci)
660{
661 isdn_ctrl cmd;
662
663 capi_fill_DISCONNECT_REQ(&cmsg,
664 global.ap.applid,
665 card->msgid++,
666 ncci->plcip->plci,
667 NULL, /* BChannelinformation */
668 NULL, /* Keypadfacility */
669 NULL, /* Useruserdata */ /* $$$$ */
670 NULL /* Facilitydataarray */
671 );
672 send_message(card, &cmsg);
673 plci_change_state(card, ncci->plcip, EV_PLCI_DISCONNECT_REQ);
674
675 cmd.command = ISDN_STAT_BHUP;
676 cmd.driver = card->myid;
677 cmd.arg = ncci->chan;
678 card->interface.statcallb(&cmd);
679 free_ncci(card, ncci);
680}
681
682/* ------------------------------------------------------------------ */
683
684struct nccistatechange {
685 int actstate;
686 int nextstate;
687 int event;
688 void (*changefunc) (capidrv_contr * card, capidrv_ncci * ncci);
689};
690
691static struct nccistatechange nccitable[] =
692{
693 /* N-0 */
694 {ST_NCCI_NONE, ST_NCCI_OUTGOING, EV_NCCI_CONNECT_B3_REQ, NULL},
695 {ST_NCCI_NONE, ST_NCCI_INCOMING, EV_NCCI_CONNECT_B3_IND, NULL},
696 /* N-0.1 */
697 {ST_NCCI_OUTGOING, ST_NCCI_ALLOCATED, EV_NCCI_CONNECT_B3_CONF_OK, NULL},
698 {ST_NCCI_OUTGOING, ST_NCCI_NONE, EV_NCCI_CONNECT_B3_CONF_ERROR, n0},
699 /* N-1 */
700 {ST_NCCI_INCOMING, ST_NCCI_DISCONNECTING, EV_NCCI_CONNECT_B3_REJECT, NULL},
701 {ST_NCCI_INCOMING, ST_NCCI_ALLOCATED, EV_NCCI_CONNECT_B3_RESP, NULL},
702 {ST_NCCI_INCOMING, ST_NCCI_DISCONNECTED, EV_NCCI_DISCONNECT_B3_IND, NULL},
703 {ST_NCCI_INCOMING, ST_NCCI_DISCONNECTING, EV_NCCI_DISCONNECT_B3_REQ, NULL},
704 /* N-2 */
705 {ST_NCCI_ALLOCATED, ST_NCCI_ACTIVE, EV_NCCI_CONNECT_B3_ACTIVE_IND, NULL},
706 {ST_NCCI_ALLOCATED, ST_NCCI_DISCONNECTED, EV_NCCI_DISCONNECT_B3_IND, NULL},
707 {ST_NCCI_ALLOCATED, ST_NCCI_DISCONNECTING, EV_NCCI_DISCONNECT_B3_REQ, NULL},
708 /* N-ACT */
709 {ST_NCCI_ACTIVE, ST_NCCI_ACTIVE, EV_NCCI_RESET_B3_IND, NULL},
710 {ST_NCCI_ACTIVE, ST_NCCI_RESETING, EV_NCCI_RESET_B3_REQ, NULL},
711 {ST_NCCI_ACTIVE, ST_NCCI_DISCONNECTED, EV_NCCI_DISCONNECT_B3_IND, NULL},
712 {ST_NCCI_ACTIVE, ST_NCCI_DISCONNECTING, EV_NCCI_DISCONNECT_B3_REQ, NULL},
713 /* N-3 */
714 {ST_NCCI_RESETING, ST_NCCI_ACTIVE, EV_NCCI_RESET_B3_IND, NULL},
715 {ST_NCCI_RESETING, ST_NCCI_DISCONNECTED, EV_NCCI_DISCONNECT_B3_IND, NULL},
716 {ST_NCCI_RESETING, ST_NCCI_DISCONNECTING, EV_NCCI_DISCONNECT_B3_REQ, NULL},
717 /* N-4 */
718 {ST_NCCI_DISCONNECTING, ST_NCCI_DISCONNECTED, EV_NCCI_DISCONNECT_B3_IND, NULL},
719 {ST_NCCI_DISCONNECTING, ST_NCCI_PREVIOUS, EV_NCCI_DISCONNECT_B3_CONF_ERROR,NULL},
720 /* N-5 */
721 {ST_NCCI_DISCONNECTED, ST_NCCI_NONE, EV_NCCI_DISCONNECT_B3_RESP, n0},
722 {},
723};
724
725static void ncci_change_state(capidrv_contr * card, capidrv_ncci * ncci, int event)
726{
727 struct nccistatechange *p = nccitable;
728 while (p->event) {
729 if (ncci->state == p->actstate && p->event == event) {
730 if (debugmode)
731 printk(KERN_DEBUG "capidrv-%d: ncci_change_state:0x%x %d -> %d\n",
732 card->contrnr, ncci->ncci, ncci->state, p->nextstate);
733 if (p->nextstate == ST_NCCI_PREVIOUS) {
734 ncci->state = ncci->oldstate;
735 ncci->oldstate = p->actstate;
736 } else {
737 ncci->oldstate = p->actstate;
738 ncci->state = p->nextstate;
739 }
740 if (p->changefunc)
741 p->changefunc(card, ncci);
742 return;
743 }
744 p++;
745 }
746 printk(KERN_ERR "capidrv-%d: ncci_change_state:0x%x state=%d event=%d ????\n",
747 card->contrnr, ncci->ncci, ncci->state, event);
748}
749
750/* ------------------------------------------------------------------- */
751
752static inline int new_bchan(capidrv_contr * card)
753{
754 int i;
755 for (i = 0; i < card->nbchan; i++) {
756 if (card->bchans[i].plcip == 0) {
757 card->bchans[i].disconnecting = 0;
758 return i;
759 }
760 }
761 return -1;
762}
763
764/* ------------------------------------------------------------------- */
765
766static void handle_controller(_cmsg * cmsg)
767{
768 capidrv_contr *card = findcontrbynumber(cmsg->adr.adrController & 0x7f);
769
770 if (!card) {
771 printk(KERN_ERR "capidrv: %s from unknown controller 0x%x\n",
772 capi_cmd2str(cmsg->Command, cmsg->Subcommand),
773 cmsg->adr.adrController & 0x7f);
774 return;
775 }
776 switch (CAPICMD(cmsg->Command, cmsg->Subcommand)) {
777
778 case CAPI_LISTEN_CONF: /* Controller */
779 if (debugmode)
780 printk(KERN_DEBUG "capidrv-%d: listenconf Info=0x%4x (%s) cipmask=0x%x\n",
781 card->contrnr, cmsg->Info, capi_info2str(cmsg->Info), card->cipmask);
782 if (cmsg->Info) {
783 listen_change_state(card, EV_LISTEN_CONF_ERROR);
784 } else if (card->cipmask == 0) {
785 listen_change_state(card, EV_LISTEN_CONF_EMPTY);
786 } else {
787 listen_change_state(card, EV_LISTEN_CONF_OK);
788 }
789 break;
790
791 case CAPI_MANUFACTURER_IND: /* Controller */
792 if ( cmsg->ManuID == 0x214D5641
793 && cmsg->Class == 0
794 && cmsg->Function == 1) {
795 u8 *data = cmsg->ManuData+3;
796 u16 len = cmsg->ManuData[0];
797 u16 layer;
798 int direction;
799 if (len == 255) {
800 len = (cmsg->ManuData[1] | (cmsg->ManuData[2] << 8));
801 data += 2;
802 }
803 len -= 2;
804 layer = ((*(data-1)) << 8) | *(data-2);
805 if (layer & 0x300)
806 direction = (layer & 0x200) ? 0 : 1;
807 else direction = (layer & 0x800) ? 0 : 1;
808 if (layer & 0x0C00) {
809 if ((layer & 0xff) == 0x80) {
810 handle_dtrace_data(card, direction, 1, data, len);
811 break;
812 }
813 } else if ((layer & 0xff) < 0x80) {
814 handle_dtrace_data(card, direction, 0, data, len);
815 break;
816 }
817 printk(KERN_INFO "capidrv-%d: %s from controller 0x%x layer 0x%x, ignored\n",
818 card->contrnr,
819 capi_cmd2str(cmsg->Command, cmsg->Subcommand),
820 cmsg->adr.adrController, layer);
821 break;
822 }
823 goto ignored;
824 case CAPI_MANUFACTURER_CONF: /* Controller */
825 if (cmsg->ManuID == 0x214D5641) {
826 char *s = NULL;
827 switch (cmsg->Class) {
828 case 0: break;
829 case 1: s = "unknown class"; break;
830 case 2: s = "unknown function"; break;
831 default: s = "unkown error"; break;
832 }
833 if (s)
834 printk(KERN_INFO "capidrv-%d: %s from controller 0x%x function %d: %s\n",
835 card->contrnr,
836 capi_cmd2str(cmsg->Command, cmsg->Subcommand),
837 cmsg->adr.adrController,
838 cmsg->Function, s);
839 break;
840 }
841 goto ignored;
842 case CAPI_FACILITY_IND: /* Controller/plci/ncci */
843 goto ignored;
844 case CAPI_FACILITY_CONF: /* Controller/plci/ncci */
845 goto ignored;
846 case CAPI_INFO_IND: /* Controller/plci */
847 goto ignored;
848 case CAPI_INFO_CONF: /* Controller/plci */
849 goto ignored;
850
851 default:
852 printk(KERN_ERR "capidrv-%d: got %s from controller 0x%x ???",
853 card->contrnr,
854 capi_cmd2str(cmsg->Command, cmsg->Subcommand),
855 cmsg->adr.adrController);
856 }
857 return;
858
859 ignored:
860 printk(KERN_INFO "capidrv-%d: %s from controller 0x%x ignored\n",
861 card->contrnr,
862 capi_cmd2str(cmsg->Command, cmsg->Subcommand),
863 cmsg->adr.adrController);
864}
865
866static void handle_incoming_call(capidrv_contr * card, _cmsg * cmsg)
867{
868 capidrv_plci *plcip;
869 capidrv_bchan *bchan;
870 isdn_ctrl cmd;
871 int chan;
872
873 if ((chan = new_bchan(card)) == -1) {
874 printk(KERN_ERR "capidrv-%d: incoming call on not existing bchan ?\n", card->contrnr);
875 return;
876 }
877 bchan = &card->bchans[chan];
878 if ((plcip = new_plci(card, chan)) == 0) {
879 printk(KERN_ERR "capidrv-%d: incoming call: no memory, sorry.\n", card->contrnr);
880 return;
881 }
882 bchan->incoming = 1;
883 plcip->plci = cmsg->adr.adrPLCI;
884 plci_change_state(card, plcip, EV_PLCI_CONNECT_IND);
885
886 cmd.command = ISDN_STAT_ICALL;
887 cmd.driver = card->myid;
888 cmd.arg = chan;
889 memset(&cmd.parm.setup, 0, sizeof(cmd.parm.setup));
890 strncpy(cmd.parm.setup.phone,
891 cmsg->CallingPartyNumber + 3,
892 cmsg->CallingPartyNumber[0] - 2);
893 strncpy(cmd.parm.setup.eazmsn,
894 cmsg->CalledPartyNumber + 2,
895 cmsg->CalledPartyNumber[0] - 1);
896 cmd.parm.setup.si1 = cip2si1(cmsg->CIPValue);
897 cmd.parm.setup.si2 = cip2si2(cmsg->CIPValue);
898 cmd.parm.setup.plan = cmsg->CallingPartyNumber[1];
899 cmd.parm.setup.screen = cmsg->CallingPartyNumber[2];
900
901 printk(KERN_INFO "capidrv-%d: incoming call %s,%d,%d,%s\n",
902 card->contrnr,
903 cmd.parm.setup.phone,
904 cmd.parm.setup.si1,
905 cmd.parm.setup.si2,
906 cmd.parm.setup.eazmsn);
907
908 if (cmd.parm.setup.si1 == 1 && cmd.parm.setup.si2 != 0) {
909 printk(KERN_INFO "capidrv-%d: patching si2=%d to 0 for VBOX\n",
910 card->contrnr,
911 cmd.parm.setup.si2);
912 cmd.parm.setup.si2 = 0;
913 }
914
915 switch (card->interface.statcallb(&cmd)) {
916 case 0:
917 case 3:
918 /* No device matching this call.
919 * and isdn_common.c has send a HANGUP command
920 * which is ignored in state ST_PLCI_INCOMING,
921 * so we send RESP to ignore the call
922 */
923 capi_cmsg_answer(cmsg);
924 cmsg->Reject = 1; /* ignore */
925 send_message(card, cmsg);
926 plci_change_state(card, plcip, EV_PLCI_CONNECT_REJECT);
927 printk(KERN_INFO "capidrv-%d: incoming call %s,%d,%d,%s ignored\n",
928 card->contrnr,
929 cmd.parm.setup.phone,
930 cmd.parm.setup.si1,
931 cmd.parm.setup.si2,
932 cmd.parm.setup.eazmsn);
933 break;
934 case 1:
935 /* At least one device matching this call (RING on ttyI)
936 * HL-driver may send ALERTING on the D-channel in this
937 * case.
938 * really means: RING on ttyI or a net interface
939 * accepted this call already.
940 *
941 * If the call was accepted, state has already changed,
942 * and CONNECT_RESP already sent.
943 */
944 if (plcip->state == ST_PLCI_INCOMING) {
945 printk(KERN_INFO "capidrv-%d: incoming call %s,%d,%d,%s tty alerting\n",
946 card->contrnr,
947 cmd.parm.setup.phone,
948 cmd.parm.setup.si1,
949 cmd.parm.setup.si2,
950 cmd.parm.setup.eazmsn);
951 capi_fill_ALERT_REQ(cmsg,
952 global.ap.applid,
953 card->msgid++,
954 plcip->plci, /* adr */
955 NULL,/* BChannelinformation */
956 NULL,/* Keypadfacility */
957 NULL,/* Useruserdata */
958 NULL /* Facilitydataarray */
959 );
960 plcip->msgid = cmsg->Messagenumber;
961 send_message(card, cmsg);
962 } else {
963 printk(KERN_INFO "capidrv-%d: incoming call %s,%d,%d,%s on netdev\n",
964 card->contrnr,
965 cmd.parm.setup.phone,
966 cmd.parm.setup.si1,
967 cmd.parm.setup.si2,
968 cmd.parm.setup.eazmsn);
969 }
970 break;
971
972 case 2: /* Call will be rejected. */
973 capi_cmsg_answer(cmsg);
974 cmsg->Reject = 2; /* reject call, normal call clearing */
975 send_message(card, cmsg);
976 plci_change_state(card, plcip, EV_PLCI_CONNECT_REJECT);
977 break;
978
979 default:
980 /* An error happened. (Invalid parameters for example.) */
981 capi_cmsg_answer(cmsg);
982 cmsg->Reject = 8; /* reject call,
983 destination out of order */
984 send_message(card, cmsg);
985 plci_change_state(card, plcip, EV_PLCI_CONNECT_REJECT);
986 break;
987 }
988 return;
989}
990
991static void handle_plci(_cmsg * cmsg)
992{
993 capidrv_contr *card = findcontrbynumber(cmsg->adr.adrController & 0x7f);
994 capidrv_plci *plcip;
995 isdn_ctrl cmd;
996
997 if (!card) {
998 printk(KERN_ERR "capidrv: %s from unknown controller 0x%x\n",
999 capi_cmd2str(cmsg->Command, cmsg->Subcommand),
1000 cmsg->adr.adrController & 0x7f);
1001 return;
1002 }
1003 switch (CAPICMD(cmsg->Command, cmsg->Subcommand)) {
1004
1005 case CAPI_DISCONNECT_IND: /* plci */
1006 if (cmsg->Reason) {
1007 printk(KERN_INFO "capidrv-%d: %s reason 0x%x (%s) for plci 0x%x\n",
1008 card->contrnr,
1009 capi_cmd2str(cmsg->Command, cmsg->Subcommand),
1010 cmsg->Reason, capi_info2str(cmsg->Reason), cmsg->adr.adrPLCI);
1011 }
1012 if (!(plcip = find_plci_by_plci(card, cmsg->adr.adrPLCI))) {
1013 capi_cmsg_answer(cmsg);
1014 send_message(card, cmsg);
1015 goto notfound;
1016 }
1017 card->bchans[plcip->chan].disconnecting = 1;
1018 plci_change_state(card, plcip, EV_PLCI_DISCONNECT_IND);
1019 capi_cmsg_answer(cmsg);
1020 send_message(card, cmsg);
1021 plci_change_state(card, plcip, EV_PLCI_DISCONNECT_RESP);
1022 break;
1023
1024 case CAPI_DISCONNECT_CONF: /* plci */
1025 if (cmsg->Info) {
1026 printk(KERN_INFO "capidrv-%d: %s info 0x%x (%s) for plci 0x%x\n",
1027 card->contrnr,
1028 capi_cmd2str(cmsg->Command, cmsg->Subcommand),
1029 cmsg->Info, capi_info2str(cmsg->Info),
1030 cmsg->adr.adrPLCI);
1031 }
1032 if (!(plcip = find_plci_by_plci(card, cmsg->adr.adrPLCI)))
1033 goto notfound;
1034
1035 card->bchans[plcip->chan].disconnecting = 1;
1036 break;
1037
1038 case CAPI_ALERT_CONF: /* plci */
1039 if (cmsg->Info) {
1040 printk(KERN_INFO "capidrv-%d: %s info 0x%x (%s) for plci 0x%x\n",
1041 card->contrnr,
1042 capi_cmd2str(cmsg->Command, cmsg->Subcommand),
1043 cmsg->Info, capi_info2str(cmsg->Info),
1044 cmsg->adr.adrPLCI);
1045 }
1046 break;
1047
1048 case CAPI_CONNECT_IND: /* plci */
1049 handle_incoming_call(card, cmsg);
1050 break;
1051
1052 case CAPI_CONNECT_CONF: /* plci */
1053 if (cmsg->Info) {
1054 printk(KERN_INFO "capidrv-%d: %s info 0x%x (%s) for plci 0x%x\n",
1055 card->contrnr,
1056 capi_cmd2str(cmsg->Command, cmsg->Subcommand),
1057 cmsg->Info, capi_info2str(cmsg->Info),
1058 cmsg->adr.adrPLCI);
1059 }
1060 if (!(plcip = find_plci_by_msgid(card, cmsg->Messagenumber)))
1061 goto notfound;
1062
1063 plcip->plci = cmsg->adr.adrPLCI;
1064 if (cmsg->Info) {
1065 plci_change_state(card, plcip, EV_PLCI_CONNECT_CONF_ERROR);
1066 } else {
1067 plci_change_state(card, plcip, EV_PLCI_CONNECT_CONF_OK);
1068 }
1069 break;
1070
1071 case CAPI_CONNECT_ACTIVE_IND: /* plci */
1072
1073 if (!(plcip = find_plci_by_plci(card, cmsg->adr.adrPLCI)))
1074 goto notfound;
1075
1076 if (card->bchans[plcip->chan].incoming) {
1077 capi_cmsg_answer(cmsg);
1078 send_message(card, cmsg);
1079 plci_change_state(card, plcip, EV_PLCI_CONNECT_ACTIVE_IND);
1080 } else {
1081 capidrv_ncci *nccip;
1082 capi_cmsg_answer(cmsg);
1083 send_message(card, cmsg);
1084
1085 nccip = new_ncci(card, plcip, cmsg->adr.adrPLCI);
1086
1087 if (!nccip) {
1088 printk(KERN_ERR "capidrv-%d: no mem for ncci, sorry\n", card->contrnr);
1089 break; /* $$$$ */
1090 }
1091 capi_fill_CONNECT_B3_REQ(cmsg,
1092 global.ap.applid,
1093 card->msgid++,
1094 plcip->plci, /* adr */
1095 NULL /* NCPI */
1096 );
1097 nccip->msgid = cmsg->Messagenumber;
1098 send_message(card, cmsg);
1099 cmd.command = ISDN_STAT_DCONN;
1100 cmd.driver = card->myid;
1101 cmd.arg = plcip->chan;
1102 card->interface.statcallb(&cmd);
1103 plci_change_state(card, plcip, EV_PLCI_CONNECT_ACTIVE_IND);
1104 ncci_change_state(card, nccip, EV_NCCI_CONNECT_B3_REQ);
1105 }
1106 break;
1107
1108 case CAPI_INFO_IND: /* Controller/plci */
1109
1110 if (!(plcip = find_plci_by_plci(card, cmsg->adr.adrPLCI)))
1111 goto notfound;
1112
1113 if (cmsg->InfoNumber == 0x4000) {
1114 if (cmsg->InfoElement[0] == 4) {
1115 cmd.command = ISDN_STAT_CINF;
1116 cmd.driver = card->myid;
1117 cmd.arg = plcip->chan;
1118 sprintf(cmd.parm.num, "%lu",
1119 (unsigned long)
1120 ((u32) cmsg->InfoElement[1]
1121 | ((u32) (cmsg->InfoElement[2]) << 8)
1122 | ((u32) (cmsg->InfoElement[3]) << 16)
1123 | ((u32) (cmsg->InfoElement[4]) << 24)));
1124 card->interface.statcallb(&cmd);
1125 break;
1126 }
1127 }
1128 printk(KERN_ERR "capidrv-%d: %s\n",
1129 card->contrnr, capi_cmsg2str(cmsg));
1130 break;
1131
1132 case CAPI_CONNECT_ACTIVE_CONF: /* plci */
1133 goto ignored;
1134 case CAPI_SELECT_B_PROTOCOL_CONF: /* plci */
1135 goto ignored;
1136 case CAPI_FACILITY_IND: /* Controller/plci/ncci */
1137 goto ignored;
1138 case CAPI_FACILITY_CONF: /* Controller/plci/ncci */
1139 goto ignored;
1140
1141 case CAPI_INFO_CONF: /* Controller/plci */
1142 goto ignored;
1143
1144 default:
1145 printk(KERN_ERR "capidrv-%d: got %s for plci 0x%x ???",
1146 card->contrnr,
1147 capi_cmd2str(cmsg->Command, cmsg->Subcommand),
1148 cmsg->adr.adrPLCI);
1149 }
1150 return;
1151 ignored:
1152 printk(KERN_INFO "capidrv-%d: %s for plci 0x%x ignored\n",
1153 card->contrnr,
1154 capi_cmd2str(cmsg->Command, cmsg->Subcommand),
1155 cmsg->adr.adrPLCI);
1156 return;
1157 notfound:
1158 printk(KERN_ERR "capidrv-%d: %s: plci 0x%x not found\n",
1159 card->contrnr,
1160 capi_cmd2str(cmsg->Command, cmsg->Subcommand),
1161 cmsg->adr.adrPLCI);
1162 return;
1163}
1164
1165static void handle_ncci(_cmsg * cmsg)
1166{
1167 capidrv_contr *card = findcontrbynumber(cmsg->adr.adrController & 0x7f);
1168 capidrv_plci *plcip;
1169 capidrv_ncci *nccip;
1170 isdn_ctrl cmd;
1171 int len;
1172
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;
1178 }
1179 switch (CAPICMD(cmsg->Command, cmsg->Subcommand)) {
1180
1181 case CAPI_CONNECT_B3_ACTIVE_IND: /* ncci */
1182 if (!(nccip = find_ncci(card, cmsg->adr.adrNCCI)))
1183 goto notfound;
1184
1185 capi_cmsg_answer(cmsg);
1186 send_message(card, cmsg);
1187 ncci_change_state(card, nccip, EV_NCCI_CONNECT_B3_ACTIVE_IND);
1188
1189 cmd.command = ISDN_STAT_BCONN;
1190 cmd.driver = card->myid;
1191 cmd.arg = nccip->chan;
1192 card->interface.statcallb(&cmd);
1193
1194 printk(KERN_INFO "capidrv-%d: chan %d up with ncci 0x%x\n",
1195 card->contrnr, nccip->chan, nccip->ncci);
1196 break;
1197
1198 case CAPI_CONNECT_B3_ACTIVE_CONF: /* ncci */
1199 goto ignored;
1200
1201 case CAPI_CONNECT_B3_IND: /* ncci */
1202
1203 plcip = find_plci_by_ncci(card, cmsg->adr.adrNCCI);
1204 if (plcip) {
1205 nccip = new_ncci(card, plcip, cmsg->adr.adrNCCI);
1206 if (nccip) {
1207 ncci_change_state(card, nccip, EV_NCCI_CONNECT_B3_IND);
1208 capi_fill_CONNECT_B3_RESP(cmsg,
1209 global.ap.applid,
1210 card->msgid++,
1211 nccip->ncci, /* adr */
1212 0, /* Reject */
1213 NULL /* NCPI */
1214 );
1215 send_message(card, cmsg);
1216 ncci_change_state(card, nccip, EV_NCCI_CONNECT_B3_RESP);
1217 break;
1218 }
1219 printk(KERN_ERR "capidrv-%d: no mem for ncci, sorry\n", card->contrnr);
1220 } else {
1221 printk(KERN_ERR "capidrv-%d: %s: plci for ncci 0x%x not found\n",
1222 card->contrnr,
1223 capi_cmd2str(cmsg->Command, cmsg->Subcommand),
1224 cmsg->adr.adrNCCI);
1225 }
1226 capi_fill_CONNECT_B3_RESP(cmsg,
1227 global.ap.applid,
1228 card->msgid++,
1229 cmsg->adr.adrNCCI,
1230 2, /* Reject */
1231 NULL /* NCPI */
1232 );
1233 send_message(card, cmsg);
1234 break;
1235
1236 case CAPI_CONNECT_B3_CONF: /* ncci */
1237
1238 if (!(nccip = find_ncci_by_msgid(card,
1239 cmsg->adr.adrNCCI,
1240 cmsg->Messagenumber)))
1241 goto notfound;
1242
1243 nccip->ncci = cmsg->adr.adrNCCI;
1244 if (cmsg->Info) {
1245 printk(KERN_INFO "capidrv-%d: %s info 0x%x (%s) for ncci 0x%x\n",
1246 card->contrnr,
1247 capi_cmd2str(cmsg->Command, cmsg->Subcommand),
1248 cmsg->Info, capi_info2str(cmsg->Info),
1249 cmsg->adr.adrNCCI);
1250 }
1251
1252 if (cmsg->Info)
1253 ncci_change_state(card, nccip, EV_NCCI_CONNECT_B3_CONF_ERROR);
1254 else
1255 ncci_change_state(card, nccip, EV_NCCI_CONNECT_B3_CONF_OK);
1256 break;
1257
1258 case CAPI_CONNECT_B3_T90_ACTIVE_IND: /* ncci */
1259 capi_cmsg_answer(cmsg);
1260 send_message(card, cmsg);
1261 break;
1262
1263 case CAPI_DATA_B3_IND: /* ncci */
1264 /* handled in handle_data() */
1265 goto ignored;
1266
1267 case CAPI_DATA_B3_CONF: /* ncci */
1268 if (cmsg->Info) {
1269 printk(KERN_WARNING "CAPI_DATA_B3_CONF: Info %x - %s\n",
1270 cmsg->Info, capi_info2str(cmsg->Info));
1271 }
1272 if (!(nccip = find_ncci(card, cmsg->adr.adrNCCI)))
1273 goto notfound;
1274
1275 len = capidrv_del_ack(nccip, cmsg->DataHandle);
1276 if (len < 0)
1277 break;
1278 cmd.command = ISDN_STAT_BSENT;
1279 cmd.driver = card->myid;
1280 cmd.arg = nccip->chan;
1281 cmd.parm.length = len;
1282 card->interface.statcallb(&cmd);
1283 break;
1284
1285 case CAPI_DISCONNECT_B3_IND: /* ncci */
1286 if (!(nccip = find_ncci(card, cmsg->adr.adrNCCI)))
1287 goto notfound;
1288
1289 card->bchans[nccip->chan].disconnecting = 1;
1290 ncci_change_state(card, nccip, EV_NCCI_DISCONNECT_B3_IND);
1291 capi_cmsg_answer(cmsg);
1292 send_message(card, cmsg);
1293 ncci_change_state(card, nccip, EV_NCCI_DISCONNECT_B3_RESP);
1294 break;
1295
1296 case CAPI_DISCONNECT_B3_CONF: /* ncci */
1297 if (!(nccip = find_ncci(card, cmsg->adr.adrNCCI)))
1298 goto notfound;
1299 if (cmsg->Info) {
1300 printk(KERN_INFO "capidrv-%d: %s info 0x%x (%s) for ncci 0x%x\n",
1301 card->contrnr,
1302 capi_cmd2str(cmsg->Command, cmsg->Subcommand),
1303 cmsg->Info, capi_info2str(cmsg->Info),
1304 cmsg->adr.adrNCCI);
1305 ncci_change_state(card, nccip, EV_NCCI_DISCONNECT_B3_CONF_ERROR);
1306 }
1307 break;
1308
1309 case CAPI_RESET_B3_IND: /* ncci */
1310 if (!(nccip = find_ncci(card, cmsg->adr.adrNCCI)))
1311 goto notfound;
1312 ncci_change_state(card, nccip, EV_NCCI_RESET_B3_IND);
1313 capi_cmsg_answer(cmsg);
1314 send_message(card, cmsg);
1315 break;
1316
1317 case CAPI_RESET_B3_CONF: /* ncci */
1318 goto ignored; /* $$$$ */
1319
1320 case CAPI_FACILITY_IND: /* Controller/plci/ncci */
1321 goto ignored;
1322 case CAPI_FACILITY_CONF: /* Controller/plci/ncci */
1323 goto ignored;
1324
1325 default:
1326 printk(KERN_ERR "capidrv-%d: got %s for ncci 0x%x ???",
1327 card->contrnr,
1328 capi_cmd2str(cmsg->Command, cmsg->Subcommand),
1329 cmsg->adr.adrNCCI);
1330 }
1331 return;
1332 ignored:
1333 printk(KERN_INFO "capidrv-%d: %s for ncci 0x%x ignored\n",
1334 card->contrnr,
1335 capi_cmd2str(cmsg->Command, cmsg->Subcommand),
1336 cmsg->adr.adrNCCI);
1337 return;
1338 notfound:
1339 printk(KERN_ERR "capidrv-%d: %s: ncci 0x%x not found\n",
1340 card->contrnr,
1341 capi_cmd2str(cmsg->Command, cmsg->Subcommand),
1342 cmsg->adr.adrNCCI);
1343}
1344
1345
1346static void handle_data(_cmsg * cmsg, struct sk_buff *skb)
1347{
1348 capidrv_contr *card = findcontrbynumber(cmsg->adr.adrController & 0x7f);
1349 capidrv_ncci *nccip;
1350
1351 if (!card) {
1352 printk(KERN_ERR "capidrv: %s from unknown controller 0x%x\n",
1353 capi_cmd2str(cmsg->Command, cmsg->Subcommand),
1354 cmsg->adr.adrController & 0x7f);
1355 kfree_skb(skb);
1356 return;
1357 }
1358 if (!(nccip = find_ncci(card, cmsg->adr.adrNCCI))) {
1359 printk(KERN_ERR "capidrv-%d: %s: ncci 0x%x not found\n",
1360 card->contrnr,
1361 capi_cmd2str(cmsg->Command, cmsg->Subcommand),
1362 cmsg->adr.adrNCCI);
1363 kfree_skb(skb);
1364 return;
1365 }
1366 (void) skb_pull(skb, CAPIMSG_LEN(skb->data));
1367 card->interface.rcvcallb_skb(card->myid, nccip->chan, skb);
1368 capi_cmsg_answer(cmsg);
1369 send_message(card, cmsg);
1370}
1371
1372static _cmsg s_cmsg;
1373
1374static void capidrv_recv_message(struct capi20_appl *ap, struct sk_buff *skb)
1375{
1376 capi_message2cmsg(&s_cmsg, skb->data);
1377 if (debugmode > 3)
1378 printk(KERN_DEBUG "capidrv_signal: applid=%d %s\n",
1379 ap->applid, capi_cmsg2str(&s_cmsg));
1380
1381 if (s_cmsg.Command == CAPI_DATA_B3
1382 && s_cmsg.Subcommand == CAPI_IND) {
1383 handle_data(&s_cmsg, skb);
1384 return;
1385 }
1386 if ((s_cmsg.adr.adrController & 0xffffff00) == 0)
1387 handle_controller(&s_cmsg);
1388 else if ((s_cmsg.adr.adrPLCI & 0xffff0000) == 0)
1389 handle_plci(&s_cmsg);
1390 else
1391 handle_ncci(&s_cmsg);
1392 /*
1393 * data of skb used in s_cmsg,
1394 * free data when s_cmsg is not used again
1395 * thanks to Lars Heete <hel@admin.de>
1396 */
1397 kfree_skb(skb);
1398}
1399
1400/* ------------------------------------------------------------------- */
1401
1402#define PUTBYTE_TO_STATUS(card, byte) \
1403 do { \
1404 *(card)->q931_write++ = (byte); \
1405 if ((card)->q931_write > (card)->q931_end) \
1406 (card)->q931_write = (card)->q931_buf; \
1407 } while (0)
1408
1409static void handle_dtrace_data(capidrv_contr *card,
1410 int send, int level2, u8 *data, u16 len)
1411{
1412 u8 *p, *end;
1413 isdn_ctrl cmd;
1414
1415 if (!len) {
1416 printk(KERN_DEBUG "capidrv-%d: avmb1_q931_data: len == %d\n",
1417 card->contrnr, len);
1418 return;
1419 }
1420
1421 if (level2) {
1422 PUTBYTE_TO_STATUS(card, 'D');
1423 PUTBYTE_TO_STATUS(card, '2');
1424 PUTBYTE_TO_STATUS(card, send ? '>' : '<');
1425 PUTBYTE_TO_STATUS(card, ':');
1426 } else {
1427 PUTBYTE_TO_STATUS(card, 'D');
1428 PUTBYTE_TO_STATUS(card, '3');
1429 PUTBYTE_TO_STATUS(card, send ? '>' : '<');
1430 PUTBYTE_TO_STATUS(card, ':');
1431 }
1432
1433 for (p = data, end = data+len; p < end; p++) {
1434 u8 w;
1435 PUTBYTE_TO_STATUS(card, ' ');
1436 w = (*p >> 4) & 0xf;
1437 PUTBYTE_TO_STATUS(card, (w < 10) ? '0'+w : 'A'-10+w);
1438 w = *p & 0xf;
1439 PUTBYTE_TO_STATUS(card, (w < 10) ? '0'+w : 'A'-10+w);
1440 }
1441 PUTBYTE_TO_STATUS(card, '\n');
1442
1443 cmd.command = ISDN_STAT_STAVAIL;
1444 cmd.driver = card->myid;
1445 cmd.arg = len*3+5;
1446 card->interface.statcallb(&cmd);
1447}
1448
1449/* ------------------------------------------------------------------- */
1450
1451static _cmsg cmdcmsg;
1452
1453static int capidrv_ioctl(isdn_ctrl * c, capidrv_contr * card)
1454{
1455 switch (c->arg) {
1456 case 1:
1457 debugmode = (int)(*((unsigned int *)c->parm.num));
1458 printk(KERN_DEBUG "capidrv-%d: debugmode=%d\n",
1459 card->contrnr, debugmode);
1460 return 0;
1461 default:
1462 printk(KERN_DEBUG "capidrv-%d: capidrv_ioctl(%ld) called ??\n",
1463 card->contrnr, c->arg);
1464 return -EINVAL;
1465 }
1466 return -EINVAL;
1467}
1468
1469/*
1470 * Handle leased lines (CAPI-Bundling)
1471 */
1472
1473struct internal_bchannelinfo {
1474 unsigned short channelalloc;
1475 unsigned short operation;
1476 unsigned char cmask[31];
1477};
1478
1479static int decodeFVteln(char *teln, unsigned long *bmaskp, int *activep)
1480{
1481 unsigned long bmask = 0;
1482 int active = !0;
1483 char *s;
1484 int i;
1485
1486 if (strncmp(teln, "FV:", 3) != 0)
1487 return 1;
1488 s = teln + 3;
1489 while (*s && *s == ' ') s++;
1490 if (!*s) return -2;
1491 if (*s == 'p' || *s == 'P') {
1492 active = 0;
1493 s++;
1494 }
1495 if (*s == 'a' || *s == 'A') {
1496 active = !0;
1497 s++;
1498 }
1499 while (*s) {
1500 int digit1 = 0;
1501 int digit2 = 0;
1502 if (!isdigit(*s)) return -3;
1503 while (isdigit(*s)) { digit1 = digit1*10 + (*s - '0'); s++; }
1504 if (digit1 <= 0 && digit1 > 30) return -4;
1505 if (*s == 0 || *s == ',' || *s == ' ') {
1506 bmask |= (1 << digit1);
1507 digit1 = 0;
1508 if (*s) s++;
1509 continue;
1510 }
1511 if (*s != '-') return -5;
1512 s++;
1513 if (!isdigit(*s)) return -3;
1514 while (isdigit(*s)) { digit2 = digit2*10 + (*s - '0'); s++; }
1515 if (digit2 <= 0 && digit2 > 30) return -4;
1516 if (*s == 0 || *s == ',' || *s == ' ') {
1517 if (digit1 > digit2)
1518 for (i = digit2; i <= digit1 ; i++)
1519 bmask |= (1 << i);
1520 else
1521 for (i = digit1; i <= digit2 ; i++)
1522 bmask |= (1 << i);
1523 digit1 = digit2 = 0;
1524 if (*s) s++;
1525 continue;
1526 }
1527 return -6;
1528 }
1529 if (activep) *activep = active;
1530 if (bmaskp) *bmaskp = bmask;
1531 return 0;
1532}
1533
1534static int FVteln2capi20(char *teln, u8 AdditionalInfo[1+2+2+31])
1535{
1536 unsigned long bmask;
1537 int active;
1538 int rc, i;
1539
1540 rc = decodeFVteln(teln, &bmask, &active);
1541 if (rc) return rc;
1542 /* Length */
1543 AdditionalInfo[0] = 2+2+31;
1544 /* Channel: 3 => use channel allocation */
1545 AdditionalInfo[1] = 3; AdditionalInfo[2] = 0;
1546 /* Operation: 0 => DTE mode, 1 => DCE mode */
1547 if (active) {
1548 AdditionalInfo[3] = 0; AdditionalInfo[4] = 0;
1549 } else {
1550 AdditionalInfo[3] = 1; AdditionalInfo[4] = 0;
1551 }
1552 /* Channel mask array */
1553 AdditionalInfo[5] = 0; /* no D-Channel */
1554 for (i=1; i <= 30; i++)
1555 AdditionalInfo[5+i] = (bmask & (1 << i)) ? 0xff : 0;
1556 return 0;
1557}
1558
1559static int capidrv_command(isdn_ctrl * c, capidrv_contr * card)
1560{
1561 isdn_ctrl cmd;
1562 struct capidrv_bchan *bchan;
1563 struct capidrv_plci *plcip;
1564 u8 AdditionalInfo[1+2+2+31];
1565 int rc, isleasedline = 0;
1566
1567 if (c->command == ISDN_CMD_IOCTL)
1568 return capidrv_ioctl(c, card);
1569
1570 switch (c->command) {
1571 case ISDN_CMD_DIAL:{
1572 u8 calling[ISDN_MSNLEN + 3];
1573 u8 called[ISDN_MSNLEN + 2];
1574
1575 if (debugmode)
1576 printk(KERN_DEBUG "capidrv-%d: ISDN_CMD_DIAL(ch=%ld,\"%s,%d,%d,%s\")\n",
1577 card->contrnr,
1578 c->arg,
1579 c->parm.setup.phone,
1580 c->parm.setup.si1,
1581 c->parm.setup.si2,
1582 c->parm.setup.eazmsn);
1583
1584 bchan = &card->bchans[c->arg % card->nbchan];
1585
1586 if (bchan->plcip) {
1587 printk(KERN_ERR "capidrv-%d: dail ch=%ld,\"%s,%d,%d,%s\" in use (plci=0x%x)\n",
1588 card->contrnr,
1589 c->arg,
1590 c->parm.setup.phone,
1591 c->parm.setup.si1,
1592 c->parm.setup.si2,
1593 c->parm.setup.eazmsn,
1594 bchan->plcip->plci);
1595 return 0;
1596 }
1597 bchan->si1 = c->parm.setup.si1;
1598 bchan->si2 = c->parm.setup.si2;
1599
1600 strncpy(bchan->num, c->parm.setup.phone, sizeof(bchan->num));
1601 strncpy(bchan->mynum, c->parm.setup.eazmsn, sizeof(bchan->mynum));
1602 rc = FVteln2capi20(bchan->num, AdditionalInfo);
1603 isleasedline = (rc == 0);
1604 if (rc < 0)
1605 printk(KERN_ERR "capidrv-%d: WARNING: invalid leased linedefinition \"%s\"\n", card->contrnr, bchan->num);
1606
1607 if (isleasedline) {
1608 calling[0] = 0;
1609 called[0] = 0;
1610 if (debugmode)
1611 printk(KERN_DEBUG "capidrv-%d: connecting leased line\n", card->contrnr);
1612 } else {
1613 calling[0] = strlen(bchan->mynum) + 2;
1614 calling[1] = 0;
1615 calling[2] = 0x80;
1616 strncpy(calling + 3, bchan->mynum, ISDN_MSNLEN);
1617 called[0] = strlen(bchan->num) + 1;
1618 called[1] = 0x80;
1619 strncpy(called + 2, bchan->num, ISDN_MSNLEN);
1620 }
1621
1622 capi_fill_CONNECT_REQ(&cmdcmsg,
1623 global.ap.applid,
1624 card->msgid++,
1625 card->contrnr, /* adr */
1626 si2cip(bchan->si1, bchan->si2), /* cipvalue */
1627 called, /* CalledPartyNumber */
1628 calling, /* CallingPartyNumber */
1629 NULL, /* CalledPartySubaddress */
1630 NULL, /* CallingPartySubaddress */
1631 b1prot(bchan->l2, bchan->l3), /* B1protocol */
1632 b2prot(bchan->l2, bchan->l3), /* B2protocol */
1633 b3prot(bchan->l2, bchan->l3), /* B3protocol */
1634 b1config(bchan->l2, bchan->l3), /* B1configuration */
1635 NULL, /* B2configuration */
1636 NULL, /* B3configuration */
1637 NULL, /* BC */
1638 NULL, /* LLC */
1639 NULL, /* HLC */
1640 /* BChannelinformation */
1641 isleasedline ? AdditionalInfo : NULL,
1642 NULL, /* Keypadfacility */
1643 NULL, /* Useruserdata */
1644 NULL /* Facilitydataarray */
1645 );
1646 if ((plcip = new_plci(card, (c->arg % card->nbchan))) == 0) {
1647 cmd.command = ISDN_STAT_DHUP;
1648 cmd.driver = card->myid;
1649 cmd.arg = (c->arg % card->nbchan);
1650 card->interface.statcallb(&cmd);
1651 return -1;
1652 }
1653 plcip->msgid = cmdcmsg.Messagenumber;
1654 plcip->leasedline = isleasedline;
1655 plci_change_state(card, plcip, EV_PLCI_CONNECT_REQ);
1656 send_message(card, &cmdcmsg);
1657 return 0;
1658 }
1659
1660 case ISDN_CMD_ACCEPTD:
1661
1662 bchan = &card->bchans[c->arg % card->nbchan];
1663 if (debugmode)
1664 printk(KERN_DEBUG "capidrv-%d: ISDN_CMD_ACCEPTD(ch=%ld) l2=%d l3=%d\n",
1665 card->contrnr,
1666 c->arg, bchan->l2, bchan->l3);
1667
1668 capi_fill_CONNECT_RESP(&cmdcmsg,
1669 global.ap.applid,
1670 card->msgid++,
1671 bchan->plcip->plci, /* adr */
1672 0, /* Reject */
1673 b1prot(bchan->l2, bchan->l3), /* B1protocol */
1674 b2prot(bchan->l2, bchan->l3), /* B2protocol */
1675 b3prot(bchan->l2, bchan->l3), /* B3protocol */
1676 b1config(bchan->l2, bchan->l3), /* B1configuration */
1677 NULL, /* B2configuration */
1678 NULL, /* B3configuration */
1679 NULL, /* ConnectedNumber */
1680 NULL, /* ConnectedSubaddress */
1681 NULL, /* LLC */
1682 NULL, /* BChannelinformation */
1683 NULL, /* Keypadfacility */
1684 NULL, /* Useruserdata */
1685 NULL /* Facilitydataarray */
1686 );
1687 capi_cmsg2message(&cmdcmsg, cmdcmsg.buf);
1688 plci_change_state(card, bchan->plcip, EV_PLCI_CONNECT_RESP);
1689 send_message(card, &cmdcmsg);
1690 return 0;
1691
1692 case ISDN_CMD_ACCEPTB:
1693 if (debugmode)
1694 printk(KERN_DEBUG "capidrv-%d: ISDN_CMD_ACCEPTB(ch=%ld)\n",
1695 card->contrnr,
1696 c->arg);
1697 return -ENOSYS;
1698
1699 case ISDN_CMD_HANGUP:
1700 if (debugmode)
1701 printk(KERN_DEBUG "capidrv-%d: ISDN_CMD_HANGUP(ch=%ld)\n",
1702 card->contrnr,
1703 c->arg);
1704 bchan = &card->bchans[c->arg % card->nbchan];
1705
1706 if (bchan->disconnecting) {
1707 if (debugmode)
1708 printk(KERN_DEBUG "capidrv-%d: chan %ld already disconnecting ...\n",
1709 card->contrnr,
1710 c->arg);
1711 return 0;
1712 }
1713 if (bchan->nccip) {
1714 bchan->disconnecting = 1;
1715 capi_fill_DISCONNECT_B3_REQ(&cmdcmsg,
1716 global.ap.applid,
1717 card->msgid++,
1718 bchan->nccip->ncci,
1719 NULL /* NCPI */
1720 );
1721 ncci_change_state(card, bchan->nccip, EV_NCCI_DISCONNECT_B3_REQ);
1722 send_message(card, &cmdcmsg);
1723 return 0;
1724 } else if (bchan->plcip) {
1725 if (bchan->plcip->state == ST_PLCI_INCOMING) {
1726 /*
1727 * just ignore, we a called from
1728 * isdn_status_callback(),
1729 * which will return 0 or 2, this is handled
1730 * by the CONNECT_IND handler
1731 */
1732 bchan->disconnecting = 1;
1733 return 0;
1734 } else if (bchan->plcip->plci) {
1735 bchan->disconnecting = 1;
1736 capi_fill_DISCONNECT_REQ(&cmdcmsg,
1737 global.ap.applid,
1738 card->msgid++,
1739 bchan->plcip->plci,
1740 NULL, /* BChannelinformation */
1741 NULL, /* Keypadfacility */
1742 NULL, /* Useruserdata */
1743 NULL /* Facilitydataarray */
1744 );
1745 plci_change_state(card, bchan->plcip, EV_PLCI_DISCONNECT_REQ);
1746 send_message(card, &cmdcmsg);
1747 return 0;
1748 } else {
1749 printk(KERN_ERR "capidrv-%d: chan %ld disconnect request while waiting for CONNECT_CONF\n",
1750 card->contrnr,
1751 c->arg);
1752 return -EINVAL;
1753 }
1754 }
1755 printk(KERN_ERR "capidrv-%d: chan %ld disconnect request on free channel\n",
1756 card->contrnr,
1757 c->arg);
1758 return -EINVAL;
1759/* ready */
1760
1761 case ISDN_CMD_SETL2:
1762 if (debugmode)
1763 printk(KERN_DEBUG "capidrv-%d: set L2 on chan %ld to %ld\n",
1764 card->contrnr,
1765 (c->arg & 0xff), (c->arg >> 8));
1766 bchan = &card->bchans[(c->arg & 0xff) % card->nbchan];
1767 bchan->l2 = (c->arg >> 8);
1768 return 0;
1769
1770 case ISDN_CMD_SETL3:
1771 if (debugmode)
1772 printk(KERN_DEBUG "capidrv-%d: set L3 on chan %ld to %ld\n",
1773 card->contrnr,
1774 (c->arg & 0xff), (c->arg >> 8));
1775 bchan = &card->bchans[(c->arg & 0xff) % card->nbchan];
1776 bchan->l3 = (c->arg >> 8);
1777 return 0;
1778
1779 case ISDN_CMD_SETEAZ:
1780 if (debugmode)
1781 printk(KERN_DEBUG "capidrv-%d: set EAZ \"%s\" on chan %ld\n",
1782 card->contrnr,
1783 c->parm.num, c->arg);
1784 bchan = &card->bchans[c->arg % card->nbchan];
1785 strncpy(bchan->msn, c->parm.num, ISDN_MSNLEN);
1786 return 0;
1787
1788 case ISDN_CMD_CLREAZ:
1789 if (debugmode)
1790 printk(KERN_DEBUG "capidrv-%d: clearing EAZ on chan %ld\n",
1791 card->contrnr, c->arg);
1792 bchan = &card->bchans[c->arg % card->nbchan];
1793 bchan->msn[0] = 0;
1794 return 0;
1795
1796 default:
1797 printk(KERN_ERR "capidrv-%d: ISDN_CMD_%d, Huh?\n",
1798 card->contrnr, c->command);
1799 return -EINVAL;
1800 }
1801 return 0;
1802}
1803
1804static int if_command(isdn_ctrl * c)
1805{
1806 capidrv_contr *card = findcontrbydriverid(c->driver);
1807
1808 if (card)
1809 return capidrv_command(c, card);
1810
1811 printk(KERN_ERR
1812 "capidrv: if_command %d called with invalid driverId %d!\n",
1813 c->command, c->driver);
1814 return -ENODEV;
1815}
1816
1817static _cmsg sendcmsg;
1818
1819static int if_sendbuf(int id, int channel, int doack, struct sk_buff *skb)
1820{
1821 capidrv_contr *card = findcontrbydriverid(id);
1822 capidrv_bchan *bchan;
1823 capidrv_ncci *nccip;
1824 int len = skb->len;
1825 int msglen;
1826 u16 errcode;
1827 u16 datahandle;
1828
1829 if (!card) {
1830 printk(KERN_ERR "capidrv: if_sendbuf called with invalid driverId %d!\n",
1831 id);
1832 return 0;
1833 }
1834 if (debugmode > 4)
1835 printk(KERN_DEBUG "capidrv-%d: sendbuf len=%d skb=%p doack=%d\n",
1836 card->contrnr, len, skb, doack);
1837 bchan = &card->bchans[channel % card->nbchan];
1838 nccip = bchan->nccip;
1839 if (!nccip || nccip->state != ST_NCCI_ACTIVE) {
1840 printk(KERN_ERR "capidrv-%d: if_sendbuf: %s:%d: chan not up!\n",
1841 card->contrnr, card->name, channel);
1842 return 0;
1843 }
1844 datahandle = nccip->datahandle;
1845 capi_fill_DATA_B3_REQ(&sendcmsg, global.ap.applid, card->msgid++,
1846 nccip->ncci, /* adr */
1847 (u32) skb->data, /* Data */
1848 skb->len, /* DataLength */
1849 datahandle, /* DataHandle */
1850 0 /* Flags */
1851 );
1852
1853 if (capidrv_add_ack(nccip, datahandle, doack ? (int)skb->len : -1) < 0)
1854 return 0;
1855
1856 capi_cmsg2message(&sendcmsg, sendcmsg.buf);
1857 msglen = CAPIMSG_LEN(sendcmsg.buf);
1858 if (skb_headroom(skb) < msglen) {
1859 struct sk_buff *nskb = skb_realloc_headroom(skb, msglen);
1860 if (!nskb) {
1861 printk(KERN_ERR "capidrv-%d: if_sendbuf: no memory\n",
1862 card->contrnr);
1863 (void)capidrv_del_ack(nccip, datahandle);
1864 return 0;
1865 }
1866 printk(KERN_DEBUG "capidrv-%d: only %d bytes headroom, need %d\n",
1867 card->contrnr, skb_headroom(skb), msglen);
1868 memcpy(skb_push(nskb, msglen), sendcmsg.buf, msglen);
1869 errcode = capi20_put_message(&global.ap, nskb);
1870 if (errcode == CAPI_NOERROR) {
1871 dev_kfree_skb(skb);
1872 nccip->datahandle++;
1873 return len;
1874 }
1875 if (debugmode > 3)
1876 printk(KERN_DEBUG "capidrv-%d: sendbuf putmsg ret(%x) - %s\n",
1877 card->contrnr, errcode, capi_info2str(errcode));
1878 (void)capidrv_del_ack(nccip, datahandle);
1879 dev_kfree_skb(nskb);
1880 return errcode == CAPI_SENDQUEUEFULL ? 0 : -1;
1881 } else {
1882 memcpy(skb_push(skb, msglen), sendcmsg.buf, msglen);
1883 errcode = capi20_put_message(&global.ap, skb);
1884 if (errcode == CAPI_NOERROR) {
1885 nccip->datahandle++;
1886 return len;
1887 }
1888 if (debugmode > 3)
1889 printk(KERN_DEBUG "capidrv-%d: sendbuf putmsg ret(%x) - %s\n",
1890 card->contrnr, errcode, capi_info2str(errcode));
1891 skb_pull(skb, msglen);
1892 (void)capidrv_del_ack(nccip, datahandle);
1893 return errcode == CAPI_SENDQUEUEFULL ? 0 : -1;
1894 }
1895}
1896
1897static int if_readstat(u8 __user *buf, int len, int id, int channel)
1898{
1899 capidrv_contr *card = findcontrbydriverid(id);
1900 int count;
1901 u8 __user *p;
1902
1903 if (!card) {
1904 printk(KERN_ERR "capidrv: if_readstat called with invalid driverId %d!\n",
1905 id);
1906 return -ENODEV;
1907 }
1908
1909 for (p=buf, count=0; count < len; p++, count++) {
1910 put_user(*card->q931_read++, p);
1911 if (card->q931_read > card->q931_end)
1912 card->q931_read = card->q931_buf;
1913 }
1914 return count;
1915
1916}
1917
1918static void enable_dchannel_trace(capidrv_contr *card)
1919{
1920 u8 manufacturer[CAPI_MANUFACTURER_LEN];
1921 capi_version version;
1922 u16 contr = card->contrnr;
1923 u16 errcode;
1924 u16 avmversion[3];
1925
1926 errcode = capi20_get_manufacturer(contr, manufacturer);
1927 if (errcode != CAPI_NOERROR) {
1928 printk(KERN_ERR "%s: can't get manufacturer (0x%x)\n",
1929 card->name, errcode);
1930 return;
1931 }
1932 if (strstr(manufacturer, "AVM") == 0) {
1933 printk(KERN_ERR "%s: not from AVM, no d-channel trace possible (%s)\n",
1934 card->name, manufacturer);
1935 return;
1936 }
1937 errcode = capi20_get_version(contr, &version);
1938 if (errcode != CAPI_NOERROR) {
1939 printk(KERN_ERR "%s: can't get version (0x%x)\n",
1940 card->name, errcode);
1941 return;
1942 }
1943 avmversion[0] = (version.majormanuversion >> 4) & 0x0f;
1944 avmversion[1] = (version.majormanuversion << 4) & 0xf0;
1945 avmversion[1] |= (version.minormanuversion >> 4) & 0x0f;
1946 avmversion[2] |= version.minormanuversion & 0x0f;
1947
1948 if (avmversion[0] > 3 || (avmversion[0] == 3 && avmversion[1] > 5)) {
1949 printk(KERN_INFO "%s: D2 trace enabled\n", card->name);
1950 capi_fill_MANUFACTURER_REQ(&cmdcmsg, global.ap.applid,
1951 card->msgid++,
1952 contr,
1953 0x214D5641, /* ManuID */
1954 0, /* Class */
1955 1, /* Function */
1956 (_cstruct)"\004\200\014\000\000");
1957 } else {
1958 printk(KERN_INFO "%s: D3 trace enabled\n", card->name);
1959 capi_fill_MANUFACTURER_REQ(&cmdcmsg, global.ap.applid,
1960 card->msgid++,
1961 contr,
1962 0x214D5641, /* ManuID */
1963 0, /* Class */
1964 1, /* Function */
1965 (_cstruct)"\004\002\003\000\000");
1966 }
1967 send_message(card, &cmdcmsg);
1968}
1969
1970
1971static void send_listen(capidrv_contr *card)
1972{
1973 capi_fill_LISTEN_REQ(&cmdcmsg, global.ap.applid,
1974 card->msgid++,
1975 card->contrnr, /* controller */
1976 1 << 6, /* Infomask */
1977 card->cipmask,
1978 card->cipmask2,
1979 NULL, NULL);
1980 send_message(card, &cmdcmsg);
1981 listen_change_state(card, EV_LISTEN_REQ);
1982}
1983
1984static void listentimerfunc(unsigned long x)
1985{
1986 capidrv_contr *card = (capidrv_contr *)x;
1987 if (card->state != ST_LISTEN_NONE && card->state != ST_LISTEN_ACTIVE)
1988 printk(KERN_ERR "%s: controller dead ??\n", card->name);
1989 send_listen(card);
1990 mod_timer(&card->listentimer, jiffies + 60*HZ);
1991}
1992
1993
1994static int capidrv_addcontr(u16 contr, struct capi_profile *profp)
1995{
1996 capidrv_contr *card;
1997 unsigned long flags;
1998 isdn_ctrl cmd;
1999 char id[20];
2000 int i;
2001
2002 sprintf(id, "capidrv-%d", contr);
2003 if (!try_module_get(THIS_MODULE)) {
2004 printk(KERN_WARNING "capidrv: (%s) Could not reserve module\n", id);
2005 return -1;
2006 }
2007 if (!(card = (capidrv_contr *) kmalloc(sizeof(capidrv_contr), GFP_ATOMIC))) {
2008 printk(KERN_WARNING
2009 "capidrv: (%s) Could not allocate contr-struct.\n", id);
2010 return -1;
2011 }
2012 memset(card, 0, sizeof(capidrv_contr));
2013 card->owner = THIS_MODULE;
2014 init_timer(&card->listentimer);
2015 strcpy(card->name, id);
2016 card->contrnr = contr;
2017 card->nbchan = profp->nbchannel;
2018 card->bchans = (capidrv_bchan *) kmalloc(sizeof(capidrv_bchan) * card->nbchan, GFP_ATOMIC);
2019 if (!card->bchans) {
2020 printk(KERN_WARNING
2021 "capidrv: (%s) Could not allocate bchan-structs.\n", id);
2022 module_put(card->owner);
2023 kfree(card);
2024 return -1;
2025 }
2026 card->interface.channels = profp->nbchannel;
2027 card->interface.maxbufsize = 2048;
2028 card->interface.command = if_command;
2029 card->interface.writebuf_skb = if_sendbuf;
2030 card->interface.writecmd = NULL;
2031 card->interface.readstat = if_readstat;
2032 card->interface.features = ISDN_FEATURE_L2_HDLC |
2033 ISDN_FEATURE_L2_TRANS |
2034 ISDN_FEATURE_L3_TRANS |
2035 ISDN_FEATURE_P_UNKNOWN |
2036 ISDN_FEATURE_L2_X75I |
2037 ISDN_FEATURE_L2_X75UI |
2038 ISDN_FEATURE_L2_X75BUI;
2039 if (profp->support1 & (1<<2))
2040 card->interface.features |= ISDN_FEATURE_L2_V11096 |
2041 ISDN_FEATURE_L2_V11019 |
2042 ISDN_FEATURE_L2_V11038;
2043 if (profp->support1 & (1<<8))
2044 card->interface.features |= ISDN_FEATURE_L2_MODEM;
2045 card->interface.hl_hdrlen = 22; /* len of DATA_B3_REQ */
2046 strncpy(card->interface.id, id, sizeof(card->interface.id) - 1);
2047
2048
2049 card->q931_read = card->q931_buf;
2050 card->q931_write = card->q931_buf;
2051 card->q931_end = card->q931_buf + sizeof(card->q931_buf) - 1;
2052
2053 if (!register_isdn(&card->interface)) {
2054 printk(KERN_ERR "capidrv: Unable to register contr %s\n", id);
2055 kfree(card->bchans);
2056 module_put(card->owner);
2057 kfree(card);
2058 return -1;
2059 }
2060 card->myid = card->interface.channels;
2061 memset(card->bchans, 0, sizeof(capidrv_bchan) * card->nbchan);
2062 for (i = 0; i < card->nbchan; i++) {
2063 card->bchans[i].contr = card;
2064 }
2065
2066 spin_lock_irqsave(&global_lock, flags);
2067 card->next = global.contr_list;
2068 global.contr_list = card;
2069 global.ncontr++;
2070 spin_unlock_irqrestore(&global_lock, flags);
2071
2072 cmd.command = ISDN_STAT_RUN;
2073 cmd.driver = card->myid;
2074 card->interface.statcallb(&cmd);
2075
2076 card->cipmask = 0x1FFF03FF; /* any */
2077 card->cipmask2 = 0;
2078
2079 card->listentimer.data = (unsigned long)card;
2080 card->listentimer.function = listentimerfunc;
2081 send_listen(card);
2082 mod_timer(&card->listentimer, jiffies + 60*HZ);
2083
2084 printk(KERN_INFO "%s: now up (%d B channels)\n",
2085 card->name, card->nbchan);
2086
2087 enable_dchannel_trace(card);
2088
2089 return 0;
2090}
2091
2092static int capidrv_delcontr(u16 contr)
2093{
2094 capidrv_contr **pp, *card;
2095 unsigned long flags;
2096 isdn_ctrl cmd;
2097
2098 spin_lock_irqsave(&global_lock, flags);
2099 for (card = global.contr_list; card; card = card->next) {
2100 if (card->contrnr == contr)
2101 break;
2102 }
2103 if (!card) {
2104 spin_unlock_irqrestore(&global_lock, flags);
2105 printk(KERN_ERR "capidrv: delcontr: no contr %u\n", contr);
2106 return -1;
2107 }
2108 #warning FIXME: maybe a race condition the card should be removed here from global list /kkeil
2109 spin_unlock_irqrestore(&global_lock, flags);
2110
2111 del_timer(&card->listentimer);
2112
2113 if (debugmode)
2114 printk(KERN_DEBUG "capidrv-%d: id=%d unloading\n",
2115 card->contrnr, card->myid);
2116
2117 cmd.command = ISDN_STAT_STOP;
2118 cmd.driver = card->myid;
2119 card->interface.statcallb(&cmd);
2120
2121 while (card->nbchan) {
2122
2123 cmd.command = ISDN_STAT_DISCH;
2124 cmd.driver = card->myid;
2125 cmd.arg = card->nbchan-1;
2126 cmd.parm.num[0] = 0;
2127 if (debugmode)
2128 printk(KERN_DEBUG "capidrv-%d: id=%d disable chan=%ld\n",
2129 card->contrnr, card->myid, cmd.arg);
2130 card->interface.statcallb(&cmd);
2131
2132 if (card->bchans[card->nbchan-1].nccip)
2133 free_ncci(card, card->bchans[card->nbchan-1].nccip);
2134 if (card->bchans[card->nbchan-1].plcip)
2135 free_plci(card, card->bchans[card->nbchan-1].plcip);
2136 if (card->plci_list)
2137 printk(KERN_ERR "capidrv: bug in free_plci()\n");
2138 card->nbchan--;
2139 }
2140 kfree(card->bchans);
2141 card->bchans = NULL;
2142
2143 if (debugmode)
2144 printk(KERN_DEBUG "capidrv-%d: id=%d isdn unload\n",
2145 card->contrnr, card->myid);
2146
2147 cmd.command = ISDN_STAT_UNLOAD;
2148 cmd.driver = card->myid;
2149 card->interface.statcallb(&cmd);
2150
2151 if (debugmode)
2152 printk(KERN_DEBUG "capidrv-%d: id=%d remove contr from list\n",
2153 card->contrnr, card->myid);
2154
2155 spin_lock_irqsave(&global_lock, flags);
2156 for (pp = &global.contr_list; *pp; pp = &(*pp)->next) {
2157 if (*pp == card) {
2158 *pp = (*pp)->next;
2159 card->next = NULL;
2160 global.ncontr--;
2161 break;
2162 }
2163 }
2164 spin_unlock_irqrestore(&global_lock, flags);
2165
2166 module_put(card->owner);
2167 printk(KERN_INFO "%s: now down.\n", card->name);
2168 kfree(card);
2169 return 0;
2170}
2171
2172
2173static void lower_callback(unsigned int cmd, u32 contr, void *data)
2174{
2175
2176 switch (cmd) {
2177 case KCI_CONTRUP:
2178 printk(KERN_INFO "capidrv: controller %hu up\n", contr);
2179 (void) capidrv_addcontr(contr, (capi_profile *) data);
2180 break;
2181 case KCI_CONTRDOWN:
2182 printk(KERN_INFO "capidrv: controller %hu down\n", contr);
2183 (void) capidrv_delcontr(contr);
2184 break;
2185 }
2186}
2187
2188/*
2189 * /proc/capi/capidrv:
2190 * nrecvctlpkt nrecvdatapkt nsendctlpkt nsenddatapkt
2191 */
2192static int proc_capidrv_read_proc(char *page, char **start, off_t off,
2193 int count, int *eof, void *data)
2194{
2195 int len = 0;
2196
2197 len += sprintf(page+len, "%lu %lu %lu %lu\n",
2198 global.ap.nrecvctlpkt,
2199 global.ap.nrecvdatapkt,
2200 global.ap.nsentctlpkt,
2201 global.ap.nsentdatapkt);
2202 if (off+count >= len)
2203 *eof = 1;
2204 if (len < off)
2205 return 0;
2206 *start = page + off;
2207 return ((count < len-off) ? count : len-off);
2208}
2209
2210static struct procfsentries {
2211 char *name;
2212 mode_t mode;
2213 int (*read_proc)(char *page, char **start, off_t off,
2214 int count, int *eof, void *data);
2215 struct proc_dir_entry *procent;
2216} procfsentries[] = {
2217 /* { "capi", S_IFDIR, 0 }, */
2218 { "capi/capidrv", 0 , proc_capidrv_read_proc },
2219};
2220
2221static void __init proc_init(void)
2222{
2223 int nelem = sizeof(procfsentries)/sizeof(procfsentries[0]);
2224 int i;
2225
2226 for (i=0; i < nelem; i++) {
2227 struct procfsentries *p = procfsentries + i;
2228 p->procent = create_proc_entry(p->name, p->mode, NULL);
2229 if (p->procent) p->procent->read_proc = p->read_proc;
2230 }
2231}
2232
2233static void __exit proc_exit(void)
2234{
2235 int nelem = sizeof(procfsentries)/sizeof(procfsentries[0]);
2236 int i;
2237
2238 for (i=nelem-1; i >= 0; i--) {
2239 struct procfsentries *p = procfsentries + i;
2240 if (p->procent) {
2241 remove_proc_entry(p->name, NULL);
2242 p->procent = NULL;
2243 }
2244 }
2245}
2246
2247static int __init capidrv_init(void)
2248{
2249 capi_profile profile;
2250 char rev[32];
2251 char *p;
2252 u32 ncontr, contr;
2253 u16 errcode;
2254
2255 if ((p = strchr(revision, ':')) != 0 && p[1]) {
2256 strncpy(rev, p + 2, sizeof(rev));
2257 rev[sizeof(rev)-1] = 0;
2258 if ((p = strchr(rev, '$')) != 0 && p > rev)
2259 *(p-1) = 0;
2260 } else
2261 strcpy(rev, "1.0");
2262
2263 global.ap.rparam.level3cnt = -2; /* number of bchannels twice */
2264 global.ap.rparam.datablkcnt = 16;
2265 global.ap.rparam.datablklen = 2048;
2266
2267 global.ap.recv_message = capidrv_recv_message;
2268 errcode = capi20_register(&global.ap);
2269 if (errcode) {
2270 return -EIO;
2271 }
2272
2273 capi20_set_callback(&global.ap, lower_callback);
2274
2275 errcode = capi20_get_profile(0, &profile);
2276 if (errcode != CAPI_NOERROR) {
2277 capi20_release(&global.ap);
2278 return -EIO;
2279 }
2280
2281 ncontr = profile.ncontroller;
2282 for (contr = 1; contr <= ncontr; contr++) {
2283 errcode = capi20_get_profile(contr, &profile);
2284 if (errcode != CAPI_NOERROR)
2285 continue;
2286 (void) capidrv_addcontr(contr, &profile);
2287 }
2288 proc_init();
2289
2290 printk(KERN_NOTICE "capidrv: Rev %s: loaded\n", rev);
2291 return 0;
2292}
2293
2294static void __exit capidrv_exit(void)
2295{
2296 char rev[10];
2297 char *p;
2298
2299 if ((p = strchr(revision, ':')) != 0) {
2300 strcpy(rev, p + 1);
2301 p = strchr(rev, '$');
2302 *p = 0;
2303 } else {
2304 strcpy(rev, " ??? ");
2305 }
2306
2307 capi20_release(&global.ap);
2308
2309 proc_exit();
2310
2311 printk(KERN_NOTICE "capidrv: Rev%s: unloaded\n", rev);
2312}
2313
2314module_init(capidrv_init);
2315module_exit(capidrv_exit);
diff --git a/drivers/isdn/capi/capidrv.h b/drivers/isdn/capi/capidrv.h
new file mode 100644
index 000000000000..1e698e1e269f
--- /dev/null
+++ b/drivers/isdn/capi/capidrv.h
@@ -0,0 +1,140 @@
1/* $Id: capidrv.h,v 1.2.8.2 2001/09/23 22:24:33 kai Exp $
2 *
3 * ISDN4Linux Driver, using capi20 interface (kernelcapi)
4 *
5 * Copyright 1997 by Carsten Paeth <calle@calle.de>
6 *
7 * This software may be used and distributed according to the terms
8 * of the GNU General Public License, incorporated herein by reference.
9 *
10 */
11
12#ifndef __CAPIDRV_H__
13#define __CAPIDRV_H__
14
15/*
16 * LISTEN state machine
17 */
18#define ST_LISTEN_NONE 0 /* L-0 */
19#define ST_LISTEN_WAIT_CONF 1 /* L-0.1 */
20#define ST_LISTEN_ACTIVE 2 /* L-1 */
21#define ST_LISTEN_ACTIVE_WAIT_CONF 3 /* L-1.1 */
22
23
24#define EV_LISTEN_REQ 1 /* L-0 -> L-0.1
25 L-1 -> L-1.1 */
26#define EV_LISTEN_CONF_ERROR 2 /* L-0.1 -> L-0
27 L-1.1 -> L-1 */
28#define EV_LISTEN_CONF_EMPTY 3 /* L-0.1 -> L-0
29 L-1.1 -> L-0 */
30#define EV_LISTEN_CONF_OK 4 /* L-0.1 -> L-1
31 L-1.1 -> L.1 */
32
33/*
34 * per plci state machine
35 */
36#define ST_PLCI_NONE 0 /* P-0 */
37#define ST_PLCI_OUTGOING 1 /* P-0.1 */
38#define ST_PLCI_ALLOCATED 2 /* P-1 */
39#define ST_PLCI_ACTIVE 3 /* P-ACT */
40#define ST_PLCI_INCOMING 4 /* P-2 */
41#define ST_PLCI_FACILITY_IND 5 /* P-3 */
42#define ST_PLCI_ACCEPTING 6 /* P-4 */
43#define ST_PLCI_DISCONNECTING 7 /* P-5 */
44#define ST_PLCI_DISCONNECTED 8 /* P-6 */
45#define ST_PLCI_RESUMEING 9 /* P-0.Res */
46#define ST_PLCI_RESUME 10 /* P-Res */
47#define ST_PLCI_HELD 11 /* P-HELD */
48
49#define EV_PLCI_CONNECT_REQ 1 /* P-0 -> P-0.1
50 */
51#define EV_PLCI_CONNECT_CONF_ERROR 2 /* P-0.1 -> P-0
52 */
53#define EV_PLCI_CONNECT_CONF_OK 3 /* P-0.1 -> P-1
54 */
55#define EV_PLCI_FACILITY_IND_UP 4 /* P-0 -> P-1
56 */
57#define EV_PLCI_CONNECT_IND 5 /* P-0 -> P-2
58 */
59#define EV_PLCI_CONNECT_ACTIVE_IND 6 /* P-1 -> P-ACT
60 */
61#define EV_PLCI_CONNECT_REJECT 7 /* P-2 -> P-5
62 P-3 -> P-5
63 */
64#define EV_PLCI_DISCONNECT_REQ 8 /* P-1 -> P-5
65 P-2 -> P-5
66 P-3 -> P-5
67 P-4 -> P-5
68 P-ACT -> P-5
69 P-Res -> P-5 (*)
70 P-HELD -> P-5 (*)
71 */
72#define EV_PLCI_DISCONNECT_IND 9 /* P-1 -> P-6
73 P-2 -> P-6
74 P-3 -> P-6
75 P-4 -> P-6
76 P-5 -> P-6
77 P-ACT -> P-6
78 P-Res -> P-6 (*)
79 P-HELD -> P-6 (*)
80 */
81#define EV_PLCI_FACILITY_IND_DOWN 10 /* P-0.1 -> P-5
82 P-1 -> P-5
83 P-ACT -> P-5
84 P-2 -> P-5
85 P-3 -> P-5
86 P-4 -> P-5
87 */
88#define EV_PLCI_DISCONNECT_RESP 11 /* P-6 -> P-0
89 */
90#define EV_PLCI_CONNECT_RESP 12 /* P-6 -> P-0
91 */
92
93#define EV_PLCI_RESUME_REQ 13 /* P-0 -> P-0.Res
94 */
95#define EV_PLCI_RESUME_CONF_OK 14 /* P-0.Res -> P-Res
96 */
97#define EV_PLCI_RESUME_CONF_ERROR 15 /* P-0.Res -> P-0
98 */
99#define EV_PLCI_RESUME_IND 16 /* P-Res -> P-ACT
100 */
101#define EV_PLCI_HOLD_IND 17 /* P-ACT -> P-HELD
102 */
103#define EV_PLCI_RETRIEVE_IND 18 /* P-HELD -> P-ACT
104 */
105#define EV_PLCI_SUSPEND_IND 19 /* P-ACT -> P-5
106 */
107#define EV_PLCI_CD_IND 20 /* P-2 -> P-5
108 */
109
110/*
111 * per ncci state machine
112 */
113#define ST_NCCI_PREVIOUS -1
114#define ST_NCCI_NONE 0 /* N-0 */
115#define ST_NCCI_OUTGOING 1 /* N-0.1 */
116#define ST_NCCI_INCOMING 2 /* N-1 */
117#define ST_NCCI_ALLOCATED 3 /* N-2 */
118#define ST_NCCI_ACTIVE 4 /* N-ACT */
119#define ST_NCCI_RESETING 5 /* N-3 */
120#define ST_NCCI_DISCONNECTING 6 /* N-4 */
121#define ST_NCCI_DISCONNECTED 7 /* N-5 */
122
123#define EV_NCCI_CONNECT_B3_REQ 1 /* N-0 -> N-0.1 */
124#define EV_NCCI_CONNECT_B3_IND 2 /* N-0 -> N.1 */
125#define EV_NCCI_CONNECT_B3_CONF_OK 3 /* N-0.1 -> N.2 */
126#define EV_NCCI_CONNECT_B3_CONF_ERROR 4 /* N-0.1 -> N.0 */
127#define EV_NCCI_CONNECT_B3_REJECT 5 /* N-1 -> N-4 */
128#define EV_NCCI_CONNECT_B3_RESP 6 /* N-1 -> N-2 */
129#define EV_NCCI_CONNECT_B3_ACTIVE_IND 7 /* N-2 -> N-ACT */
130#define EV_NCCI_RESET_B3_REQ 8 /* N-ACT -> N-3 */
131#define EV_NCCI_RESET_B3_IND 9 /* N-3 -> N-ACT */
132#define EV_NCCI_DISCONNECT_B3_IND 10 /* N-4 -> N.5 */
133#define EV_NCCI_DISCONNECT_B3_CONF_ERROR 11 /* N-4 -> previous */
134#define EV_NCCI_DISCONNECT_B3_REQ 12 /* N-1 -> N-4
135 N-2 -> N-4
136 N-3 -> N-4
137 N-ACT -> N-4 */
138#define EV_NCCI_DISCONNECT_B3_RESP 13 /* N-5 -> N-0 */
139
140#endif /* __CAPIDRV_H__ */
diff --git a/drivers/isdn/capi/capifs.c b/drivers/isdn/capi/capifs.c
new file mode 100644
index 000000000000..f8570fd9d2ab
--- /dev/null
+++ b/drivers/isdn/capi/capifs.c
@@ -0,0 +1,212 @@
1/* $Id: capifs.c,v 1.1.2.3 2004/01/16 21:09:26 keil Exp $
2 *
3 * Copyright 2000 by Carsten Paeth <calle@calle.de>
4 *
5 * Heavily based on devpts filesystem from H. Peter Anvin
6 *
7 * This software may be used and distributed according to the terms
8 * of the GNU General Public License, incorporated herein by reference.
9 *
10 */
11
12#include <linux/fs.h>
13#include <linux/mount.h>
14#include <linux/namei.h>
15#include <linux/module.h>
16#include <linux/init.h>
17#include <linux/ctype.h>
18
19MODULE_DESCRIPTION("CAPI4Linux: /dev/capi/ filesystem");
20MODULE_AUTHOR("Carsten Paeth");
21MODULE_LICENSE("GPL");
22
23/* ------------------------------------------------------------------ */
24
25static char *revision = "$Revision: 1.1.2.3 $";
26
27/* ------------------------------------------------------------------ */
28
29#define CAPIFS_SUPER_MAGIC (('C'<<8)|'N')
30
31static struct vfsmount *capifs_mnt;
32static struct dentry *capifs_root;
33
34static struct {
35 int setuid;
36 int setgid;
37 uid_t uid;
38 gid_t gid;
39 umode_t mode;
40} config = {.mode = 0600};
41
42/* ------------------------------------------------------------------ */
43
44static int capifs_remount(struct super_block *s, int *flags, char *data)
45{
46 int setuid = 0;
47 int setgid = 0;
48 uid_t uid = 0;
49 gid_t gid = 0;
50 umode_t mode = 0600;
51 char *this_char;
52
53 this_char = NULL;
54 while ((this_char = strsep(&data, ",")) != NULL) {
55 int n;
56 char dummy;
57 if (!*this_char)
58 continue;
59 if (sscanf(this_char, "uid=%i%c", &n, &dummy) == 1) {
60 setuid = 1;
61 uid = n;
62 } else if (sscanf(this_char, "gid=%i%c", &n, &dummy) == 1) {
63 setgid = 1;
64 gid = n;
65 } else if (sscanf(this_char, "mode=%o%c", &n, &dummy) == 1)
66 mode = n & ~S_IFMT;
67 else {
68 printk("capifs: called with bogus options\n");
69 return -EINVAL;
70 }
71 }
72 config.setuid = setuid;
73 config.setgid = setgid;
74 config.uid = uid;
75 config.gid = gid;
76 config.mode = mode;
77 return 0;
78}
79
80static struct super_operations capifs_sops =
81{
82 .statfs = simple_statfs,
83 .remount_fs = capifs_remount,
84};
85
86
87static int
88capifs_fill_super(struct super_block *s, void *data, int silent)
89{
90 struct inode * inode;
91
92 s->s_blocksize = 1024;
93 s->s_blocksize_bits = 10;
94 s->s_magic = CAPIFS_SUPER_MAGIC;
95 s->s_op = &capifs_sops;
96 s->s_time_gran = 1;
97
98 inode = new_inode(s);
99 if (!inode)
100 goto fail;
101 inode->i_ino = 1;
102 inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
103 inode->i_blocks = 0;
104 inode->i_blksize = 1024;
105 inode->i_uid = inode->i_gid = 0;
106 inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO | S_IWUSR;
107 inode->i_op = &simple_dir_inode_operations;
108 inode->i_fop = &simple_dir_operations;
109 inode->i_nlink = 2;
110
111 capifs_root = s->s_root = d_alloc_root(inode);
112 if (s->s_root)
113 return 0;
114
115 printk("capifs: get root dentry failed\n");
116 iput(inode);
117fail:
118 return -ENOMEM;
119}
120
121static struct super_block *capifs_get_sb(struct file_system_type *fs_type,
122 int flags, const char *dev_name, void *data)
123{
124 return get_sb_single(fs_type, flags, data, capifs_fill_super);
125}
126
127static struct file_system_type capifs_fs_type = {
128 .owner = THIS_MODULE,
129 .name = "capifs",
130 .get_sb = capifs_get_sb,
131 .kill_sb = kill_anon_super,
132};
133
134static struct dentry *get_node(int num)
135{
136 char s[10];
137 struct dentry *root = capifs_root;
138 down(&root->d_inode->i_sem);
139 return lookup_one_len(s, root, sprintf(s, "%d", num));
140}
141
142void capifs_new_ncci(unsigned int number, dev_t device)
143{
144 struct dentry *dentry;
145 struct inode *inode = new_inode(capifs_mnt->mnt_sb);
146 if (!inode)
147 return;
148 inode->i_ino = number+2;
149 inode->i_blksize = 1024;
150 inode->i_uid = config.setuid ? config.uid : current->fsuid;
151 inode->i_gid = config.setgid ? config.gid : current->fsgid;
152 inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
153 init_special_inode(inode, S_IFCHR|config.mode, device);
154 //inode->i_op = &capifs_file_inode_operations;
155
156 dentry = get_node(number);
157 if (!IS_ERR(dentry) && !dentry->d_inode)
158 d_instantiate(dentry, inode);
159 up(&capifs_root->d_inode->i_sem);
160}
161
162void capifs_free_ncci(unsigned int number)
163{
164 struct dentry *dentry = get_node(number);
165
166 if (!IS_ERR(dentry)) {
167 struct inode *inode = dentry->d_inode;
168 if (inode) {
169 inode->i_nlink--;
170 d_delete(dentry);
171 dput(dentry);
172 }
173 dput(dentry);
174 }
175 up(&capifs_root->d_inode->i_sem);
176}
177
178static int __init capifs_init(void)
179{
180 char rev[32];
181 char *p;
182 int err;
183
184 if ((p = strchr(revision, ':')) != 0 && p[1]) {
185 strlcpy(rev, p + 2, sizeof(rev));
186 if ((p = strchr(rev, '$')) != 0 && p > rev)
187 *(p-1) = 0;
188 } else
189 strcpy(rev, "1.0");
190
191 err = register_filesystem(&capifs_fs_type);
192 if (!err) {
193 capifs_mnt = kern_mount(&capifs_fs_type);
194 if (IS_ERR(capifs_mnt))
195 err = PTR_ERR(capifs_mnt);
196 }
197 if (!err)
198 printk(KERN_NOTICE "capifs: Rev %s\n", rev);
199 return err;
200}
201
202static void __exit capifs_exit(void)
203{
204 unregister_filesystem(&capifs_fs_type);
205 mntput(capifs_mnt);
206}
207
208EXPORT_SYMBOL(capifs_new_ncci);
209EXPORT_SYMBOL(capifs_free_ncci);
210
211module_init(capifs_init);
212module_exit(capifs_exit);
diff --git a/drivers/isdn/capi/capifs.h b/drivers/isdn/capi/capifs.h
new file mode 100644
index 000000000000..d0bd4c3c430a
--- /dev/null
+++ b/drivers/isdn/capi/capifs.h
@@ -0,0 +1,11 @@
1/* $Id: capifs.h,v 1.1.2.2 2004/01/16 21:09:26 keil Exp $
2 *
3 * Copyright 2000 by Carsten Paeth <calle@calle.de>
4 *
5 * This software may be used and distributed according to the terms
6 * of the GNU General Public License, incorporated herein by reference.
7 *
8 */
9
10void capifs_new_ncci(unsigned int num, dev_t device);
11void capifs_free_ncci(unsigned int num);
diff --git a/drivers/isdn/capi/capilib.c b/drivers/isdn/capi/capilib.c
new file mode 100644
index 000000000000..68409d971e73
--- /dev/null
+++ b/drivers/isdn/capi/capilib.c
@@ -0,0 +1,200 @@
1
2#include <linux/kernel.h>
3#include <linux/module.h>
4#include <linux/isdn/capilli.h>
5
6#define DBG(format, arg...) do { \
7printk(KERN_DEBUG "%s: " format "\n" , __FUNCTION__ , ## arg); \
8} while (0)
9
10struct capilib_msgidqueue {
11 struct capilib_msgidqueue *next;
12 u16 msgid;
13};
14
15struct capilib_ncci {
16 struct list_head list;
17 u16 applid;
18 u32 ncci;
19 u32 winsize;
20 int nmsg;
21 struct capilib_msgidqueue *msgidqueue;
22 struct capilib_msgidqueue *msgidlast;
23 struct capilib_msgidqueue *msgidfree;
24 struct capilib_msgidqueue msgidpool[CAPI_MAXDATAWINDOW];
25};
26
27// ---------------------------------------------------------------------------
28// NCCI Handling
29
30static inline void mq_init(struct capilib_ncci * np)
31{
32 u_int i;
33 np->msgidqueue = NULL;
34 np->msgidlast = NULL;
35 np->nmsg = 0;
36 memset(np->msgidpool, 0, sizeof(np->msgidpool));
37 np->msgidfree = &np->msgidpool[0];
38 for (i = 1; i < np->winsize; i++) {
39 np->msgidpool[i].next = np->msgidfree;
40 np->msgidfree = &np->msgidpool[i];
41 }
42}
43
44static inline int mq_enqueue(struct capilib_ncci * np, u16 msgid)
45{
46 struct capilib_msgidqueue *mq;
47 if ((mq = np->msgidfree) == 0)
48 return 0;
49 np->msgidfree = mq->next;
50 mq->msgid = msgid;
51 mq->next = NULL;
52 if (np->msgidlast)
53 np->msgidlast->next = mq;
54 np->msgidlast = mq;
55 if (!np->msgidqueue)
56 np->msgidqueue = mq;
57 np->nmsg++;
58 return 1;
59}
60
61static inline int mq_dequeue(struct capilib_ncci * np, u16 msgid)
62{
63 struct capilib_msgidqueue **pp;
64 for (pp = &np->msgidqueue; *pp; pp = &(*pp)->next) {
65 if ((*pp)->msgid == msgid) {
66 struct capilib_msgidqueue *mq = *pp;
67 *pp = mq->next;
68 if (mq == np->msgidlast)
69 np->msgidlast = NULL;
70 mq->next = np->msgidfree;
71 np->msgidfree = mq;
72 np->nmsg--;
73 return 1;
74 }
75 }
76 return 0;
77}
78
79void capilib_new_ncci(struct list_head *head, u16 applid, u32 ncci, u32 winsize)
80{
81 struct capilib_ncci *np;
82
83 np = kmalloc(sizeof(*np), GFP_ATOMIC);
84 if (!np) {
85 printk(KERN_WARNING "capilib_new_ncci: no memory.\n");
86 return;
87 }
88 if (winsize > CAPI_MAXDATAWINDOW) {
89 printk(KERN_ERR "capi_new_ncci: winsize %d too big\n",
90 winsize);
91 winsize = CAPI_MAXDATAWINDOW;
92 }
93 np->applid = applid;
94 np->ncci = ncci;
95 np->winsize = winsize;
96 mq_init(np);
97 list_add_tail(&np->list, head);
98 DBG("kcapi: appl %d ncci 0x%x up", applid, ncci);
99}
100
101EXPORT_SYMBOL(capilib_new_ncci);
102
103void capilib_free_ncci(struct list_head *head, u16 applid, u32 ncci)
104{
105 struct list_head *l;
106 struct capilib_ncci *np;
107
108 list_for_each(l, head) {
109 np = list_entry(l, struct capilib_ncci, list);
110 if (np->applid != applid)
111 continue;
112 if (np->ncci != ncci)
113 continue;
114 printk(KERN_INFO "kcapi: appl %d ncci 0x%x down\n", applid, ncci);
115 list_del(&np->list);
116 kfree(np);
117 return;
118 }
119 printk(KERN_ERR "capilib_free_ncci: ncci 0x%x not found\n", ncci);
120}
121
122EXPORT_SYMBOL(capilib_free_ncci);
123
124void capilib_release_appl(struct list_head *head, u16 applid)
125{
126 struct list_head *l, *n;
127 struct capilib_ncci *np;
128
129 list_for_each_safe(l, n, head) {
130 np = list_entry(l, struct capilib_ncci, list);
131 if (np->applid != applid)
132 continue;
133 printk(KERN_INFO "kcapi: appl %d ncci 0x%x forced down\n", applid, np->ncci);
134 list_del(&np->list);
135 kfree(np);
136 }
137}
138
139EXPORT_SYMBOL(capilib_release_appl);
140
141void capilib_release(struct list_head *head)
142{
143 struct list_head *l, *n;
144 struct capilib_ncci *np;
145
146 list_for_each_safe(l, n, head) {
147 np = list_entry(l, struct capilib_ncci, list);
148 printk(KERN_INFO "kcapi: appl %d ncci 0x%x forced down\n", np->applid, np->ncci);
149 list_del(&np->list);
150 kfree(np);
151 }
152}
153
154EXPORT_SYMBOL(capilib_release);
155
156u16 capilib_data_b3_req(struct list_head *head, u16 applid, u32 ncci, u16 msgid)
157{
158 struct list_head *l;
159 struct capilib_ncci *np;
160
161 list_for_each(l, head) {
162 np = list_entry(l, struct capilib_ncci, list);
163 if (np->applid != applid)
164 continue;
165 if (np->ncci != ncci)
166 continue;
167
168 if (mq_enqueue(np, msgid) == 0)
169 return CAPI_SENDQUEUEFULL;
170
171 return CAPI_NOERROR;
172 }
173 printk(KERN_ERR "capilib_data_b3_req: ncci 0x%x not found\n", ncci);
174 return CAPI_NOERROR;
175}
176
177EXPORT_SYMBOL(capilib_data_b3_req);
178
179void capilib_data_b3_conf(struct list_head *head, u16 applid, u32 ncci, u16 msgid)
180{
181 struct list_head *l;
182 struct capilib_ncci *np;
183
184 list_for_each(l, head) {
185 np = list_entry(l, struct capilib_ncci, list);
186 if (np->applid != applid)
187 continue;
188 if (np->ncci != ncci)
189 continue;
190
191 if (mq_dequeue(np, msgid) == 0) {
192 printk(KERN_ERR "kcapi: msgid %hu ncci 0x%x not on queue\n",
193 msgid, ncci);
194 }
195 return;
196 }
197 printk(KERN_ERR "capilib_data_b3_conf: ncci 0x%x not found\n", ncci);
198}
199
200EXPORT_SYMBOL(capilib_data_b3_conf);
diff --git a/drivers/isdn/capi/capiutil.c b/drivers/isdn/capi/capiutil.c
new file mode 100644
index 000000000000..e7cf6bc286a6
--- /dev/null
+++ b/drivers/isdn/capi/capiutil.c
@@ -0,0 +1,859 @@
1/* $Id: capiutil.c,v 1.13.6.4 2001/09/23 22:24:33 kai Exp $
2 *
3 * CAPI 2.0 convert capi message to capi message struct
4 *
5 * From CAPI 2.0 Development Kit AVM 1995 (msg.c)
6 * Rewritten for Linux 1996 by Carsten Paeth <calle@calle.de>
7 *
8 * This software may be used and distributed according to the terms
9 * of the GNU General Public License, incorporated herein by reference.
10 *
11 */
12
13#include <linux/module.h>
14#include <linux/string.h>
15#include <linux/ctype.h>
16#include <linux/stddef.h>
17#include <linux/kernel.h>
18#include <linux/mm.h>
19#include <linux/init.h>
20#include <linux/config.h>
21#include <linux/isdn/capiutil.h>
22
23/* from CAPI2.0 DDK AVM Berlin GmbH */
24
25#ifndef CONFIG_ISDN_DRV_AVMB1_VERBOSE_REASON
26char *capi_info2str(u16 reason)
27{
28 return "..";
29}
30#else
31char *capi_info2str(u16 reason)
32{
33 switch (reason) {
34
35/*-- informative values (corresponding message was processed) -----*/
36 case 0x0001:
37 return "NCPI not supported by current protocol, NCPI ignored";
38 case 0x0002:
39 return "Flags not supported by current protocol, flags ignored";
40 case 0x0003:
41 return "Alert already sent by another application";
42
43/*-- error information concerning CAPI_REGISTER -----*/
44 case 0x1001:
45 return "Too many applications";
46 case 0x1002:
47 return "Logical block size too small, must be at least 128 Bytes";
48 case 0x1003:
49 return "Buffer exceeds 64 kByte";
50 case 0x1004:
51 return "Message buffer size too small, must be at least 1024 Bytes";
52 case 0x1005:
53 return "Max. number of logical connections not supported";
54 case 0x1006:
55 return "Reserved";
56 case 0x1007:
57 return "The message could not be accepted because of an internal busy condition";
58 case 0x1008:
59 return "OS resource error (no memory ?)";
60 case 0x1009:
61 return "CAPI not installed";
62 case 0x100A:
63 return "Controller does not support external equipment";
64 case 0x100B:
65 return "Controller does only support external equipment";
66
67/*-- error information concerning message exchange functions -----*/
68 case 0x1101:
69 return "Illegal application number";
70 case 0x1102:
71 return "Illegal command or subcommand or message length less than 12 bytes";
72 case 0x1103:
73 return "The message could not be accepted because of a queue full condition !! The error code does not imply that CAPI cannot receive messages directed to another controller, PLCI or NCCI";
74 case 0x1104:
75 return "Queue is empty";
76 case 0x1105:
77 return "Queue overflow, a message was lost !! This indicates a configuration error. The only recovery from this error is to perform a CAPI_RELEASE";
78 case 0x1106:
79 return "Unknown notification parameter";
80 case 0x1107:
81 return "The Message could not be accepted because of an internal busy condition";
82 case 0x1108:
83 return "OS Resource error (no memory ?)";
84 case 0x1109:
85 return "CAPI not installed";
86 case 0x110A:
87 return "Controller does not support external equipment";
88 case 0x110B:
89 return "Controller does only support external equipment";
90
91/*-- error information concerning resource / coding problems -----*/
92 case 0x2001:
93 return "Message not supported in current state";
94 case 0x2002:
95 return "Illegal Controller / PLCI / NCCI";
96 case 0x2003:
97 return "Out of PLCI";
98 case 0x2004:
99 return "Out of NCCI";
100 case 0x2005:
101 return "Out of LISTEN";
102 case 0x2006:
103 return "Out of FAX resources (protocol T.30)";
104 case 0x2007:
105 return "Illegal message parameter coding";
106
107/*-- error information concerning requested services -----*/
108 case 0x3001:
109 return "B1 protocol not supported";
110 case 0x3002:
111 return "B2 protocol not supported";
112 case 0x3003:
113 return "B3 protocol not supported";
114 case 0x3004:
115 return "B1 protocol parameter not supported";
116 case 0x3005:
117 return "B2 protocol parameter not supported";
118 case 0x3006:
119 return "B3 protocol parameter not supported";
120 case 0x3007:
121 return "B protocol combination not supported";
122 case 0x3008:
123 return "NCPI not supported";
124 case 0x3009:
125 return "CIP Value unknown";
126 case 0x300A:
127 return "Flags not supported (reserved bits)";
128 case 0x300B:
129 return "Facility not supported";
130 case 0x300C:
131 return "Data length not supported by current protocol";
132 case 0x300D:
133 return "Reset procedure not supported by current protocol";
134
135/*-- informations about the clearing of a physical connection -----*/
136 case 0x3301:
137 return "Protocol error layer 1 (broken line or B-channel removed by signalling protocol)";
138 case 0x3302:
139 return "Protocol error layer 2";
140 case 0x3303:
141 return "Protocol error layer 3";
142 case 0x3304:
143 return "Another application got that call";
144/*-- T.30 specific reasons -----*/
145 case 0x3311:
146 return "Connecting not successful (remote station is no FAX G3 machine)";
147 case 0x3312:
148 return "Connecting not successful (training error)";
149 case 0x3313:
150 return "Disconnected before transfer (remote station does not support transfer mode, e.g. resolution)";
151 case 0x3314:
152 return "Disconnected during transfer (remote abort)";
153 case 0x3315:
154 return "Disconnected during transfer (remote procedure error, e.g. unsuccessful repetition of T.30 commands)";
155 case 0x3316:
156 return "Disconnected during transfer (local tx data underrun)";
157 case 0x3317:
158 return "Disconnected during transfer (local rx data overflow)";
159 case 0x3318:
160 return "Disconnected during transfer (local abort)";
161 case 0x3319:
162 return "Illegal parameter coding (e.g. SFF coding error)";
163
164/*-- disconnect causes from the network according to ETS 300 102-1/Q.931 -----*/
165 case 0x3481: return "Unallocated (unassigned) number";
166 case 0x3482: return "No route to specified transit network";
167 case 0x3483: return "No route to destination";
168 case 0x3486: return "Channel unacceptable";
169 case 0x3487:
170 return "Call awarded and being delivered in an established channel";
171 case 0x3490: return "Normal call clearing";
172 case 0x3491: return "User busy";
173 case 0x3492: return "No user responding";
174 case 0x3493: return "No answer from user (user alerted)";
175 case 0x3495: return "Call rejected";
176 case 0x3496: return "Number changed";
177 case 0x349A: return "Non-selected user clearing";
178 case 0x349B: return "Destination out of order";
179 case 0x349C: return "Invalid number format";
180 case 0x349D: return "Facility rejected";
181 case 0x349E: return "Response to STATUS ENQUIRY";
182 case 0x349F: return "Normal, unspecified";
183 case 0x34A2: return "No circuit / channel available";
184 case 0x34A6: return "Network out of order";
185 case 0x34A9: return "Temporary failure";
186 case 0x34AA: return "Switching equipment congestion";
187 case 0x34AB: return "Access information discarded";
188 case 0x34AC: return "Requested circuit / channel not available";
189 case 0x34AF: return "Resources unavailable, unspecified";
190 case 0x34B1: return "Quality of service unavailable";
191 case 0x34B2: return "Requested facility not subscribed";
192 case 0x34B9: return "Bearer capability not authorized";
193 case 0x34BA: return "Bearer capability not presently available";
194 case 0x34BF: return "Service or option not available, unspecified";
195 case 0x34C1: return "Bearer capability not implemented";
196 case 0x34C2: return "Channel type not implemented";
197 case 0x34C5: return "Requested facility not implemented";
198 case 0x34C6: return "Only restricted digital information bearer capability is available";
199 case 0x34CF: return "Service or option not implemented, unspecified";
200 case 0x34D1: return "Invalid call reference value";
201 case 0x34D2: return "Identified channel does not exist";
202 case 0x34D3: return "A suspended call exists, but this call identity does not";
203 case 0x34D4: return "Call identity in use";
204 case 0x34D5: return "No call suspended";
205 case 0x34D6: return "Call having the requested call identity has been cleared";
206 case 0x34D8: return "Incompatible destination";
207 case 0x34DB: return "Invalid transit network selection";
208 case 0x34DF: return "Invalid message, unspecified";
209 case 0x34E0: return "Mandatory information element is missing";
210 case 0x34E1: return "Message type non-existent or not implemented";
211 case 0x34E2: return "Message not compatible with call state or message type non-existent or not implemented";
212 case 0x34E3: return "Information element non-existent or not implemented";
213 case 0x34E4: return "Invalid information element contents";
214 case 0x34E5: return "Message not compatible with call state";
215 case 0x34E6: return "Recovery on timer expiry";
216 case 0x34EF: return "Protocol error, unspecified";
217 case 0x34FF: return "Interworking, unspecified";
218
219 default: return "No additional information";
220 }
221}
222#endif
223
224typedef struct {
225 int typ;
226 size_t off;
227} _cdef;
228
229#define _CBYTE 1
230#define _CWORD 2
231#define _CDWORD 3
232#define _CSTRUCT 4
233#define _CMSTRUCT 5
234#define _CEND 6
235
236static _cdef cdef[] =
237{
238 /*00 */
239 {_CEND},
240 /*01 */
241 {_CEND},
242 /*02 */
243 {_CEND},
244 /*03 */
245 {_CDWORD, offsetof(_cmsg, adr.adrController)},
246 /*04 */
247 {_CMSTRUCT, offsetof(_cmsg, AdditionalInfo)},
248 /*05 */
249 {_CSTRUCT, offsetof(_cmsg, B1configuration)},
250 /*06 */
251 {_CWORD, offsetof(_cmsg, B1protocol)},
252 /*07 */
253 {_CSTRUCT, offsetof(_cmsg, B2configuration)},
254 /*08 */
255 {_CWORD, offsetof(_cmsg, B2protocol)},
256 /*09 */
257 {_CSTRUCT, offsetof(_cmsg, B3configuration)},
258 /*0a */
259 {_CWORD, offsetof(_cmsg, B3protocol)},
260 /*0b */
261 {_CSTRUCT, offsetof(_cmsg, BC)},
262 /*0c */
263 {_CSTRUCT, offsetof(_cmsg, BChannelinformation)},
264 /*0d */
265 {_CMSTRUCT, offsetof(_cmsg, BProtocol)},
266 /*0e */
267 {_CSTRUCT, offsetof(_cmsg, CalledPartyNumber)},
268 /*0f */
269 {_CSTRUCT, offsetof(_cmsg, CalledPartySubaddress)},
270 /*10 */
271 {_CSTRUCT, offsetof(_cmsg, CallingPartyNumber)},
272 /*11 */
273 {_CSTRUCT, offsetof(_cmsg, CallingPartySubaddress)},
274 /*12 */
275 {_CDWORD, offsetof(_cmsg, CIPmask)},
276 /*13 */
277 {_CDWORD, offsetof(_cmsg, CIPmask2)},
278 /*14 */
279 {_CWORD, offsetof(_cmsg, CIPValue)},
280 /*15 */
281 {_CDWORD, offsetof(_cmsg, Class)},
282 /*16 */
283 {_CSTRUCT, offsetof(_cmsg, ConnectedNumber)},
284 /*17 */
285 {_CSTRUCT, offsetof(_cmsg, ConnectedSubaddress)},
286 /*18 */
287 {_CDWORD, offsetof(_cmsg, Data)},
288 /*19 */
289 {_CWORD, offsetof(_cmsg, DataHandle)},
290 /*1a */
291 {_CWORD, offsetof(_cmsg, DataLength)},
292 /*1b */
293 {_CSTRUCT, offsetof(_cmsg, FacilityConfirmationParameter)},
294 /*1c */
295 {_CSTRUCT, offsetof(_cmsg, Facilitydataarray)},
296 /*1d */
297 {_CSTRUCT, offsetof(_cmsg, FacilityIndicationParameter)},
298 /*1e */
299 {_CSTRUCT, offsetof(_cmsg, FacilityRequestParameter)},
300 /*1f */
301 {_CWORD, offsetof(_cmsg, FacilitySelector)},
302 /*20 */
303 {_CWORD, offsetof(_cmsg, Flags)},
304 /*21 */
305 {_CDWORD, offsetof(_cmsg, Function)},
306 /*22 */
307 {_CSTRUCT, offsetof(_cmsg, HLC)},
308 /*23 */
309 {_CWORD, offsetof(_cmsg, Info)},
310 /*24 */
311 {_CSTRUCT, offsetof(_cmsg, InfoElement)},
312 /*25 */
313 {_CDWORD, offsetof(_cmsg, InfoMask)},
314 /*26 */
315 {_CWORD, offsetof(_cmsg, InfoNumber)},
316 /*27 */
317 {_CSTRUCT, offsetof(_cmsg, Keypadfacility)},
318 /*28 */
319 {_CSTRUCT, offsetof(_cmsg, LLC)},
320 /*29 */
321 {_CSTRUCT, offsetof(_cmsg, ManuData)},
322 /*2a */
323 {_CDWORD, offsetof(_cmsg, ManuID)},
324 /*2b */
325 {_CSTRUCT, offsetof(_cmsg, NCPI)},
326 /*2c */
327 {_CWORD, offsetof(_cmsg, Reason)},
328 /*2d */
329 {_CWORD, offsetof(_cmsg, Reason_B3)},
330 /*2e */
331 {_CWORD, offsetof(_cmsg, Reject)},
332 /*2f */
333 {_CSTRUCT, offsetof(_cmsg, Useruserdata)}
334};
335
336static unsigned char *cpars[] =
337{
338 /* ALERT_REQ */ [0x01] = "\x03\x04\x0c\x27\x2f\x1c\x01\x01",
339 /* CONNECT_REQ */ [0x02] = "\x03\x14\x0e\x10\x0f\x11\x0d\x06\x08\x0a\x05\x07\x09\x01\x0b\x28\x22\x04\x0c\x27\x2f\x1c\x01\x01",
340 /* DISCONNECT_REQ */ [0x04] = "\x03\x04\x0c\x27\x2f\x1c\x01\x01",
341 /* LISTEN_REQ */ [0x05] = "\x03\x25\x12\x13\x10\x11\x01",
342 /* INFO_REQ */ [0x08] = "\x03\x0e\x04\x0c\x27\x2f\x1c\x01\x01",
343 /* FACILITY_REQ */ [0x09] = "\x03\x1f\x1e\x01",
344 /* SELECT_B_PROTOCOL_REQ */ [0x0a] = "\x03\x0d\x06\x08\x0a\x05\x07\x09\x01\x01",
345 /* CONNECT_B3_REQ */ [0x0b] = "\x03\x2b\x01",
346 /* DISCONNECT_B3_REQ */ [0x0d] = "\x03\x2b\x01",
347 /* DATA_B3_REQ */ [0x0f] = "\x03\x18\x1a\x19\x20\x01",
348 /* RESET_B3_REQ */ [0x10] = "\x03\x2b\x01",
349 /* ALERT_CONF */ [0x13] = "\x03\x23\x01",
350 /* CONNECT_CONF */ [0x14] = "\x03\x23\x01",
351 /* DISCONNECT_CONF */ [0x16] = "\x03\x23\x01",
352 /* LISTEN_CONF */ [0x17] = "\x03\x23\x01",
353 /* MANUFACTURER_REQ */ [0x18] = "\x03\x2a\x15\x21\x29\x01",
354 /* INFO_CONF */ [0x1a] = "\x03\x23\x01",
355 /* FACILITY_CONF */ [0x1b] = "\x03\x23\x1f\x1b\x01",
356 /* SELECT_B_PROTOCOL_CONF */ [0x1c] = "\x03\x23\x01",
357 /* CONNECT_B3_CONF */ [0x1d] = "\x03\x23\x01",
358 /* DISCONNECT_B3_CONF */ [0x1f] = "\x03\x23\x01",
359 /* DATA_B3_CONF */ [0x21] = "\x03\x19\x23\x01",
360 /* RESET_B3_CONF */ [0x22] = "\x03\x23\x01",
361 /* CONNECT_IND */ [0x26] = "\x03\x14\x0e\x10\x0f\x11\x0b\x28\x22\x04\x0c\x27\x2f\x1c\x01\x01",
362 /* CONNECT_ACTIVE_IND */ [0x27] = "\x03\x16\x17\x28\x01",
363 /* DISCONNECT_IND */ [0x28] = "\x03\x2c\x01",
364 /* MANUFACTURER_CONF */ [0x2a] = "\x03\x2a\x15\x21\x29\x01",
365 /* INFO_IND */ [0x2c] = "\x03\x26\x24\x01",
366 /* FACILITY_IND */ [0x2d] = "\x03\x1f\x1d\x01",
367 /* CONNECT_B3_IND */ [0x2f] = "\x03\x2b\x01",
368 /* CONNECT_B3_ACTIVE_IND */ [0x30] = "\x03\x2b\x01",
369 /* DISCONNECT_B3_IND */ [0x31] = "\x03\x2d\x2b\x01",
370 /* DATA_B3_IND */ [0x33] = "\x03\x18\x1a\x19\x20\x01",
371 /* RESET_B3_IND */ [0x34] = "\x03\x2b\x01",
372 /* CONNECT_B3_T90_ACTIVE_IND */ [0x35] = "\x03\x2b\x01",
373 /* CONNECT_RESP */ [0x38] = "\x03\x2e\x0d\x06\x08\x0a\x05\x07\x09\x01\x16\x17\x28\x04\x0c\x27\x2f\x1c\x01\x01",
374 /* CONNECT_ACTIVE_RESP */ [0x39] = "\x03\x01",
375 /* DISCONNECT_RESP */ [0x3a] = "\x03\x01",
376 /* MANUFACTURER_IND */ [0x3c] = "\x03\x2a\x15\x21\x29\x01",
377 /* INFO_RESP */ [0x3e] = "\x03\x01",
378 /* FACILITY_RESP */ [0x3f] = "\x03\x1f\x01",
379 /* CONNECT_B3_RESP */ [0x41] = "\x03\x2e\x2b\x01",
380 /* CONNECT_B3_ACTIVE_RESP */ [0x42] = "\x03\x01",
381 /* DISCONNECT_B3_RESP */ [0x43] = "\x03\x01",
382 /* DATA_B3_RESP */ [0x45] = "\x03\x19\x01",
383 /* RESET_B3_RESP */ [0x46] = "\x03\x01",
384 /* CONNECT_B3_T90_ACTIVE_RESP */ [0x47] = "\x03\x01",
385 /* MANUFACTURER_RESP */ [0x4e] = "\x03\x2a\x15\x21\x29\x01",
386};
387
388/*-------------------------------------------------------*/
389
390#define byteTLcpy(x,y) *(u8 *)(x)=*(u8 *)(y);
391#define wordTLcpy(x,y) *(u16 *)(x)=*(u16 *)(y);
392#define dwordTLcpy(x,y) memcpy(x,y,4);
393#define structTLcpy(x,y,l) memcpy (x,y,l)
394#define structTLcpyovl(x,y,l) memmove (x,y,l)
395
396#define byteTRcpy(x,y) *(u8 *)(y)=*(u8 *)(x);
397#define wordTRcpy(x,y) *(u16 *)(y)=*(u16 *)(x);
398#define dwordTRcpy(x,y) memcpy(y,x,4);
399#define structTRcpy(x,y,l) memcpy (y,x,l)
400#define structTRcpyovl(x,y,l) memmove (y,x,l)
401
402/*-------------------------------------------------------*/
403static unsigned command_2_index(unsigned c, unsigned sc)
404{
405 if (c & 0x80)
406 c = 0x9 + (c & 0x0f);
407 else if (c <= 0x0f);
408 else if (c == 0x41)
409 c = 0x9 + 0x1;
410 else if (c == 0xff)
411 c = 0x00;
412 return (sc & 3) * (0x9 + 0x9) + c;
413}
414
415/*-------------------------------------------------------*/
416#define TYP (cdef[cmsg->par[cmsg->p]].typ)
417#define OFF (((u8 *)cmsg)+cdef[cmsg->par[cmsg->p]].off)
418
419static void jumpcstruct(_cmsg * cmsg)
420{
421 unsigned layer;
422 for (cmsg->p++, layer = 1; layer;) {
423 /* $$$$$ assert (cmsg->p); */
424 cmsg->p++;
425 switch (TYP) {
426 case _CMSTRUCT:
427 layer++;
428 break;
429 case _CEND:
430 layer--;
431 break;
432 }
433 }
434}
435/*-------------------------------------------------------*/
436static void pars_2_message(_cmsg * cmsg)
437{
438
439 for (; TYP != _CEND; cmsg->p++) {
440 switch (TYP) {
441 case _CBYTE:
442 byteTLcpy(cmsg->m + cmsg->l, OFF);
443 cmsg->l++;
444 break;
445 case _CWORD:
446 wordTLcpy(cmsg->m + cmsg->l, OFF);
447 cmsg->l += 2;
448 break;
449 case _CDWORD:
450 dwordTLcpy(cmsg->m + cmsg->l, OFF);
451 cmsg->l += 4;
452 break;
453 case _CSTRUCT:
454 if (*(u8 **) OFF == 0) {
455 *(cmsg->m + cmsg->l) = '\0';
456 cmsg->l++;
457 } else if (**(_cstruct *) OFF != 0xff) {
458 structTLcpy(cmsg->m + cmsg->l, *(_cstruct *) OFF, 1 + **(_cstruct *) OFF);
459 cmsg->l += 1 + **(_cstruct *) OFF;
460 } else {
461 _cstruct s = *(_cstruct *) OFF;
462 structTLcpy(cmsg->m + cmsg->l, s, 3 + *(u16 *) (s + 1));
463 cmsg->l += 3 + *(u16 *) (s + 1);
464 }
465 break;
466 case _CMSTRUCT:
467/*----- Metastruktur 0 -----*/
468 if (*(_cmstruct *) OFF == CAPI_DEFAULT) {
469 *(cmsg->m + cmsg->l) = '\0';
470 cmsg->l++;
471 jumpcstruct(cmsg);
472 }
473/*----- Metastruktur wird composed -----*/
474 else {
475 unsigned _l = cmsg->l;
476 unsigned _ls;
477 cmsg->l++;
478 cmsg->p++;
479 pars_2_message(cmsg);
480 _ls = cmsg->l - _l - 1;
481 if (_ls < 255)
482 (cmsg->m + _l)[0] = (u8) _ls;
483 else {
484 structTLcpyovl(cmsg->m + _l + 3, cmsg->m + _l + 1, _ls);
485 (cmsg->m + _l)[0] = 0xff;
486 wordTLcpy(cmsg->m + _l + 1, &_ls);
487 }
488 }
489 break;
490 }
491 }
492}
493
494/*-------------------------------------------------------*/
495unsigned capi_cmsg2message(_cmsg * cmsg, u8 * msg)
496{
497 cmsg->m = msg;
498 cmsg->l = 8;
499 cmsg->p = 0;
500 cmsg->par = cpars[command_2_index(cmsg->Command, cmsg->Subcommand)];
501
502 pars_2_message(cmsg);
503
504 wordTLcpy(msg + 0, &cmsg->l);
505 byteTLcpy(cmsg->m + 4, &cmsg->Command);
506 byteTLcpy(cmsg->m + 5, &cmsg->Subcommand);
507 wordTLcpy(cmsg->m + 2, &cmsg->ApplId);
508 wordTLcpy(cmsg->m + 6, &cmsg->Messagenumber);
509
510 return 0;
511}
512
513/*-------------------------------------------------------*/
514static void message_2_pars(_cmsg * cmsg)
515{
516 for (; TYP != _CEND; cmsg->p++) {
517
518 switch (TYP) {
519 case _CBYTE:
520 byteTRcpy(cmsg->m + cmsg->l, OFF);
521 cmsg->l++;
522 break;
523 case _CWORD:
524 wordTRcpy(cmsg->m + cmsg->l, OFF);
525 cmsg->l += 2;
526 break;
527 case _CDWORD:
528 dwordTRcpy(cmsg->m + cmsg->l, OFF);
529 cmsg->l += 4;
530 break;
531 case _CSTRUCT:
532 *(u8 **) OFF = cmsg->m + cmsg->l;
533
534 if (cmsg->m[cmsg->l] != 0xff)
535 cmsg->l += 1 + cmsg->m[cmsg->l];
536 else
537 cmsg->l += 3 + *(u16 *) (cmsg->m + cmsg->l + 1);
538 break;
539 case _CMSTRUCT:
540/*----- Metastruktur 0 -----*/
541 if (cmsg->m[cmsg->l] == '\0') {
542 *(_cmstruct *) OFF = CAPI_DEFAULT;
543 cmsg->l++;
544 jumpcstruct(cmsg);
545 } else {
546 unsigned _l = cmsg->l;
547 *(_cmstruct *) OFF = CAPI_COMPOSE;
548 cmsg->l = (cmsg->m + _l)[0] == 255 ? cmsg->l + 3 : cmsg->l + 1;
549 cmsg->p++;
550 message_2_pars(cmsg);
551 }
552 break;
553 }
554 }
555}
556
557/*-------------------------------------------------------*/
558unsigned capi_message2cmsg(_cmsg * cmsg, u8 * msg)
559{
560 memset(cmsg, 0, sizeof(_cmsg));
561 cmsg->m = msg;
562 cmsg->l = 8;
563 cmsg->p = 0;
564 byteTRcpy(cmsg->m + 4, &cmsg->Command);
565 byteTRcpy(cmsg->m + 5, &cmsg->Subcommand);
566 cmsg->par = cpars[command_2_index(cmsg->Command, cmsg->Subcommand)];
567
568 message_2_pars(cmsg);
569
570 wordTRcpy(msg + 0, &cmsg->l);
571 wordTRcpy(cmsg->m + 2, &cmsg->ApplId);
572 wordTRcpy(cmsg->m + 6, &cmsg->Messagenumber);
573
574 return 0;
575}
576
577/*-------------------------------------------------------*/
578unsigned capi_cmsg_header(_cmsg * cmsg, u16 _ApplId,
579 u8 _Command, u8 _Subcommand,
580 u16 _Messagenumber, u32 _Controller)
581{
582 memset(cmsg, 0, sizeof(_cmsg));
583 cmsg->ApplId = _ApplId;
584 cmsg->Command = _Command;
585 cmsg->Subcommand = _Subcommand;
586 cmsg->Messagenumber = _Messagenumber;
587 cmsg->adr.adrController = _Controller;
588 return 0;
589}
590
591/*-------------------------------------------------------*/
592
593static char *mnames[] =
594{
595 [0x01] = "ALERT_REQ",
596 [0x02] = "CONNECT_REQ",
597 [0x04] = "DISCONNECT_REQ",
598 [0x05] = "LISTEN_REQ",
599 [0x08] = "INFO_REQ",
600 [0x09] = "FACILITY_REQ",
601 [0x0a] = "SELECT_B_PROTOCOL_REQ",
602 [0x0b] = "CONNECT_B3_REQ",
603 [0x0d] = "DISCONNECT_B3_REQ",
604 [0x0f] = "DATA_B3_REQ",
605 [0x10] = "RESET_B3_REQ",
606 [0x13] = "ALERT_CONF",
607 [0x14] = "CONNECT_CONF",
608 [0x16] = "DISCONNECT_CONF",
609 [0x17] = "LISTEN_CONF",
610 [0x18] = "MANUFACTURER_REQ",
611 [0x1a] = "INFO_CONF",
612 [0x1b] = "FACILITY_CONF",
613 [0x1c] = "SELECT_B_PROTOCOL_CONF",
614 [0x1d] = "CONNECT_B3_CONF",
615 [0x1f] = "DISCONNECT_B3_CONF",
616 [0x21] = "DATA_B3_CONF",
617 [0x22] = "RESET_B3_CONF",
618 [0x26] = "CONNECT_IND",
619 [0x27] = "CONNECT_ACTIVE_IND",
620 [0x28] = "DISCONNECT_IND",
621 [0x2a] = "MANUFACTURER_CONF",
622 [0x2c] = "INFO_IND",
623 [0x2d] = "FACILITY_IND",
624 [0x2f] = "CONNECT_B3_IND",
625 [0x30] = "CONNECT_B3_ACTIVE_IND",
626 [0x31] = "DISCONNECT_B3_IND",
627 [0x33] = "DATA_B3_IND",
628 [0x34] = "RESET_B3_IND",
629 [0x35] = "CONNECT_B3_T90_ACTIVE_IND",
630 [0x38] = "CONNECT_RESP",
631 [0x39] = "CONNECT_ACTIVE_RESP",
632 [0x3a] = "DISCONNECT_RESP",
633 [0x3c] = "MANUFACTURER_IND",
634 [0x3e] = "INFO_RESP",
635 [0x3f] = "FACILITY_RESP",
636 [0x41] = "CONNECT_B3_RESP",
637 [0x42] = "CONNECT_B3_ACTIVE_RESP",
638 [0x43] = "DISCONNECT_B3_RESP",
639 [0x45] = "DATA_B3_RESP",
640 [0x46] = "RESET_B3_RESP",
641 [0x47] = "CONNECT_B3_T90_ACTIVE_RESP",
642 [0x4e] = "MANUFACTURER_RESP"
643};
644
645char *capi_cmd2str(u8 cmd, u8 subcmd)
646{
647 return mnames[command_2_index(cmd, subcmd)];
648}
649
650
651/*-------------------------------------------------------*/
652/*-------------------------------------------------------*/
653
654static char *pnames[] =
655{
656 /*00 */ NULL,
657 /*01 */ NULL,
658 /*02 */ NULL,
659 /*03 */ "Controller/PLCI/NCCI",
660 /*04 */ "AdditionalInfo",
661 /*05 */ "B1configuration",
662 /*06 */ "B1protocol",
663 /*07 */ "B2configuration",
664 /*08 */ "B2protocol",
665 /*09 */ "B3configuration",
666 /*0a */ "B3protocol",
667 /*0b */ "BC",
668 /*0c */ "BChannelinformation",
669 /*0d */ "BProtocol",
670 /*0e */ "CalledPartyNumber",
671 /*0f */ "CalledPartySubaddress",
672 /*10 */ "CallingPartyNumber",
673 /*11 */ "CallingPartySubaddress",
674 /*12 */ "CIPmask",
675 /*13 */ "CIPmask2",
676 /*14 */ "CIPValue",
677 /*15 */ "Class",
678 /*16 */ "ConnectedNumber",
679 /*17 */ "ConnectedSubaddress",
680 /*18 */ "Data32",
681 /*19 */ "DataHandle",
682 /*1a */ "DataLength",
683 /*1b */ "FacilityConfirmationParameter",
684 /*1c */ "Facilitydataarray",
685 /*1d */ "FacilityIndicationParameter",
686 /*1e */ "FacilityRequestParameter",
687 /*1f */ "FacilitySelector",
688 /*20 */ "Flags",
689 /*21 */ "Function",
690 /*22 */ "HLC",
691 /*23 */ "Info",
692 /*24 */ "InfoElement",
693 /*25 */ "InfoMask",
694 /*26 */ "InfoNumber",
695 /*27 */ "Keypadfacility",
696 /*28 */ "LLC",
697 /*29 */ "ManuData",
698 /*2a */ "ManuID",
699 /*2b */ "NCPI",
700 /*2c */ "Reason",
701 /*2d */ "Reason_B3",
702 /*2e */ "Reject",
703 /*2f */ "Useruserdata"
704};
705
706
707static char buf[8192];
708static char *p = NULL;
709
710#include <stdarg.h>
711
712/*-------------------------------------------------------*/
713static void bufprint(char *fmt,...)
714{
715 va_list f;
716 va_start(f, fmt);
717 vsprintf(p, fmt, f);
718 va_end(f);
719 p += strlen(p);
720}
721
722static void printstructlen(u8 * m, unsigned len)
723{
724 unsigned hex = 0;
725 for (; len; len--, m++)
726 if (isalnum(*m) || *m == ' ') {
727 if (hex)
728 bufprint(">");
729 bufprint("%c", *m);
730 hex = 0;
731 } else {
732 if (!hex)
733 bufprint("<%02x", *m);
734 else
735 bufprint(" %02x", *m);
736 hex = 1;
737 }
738 if (hex)
739 bufprint(">");
740}
741
742static void printstruct(u8 * m)
743{
744 unsigned len;
745 if (m[0] != 0xff) {
746 len = m[0];
747 m += 1;
748 } else {
749 len = ((u16 *) (m + 1))[0];
750 m += 3;
751 }
752 printstructlen(m, len);
753}
754
755/*-------------------------------------------------------*/
756#define NAME (pnames[cmsg->par[cmsg->p]])
757
758static void protocol_message_2_pars(_cmsg * cmsg, int level)
759{
760 for (; TYP != _CEND; cmsg->p++) {
761 int slen = 29 + 3 - level;
762 int i;
763
764 bufprint(" ");
765 for (i = 0; i < level - 1; i++)
766 bufprint(" ");
767
768 switch (TYP) {
769 case _CBYTE:
770 bufprint("%-*s = 0x%x\n", slen, NAME, *(u8 *) (cmsg->m + cmsg->l));
771 cmsg->l++;
772 break;
773 case _CWORD:
774 bufprint("%-*s = 0x%x\n", slen, NAME, *(u16 *) (cmsg->m + cmsg->l));
775 cmsg->l += 2;
776 break;
777 case _CDWORD:
778 bufprint("%-*s = 0x%lx\n", slen, NAME, *(u32 *) (cmsg->m + cmsg->l));
779 cmsg->l += 4;
780 break;
781 case _CSTRUCT:
782 bufprint("%-*s = ", slen, NAME);
783 if (cmsg->m[cmsg->l] == '\0')
784 bufprint("default");
785 else
786 printstruct(cmsg->m + cmsg->l);
787 bufprint("\n");
788 if (cmsg->m[cmsg->l] != 0xff)
789 cmsg->l += 1 + cmsg->m[cmsg->l];
790 else
791 cmsg->l += 3 + *(u16 *) (cmsg->m + cmsg->l + 1);
792
793 break;
794
795 case _CMSTRUCT:
796/*----- Metastruktur 0 -----*/
797 if (cmsg->m[cmsg->l] == '\0') {
798 bufprint("%-*s = default\n", slen, NAME);
799 cmsg->l++;
800 jumpcstruct(cmsg);
801 } else {
802 char *name = NAME;
803 unsigned _l = cmsg->l;
804 bufprint("%-*s\n", slen, name);
805 cmsg->l = (cmsg->m + _l)[0] == 255 ? cmsg->l + 3 : cmsg->l + 1;
806 cmsg->p++;
807 protocol_message_2_pars(cmsg, level + 1);
808 }
809 break;
810 }
811 }
812}
813/*-------------------------------------------------------*/
814char *capi_message2str(u8 * msg)
815{
816
817 _cmsg cmsg;
818 p = buf;
819 p[0] = 0;
820
821 cmsg.m = msg;
822 cmsg.l = 8;
823 cmsg.p = 0;
824 byteTRcpy(cmsg.m + 4, &cmsg.Command);
825 byteTRcpy(cmsg.m + 5, &cmsg.Subcommand);
826 cmsg.par = cpars[command_2_index(cmsg.Command, cmsg.Subcommand)];
827
828 bufprint("%-26s ID=%03d #0x%04x LEN=%04d\n",
829 mnames[command_2_index(cmsg.Command, cmsg.Subcommand)],
830 ((unsigned short *) msg)[1],
831 ((unsigned short *) msg)[3],
832 ((unsigned short *) msg)[0]);
833
834 protocol_message_2_pars(&cmsg, 1);
835 return buf;
836}
837
838char *capi_cmsg2str(_cmsg * cmsg)
839{
840 p = buf;
841 p[0] = 0;
842 cmsg->l = 8;
843 cmsg->p = 0;
844 bufprint("%s ID=%03d #0x%04x LEN=%04d\n",
845 mnames[command_2_index(cmsg->Command, cmsg->Subcommand)],
846 ((u16 *) cmsg->m)[1],
847 ((u16 *) cmsg->m)[3],
848 ((u16 *) cmsg->m)[0]);
849 protocol_message_2_pars(cmsg, 1);
850 return buf;
851}
852
853EXPORT_SYMBOL(capi_cmsg2message);
854EXPORT_SYMBOL(capi_message2cmsg);
855EXPORT_SYMBOL(capi_cmsg_header);
856EXPORT_SYMBOL(capi_cmd2str);
857EXPORT_SYMBOL(capi_cmsg2str);
858EXPORT_SYMBOL(capi_message2str);
859EXPORT_SYMBOL(capi_info2str);
diff --git a/drivers/isdn/capi/kcapi.c b/drivers/isdn/capi/kcapi.c
new file mode 100644
index 000000000000..feec40cf5900
--- /dev/null
+++ b/drivers/isdn/capi/kcapi.c
@@ -0,0 +1,991 @@
1/* $Id: kcapi.c,v 1.1.2.8 2004/03/26 19:57:20 armin Exp $
2 *
3 * Kernel CAPI 2.0 Module
4 *
5 * Copyright 1999 by Carsten Paeth <calle@calle.de>
6 * Copyright 2002 by Kai Germaschewski <kai@germaschewski.name>
7 *
8 * This software may be used and distributed according to the terms
9 * of the GNU General Public License, incorporated herein by reference.
10 *
11 */
12
13#define CONFIG_AVMB1_COMPAT
14
15#include "kcapi.h"
16#include <linux/module.h>
17#include <linux/mm.h>
18#include <linux/interrupt.h>
19#include <linux/ioport.h>
20#include <linux/proc_fs.h>
21#include <linux/seq_file.h>
22#include <linux/skbuff.h>
23#include <linux/workqueue.h>
24#include <linux/capi.h>
25#include <linux/kernelcapi.h>
26#include <linux/init.h>
27#include <linux/moduleparam.h>
28#include <linux/delay.h>
29#include <asm/uaccess.h>
30#include <linux/isdn/capicmd.h>
31#include <linux/isdn/capiutil.h>
32#ifdef CONFIG_AVMB1_COMPAT
33#include <linux/b1lli.h>
34#endif
35
36static char *revision = "$Revision: 1.1.2.8 $";
37
38/* ------------------------------------------------------------- */
39
40static int showcapimsgs = 0;
41
42MODULE_DESCRIPTION("CAPI4Linux: kernel CAPI layer");
43MODULE_AUTHOR("Carsten Paeth");
44MODULE_LICENSE("GPL");
45module_param(showcapimsgs, uint, 0);
46
47/* ------------------------------------------------------------- */
48
49struct capi_notifier {
50 struct work_struct work;
51 unsigned int cmd;
52 u32 controller;
53 u16 applid;
54 u32 ncci;
55};
56
57/* ------------------------------------------------------------- */
58
59static struct capi_version driver_version = {2, 0, 1, 1<<4};
60static char driver_serial[CAPI_SERIAL_LEN] = "0004711";
61static char capi_manufakturer[64] = "AVM Berlin";
62
63#define NCCI2CTRL(ncci) (((ncci) >> 24) & 0x7f)
64
65LIST_HEAD(capi_drivers);
66DEFINE_RWLOCK(capi_drivers_list_lock);
67
68static DEFINE_RWLOCK(application_lock);
69static DECLARE_MUTEX(controller_sem);
70
71struct capi20_appl *capi_applications[CAPI_MAXAPPL];
72struct capi_ctr *capi_cards[CAPI_MAXCONTR];
73
74static int ncards;
75
76/* -------- controller ref counting -------------------------------------- */
77
78static inline struct capi_ctr *
79capi_ctr_get(struct capi_ctr *card)
80{
81 if (!try_module_get(card->owner))
82 return NULL;
83 return card;
84}
85
86static inline void
87capi_ctr_put(struct capi_ctr *card)
88{
89 module_put(card->owner);
90}
91
92/* ------------------------------------------------------------- */
93
94static inline struct capi_ctr *get_capi_ctr_by_nr(u16 contr)
95{
96 if (contr - 1 >= CAPI_MAXCONTR)
97 return NULL;
98
99 return capi_cards[contr - 1];
100}
101
102static inline struct capi20_appl *get_capi_appl_by_nr(u16 applid)
103{
104 if (applid - 1 >= CAPI_MAXAPPL)
105 return NULL;
106
107 return capi_applications[applid - 1];
108}
109
110/* -------- util functions ------------------------------------ */
111
112static inline int capi_cmd_valid(u8 cmd)
113{
114 switch (cmd) {
115 case CAPI_ALERT:
116 case CAPI_CONNECT:
117 case CAPI_CONNECT_ACTIVE:
118 case CAPI_CONNECT_B3_ACTIVE:
119 case CAPI_CONNECT_B3:
120 case CAPI_CONNECT_B3_T90_ACTIVE:
121 case CAPI_DATA_B3:
122 case CAPI_DISCONNECT_B3:
123 case CAPI_DISCONNECT:
124 case CAPI_FACILITY:
125 case CAPI_INFO:
126 case CAPI_LISTEN:
127 case CAPI_MANUFACTURER:
128 case CAPI_RESET_B3:
129 case CAPI_SELECT_B_PROTOCOL:
130 return 1;
131 }
132 return 0;
133}
134
135static inline int capi_subcmd_valid(u8 subcmd)
136{
137 switch (subcmd) {
138 case CAPI_REQ:
139 case CAPI_CONF:
140 case CAPI_IND:
141 case CAPI_RESP:
142 return 1;
143 }
144 return 0;
145}
146
147/* ------------------------------------------------------------ */
148
149static void register_appl(struct capi_ctr *card, u16 applid, capi_register_params *rparam)
150{
151 card = capi_ctr_get(card);
152
153 if (card)
154 card->register_appl(card, applid, rparam);
155 else
156 printk(KERN_WARNING "%s: cannot get card resources\n", __FUNCTION__);
157}
158
159
160static void release_appl(struct capi_ctr *card, u16 applid)
161{
162 DBG("applid %#x", applid);
163
164 card->release_appl(card, applid);
165 capi_ctr_put(card);
166}
167
168/* -------- KCI_CONTRUP --------------------------------------- */
169
170static void notify_up(u32 contr)
171{
172 struct capi_ctr *card = get_capi_ctr_by_nr(contr);
173 struct capi20_appl *ap;
174 u16 applid;
175
176 if (showcapimsgs & 1) {
177 printk(KERN_DEBUG "kcapi: notify up contr %d\n", contr);
178 }
179 if (!card) {
180 printk(KERN_WARNING "%s: invalid contr %d\n", __FUNCTION__, contr);
181 return;
182 }
183 for (applid = 1; applid <= CAPI_MAXAPPL; applid++) {
184 ap = get_capi_appl_by_nr(applid);
185 if (!ap || ap->release_in_progress) continue;
186 register_appl(card, applid, &ap->rparam);
187 if (ap->callback && !ap->release_in_progress)
188 ap->callback(KCI_CONTRUP, contr, &card->profile);
189 }
190}
191
192/* -------- KCI_CONTRDOWN ------------------------------------- */
193
194static void notify_down(u32 contr)
195{
196 struct capi20_appl *ap;
197 u16 applid;
198
199 if (showcapimsgs & 1) {
200 printk(KERN_DEBUG "kcapi: notify down contr %d\n", contr);
201 }
202
203 for (applid = 1; applid <= CAPI_MAXAPPL; applid++) {
204 ap = get_capi_appl_by_nr(applid);
205 if (ap && ap->callback && !ap->release_in_progress)
206 ap->callback(KCI_CONTRDOWN, contr, NULL);
207 }
208}
209
210static void notify_handler(void *data)
211{
212 struct capi_notifier *np = data;
213
214 switch (np->cmd) {
215 case KCI_CONTRUP:
216 notify_up(np->controller);
217 break;
218 case KCI_CONTRDOWN:
219 notify_down(np->controller);
220 break;
221 }
222
223 kfree(np);
224}
225
226/*
227 * The notifier will result in adding/deleteing of devices. Devices can
228 * only removed in user process, not in bh.
229 */
230static int notify_push(unsigned int cmd, u32 controller, u16 applid, u32 ncci)
231{
232 struct capi_notifier *np = kmalloc(sizeof(*np), GFP_ATOMIC);
233
234 if (!np)
235 return -ENOMEM;
236
237 INIT_WORK(&np->work, notify_handler, np);
238 np->cmd = cmd;
239 np->controller = controller;
240 np->applid = applid;
241 np->ncci = ncci;
242
243 schedule_work(&np->work);
244 return 0;
245}
246
247
248/* -------- Receiver ------------------------------------------ */
249
250static void recv_handler(void *_ap)
251{
252 struct sk_buff *skb;
253 struct capi20_appl *ap = (struct capi20_appl *) _ap;
254
255 if ((!ap) || (ap->release_in_progress))
256 return;
257
258 down(&ap->recv_sem);
259 while ((skb = skb_dequeue(&ap->recv_queue))) {
260 if (CAPIMSG_CMD(skb->data) == CAPI_DATA_B3_IND)
261 ap->nrecvdatapkt++;
262 else
263 ap->nrecvctlpkt++;
264
265 ap->recv_message(ap, skb);
266 }
267 up(&ap->recv_sem);
268}
269
270void capi_ctr_handle_message(struct capi_ctr * card, u16 appl, struct sk_buff *skb)
271{
272 struct capi20_appl *ap;
273 int showctl = 0;
274 u8 cmd, subcmd;
275 unsigned long flags;
276
277 if (card->cardstate != CARD_RUNNING) {
278 printk(KERN_INFO "kcapi: controller %d not active, got: %s",
279 card->cnr, capi_message2str(skb->data));
280 goto error;
281 }
282
283 cmd = CAPIMSG_COMMAND(skb->data);
284 subcmd = CAPIMSG_SUBCOMMAND(skb->data);
285 if (cmd == CAPI_DATA_B3 && subcmd == CAPI_IND) {
286 card->nrecvdatapkt++;
287 if (card->traceflag > 2) showctl |= 2;
288 } else {
289 card->nrecvctlpkt++;
290 if (card->traceflag) showctl |= 2;
291 }
292 showctl |= (card->traceflag & 1);
293 if (showctl & 2) {
294 if (showctl & 1) {
295 printk(KERN_DEBUG "kcapi: got [0x%lx] id#%d %s len=%u\n",
296 (unsigned long) card->cnr,
297 CAPIMSG_APPID(skb->data),
298 capi_cmd2str(cmd, subcmd),
299 CAPIMSG_LEN(skb->data));
300 } else {
301 printk(KERN_DEBUG "kcapi: got [0x%lx] %s\n",
302 (unsigned long) card->cnr,
303 capi_message2str(skb->data));
304 }
305
306 }
307
308 read_lock_irqsave(&application_lock, flags);
309 ap = get_capi_appl_by_nr(CAPIMSG_APPID(skb->data));
310 if ((!ap) || (ap->release_in_progress)) {
311 read_unlock_irqrestore(&application_lock, flags);
312 printk(KERN_ERR "kcapi: handle_message: applid %d state released (%s)\n",
313 CAPIMSG_APPID(skb->data), capi_message2str(skb->data));
314 goto error;
315 }
316 skb_queue_tail(&ap->recv_queue, skb);
317 schedule_work(&ap->recv_work);
318 read_unlock_irqrestore(&application_lock, flags);
319
320 return;
321
322error:
323 kfree_skb(skb);
324}
325
326EXPORT_SYMBOL(capi_ctr_handle_message);
327
328void capi_ctr_ready(struct capi_ctr * card)
329{
330 card->cardstate = CARD_RUNNING;
331
332 printk(KERN_NOTICE "kcapi: card %d \"%s\" ready.\n",
333 card->cnr, card->name);
334
335 notify_push(KCI_CONTRUP, card->cnr, 0, 0);
336}
337
338EXPORT_SYMBOL(capi_ctr_ready);
339
340void capi_ctr_reseted(struct capi_ctr * card)
341{
342 u16 appl;
343
344 DBG("");
345
346 if (card->cardstate == CARD_DETECTED)
347 return;
348
349 card->cardstate = CARD_DETECTED;
350
351 memset(card->manu, 0, sizeof(card->manu));
352 memset(&card->version, 0, sizeof(card->version));
353 memset(&card->profile, 0, sizeof(card->profile));
354 memset(card->serial, 0, sizeof(card->serial));
355
356 for (appl = 1; appl <= CAPI_MAXAPPL; appl++) {
357 struct capi20_appl *ap = get_capi_appl_by_nr(appl);
358 if (!ap || ap->release_in_progress)
359 continue;
360
361 capi_ctr_put(card);
362 }
363
364 printk(KERN_NOTICE "kcapi: card %d down.\n", card->cnr);
365
366 notify_push(KCI_CONTRDOWN, card->cnr, 0, 0);
367}
368
369EXPORT_SYMBOL(capi_ctr_reseted);
370
371void capi_ctr_suspend_output(struct capi_ctr *card)
372{
373 if (!card->blocked) {
374 printk(KERN_DEBUG "kcapi: card %d suspend\n", card->cnr);
375 card->blocked = 1;
376 }
377}
378
379EXPORT_SYMBOL(capi_ctr_suspend_output);
380
381void capi_ctr_resume_output(struct capi_ctr *card)
382{
383 if (card->blocked) {
384 printk(KERN_DEBUG "kcapi: card %d resume\n", card->cnr);
385 card->blocked = 0;
386 }
387}
388
389EXPORT_SYMBOL(capi_ctr_resume_output);
390
391/* ------------------------------------------------------------- */
392
393int
394attach_capi_ctr(struct capi_ctr *card)
395{
396 int i;
397
398 down(&controller_sem);
399
400 for (i = 0; i < CAPI_MAXCONTR; i++) {
401 if (capi_cards[i] == NULL)
402 break;
403 }
404 if (i == CAPI_MAXCONTR) {
405 up(&controller_sem);
406 printk(KERN_ERR "kcapi: out of controller slots\n");
407 return -EBUSY;
408 }
409 capi_cards[i] = card;
410
411 up(&controller_sem);
412
413 card->nrecvctlpkt = 0;
414 card->nrecvdatapkt = 0;
415 card->nsentctlpkt = 0;
416 card->nsentdatapkt = 0;
417 card->cnr = i + 1;
418 card->cardstate = CARD_DETECTED;
419 card->blocked = 0;
420 card->traceflag = showcapimsgs;
421
422 sprintf(card->procfn, "capi/controllers/%d", card->cnr);
423 card->procent = create_proc_entry(card->procfn, 0, NULL);
424 if (card->procent) {
425 card->procent->read_proc =
426 (int (*)(char *,char **,off_t,int,int *,void *))
427 card->ctr_read_proc;
428 card->procent->data = card;
429 }
430
431 ncards++;
432 printk(KERN_NOTICE "kcapi: Controller %d: %s attached\n",
433 card->cnr, card->name);
434 return 0;
435}
436
437EXPORT_SYMBOL(attach_capi_ctr);
438
439int detach_capi_ctr(struct capi_ctr *card)
440{
441 if (card->cardstate != CARD_DETECTED)
442 capi_ctr_reseted(card);
443
444 ncards--;
445
446 if (card->procent) {
447 remove_proc_entry(card->procfn, NULL);
448 card->procent = NULL;
449 }
450 capi_cards[card->cnr - 1] = NULL;
451 printk(KERN_NOTICE "kcapi: Controller %d: %s unregistered\n",
452 card->cnr, card->name);
453
454 return 0;
455}
456
457EXPORT_SYMBOL(detach_capi_ctr);
458
459void register_capi_driver(struct capi_driver *driver)
460{
461 unsigned long flags;
462
463 write_lock_irqsave(&capi_drivers_list_lock, flags);
464 list_add_tail(&driver->list, &capi_drivers);
465 write_unlock_irqrestore(&capi_drivers_list_lock, flags);
466}
467
468EXPORT_SYMBOL(register_capi_driver);
469
470void unregister_capi_driver(struct capi_driver *driver)
471{
472 unsigned long flags;
473
474 write_lock_irqsave(&capi_drivers_list_lock, flags);
475 list_del(&driver->list);
476 write_unlock_irqrestore(&capi_drivers_list_lock, flags);
477}
478
479EXPORT_SYMBOL(unregister_capi_driver);
480
481/* ------------------------------------------------------------- */
482/* -------- CAPI2.0 Interface ---------------------------------- */
483/* ------------------------------------------------------------- */
484
485u16 capi20_isinstalled(void)
486{
487 int i;
488 for (i = 0; i < CAPI_MAXCONTR; i++) {
489 if (capi_cards[i] && capi_cards[i]->cardstate == CARD_RUNNING)
490 return CAPI_NOERROR;
491 }
492 return CAPI_REGNOTINSTALLED;
493}
494
495EXPORT_SYMBOL(capi20_isinstalled);
496
497u16 capi20_register(struct capi20_appl *ap)
498{
499 int i;
500 u16 applid;
501 unsigned long flags;
502
503 DBG("");
504
505 if (ap->rparam.datablklen < 128)
506 return CAPI_LOGBLKSIZETOSMALL;
507
508 write_lock_irqsave(&application_lock, flags);
509
510 for (applid = 1; applid <= CAPI_MAXAPPL; applid++) {
511 if (capi_applications[applid - 1] == NULL)
512 break;
513 }
514 if (applid > CAPI_MAXAPPL) {
515 write_unlock_irqrestore(&application_lock, flags);
516 return CAPI_TOOMANYAPPLS;
517 }
518
519 ap->applid = applid;
520 capi_applications[applid - 1] = ap;
521
522 ap->nrecvctlpkt = 0;
523 ap->nrecvdatapkt = 0;
524 ap->nsentctlpkt = 0;
525 ap->nsentdatapkt = 0;
526 ap->callback = NULL;
527 init_MUTEX(&ap->recv_sem);
528 skb_queue_head_init(&ap->recv_queue);
529 INIT_WORK(&ap->recv_work, recv_handler, (void *)ap);
530 ap->release_in_progress = 0;
531
532 write_unlock_irqrestore(&application_lock, flags);
533
534 down(&controller_sem);
535 for (i = 0; i < CAPI_MAXCONTR; i++) {
536 if (!capi_cards[i] || capi_cards[i]->cardstate != CARD_RUNNING)
537 continue;
538 register_appl(capi_cards[i], applid, &ap->rparam);
539 }
540 up(&controller_sem);
541
542 if (showcapimsgs & 1) {
543 printk(KERN_DEBUG "kcapi: appl %d up\n", applid);
544 }
545
546 return CAPI_NOERROR;
547}
548
549EXPORT_SYMBOL(capi20_register);
550
551u16 capi20_release(struct capi20_appl *ap)
552{
553 int i;
554 unsigned long flags;
555
556 DBG("applid %#x", ap->applid);
557
558 write_lock_irqsave(&application_lock, flags);
559 ap->release_in_progress = 1;
560 capi_applications[ap->applid - 1] = NULL;
561 write_unlock_irqrestore(&application_lock, flags);
562
563 down(&controller_sem);
564 for (i = 0; i < CAPI_MAXCONTR; i++) {
565 if (!capi_cards[i] || capi_cards[i]->cardstate != CARD_RUNNING)
566 continue;
567 release_appl(capi_cards[i], ap->applid);
568 }
569 up(&controller_sem);
570
571 flush_scheduled_work();
572 skb_queue_purge(&ap->recv_queue);
573
574 if (showcapimsgs & 1) {
575 printk(KERN_DEBUG "kcapi: appl %d down\n", ap->applid);
576 }
577
578 return CAPI_NOERROR;
579}
580
581EXPORT_SYMBOL(capi20_release);
582
583u16 capi20_put_message(struct capi20_appl *ap, struct sk_buff *skb)
584{
585 struct capi_ctr *card;
586 int showctl = 0;
587 u8 cmd, subcmd;
588
589 DBG("applid %#x", ap->applid);
590
591 if (ncards == 0)
592 return CAPI_REGNOTINSTALLED;
593 if ((ap->applid == 0) || ap->release_in_progress)
594 return CAPI_ILLAPPNR;
595 if (skb->len < 12
596 || !capi_cmd_valid(CAPIMSG_COMMAND(skb->data))
597 || !capi_subcmd_valid(CAPIMSG_SUBCOMMAND(skb->data)))
598 return CAPI_ILLCMDORSUBCMDORMSGTOSMALL;
599 card = get_capi_ctr_by_nr(CAPIMSG_CONTROLLER(skb->data));
600 if (!card || card->cardstate != CARD_RUNNING) {
601 card = get_capi_ctr_by_nr(1); // XXX why?
602 if (!card || card->cardstate != CARD_RUNNING)
603 return CAPI_REGNOTINSTALLED;
604 }
605 if (card->blocked)
606 return CAPI_SENDQUEUEFULL;
607
608 cmd = CAPIMSG_COMMAND(skb->data);
609 subcmd = CAPIMSG_SUBCOMMAND(skb->data);
610
611 if (cmd == CAPI_DATA_B3 && subcmd== CAPI_REQ) {
612 card->nsentdatapkt++;
613 ap->nsentdatapkt++;
614 if (card->traceflag > 2) showctl |= 2;
615 } else {
616 card->nsentctlpkt++;
617 ap->nsentctlpkt++;
618 if (card->traceflag) showctl |= 2;
619 }
620 showctl |= (card->traceflag & 1);
621 if (showctl & 2) {
622 if (showctl & 1) {
623 printk(KERN_DEBUG "kcapi: put [%#x] id#%d %s len=%u\n",
624 CAPIMSG_CONTROLLER(skb->data),
625 CAPIMSG_APPID(skb->data),
626 capi_cmd2str(cmd, subcmd),
627 CAPIMSG_LEN(skb->data));
628 } else {
629 printk(KERN_DEBUG "kcapi: put [%#x] %s\n",
630 CAPIMSG_CONTROLLER(skb->data),
631 capi_message2str(skb->data));
632 }
633
634 }
635 return card->send_message(card, skb);
636}
637
638EXPORT_SYMBOL(capi20_put_message);
639
640u16 capi20_get_manufacturer(u32 contr, u8 *buf)
641{
642 struct capi_ctr *card;
643
644 if (contr == 0) {
645 strlcpy(buf, capi_manufakturer, CAPI_MANUFACTURER_LEN);
646 return CAPI_NOERROR;
647 }
648 card = get_capi_ctr_by_nr(contr);
649 if (!card || card->cardstate != CARD_RUNNING)
650 return CAPI_REGNOTINSTALLED;
651 strlcpy(buf, card->manu, CAPI_MANUFACTURER_LEN);
652 return CAPI_NOERROR;
653}
654
655EXPORT_SYMBOL(capi20_get_manufacturer);
656
657u16 capi20_get_version(u32 contr, struct capi_version *verp)
658{
659 struct capi_ctr *card;
660
661 if (contr == 0) {
662 *verp = driver_version;
663 return CAPI_NOERROR;
664 }
665 card = get_capi_ctr_by_nr(contr);
666 if (!card || card->cardstate != CARD_RUNNING)
667 return CAPI_REGNOTINSTALLED;
668
669 memcpy((void *) verp, &card->version, sizeof(capi_version));
670 return CAPI_NOERROR;
671}
672
673EXPORT_SYMBOL(capi20_get_version);
674
675u16 capi20_get_serial(u32 contr, u8 *serial)
676{
677 struct capi_ctr *card;
678
679 if (contr == 0) {
680 strlcpy(serial, driver_serial, CAPI_SERIAL_LEN);
681 return CAPI_NOERROR;
682 }
683 card = get_capi_ctr_by_nr(contr);
684 if (!card || card->cardstate != CARD_RUNNING)
685 return CAPI_REGNOTINSTALLED;
686
687 strlcpy((void *) serial, card->serial, CAPI_SERIAL_LEN);
688 return CAPI_NOERROR;
689}
690
691EXPORT_SYMBOL(capi20_get_serial);
692
693u16 capi20_get_profile(u32 contr, struct capi_profile *profp)
694{
695 struct capi_ctr *card;
696
697 if (contr == 0) {
698 profp->ncontroller = ncards;
699 return CAPI_NOERROR;
700 }
701 card = get_capi_ctr_by_nr(contr);
702 if (!card || card->cardstate != CARD_RUNNING)
703 return CAPI_REGNOTINSTALLED;
704
705 memcpy((void *) profp, &card->profile,
706 sizeof(struct capi_profile));
707 return CAPI_NOERROR;
708}
709
710EXPORT_SYMBOL(capi20_get_profile);
711
712#ifdef CONFIG_AVMB1_COMPAT
713static int old_capi_manufacturer(unsigned int cmd, void __user *data)
714{
715 avmb1_loadandconfigdef ldef;
716 avmb1_extcarddef cdef;
717 avmb1_resetdef rdef;
718 capicardparams cparams;
719 struct capi_ctr *card;
720 struct capi_driver *driver = NULL;
721 capiloaddata ldata;
722 struct list_head *l;
723 unsigned long flags;
724 int retval;
725
726 switch (cmd) {
727 case AVMB1_ADDCARD:
728 case AVMB1_ADDCARD_WITH_TYPE:
729 if (cmd == AVMB1_ADDCARD) {
730 if ((retval = copy_from_user(&cdef, data,
731 sizeof(avmb1_carddef))))
732 return retval;
733 cdef.cardtype = AVM_CARDTYPE_B1;
734 } else {
735 if ((retval = copy_from_user(&cdef, data,
736 sizeof(avmb1_extcarddef))))
737 return retval;
738 }
739 cparams.port = cdef.port;
740 cparams.irq = cdef.irq;
741 cparams.cardnr = cdef.cardnr;
742
743 read_lock_irqsave(&capi_drivers_list_lock, flags);
744 switch (cdef.cardtype) {
745 case AVM_CARDTYPE_B1:
746 list_for_each(l, &capi_drivers) {
747 driver = list_entry(l, struct capi_driver, list);
748 if (strcmp(driver->name, "b1isa") == 0)
749 break;
750 }
751 break;
752 case AVM_CARDTYPE_T1:
753 list_for_each(l, &capi_drivers) {
754 driver = list_entry(l, struct capi_driver, list);
755 if (strcmp(driver->name, "t1isa") == 0)
756 break;
757 }
758 break;
759 default:
760 driver = NULL;
761 break;
762 }
763 if (!driver) {
764 read_unlock_irqrestore(&capi_drivers_list_lock, flags);
765 printk(KERN_ERR "kcapi: driver not loaded.\n");
766 return -EIO;
767 }
768 if (!driver->add_card) {
769 read_unlock_irqrestore(&capi_drivers_list_lock, flags);
770 printk(KERN_ERR "kcapi: driver has no add card function.\n");
771 return -EIO;
772 }
773
774 retval = driver->add_card(driver, &cparams);
775 read_unlock_irqrestore(&capi_drivers_list_lock, flags);
776 return retval;
777
778 case AVMB1_LOAD:
779 case AVMB1_LOAD_AND_CONFIG:
780
781 if (cmd == AVMB1_LOAD) {
782 if (copy_from_user(&ldef, data,
783 sizeof(avmb1_loaddef)))
784 return -EFAULT;
785 ldef.t4config.len = 0;
786 ldef.t4config.data = NULL;
787 } else {
788 if (copy_from_user(&ldef, data,
789 sizeof(avmb1_loadandconfigdef)))
790 return -EFAULT;
791 }
792 card = get_capi_ctr_by_nr(ldef.contr);
793 card = capi_ctr_get(card);
794 if (!card)
795 return -ESRCH;
796 if (card->load_firmware == 0) {
797 printk(KERN_DEBUG "kcapi: load: no load function\n");
798 return -ESRCH;
799 }
800
801 if (ldef.t4file.len <= 0) {
802 printk(KERN_DEBUG "kcapi: load: invalid parameter: length of t4file is %d ?\n", ldef.t4file.len);
803 return -EINVAL;
804 }
805 if (ldef.t4file.data == 0) {
806 printk(KERN_DEBUG "kcapi: load: invalid parameter: dataptr is 0\n");
807 return -EINVAL;
808 }
809
810 ldata.firmware.user = 1;
811 ldata.firmware.data = ldef.t4file.data;
812 ldata.firmware.len = ldef.t4file.len;
813 ldata.configuration.user = 1;
814 ldata.configuration.data = ldef.t4config.data;
815 ldata.configuration.len = ldef.t4config.len;
816
817 if (card->cardstate != CARD_DETECTED) {
818 printk(KERN_INFO "kcapi: load: contr=%d not in detect state\n", ldef.contr);
819 return -EBUSY;
820 }
821 card->cardstate = CARD_LOADING;
822
823 retval = card->load_firmware(card, &ldata);
824
825 if (retval) {
826 card->cardstate = CARD_DETECTED;
827 capi_ctr_put(card);
828 return retval;
829 }
830
831 while (card->cardstate != CARD_RUNNING) {
832
833 msleep_interruptible(100); /* 0.1 sec */
834
835 if (signal_pending(current)) {
836 capi_ctr_put(card);
837 return -EINTR;
838 }
839 }
840 capi_ctr_put(card);
841 return 0;
842
843 case AVMB1_RESETCARD:
844 if (copy_from_user(&rdef, data, sizeof(avmb1_resetdef)))
845 return -EFAULT;
846 card = get_capi_ctr_by_nr(rdef.contr);
847 if (!card)
848 return -ESRCH;
849
850 if (card->cardstate == CARD_DETECTED)
851 return 0;
852
853 card->reset_ctr(card);
854
855 while (card->cardstate > CARD_DETECTED) {
856
857 msleep_interruptible(100); /* 0.1 sec */
858
859 if (signal_pending(current))
860 return -EINTR;
861 }
862 return 0;
863
864 }
865 return -EINVAL;
866}
867#endif
868
869int capi20_manufacturer(unsigned int cmd, void __user *data)
870{
871 struct capi_ctr *card;
872
873 switch (cmd) {
874#ifdef CONFIG_AVMB1_COMPAT
875 case AVMB1_LOAD:
876 case AVMB1_LOAD_AND_CONFIG:
877 case AVMB1_RESETCARD:
878 case AVMB1_GET_CARDINFO:
879 case AVMB1_REMOVECARD:
880 return old_capi_manufacturer(cmd, data);
881#endif
882 case KCAPI_CMD_TRACE:
883 {
884 kcapi_flagdef fdef;
885
886 if (copy_from_user(&fdef, data, sizeof(kcapi_flagdef)))
887 return -EFAULT;
888
889 card = get_capi_ctr_by_nr(fdef.contr);
890 if (!card)
891 return -ESRCH;
892
893 card->traceflag = fdef.flag;
894 printk(KERN_INFO "kcapi: contr %d set trace=%d\n",
895 card->cnr, card->traceflag);
896 return 0;
897 }
898 case KCAPI_CMD_ADDCARD:
899 {
900 struct list_head *l;
901 struct capi_driver *driver = NULL;
902 capicardparams cparams;
903 kcapi_carddef cdef;
904 int retval;
905
906 if ((retval = copy_from_user(&cdef, data, sizeof(cdef))))
907 return retval;
908
909 cparams.port = cdef.port;
910 cparams.irq = cdef.irq;
911 cparams.membase = cdef.membase;
912 cparams.cardnr = cdef.cardnr;
913 cparams.cardtype = 0;
914 cdef.driver[sizeof(cdef.driver)-1] = 0;
915
916 list_for_each(l, &capi_drivers) {
917 driver = list_entry(l, struct capi_driver, list);
918 if (strcmp(driver->name, cdef.driver) == 0)
919 break;
920 }
921 if (driver == 0) {
922 printk(KERN_ERR "kcapi: driver \"%s\" not loaded.\n",
923 cdef.driver);
924 return -ESRCH;
925 }
926
927 if (!driver->add_card) {
928 printk(KERN_ERR "kcapi: driver \"%s\" has no add card function.\n", cdef.driver);
929 return -EIO;
930 }
931
932 return driver->add_card(driver, &cparams);
933 }
934
935 default:
936 printk(KERN_ERR "kcapi: manufacturer command %d unknown.\n",
937 cmd);
938 break;
939
940 }
941 return -EINVAL;
942}
943
944EXPORT_SYMBOL(capi20_manufacturer);
945
946/* temporary hack */
947void capi20_set_callback(struct capi20_appl *ap,
948 void (*callback) (unsigned int cmd, __u32 contr, void *data))
949{
950 ap->callback = callback;
951}
952
953EXPORT_SYMBOL(capi20_set_callback);
954
955/* ------------------------------------------------------------- */
956/* -------- Init & Cleanup ------------------------------------- */
957/* ------------------------------------------------------------- */
958
959/*
960 * init / exit functions
961 */
962
963static int __init kcapi_init(void)
964{
965 char *p;
966 char rev[32];
967
968 kcapi_proc_init();
969
970 if ((p = strchr(revision, ':')) != 0 && p[1]) {
971 strlcpy(rev, p + 2, sizeof(rev));
972 if ((p = strchr(rev, '$')) != 0 && p > rev)
973 *(p-1) = 0;
974 } else
975 strcpy(rev, "1.0");
976
977 printk(KERN_NOTICE "CAPI Subsystem Rev %s\n", rev);
978
979 return 0;
980}
981
982static void __exit kcapi_exit(void)
983{
984 kcapi_proc_exit();
985
986 /* make sure all notifiers are finished */
987 flush_scheduled_work();
988}
989
990module_init(kcapi_init);
991module_exit(kcapi_exit);
diff --git a/drivers/isdn/capi/kcapi.h b/drivers/isdn/capi/kcapi.h
new file mode 100644
index 000000000000..1cb2c40f9921
--- /dev/null
+++ b/drivers/isdn/capi/kcapi.h
@@ -0,0 +1,49 @@
1/*
2 * Kernel CAPI 2.0 Module
3 *
4 * Copyright 1999 by Carsten Paeth <calle@calle.de>
5 * Copyright 2002 by Kai Germaschewski <kai@germaschewski.name>
6 *
7 * This software may be used and distributed according to the terms
8 * of the GNU General Public License, incorporated herein by reference.
9 *
10 */
11
12
13#include <linux/kernel.h>
14#include <linux/spinlock.h>
15#include <linux/list.h>
16#include <linux/isdn/capilli.h>
17
18#ifdef KCAPI_DEBUG
19#define DBG(format, arg...) do { \
20printk(KERN_DEBUG "%s: " format "\n" , __FUNCTION__ , ## arg); \
21} while (0)
22#else
23#define DBG(format, arg...) /* */
24#endif
25
26enum {
27 CARD_DETECTED = 1,
28 CARD_LOADING = 2,
29 CARD_RUNNING = 3,
30};
31
32extern struct list_head capi_drivers;
33extern rwlock_t capi_drivers_list_lock;
34
35extern struct capi20_appl *capi_applications[CAPI_MAXAPPL];
36extern struct capi_ctr *capi_cards[CAPI_MAXCONTR];
37
38#ifdef CONFIG_PROC_FS
39
40void kcapi_proc_init(void);
41void kcapi_proc_exit(void);
42
43#else
44
45static inline void kcapi_proc_init(void) { };
46static inline void kcapi_proc_exit(void) { };
47
48#endif
49
diff --git a/drivers/isdn/capi/kcapi_proc.c b/drivers/isdn/capi/kcapi_proc.c
new file mode 100644
index 000000000000..16dc5418ff41
--- /dev/null
+++ b/drivers/isdn/capi/kcapi_proc.c
@@ -0,0 +1,336 @@
1/*
2 * Kernel CAPI 2.0 Module - /proc/capi handling
3 *
4 * Copyright 1999 by Carsten Paeth <calle@calle.de>
5 * Copyright 2002 by Kai Germaschewski <kai@germaschewski.name>
6 *
7 * This software may be used and distributed according to the terms
8 * of the GNU General Public License, incorporated herein by reference.
9 *
10 */
11
12
13#include "kcapi.h"
14#include <linux/proc_fs.h>
15#include <linux/seq_file.h>
16#include <linux/init.h>
17
18static char *
19cardstate2str(unsigned short cardstate)
20{
21 switch (cardstate) {
22 case CARD_DETECTED: return "detected";
23 case CARD_LOADING: return "loading";
24 case CARD_RUNNING: return "running";
25 default: return "???";
26 }
27}
28
29// /proc/capi
30// ===========================================================================
31
32// /proc/capi/controller:
33// cnr driver cardstate name driverinfo
34// /proc/capi/contrstats:
35// cnr nrecvctlpkt nrecvdatapkt nsentctlpkt nsentdatapkt
36// ---------------------------------------------------------------------------
37
38static void *controller_start(struct seq_file *seq, loff_t *pos)
39{
40 if (*pos < CAPI_MAXCONTR)
41 return &capi_cards[*pos];
42
43 return NULL;
44}
45
46static void *controller_next(struct seq_file *seq, void *v, loff_t *pos)
47{
48 ++*pos;
49 if (*pos < CAPI_MAXCONTR)
50 return &capi_cards[*pos];
51
52 return NULL;
53}
54
55static void controller_stop(struct seq_file *seq, void *v)
56{
57}
58
59static int controller_show(struct seq_file *seq, void *v)
60{
61 struct capi_ctr *ctr = *(struct capi_ctr **) v;
62
63 if (!ctr)
64 return 0;
65
66 seq_printf(seq, "%d %-10s %-8s %-16s %s\n",
67 ctr->cnr, ctr->driver_name,
68 cardstate2str(ctr->cardstate),
69 ctr->name,
70 ctr->procinfo ? ctr->procinfo(ctr) : "");
71
72 return 0;
73}
74
75static int contrstats_show(struct seq_file *seq, void *v)
76{
77 struct capi_ctr *ctr = *(struct capi_ctr **) v;
78
79 if (!ctr)
80 return 0;
81
82 seq_printf(seq, "%d %lu %lu %lu %lu\n",
83 ctr->cnr,
84 ctr->nrecvctlpkt,
85 ctr->nrecvdatapkt,
86 ctr->nsentctlpkt,
87 ctr->nsentdatapkt);
88
89 return 0;
90}
91
92struct seq_operations seq_controller_ops = {
93 .start = controller_start,
94 .next = controller_next,
95 .stop = controller_stop,
96 .show = controller_show,
97};
98
99struct seq_operations seq_contrstats_ops = {
100 .start = controller_start,
101 .next = controller_next,
102 .stop = controller_stop,
103 .show = contrstats_show,
104};
105
106static int seq_controller_open(struct inode *inode, struct file *file)
107{
108 return seq_open(file, &seq_controller_ops);
109}
110
111static int seq_contrstats_open(struct inode *inode, struct file *file)
112{
113 return seq_open(file, &seq_contrstats_ops);
114}
115
116static struct file_operations proc_controller_ops = {
117 .open = seq_controller_open,
118 .read = seq_read,
119 .llseek = seq_lseek,
120 .release = seq_release,
121};
122
123static struct file_operations proc_contrstats_ops = {
124 .open = seq_contrstats_open,
125 .read = seq_read,
126 .llseek = seq_lseek,
127 .release = seq_release,
128};
129
130// /proc/capi/applications:
131// applid l3cnt dblkcnt dblklen #ncci recvqueuelen
132// /proc/capi/applstats:
133// applid nrecvctlpkt nrecvdatapkt nsentctlpkt nsentdatapkt
134// ---------------------------------------------------------------------------
135
136static void *
137applications_start(struct seq_file *seq, loff_t *pos)
138{
139 if (*pos < CAPI_MAXAPPL)
140 return &capi_applications[*pos];
141
142 return NULL;
143}
144
145static void *
146applications_next(struct seq_file *seq, void *v, loff_t *pos)
147{
148 ++*pos;
149 if (*pos < CAPI_MAXAPPL)
150 return &capi_applications[*pos];
151
152 return NULL;
153}
154
155static void
156applications_stop(struct seq_file *seq, void *v)
157{
158}
159
160static int
161applications_show(struct seq_file *seq, void *v)
162{
163 struct capi20_appl *ap = *(struct capi20_appl **) v;
164
165 if (!ap)
166 return 0;
167
168 seq_printf(seq, "%u %d %d %d\n",
169 ap->applid,
170 ap->rparam.level3cnt,
171 ap->rparam.datablkcnt,
172 ap->rparam.datablklen);
173
174 return 0;
175}
176
177static int
178applstats_show(struct seq_file *seq, void *v)
179{
180 struct capi20_appl *ap = *(struct capi20_appl **) v;
181
182 if (!ap)
183 return 0;
184
185 seq_printf(seq, "%u %lu %lu %lu %lu\n",
186 ap->applid,
187 ap->nrecvctlpkt,
188 ap->nrecvdatapkt,
189 ap->nsentctlpkt,
190 ap->nsentdatapkt);
191
192 return 0;
193}
194
195struct seq_operations seq_applications_ops = {
196 .start = applications_start,
197 .next = applications_next,
198 .stop = applications_stop,
199 .show = applications_show,
200};
201
202struct seq_operations seq_applstats_ops = {
203 .start = applications_start,
204 .next = applications_next,
205 .stop = applications_stop,
206 .show = applstats_show,
207};
208
209static int
210seq_applications_open(struct inode *inode, struct file *file)
211{
212 return seq_open(file, &seq_applications_ops);
213}
214
215static int
216seq_applstats_open(struct inode *inode, struct file *file)
217{
218 return seq_open(file, &seq_applstats_ops);
219}
220
221static struct file_operations proc_applications_ops = {
222 .open = seq_applications_open,
223 .read = seq_read,
224 .llseek = seq_lseek,
225 .release = seq_release,
226};
227
228static struct file_operations proc_applstats_ops = {
229 .open = seq_applstats_open,
230 .read = seq_read,
231 .llseek = seq_lseek,
232 .release = seq_release,
233};
234
235static void
236create_seq_entry(char *name, mode_t mode, struct file_operations *f)
237{
238 struct proc_dir_entry *entry;
239 entry = create_proc_entry(name, mode, NULL);
240 if (entry)
241 entry->proc_fops = f;
242}
243
244// ---------------------------------------------------------------------------
245
246
247static __inline__ struct capi_driver *capi_driver_get_idx(loff_t pos)
248{
249 struct capi_driver *drv = NULL;
250 struct list_head *l;
251 loff_t i;
252
253 i = 0;
254 list_for_each(l, &capi_drivers) {
255 drv = list_entry(l, struct capi_driver, list);
256 if (i++ == pos)
257 return drv;
258 }
259 return NULL;
260}
261
262static void *capi_driver_start(struct seq_file *seq, loff_t *pos)
263{
264 struct capi_driver *drv;
265 read_lock(&capi_drivers_list_lock);
266 drv = capi_driver_get_idx(*pos);
267 return drv;
268}
269
270static void *capi_driver_next(struct seq_file *seq, void *v, loff_t *pos)
271{
272 struct capi_driver *drv = (struct capi_driver *)v;
273 ++*pos;
274 if (drv->list.next == &capi_drivers) return NULL;
275 return list_entry(drv->list.next, struct capi_driver, list);
276}
277
278static void capi_driver_stop(struct seq_file *seq, void *v)
279{
280 read_unlock(&capi_drivers_list_lock);
281}
282
283static int capi_driver_show(struct seq_file *seq, void *v)
284{
285 struct capi_driver *drv = (struct capi_driver *)v;
286 seq_printf(seq, "%-32s %s\n", drv->name, drv->revision);
287 return 0;
288}
289
290struct seq_operations seq_capi_driver_ops = {
291 .start = capi_driver_start,
292 .next = capi_driver_next,
293 .stop = capi_driver_stop,
294 .show = capi_driver_show,
295};
296
297static int
298seq_capi_driver_open(struct inode *inode, struct file *file)
299{
300 int err;
301 err = seq_open(file, &seq_capi_driver_ops);
302 return err;
303}
304
305static struct file_operations proc_driver_ops = {
306 .open = seq_capi_driver_open,
307 .read = seq_read,
308 .llseek = seq_lseek,
309 .release = seq_release,
310};
311
312// ---------------------------------------------------------------------------
313
314void __init
315kcapi_proc_init(void)
316{
317 proc_mkdir("capi", NULL);
318 proc_mkdir("capi/controllers", NULL);
319 create_seq_entry("capi/controller", 0, &proc_controller_ops);
320 create_seq_entry("capi/contrstats", 0, &proc_contrstats_ops);
321 create_seq_entry("capi/applications", 0, &proc_applications_ops);
322 create_seq_entry("capi/applstats", 0, &proc_applstats_ops);
323 create_seq_entry("capi/driver", 0, &proc_driver_ops);
324}
325
326void __exit
327kcapi_proc_exit(void)
328{
329 remove_proc_entry("capi/driver", NULL);
330 remove_proc_entry("capi/controller", NULL);
331 remove_proc_entry("capi/contrstats", NULL);
332 remove_proc_entry("capi/applications", NULL);
333 remove_proc_entry("capi/applstats", NULL);
334 remove_proc_entry("capi/controllers", NULL);
335 remove_proc_entry("capi", NULL);
336}