2 * $Id: capi.c,v 1.19 1999/07/09 15:05:42 keil Exp $
4 * CAPI 2.0 Interface for Linux
6 * Copyright 1996 by Carsten Paeth (calle@calle.in-berlin.de)
9 * Revision 1.19 1999/07/09 15:05:42 keil
10 * compat.h is now isdn_compat.h
12 * Revision 1.18 1999/07/06 07:42:01 calle
13 * - changes in /proc interface
14 * - check and changed calls to [dev_]kfree_skb and [dev_]alloc_skb.
16 * Revision 1.17 1999/07/01 15:26:30 calle
17 * complete new version (I love it):
18 * + new hardware independed "capi_driver" interface that will make it easy to:
19 * - support other controllers with CAPI-2.0 (i.e. USB Controller)
20 * - write a CAPI-2.0 for the passive cards
21 * - support serial link CAPI-2.0 boxes.
22 * + wrote "capi_driver" for all supported cards.
23 * + "capi_driver" (supported cards) now have to be configured with
24 * make menuconfig, in the past all supported cards where included
26 * + new and better informations in /proc/capi/
27 * + new ioctl to switch trace of capi messages per controller
28 * using "avmcapictrl trace [contr] on|off|...."
29 * + complete testcircle with all supported cards and also the
30 * PCMCIA cards (now patch for pcmcia-cs-3.0.13 needed) done.
32 * Revision 1.16 1999/07/01 08:22:57 keil
33 * compatibility macros now in <linux/isdn_compat.h>
35 * Revision 1.15 1999/06/21 15:24:11 calle
36 * extend information in /proc.
38 * Revision 1.14 1999/06/10 16:51:03 calle
39 * Bugfix: open/release of control device was not handled correct.
41 * Revision 1.13 1998/08/28 04:32:25 calle
42 * Added patch send by Michael.Mueller4@post.rwth-aachen.de, to get AVM B1
43 * driver running with 2.1.118.
45 * Revision 1.12 1998/05/26 22:39:34 he
46 * sync'ed with 2.1.102 where appropriate (CAPABILITY changes)
48 * cleared dev.tbusy in isdn_net BCONN status callback
50 * Revision 1.11 1998/03/09 17:46:37 he
51 * merged in 2.1.89 changes
53 * Revision 1.10 1998/02/13 07:09:13 calle
54 * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb()
56 * Revision 1.9 1998/01/31 11:14:44 calle
57 * merged changes to 2.0 tree, prepare 2.1.82 to work.
59 * Revision 1.8 1997/11/04 06:12:08 calle
60 * capi.c: new read/write in file_ops since 2.1.60
61 * capidrv.c: prepared isdnlog interface for d2-trace in newer firmware.
62 * capiutil.c: needs config.h (CONFIG_ISDN_DRV_AVMB1_VERBOSE_REASON)
63 * compat.h: added #define LinuxVersionCode
65 * Revision 1.7 1997/10/11 10:29:34 calle
66 * llseek() parameters changed in 2.1.56.
68 * Revision 1.6 1997/10/01 09:21:15 fritz
69 * Removed old compatibility stuff for 2.0.X kernels.
70 * From now on, this code is for 2.1.X ONLY!
71 * Old stuff is still in the separate branch.
73 * Revision 1.5 1997/08/21 23:11:55 fritz
74 * Added changes for kernels >= 2.1.45
76 * Revision 1.4 1997/05/27 15:17:50 fritz
77 * Added changes for recent 2.1.x kernels:
78 * changed return type of isdn_close
79 * queue_task_* -> queue_task
80 * clear/set_bit -> test_and_... where apropriate.
81 * changed type of hard_header_cache parameter.
83 * Revision 1.3 1997/05/18 09:24:14 calle
84 * added verbose disconnect reason reporting to avmb1.
85 * some fixes in capi20 interface.
86 * changed info messages for B1-PCI
88 * Revision 1.2 1997/03/05 21:17:59 fritz
89 * Added capi_poll for compiling under 2.1.27
91 * Revision 1.1 1997/03/04 21:50:29 calle
92 * Frirst version in isdn4linux
94 * Revision 2.2 1997/02/12 09:31:39 calle
97 * Revision 1.1 1997/01/31 10:32:20 calle
102 #include <linux/module.h>
103 #include <linux/errno.h>
104 #include <linux/kernel.h>
105 #include <linux/major.h>
106 #include <linux/sched.h>
107 #include <linux/malloc.h>
108 #include <linux/fcntl.h>
109 #include <linux/fs.h>
110 #include <linux/signal.h>
111 #include <linux/mm.h>
112 #include <linux/timer.h>
113 #include <linux/wait.h>
114 #include <linux/skbuff.h>
115 #include <linux/proc_fs.h>
116 #include <linux/poll.h>
117 #include <linux/capi.h>
118 #include <linux/kernelcapi.h>
120 #include <linux/isdn_compat.h>
121 #include "capiutil.h"
125 MODULE_AUTHOR("Carsten Paeth (calle@calle.in-berlin.de)");
127 /* -------- driver information -------------------------------------- */
129 int capi_major
= 68; /* allocated */
131 MODULE_PARM(capi_major
, "i");
133 /* -------- global variables ---------------------------------------- */
135 static struct capidev capidevs
[CAPI_MAXMINOR
+ 1];
136 struct capi_interface
*capifuncs
;
138 /* -------- function called by lower level -------------------------- */
140 static void capi_signal(__u16 applid
, __u32 minor
)
142 struct capidev
*cdev
;
143 struct sk_buff
*skb
= 0;
145 if (minor
> CAPI_MAXMINOR
|| !capidevs
[minor
].is_registered
) {
146 printk(KERN_ERR
"BUG: capi_signal: illegal minor %d\n", minor
);
149 cdev
= &capidevs
[minor
];
150 (void) (*capifuncs
->capi_get_message
) (applid
, &skb
);
152 skb_queue_tail(&cdev
->recv_queue
, skb
);
153 wake_up_interruptible(&cdev
->recv_wait
);
155 printk(KERN_ERR
"BUG: capi_signal: no skb\n");
159 /* -------- file_operations ----------------------------------------- */
161 static long long capi_llseek(struct file
*file
,
162 long long offset
, int origin
)
167 static ssize_t
capi_read(struct file
*file
, char *buf
,
168 size_t count
, loff_t
*ppos
)
170 struct inode
*inode
= file
->f_dentry
->d_inode
;
171 unsigned int minor
= MINOR(inode
->i_rdev
);
172 struct capidev
*cdev
;
177 if (ppos
!= &file
->f_pos
)
180 if (!minor
|| minor
> CAPI_MAXMINOR
|| !capidevs
[minor
].is_registered
)
183 cdev
= &capidevs
[minor
];
185 if ((skb
= skb_dequeue(&cdev
->recv_queue
)) == 0) {
187 if (file
->f_flags
& O_NONBLOCK
)
191 interruptible_sleep_on(&cdev
->recv_wait
);
192 if ((skb
= skb_dequeue(&cdev
->recv_queue
)) != 0)
194 if (signal_pending(current
))
198 return -ERESTARTNOHAND
;
200 if (skb
->len
> count
) {
201 skb_queue_head(&cdev
->recv_queue
, skb
);
204 if (CAPIMSG_COMMAND(skb
->data
) == CAPI_DATA_B3
205 && CAPIMSG_SUBCOMMAND(skb
->data
) == CAPI_IND
)
206 CAPIMSG_SETDATA(skb
->data
, buf
+ CAPIMSG_LEN(skb
->data
));
207 retval
= copy_to_user(buf
, skb
->data
, skb
->len
);
209 skb_queue_head(&cdev
->recv_queue
, skb
);
214 if (CAPIMSG_COMMAND(skb
->data
) == CAPI_DATA_B3
215 && CAPIMSG_SUBCOMMAND(skb
->data
) == CAPI_IND
)
216 cdev
->nrecvdatapkt
++;
217 else cdev
->nrecvctlpkt
++;
223 static ssize_t
capi_write(struct file
*file
, const char *buf
,
224 size_t count
, loff_t
*ppos
)
226 struct inode
*inode
= file
->f_dentry
->d_inode
;
227 unsigned int minor
= MINOR(inode
->i_rdev
);
228 struct capidev
*cdev
;
235 if (ppos
!= &file
->f_pos
)
238 if (!minor
|| minor
> CAPI_MAXMINOR
|| !capidevs
[minor
].is_registered
)
241 cdev
= &capidevs
[minor
];
243 skb
= alloc_skb(count
, GFP_USER
);
245 if ((retval
= copy_from_user(skb_put(skb
, count
), buf
, count
))) {
249 cmd
= CAPIMSG_COMMAND(skb
->data
);
250 subcmd
= CAPIMSG_SUBCOMMAND(skb
->data
);
251 mlen
= CAPIMSG_LEN(skb
->data
);
252 if (cmd
== CAPI_DATA_B3
&& subcmd
== CAPI_REQ
) {
253 __u16 dlen
= CAPIMSG_DATALEN(skb
->data
);
254 if (mlen
+ dlen
!= count
) {
258 } else if (mlen
!= count
) {
262 CAPIMSG_SETAPPID(skb
->data
, cdev
->applid
);
264 cdev
->errcode
= (*capifuncs
->capi_put_message
) (cdev
->applid
, skb
);
270 if (cmd
== CAPI_DATA_B3
&& subcmd
== CAPI_REQ
)
271 cdev
->nsentdatapkt
++;
272 else cdev
->nsentctlpkt
++;
277 capi_poll(struct file
*file
, poll_table
* wait
)
279 unsigned int mask
= 0;
280 #if (LINUX_VERSION_CODE >= 0x02012d)
281 unsigned int minor
= MINOR(file
->f_dentry
->d_inode
->i_rdev
);
283 unsigned int minor
= MINOR(file
->f_inode
->i_rdev
);
285 struct capidev
*cdev
;
287 if (!minor
|| minor
> CAPI_MAXMINOR
|| !capidevs
[minor
].is_registered
)
290 cdev
= &capidevs
[minor
];
291 #if (LINUX_VERSION_CODE < 0x020159) /* 2.1.89 */
292 #define poll_wait(f,wq,w) poll_wait((wq),(w))
294 poll_wait(file
, &(cdev
->recv_wait
), wait
);
295 mask
= POLLOUT
| POLLWRNORM
;
296 if (!skb_queue_empty(&cdev
->recv_queue
))
297 mask
|= POLLIN
| POLLRDNORM
;
301 static int capi_ioctl(struct inode
*inode
, struct file
*file
,
302 unsigned int cmd
, unsigned long arg
)
304 unsigned int minor
= MINOR(inode
->i_rdev
);
305 struct capidev
*cdev
;
306 capi_ioctl_struct data
;
310 if (minor
>= CAPI_MAXMINOR
|| !capidevs
[minor
].is_open
)
313 cdev
= &capidevs
[minor
];
320 retval
= copy_from_user((void *) &data
.rparams
,
321 (void *) arg
, sizeof(struct capi_register_params
));
324 if (cdev
->is_registered
)
326 cdev
->errcode
= (*capifuncs
->capi_register
) (&data
.rparams
,
330 (void) (*capifuncs
->capi_set_signal
) (cdev
->applid
, capi_signal
, minor
);
331 cdev
->is_registered
= 1;
335 case CAPI_GET_VERSION
:
337 retval
= copy_from_user((void *) &data
.contr
,
342 cdev
->errcode
= (*capifuncs
->capi_get_version
) (data
.contr
, &data
.version
);
345 retval
= copy_to_user((void *) arg
,
346 (void *) &data
.version
,
347 sizeof(data
.version
));
353 case CAPI_GET_SERIAL
:
355 retval
= copy_from_user((void *) &data
.contr
,
360 cdev
->errcode
= (*capifuncs
->capi_get_serial
) (data
.contr
, data
.serial
);
363 retval
= copy_to_user((void *) arg
,
364 (void *) data
.serial
,
365 sizeof(data
.serial
));
370 case CAPI_GET_PROFILE
:
372 retval
= copy_from_user((void *) &data
.contr
,
378 if (data
.contr
== 0) {
379 cdev
->errcode
= (*capifuncs
->capi_get_profile
) (data
.contr
, &data
.profile
);
383 retval
= copy_to_user((void *) arg
,
384 (void *) &data
.profile
.ncontroller
,
385 sizeof(data
.profile
.ncontroller
));
388 cdev
->errcode
= (*capifuncs
->capi_get_profile
) (data
.contr
, &data
.profile
);
392 retval
= copy_to_user((void *) arg
,
393 (void *) &data
.profile
,
394 sizeof(data
.profile
));
401 case CAPI_GET_MANUFACTURER
:
403 retval
= copy_from_user((void *) &data
.contr
,
408 cdev
->errcode
= (*capifuncs
->capi_get_manufacturer
) (data
.contr
, data
.manufacturer
);
412 retval
= copy_to_user((void *) arg
, (void *) data
.manufacturer
,
413 sizeof(data
.manufacturer
));
419 case CAPI_GET_ERRCODE
:
420 data
.errcode
= cdev
->errcode
;
421 cdev
->errcode
= CAPI_NOERROR
;
423 retval
= copy_to_user((void *) arg
,
424 (void *) &data
.errcode
,
425 sizeof(data
.errcode
));
432 if ((*capifuncs
->capi_installed
) ())
436 case CAPI_MANUFACTURER_CMD
:
438 struct capi_manufacturer_cmd mcmd
;
441 if (!capable(CAP_SYS_ADMIN
))
443 retval
= copy_from_user((void *) &mcmd
, (void *) arg
,
447 return (*capifuncs
->capi_manufacturer
) (mcmd
.cmd
, mcmd
.data
);
454 static int capi_open(struct inode
*inode
, struct file
*file
)
456 unsigned int minor
= MINOR(inode
->i_rdev
);
458 if (minor
>= CAPI_MAXMINOR
)
462 if (capidevs
[minor
].is_open
)
465 capidevs
[minor
].is_open
= 1;
466 skb_queue_head_init(&capidevs
[minor
].recv_queue
);
468 capidevs
[minor
].nopen
++;
471 capidevs
[minor
].is_open
++;
479 capi_release(struct inode
*inode
, struct file
*file
)
481 unsigned int minor
= MINOR(inode
->i_rdev
);
482 struct capidev
*cdev
;
485 if (minor
>= CAPI_MAXMINOR
|| !capidevs
[minor
].is_open
) {
486 printk(KERN_ERR
"capi20: release minor %d ???\n", minor
);
489 cdev
= &capidevs
[minor
];
493 if (cdev
->is_registered
)
494 (*capifuncs
->capi_release
) (cdev
->applid
);
496 cdev
->is_registered
= 0;
499 while ((skb
= skb_dequeue(&cdev
->recv_queue
)) != 0) {
511 static struct file_operations capi_fops
=
516 NULL
, /* capi_readdir */
519 NULL
, /* capi_mmap */
521 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,118)
522 NULL
, /* capi_flush */
525 NULL
, /* capi_fsync */
526 NULL
, /* capi_fasync */
529 /* -------- /proc functions ----------------------------------- */
533 * minor opencount nrecvctlpkt nrecvdatapkt nsendctlpkt nsenddatapkt
535 static int proc_capidev_read_proc(char *page
, char **start
, off_t off
,
536 int count
, int *eof
, void *data
)
543 for (i
=0; i
< CAPI_MAXMINOR
; i
++) {
545 if (cp
->nopen
== 0) continue;
546 len
+= sprintf(page
+len
, "%d %lu %lu %lu %lu %lu\n",
553 if (len
+begin
> off
+count
)
555 if (len
+begin
< off
) {
561 if (i
>= CAPI_MAXMINOR
)
563 if (off
>= len
+begin
)
565 *start
= page
+ (begin
-off
);
566 return ((count
< begin
+len
-off
) ? count
: begin
+len
-off
);
569 static struct procfsentries
{
572 int (*read_proc
)(char *page
, char **start
, off_t off
,
573 int count
, int *eof
, void *data
);
574 struct proc_dir_entry
*procent
;
575 } procfsentries
[] = {
576 /* { "capi", S_IFDIR, 0 }, */
577 { "capi/capi20", 0 , proc_capidev_read_proc
},
580 static void proc_init(void)
582 int nelem
= sizeof(procfsentries
)/sizeof(procfsentries
[0]);
585 for (i
=0; i
< nelem
; i
++) {
586 struct procfsentries
*p
= procfsentries
+ i
;
587 p
->procent
= create_proc_entry(p
->name
, p
->mode
, 0);
588 if (p
->procent
) p
->procent
->read_proc
= p
->read_proc
;
592 static void proc_exit(void)
594 int nelem
= sizeof(procfsentries
)/sizeof(procfsentries
[0]);
597 for (i
=nelem
-1; i
>= 0; i
--) {
598 struct procfsentries
*p
= procfsentries
+ i
;
600 remove_proc_entry(p
->name
, 0);
605 /* -------- init function and module interface ---------------------- */
608 #define capi_init init_module
611 static struct capi_interface_user cuser
= {
618 #ifdef COMPAT_HAS_NEW_WAITQ
622 memset(capidevs
, 0, sizeof(capidevs
));
623 #ifdef COMPAT_HAS_NEW_WAITQ
624 for ( j
= 0; j
< CAPI_MAXMINOR
+1; j
++ ) {
625 init_waitqueue_head(&capidevs
[j
].recv_wait
);
629 if (register_chrdev(capi_major
, "capi20", &capi_fops
)) {
630 printk(KERN_ERR
"capi20: unable to get major %d\n", capi_major
);
633 printk(KERN_NOTICE
"capi20: started up with major %d\n", capi_major
);
635 if ((capifuncs
= attach_capi_interface(&cuser
)) == 0) {
636 unregister_chrdev(capi_major
, "capi20");
644 void cleanup_module(void)
647 unregister_chrdev(capi_major
, "capi20");
648 (void) detach_capi_interface(&cuser
);