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 | #include "kcapi.h" |
14 | #include <linux/module.h> |
15 | #include <linux/mm.h> |
16 | #include <linux/interrupt.h> |
17 | #include <linux/ioport.h> |
18 | #include <linux/proc_fs.h> |
19 | #include <linux/sched/signal.h> |
20 | #include <linux/seq_file.h> |
21 | #include <linux/skbuff.h> |
22 | #include <linux/workqueue.h> |
23 | #include <linux/capi.h> |
24 | #include <linux/kernelcapi.h> |
25 | #include <linux/init.h> |
26 | #include <linux/moduleparam.h> |
27 | #include <linux/delay.h> |
28 | #include <linux/slab.h> |
29 | #include <linux/uaccess.h> |
30 | #include <linux/isdn/capicmd.h> |
31 | #include <linux/isdn/capiutil.h> |
32 | #include <linux/mutex.h> |
33 | #include <linux/rcupdate.h> |
34 | |
35 | static int showcapimsgs; |
36 | static struct workqueue_struct *kcapi_wq; |
37 | |
38 | module_param(showcapimsgs, uint, 0); |
39 | |
40 | /* ------------------------------------------------------------- */ |
41 | |
42 | struct capictr_event { |
43 | struct work_struct work; |
44 | unsigned int type; |
45 | u32 controller; |
46 | }; |
47 | |
48 | /* ------------------------------------------------------------- */ |
49 | |
50 | static const struct capi_version driver_version = {2, 0, 1, 1 << 4}; |
51 | static char driver_serial[CAPI_SERIAL_LEN] = "0004711" ; |
52 | static char capi_manufakturer[64] = "AVM Berlin" ; |
53 | |
54 | #define NCCI2CTRL(ncci) (((ncci) >> 24) & 0x7f) |
55 | |
56 | struct capi_ctr *capi_controller[CAPI_MAXCONTR]; |
57 | DEFINE_MUTEX(capi_controller_lock); |
58 | |
59 | struct capi20_appl *capi_applications[CAPI_MAXAPPL]; |
60 | |
61 | static int ncontrollers; |
62 | |
63 | /* -------- controller ref counting -------------------------------------- */ |
64 | |
65 | static inline struct capi_ctr * |
66 | capi_ctr_get(struct capi_ctr *ctr) |
67 | { |
68 | if (!try_module_get(module: ctr->owner)) |
69 | return NULL; |
70 | return ctr; |
71 | } |
72 | |
73 | static inline void |
74 | capi_ctr_put(struct capi_ctr *ctr) |
75 | { |
76 | module_put(module: ctr->owner); |
77 | } |
78 | |
79 | /* ------------------------------------------------------------- */ |
80 | |
81 | static inline struct capi_ctr *get_capi_ctr_by_nr(u16 contr) |
82 | { |
83 | if (contr < 1 || contr - 1 >= CAPI_MAXCONTR) |
84 | return NULL; |
85 | |
86 | return capi_controller[contr - 1]; |
87 | } |
88 | |
89 | static inline struct capi20_appl *__get_capi_appl_by_nr(u16 applid) |
90 | { |
91 | lockdep_assert_held(&capi_controller_lock); |
92 | |
93 | if (applid < 1 || applid - 1 >= CAPI_MAXAPPL) |
94 | return NULL; |
95 | |
96 | return capi_applications[applid - 1]; |
97 | } |
98 | |
99 | static inline struct capi20_appl *get_capi_appl_by_nr(u16 applid) |
100 | { |
101 | if (applid < 1 || applid - 1 >= CAPI_MAXAPPL) |
102 | return NULL; |
103 | |
104 | return rcu_dereference(capi_applications[applid - 1]); |
105 | } |
106 | |
107 | /* -------- util functions ------------------------------------ */ |
108 | |
109 | static inline int capi_cmd_valid(u8 cmd) |
110 | { |
111 | switch (cmd) { |
112 | case CAPI_ALERT: |
113 | case CAPI_CONNECT: |
114 | case CAPI_CONNECT_ACTIVE: |
115 | case CAPI_CONNECT_B3_ACTIVE: |
116 | case CAPI_CONNECT_B3: |
117 | case CAPI_CONNECT_B3_T90_ACTIVE: |
118 | case CAPI_DATA_B3: |
119 | case CAPI_DISCONNECT_B3: |
120 | case CAPI_DISCONNECT: |
121 | case CAPI_FACILITY: |
122 | case CAPI_INFO: |
123 | case CAPI_LISTEN: |
124 | case CAPI_MANUFACTURER: |
125 | case CAPI_RESET_B3: |
126 | case CAPI_SELECT_B_PROTOCOL: |
127 | return 1; |
128 | } |
129 | return 0; |
130 | } |
131 | |
132 | static inline int capi_subcmd_valid(u8 subcmd) |
133 | { |
134 | switch (subcmd) { |
135 | case CAPI_REQ: |
136 | case CAPI_CONF: |
137 | case CAPI_IND: |
138 | case CAPI_RESP: |
139 | return 1; |
140 | } |
141 | return 0; |
142 | } |
143 | |
144 | /* ------------------------------------------------------------ */ |
145 | |
146 | static void |
147 | register_appl(struct capi_ctr *ctr, u16 applid, capi_register_params *rparam) |
148 | { |
149 | ctr = capi_ctr_get(ctr); |
150 | |
151 | if (ctr) |
152 | ctr->register_appl(ctr, applid, rparam); |
153 | else |
154 | printk(KERN_WARNING "%s: cannot get controller resources\n" , |
155 | __func__); |
156 | } |
157 | |
158 | |
159 | static void release_appl(struct capi_ctr *ctr, u16 applid) |
160 | { |
161 | DBG("applid %#x" , applid); |
162 | |
163 | ctr->release_appl(ctr, applid); |
164 | capi_ctr_put(ctr); |
165 | } |
166 | |
167 | static void notify_up(u32 contr) |
168 | { |
169 | struct capi20_appl *ap; |
170 | struct capi_ctr *ctr; |
171 | u16 applid; |
172 | |
173 | mutex_lock(&capi_controller_lock); |
174 | |
175 | if (showcapimsgs & 1) |
176 | printk(KERN_DEBUG "kcapi: notify up contr %d\n" , contr); |
177 | |
178 | ctr = get_capi_ctr_by_nr(contr); |
179 | if (ctr) { |
180 | if (ctr->state == CAPI_CTR_RUNNING) |
181 | goto unlock_out; |
182 | |
183 | ctr->state = CAPI_CTR_RUNNING; |
184 | |
185 | for (applid = 1; applid <= CAPI_MAXAPPL; applid++) { |
186 | ap = __get_capi_appl_by_nr(applid); |
187 | if (ap) |
188 | register_appl(ctr, applid, rparam: &ap->rparam); |
189 | } |
190 | } else |
191 | printk(KERN_WARNING "%s: invalid contr %d\n" , __func__, contr); |
192 | |
193 | unlock_out: |
194 | mutex_unlock(lock: &capi_controller_lock); |
195 | } |
196 | |
197 | static void ctr_down(struct capi_ctr *ctr, int new_state) |
198 | { |
199 | struct capi20_appl *ap; |
200 | u16 applid; |
201 | |
202 | if (ctr->state == CAPI_CTR_DETECTED || ctr->state == CAPI_CTR_DETACHED) |
203 | return; |
204 | |
205 | ctr->state = new_state; |
206 | |
207 | memset(ctr->manu, 0, sizeof(ctr->manu)); |
208 | memset(&ctr->version, 0, sizeof(ctr->version)); |
209 | memset(&ctr->profile, 0, sizeof(ctr->profile)); |
210 | memset(ctr->serial, 0, sizeof(ctr->serial)); |
211 | |
212 | for (applid = 1; applid <= CAPI_MAXAPPL; applid++) { |
213 | ap = __get_capi_appl_by_nr(applid); |
214 | if (ap) |
215 | capi_ctr_put(ctr); |
216 | } |
217 | } |
218 | |
219 | static void notify_down(u32 contr) |
220 | { |
221 | struct capi_ctr *ctr; |
222 | |
223 | mutex_lock(&capi_controller_lock); |
224 | |
225 | if (showcapimsgs & 1) |
226 | printk(KERN_DEBUG "kcapi: notify down contr %d\n" , contr); |
227 | |
228 | ctr = get_capi_ctr_by_nr(contr); |
229 | if (ctr) |
230 | ctr_down(ctr, new_state: CAPI_CTR_DETECTED); |
231 | else |
232 | printk(KERN_WARNING "%s: invalid contr %d\n" , __func__, contr); |
233 | |
234 | mutex_unlock(lock: &capi_controller_lock); |
235 | } |
236 | |
237 | static void do_notify_work(struct work_struct *work) |
238 | { |
239 | struct capictr_event *event = |
240 | container_of(work, struct capictr_event, work); |
241 | |
242 | switch (event->type) { |
243 | case CAPICTR_UP: |
244 | notify_up(contr: event->controller); |
245 | break; |
246 | case CAPICTR_DOWN: |
247 | notify_down(contr: event->controller); |
248 | break; |
249 | } |
250 | |
251 | kfree(objp: event); |
252 | } |
253 | |
254 | static int notify_push(unsigned int event_type, u32 controller) |
255 | { |
256 | struct capictr_event *event = kmalloc(size: sizeof(*event), GFP_ATOMIC); |
257 | |
258 | if (!event) |
259 | return -ENOMEM; |
260 | |
261 | INIT_WORK(&event->work, do_notify_work); |
262 | event->type = event_type; |
263 | event->controller = controller; |
264 | |
265 | queue_work(wq: kcapi_wq, work: &event->work); |
266 | return 0; |
267 | } |
268 | |
269 | /* -------- Receiver ------------------------------------------ */ |
270 | |
271 | static void recv_handler(struct work_struct *work) |
272 | { |
273 | struct sk_buff *skb; |
274 | struct capi20_appl *ap = |
275 | container_of(work, struct capi20_appl, recv_work); |
276 | |
277 | if ((!ap) || (ap->release_in_progress)) |
278 | return; |
279 | |
280 | mutex_lock(&ap->recv_mtx); |
281 | while ((skb = skb_dequeue(list: &ap->recv_queue))) { |
282 | if (CAPIMSG_CMD(skb->data) == CAPI_DATA_B3_IND) |
283 | ap->nrecvdatapkt++; |
284 | else |
285 | ap->nrecvctlpkt++; |
286 | |
287 | ap->recv_message(ap, skb); |
288 | } |
289 | mutex_unlock(lock: &ap->recv_mtx); |
290 | } |
291 | |
292 | /** |
293 | * capi_ctr_handle_message() - handle incoming CAPI message |
294 | * @ctr: controller descriptor structure. |
295 | * @appl: application ID. |
296 | * @skb: message. |
297 | * |
298 | * Called by hardware driver to pass a CAPI message to the application. |
299 | */ |
300 | |
301 | void capi_ctr_handle_message(struct capi_ctr *ctr, u16 appl, |
302 | struct sk_buff *skb) |
303 | { |
304 | struct capi20_appl *ap; |
305 | int showctl = 0; |
306 | u8 cmd, subcmd; |
307 | _cdebbuf *cdb; |
308 | |
309 | if (ctr->state != CAPI_CTR_RUNNING) { |
310 | cdb = capi_message2str(msg: skb->data); |
311 | if (cdb) { |
312 | printk(KERN_INFO "kcapi: controller [%03d] not active, got: %s" , |
313 | ctr->cnr, cdb->buf); |
314 | cdebbuf_free(cdb); |
315 | } else |
316 | printk(KERN_INFO "kcapi: controller [%03d] not active, cannot trace\n" , |
317 | ctr->cnr); |
318 | goto error; |
319 | } |
320 | |
321 | cmd = CAPIMSG_COMMAND(skb->data); |
322 | subcmd = CAPIMSG_SUBCOMMAND(skb->data); |
323 | if (cmd == CAPI_DATA_B3 && subcmd == CAPI_IND) { |
324 | ctr->nrecvdatapkt++; |
325 | if (ctr->traceflag > 2) |
326 | showctl |= 2; |
327 | } else { |
328 | ctr->nrecvctlpkt++; |
329 | if (ctr->traceflag) |
330 | showctl |= 2; |
331 | } |
332 | showctl |= (ctr->traceflag & 1); |
333 | if (showctl & 2) { |
334 | if (showctl & 1) { |
335 | printk(KERN_DEBUG "kcapi: got [%03d] id#%d %s len=%u\n" , |
336 | ctr->cnr, CAPIMSG_APPID(skb->data), |
337 | capi_cmd2str(cmd, subcmd), |
338 | CAPIMSG_LEN(skb->data)); |
339 | } else { |
340 | cdb = capi_message2str(msg: skb->data); |
341 | if (cdb) { |
342 | printk(KERN_DEBUG "kcapi: got [%03d] %s\n" , |
343 | ctr->cnr, cdb->buf); |
344 | cdebbuf_free(cdb); |
345 | } else |
346 | printk(KERN_DEBUG "kcapi: got [%03d] id#%d %s len=%u, cannot trace\n" , |
347 | ctr->cnr, CAPIMSG_APPID(skb->data), |
348 | capi_cmd2str(cmd, subcmd), |
349 | CAPIMSG_LEN(skb->data)); |
350 | } |
351 | |
352 | } |
353 | |
354 | rcu_read_lock(); |
355 | ap = get_capi_appl_by_nr(CAPIMSG_APPID(skb->data)); |
356 | if (!ap) { |
357 | rcu_read_unlock(); |
358 | cdb = capi_message2str(msg: skb->data); |
359 | if (cdb) { |
360 | printk(KERN_ERR "kcapi: handle_message: applid %d state released (%s)\n" , |
361 | CAPIMSG_APPID(skb->data), cdb->buf); |
362 | cdebbuf_free(cdb); |
363 | } else |
364 | printk(KERN_ERR "kcapi: handle_message: applid %d state released (%s) cannot trace\n" , |
365 | CAPIMSG_APPID(skb->data), |
366 | capi_cmd2str(cmd, subcmd)); |
367 | goto error; |
368 | } |
369 | skb_queue_tail(list: &ap->recv_queue, newsk: skb); |
370 | queue_work(wq: kcapi_wq, work: &ap->recv_work); |
371 | rcu_read_unlock(); |
372 | |
373 | return; |
374 | |
375 | error: |
376 | kfree_skb(skb); |
377 | } |
378 | |
379 | EXPORT_SYMBOL(capi_ctr_handle_message); |
380 | |
381 | /** |
382 | * capi_ctr_ready() - signal CAPI controller ready |
383 | * @ctr: controller descriptor structure. |
384 | * |
385 | * Called by hardware driver to signal that the controller is up and running. |
386 | */ |
387 | |
388 | void capi_ctr_ready(struct capi_ctr *ctr) |
389 | { |
390 | printk(KERN_NOTICE "kcapi: controller [%03d] \"%s\" ready.\n" , |
391 | ctr->cnr, ctr->name); |
392 | |
393 | notify_push(CAPICTR_UP, controller: ctr->cnr); |
394 | } |
395 | |
396 | EXPORT_SYMBOL(capi_ctr_ready); |
397 | |
398 | /** |
399 | * capi_ctr_down() - signal CAPI controller not ready |
400 | * @ctr: controller descriptor structure. |
401 | * |
402 | * Called by hardware driver to signal that the controller is down and |
403 | * unavailable for use. |
404 | */ |
405 | |
406 | void capi_ctr_down(struct capi_ctr *ctr) |
407 | { |
408 | printk(KERN_NOTICE "kcapi: controller [%03d] down.\n" , ctr->cnr); |
409 | |
410 | notify_push(CAPICTR_DOWN, controller: ctr->cnr); |
411 | } |
412 | |
413 | EXPORT_SYMBOL(capi_ctr_down); |
414 | |
415 | /* ------------------------------------------------------------- */ |
416 | |
417 | /** |
418 | * attach_capi_ctr() - register CAPI controller |
419 | * @ctr: controller descriptor structure. |
420 | * |
421 | * Called by hardware driver to register a controller with the CAPI subsystem. |
422 | * Return value: 0 on success, error code < 0 on error |
423 | */ |
424 | |
425 | int attach_capi_ctr(struct capi_ctr *ctr) |
426 | { |
427 | int i; |
428 | |
429 | mutex_lock(&capi_controller_lock); |
430 | |
431 | for (i = 0; i < CAPI_MAXCONTR; i++) { |
432 | if (!capi_controller[i]) |
433 | break; |
434 | } |
435 | if (i == CAPI_MAXCONTR) { |
436 | mutex_unlock(lock: &capi_controller_lock); |
437 | printk(KERN_ERR "kcapi: out of controller slots\n" ); |
438 | return -EBUSY; |
439 | } |
440 | capi_controller[i] = ctr; |
441 | |
442 | ctr->nrecvctlpkt = 0; |
443 | ctr->nrecvdatapkt = 0; |
444 | ctr->nsentctlpkt = 0; |
445 | ctr->nsentdatapkt = 0; |
446 | ctr->cnr = i + 1; |
447 | ctr->state = CAPI_CTR_DETECTED; |
448 | ctr->blocked = 0; |
449 | ctr->traceflag = showcapimsgs; |
450 | |
451 | sprintf(buf: ctr->procfn, fmt: "capi/controllers/%d" , ctr->cnr); |
452 | ctr->procent = proc_create_single_data(name: ctr->procfn, mode: 0, NULL, |
453 | show: ctr->proc_show, data: ctr); |
454 | |
455 | ncontrollers++; |
456 | |
457 | mutex_unlock(lock: &capi_controller_lock); |
458 | |
459 | printk(KERN_NOTICE "kcapi: controller [%03d]: %s attached\n" , |
460 | ctr->cnr, ctr->name); |
461 | return 0; |
462 | } |
463 | |
464 | EXPORT_SYMBOL(attach_capi_ctr); |
465 | |
466 | /** |
467 | * detach_capi_ctr() - unregister CAPI controller |
468 | * @ctr: controller descriptor structure. |
469 | * |
470 | * Called by hardware driver to remove the registration of a controller |
471 | * with the CAPI subsystem. |
472 | * Return value: 0 on success, error code < 0 on error |
473 | */ |
474 | |
475 | int detach_capi_ctr(struct capi_ctr *ctr) |
476 | { |
477 | int err = 0; |
478 | |
479 | mutex_lock(&capi_controller_lock); |
480 | |
481 | ctr_down(ctr, new_state: CAPI_CTR_DETACHED); |
482 | |
483 | if (ctr->cnr < 1 || ctr->cnr - 1 >= CAPI_MAXCONTR) { |
484 | err = -EINVAL; |
485 | goto unlock_out; |
486 | } |
487 | |
488 | if (capi_controller[ctr->cnr - 1] != ctr) { |
489 | err = -EINVAL; |
490 | goto unlock_out; |
491 | } |
492 | capi_controller[ctr->cnr - 1] = NULL; |
493 | ncontrollers--; |
494 | |
495 | if (ctr->procent) |
496 | remove_proc_entry(ctr->procfn, NULL); |
497 | |
498 | printk(KERN_NOTICE "kcapi: controller [%03d]: %s unregistered\n" , |
499 | ctr->cnr, ctr->name); |
500 | |
501 | unlock_out: |
502 | mutex_unlock(lock: &capi_controller_lock); |
503 | |
504 | return err; |
505 | } |
506 | |
507 | EXPORT_SYMBOL(detach_capi_ctr); |
508 | |
509 | /* ------------------------------------------------------------- */ |
510 | /* -------- CAPI2.0 Interface ---------------------------------- */ |
511 | /* ------------------------------------------------------------- */ |
512 | |
513 | /** |
514 | * capi20_isinstalled() - CAPI 2.0 operation CAPI_INSTALLED |
515 | * |
516 | * Return value: CAPI result code (CAPI_NOERROR if at least one ISDN controller |
517 | * is ready for use, CAPI_REGNOTINSTALLED otherwise) |
518 | */ |
519 | |
520 | u16 capi20_isinstalled(void) |
521 | { |
522 | u16 ret = CAPI_REGNOTINSTALLED; |
523 | int i; |
524 | |
525 | mutex_lock(&capi_controller_lock); |
526 | |
527 | for (i = 0; i < CAPI_MAXCONTR; i++) |
528 | if (capi_controller[i] && |
529 | capi_controller[i]->state == CAPI_CTR_RUNNING) { |
530 | ret = CAPI_NOERROR; |
531 | break; |
532 | } |
533 | |
534 | mutex_unlock(lock: &capi_controller_lock); |
535 | |
536 | return ret; |
537 | } |
538 | |
539 | /** |
540 | * capi20_register() - CAPI 2.0 operation CAPI_REGISTER |
541 | * @ap: CAPI application descriptor structure. |
542 | * |
543 | * Register an application's presence with CAPI. |
544 | * A unique application ID is assigned and stored in @ap->applid. |
545 | * After this function returns successfully, the message receive |
546 | * callback function @ap->recv_message() may be called at any time |
547 | * until capi20_release() has been called for the same @ap. |
548 | * Return value: CAPI result code |
549 | */ |
550 | |
551 | u16 capi20_register(struct capi20_appl *ap) |
552 | { |
553 | int i; |
554 | u16 applid; |
555 | |
556 | DBG("" ); |
557 | |
558 | if (ap->rparam.datablklen < 128) |
559 | return CAPI_LOGBLKSIZETOSMALL; |
560 | |
561 | ap->nrecvctlpkt = 0; |
562 | ap->nrecvdatapkt = 0; |
563 | ap->nsentctlpkt = 0; |
564 | ap->nsentdatapkt = 0; |
565 | mutex_init(&ap->recv_mtx); |
566 | skb_queue_head_init(list: &ap->recv_queue); |
567 | INIT_WORK(&ap->recv_work, recv_handler); |
568 | ap->release_in_progress = 0; |
569 | |
570 | mutex_lock(&capi_controller_lock); |
571 | |
572 | for (applid = 1; applid <= CAPI_MAXAPPL; applid++) { |
573 | if (capi_applications[applid - 1] == NULL) |
574 | break; |
575 | } |
576 | if (applid > CAPI_MAXAPPL) { |
577 | mutex_unlock(lock: &capi_controller_lock); |
578 | return CAPI_TOOMANYAPPLS; |
579 | } |
580 | |
581 | ap->applid = applid; |
582 | capi_applications[applid - 1] = ap; |
583 | |
584 | for (i = 0; i < CAPI_MAXCONTR; i++) { |
585 | if (!capi_controller[i] || |
586 | capi_controller[i]->state != CAPI_CTR_RUNNING) |
587 | continue; |
588 | register_appl(ctr: capi_controller[i], applid, rparam: &ap->rparam); |
589 | } |
590 | |
591 | mutex_unlock(lock: &capi_controller_lock); |
592 | |
593 | if (showcapimsgs & 1) { |
594 | printk(KERN_DEBUG "kcapi: appl %d up\n" , applid); |
595 | } |
596 | |
597 | return CAPI_NOERROR; |
598 | } |
599 | |
600 | /** |
601 | * capi20_release() - CAPI 2.0 operation CAPI_RELEASE |
602 | * @ap: CAPI application descriptor structure. |
603 | * |
604 | * Terminate an application's registration with CAPI. |
605 | * After this function returns successfully, the message receive |
606 | * callback function @ap->recv_message() will no longer be called. |
607 | * Return value: CAPI result code |
608 | */ |
609 | |
610 | u16 capi20_release(struct capi20_appl *ap) |
611 | { |
612 | int i; |
613 | |
614 | DBG("applid %#x" , ap->applid); |
615 | |
616 | mutex_lock(&capi_controller_lock); |
617 | |
618 | ap->release_in_progress = 1; |
619 | capi_applications[ap->applid - 1] = NULL; |
620 | |
621 | synchronize_rcu(); |
622 | |
623 | for (i = 0; i < CAPI_MAXCONTR; i++) { |
624 | if (!capi_controller[i] || |
625 | capi_controller[i]->state != CAPI_CTR_RUNNING) |
626 | continue; |
627 | release_appl(ctr: capi_controller[i], applid: ap->applid); |
628 | } |
629 | |
630 | mutex_unlock(lock: &capi_controller_lock); |
631 | |
632 | flush_workqueue(kcapi_wq); |
633 | skb_queue_purge(list: &ap->recv_queue); |
634 | |
635 | if (showcapimsgs & 1) { |
636 | printk(KERN_DEBUG "kcapi: appl %d down\n" , ap->applid); |
637 | } |
638 | |
639 | return CAPI_NOERROR; |
640 | } |
641 | |
642 | /** |
643 | * capi20_put_message() - CAPI 2.0 operation CAPI_PUT_MESSAGE |
644 | * @ap: CAPI application descriptor structure. |
645 | * @skb: CAPI message. |
646 | * |
647 | * Transfer a single message to CAPI. |
648 | * Return value: CAPI result code |
649 | */ |
650 | |
651 | u16 capi20_put_message(struct capi20_appl *ap, struct sk_buff *skb) |
652 | { |
653 | struct capi_ctr *ctr; |
654 | int showctl = 0; |
655 | u8 cmd, subcmd; |
656 | |
657 | DBG("applid %#x" , ap->applid); |
658 | |
659 | if (ncontrollers == 0) |
660 | return CAPI_REGNOTINSTALLED; |
661 | if ((ap->applid == 0) || ap->release_in_progress) |
662 | return CAPI_ILLAPPNR; |
663 | if (skb->len < 12 |
664 | || !capi_cmd_valid(CAPIMSG_COMMAND(skb->data)) |
665 | || !capi_subcmd_valid(CAPIMSG_SUBCOMMAND(skb->data))) |
666 | return CAPI_ILLCMDORSUBCMDORMSGTOSMALL; |
667 | |
668 | /* |
669 | * The controller reference is protected by the existence of the |
670 | * application passed to us. We assume that the caller properly |
671 | * synchronizes this service with capi20_release. |
672 | */ |
673 | ctr = get_capi_ctr_by_nr(CAPIMSG_CONTROLLER(skb->data)); |
674 | if (!ctr || ctr->state != CAPI_CTR_RUNNING) |
675 | return CAPI_REGNOTINSTALLED; |
676 | if (ctr->blocked) |
677 | return CAPI_SENDQUEUEFULL; |
678 | |
679 | cmd = CAPIMSG_COMMAND(skb->data); |
680 | subcmd = CAPIMSG_SUBCOMMAND(skb->data); |
681 | |
682 | if (cmd == CAPI_DATA_B3 && subcmd == CAPI_REQ) { |
683 | ctr->nsentdatapkt++; |
684 | ap->nsentdatapkt++; |
685 | if (ctr->traceflag > 2) |
686 | showctl |= 2; |
687 | } else { |
688 | ctr->nsentctlpkt++; |
689 | ap->nsentctlpkt++; |
690 | if (ctr->traceflag) |
691 | showctl |= 2; |
692 | } |
693 | showctl |= (ctr->traceflag & 1); |
694 | if (showctl & 2) { |
695 | if (showctl & 1) { |
696 | printk(KERN_DEBUG "kcapi: put [%03d] id#%d %s len=%u\n" , |
697 | CAPIMSG_CONTROLLER(skb->data), |
698 | CAPIMSG_APPID(skb->data), |
699 | capi_cmd2str(cmd, subcmd), |
700 | CAPIMSG_LEN(skb->data)); |
701 | } else { |
702 | _cdebbuf *cdb = capi_message2str(msg: skb->data); |
703 | if (cdb) { |
704 | printk(KERN_DEBUG "kcapi: put [%03d] %s\n" , |
705 | CAPIMSG_CONTROLLER(skb->data), |
706 | cdb->buf); |
707 | cdebbuf_free(cdb); |
708 | } else |
709 | printk(KERN_DEBUG "kcapi: put [%03d] id#%d %s len=%u cannot trace\n" , |
710 | CAPIMSG_CONTROLLER(skb->data), |
711 | CAPIMSG_APPID(skb->data), |
712 | capi_cmd2str(cmd, subcmd), |
713 | CAPIMSG_LEN(skb->data)); |
714 | } |
715 | } |
716 | return ctr->send_message(ctr, skb); |
717 | } |
718 | |
719 | /** |
720 | * capi20_get_manufacturer() - CAPI 2.0 operation CAPI_GET_MANUFACTURER |
721 | * @contr: controller number. |
722 | * @buf: result buffer (64 bytes). |
723 | * |
724 | * Retrieve information about the manufacturer of the specified ISDN controller |
725 | * or (for @contr == 0) the driver itself. |
726 | * Return value: CAPI result code |
727 | */ |
728 | |
729 | u16 capi20_get_manufacturer(u32 contr, u8 buf[CAPI_MANUFACTURER_LEN]) |
730 | { |
731 | struct capi_ctr *ctr; |
732 | u16 ret; |
733 | |
734 | if (contr == 0) { |
735 | strscpy_pad(dest: buf, src: capi_manufakturer, CAPI_MANUFACTURER_LEN); |
736 | return CAPI_NOERROR; |
737 | } |
738 | |
739 | mutex_lock(&capi_controller_lock); |
740 | |
741 | ctr = get_capi_ctr_by_nr(contr); |
742 | if (ctr && ctr->state == CAPI_CTR_RUNNING) { |
743 | strscpy_pad(dest: buf, src: ctr->manu, CAPI_MANUFACTURER_LEN); |
744 | ret = CAPI_NOERROR; |
745 | } else |
746 | ret = CAPI_REGNOTINSTALLED; |
747 | |
748 | mutex_unlock(lock: &capi_controller_lock); |
749 | return ret; |
750 | } |
751 | |
752 | /** |
753 | * capi20_get_version() - CAPI 2.0 operation CAPI_GET_VERSION |
754 | * @contr: controller number. |
755 | * @verp: result structure. |
756 | * |
757 | * Retrieve version information for the specified ISDN controller |
758 | * or (for @contr == 0) the driver itself. |
759 | * Return value: CAPI result code |
760 | */ |
761 | |
762 | u16 capi20_get_version(u32 contr, struct capi_version *verp) |
763 | { |
764 | struct capi_ctr *ctr; |
765 | u16 ret; |
766 | |
767 | if (contr == 0) { |
768 | *verp = driver_version; |
769 | return CAPI_NOERROR; |
770 | } |
771 | |
772 | mutex_lock(&capi_controller_lock); |
773 | |
774 | ctr = get_capi_ctr_by_nr(contr); |
775 | if (ctr && ctr->state == CAPI_CTR_RUNNING) { |
776 | memcpy(verp, &ctr->version, sizeof(capi_version)); |
777 | ret = CAPI_NOERROR; |
778 | } else |
779 | ret = CAPI_REGNOTINSTALLED; |
780 | |
781 | mutex_unlock(lock: &capi_controller_lock); |
782 | return ret; |
783 | } |
784 | |
785 | /** |
786 | * capi20_get_serial() - CAPI 2.0 operation CAPI_GET_SERIAL_NUMBER |
787 | * @contr: controller number. |
788 | * @serial: result buffer (8 bytes). |
789 | * |
790 | * Retrieve the serial number of the specified ISDN controller |
791 | * or (for @contr == 0) the driver itself. |
792 | * Return value: CAPI result code |
793 | */ |
794 | |
795 | u16 capi20_get_serial(u32 contr, u8 serial[CAPI_SERIAL_LEN]) |
796 | { |
797 | struct capi_ctr *ctr; |
798 | u16 ret; |
799 | |
800 | if (contr == 0) { |
801 | strscpy(p: serial, q: driver_serial, CAPI_SERIAL_LEN); |
802 | return CAPI_NOERROR; |
803 | } |
804 | |
805 | mutex_lock(&capi_controller_lock); |
806 | |
807 | ctr = get_capi_ctr_by_nr(contr); |
808 | if (ctr && ctr->state == CAPI_CTR_RUNNING) { |
809 | strscpy(p: serial, q: ctr->serial, CAPI_SERIAL_LEN); |
810 | ret = CAPI_NOERROR; |
811 | } else |
812 | ret = CAPI_REGNOTINSTALLED; |
813 | |
814 | mutex_unlock(lock: &capi_controller_lock); |
815 | return ret; |
816 | } |
817 | |
818 | /** |
819 | * capi20_get_profile() - CAPI 2.0 operation CAPI_GET_PROFILE |
820 | * @contr: controller number. |
821 | * @profp: result structure. |
822 | * |
823 | * Retrieve capability information for the specified ISDN controller |
824 | * or (for @contr == 0) the number of installed controllers. |
825 | * Return value: CAPI result code |
826 | */ |
827 | |
828 | u16 capi20_get_profile(u32 contr, struct capi_profile *profp) |
829 | { |
830 | struct capi_ctr *ctr; |
831 | u16 ret; |
832 | |
833 | if (contr == 0) { |
834 | profp->ncontroller = ncontrollers; |
835 | return CAPI_NOERROR; |
836 | } |
837 | |
838 | mutex_lock(&capi_controller_lock); |
839 | |
840 | ctr = get_capi_ctr_by_nr(contr); |
841 | if (ctr && ctr->state == CAPI_CTR_RUNNING) { |
842 | memcpy(profp, &ctr->profile, sizeof(struct capi_profile)); |
843 | ret = CAPI_NOERROR; |
844 | } else |
845 | ret = CAPI_REGNOTINSTALLED; |
846 | |
847 | mutex_unlock(lock: &capi_controller_lock); |
848 | return ret; |
849 | } |
850 | |
851 | /** |
852 | * capi20_manufacturer() - CAPI 2.0 operation CAPI_MANUFACTURER |
853 | * @cmd: command. |
854 | * @data: parameter. |
855 | * |
856 | * Perform manufacturer specific command. |
857 | * Return value: CAPI result code |
858 | */ |
859 | |
860 | int capi20_manufacturer(unsigned long cmd, void __user *data) |
861 | { |
862 | struct capi_ctr *ctr; |
863 | int retval; |
864 | |
865 | switch (cmd) { |
866 | case KCAPI_CMD_TRACE: |
867 | { |
868 | kcapi_flagdef fdef; |
869 | |
870 | if (copy_from_user(to: &fdef, from: data, n: sizeof(kcapi_flagdef))) |
871 | return -EFAULT; |
872 | |
873 | mutex_lock(&capi_controller_lock); |
874 | |
875 | ctr = get_capi_ctr_by_nr(contr: fdef.contr); |
876 | if (ctr) { |
877 | ctr->traceflag = fdef.flag; |
878 | printk(KERN_INFO "kcapi: contr [%03d] set trace=%d\n" , |
879 | ctr->cnr, ctr->traceflag); |
880 | retval = 0; |
881 | } else |
882 | retval = -ESRCH; |
883 | |
884 | mutex_unlock(lock: &capi_controller_lock); |
885 | |
886 | return retval; |
887 | } |
888 | |
889 | default: |
890 | printk(KERN_ERR "kcapi: manufacturer command %lu unknown.\n" , |
891 | cmd); |
892 | break; |
893 | |
894 | } |
895 | return -EINVAL; |
896 | } |
897 | |
898 | /* ------------------------------------------------------------- */ |
899 | /* -------- Init & Cleanup ------------------------------------- */ |
900 | /* ------------------------------------------------------------- */ |
901 | |
902 | /* |
903 | * init / exit functions |
904 | */ |
905 | |
906 | int __init kcapi_init(void) |
907 | { |
908 | int err; |
909 | |
910 | kcapi_wq = alloc_workqueue(fmt: "kcapi" , flags: 0, max_active: 0); |
911 | if (!kcapi_wq) |
912 | return -ENOMEM; |
913 | |
914 | err = cdebug_init(); |
915 | if (err) { |
916 | destroy_workqueue(wq: kcapi_wq); |
917 | return err; |
918 | } |
919 | |
920 | kcapi_proc_init(); |
921 | return 0; |
922 | } |
923 | |
924 | void kcapi_exit(void) |
925 | { |
926 | kcapi_proc_exit(); |
927 | |
928 | cdebug_exit(); |
929 | destroy_workqueue(wq: kcapi_wq); |
930 | } |
931 | |