brintos

brintos / linux-shallow public Read only

0
0
Text · 21.0 KiB · c5d13bd Raw
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