kcapi.c 29.1 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7 8 9 10 11 12
/* $Id: kcapi.c,v 1.1.2.8 2004/03/26 19:57:20 armin Exp $
 * 
 * Kernel CAPI 2.0 Module
 * 
 * Copyright 1999 by Carsten Paeth <calle@calle.de>
 * Copyright 2002 by Kai Germaschewski <kai@germaschewski.name>
 * 
 * This software may be used and distributed according to the terms
 * of the GNU General Public License, incorporated herein by reference.
 *
 */

13
#define AVMB1_COMPAT
L
Linus Torvalds 已提交
14 15 16 17 18 19 20

#include "kcapi.h"
#include <linux/module.h>
#include <linux/mm.h>
#include <linux/interrupt.h>
#include <linux/ioport.h>
#include <linux/proc_fs.h>
21
#include <linux/sched.h>
L
Linus Torvalds 已提交
22 23 24 25 26 27 28 29 30 31 32
#include <linux/seq_file.h>
#include <linux/skbuff.h>
#include <linux/workqueue.h>
#include <linux/capi.h>
#include <linux/kernelcapi.h>
#include <linux/init.h>
#include <linux/moduleparam.h>
#include <linux/delay.h>
#include <asm/uaccess.h>
#include <linux/isdn/capicmd.h>
#include <linux/isdn/capiutil.h>
33
#ifdef AVMB1_COMPAT
L
Linus Torvalds 已提交
34 35
#include <linux/b1lli.h>
#endif
A
Arjan van de Ven 已提交
36
#include <linux/mutex.h>
J
Jan Kiszka 已提交
37
#include <linux/rcupdate.h>
L
Linus Torvalds 已提交
38 39 40 41 42 43 44 45 46 47

static int showcapimsgs = 0;

MODULE_DESCRIPTION("CAPI4Linux: kernel CAPI layer");
MODULE_AUTHOR("Carsten Paeth");
MODULE_LICENSE("GPL");
module_param(showcapimsgs, uint, 0);

/* ------------------------------------------------------------- */

48
struct capictr_event {
L
Linus Torvalds 已提交
49
	struct work_struct work;
50
	unsigned int type;
L
Linus Torvalds 已提交
51 52 53 54 55 56 57 58 59 60 61 62
	u32 controller;
};

/* ------------------------------------------------------------- */

static struct capi_version driver_version = {2, 0, 1, 1<<4};
static char driver_serial[CAPI_SERIAL_LEN] = "0004711";
static char capi_manufakturer[64] = "AVM Berlin";

#define NCCI2CTRL(ncci)    (((ncci) >> 24) & 0x7f)

LIST_HEAD(capi_drivers);
63
DEFINE_MUTEX(capi_drivers_lock);
L
Linus Torvalds 已提交
64

65 66 67
struct capi_ctr *capi_controller[CAPI_MAXCONTR];
DEFINE_MUTEX(capi_controller_lock);

L
Linus Torvalds 已提交
68 69
struct capi20_appl *capi_applications[CAPI_MAXAPPL];

70
static int ncontrollers;
L
Linus Torvalds 已提交
71

72 73
static BLOCKING_NOTIFIER_HEAD(ctr_notifier_list);

L
Linus Torvalds 已提交
74 75 76
/* -------- controller ref counting -------------------------------------- */

static inline struct capi_ctr *
77
capi_ctr_get(struct capi_ctr *ctr)
L
Linus Torvalds 已提交
78
{
79
	if (!try_module_get(ctr->owner))
L
Linus Torvalds 已提交
80
		return NULL;
81
	return ctr;
L
Linus Torvalds 已提交
82 83 84
}

static inline void
85
capi_ctr_put(struct capi_ctr *ctr)
L
Linus Torvalds 已提交
86
{
87
	module_put(ctr->owner);
L
Linus Torvalds 已提交
88 89 90 91 92 93 94 95 96
}

/* ------------------------------------------------------------- */

static inline struct capi_ctr *get_capi_ctr_by_nr(u16 contr)
{
	if (contr - 1 >= CAPI_MAXCONTR)
		return NULL;

97
	return capi_controller[contr - 1];
L
Linus Torvalds 已提交
98 99 100 101 102 103 104
}

static inline struct capi20_appl *get_capi_appl_by_nr(u16 applid)
{
	if (applid - 1 >= CAPI_MAXAPPL)
		return NULL;

J
Jan Kiszka 已提交
105
	return rcu_dereference(capi_applications[applid - 1]);
L
Linus Torvalds 已提交
106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146
}

/* -------- util functions ------------------------------------ */

static inline int capi_cmd_valid(u8 cmd)
{
	switch (cmd) {
	case CAPI_ALERT:
	case CAPI_CONNECT:
	case CAPI_CONNECT_ACTIVE:
	case CAPI_CONNECT_B3_ACTIVE:
	case CAPI_CONNECT_B3:
	case CAPI_CONNECT_B3_T90_ACTIVE:
	case CAPI_DATA_B3:
	case CAPI_DISCONNECT_B3:
	case CAPI_DISCONNECT:
	case CAPI_FACILITY:
	case CAPI_INFO:
	case CAPI_LISTEN:
	case CAPI_MANUFACTURER:
	case CAPI_RESET_B3:
	case CAPI_SELECT_B_PROTOCOL:
		return 1;
	}
	return 0;
}

static inline int capi_subcmd_valid(u8 subcmd)
{
	switch (subcmd) {
	case CAPI_REQ:
	case CAPI_CONF:
	case CAPI_IND:
	case CAPI_RESP:
		return 1;
	}
	return 0;
}

/* ------------------------------------------------------------ */

147 148
static void
register_appl(struct capi_ctr *ctr, u16 applid, capi_register_params *rparam)
L
Linus Torvalds 已提交
149
{
150
	ctr = capi_ctr_get(ctr);
L
Linus Torvalds 已提交
151

152 153
	if (ctr)
		ctr->register_appl(ctr, applid, rparam);
L
Linus Torvalds 已提交
154
	else
155 156
		printk(KERN_WARNING "%s: cannot get controller resources\n",
		       __func__);
L
Linus Torvalds 已提交
157 158 159
}


160
static void release_appl(struct capi_ctr *ctr, u16 applid)
L
Linus Torvalds 已提交
161 162 163
{
	DBG("applid %#x", applid);
	
164 165
	ctr->release_appl(ctr, applid);
	capi_ctr_put(ctr);
L
Linus Torvalds 已提交
166 167 168 169 170
}

static void notify_up(u32 contr)
{
	struct capi20_appl *ap;
J
Jan Kiszka 已提交
171
	struct capi_ctr *ctr;
L
Linus Torvalds 已提交
172 173
	u16 applid;

174 175
	mutex_lock(&capi_controller_lock);

J
Jan Kiszka 已提交
176
	if (showcapimsgs & 1)
L
Linus Torvalds 已提交
177
	        printk(KERN_DEBUG "kcapi: notify up contr %d\n", contr);
J
Jan Kiszka 已提交
178 179 180 181

	ctr = get_capi_ctr_by_nr(contr);
	if (ctr) {
		if (ctr->state == CAPI_CTR_RUNNING)
182
			goto unlock_out;
J
Jan Kiszka 已提交
183 184 185 186 187

		ctr->state = CAPI_CTR_RUNNING;

		for (applid = 1; applid <= CAPI_MAXAPPL; applid++) {
			ap = get_capi_appl_by_nr(applid);
J
Jan Kiszka 已提交
188
			if (!ap)
J
Jan Kiszka 已提交
189 190 191
				continue;
			register_appl(ctr, applid, &ap->rparam);
		}
192 193

		wake_up_interruptible_all(&ctr->state_wait_queue);
J
Jan Kiszka 已提交
194
	} else
195
		printk(KERN_WARNING "%s: invalid contr %d\n", __func__, contr);
196 197 198

unlock_out:
	mutex_unlock(&capi_controller_lock);
L
Linus Torvalds 已提交
199 200
}

201
static void ctr_down(struct capi_ctr *ctr, int new_state)
L
Linus Torvalds 已提交
202 203 204 205
{
	struct capi20_appl *ap;
	u16 applid;

206
	if (ctr->state == CAPI_CTR_DETECTED || ctr->state == CAPI_CTR_DETACHED)
J
Jan Kiszka 已提交
207 208
		return;

209
	ctr->state = new_state;
J
Jan Kiszka 已提交
210 211 212 213 214

	memset(ctr->manu, 0, sizeof(ctr->manu));
	memset(&ctr->version, 0, sizeof(ctr->version));
	memset(&ctr->profile, 0, sizeof(ctr->profile));
	memset(ctr->serial, 0, sizeof(ctr->serial));
L
Linus Torvalds 已提交
215 216 217

	for (applid = 1; applid <= CAPI_MAXAPPL; applid++) {
		ap = get_capi_appl_by_nr(applid);
J
Jan Kiszka 已提交
218
		if (ap)
J
Jan Kiszka 已提交
219
			capi_ctr_put(ctr);
L
Linus Torvalds 已提交
220
	}
221 222

	wake_up_interruptible_all(&ctr->state_wait_queue);
L
Linus Torvalds 已提交
223 224
}

J
Jan Kiszka 已提交
225 226 227 228
static void notify_down(u32 contr)
{
	struct capi_ctr *ctr;

229 230
	mutex_lock(&capi_controller_lock);

J
Jan Kiszka 已提交
231 232 233 234 235
	if (showcapimsgs & 1)
		printk(KERN_DEBUG "kcapi: notify down contr %d\n", contr);

	ctr = get_capi_ctr_by_nr(contr);
	if (ctr)
236
		ctr_down(ctr, CAPI_CTR_DETECTED);
J
Jan Kiszka 已提交
237 238
	else
		printk(KERN_WARNING "%s: invalid contr %d\n", __func__, contr);
239 240

	mutex_unlock(&capi_controller_lock);
J
Jan Kiszka 已提交
241 242
}

243 244
static int
notify_handler(struct notifier_block *nb, unsigned long val, void *v)
L
Linus Torvalds 已提交
245
{
246
	u32 contr = (long)v;
L
Linus Torvalds 已提交
247

248 249 250
	switch (val) {
	case CAPICTR_UP:
		notify_up(contr);
L
Linus Torvalds 已提交
251
		break;
252 253
	case CAPICTR_DOWN:
		notify_down(contr);
L
Linus Torvalds 已提交
254 255
		break;
	}
256 257 258 259 260 261 262
	return NOTIFY_OK;
}

static void do_notify_work(struct work_struct *work)
{
	struct capictr_event *event =
		container_of(work, struct capictr_event, work);
L
Linus Torvalds 已提交
263

264 265 266
	blocking_notifier_call_chain(&ctr_notifier_list, event->type,
				     (void *)(long)event->controller);
	kfree(event);
L
Linus Torvalds 已提交
267 268 269 270 271 272
}

/*
 * The notifier will result in adding/deleteing of devices. Devices can
 * only removed in user process, not in bh.
 */
273
static int notify_push(unsigned int event_type, u32 controller)
L
Linus Torvalds 已提交
274
{
275
	struct capictr_event *event = kmalloc(sizeof(*event), GFP_ATOMIC);
L
Linus Torvalds 已提交
276

277
	if (!event)
L
Linus Torvalds 已提交
278 279
		return -ENOMEM;

280 281 282
	INIT_WORK(&event->work, do_notify_work);
	event->type = event_type;
	event->controller = controller;
L
Linus Torvalds 已提交
283

284
	schedule_work(&event->work);
L
Linus Torvalds 已提交
285 286 287
	return 0;
}

288 289 290 291 292 293 294 295 296 297 298 299
int register_capictr_notifier(struct notifier_block *nb)
{
	return blocking_notifier_chain_register(&ctr_notifier_list, nb);
}
EXPORT_SYMBOL_GPL(register_capictr_notifier);

int unregister_capictr_notifier(struct notifier_block *nb)
{
	return blocking_notifier_chain_unregister(&ctr_notifier_list, nb);
}
EXPORT_SYMBOL_GPL(unregister_capictr_notifier);

L
Linus Torvalds 已提交
300 301
/* -------- Receiver ------------------------------------------ */

D
David Howells 已提交
302
static void recv_handler(struct work_struct *work)
L
Linus Torvalds 已提交
303 304
{
	struct sk_buff *skb;
D
David Howells 已提交
305 306
	struct capi20_appl *ap =
		container_of(work, struct capi20_appl, recv_work);
L
Linus Torvalds 已提交
307 308 309 310

	if ((!ap) || (ap->release_in_progress))
		return;

311
	mutex_lock(&ap->recv_mtx);
L
Linus Torvalds 已提交
312 313 314 315 316 317 318 319
	while ((skb = skb_dequeue(&ap->recv_queue))) {
		if (CAPIMSG_CMD(skb->data) == CAPI_DATA_B3_IND)
			ap->nrecvdatapkt++;
		else
			ap->nrecvctlpkt++;

		ap->recv_message(ap, skb);
	}
320
	mutex_unlock(&ap->recv_mtx);
L
Linus Torvalds 已提交
321 322
}

323 324
/**
 * capi_ctr_handle_message() - handle incoming CAPI message
325
 * @ctr:	controller descriptor structure.
326 327 328 329 330 331
 * @appl:	application ID.
 * @skb:	message.
 *
 * Called by hardware driver to pass a CAPI message to the application.
 */

332 333
void capi_ctr_handle_message(struct capi_ctr *ctr, u16 appl,
			     struct sk_buff *skb)
L
Linus Torvalds 已提交
334 335 336 337
{
	struct capi20_appl *ap;
	int showctl = 0;
	u8 cmd, subcmd;
338
	_cdebbuf *cdb;
L
Linus Torvalds 已提交
339

340
	if (ctr->state != CAPI_CTR_RUNNING) {
341 342 343
		cdb = capi_message2str(skb->data);
		if (cdb) {
			printk(KERN_INFO "kcapi: controller [%03d] not active, got: %s",
344
				ctr->cnr, cdb->buf);
345 346 347
			cdebbuf_free(cdb);
		} else
			printk(KERN_INFO "kcapi: controller [%03d] not active, cannot trace\n",
348
				ctr->cnr);
L
Linus Torvalds 已提交
349 350 351 352 353 354
		goto error;
	}

	cmd = CAPIMSG_COMMAND(skb->data);
        subcmd = CAPIMSG_SUBCOMMAND(skb->data);
	if (cmd == CAPI_DATA_B3 && subcmd == CAPI_IND) {
355 356 357
		ctr->nrecvdatapkt++;
		if (ctr->traceflag > 2)
			showctl |= 2;
L
Linus Torvalds 已提交
358
	} else {
359 360 361
		ctr->nrecvctlpkt++;
		if (ctr->traceflag)
			showctl |= 2;
L
Linus Torvalds 已提交
362
	}
363
	showctl |= (ctr->traceflag & 1);
L
Linus Torvalds 已提交
364 365
	if (showctl & 2) {
		if (showctl & 1) {
366
			printk(KERN_DEBUG "kcapi: got [%03d] id#%d %s len=%u\n",
367
			       ctr->cnr, CAPIMSG_APPID(skb->data),
L
Linus Torvalds 已提交
368 369 370
			       capi_cmd2str(cmd, subcmd),
			       CAPIMSG_LEN(skb->data));
		} else {
371 372 373
			cdb = capi_message2str(skb->data);
			if (cdb) {
				printk(KERN_DEBUG "kcapi: got [%03d] %s\n",
374
					ctr->cnr, cdb->buf);
375 376 377
				cdebbuf_free(cdb);
			} else
				printk(KERN_DEBUG "kcapi: got [%03d] id#%d %s len=%u, cannot trace\n",
378
					ctr->cnr, CAPIMSG_APPID(skb->data),
379 380
					capi_cmd2str(cmd, subcmd),
					CAPIMSG_LEN(skb->data));
L
Linus Torvalds 已提交
381 382 383 384
		}

	}

J
Jan Kiszka 已提交
385
	rcu_read_lock();
L
Linus Torvalds 已提交
386
	ap = get_capi_appl_by_nr(CAPIMSG_APPID(skb->data));
J
Jan Kiszka 已提交
387 388
	if (!ap) {
		rcu_read_unlock();
389 390 391 392 393 394 395 396 397
		cdb = capi_message2str(skb->data);
		if (cdb) {
			printk(KERN_ERR "kcapi: handle_message: applid %d state released (%s)\n",
			CAPIMSG_APPID(skb->data), cdb->buf);
			cdebbuf_free(cdb);
		} else
			printk(KERN_ERR "kcapi: handle_message: applid %d state released (%s) cannot trace\n",
				CAPIMSG_APPID(skb->data),
				capi_cmd2str(cmd, subcmd));
L
Linus Torvalds 已提交
398 399 400 401
		goto error;
	}
	skb_queue_tail(&ap->recv_queue, skb);
	schedule_work(&ap->recv_work);
J
Jan Kiszka 已提交
402
	rcu_read_unlock();
L
Linus Torvalds 已提交
403 404 405 406 407 408 409 410 411

	return;

error:
	kfree_skb(skb);
}

EXPORT_SYMBOL(capi_ctr_handle_message);

412 413
/**
 * capi_ctr_ready() - signal CAPI controller ready
414
 * @ctr:	controller descriptor structure.
415 416 417 418
 *
 * Called by hardware driver to signal that the controller is up and running.
 */

419
void capi_ctr_ready(struct capi_ctr *ctr)
L
Linus Torvalds 已提交
420
{
421 422
	printk(KERN_NOTICE "kcapi: controller [%03d] \"%s\" ready.\n",
	       ctr->cnr, ctr->name);
L
Linus Torvalds 已提交
423

424
	notify_push(CAPICTR_UP, ctr->cnr);
L
Linus Torvalds 已提交
425 426 427 428
}

EXPORT_SYMBOL(capi_ctr_ready);

429
/**
430
 * capi_ctr_down() - signal CAPI controller not ready
431
 * @ctr:	controller descriptor structure.
432 433 434 435 436
 *
 * Called by hardware driver to signal that the controller is down and
 * unavailable for use.
 */

437
void capi_ctr_down(struct capi_ctr *ctr)
L
Linus Torvalds 已提交
438
{
439
	printk(KERN_NOTICE "kcapi: controller [%03d] down.\n", ctr->cnr);
L
Linus Torvalds 已提交
440

441
	notify_push(CAPICTR_DOWN, ctr->cnr);
L
Linus Torvalds 已提交
442 443
}

444
EXPORT_SYMBOL(capi_ctr_down);
L
Linus Torvalds 已提交
445

446 447
/**
 * capi_ctr_suspend_output() - suspend controller
448
 * @ctr:	controller descriptor structure.
449 450
 *
 * Called by hardware driver to stop data flow.
451 452 453
 *
 * Note: The caller is responsible for synchronizing concurrent state changes
 * as well as invocations of capi_ctr_handle_message.
454 455
 */

456
void capi_ctr_suspend_output(struct capi_ctr *ctr)
L
Linus Torvalds 已提交
457
{
458 459 460 461
	if (!ctr->blocked) {
		printk(KERN_DEBUG "kcapi: controller [%03d] suspend\n",
		       ctr->cnr);
		ctr->blocked = 1;
L
Linus Torvalds 已提交
462 463 464 465 466
	}
}

EXPORT_SYMBOL(capi_ctr_suspend_output);

467 468
/**
 * capi_ctr_resume_output() - resume controller
469
 * @ctr:	controller descriptor structure.
470 471
 *
 * Called by hardware driver to resume data flow.
472 473 474
 *
 * Note: The caller is responsible for synchronizing concurrent state changes
 * as well as invocations of capi_ctr_handle_message.
475 476
 */

477
void capi_ctr_resume_output(struct capi_ctr *ctr)
L
Linus Torvalds 已提交
478
{
479 480 481 482
	if (ctr->blocked) {
		printk(KERN_DEBUG "kcapi: controller [%03d] resumed\n",
		       ctr->cnr);
		ctr->blocked = 0;
L
Linus Torvalds 已提交
483 484 485 486 487 488 489
	}
}

EXPORT_SYMBOL(capi_ctr_resume_output);

/* ------------------------------------------------------------- */

490 491
/**
 * attach_capi_ctr() - register CAPI controller
492
 * @ctr:	controller descriptor structure.
493 494 495 496 497
 *
 * Called by hardware driver to register a controller with the CAPI subsystem.
 * Return value: 0 on success, error code < 0 on error
 */

498
int attach_capi_ctr(struct capi_ctr *ctr)
L
Linus Torvalds 已提交
499 500 501
{
	int i;

502
	mutex_lock(&capi_controller_lock);
L
Linus Torvalds 已提交
503 504

	for (i = 0; i < CAPI_MAXCONTR; i++) {
505
		if (!capi_controller[i])
L
Linus Torvalds 已提交
506 507 508
			break;
	}
	if (i == CAPI_MAXCONTR) {
509
		mutex_unlock(&capi_controller_lock);
L
Linus Torvalds 已提交
510 511 512
		printk(KERN_ERR "kcapi: out of controller slots\n");
	   	return -EBUSY;
	}
513
	capi_controller[i] = ctr;
L
Linus Torvalds 已提交
514

515 516 517 518 519 520 521 522
	ctr->nrecvctlpkt = 0;
	ctr->nrecvdatapkt = 0;
	ctr->nsentctlpkt = 0;
	ctr->nsentdatapkt = 0;
	ctr->cnr = i + 1;
	ctr->state = CAPI_CTR_DETECTED;
	ctr->blocked = 0;
	ctr->traceflag = showcapimsgs;
523
	init_waitqueue_head(&ctr->state_wait_queue);
524 525 526 527 528

	sprintf(ctr->procfn, "capi/controllers/%d", ctr->cnr);
	ctr->procent = proc_create_data(ctr->procfn, 0, NULL, ctr->proc_fops, ctr);

	ncontrollers++;
529 530 531

	mutex_unlock(&capi_controller_lock);

532 533
	printk(KERN_NOTICE "kcapi: controller [%03d]: %s attached\n",
			ctr->cnr, ctr->name);
L
Linus Torvalds 已提交
534 535 536 537 538
	return 0;
}

EXPORT_SYMBOL(attach_capi_ctr);

539 540
/**
 * detach_capi_ctr() - unregister CAPI controller
541
 * @ctr:	controller descriptor structure.
542 543 544 545 546 547
 *
 * Called by hardware driver to remove the registration of a controller
 * with the CAPI subsystem.
 * Return value: 0 on success, error code < 0 on error
 */

548
int detach_capi_ctr(struct capi_ctr *ctr)
L
Linus Torvalds 已提交
549
{
550
	int err = 0;
L
Linus Torvalds 已提交
551

552
	mutex_lock(&capi_controller_lock);
L
Linus Torvalds 已提交
553

554 555 556 557 558
	ctr_down(ctr, CAPI_CTR_DETACHED);

	if (capi_controller[ctr->cnr - 1] != ctr) {
		err = -EINVAL;
		goto unlock_out;
L
Linus Torvalds 已提交
559
	}
560
	capi_controller[ctr->cnr - 1] = NULL;
561 562 563 564 565
	ncontrollers--;

	if (ctr->procent)
		remove_proc_entry(ctr->procfn, NULL);

566 567
	printk(KERN_NOTICE "kcapi: controller [%03d]: %s unregistered\n",
	       ctr->cnr, ctr->name);
L
Linus Torvalds 已提交
568

569 570 571 572
unlock_out:
	mutex_unlock(&capi_controller_lock);

	return err;
L
Linus Torvalds 已提交
573 574 575 576
}

EXPORT_SYMBOL(detach_capi_ctr);

577 578 579 580 581 582 583
/**
 * register_capi_driver() - register CAPI driver
 * @driver:	driver descriptor structure.
 *
 * Called by hardware driver to register itself with the CAPI subsystem.
 */

L
Linus Torvalds 已提交
584 585
void register_capi_driver(struct capi_driver *driver)
{
586
	mutex_lock(&capi_drivers_lock);
L
Linus Torvalds 已提交
587
	list_add_tail(&driver->list, &capi_drivers);
588
	mutex_unlock(&capi_drivers_lock);
L
Linus Torvalds 已提交
589 590 591 592
}

EXPORT_SYMBOL(register_capi_driver);

593 594 595 596 597 598 599
/**
 * unregister_capi_driver() - unregister CAPI driver
 * @driver:	driver descriptor structure.
 *
 * Called by hardware driver to unregister itself from the CAPI subsystem.
 */

L
Linus Torvalds 已提交
600 601
void unregister_capi_driver(struct capi_driver *driver)
{
602
	mutex_lock(&capi_drivers_lock);
L
Linus Torvalds 已提交
603
	list_del(&driver->list);
604
	mutex_unlock(&capi_drivers_lock);
L
Linus Torvalds 已提交
605 606 607 608 609 610 611 612
}

EXPORT_SYMBOL(unregister_capi_driver);

/* ------------------------------------------------------------- */
/* -------- CAPI2.0 Interface ---------------------------------- */
/* ------------------------------------------------------------- */

613 614 615 616 617 618 619
/**
 * capi20_isinstalled() - CAPI 2.0 operation CAPI_INSTALLED
 *
 * Return value: CAPI result code (CAPI_NOERROR if at least one ISDN controller
 *	is ready for use, CAPI_REGNOTINSTALLED otherwise)
 */

L
Linus Torvalds 已提交
620 621
u16 capi20_isinstalled(void)
{
622
	u16 ret = CAPI_REGNOTINSTALLED;
L
Linus Torvalds 已提交
623
	int i;
624 625 626 627

	mutex_lock(&capi_controller_lock);

	for (i = 0; i < CAPI_MAXCONTR; i++)
628
		if (capi_controller[i] &&
629 630 631 632 633 634 635 636
		    capi_controller[i]->state == CAPI_CTR_RUNNING) {
			ret = CAPI_NOERROR;
			break;
		}

	mutex_unlock(&capi_controller_lock);

	return ret;
L
Linus Torvalds 已提交
637 638 639 640
}

EXPORT_SYMBOL(capi20_isinstalled);

641 642 643 644 645 646 647 648 649 650 651 652
/**
 * capi20_register() - CAPI 2.0 operation CAPI_REGISTER
 * @ap:		CAPI application descriptor structure.
 *
 * Register an application's presence with CAPI.
 * A unique application ID is assigned and stored in @ap->applid.
 * After this function returns successfully, the message receive
 * callback function @ap->recv_message() may be called at any time
 * until capi20_release() has been called for the same @ap.
 * Return value: CAPI result code
 */

L
Linus Torvalds 已提交
653 654 655 656 657 658 659 660 661 662
u16 capi20_register(struct capi20_appl *ap)
{
	int i;
	u16 applid;

	DBG("");

	if (ap->rparam.datablklen < 128)
		return CAPI_LOGBLKSIZETOSMALL;

J
Jan Kiszka 已提交
663 664 665 666 667 668 669 670 671 672
	ap->nrecvctlpkt = 0;
	ap->nrecvdatapkt = 0;
	ap->nsentctlpkt = 0;
	ap->nsentdatapkt = 0;
	mutex_init(&ap->recv_mtx);
	skb_queue_head_init(&ap->recv_queue);
	INIT_WORK(&ap->recv_work, recv_handler);
	ap->release_in_progress = 0;

	mutex_lock(&capi_controller_lock);
L
Linus Torvalds 已提交
673 674 675 676 677 678

	for (applid = 1; applid <= CAPI_MAXAPPL; applid++) {
		if (capi_applications[applid - 1] == NULL)
			break;
	}
	if (applid > CAPI_MAXAPPL) {
J
Jan Kiszka 已提交
679
		mutex_unlock(&capi_controller_lock);
L
Linus Torvalds 已提交
680 681 682 683 684 685 686
		return CAPI_TOOMANYAPPLS;
	}

	ap->applid = applid;
	capi_applications[applid - 1] = ap;

	for (i = 0; i < CAPI_MAXCONTR; i++) {
687 688
		if (!capi_controller[i] ||
		    capi_controller[i]->state != CAPI_CTR_RUNNING)
L
Linus Torvalds 已提交
689
			continue;
690
		register_appl(capi_controller[i], applid, &ap->rparam);
L
Linus Torvalds 已提交
691
	}
692 693

	mutex_unlock(&capi_controller_lock);
L
Linus Torvalds 已提交
694 695 696 697 698 699 700 701 702 703

	if (showcapimsgs & 1) {
		printk(KERN_DEBUG "kcapi: appl %d up\n", applid);
	}

	return CAPI_NOERROR;
}

EXPORT_SYMBOL(capi20_register);

704 705 706 707 708 709 710 711 712 713
/**
 * capi20_release() - CAPI 2.0 operation CAPI_RELEASE
 * @ap:		CAPI application descriptor structure.
 *
 * Terminate an application's registration with CAPI.
 * After this function returns successfully, the message receive
 * callback function @ap->recv_message() will no longer be called.
 * Return value: CAPI result code
 */

L
Linus Torvalds 已提交
714 715 716 717 718 719
u16 capi20_release(struct capi20_appl *ap)
{
	int i;

	DBG("applid %#x", ap->applid);

J
Jan Kiszka 已提交
720 721
	mutex_lock(&capi_controller_lock);

L
Linus Torvalds 已提交
722 723 724
	ap->release_in_progress = 1;
	capi_applications[ap->applid - 1] = NULL;

J
Jan Kiszka 已提交
725
	synchronize_rcu();
726

L
Linus Torvalds 已提交
727
	for (i = 0; i < CAPI_MAXCONTR; i++) {
728 729
		if (!capi_controller[i] ||
		    capi_controller[i]->state != CAPI_CTR_RUNNING)
L
Linus Torvalds 已提交
730
			continue;
731
		release_appl(capi_controller[i], ap->applid);
L
Linus Torvalds 已提交
732
	}
733 734

	mutex_unlock(&capi_controller_lock);
L
Linus Torvalds 已提交
735 736 737 738 739 740 741 742 743 744 745 746 747

	flush_scheduled_work();
	skb_queue_purge(&ap->recv_queue);

	if (showcapimsgs & 1) {
		printk(KERN_DEBUG "kcapi: appl %d down\n", ap->applid);
	}

	return CAPI_NOERROR;
}

EXPORT_SYMBOL(capi20_release);

748 749 750 751 752 753 754 755 756
/**
 * capi20_put_message() - CAPI 2.0 operation CAPI_PUT_MESSAGE
 * @ap:		CAPI application descriptor structure.
 * @skb:	CAPI message.
 *
 * Transfer a single message to CAPI.
 * Return value: CAPI result code
 */

L
Linus Torvalds 已提交
757 758
u16 capi20_put_message(struct capi20_appl *ap, struct sk_buff *skb)
{
759
	struct capi_ctr *ctr;
L
Linus Torvalds 已提交
760 761 762 763 764
	int showctl = 0;
	u8 cmd, subcmd;

	DBG("applid %#x", ap->applid);
 
765
	if (ncontrollers == 0)
L
Linus Torvalds 已提交
766 767 768 769 770 771 772
		return CAPI_REGNOTINSTALLED;
	if ((ap->applid == 0) || ap->release_in_progress)
		return CAPI_ILLAPPNR;
	if (skb->len < 12
	    || !capi_cmd_valid(CAPIMSG_COMMAND(skb->data))
	    || !capi_subcmd_valid(CAPIMSG_SUBCOMMAND(skb->data)))
		return CAPI_ILLCMDORSUBCMDORMSGTOSMALL;
773 774 775 776 777 778

	/*
	 * The controller reference is protected by the existence of the
	 * application passed to us. We assume that the caller properly
	 * synchronizes this service with capi20_release.
	 */
779
	ctr = get_capi_ctr_by_nr(CAPIMSG_CONTROLLER(skb->data));
780 781
	if (!ctr || ctr->state != CAPI_CTR_RUNNING)
		return CAPI_REGNOTINSTALLED;
782
	if (ctr->blocked)
L
Linus Torvalds 已提交
783 784 785 786 787 788
		return CAPI_SENDQUEUEFULL;

	cmd = CAPIMSG_COMMAND(skb->data);
        subcmd = CAPIMSG_SUBCOMMAND(skb->data);

	if (cmd == CAPI_DATA_B3 && subcmd== CAPI_REQ) {
789
		ctr->nsentdatapkt++;
L
Linus Torvalds 已提交
790
		ap->nsentdatapkt++;
791 792
		if (ctr->traceflag > 2)
			showctl |= 2;
L
Linus Torvalds 已提交
793
	} else {
794
		ctr->nsentctlpkt++;
L
Linus Torvalds 已提交
795
		ap->nsentctlpkt++;
796 797
		if (ctr->traceflag)
			showctl |= 2;
L
Linus Torvalds 已提交
798
	}
799
	showctl |= (ctr->traceflag & 1);
L
Linus Torvalds 已提交
800 801
	if (showctl & 2) {
		if (showctl & 1) {
802
			printk(KERN_DEBUG "kcapi: put [%03d] id#%d %s len=%u\n",
L
Linus Torvalds 已提交
803 804 805 806 807
			       CAPIMSG_CONTROLLER(skb->data),
			       CAPIMSG_APPID(skb->data),
			       capi_cmd2str(cmd, subcmd),
			       CAPIMSG_LEN(skb->data));
		} else {
808 809 810 811 812 813 814 815 816 817 818 819
			_cdebbuf *cdb = capi_message2str(skb->data);
			if (cdb) {
				printk(KERN_DEBUG "kcapi: put [%03d] %s\n",
					CAPIMSG_CONTROLLER(skb->data),
					cdb->buf);
				cdebbuf_free(cdb);
			} else
				printk(KERN_DEBUG "kcapi: put [%03d] id#%d %s len=%u cannot trace\n",
					CAPIMSG_CONTROLLER(skb->data),
					CAPIMSG_APPID(skb->data),
					capi_cmd2str(cmd, subcmd),
					CAPIMSG_LEN(skb->data));
L
Linus Torvalds 已提交
820 821
		}
	}
822
	return ctr->send_message(ctr, skb);
L
Linus Torvalds 已提交
823 824 825 826
}

EXPORT_SYMBOL(capi20_put_message);

827 828 829 830 831 832 833 834 835 836
/**
 * capi20_get_manufacturer() - CAPI 2.0 operation CAPI_GET_MANUFACTURER
 * @contr:	controller number.
 * @buf:	result buffer (64 bytes).
 *
 * Retrieve information about the manufacturer of the specified ISDN controller
 * or (for @contr == 0) the driver itself.
 * Return value: CAPI result code
 */

L
Linus Torvalds 已提交
837 838
u16 capi20_get_manufacturer(u32 contr, u8 *buf)
{
839
	struct capi_ctr *ctr;
840
	u16 ret;
L
Linus Torvalds 已提交
841 842 843 844 845

	if (contr == 0) {
		strlcpy(buf, capi_manufakturer, CAPI_MANUFACTURER_LEN);
		return CAPI_NOERROR;
	}
846 847 848

	mutex_lock(&capi_controller_lock);

849
	ctr = get_capi_ctr_by_nr(contr);
850 851 852 853 854 855 856 857
	if (ctr && ctr->state == CAPI_CTR_RUNNING) {
		strlcpy(buf, ctr->manu, CAPI_MANUFACTURER_LEN);
		ret = CAPI_NOERROR;
	} else
		ret = CAPI_REGNOTINSTALLED;

	mutex_unlock(&capi_controller_lock);
	return ret;
L
Linus Torvalds 已提交
858 859 860 861
}

EXPORT_SYMBOL(capi20_get_manufacturer);

862 863 864 865 866 867 868 869 870 871
/**
 * capi20_get_version() - CAPI 2.0 operation CAPI_GET_VERSION
 * @contr:	controller number.
 * @verp:	result structure.
 *
 * Retrieve version information for the specified ISDN controller
 * or (for @contr == 0) the driver itself.
 * Return value: CAPI result code
 */

L
Linus Torvalds 已提交
872 873
u16 capi20_get_version(u32 contr, struct capi_version *verp)
{
874
	struct capi_ctr *ctr;
875
	u16 ret;
L
Linus Torvalds 已提交
876 877 878 879 880

	if (contr == 0) {
		*verp = driver_version;
		return CAPI_NOERROR;
	}
881 882 883

	mutex_lock(&capi_controller_lock);

884
	ctr = get_capi_ctr_by_nr(contr);
885 886 887 888 889
	if (ctr && ctr->state == CAPI_CTR_RUNNING) {
		memcpy(verp, &ctr->version, sizeof(capi_version));
		ret = CAPI_NOERROR;
	} else
		ret = CAPI_REGNOTINSTALLED;
L
Linus Torvalds 已提交
890

891 892
	mutex_unlock(&capi_controller_lock);
	return ret;
L
Linus Torvalds 已提交
893 894 895 896
}

EXPORT_SYMBOL(capi20_get_version);

897 898 899 900 901 902 903 904 905 906
/**
 * capi20_get_serial() - CAPI 2.0 operation CAPI_GET_SERIAL_NUMBER
 * @contr:	controller number.
 * @serial:	result buffer (8 bytes).
 *
 * Retrieve the serial number of the specified ISDN controller
 * or (for @contr == 0) the driver itself.
 * Return value: CAPI result code
 */

L
Linus Torvalds 已提交
907 908
u16 capi20_get_serial(u32 contr, u8 *serial)
{
909
	struct capi_ctr *ctr;
910
	u16 ret;
L
Linus Torvalds 已提交
911 912 913 914 915

	if (contr == 0) {
		strlcpy(serial, driver_serial, CAPI_SERIAL_LEN);
		return CAPI_NOERROR;
	}
916 917 918

	mutex_lock(&capi_controller_lock);

919
	ctr = get_capi_ctr_by_nr(contr);
920 921 922 923 924
	if (ctr && ctr->state == CAPI_CTR_RUNNING) {
		strlcpy(serial, ctr->serial, CAPI_SERIAL_LEN);
		ret = CAPI_NOERROR;
	} else
		ret = CAPI_REGNOTINSTALLED;
L
Linus Torvalds 已提交
925

926 927
	mutex_unlock(&capi_controller_lock);
	return ret;
L
Linus Torvalds 已提交
928 929 930 931
}

EXPORT_SYMBOL(capi20_get_serial);

932 933 934 935 936 937 938 939 940 941
/**
 * capi20_get_profile() - CAPI 2.0 operation CAPI_GET_PROFILE
 * @contr:	controller number.
 * @profp:	result structure.
 *
 * Retrieve capability information for the specified ISDN controller
 * or (for @contr == 0) the number of installed controllers.
 * Return value: CAPI result code
 */

L
Linus Torvalds 已提交
942 943
u16 capi20_get_profile(u32 contr, struct capi_profile *profp)
{
944
	struct capi_ctr *ctr;
945
	u16 ret;
L
Linus Torvalds 已提交
946 947

	if (contr == 0) {
948
		profp->ncontroller = ncontrollers;
L
Linus Torvalds 已提交
949 950
		return CAPI_NOERROR;
	}
951 952 953

	mutex_lock(&capi_controller_lock);

954
	ctr = get_capi_ctr_by_nr(contr);
955 956 957 958 959
	if (ctr && ctr->state == CAPI_CTR_RUNNING) {
		memcpy(profp, &ctr->profile, sizeof(struct capi_profile));
		ret = CAPI_NOERROR;
	} else
		ret = CAPI_REGNOTINSTALLED;
L
Linus Torvalds 已提交
960

961 962
	mutex_unlock(&capi_controller_lock);
	return ret;
L
Linus Torvalds 已提交
963 964 965 966
}

EXPORT_SYMBOL(capi20_get_profile);

967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002
/* Must be called with capi_controller_lock held. */
static int wait_on_ctr_state(struct capi_ctr *ctr, unsigned int state)
{
	DEFINE_WAIT(wait);
	int retval = 0;

	ctr = capi_ctr_get(ctr);
	if (!ctr)
		return -ESRCH;

	for (;;) {
		prepare_to_wait(&ctr->state_wait_queue, &wait,
				TASK_INTERRUPTIBLE);

		if (ctr->state == state)
			break;
		if (ctr->state == CAPI_CTR_DETACHED) {
			retval = -ESRCH;
			break;
		}
		if (signal_pending(current)) {
			retval = -EINTR;
			break;
		}

		mutex_unlock(&capi_controller_lock);
		schedule();
		mutex_lock(&capi_controller_lock);
	}
	finish_wait(&ctr->state_wait_queue, &wait);

	capi_ctr_put(ctr);

	return retval;
}

1003
#ifdef AVMB1_COMPAT
L
Linus Torvalds 已提交
1004 1005 1006 1007 1008 1009
static int old_capi_manufacturer(unsigned int cmd, void __user *data)
{
	avmb1_loadandconfigdef ldef;
	avmb1_extcarddef cdef;
	avmb1_resetdef rdef;
	capicardparams cparams;
1010
	struct capi_ctr *ctr;
L
Linus Torvalds 已提交
1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032
	struct capi_driver *driver = NULL;
	capiloaddata ldata;
	struct list_head *l;
	int retval;

	switch (cmd) {
	case AVMB1_ADDCARD:
	case AVMB1_ADDCARD_WITH_TYPE:
		if (cmd == AVMB1_ADDCARD) {
		   if ((retval = copy_from_user(&cdef, data,
					    sizeof(avmb1_carddef))))
			   return retval;
		   cdef.cardtype = AVM_CARDTYPE_B1;
		} else {
		   if ((retval = copy_from_user(&cdef, data,
					    sizeof(avmb1_extcarddef))))
			   return retval;
		}
		cparams.port = cdef.port;
		cparams.irq = cdef.irq;
		cparams.cardnr = cdef.cardnr;

1033 1034
		mutex_lock(&capi_drivers_lock);

L
Linus Torvalds 已提交
1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055
                switch (cdef.cardtype) {
			case AVM_CARDTYPE_B1:
				list_for_each(l, &capi_drivers) {
					driver = list_entry(l, struct capi_driver, list);
					if (strcmp(driver->name, "b1isa") == 0)
						break;
				}
				break;
			case AVM_CARDTYPE_T1:
				list_for_each(l, &capi_drivers) {
					driver = list_entry(l, struct capi_driver, list);
					if (strcmp(driver->name, "t1isa") == 0)
						break;
				}
				break;
			default:
				driver = NULL;
				break;
		}
		if (!driver) {
			printk(KERN_ERR "kcapi: driver not loaded.\n");
1056 1057
			retval = -EIO;
		} else if (!driver->add_card) {
L
Linus Torvalds 已提交
1058
			printk(KERN_ERR "kcapi: driver has no add card function.\n");
1059 1060 1061
			retval = -EIO;
		} else
			retval = driver->add_card(driver, &cparams);
L
Linus Torvalds 已提交
1062

1063
		mutex_unlock(&capi_drivers_lock);
L
Linus Torvalds 已提交
1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079
		return retval;

	case AVMB1_LOAD:
	case AVMB1_LOAD_AND_CONFIG:

		if (cmd == AVMB1_LOAD) {
			if (copy_from_user(&ldef, data,
					   sizeof(avmb1_loaddef)))
				return -EFAULT;
			ldef.t4config.len = 0;
			ldef.t4config.data = NULL;
		} else {
			if (copy_from_user(&ldef, data,
					   sizeof(avmb1_loadandconfigdef)))
				return -EFAULT;
		}
1080 1081 1082

		mutex_lock(&capi_controller_lock);

1083
		ctr = get_capi_ctr_by_nr(ldef.contr);
1084 1085 1086 1087 1088
		if (!ctr) {
			retval = -EINVAL;
			goto load_unlock_out;
		}

1089
		if (ctr->load_firmware == NULL) {
L
Linus Torvalds 已提交
1090
			printk(KERN_DEBUG "kcapi: load: no load function\n");
1091 1092
			retval = -ESRCH;
			goto load_unlock_out;
L
Linus Torvalds 已提交
1093 1094 1095 1096
		}

		if (ldef.t4file.len <= 0) {
			printk(KERN_DEBUG "kcapi: load: invalid parameter: length of t4file is %d ?\n", ldef.t4file.len);
1097 1098
			retval = -EINVAL;
			goto load_unlock_out;
L
Linus Torvalds 已提交
1099
		}
1100
		if (ldef.t4file.data == NULL) {
L
Linus Torvalds 已提交
1101
			printk(KERN_DEBUG "kcapi: load: invalid parameter: dataptr is 0\n");
1102 1103
			retval = -EINVAL;
			goto load_unlock_out;
L
Linus Torvalds 已提交
1104 1105 1106 1107 1108 1109 1110 1111 1112
		}

		ldata.firmware.user = 1;
		ldata.firmware.data = ldef.t4file.data;
		ldata.firmware.len = ldef.t4file.len;
		ldata.configuration.user = 1;
		ldata.configuration.data = ldef.t4config.data;
		ldata.configuration.len = ldef.t4config.len;

1113
		if (ctr->state != CAPI_CTR_DETECTED) {
L
Linus Torvalds 已提交
1114
			printk(KERN_INFO "kcapi: load: contr=%d not in detect state\n", ldef.contr);
1115 1116
			retval = -EBUSY;
			goto load_unlock_out;
L
Linus Torvalds 已提交
1117
		}
1118
		ctr->state = CAPI_CTR_LOADING;
L
Linus Torvalds 已提交
1119

1120
		retval = ctr->load_firmware(ctr, &ldata);
L
Linus Torvalds 已提交
1121
		if (retval) {
1122
			ctr->state = CAPI_CTR_DETECTED;
1123
			goto load_unlock_out;
L
Linus Torvalds 已提交
1124 1125
		}

1126
		retval = wait_on_ctr_state(ctr, CAPI_CTR_RUNNING);
L
Linus Torvalds 已提交
1127

1128 1129 1130
load_unlock_out:
		mutex_unlock(&capi_controller_lock);
		return retval;
L
Linus Torvalds 已提交
1131 1132 1133 1134

	case AVMB1_RESETCARD:
		if (copy_from_user(&rdef, data, sizeof(avmb1_resetdef)))
			return -EFAULT;
1135 1136 1137 1138 1139

		retval = 0;

		mutex_lock(&capi_controller_lock);

1140
		ctr = get_capi_ctr_by_nr(rdef.contr);
1141 1142 1143 1144
		if (!ctr) {
			retval = -ESRCH;
			goto reset_unlock_out;
		}
L
Linus Torvalds 已提交
1145

1146
		if (ctr->state == CAPI_CTR_DETECTED)
1147
			goto reset_unlock_out;
L
Linus Torvalds 已提交
1148

1149
		ctr->reset_ctr(ctr);
L
Linus Torvalds 已提交
1150

1151
		retval = wait_on_ctr_state(ctr, CAPI_CTR_DETECTED);
L
Linus Torvalds 已提交
1152

1153 1154 1155
reset_unlock_out:
		mutex_unlock(&capi_controller_lock);
		return retval;
L
Linus Torvalds 已提交
1156 1157 1158 1159 1160
	}
	return -EINVAL;
}
#endif

1161 1162 1163 1164 1165 1166 1167 1168 1169
/**
 * capi20_manufacturer() - CAPI 2.0 operation CAPI_MANUFACTURER
 * @cmd:	command.
 * @data:	parameter.
 *
 * Perform manufacturer specific command.
 * Return value: CAPI result code
 */

L
Linus Torvalds 已提交
1170 1171
int capi20_manufacturer(unsigned int cmd, void __user *data)
{
1172
	struct capi_ctr *ctr;
1173
	int retval;
L
Linus Torvalds 已提交
1174 1175

	switch (cmd) {
1176
#ifdef AVMB1_COMPAT
L
Linus Torvalds 已提交
1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190
	case AVMB1_LOAD:
	case AVMB1_LOAD_AND_CONFIG:
	case AVMB1_RESETCARD:
	case AVMB1_GET_CARDINFO:
	case AVMB1_REMOVECARD:
		return old_capi_manufacturer(cmd, data);
#endif
	case KCAPI_CMD_TRACE:
	{
		kcapi_flagdef fdef;

		if (copy_from_user(&fdef, data, sizeof(kcapi_flagdef)))
			return -EFAULT;

1191 1192
		mutex_lock(&capi_controller_lock);

1193
		ctr = get_capi_ctr_by_nr(fdef.contr);
1194 1195 1196 1197 1198 1199 1200 1201 1202
		if (ctr) {
			ctr->traceflag = fdef.flag;
			printk(KERN_INFO "kcapi: contr [%03d] set trace=%d\n",
			       ctr->cnr, ctr->traceflag);
			retval = 0;
		} else
			retval = -ESRCH;

		mutex_unlock(&capi_controller_lock);
L
Linus Torvalds 已提交
1203

1204
		return retval;
L
Linus Torvalds 已提交
1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222
	}
	case KCAPI_CMD_ADDCARD:
	{
		struct list_head *l;
		struct capi_driver *driver = NULL;
		capicardparams cparams;
		kcapi_carddef cdef;

		if ((retval = copy_from_user(&cdef, data, sizeof(cdef))))
			return retval;

		cparams.port = cdef.port;
		cparams.irq = cdef.irq;
		cparams.membase = cdef.membase;
		cparams.cardnr = cdef.cardnr;
		cparams.cardtype = 0;
		cdef.driver[sizeof(cdef.driver)-1] = 0;

1223 1224
		mutex_lock(&capi_drivers_lock);

L
Linus Torvalds 已提交
1225 1226 1227 1228 1229
		list_for_each(l, &capi_drivers) {
			driver = list_entry(l, struct capi_driver, list);
			if (strcmp(driver->name, cdef.driver) == 0)
				break;
		}
1230
		if (driver == NULL) {
L
Linus Torvalds 已提交
1231 1232
			printk(KERN_ERR "kcapi: driver \"%s\" not loaded.\n",
					cdef.driver);
1233 1234
			retval = -ESRCH;
		} else if (!driver->add_card) {
L
Linus Torvalds 已提交
1235
			printk(KERN_ERR "kcapi: driver \"%s\" has no add card function.\n", cdef.driver);
1236 1237 1238
			retval = -EIO;
		} else
			retval = driver->add_card(driver, &cparams);
L
Linus Torvalds 已提交
1239

1240 1241
		mutex_unlock(&capi_drivers_lock);
		return retval;
L
Linus Torvalds 已提交
1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262
	}

	default:
		printk(KERN_ERR "kcapi: manufacturer command %d unknown.\n",
					cmd);
		break;

	}
	return -EINVAL;
}

EXPORT_SYMBOL(capi20_manufacturer);

/* ------------------------------------------------------------- */
/* -------- Init & Cleanup ------------------------------------- */
/* ------------------------------------------------------------- */

/*
 * init / exit functions
 */

1263 1264 1265 1266 1267
static struct notifier_block capictr_nb = {
	.notifier_call = notify_handler,
	.priority = INT_MAX,
};

L
Linus Torvalds 已提交
1268 1269
static int __init kcapi_init(void)
{
1270
	int err;
L
Linus Torvalds 已提交
1271

1272 1273
	register_capictr_notifier(&capictr_nb);

1274 1275 1276 1277
	err = cdebug_init();
	if (!err)
		kcapi_proc_init();
	return err;
L
Linus Torvalds 已提交
1278 1279 1280 1281 1282 1283 1284 1285
}

static void __exit kcapi_exit(void)
{
        kcapi_proc_exit();

	/* make sure all notifiers are finished */
	flush_scheduled_work();
1286
	cdebug_exit();
L
Linus Torvalds 已提交
1287 1288 1289 1290
}

module_init(kcapi_init);
module_exit(kcapi_exit);