blob: ef564ee1c06ca70a86922c04503fc45abee9932c [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/* $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
Robert P. J. Day37772ac2008-04-28 02:14:42 -070013#define AVMB1_COMPAT
Linus Torvalds1da177e2005-04-16 15:20:36 -070014
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>
Alexey Dobriyand43c36d2009-10-07 17:09:06 +040021#include <linux/sched.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070022#include <linux/seq_file.h>
23#include <linux/skbuff.h>
24#include <linux/workqueue.h>
25#include <linux/capi.h>
26#include <linux/kernelcapi.h>
27#include <linux/init.h>
28#include <linux/moduleparam.h>
29#include <linux/delay.h>
30#include <asm/uaccess.h>
31#include <linux/isdn/capicmd.h>
32#include <linux/isdn/capiutil.h>
Robert P. J. Day37772ac2008-04-28 02:14:42 -070033#ifdef AVMB1_COMPAT
Linus Torvalds1da177e2005-04-16 15:20:36 -070034#include <linux/b1lli.h>
35#endif
Arjan van de Ven9cdf1822006-03-23 03:00:21 -080036#include <linux/mutex.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070037
Linus Torvalds1da177e2005-04-16 15:20:36 -070038static int showcapimsgs = 0;
39
40MODULE_DESCRIPTION("CAPI4Linux: kernel CAPI layer");
41MODULE_AUTHOR("Carsten Paeth");
42MODULE_LICENSE("GPL");
43module_param(showcapimsgs, uint, 0);
44
45/* ------------------------------------------------------------- */
46
47struct capi_notifier {
48 struct work_struct work;
49 unsigned int cmd;
50 u32 controller;
51 u16 applid;
52 u32 ncci;
53};
54
55/* ------------------------------------------------------------- */
56
57static struct capi_version driver_version = {2, 0, 1, 1<<4};
58static char driver_serial[CAPI_SERIAL_LEN] = "0004711";
59static char capi_manufakturer[64] = "AVM Berlin";
60
61#define NCCI2CTRL(ncci) (((ncci) >> 24) & 0x7f)
62
63LIST_HEAD(capi_drivers);
64DEFINE_RWLOCK(capi_drivers_list_lock);
65
66static DEFINE_RWLOCK(application_lock);
Arjan van de Ven9cdf1822006-03-23 03:00:21 -080067static DEFINE_MUTEX(controller_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -070068
69struct capi20_appl *capi_applications[CAPI_MAXAPPL];
70struct capi_ctr *capi_cards[CAPI_MAXCONTR];
71
72static int ncards;
73
74/* -------- controller ref counting -------------------------------------- */
75
76static inline struct capi_ctr *
77capi_ctr_get(struct capi_ctr *card)
78{
79 if (!try_module_get(card->owner))
80 return NULL;
81 return card;
82}
83
84static inline void
85capi_ctr_put(struct capi_ctr *card)
86{
87 module_put(card->owner);
88}
89
90/* ------------------------------------------------------------- */
91
92static inline struct capi_ctr *get_capi_ctr_by_nr(u16 contr)
93{
94 if (contr - 1 >= CAPI_MAXCONTR)
95 return NULL;
96
97 return capi_cards[contr - 1];
98}
99
100static inline struct capi20_appl *get_capi_appl_by_nr(u16 applid)
101{
102 if (applid - 1 >= CAPI_MAXAPPL)
103 return NULL;
104
105 return capi_applications[applid - 1];
106}
107
108/* -------- util functions ------------------------------------ */
109
110static inline int capi_cmd_valid(u8 cmd)
111{
112 switch (cmd) {
113 case CAPI_ALERT:
114 case CAPI_CONNECT:
115 case CAPI_CONNECT_ACTIVE:
116 case CAPI_CONNECT_B3_ACTIVE:
117 case CAPI_CONNECT_B3:
118 case CAPI_CONNECT_B3_T90_ACTIVE:
119 case CAPI_DATA_B3:
120 case CAPI_DISCONNECT_B3:
121 case CAPI_DISCONNECT:
122 case CAPI_FACILITY:
123 case CAPI_INFO:
124 case CAPI_LISTEN:
125 case CAPI_MANUFACTURER:
126 case CAPI_RESET_B3:
127 case CAPI_SELECT_B_PROTOCOL:
128 return 1;
129 }
130 return 0;
131}
132
133static inline int capi_subcmd_valid(u8 subcmd)
134{
135 switch (subcmd) {
136 case CAPI_REQ:
137 case CAPI_CONF:
138 case CAPI_IND:
139 case CAPI_RESP:
140 return 1;
141 }
142 return 0;
143}
144
145/* ------------------------------------------------------------ */
146
147static void register_appl(struct capi_ctr *card, u16 applid, capi_register_params *rparam)
148{
149 card = capi_ctr_get(card);
150
151 if (card)
152 card->register_appl(card, applid, rparam);
153 else
Harvey Harrison156f1ed2008-04-28 02:14:40 -0700154 printk(KERN_WARNING "%s: cannot get card resources\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700155}
156
157
158static void release_appl(struct capi_ctr *card, u16 applid)
159{
160 DBG("applid %#x", applid);
161
162 card->release_appl(card, applid);
163 capi_ctr_put(card);
164}
165
166/* -------- KCI_CONTRUP --------------------------------------- */
167
168static void notify_up(u32 contr)
169{
170 struct capi_ctr *card = get_capi_ctr_by_nr(contr);
171 struct capi20_appl *ap;
172 u16 applid;
173
174 if (showcapimsgs & 1) {
175 printk(KERN_DEBUG "kcapi: notify up contr %d\n", contr);
176 }
177 if (!card) {
Harvey Harrison156f1ed2008-04-28 02:14:40 -0700178 printk(KERN_WARNING "%s: invalid contr %d\n", __func__, contr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700179 return;
180 }
181 for (applid = 1; applid <= CAPI_MAXAPPL; applid++) {
182 ap = get_capi_appl_by_nr(applid);
183 if (!ap || ap->release_in_progress) continue;
184 register_appl(card, applid, &ap->rparam);
185 if (ap->callback && !ap->release_in_progress)
186 ap->callback(KCI_CONTRUP, contr, &card->profile);
187 }
188}
189
190/* -------- KCI_CONTRDOWN ------------------------------------- */
191
192static void notify_down(u32 contr)
193{
194 struct capi20_appl *ap;
195 u16 applid;
196
197 if (showcapimsgs & 1) {
198 printk(KERN_DEBUG "kcapi: notify down contr %d\n", contr);
199 }
200
201 for (applid = 1; applid <= CAPI_MAXAPPL; applid++) {
202 ap = get_capi_appl_by_nr(applid);
203 if (ap && ap->callback && !ap->release_in_progress)
204 ap->callback(KCI_CONTRDOWN, contr, NULL);
205 }
206}
207
David Howellsc4028952006-11-22 14:57:56 +0000208static void notify_handler(struct work_struct *work)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700209{
David Howellsc4028952006-11-22 14:57:56 +0000210 struct capi_notifier *np =
211 container_of(work, struct capi_notifier, work);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700212
213 switch (np->cmd) {
214 case KCI_CONTRUP:
215 notify_up(np->controller);
216 break;
217 case KCI_CONTRDOWN:
218 notify_down(np->controller);
219 break;
220 }
221
222 kfree(np);
223}
224
225/*
226 * The notifier will result in adding/deleteing of devices. Devices can
227 * only removed in user process, not in bh.
228 */
229static int notify_push(unsigned int cmd, u32 controller, u16 applid, u32 ncci)
230{
231 struct capi_notifier *np = kmalloc(sizeof(*np), GFP_ATOMIC);
232
233 if (!np)
234 return -ENOMEM;
235
David Howellsc4028952006-11-22 14:57:56 +0000236 INIT_WORK(&np->work, notify_handler);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700237 np->cmd = cmd;
238 np->controller = controller;
239 np->applid = applid;
240 np->ncci = ncci;
241
242 schedule_work(&np->work);
243 return 0;
244}
245
246
247/* -------- Receiver ------------------------------------------ */
248
David Howellsc4028952006-11-22 14:57:56 +0000249static void recv_handler(struct work_struct *work)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700250{
251 struct sk_buff *skb;
David Howellsc4028952006-11-22 14:57:56 +0000252 struct capi20_appl *ap =
253 container_of(work, struct capi20_appl, recv_work);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700254
255 if ((!ap) || (ap->release_in_progress))
256 return;
257
Matthias Kaehlcke67837f22007-07-17 04:04:16 -0700258 mutex_lock(&ap->recv_mtx);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700259 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 }
Matthias Kaehlcke67837f22007-07-17 04:04:16 -0700267 mutex_unlock(&ap->recv_mtx);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700268}
269
Tilman Schmidt554f2002009-04-23 02:24:21 +0000270/**
271 * capi_ctr_handle_message() - handle incoming CAPI message
272 * @card: controller descriptor structure.
273 * @appl: application ID.
274 * @skb: message.
275 *
276 * Called by hardware driver to pass a CAPI message to the application.
277 */
278
Linus Torvalds1da177e2005-04-16 15:20:36 -0700279void capi_ctr_handle_message(struct capi_ctr * card, u16 appl, struct sk_buff *skb)
280{
281 struct capi20_appl *ap;
282 int showctl = 0;
283 u8 cmd, subcmd;
284 unsigned long flags;
Karsten Keil17f0cd22007-02-28 20:13:50 -0800285 _cdebbuf *cdb;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700286
287 if (card->cardstate != CARD_RUNNING) {
Karsten Keil17f0cd22007-02-28 20:13:50 -0800288 cdb = capi_message2str(skb->data);
289 if (cdb) {
290 printk(KERN_INFO "kcapi: controller [%03d] not active, got: %s",
291 card->cnr, cdb->buf);
292 cdebbuf_free(cdb);
293 } else
294 printk(KERN_INFO "kcapi: controller [%03d] not active, cannot trace\n",
295 card->cnr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700296 goto error;
297 }
298
299 cmd = CAPIMSG_COMMAND(skb->data);
300 subcmd = CAPIMSG_SUBCOMMAND(skb->data);
301 if (cmd == CAPI_DATA_B3 && subcmd == CAPI_IND) {
302 card->nrecvdatapkt++;
303 if (card->traceflag > 2) showctl |= 2;
304 } else {
305 card->nrecvctlpkt++;
306 if (card->traceflag) showctl |= 2;
307 }
308 showctl |= (card->traceflag & 1);
309 if (showctl & 2) {
310 if (showctl & 1) {
Karsten Keil17f0cd22007-02-28 20:13:50 -0800311 printk(KERN_DEBUG "kcapi: got [%03d] id#%d %s len=%u\n",
312 card->cnr, CAPIMSG_APPID(skb->data),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700313 capi_cmd2str(cmd, subcmd),
314 CAPIMSG_LEN(skb->data));
315 } else {
Karsten Keil17f0cd22007-02-28 20:13:50 -0800316 cdb = capi_message2str(skb->data);
317 if (cdb) {
318 printk(KERN_DEBUG "kcapi: got [%03d] %s\n",
319 card->cnr, cdb->buf);
320 cdebbuf_free(cdb);
321 } else
322 printk(KERN_DEBUG "kcapi: got [%03d] id#%d %s len=%u, cannot trace\n",
323 card->cnr, CAPIMSG_APPID(skb->data),
324 capi_cmd2str(cmd, subcmd),
325 CAPIMSG_LEN(skb->data));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700326 }
327
328 }
329
330 read_lock_irqsave(&application_lock, flags);
331 ap = get_capi_appl_by_nr(CAPIMSG_APPID(skb->data));
332 if ((!ap) || (ap->release_in_progress)) {
333 read_unlock_irqrestore(&application_lock, flags);
Karsten Keil17f0cd22007-02-28 20:13:50 -0800334 cdb = capi_message2str(skb->data);
335 if (cdb) {
336 printk(KERN_ERR "kcapi: handle_message: applid %d state released (%s)\n",
337 CAPIMSG_APPID(skb->data), cdb->buf);
338 cdebbuf_free(cdb);
339 } else
340 printk(KERN_ERR "kcapi: handle_message: applid %d state released (%s) cannot trace\n",
341 CAPIMSG_APPID(skb->data),
342 capi_cmd2str(cmd, subcmd));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700343 goto error;
344 }
345 skb_queue_tail(&ap->recv_queue, skb);
346 schedule_work(&ap->recv_work);
347 read_unlock_irqrestore(&application_lock, flags);
348
349 return;
350
351error:
352 kfree_skb(skb);
353}
354
355EXPORT_SYMBOL(capi_ctr_handle_message);
356
Tilman Schmidt554f2002009-04-23 02:24:21 +0000357/**
358 * capi_ctr_ready() - signal CAPI controller ready
359 * @card: controller descriptor structure.
360 *
361 * Called by hardware driver to signal that the controller is up and running.
362 */
363
Linus Torvalds1da177e2005-04-16 15:20:36 -0700364void capi_ctr_ready(struct capi_ctr * card)
365{
366 card->cardstate = CARD_RUNNING;
367
Karsten Keil17f0cd22007-02-28 20:13:50 -0800368 printk(KERN_NOTICE "kcapi: card [%03d] \"%s\" ready.\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700369 card->cnr, card->name);
370
371 notify_push(KCI_CONTRUP, card->cnr, 0, 0);
372}
373
374EXPORT_SYMBOL(capi_ctr_ready);
375
Tilman Schmidt554f2002009-04-23 02:24:21 +0000376/**
Tilman Schmidt4e329972009-06-07 09:09:23 +0000377 * capi_ctr_down() - signal CAPI controller not ready
Tilman Schmidt554f2002009-04-23 02:24:21 +0000378 * @card: controller descriptor structure.
379 *
380 * Called by hardware driver to signal that the controller is down and
381 * unavailable for use.
382 */
383
Tilman Schmidt4e329972009-06-07 09:09:23 +0000384void capi_ctr_down(struct capi_ctr * card)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700385{
386 u16 appl;
387
388 DBG("");
389
390 if (card->cardstate == CARD_DETECTED)
391 return;
392
393 card->cardstate = CARD_DETECTED;
394
395 memset(card->manu, 0, sizeof(card->manu));
396 memset(&card->version, 0, sizeof(card->version));
397 memset(&card->profile, 0, sizeof(card->profile));
398 memset(card->serial, 0, sizeof(card->serial));
399
400 for (appl = 1; appl <= CAPI_MAXAPPL; appl++) {
401 struct capi20_appl *ap = get_capi_appl_by_nr(appl);
402 if (!ap || ap->release_in_progress)
403 continue;
404
405 capi_ctr_put(card);
406 }
407
Karsten Keil17f0cd22007-02-28 20:13:50 -0800408 printk(KERN_NOTICE "kcapi: card [%03d] down.\n", card->cnr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700409
410 notify_push(KCI_CONTRDOWN, card->cnr, 0, 0);
411}
412
Tilman Schmidt4e329972009-06-07 09:09:23 +0000413EXPORT_SYMBOL(capi_ctr_down);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700414
Tilman Schmidt554f2002009-04-23 02:24:21 +0000415/**
416 * capi_ctr_suspend_output() - suspend controller
417 * @card: controller descriptor structure.
418 *
419 * Called by hardware driver to stop data flow.
420 */
421
Linus Torvalds1da177e2005-04-16 15:20:36 -0700422void capi_ctr_suspend_output(struct capi_ctr *card)
423{
424 if (!card->blocked) {
Karsten Keil17f0cd22007-02-28 20:13:50 -0800425 printk(KERN_DEBUG "kcapi: card [%03d] suspend\n", card->cnr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700426 card->blocked = 1;
427 }
428}
429
430EXPORT_SYMBOL(capi_ctr_suspend_output);
431
Tilman Schmidt554f2002009-04-23 02:24:21 +0000432/**
433 * capi_ctr_resume_output() - resume controller
434 * @card: controller descriptor structure.
435 *
436 * Called by hardware driver to resume data flow.
437 */
438
Linus Torvalds1da177e2005-04-16 15:20:36 -0700439void capi_ctr_resume_output(struct capi_ctr *card)
440{
441 if (card->blocked) {
Karsten Keil17f0cd22007-02-28 20:13:50 -0800442 printk(KERN_DEBUG "kcapi: card [%03d] resume\n", card->cnr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700443 card->blocked = 0;
444 }
445}
446
447EXPORT_SYMBOL(capi_ctr_resume_output);
448
449/* ------------------------------------------------------------- */
450
Tilman Schmidt554f2002009-04-23 02:24:21 +0000451/**
452 * attach_capi_ctr() - register CAPI controller
453 * @card: controller descriptor structure.
454 *
455 * Called by hardware driver to register a controller with the CAPI subsystem.
456 * Return value: 0 on success, error code < 0 on error
457 */
458
Linus Torvalds1da177e2005-04-16 15:20:36 -0700459int
460attach_capi_ctr(struct capi_ctr *card)
461{
462 int i;
463
Arjan van de Ven9cdf1822006-03-23 03:00:21 -0800464 mutex_lock(&controller_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700465
466 for (i = 0; i < CAPI_MAXCONTR; i++) {
467 if (capi_cards[i] == NULL)
468 break;
469 }
470 if (i == CAPI_MAXCONTR) {
Arjan van de Ven9cdf1822006-03-23 03:00:21 -0800471 mutex_unlock(&controller_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700472 printk(KERN_ERR "kcapi: out of controller slots\n");
473 return -EBUSY;
474 }
475 capi_cards[i] = card;
476
Arjan van de Ven9cdf1822006-03-23 03:00:21 -0800477 mutex_unlock(&controller_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700478
479 card->nrecvctlpkt = 0;
480 card->nrecvdatapkt = 0;
481 card->nsentctlpkt = 0;
482 card->nsentdatapkt = 0;
483 card->cnr = i + 1;
484 card->cardstate = CARD_DETECTED;
485 card->blocked = 0;
486 card->traceflag = showcapimsgs;
487
488 sprintf(card->procfn, "capi/controllers/%d", card->cnr);
Alexey Dobriyan9a58a802010-01-14 03:10:54 -0800489 card->procent = proc_create_data(card->procfn, 0, NULL, card->proc_fops, card);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700490
491 ncards++;
Karsten Keil17f0cd22007-02-28 20:13:50 -0800492 printk(KERN_NOTICE "kcapi: Controller [%03d]: %s attached\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700493 card->cnr, card->name);
494 return 0;
495}
496
497EXPORT_SYMBOL(attach_capi_ctr);
498
Tilman Schmidt554f2002009-04-23 02:24:21 +0000499/**
500 * detach_capi_ctr() - unregister CAPI controller
501 * @card: controller descriptor structure.
502 *
503 * Called by hardware driver to remove the registration of a controller
504 * with the CAPI subsystem.
505 * Return value: 0 on success, error code < 0 on error
506 */
507
Linus Torvalds1da177e2005-04-16 15:20:36 -0700508int detach_capi_ctr(struct capi_ctr *card)
509{
510 if (card->cardstate != CARD_DETECTED)
Tilman Schmidt4e329972009-06-07 09:09:23 +0000511 capi_ctr_down(card);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700512
513 ncards--;
514
515 if (card->procent) {
516 remove_proc_entry(card->procfn, NULL);
517 card->procent = NULL;
518 }
519 capi_cards[card->cnr - 1] = NULL;
Karsten Keil17f0cd22007-02-28 20:13:50 -0800520 printk(KERN_NOTICE "kcapi: Controller [%03d]: %s unregistered\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700521 card->cnr, card->name);
522
523 return 0;
524}
525
526EXPORT_SYMBOL(detach_capi_ctr);
527
Tilman Schmidt554f2002009-04-23 02:24:21 +0000528/**
529 * register_capi_driver() - register CAPI driver
530 * @driver: driver descriptor structure.
531 *
532 * Called by hardware driver to register itself with the CAPI subsystem.
533 */
534
Linus Torvalds1da177e2005-04-16 15:20:36 -0700535void register_capi_driver(struct capi_driver *driver)
536{
537 unsigned long flags;
538
539 write_lock_irqsave(&capi_drivers_list_lock, flags);
540 list_add_tail(&driver->list, &capi_drivers);
541 write_unlock_irqrestore(&capi_drivers_list_lock, flags);
542}
543
544EXPORT_SYMBOL(register_capi_driver);
545
Tilman Schmidt554f2002009-04-23 02:24:21 +0000546/**
547 * unregister_capi_driver() - unregister CAPI driver
548 * @driver: driver descriptor structure.
549 *
550 * Called by hardware driver to unregister itself from the CAPI subsystem.
551 */
552
Linus Torvalds1da177e2005-04-16 15:20:36 -0700553void unregister_capi_driver(struct capi_driver *driver)
554{
555 unsigned long flags;
556
557 write_lock_irqsave(&capi_drivers_list_lock, flags);
558 list_del(&driver->list);
559 write_unlock_irqrestore(&capi_drivers_list_lock, flags);
560}
561
562EXPORT_SYMBOL(unregister_capi_driver);
563
564/* ------------------------------------------------------------- */
565/* -------- CAPI2.0 Interface ---------------------------------- */
566/* ------------------------------------------------------------- */
567
Tilman Schmidt554f2002009-04-23 02:24:21 +0000568/**
569 * capi20_isinstalled() - CAPI 2.0 operation CAPI_INSTALLED
570 *
571 * Return value: CAPI result code (CAPI_NOERROR if at least one ISDN controller
572 * is ready for use, CAPI_REGNOTINSTALLED otherwise)
573 */
574
Linus Torvalds1da177e2005-04-16 15:20:36 -0700575u16 capi20_isinstalled(void)
576{
577 int i;
578 for (i = 0; i < CAPI_MAXCONTR; i++) {
579 if (capi_cards[i] && capi_cards[i]->cardstate == CARD_RUNNING)
580 return CAPI_NOERROR;
581 }
582 return CAPI_REGNOTINSTALLED;
583}
584
585EXPORT_SYMBOL(capi20_isinstalled);
586
Tilman Schmidt554f2002009-04-23 02:24:21 +0000587/**
588 * capi20_register() - CAPI 2.0 operation CAPI_REGISTER
589 * @ap: CAPI application descriptor structure.
590 *
591 * Register an application's presence with CAPI.
592 * A unique application ID is assigned and stored in @ap->applid.
593 * After this function returns successfully, the message receive
594 * callback function @ap->recv_message() may be called at any time
595 * until capi20_release() has been called for the same @ap.
596 * Return value: CAPI result code
597 */
598
Linus Torvalds1da177e2005-04-16 15:20:36 -0700599u16 capi20_register(struct capi20_appl *ap)
600{
601 int i;
602 u16 applid;
603 unsigned long flags;
604
605 DBG("");
606
607 if (ap->rparam.datablklen < 128)
608 return CAPI_LOGBLKSIZETOSMALL;
609
610 write_lock_irqsave(&application_lock, flags);
611
612 for (applid = 1; applid <= CAPI_MAXAPPL; applid++) {
613 if (capi_applications[applid - 1] == NULL)
614 break;
615 }
616 if (applid > CAPI_MAXAPPL) {
617 write_unlock_irqrestore(&application_lock, flags);
618 return CAPI_TOOMANYAPPLS;
619 }
620
621 ap->applid = applid;
622 capi_applications[applid - 1] = ap;
623
624 ap->nrecvctlpkt = 0;
625 ap->nrecvdatapkt = 0;
626 ap->nsentctlpkt = 0;
627 ap->nsentdatapkt = 0;
628 ap->callback = NULL;
Matthias Kaehlcke67837f22007-07-17 04:04:16 -0700629 mutex_init(&ap->recv_mtx);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700630 skb_queue_head_init(&ap->recv_queue);
David Howellsc4028952006-11-22 14:57:56 +0000631 INIT_WORK(&ap->recv_work, recv_handler);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700632 ap->release_in_progress = 0;
633
634 write_unlock_irqrestore(&application_lock, flags);
635
Arjan van de Ven9cdf1822006-03-23 03:00:21 -0800636 mutex_lock(&controller_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700637 for (i = 0; i < CAPI_MAXCONTR; i++) {
638 if (!capi_cards[i] || capi_cards[i]->cardstate != CARD_RUNNING)
639 continue;
640 register_appl(capi_cards[i], applid, &ap->rparam);
641 }
Arjan van de Ven9cdf1822006-03-23 03:00:21 -0800642 mutex_unlock(&controller_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700643
644 if (showcapimsgs & 1) {
645 printk(KERN_DEBUG "kcapi: appl %d up\n", applid);
646 }
647
648 return CAPI_NOERROR;
649}
650
651EXPORT_SYMBOL(capi20_register);
652
Tilman Schmidt554f2002009-04-23 02:24:21 +0000653/**
654 * capi20_release() - CAPI 2.0 operation CAPI_RELEASE
655 * @ap: CAPI application descriptor structure.
656 *
657 * Terminate an application's registration with CAPI.
658 * After this function returns successfully, the message receive
659 * callback function @ap->recv_message() will no longer be called.
660 * Return value: CAPI result code
661 */
662
Linus Torvalds1da177e2005-04-16 15:20:36 -0700663u16 capi20_release(struct capi20_appl *ap)
664{
665 int i;
666 unsigned long flags;
667
668 DBG("applid %#x", ap->applid);
669
670 write_lock_irqsave(&application_lock, flags);
671 ap->release_in_progress = 1;
672 capi_applications[ap->applid - 1] = NULL;
673 write_unlock_irqrestore(&application_lock, flags);
674
Arjan van de Ven9cdf1822006-03-23 03:00:21 -0800675 mutex_lock(&controller_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700676 for (i = 0; i < CAPI_MAXCONTR; i++) {
677 if (!capi_cards[i] || capi_cards[i]->cardstate != CARD_RUNNING)
678 continue;
679 release_appl(capi_cards[i], ap->applid);
680 }
Arjan van de Ven9cdf1822006-03-23 03:00:21 -0800681 mutex_unlock(&controller_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700682
683 flush_scheduled_work();
684 skb_queue_purge(&ap->recv_queue);
685
686 if (showcapimsgs & 1) {
687 printk(KERN_DEBUG "kcapi: appl %d down\n", ap->applid);
688 }
689
690 return CAPI_NOERROR;
691}
692
693EXPORT_SYMBOL(capi20_release);
694
Tilman Schmidt554f2002009-04-23 02:24:21 +0000695/**
696 * capi20_put_message() - CAPI 2.0 operation CAPI_PUT_MESSAGE
697 * @ap: CAPI application descriptor structure.
698 * @skb: CAPI message.
699 *
700 * Transfer a single message to CAPI.
701 * Return value: CAPI result code
702 */
703
Linus Torvalds1da177e2005-04-16 15:20:36 -0700704u16 capi20_put_message(struct capi20_appl *ap, struct sk_buff *skb)
705{
706 struct capi_ctr *card;
707 int showctl = 0;
708 u8 cmd, subcmd;
709
710 DBG("applid %#x", ap->applid);
711
712 if (ncards == 0)
713 return CAPI_REGNOTINSTALLED;
714 if ((ap->applid == 0) || ap->release_in_progress)
715 return CAPI_ILLAPPNR;
716 if (skb->len < 12
717 || !capi_cmd_valid(CAPIMSG_COMMAND(skb->data))
718 || !capi_subcmd_valid(CAPIMSG_SUBCOMMAND(skb->data)))
719 return CAPI_ILLCMDORSUBCMDORMSGTOSMALL;
720 card = get_capi_ctr_by_nr(CAPIMSG_CONTROLLER(skb->data));
721 if (!card || card->cardstate != CARD_RUNNING) {
722 card = get_capi_ctr_by_nr(1); // XXX why?
723 if (!card || card->cardstate != CARD_RUNNING)
724 return CAPI_REGNOTINSTALLED;
725 }
726 if (card->blocked)
727 return CAPI_SENDQUEUEFULL;
728
729 cmd = CAPIMSG_COMMAND(skb->data);
730 subcmd = CAPIMSG_SUBCOMMAND(skb->data);
731
732 if (cmd == CAPI_DATA_B3 && subcmd== CAPI_REQ) {
733 card->nsentdatapkt++;
734 ap->nsentdatapkt++;
735 if (card->traceflag > 2) showctl |= 2;
736 } else {
737 card->nsentctlpkt++;
738 ap->nsentctlpkt++;
739 if (card->traceflag) showctl |= 2;
740 }
741 showctl |= (card->traceflag & 1);
742 if (showctl & 2) {
743 if (showctl & 1) {
Karsten Keil17f0cd22007-02-28 20:13:50 -0800744 printk(KERN_DEBUG "kcapi: put [%03d] id#%d %s len=%u\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700745 CAPIMSG_CONTROLLER(skb->data),
746 CAPIMSG_APPID(skb->data),
747 capi_cmd2str(cmd, subcmd),
748 CAPIMSG_LEN(skb->data));
749 } else {
Karsten Keil17f0cd22007-02-28 20:13:50 -0800750 _cdebbuf *cdb = capi_message2str(skb->data);
751 if (cdb) {
752 printk(KERN_DEBUG "kcapi: put [%03d] %s\n",
753 CAPIMSG_CONTROLLER(skb->data),
754 cdb->buf);
755 cdebbuf_free(cdb);
756 } else
757 printk(KERN_DEBUG "kcapi: put [%03d] id#%d %s len=%u cannot trace\n",
758 CAPIMSG_CONTROLLER(skb->data),
759 CAPIMSG_APPID(skb->data),
760 capi_cmd2str(cmd, subcmd),
761 CAPIMSG_LEN(skb->data));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700763 }
764 return card->send_message(card, skb);
765}
766
767EXPORT_SYMBOL(capi20_put_message);
768
Tilman Schmidt554f2002009-04-23 02:24:21 +0000769/**
770 * capi20_get_manufacturer() - CAPI 2.0 operation CAPI_GET_MANUFACTURER
771 * @contr: controller number.
772 * @buf: result buffer (64 bytes).
773 *
774 * Retrieve information about the manufacturer of the specified ISDN controller
775 * or (for @contr == 0) the driver itself.
776 * Return value: CAPI result code
777 */
778
Linus Torvalds1da177e2005-04-16 15:20:36 -0700779u16 capi20_get_manufacturer(u32 contr, u8 *buf)
780{
781 struct capi_ctr *card;
782
783 if (contr == 0) {
784 strlcpy(buf, capi_manufakturer, CAPI_MANUFACTURER_LEN);
785 return CAPI_NOERROR;
786 }
787 card = get_capi_ctr_by_nr(contr);
788 if (!card || card->cardstate != CARD_RUNNING)
789 return CAPI_REGNOTINSTALLED;
790 strlcpy(buf, card->manu, CAPI_MANUFACTURER_LEN);
791 return CAPI_NOERROR;
792}
793
794EXPORT_SYMBOL(capi20_get_manufacturer);
795
Tilman Schmidt554f2002009-04-23 02:24:21 +0000796/**
797 * capi20_get_version() - CAPI 2.0 operation CAPI_GET_VERSION
798 * @contr: controller number.
799 * @verp: result structure.
800 *
801 * Retrieve version information for the specified ISDN controller
802 * or (for @contr == 0) the driver itself.
803 * Return value: CAPI result code
804 */
805
Linus Torvalds1da177e2005-04-16 15:20:36 -0700806u16 capi20_get_version(u32 contr, struct capi_version *verp)
807{
808 struct capi_ctr *card;
809
810 if (contr == 0) {
811 *verp = driver_version;
812 return CAPI_NOERROR;
813 }
814 card = get_capi_ctr_by_nr(contr);
815 if (!card || card->cardstate != CARD_RUNNING)
816 return CAPI_REGNOTINSTALLED;
817
818 memcpy((void *) verp, &card->version, sizeof(capi_version));
819 return CAPI_NOERROR;
820}
821
822EXPORT_SYMBOL(capi20_get_version);
823
Tilman Schmidt554f2002009-04-23 02:24:21 +0000824/**
825 * capi20_get_serial() - CAPI 2.0 operation CAPI_GET_SERIAL_NUMBER
826 * @contr: controller number.
827 * @serial: result buffer (8 bytes).
828 *
829 * Retrieve the serial number of the specified ISDN controller
830 * or (for @contr == 0) the driver itself.
831 * Return value: CAPI result code
832 */
833
Linus Torvalds1da177e2005-04-16 15:20:36 -0700834u16 capi20_get_serial(u32 contr, u8 *serial)
835{
836 struct capi_ctr *card;
837
838 if (contr == 0) {
839 strlcpy(serial, driver_serial, CAPI_SERIAL_LEN);
840 return CAPI_NOERROR;
841 }
842 card = get_capi_ctr_by_nr(contr);
843 if (!card || card->cardstate != CARD_RUNNING)
844 return CAPI_REGNOTINSTALLED;
845
846 strlcpy((void *) serial, card->serial, CAPI_SERIAL_LEN);
847 return CAPI_NOERROR;
848}
849
850EXPORT_SYMBOL(capi20_get_serial);
851
Tilman Schmidt554f2002009-04-23 02:24:21 +0000852/**
853 * capi20_get_profile() - CAPI 2.0 operation CAPI_GET_PROFILE
854 * @contr: controller number.
855 * @profp: result structure.
856 *
857 * Retrieve capability information for the specified ISDN controller
858 * or (for @contr == 0) the number of installed controllers.
859 * Return value: CAPI result code
860 */
861
Linus Torvalds1da177e2005-04-16 15:20:36 -0700862u16 capi20_get_profile(u32 contr, struct capi_profile *profp)
863{
864 struct capi_ctr *card;
865
866 if (contr == 0) {
867 profp->ncontroller = ncards;
868 return CAPI_NOERROR;
869 }
870 card = get_capi_ctr_by_nr(contr);
871 if (!card || card->cardstate != CARD_RUNNING)
872 return CAPI_REGNOTINSTALLED;
873
874 memcpy((void *) profp, &card->profile,
875 sizeof(struct capi_profile));
876 return CAPI_NOERROR;
877}
878
879EXPORT_SYMBOL(capi20_get_profile);
880
Robert P. J. Day37772ac2008-04-28 02:14:42 -0700881#ifdef AVMB1_COMPAT
Linus Torvalds1da177e2005-04-16 15:20:36 -0700882static int old_capi_manufacturer(unsigned int cmd, void __user *data)
883{
884 avmb1_loadandconfigdef ldef;
885 avmb1_extcarddef cdef;
886 avmb1_resetdef rdef;
887 capicardparams cparams;
888 struct capi_ctr *card;
889 struct capi_driver *driver = NULL;
890 capiloaddata ldata;
891 struct list_head *l;
892 unsigned long flags;
893 int retval;
894
895 switch (cmd) {
896 case AVMB1_ADDCARD:
897 case AVMB1_ADDCARD_WITH_TYPE:
898 if (cmd == AVMB1_ADDCARD) {
899 if ((retval = copy_from_user(&cdef, data,
900 sizeof(avmb1_carddef))))
901 return retval;
902 cdef.cardtype = AVM_CARDTYPE_B1;
903 } else {
904 if ((retval = copy_from_user(&cdef, data,
905 sizeof(avmb1_extcarddef))))
906 return retval;
907 }
908 cparams.port = cdef.port;
909 cparams.irq = cdef.irq;
910 cparams.cardnr = cdef.cardnr;
911
912 read_lock_irqsave(&capi_drivers_list_lock, flags);
913 switch (cdef.cardtype) {
914 case AVM_CARDTYPE_B1:
915 list_for_each(l, &capi_drivers) {
916 driver = list_entry(l, struct capi_driver, list);
917 if (strcmp(driver->name, "b1isa") == 0)
918 break;
919 }
920 break;
921 case AVM_CARDTYPE_T1:
922 list_for_each(l, &capi_drivers) {
923 driver = list_entry(l, struct capi_driver, list);
924 if (strcmp(driver->name, "t1isa") == 0)
925 break;
926 }
927 break;
928 default:
929 driver = NULL;
930 break;
931 }
932 if (!driver) {
933 read_unlock_irqrestore(&capi_drivers_list_lock, flags);
934 printk(KERN_ERR "kcapi: driver not loaded.\n");
935 return -EIO;
936 }
937 if (!driver->add_card) {
938 read_unlock_irqrestore(&capi_drivers_list_lock, flags);
939 printk(KERN_ERR "kcapi: driver has no add card function.\n");
940 return -EIO;
941 }
942
943 retval = driver->add_card(driver, &cparams);
944 read_unlock_irqrestore(&capi_drivers_list_lock, flags);
945 return retval;
946
947 case AVMB1_LOAD:
948 case AVMB1_LOAD_AND_CONFIG:
949
950 if (cmd == AVMB1_LOAD) {
951 if (copy_from_user(&ldef, data,
952 sizeof(avmb1_loaddef)))
953 return -EFAULT;
954 ldef.t4config.len = 0;
955 ldef.t4config.data = NULL;
956 } else {
957 if (copy_from_user(&ldef, data,
958 sizeof(avmb1_loadandconfigdef)))
959 return -EFAULT;
960 }
961 card = get_capi_ctr_by_nr(ldef.contr);
Jesper Juhle8a285b2007-10-16 01:27:52 -0700962 if (!card)
963 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700964 card = capi_ctr_get(card);
965 if (!card)
966 return -ESRCH;
Harvey Harrison2f9e9b62008-04-28 02:14:37 -0700967 if (card->load_firmware == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700968 printk(KERN_DEBUG "kcapi: load: no load function\n");
Julia Lawall4d5392c2008-09-22 19:04:54 -0700969 capi_ctr_put(card);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700970 return -ESRCH;
971 }
972
973 if (ldef.t4file.len <= 0) {
974 printk(KERN_DEBUG "kcapi: load: invalid parameter: length of t4file is %d ?\n", ldef.t4file.len);
Julia Lawall4d5392c2008-09-22 19:04:54 -0700975 capi_ctr_put(card);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700976 return -EINVAL;
977 }
Harvey Harrison2f9e9b62008-04-28 02:14:37 -0700978 if (ldef.t4file.data == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700979 printk(KERN_DEBUG "kcapi: load: invalid parameter: dataptr is 0\n");
Julia Lawall4d5392c2008-09-22 19:04:54 -0700980 capi_ctr_put(card);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700981 return -EINVAL;
982 }
983
984 ldata.firmware.user = 1;
985 ldata.firmware.data = ldef.t4file.data;
986 ldata.firmware.len = ldef.t4file.len;
987 ldata.configuration.user = 1;
988 ldata.configuration.data = ldef.t4config.data;
989 ldata.configuration.len = ldef.t4config.len;
990
991 if (card->cardstate != CARD_DETECTED) {
992 printk(KERN_INFO "kcapi: load: contr=%d not in detect state\n", ldef.contr);
Julia Lawall4d5392c2008-09-22 19:04:54 -0700993 capi_ctr_put(card);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700994 return -EBUSY;
995 }
996 card->cardstate = CARD_LOADING;
997
998 retval = card->load_firmware(card, &ldata);
999
1000 if (retval) {
1001 card->cardstate = CARD_DETECTED;
1002 capi_ctr_put(card);
1003 return retval;
1004 }
1005
1006 while (card->cardstate != CARD_RUNNING) {
1007
1008 msleep_interruptible(100); /* 0.1 sec */
1009
1010 if (signal_pending(current)) {
1011 capi_ctr_put(card);
1012 return -EINTR;
1013 }
1014 }
1015 capi_ctr_put(card);
1016 return 0;
1017
1018 case AVMB1_RESETCARD:
1019 if (copy_from_user(&rdef, data, sizeof(avmb1_resetdef)))
1020 return -EFAULT;
1021 card = get_capi_ctr_by_nr(rdef.contr);
1022 if (!card)
1023 return -ESRCH;
1024
1025 if (card->cardstate == CARD_DETECTED)
1026 return 0;
1027
1028 card->reset_ctr(card);
1029
1030 while (card->cardstate > CARD_DETECTED) {
1031
1032 msleep_interruptible(100); /* 0.1 sec */
1033
1034 if (signal_pending(current))
1035 return -EINTR;
1036 }
1037 return 0;
1038
1039 }
1040 return -EINVAL;
1041}
1042#endif
1043
Tilman Schmidt554f2002009-04-23 02:24:21 +00001044/**
1045 * capi20_manufacturer() - CAPI 2.0 operation CAPI_MANUFACTURER
1046 * @cmd: command.
1047 * @data: parameter.
1048 *
1049 * Perform manufacturer specific command.
1050 * Return value: CAPI result code
1051 */
1052
Linus Torvalds1da177e2005-04-16 15:20:36 -07001053int capi20_manufacturer(unsigned int cmd, void __user *data)
1054{
1055 struct capi_ctr *card;
1056
1057 switch (cmd) {
Robert P. J. Day37772ac2008-04-28 02:14:42 -07001058#ifdef AVMB1_COMPAT
Linus Torvalds1da177e2005-04-16 15:20:36 -07001059 case AVMB1_LOAD:
1060 case AVMB1_LOAD_AND_CONFIG:
1061 case AVMB1_RESETCARD:
1062 case AVMB1_GET_CARDINFO:
1063 case AVMB1_REMOVECARD:
1064 return old_capi_manufacturer(cmd, data);
1065#endif
1066 case KCAPI_CMD_TRACE:
1067 {
1068 kcapi_flagdef fdef;
1069
1070 if (copy_from_user(&fdef, data, sizeof(kcapi_flagdef)))
1071 return -EFAULT;
1072
1073 card = get_capi_ctr_by_nr(fdef.contr);
1074 if (!card)
1075 return -ESRCH;
1076
1077 card->traceflag = fdef.flag;
Karsten Keil17f0cd22007-02-28 20:13:50 -08001078 printk(KERN_INFO "kcapi: contr [%03d] set trace=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001079 card->cnr, card->traceflag);
1080 return 0;
1081 }
1082 case KCAPI_CMD_ADDCARD:
1083 {
1084 struct list_head *l;
1085 struct capi_driver *driver = NULL;
1086 capicardparams cparams;
1087 kcapi_carddef cdef;
1088 int retval;
1089
1090 if ((retval = copy_from_user(&cdef, data, sizeof(cdef))))
1091 return retval;
1092
1093 cparams.port = cdef.port;
1094 cparams.irq = cdef.irq;
1095 cparams.membase = cdef.membase;
1096 cparams.cardnr = cdef.cardnr;
1097 cparams.cardtype = 0;
1098 cdef.driver[sizeof(cdef.driver)-1] = 0;
1099
1100 list_for_each(l, &capi_drivers) {
1101 driver = list_entry(l, struct capi_driver, list);
1102 if (strcmp(driver->name, cdef.driver) == 0)
1103 break;
1104 }
Harvey Harrison2f9e9b62008-04-28 02:14:37 -07001105 if (driver == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001106 printk(KERN_ERR "kcapi: driver \"%s\" not loaded.\n",
1107 cdef.driver);
1108 return -ESRCH;
1109 }
1110
1111 if (!driver->add_card) {
1112 printk(KERN_ERR "kcapi: driver \"%s\" has no add card function.\n", cdef.driver);
1113 return -EIO;
1114 }
1115
1116 return driver->add_card(driver, &cparams);
1117 }
1118
1119 default:
1120 printk(KERN_ERR "kcapi: manufacturer command %d unknown.\n",
1121 cmd);
1122 break;
1123
1124 }
1125 return -EINVAL;
1126}
1127
1128EXPORT_SYMBOL(capi20_manufacturer);
1129
1130/* temporary hack */
Tilman Schmidt554f2002009-04-23 02:24:21 +00001131
1132/**
1133 * capi20_set_callback() - set CAPI application notification callback function
1134 * @ap: CAPI application descriptor structure.
1135 * @callback: callback function (NULL to remove).
1136 *
1137 * If not NULL, the callback function will be called to notify the
1138 * application of the addition or removal of a controller.
1139 * The first argument (cmd) will tell whether the controller was added
1140 * (KCI_CONTRUP) or removed (KCI_CONTRDOWN).
1141 * The second argument (contr) will be the controller number.
1142 * For cmd==KCI_CONTRUP the third argument (data) will be a pointer to the
1143 * new controller's capability profile structure.
1144 */
1145
Linus Torvalds1da177e2005-04-16 15:20:36 -07001146void capi20_set_callback(struct capi20_appl *ap,
1147 void (*callback) (unsigned int cmd, __u32 contr, void *data))
1148{
1149 ap->callback = callback;
1150}
1151
1152EXPORT_SYMBOL(capi20_set_callback);
1153
1154/* ------------------------------------------------------------- */
1155/* -------- Init & Cleanup ------------------------------------- */
1156/* ------------------------------------------------------------- */
1157
1158/*
1159 * init / exit functions
1160 */
1161
1162static int __init kcapi_init(void)
1163{
Jan Kiszka88549d62010-02-08 10:12:09 +00001164 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001165
Jan Kiszka88549d62010-02-08 10:12:09 +00001166 err = cdebug_init();
1167 if (!err)
1168 kcapi_proc_init();
1169 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001170}
1171
1172static void __exit kcapi_exit(void)
1173{
1174 kcapi_proc_exit();
1175
1176 /* make sure all notifiers are finished */
1177 flush_scheduled_work();
Karsten Keil17f0cd22007-02-28 20:13:50 -08001178 cdebug_exit();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001179}
1180
1181module_init(kcapi_init);
1182module_exit(kcapi_exit);