kcapi.c 29.2 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
#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>
30
#include <linux/slab.h>
L
Linus Torvalds 已提交
31 32 33
#include <asm/uaccess.h>
#include <linux/isdn/capicmd.h>
#include <linux/isdn/capiutil.h>
34
#ifdef AVMB1_COMPAT
L
Linus Torvalds 已提交
35 36
#include <linux/b1lli.h>
#endif
A
Arjan van de Ven 已提交
37
#include <linux/mutex.h>
J
Jan Kiszka 已提交
38
#include <linux/rcupdate.h>
L
Linus Torvalds 已提交
39 40 41 42 43 44 45 46 47 48

static int showcapimsgs = 0;

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

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

49
struct capictr_event {
L
Linus Torvalds 已提交
50
	struct work_struct work;
51
	unsigned int type;
L
Linus Torvalds 已提交
52 53 54 55 56 57 58 59 60 61 62 63
	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);
64
DEFINE_MUTEX(capi_drivers_lock);
L
Linus Torvalds 已提交
65

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

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

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

73 74
static BLOCKING_NOTIFIER_HEAD(ctr_notifier_list);

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

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

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

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

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

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

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

J
Jan Kiszka 已提交
106
	return rcu_dereference(capi_applications[applid - 1]);
L
Linus Torvalds 已提交
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 147
}

/* -------- 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;
}

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

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

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


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

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

175 176
	mutex_lock(&capi_controller_lock);

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

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

		ctr->state = CAPI_CTR_RUNNING;

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

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

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

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

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

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

	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 已提交
216 217 218

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

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

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

230 231
	mutex_lock(&capi_controller_lock);

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

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

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

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

249 250 251
	switch (val) {
	case CAPICTR_UP:
		notify_up(contr);
L
Linus Torvalds 已提交
252
		break;
253 254
	case CAPICTR_DOWN:
		notify_down(contr);
L
Linus Torvalds 已提交
255 256
		break;
	}
257 258 259 260 261 262 263
	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 已提交
264

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

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

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

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

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

289 290 291 292 293 294 295 296 297 298 299 300
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 已提交
301 302
/* -------- Receiver ------------------------------------------ */

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

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

312
	mutex_lock(&ap->recv_mtx);
L
Linus Torvalds 已提交
313 314 315 316 317 318 319 320
	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);
	}
321
	mutex_unlock(&ap->recv_mtx);
L
Linus Torvalds 已提交
322 323
}

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

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

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

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

	}

J
Jan Kiszka 已提交
386
	rcu_read_lock();
L
Linus Torvalds 已提交
387
	ap = get_capi_appl_by_nr(CAPIMSG_APPID(skb->data));
J
Jan Kiszka 已提交
388 389
	if (!ap) {
		rcu_read_unlock();
390 391 392 393 394 395 396 397 398
		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 已提交
399 400 401 402
		goto error;
	}
	skb_queue_tail(&ap->recv_queue, skb);
	schedule_work(&ap->recv_work);
J
Jan Kiszka 已提交
403
	rcu_read_unlock();
L
Linus Torvalds 已提交
404 405 406 407 408 409 410 411 412

	return;

error:
	kfree_skb(skb);
}

EXPORT_SYMBOL(capi_ctr_handle_message);

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

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

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

EXPORT_SYMBOL(capi_ctr_ready);

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

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

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

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

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

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

EXPORT_SYMBOL(capi_ctr_suspend_output);

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

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

EXPORT_SYMBOL(capi_ctr_resume_output);

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

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

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

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

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

516 517 518 519 520 521 522 523
	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;
524
	init_waitqueue_head(&ctr->state_wait_queue);
525 526 527 528 529

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

	ncontrollers++;
530 531 532

	mutex_unlock(&capi_controller_lock);

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

EXPORT_SYMBOL(attach_capi_ctr);

540 541
/**
 * detach_capi_ctr() - unregister CAPI controller
542
 * @ctr:	controller descriptor structure.
543 544 545 546 547 548
 *
 * 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
 */

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

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

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

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

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

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

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

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

EXPORT_SYMBOL(detach_capi_ctr);

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

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

EXPORT_SYMBOL(register_capi_driver);

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

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

EXPORT_SYMBOL(unregister_capi_driver);

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

614 615 616 617 618 619 620
/**
 * 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 已提交
621 622
u16 capi20_isinstalled(void)
{
623
	u16 ret = CAPI_REGNOTINSTALLED;
L
Linus Torvalds 已提交
624
	int i;
625 626 627 628

	mutex_lock(&capi_controller_lock);

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

	mutex_unlock(&capi_controller_lock);

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

EXPORT_SYMBOL(capi20_isinstalled);

642 643 644 645 646 647 648 649 650 651 652 653
/**
 * 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 已提交
654 655 656 657 658 659 660 661 662 663
u16 capi20_register(struct capi20_appl *ap)
{
	int i;
	u16 applid;

	DBG("");

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

J
Jan Kiszka 已提交
664 665 666 667 668 669 670 671 672 673
	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 已提交
674 675 676 677 678 679

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

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

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

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

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

	return CAPI_NOERROR;
}

EXPORT_SYMBOL(capi20_register);

705 706 707 708 709 710 711 712 713 714
/**
 * 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 已提交
715 716 717 718 719 720
u16 capi20_release(struct capi20_appl *ap)
{
	int i;

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

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

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

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

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

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

	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);

749 750 751 752 753 754 755 756 757
/**
 * 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 已提交
758 759
u16 capi20_put_message(struct capi20_appl *ap, struct sk_buff *skb)
{
760
	struct capi_ctr *ctr;
L
Linus Torvalds 已提交
761 762 763 764 765
	int showctl = 0;
	u8 cmd, subcmd;

	DBG("applid %#x", ap->applid);
 
766
	if (ncontrollers == 0)
L
Linus Torvalds 已提交
767 768 769 770 771 772 773
		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;
774 775 776 777 778 779

	/*
	 * 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.
	 */
780
	ctr = get_capi_ctr_by_nr(CAPIMSG_CONTROLLER(skb->data));
781 782
	if (!ctr || ctr->state != CAPI_CTR_RUNNING)
		return CAPI_REGNOTINSTALLED;
783
	if (ctr->blocked)
L
Linus Torvalds 已提交
784 785 786 787 788 789
		return CAPI_SENDQUEUEFULL;

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

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

EXPORT_SYMBOL(capi20_put_message);

828 829 830 831 832 833 834 835 836 837
/**
 * 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 已提交
838 839
u16 capi20_get_manufacturer(u32 contr, u8 *buf)
{
840
	struct capi_ctr *ctr;
841
	u16 ret;
L
Linus Torvalds 已提交
842 843 844 845 846

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

	mutex_lock(&capi_controller_lock);

850
	ctr = get_capi_ctr_by_nr(contr);
851 852 853 854 855 856 857 858
	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 已提交
859 860 861 862
}

EXPORT_SYMBOL(capi20_get_manufacturer);

863 864 865 866 867 868 869 870 871 872
/**
 * 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 已提交
873 874
u16 capi20_get_version(u32 contr, struct capi_version *verp)
{
875
	struct capi_ctr *ctr;
876
	u16 ret;
L
Linus Torvalds 已提交
877 878 879 880 881

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

	mutex_lock(&capi_controller_lock);

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

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

EXPORT_SYMBOL(capi20_get_version);

898 899 900 901 902 903 904 905 906 907
/**
 * 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 已提交
908 909
u16 capi20_get_serial(u32 contr, u8 *serial)
{
910
	struct capi_ctr *ctr;
911
	u16 ret;
L
Linus Torvalds 已提交
912 913 914 915 916

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

	mutex_lock(&capi_controller_lock);

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

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

EXPORT_SYMBOL(capi20_get_serial);

933 934 935 936 937 938 939 940 941 942
/**
 * 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 已提交
943 944
u16 capi20_get_profile(u32 contr, struct capi_profile *profp)
{
945
	struct capi_ctr *ctr;
946
	u16 ret;
L
Linus Torvalds 已提交
947 948

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

	mutex_lock(&capi_controller_lock);

955
	ctr = get_capi_ctr_by_nr(contr);
956 957 958 959 960
	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 已提交
961

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

EXPORT_SYMBOL(capi20_get_profile);

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 1003
/* 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;
}

1004
#ifdef AVMB1_COMPAT
L
Linus Torvalds 已提交
1005 1006 1007 1008 1009 1010
static int old_capi_manufacturer(unsigned int cmd, void __user *data)
{
	avmb1_loadandconfigdef ldef;
	avmb1_extcarddef cdef;
	avmb1_resetdef rdef;
	capicardparams cparams;
1011
	struct capi_ctr *ctr;
L
Linus Torvalds 已提交
1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033
	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;

1034 1035
		mutex_lock(&capi_drivers_lock);

L
Linus Torvalds 已提交
1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056
                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");
1057 1058
			retval = -EIO;
		} else if (!driver->add_card) {
L
Linus Torvalds 已提交
1059
			printk(KERN_ERR "kcapi: driver has no add card function.\n");
1060 1061 1062
			retval = -EIO;
		} else
			retval = driver->add_card(driver, &cparams);
L
Linus Torvalds 已提交
1063

1064
		mutex_unlock(&capi_drivers_lock);
L
Linus Torvalds 已提交
1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080
		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;
		}
1081 1082 1083

		mutex_lock(&capi_controller_lock);

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

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

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

		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;

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

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

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

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

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

		retval = 0;

		mutex_lock(&capi_controller_lock);

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

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

1150 1151 1152 1153 1154 1155
		if (ctr->reset_ctr == NULL) {
			printk(KERN_DEBUG "kcapi: reset: no reset function\n");
			retval = -ESRCH;
			goto reset_unlock_out;
		}

1156
		ctr->reset_ctr(ctr);
L
Linus Torvalds 已提交
1157

1158
		retval = wait_on_ctr_state(ctr, CAPI_CTR_DETECTED);
L
Linus Torvalds 已提交
1159

1160 1161 1162
reset_unlock_out:
		mutex_unlock(&capi_controller_lock);
		return retval;
L
Linus Torvalds 已提交
1163 1164 1165 1166 1167
	}
	return -EINVAL;
}
#endif

1168 1169 1170 1171 1172 1173 1174 1175 1176
/**
 * capi20_manufacturer() - CAPI 2.0 operation CAPI_MANUFACTURER
 * @cmd:	command.
 * @data:	parameter.
 *
 * Perform manufacturer specific command.
 * Return value: CAPI result code
 */

L
Linus Torvalds 已提交
1177 1178
int capi20_manufacturer(unsigned int cmd, void __user *data)
{
1179
	struct capi_ctr *ctr;
1180
	int retval;
L
Linus Torvalds 已提交
1181 1182

	switch (cmd) {
1183
#ifdef AVMB1_COMPAT
L
Linus Torvalds 已提交
1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197
	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;

1198 1199
		mutex_lock(&capi_controller_lock);

1200
		ctr = get_capi_ctr_by_nr(fdef.contr);
1201 1202 1203 1204 1205 1206 1207 1208 1209
		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 已提交
1210

1211
		return retval;
L
Linus Torvalds 已提交
1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229
	}
	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;

1230 1231
		mutex_lock(&capi_drivers_lock);

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

1247 1248
		mutex_unlock(&capi_drivers_lock);
		return retval;
L
Linus Torvalds 已提交
1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269
	}

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

	}
	return -EINVAL;
}

EXPORT_SYMBOL(capi20_manufacturer);

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

/*
 * init / exit functions
 */

1270 1271 1272 1273 1274
static struct notifier_block capictr_nb = {
	.notifier_call = notify_handler,
	.priority = INT_MAX,
};

L
Linus Torvalds 已提交
1275 1276
static int __init kcapi_init(void)
{
1277
	int err;
L
Linus Torvalds 已提交
1278

1279 1280
	register_capictr_notifier(&capictr_nb);

1281 1282 1283 1284
	err = cdebug_init();
	if (!err)
		kcapi_proc_init();
	return err;
L
Linus Torvalds 已提交
1285 1286 1287 1288 1289 1290 1291 1292
}

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

	/* make sure all notifiers are finished */
	flush_scheduled_work();
1293
	cdebug_exit();
L
Linus Torvalds 已提交
1294 1295 1296 1297
}

module_init(kcapi_init);
module_exit(kcapi_exit);