2 * $Id: capi.c,v 1.10 1998/02/13 07:09:13 calle Exp $
4 * CAPI 2.0 Interface for Linux
6 * Copyright 1996 by Carsten Paeth (calle@calle.in-berlin.de)
9 * Revision 1.10 1998/02/13 07:09:13 calle
10 * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb()
12 * Revision 1.9 1998/01/31 11:14:44 calle
13 * merged changes to 2.0 tree, prepare 2.1.82 to work.
15 * Revision 1.8 1997/11/04 06:12:08 calle
16 * capi.c: new read/write in file_ops since 2.1.60
17 * capidrv.c: prepared isdnlog interface for d2-trace in newer firmware.
18 * capiutil.c: needs config.h (CONFIG_ISDN_DRV_AVMB1_VERBOSE_REASON)
19 * compat.h: added #define LinuxVersionCode
21 * Revision 1.7 1997/10/11 10:29:34 calle
22 * llseek() parameters changed in 2.1.56.
24 * Revision 1.6 1997/10/01 09:21:15 fritz
25 * Removed old compatibility stuff for 2.0.X kernels.
26 * From now on, this code is for 2.1.X ONLY!
27 * Old stuff is still in the separate branch.
29 * Revision 1.5 1997/08/21 23:11:55 fritz
30 * Added changes for kernels >= 2.1.45
32 * Revision 1.4 1997/05/27 15:17:50 fritz
33 * Added changes for recent 2.1.x kernels:
34 * changed return type of isdn_close
35 * queue_task_* -> queue_task
36 * clear/set_bit -> test_and_... where apropriate.
37 * changed type of hard_header_cache parameter.
39 * Revision 1.3 1997/05/18 09:24:14 calle
40 * added verbose disconnect reason reporting to avmb1.
41 * some fixes in capi20 interface.
42 * changed info messages for B1-PCI
44 * Revision 1.2 1997/03/05 21:17:59 fritz
45 * Added capi_poll for compiling under 2.1.27
47 * Revision 1.1 1997/03/04 21:50:29 calle
48 * Frirst version in isdn4linux
50 * Revision 2.2 1997/02/12 09:31:39 calle
53 * Revision 1.1 1997/01/31 10:32:20 calle
58 #include <linux/module.h>
59 #include <linux/errno.h>
60 #include <linux/kernel.h>
61 #include <linux/major.h>
62 #include <linux/sched.h>
63 #include <linux/malloc.h>
64 #include <linux/fcntl.h>
66 #include <linux/signal.h>
68 #include <linux/timer.h>
69 #include <linux/wait.h>
70 #include <linux/skbuff.h>
71 #include <linux/poll.h>
72 #include <linux/capi.h>
73 #include <linux/kernelcapi.h>
80 MODULE_AUTHOR("Carsten Paeth (calle@calle.in-berlin.de)");
82 /* -------- driver information -------------------------------------- */
84 int capi_major
= 68; /* allocated */
86 MODULE_PARM(capi_major
, "i");
88 /* -------- global variables ---------------------------------------- */
90 static struct capidev capidevs
[CAPI_MAXMINOR
+ 1];
91 struct capi_interface
*capifuncs
;
93 /* -------- function called by lower level -------------------------- */
95 static void capi_signal(__u16 applid
, __u32 minor
)
98 struct sk_buff
*skb
= 0;
100 if (minor
> CAPI_MAXMINOR
|| !capidevs
[minor
].is_registered
) {
101 printk(KERN_ERR
"BUG: capi_signal: illegal minor %d\n", minor
);
104 cdev
= &capidevs
[minor
];
105 (void) (*capifuncs
->capi_get_message
) (applid
, &skb
);
107 skb_queue_tail(&cdev
->recv_queue
, skb
);
108 wake_up_interruptible(&cdev
->recv_wait
);
110 printk(KERN_ERR
"BUG: capi_signal: no skb\n");
114 /* -------- file_operations ----------------------------------------- */
116 static long long capi_llseek(struct file
*file
,
117 long long offset
, int origin
)
122 static ssize_t
capi_read(struct file
*file
, char *buf
,
123 size_t count
, loff_t
*ppos
)
125 struct inode
*inode
= file
->f_dentry
->d_inode
;
126 unsigned int minor
= MINOR(inode
->i_rdev
);
127 struct capidev
*cdev
;
132 if (ppos
!= &file
->f_pos
)
135 if (!minor
|| minor
> CAPI_MAXMINOR
|| !capidevs
[minor
].is_registered
)
138 cdev
= &capidevs
[minor
];
140 if ((skb
= skb_dequeue(&cdev
->recv_queue
)) == 0) {
142 if (file
->f_flags
& O_NONBLOCK
)
146 interruptible_sleep_on(&cdev
->recv_wait
);
147 if ((skb
= skb_dequeue(&cdev
->recv_queue
)) != 0)
149 if (signal_pending(current
))
153 return -ERESTARTNOHAND
;
155 if (skb
->len
> count
) {
156 skb_queue_head(&cdev
->recv_queue
, skb
);
159 if (CAPIMSG_COMMAND(skb
->data
) == CAPI_DATA_B3
160 && CAPIMSG_SUBCOMMAND(skb
->data
) == CAPI_IND
)
161 CAPIMSG_SETDATA(skb
->data
, buf
+ CAPIMSG_LEN(skb
->data
));
162 retval
= copy_to_user(buf
, skb
->data
, skb
->len
);
164 skb_queue_head(&cdev
->recv_queue
, skb
);
175 static ssize_t
capi_write(struct file
*file
, const char *buf
,
176 size_t count
, loff_t
*ppos
)
178 struct inode
*inode
= file
->f_dentry
->d_inode
;
179 unsigned int minor
= MINOR(inode
->i_rdev
);
180 struct capidev
*cdev
;
187 if (ppos
!= &file
->f_pos
)
190 if (!minor
|| minor
> CAPI_MAXMINOR
|| !capidevs
[minor
].is_registered
)
193 cdev
= &capidevs
[minor
];
195 skb
= alloc_skb(count
, GFP_USER
);
197 if ((retval
= copy_from_user(skb_put(skb
, count
), buf
, count
))) {
201 cmd
= CAPIMSG_COMMAND(skb
->data
);
202 subcmd
= CAPIMSG_SUBCOMMAND(skb
->data
);
203 mlen
= CAPIMSG_LEN(skb
->data
);
204 if (cmd
== CAPI_DATA_B3
&& subcmd
== CAPI_REQ
) {
205 __u16 dlen
= CAPIMSG_DATALEN(skb
->data
);
206 if (mlen
+ dlen
!= count
) {
210 } else if (mlen
!= count
) {
214 CAPIMSG_SETAPPID(skb
->data
, cdev
->applid
);
216 cdev
->errcode
= (*capifuncs
->capi_put_message
) (cdev
->applid
, skb
);
226 capi_poll(struct file
*file
, poll_table
* wait
)
228 unsigned int mask
= 0;
229 #if (LINUX_VERSION_CODE >= 0x02012d)
230 unsigned int minor
= MINOR(file
->f_dentry
->d_inode
->i_rdev
);
232 unsigned int minor
= MINOR(file
->f_inode
->i_rdev
);
234 struct capidev
*cdev
;
236 if (!minor
|| minor
> CAPI_MAXMINOR
|| !capidevs
[minor
].is_registered
)
239 cdev
= &capidevs
[minor
];
240 poll_wait(file
, &(cdev
->recv_wait
), wait
);
241 mask
= POLLOUT
| POLLWRNORM
;
242 if (!skb_queue_empty(&cdev
->recv_queue
))
243 mask
|= POLLIN
| POLLRDNORM
;
247 static int capi_ioctl(struct inode
*inode
, struct file
*file
,
248 unsigned int cmd
, unsigned long arg
)
250 unsigned int minor
= MINOR(inode
->i_rdev
);
251 struct capidev
*cdev
;
252 capi_ioctl_struct data
;
256 if (minor
>= CAPI_MAXMINOR
|| !capidevs
[minor
].is_open
)
259 cdev
= &capidevs
[minor
];
266 retval
= copy_from_user((void *) &data
.rparams
,
267 (void *) arg
, sizeof(struct capi_register_params
));
270 if (cdev
->is_registered
)
272 cdev
->errcode
= (*capifuncs
->capi_register
) (&data
.rparams
,
276 (void) (*capifuncs
->capi_set_signal
) (cdev
->applid
, capi_signal
, minor
);
277 cdev
->is_registered
= 1;
281 case CAPI_GET_VERSION
:
283 retval
= copy_from_user((void *) &data
.contr
,
288 cdev
->errcode
= (*capifuncs
->capi_get_version
) (data
.contr
, &data
.version
);
291 retval
= copy_to_user((void *) arg
,
292 (void *) &data
.version
,
293 sizeof(data
.version
));
299 case CAPI_GET_SERIAL
:
301 retval
= copy_from_user((void *) &data
.contr
,
306 cdev
->errcode
= (*capifuncs
->capi_get_serial
) (data
.contr
, data
.serial
);
309 retval
= copy_to_user((void *) arg
,
310 (void *) data
.serial
,
311 sizeof(data
.serial
));
316 case CAPI_GET_PROFILE
:
318 retval
= copy_from_user((void *) &data
.contr
,
324 if (data
.contr
== 0) {
325 cdev
->errcode
= (*capifuncs
->capi_get_profile
) (data
.contr
, &data
.profile
);
329 retval
= copy_to_user((void *) arg
,
330 (void *) &data
.profile
.ncontroller
,
331 sizeof(data
.profile
.ncontroller
));
334 cdev
->errcode
= (*capifuncs
->capi_get_profile
) (data
.contr
, &data
.profile
);
338 retval
= copy_to_user((void *) arg
,
339 (void *) &data
.profile
,
340 sizeof(data
.profile
));
347 case CAPI_GET_MANUFACTURER
:
349 retval
= copy_from_user((void *) &data
.contr
,
354 cdev
->errcode
= (*capifuncs
->capi_get_manufacturer
) (data
.contr
, data
.manufacturer
);
358 retval
= copy_to_user((void *) arg
, (void *) data
.manufacturer
,
359 sizeof(data
.manufacturer
));
365 case CAPI_GET_ERRCODE
:
366 data
.errcode
= cdev
->errcode
;
367 cdev
->errcode
= CAPI_NOERROR
;
369 retval
= copy_to_user((void *) arg
,
370 (void *) &data
.errcode
,
371 sizeof(data
.errcode
));
378 if ((*capifuncs
->capi_installed
) ())
382 case CAPI_MANUFACTURER_CMD
:
384 struct capi_manufacturer_cmd mcmd
;
387 if (!capable(CAP_SYS_ADMIN
))
389 retval
= copy_from_user((void *) &mcmd
, (void *) arg
,
393 return (*capifuncs
->capi_manufacturer
) (mcmd
.cmd
, mcmd
.data
);
400 static int capi_open(struct inode
*inode
, struct file
*file
)
402 unsigned int minor
= MINOR(inode
->i_rdev
);
404 if (minor
>= CAPI_MAXMINOR
)
408 if (capidevs
[minor
].is_open
)
411 capidevs
[minor
].is_open
= 1;
412 skb_queue_head_init(&capidevs
[minor
].recv_queue
);
417 if (!capidevs
[minor
].is_open
) {
418 capidevs
[minor
].is_open
= 1;
428 capi_release(struct inode
*inode
, struct file
*file
)
430 unsigned int minor
= MINOR(inode
->i_rdev
);
431 struct capidev
*cdev
;
434 if (minor
>= CAPI_MAXMINOR
|| !capidevs
[minor
].is_open
) {
435 printk(KERN_ERR
"capi20: release minor %d ???\n", minor
);
438 cdev
= &capidevs
[minor
];
442 if (cdev
->is_registered
)
443 (*capifuncs
->capi_release
) (cdev
->applid
);
445 cdev
->is_registered
= 0;
448 while ((skb
= skb_dequeue(&cdev
->recv_queue
)) != 0)
457 static struct file_operations capi_fops
=
462 NULL
, /* capi_readdir */
465 NULL
, /* capi_mmap */
469 NULL
, /* capi_fsync */
470 NULL
, /* capi_fasync */
474 /* -------- init function and module interface ---------------------- */
477 #define capi_init init_module
480 static struct capi_interface_user cuser
= {
487 memset(capidevs
, 0, sizeof(capidevs
));
489 if (register_chrdev(capi_major
, "capi20", &capi_fops
)) {
490 printk(KERN_ERR
"capi20: unable to get major %d\n", capi_major
);
493 printk(KERN_NOTICE
"capi20: started up with major %d\n", capi_major
);
495 if ((capifuncs
= attach_capi_interface(&cuser
)) == 0) {
496 unregister_chrdev(capi_major
, "capi20");
503 void cleanup_module(void)
505 unregister_chrdev(capi_major
, "capi20");
506 (void) detach_capi_interface(&cuser
);