934 lines · c
1/* $Id: kcapi.c,v 1.1.2.8 2004/03/26 19:57:20 armin Exp $2 *3 * Kernel CAPI 2.0 Module4 *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 terms9 * 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 35static int showcapimsgs;36static struct workqueue_struct *kcapi_wq;37 38module_param(showcapimsgs, uint, 0);39 40/* ------------------------------------------------------------- */41 42struct capictr_event {43 struct work_struct work;44 unsigned int type;45 u32 controller;46};47 48/* ------------------------------------------------------------- */49 50static const struct capi_version driver_version = {2, 0, 1, 1 << 4};51static char driver_serial[CAPI_SERIAL_LEN] = "0004711";52static char capi_manufakturer[64] = "AVM Berlin";53 54#define NCCI2CTRL(ncci) (((ncci) >> 24) & 0x7f)55 56struct capi_ctr *capi_controller[CAPI_MAXCONTR];57DEFINE_MUTEX(capi_controller_lock);58 59struct capi20_appl *capi_applications[CAPI_MAXAPPL];60 61static int ncontrollers;62 63/* -------- controller ref counting -------------------------------------- */64 65static inline struct capi_ctr *66capi_ctr_get(struct capi_ctr *ctr)67{68 if (!try_module_get(ctr->owner))69 return NULL;70 return ctr;71}72 73static inline void74capi_ctr_put(struct capi_ctr *ctr)75{76 module_put(ctr->owner);77}78 79/* ------------------------------------------------------------- */80 81static 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 89static 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 99static 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 109static 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 132static 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 146static void147register_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 else154 printk(KERN_WARNING "%s: cannot get controller resources\n",155 __func__);156}157 158 159static 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 167static 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, &ap->rparam);189 }190 } else191 printk(KERN_WARNING "%s: invalid contr %d\n", __func__, contr);192 193unlock_out:194 mutex_unlock(&capi_controller_lock);195}196 197static 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 219static 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, CAPI_CTR_DETECTED);231 else232 printk(KERN_WARNING "%s: invalid contr %d\n", __func__, contr);233 234 mutex_unlock(&capi_controller_lock);235}236 237static 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(event->controller);245 break;246 case CAPICTR_DOWN:247 notify_down(event->controller);248 break;249 }250 251 kfree(event);252}253 254static int notify_push(unsigned int event_type, u32 controller)255{256 struct capictr_event *event = kmalloc(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(kcapi_wq, &event->work);266 return 0;267}268 269/* -------- Receiver ------------------------------------------ */270 271static 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(&ap->recv_queue))) {282 if (CAPIMSG_CMD(skb->data) == CAPI_DATA_B3_IND)283 ap->nrecvdatapkt++;284 else285 ap->nrecvctlpkt++;286 287 ap->recv_message(ap, skb);288 }289 mutex_unlock(&ap->recv_mtx);290}291 292/**293 * capi_ctr_handle_message() - handle incoming CAPI message294 * @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 301void 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(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 } else316 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(skb->data);341 if (cdb) {342 printk(KERN_DEBUG "kcapi: got [%03d] %s\n",343 ctr->cnr, cdb->buf);344 cdebbuf_free(cdb);345 } else346 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(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 } else364 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(&ap->recv_queue, skb);370 queue_work(kcapi_wq, &ap->recv_work);371 rcu_read_unlock();372 373 return;374 375error:376 kfree_skb(skb);377}378 379EXPORT_SYMBOL(capi_ctr_handle_message);380 381/**382 * capi_ctr_ready() - signal CAPI controller ready383 * @ctr: controller descriptor structure.384 *385 * Called by hardware driver to signal that the controller is up and running.386 */387 388void 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, ctr->cnr);394}395 396EXPORT_SYMBOL(capi_ctr_ready);397 398/**399 * capi_ctr_down() - signal CAPI controller not ready400 * @ctr: controller descriptor structure.401 *402 * Called by hardware driver to signal that the controller is down and403 * unavailable for use.404 */405 406void 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, ctr->cnr);411}412 413EXPORT_SYMBOL(capi_ctr_down);414 415/* ------------------------------------------------------------- */416 417/**418 * attach_capi_ctr() - register CAPI controller419 * @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 error423 */424 425int 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(&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(ctr->procfn, "capi/controllers/%d", ctr->cnr);452 ctr->procent = proc_create_single_data(ctr->procfn, 0, NULL,453 ctr->proc_show, ctr);454 455 ncontrollers++;456 457 mutex_unlock(&capi_controller_lock);458 459 printk(KERN_NOTICE "kcapi: controller [%03d]: %s attached\n",460 ctr->cnr, ctr->name);461 return 0;462}463 464EXPORT_SYMBOL(attach_capi_ctr);465 466/**467 * detach_capi_ctr() - unregister CAPI controller468 * @ctr: controller descriptor structure.469 *470 * Called by hardware driver to remove the registration of a controller471 * with the CAPI subsystem.472 * Return value: 0 on success, error code < 0 on error473 */474 475int detach_capi_ctr(struct capi_ctr *ctr)476{477 int err = 0;478 479 mutex_lock(&capi_controller_lock);480 481 ctr_down(ctr, 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 501unlock_out:502 mutex_unlock(&capi_controller_lock);503 504 return err;505}506 507EXPORT_SYMBOL(detach_capi_ctr);508 509/* ------------------------------------------------------------- */510/* -------- CAPI2.0 Interface ---------------------------------- */511/* ------------------------------------------------------------- */512 513/**514 * capi20_isinstalled() - CAPI 2.0 operation CAPI_INSTALLED515 *516 * Return value: CAPI result code (CAPI_NOERROR if at least one ISDN controller517 * is ready for use, CAPI_REGNOTINSTALLED otherwise)518 */519 520u16 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(&capi_controller_lock);535 536 return ret;537}538 539/**540 * capi20_register() - CAPI 2.0 operation CAPI_REGISTER541 * @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 receive546 * callback function @ap->recv_message() may be called at any time547 * until capi20_release() has been called for the same @ap.548 * Return value: CAPI result code549 */550 551u16 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(&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(&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(capi_controller[i], applid, &ap->rparam);589 }590 591 mutex_unlock(&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_RELEASE602 * @ap: CAPI application descriptor structure.603 *604 * Terminate an application's registration with CAPI.605 * After this function returns successfully, the message receive606 * callback function @ap->recv_message() will no longer be called.607 * Return value: CAPI result code608 */609 610u16 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(capi_controller[i], ap->applid);628 }629 630 mutex_unlock(&capi_controller_lock);631 632 flush_workqueue(kcapi_wq);633 skb_queue_purge(&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_MESSAGE644 * @ap: CAPI application descriptor structure.645 * @skb: CAPI message.646 *647 * Transfer a single message to CAPI.648 * Return value: CAPI result code649 */650 651u16 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 < 12664 || !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 the670 * application passed to us. We assume that the caller properly671 * 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(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 } else709 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_MANUFACTURER721 * @contr: controller number.722 * @buf: result buffer (64 bytes).723 *724 * Retrieve information about the manufacturer of the specified ISDN controller725 * or (for @contr == 0) the driver itself.726 * Return value: CAPI result code727 */728 729u16 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(buf, 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(buf, ctr->manu, CAPI_MANUFACTURER_LEN);744 ret = CAPI_NOERROR;745 } else746 ret = CAPI_REGNOTINSTALLED;747 748 mutex_unlock(&capi_controller_lock);749 return ret;750}751 752/**753 * capi20_get_version() - CAPI 2.0 operation CAPI_GET_VERSION754 * @contr: controller number.755 * @verp: result structure.756 *757 * Retrieve version information for the specified ISDN controller758 * or (for @contr == 0) the driver itself.759 * Return value: CAPI result code760 */761 762u16 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 } else779 ret = CAPI_REGNOTINSTALLED;780 781 mutex_unlock(&capi_controller_lock);782 return ret;783}784 785/**786 * capi20_get_serial() - CAPI 2.0 operation CAPI_GET_SERIAL_NUMBER787 * @contr: controller number.788 * @serial: result buffer (8 bytes).789 *790 * Retrieve the serial number of the specified ISDN controller791 * or (for @contr == 0) the driver itself.792 * Return value: CAPI result code793 */794 795u16 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(serial, 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(serial, ctr->serial, CAPI_SERIAL_LEN);810 ret = CAPI_NOERROR;811 } else812 ret = CAPI_REGNOTINSTALLED;813 814 mutex_unlock(&capi_controller_lock);815 return ret;816}817 818/**819 * capi20_get_profile() - CAPI 2.0 operation CAPI_GET_PROFILE820 * @contr: controller number.821 * @profp: result structure.822 *823 * Retrieve capability information for the specified ISDN controller824 * or (for @contr == 0) the number of installed controllers.825 * Return value: CAPI result code826 */827 828u16 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 } else845 ret = CAPI_REGNOTINSTALLED;846 847 mutex_unlock(&capi_controller_lock);848 return ret;849}850 851/**852 * capi20_manufacturer() - CAPI 2.0 operation CAPI_MANUFACTURER853 * @cmd: command.854 * @data: parameter.855 *856 * Perform manufacturer specific command.857 * Return value: CAPI result code858 */859 860int 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(&fdef, data, sizeof(kcapi_flagdef)))871 return -EFAULT;872 873 mutex_lock(&capi_controller_lock);874 875 ctr = get_capi_ctr_by_nr(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 } else882 retval = -ESRCH;883 884 mutex_unlock(&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 functions904 */905 906int __init kcapi_init(void)907{908 int err;909 910 kcapi_wq = alloc_workqueue("kcapi", 0, 0);911 if (!kcapi_wq)912 return -ENOMEM;913 914 err = cdebug_init();915 if (err) {916 destroy_workqueue(kcapi_wq);917 return err;918 }919 920 if (IS_ENABLED(CONFIG_PROC_FS))921 kcapi_proc_init();922 923 return 0;924}925 926void kcapi_exit(void)927{928 if (IS_ENABLED(CONFIG_PROC_FS))929 kcapi_proc_exit();930 931 cdebug_exit();932 destroy_workqueue(kcapi_wq);933}934