i4l.c 18.2 KB
Newer Older
1 2 3
/*
 * Stuff used by all variants of the driver
 *
4 5 6
 * Copyright (c) 2001 by Stefan Eilers,
 *                       Hansjoerg Lipp <hjlipp@web.de>,
 *                       Tilman Schmidt <tilman@imap.cc>.
7 8 9 10 11 12 13 14 15 16
 *
 * =====================================================================
 *	This program is free software; you can redistribute it and/or
 *	modify it under the terms of the GNU General Public License as
 *	published by the Free Software Foundation; either version 2 of
 *	the License, or (at your option) any later version.
 * =====================================================================
 */

#include "gigaset.h"
17 18 19
#include <linux/isdnif.h>

#define HW_HDR_LEN	2	/* Header size used to store ack info */
20

21
/* == Handling of I4L IO =====================================================*/
22 23 24 25 26 27 28 29 30

/* writebuf_from_LL
 * called by LL to transmit data on an open channel
 * inserts the buffer data into the send queue and starts the transmission
 * Note that this operation must not sleep!
 * When the buffer is processed completely, gigaset_skb_sent() should be called.
 * parameters:
 *	driverID	driver ID as assigned by LL
 *	channel		channel number
31 32
 *	ack		if != 0 LL wants to be notified on completion via
 *			statcallb(ISDN_STAT_BSENT)
33 34 35 36 37 38
 *	skb		skb containing data to send
 * return value:
 *	number of accepted bytes
 *	0 if temporarily unable to accept data (out of buffer space)
 *	<0 on error (eg. -EINVAL)
 */
39 40
static int writebuf_from_LL(int driverID, int channel, int ack,
			    struct sk_buff *skb)
41 42 43 44 45 46 47
{
	struct cardstate *cs;
	struct bc_state *bcs;
	unsigned len;
	unsigned skblen;

	if (!(cs = gigaset_get_cs_by_id(driverID))) {
48
		pr_err("%s: invalid driver ID (%d)\n", __func__, driverID);
49 50 51
		return -ENODEV;
	}
	if (channel < 0 || channel >= cs->channels) {
52 53
		dev_err(cs->dev, "%s: invalid channel ID (%d)\n",
			__func__, channel);
54 55 56
		return -ENODEV;
	}
	bcs = &cs->bcs[channel];
T
Tilman Schmidt 已提交
57 58 59 60 61 62

	/* can only handle linear sk_buffs */
	if (skb_linearize(skb) < 0) {
		dev_err(cs->dev, "%s: skb_linearize failed\n", __func__);
		return -ENOMEM;
	}
63 64
	len = skb->len;

65 66 67 68
	gig_dbg(DEBUG_LLDATA,
		"Receiving data from LL (id: %d, ch: %d, ack: %d, sz: %d)",
		driverID, channel, ack, len);

69 70
	if (!len) {
		if (ack)
71 72
			dev_notice(cs->dev, "%s: not ACKing empty packet\n",
				   __func__);
73 74 75
		return 0;
	}
	if (len > MAX_BUF_SIZE) {
76 77
		dev_err(cs->dev, "%s: packet too large (%d bytes)\n",
			__func__, len);
78 79 80 81 82 83
		return -EINVAL;
	}

	skblen = ack ? len : 0;
	skb->head[0] = skblen & 0xff;
	skb->head[1] = skblen >> 8;
84 85
	gig_dbg(DEBUG_MCMD, "skb: len=%u, skblen=%u: %02x %02x",
		len, skblen, (unsigned) skb->head[0], (unsigned) skb->head[1]);
86 87

	/* pass to device-specific module */
88
	return cs->ops->send_skb(bcs, skb);
89 90
}

T
Tilman Schmidt 已提交
91 92 93 94 95 96 97 98
/**
 * gigaset_skb_sent() - acknowledge sending an skb
 * @bcs:	B channel descriptor structure.
 * @skb:	sent data.
 *
 * Called by hardware module {bas,ser,usb}_gigaset when the data in a
 * skb has been successfully sent, for signalling completion to the LL.
 */
99 100
void gigaset_skb_sent(struct bc_state *bcs, struct sk_buff *skb)
{
101
	isdn_if *iif = bcs->cs->iif;
102 103 104 105 106 107
	unsigned len;
	isdn_ctrl response;

	++bcs->trans_up;

	if (skb->len)
108 109
		dev_warn(bcs->cs->dev, "%s: skb->len==%d\n",
			 __func__, skb->len);
110 111 112 113

	len = (unsigned char) skb->head[0] |
	      (unsigned) (unsigned char) skb->head[1] << 8;
	if (len) {
114 115
		gig_dbg(DEBUG_MCMD, "ACKing to LL (id: %d, ch: %d, sz: %u)",
			bcs->cs->myid, bcs->channel, len);
116 117 118 119 120

		response.driver = bcs->cs->myid;
		response.command = ISDN_STAT_BSENT;
		response.arg = bcs->channel;
		response.parm.length = len;
121
		iif->statcallb(&response);
122 123 124 125
	}
}
EXPORT_SYMBOL_GPL(gigaset_skb_sent);

126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174
/**
 * gigaset_skb_rcvd() - pass received skb to LL
 * @bcs:	B channel descriptor structure.
 * @skb:	received data.
 *
 * Called by hardware module {bas,ser,usb}_gigaset when user data has
 * been successfully received, for passing to the LL.
 * Warning: skb must not be accessed anymore!
 */
void gigaset_skb_rcvd(struct bc_state *bcs, struct sk_buff *skb)
{
	isdn_if *iif = bcs->cs->iif;

	iif->rcvcallb_skb(bcs->cs->myid, bcs->channel, skb);
	bcs->trans_down++;
}
EXPORT_SYMBOL_GPL(gigaset_skb_rcvd);

/**
 * gigaset_isdn_rcv_err() - signal receive error
 * @bcs:	B channel descriptor structure.
 *
 * Called by hardware module {bas,ser,usb}_gigaset when a receive error
 * has occurred, for signalling to the LL.
 */
void gigaset_isdn_rcv_err(struct bc_state *bcs)
{
	isdn_if *iif = bcs->cs->iif;
	isdn_ctrl response;

	/* if currently ignoring packets, just count down */
	if (bcs->ignore) {
		bcs->ignore--;
		return;
	}

	/* update statistics */
	bcs->corrupted++;

	/* error -> LL */
	gig_dbg(DEBUG_CMD, "sending L1ERR");
	response.driver = bcs->cs->myid;
	response.command = ISDN_STAT_L1ERR;
	response.arg = bcs->channel;
	response.parm.errcode = ISDN_STAT_L1ERR_RECV;
	iif->statcallb(&response);
}
EXPORT_SYMBOL_GPL(gigaset_isdn_rcv_err);

175 176 177 178 179 180
/* This function will be called by LL to send commands
 * NOTE: LL ignores the returned value, for commands other than ISDN_CMD_IOCTL,
 * so don't put too much effort into it.
 */
static int command_from_LL(isdn_ctrl *cntrl)
{
181
	struct cardstate *cs;
182 183
	struct bc_state *bcs;
	int retval = 0;
184 185 186 187
	char **commands;
	int ch;
	int i;
	size_t l;
188 189 190

	gigaset_debugdrivers();

191 192 193 194 195
	gig_dbg(DEBUG_CMD, "driver: %d, command: %d, arg: 0x%lx",
		cntrl->driver, cntrl->command, cntrl->arg);

	cs = gigaset_get_cs_by_id(cntrl->driver);
	if (cs == NULL) {
196
		pr_err("%s: invalid driver ID (%d)\n", __func__, cntrl->driver);
197 198
		return -ENODEV;
	}
199
	ch = cntrl->arg & 0xff;
200 201 202

	switch (cntrl->command) {
	case ISDN_CMD_IOCTL:
203
		dev_warn(cs->dev, "ISDN_CMD_IOCTL not supported\n");
204 205 206
		return -EINVAL;

	case ISDN_CMD_DIAL:
207
		gig_dbg(DEBUG_ANY,
208
			"ISDN_CMD_DIAL (phone: %s, msn: %s, si1: %d, si2: %d)",
209 210
			cntrl->parm.setup.phone, cntrl->parm.setup.eazmsn,
			cntrl->parm.setup.si1, cntrl->parm.setup.si2);
211

212
		if (ch >= cs->channels) {
213
			dev_err(cs->dev,
214
				"ISDN_CMD_DIAL: invalid channel (%d)\n", ch);
215 216
			return -EINVAL;
		}
217
		bcs = cs->bcs + ch;
218
		if (!gigaset_get_channel(bcs)) {
219
			dev_err(cs->dev, "ISDN_CMD_DIAL: channel not free\n");
220 221 222
			return -EBUSY;
		}

223 224
		commands = kzalloc(AT_NUM*(sizeof *commands), GFP_ATOMIC);
		if (!commands) {
225
			gigaset_free_channel(bcs);
226
			dev_err(cs->dev, "ISDN_CMD_DIAL: out of memory\n");
227 228 229
			return -ENOMEM;
		}

230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287
		l = 3 + strlen(cntrl->parm.setup.phone);
		commands[AT_DIAL] = kmalloc(l, GFP_ATOMIC);
		if (!commands[AT_DIAL])
			goto oom;
		if (cntrl->parm.setup.phone[0] == '*' &&
		    cntrl->parm.setup.phone[1] == '*') {
			/* internal call: translate ** prefix to CTP value */
			commands[AT_TYPE] = kstrdup("^SCTP=0\r", GFP_ATOMIC);
			if (!commands[AT_TYPE])
				goto oom;
			snprintf(commands[AT_DIAL], l,
				 "D%s\r", cntrl->parm.setup.phone+2);
		} else {
			commands[AT_TYPE] = kstrdup("^SCTP=1\r", GFP_ATOMIC);
			if (!commands[AT_TYPE])
				goto oom;
			snprintf(commands[AT_DIAL], l,
				 "D%s\r", cntrl->parm.setup.phone);
		}

		l = strlen(cntrl->parm.setup.eazmsn);
		if (l) {
			l += 8;
			commands[AT_MSN] = kmalloc(l, GFP_ATOMIC);
			if (!commands[AT_MSN])
				goto oom;
			snprintf(commands[AT_MSN], l, "^SMSN=%s\r",
				 cntrl->parm.setup.eazmsn);
		}

		switch (cntrl->parm.setup.si1) {
		case 1:		/* audio */
			/* BC = 9090A3: 3.1 kHz audio, A-law */
			commands[AT_BC] = kstrdup("^SBC=9090A3\r", GFP_ATOMIC);
			if (!commands[AT_BC])
				goto oom;
			break;
		case 7:		/* data */
		default:	/* hope the app knows what it is doing */
			/* BC = 8890: unrestricted digital information */
			commands[AT_BC] = kstrdup("^SBC=8890\r", GFP_ATOMIC);
			if (!commands[AT_BC])
				goto oom;
		}
		/* ToDo: other si1 values, inspect si2, set HLC/LLC */

		commands[AT_PROTO] = kmalloc(9, GFP_ATOMIC);
		if (!commands[AT_PROTO])
			goto oom;
		snprintf(commands[AT_PROTO], 9, "^SBPR=%u\r", bcs->proto2);

		commands[AT_ISO] = kmalloc(9, GFP_ATOMIC);
		if (!commands[AT_ISO])
			goto oom;
		snprintf(commands[AT_ISO], 9, "^SISO=%u\r",
			 (unsigned) bcs->channel + 1);

		if (!gigaset_add_event(cs, &bcs->at_state, EV_DIAL, commands,
T
Tilman Schmidt 已提交
288
				       bcs->at_state.seq_index, NULL)) {
289 290 291
			for (i = 0; i < AT_NUM; ++i)
				kfree(commands[i]);
			kfree(commands);
292 293 294 295
			gigaset_free_channel(bcs);
			return -ENOMEM;
		}

296
		gig_dbg(DEBUG_CMD, "scheduling DIAL");
297 298
		gigaset_schedule_event(cs);
		break;
299 300
	case ISDN_CMD_ACCEPTD:
		if (ch >= cs->channels) {
301
			dev_err(cs->dev,
302
				"ISDN_CMD_ACCEPTD: invalid channel (%d)\n", ch);
303 304
			return -EINVAL;
		}
305 306 307
		bcs = cs->bcs + ch;
		if (!gigaset_add_event(cs, &bcs->at_state,
				       EV_ACCEPT, NULL, 0, NULL))
308 309
			return -ENOMEM;

310
		gig_dbg(DEBUG_CMD, "scheduling ACCEPT");
311 312 313 314 315 316
		gigaset_schedule_event(cs);

		break;
	case ISDN_CMD_ACCEPTB:
		break;
	case ISDN_CMD_HANGUP:
317
		if (ch >= cs->channels) {
318
			dev_err(cs->dev,
319
				"ISDN_CMD_HANGUP: invalid channel (%d)\n", ch);
320 321
			return -EINVAL;
		}
322 323 324
		bcs = cs->bcs + ch;
		if (!gigaset_add_event(cs, &bcs->at_state,
				       EV_HUP, NULL, 0, NULL))
325 326
			return -ENOMEM;

327
		gig_dbg(DEBUG_CMD, "scheduling HUP");
328 329 330
		gigaset_schedule_event(cs);

		break;
331 332
	case ISDN_CMD_CLREAZ: /* Do not signal incoming signals */
		dev_info(cs->dev, "ignoring ISDN_CMD_CLREAZ\n");
333
		break;
334 335 336
	case ISDN_CMD_SETEAZ: /* Signal incoming calls for given MSN */
		dev_info(cs->dev, "ignoring ISDN_CMD_SETEAZ (%s)\n",
			 cntrl->parm.num);
337
		break;
338
	case ISDN_CMD_SETL2: /* Set L2 to given protocol */
339
		if (ch >= cs->channels) {
340
			dev_err(cs->dev,
341
				"ISDN_CMD_SETL2: invalid channel (%d)\n", ch);
342 343
			return -EINVAL;
		}
344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363
		bcs = cs->bcs + ch;
		if (bcs->chstate & CHS_D_UP) {
			dev_err(cs->dev,
				"ISDN_CMD_SETL2: channel active (%d)\n", ch);
			return -EINVAL;
		}
		switch (cntrl->arg >> 8) {
		case ISDN_PROTO_L2_HDLC:
			gig_dbg(DEBUG_CMD, "ISDN_CMD_SETL2: setting L2_HDLC");
			bcs->proto2 = L2_HDLC;
			break;
		case ISDN_PROTO_L2_TRANS:
			gig_dbg(DEBUG_CMD, "ISDN_CMD_SETL2: setting L2_VOICE");
			bcs->proto2 = L2_VOICE;
			break;
		default:
			dev_err(cs->dev,
				"ISDN_CMD_SETL2: unsupported protocol (%lu)\n",
				cntrl->arg >> 8);
			return -EINVAL;
364 365
		}
		break;
366
	case ISDN_CMD_SETL3: /* Set L3 to given protocol */
367
		if (ch >= cs->channels) {
368
			dev_err(cs->dev,
369
				"ISDN_CMD_SETL3: invalid channel (%d)\n", ch);
370 371 372 373
			return -EINVAL;
		}

		if (cntrl->arg >> 8 != ISDN_PROTO_L3_TRANS) {
374
			dev_err(cs->dev,
375
				"ISDN_CMD_SETL3: unsupported protocol (%lu)\n",
376
				cntrl->arg >> 8);
377 378 379 380 381
			return -EINVAL;
		}

		break;
	case ISDN_CMD_PROCEED:
382
		gig_dbg(DEBUG_ANY, "ISDN_CMD_PROCEED"); //FIXME
383 384
		break;
	case ISDN_CMD_ALERT:
385
		gig_dbg(DEBUG_ANY, "ISDN_CMD_ALERT"); //FIXME
386
		if (cntrl->arg >= cs->channels) {
387 388 389
			dev_err(cs->dev,
				"ISDN_CMD_ALERT: invalid channel (%d)\n",
				(int) cntrl->arg);
390 391 392 393 394 395 396
			return -EINVAL;
		}
		//bcs = cs->bcs + cntrl->arg;
		//bcs->proto2 = -1;
		// FIXME
		break;
	case ISDN_CMD_REDIR:
397
		gig_dbg(DEBUG_ANY, "ISDN_CMD_REDIR"); //FIXME
398 399
		break;
	case ISDN_CMD_PROT_IO:
400
		gig_dbg(DEBUG_ANY, "ISDN_CMD_PROT_IO");
401 402
		break;
	case ISDN_CMD_FAXCMD:
403
		gig_dbg(DEBUG_ANY, "ISDN_CMD_FAXCMD");
404 405
		break;
	case ISDN_CMD_GETL2:
406
		gig_dbg(DEBUG_ANY, "ISDN_CMD_GETL2");
407 408
		break;
	case ISDN_CMD_GETL3:
409
		gig_dbg(DEBUG_ANY, "ISDN_CMD_GETL3");
410 411
		break;
	case ISDN_CMD_GETEAZ:
412
		gig_dbg(DEBUG_ANY, "ISDN_CMD_GETEAZ");
413 414
		break;
	case ISDN_CMD_SETSIL:
415
		gig_dbg(DEBUG_ANY, "ISDN_CMD_SETSIL");
416 417
		break;
	case ISDN_CMD_GETSIL:
418
		gig_dbg(DEBUG_ANY, "ISDN_CMD_GETSIL");
419 420
		break;
	default:
421 422
		dev_err(cs->dev, "unknown command %d from LL\n",
			cntrl->command);
423 424 425 426
		return -EINVAL;
	}

	return retval;
427 428 429 430 431 432

oom:
	dev_err(bcs->cs->dev, "out of memory\n");
	for (i = 0; i < AT_NUM; ++i)
		kfree(commands[i]);
	return -ENOMEM;
433 434
}

435
static void gigaset_i4l_cmd(struct cardstate *cs, int cmd)
436
{
437
	isdn_if *iif = cs->iif;
438 439 440 441 442
	isdn_ctrl command;

	command.driver = cs->myid;
	command.command = cmd;
	command.arg = 0;
443
	iif->statcallb(&command);
444 445
}

446
static void gigaset_i4l_channel_cmd(struct bc_state *bcs, int cmd)
447
{
448
	isdn_if *iif = bcs->cs->iif;
449 450 451 452 453
	isdn_ctrl command;

	command.driver = bcs->cs->myid;
	command.command = cmd;
	command.arg = bcs->channel;
454
	iif->statcallb(&command);
455 456
}

T
Tilman Schmidt 已提交
457 458 459 460 461 462 463 464 465
/**
 * gigaset_isdn_icall() - signal incoming call
 * @at_state:	connection state structure.
 *
 * Called by main module to notify the LL that an incoming call has been
 * received. @at_state contains the parameters of the call.
 *
 * Return value: call disposition (ICALL_*)
 */
466 467 468 469
int gigaset_isdn_icall(struct at_state_t *at_state)
{
	struct cardstate *cs = at_state->cs;
	struct bc_state *bcs = at_state->bcs;
470
	isdn_if *iif = cs->iif;
471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492
	isdn_ctrl response;
	int retval;

	/* fill ICALL structure */
	response.parm.setup.si1 = 0;	/* default: unknown */
	response.parm.setup.si2 = 0;
	response.parm.setup.screen = 0;	//FIXME how to set these?
	response.parm.setup.plan = 0;
	if (!at_state->str_var[STR_ZBC]) {
		/* no BC (internal call): assume speech, A-law */
		response.parm.setup.si1 = 1;
	} else if (!strcmp(at_state->str_var[STR_ZBC], "8890")) {
		/* unrestricted digital information */
		response.parm.setup.si1 = 7;
	} else if (!strcmp(at_state->str_var[STR_ZBC], "8090A3")) {
		/* speech, A-law */
		response.parm.setup.si1 = 1;
	} else if (!strcmp(at_state->str_var[STR_ZBC], "9090A3")) {
		/* 3,1 kHz audio, A-law */
		response.parm.setup.si1 = 1;
		response.parm.setup.si2 = 2;
	} else {
493
		dev_warn(cs->dev, "RING ignored - unsupported BC %s\n",
494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510
		     at_state->str_var[STR_ZBC]);
		return ICALL_IGNORE;
	}
	if (at_state->str_var[STR_NMBR]) {
		strncpy(response.parm.setup.phone, at_state->str_var[STR_NMBR],
			sizeof response.parm.setup.phone - 1);
		response.parm.setup.phone[sizeof response.parm.setup.phone - 1] = 0;
	} else
		response.parm.setup.phone[0] = 0;
	if (at_state->str_var[STR_ZCPN]) {
		strncpy(response.parm.setup.eazmsn, at_state->str_var[STR_ZCPN],
			sizeof response.parm.setup.eazmsn - 1);
		response.parm.setup.eazmsn[sizeof response.parm.setup.eazmsn - 1] = 0;
	} else
		response.parm.setup.eazmsn[0] = 0;

	if (!bcs) {
511
		dev_notice(cs->dev, "no channel for incoming call\n");
512 513 514
		response.command = ISDN_STAT_ICALLW;
		response.arg = 0; //FIXME
	} else {
515
		gig_dbg(DEBUG_CMD, "Sending ICALL");
516 517 518 519
		response.command = ISDN_STAT_ICALL;
		response.arg = bcs->channel; //FIXME
	}
	response.driver = cs->myid;
520
	retval = iif->statcallb(&response);
521
	gig_dbg(DEBUG_CMD, "Response: %d", retval);
522 523 524 525 526 527 528 529 530
	switch (retval) {
	case 0:	/* no takers */
		return ICALL_IGNORE;
	case 1:	/* alerting */
		bcs->chstate |= CHS_NOTIFY_LL;
		return ICALL_ACCEPT;
	case 2:	/* reject */
		return ICALL_REJECT;
	case 3:	/* incomplete */
531 532
		dev_warn(cs->dev,
		       "LL requested unsupported feature: Incomplete Number\n");
533 534 535 536 537 538 539
		return ICALL_IGNORE;
	case 4:	/* proceeding */
		/* Gigaset will send ALERTING anyway.
		 * There doesn't seem to be a way to avoid this.
		 */
		return ICALL_ACCEPT;
	case 5:	/* deflect */
540 541
		dev_warn(cs->dev,
			 "LL requested unsupported feature: Call Deflection\n");
542 543
		return ICALL_IGNORE;
	default:
544
		dev_err(cs->dev, "LL error %d on ICALL\n", retval);
545 546 547 548
		return ICALL_IGNORE;
	}
}

549 550 551 552 553 554 555 556
/**
 * gigaset_isdn_connD() - signal D channel connect
 * @bcs:	B channel descriptor structure.
 *
 * Called by main module to notify the LL that the D channel connection has
 * been established.
 */
void gigaset_isdn_connD(struct bc_state *bcs)
557
{
558 559 560
	gig_dbg(DEBUG_CMD, "sending DCONN");
	gigaset_i4l_channel_cmd(bcs, ISDN_STAT_DCONN);
}
561

562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646
/**
 * gigaset_isdn_hupD() - signal D channel hangup
 * @bcs:	B channel descriptor structure.
 *
 * Called by main module to notify the LL that the D channel connection has
 * been shut down.
 */
void gigaset_isdn_hupD(struct bc_state *bcs)
{
	gig_dbg(DEBUG_CMD, "sending DHUP");
	gigaset_i4l_channel_cmd(bcs, ISDN_STAT_DHUP);
}

/**
 * gigaset_isdn_connB() - signal B channel connect
 * @bcs:	B channel descriptor structure.
 *
 * Called by main module to notify the LL that the B channel connection has
 * been established.
 */
void gigaset_isdn_connB(struct bc_state *bcs)
{
	gig_dbg(DEBUG_CMD, "sending BCONN");
	gigaset_i4l_channel_cmd(bcs, ISDN_STAT_BCONN);
}

/**
 * gigaset_isdn_hupB() - signal B channel hangup
 * @bcs:	B channel descriptor structure.
 *
 * Called by main module to notify the LL that the B channel connection has
 * been shut down.
 */
void gigaset_isdn_hupB(struct bc_state *bcs)
{
	gig_dbg(DEBUG_CMD, "sending BHUP");
	gigaset_i4l_channel_cmd(bcs, ISDN_STAT_BHUP);
}

/**
 * gigaset_isdn_start() - signal device availability
 * @cs:		device descriptor structure.
 *
 * Called by main module to notify the LL that the device is available for
 * use.
 */
void gigaset_isdn_start(struct cardstate *cs)
{
	gig_dbg(DEBUG_CMD, "sending RUN");
	gigaset_i4l_cmd(cs, ISDN_STAT_RUN);
}

/**
 * gigaset_isdn_stop() - signal device unavailability
 * @cs:		device descriptor structure.
 *
 * Called by main module to notify the LL that the device is no longer
 * available for use.
 */
void gigaset_isdn_stop(struct cardstate *cs)
{
	gig_dbg(DEBUG_CMD, "sending STOP");
	gigaset_i4l_cmd(cs, ISDN_STAT_STOP);
}

/**
 * gigaset_isdn_register() - register to LL
 * @cs:		device descriptor structure.
 * @isdnid:	device name.
 *
 * Called by main module to register the device with the LL.
 *
 * Return value: 1 for success, 0 for failure
 */
int gigaset_isdn_register(struct cardstate *cs, const char *isdnid)
{
	isdn_if *iif;

	pr_info("ISDN4Linux interface\n");

	iif = kmalloc(sizeof *iif, GFP_KERNEL);
	if (!iif) {
		pr_err("out of memory\n");
		return 0;
	}
647 648

	if (snprintf(iif->id, sizeof iif->id, "%s_%u", isdnid, cs->minor_index)
T
Tilman Schmidt 已提交
649 650
	    >= sizeof iif->id) {
		pr_err("ID too long: %s\n", isdnid);
651
		kfree(iif);
T
Tilman Schmidt 已提交
652 653
		return 0;
	}
654 655

	iif->owner = THIS_MODULE;
656
	iif->channels = cs->channels;
657
	iif->maxbufsize = MAX_BUF_SIZE;
658
	iif->features = ISDN_FEATURE_L2_TRANS |
659 660 661 662 663 664
		ISDN_FEATURE_L2_HDLC |
#ifdef GIG_X75
		ISDN_FEATURE_L2_X75I |
#endif
		ISDN_FEATURE_L3_TRANS |
		ISDN_FEATURE_P_EURO;
665
	iif->hl_hdrlen = HW_HDR_LEN;		/* Area for storing ack */
666 667
	iif->command = command_from_LL;
	iif->writebuf_skb = writebuf_from_LL;
668 669 670 671
	iif->writecmd = NULL;			/* Don't support isdnctrl */
	iif->readstat = NULL;			/* Don't support isdnctrl */
	iif->rcvcallb_skb = NULL;		/* Will be set by LL */
	iif->statcallb = NULL;			/* Will be set by LL */
672

T
Tilman Schmidt 已提交
673 674
	if (!register_isdn(iif)) {
		pr_err("register_isdn failed\n");
675
		kfree(iif);
676
		return 0;
T
Tilman Schmidt 已提交
677
	}
678

679
	cs->iif = iif;
680
	cs->myid = iif->channels;		/* Set my device id */
681
	cs->hw_hdr_len = HW_HDR_LEN;
682 683
	return 1;
}
684 685 686 687 688 689 690 691 692 693 694 695 696 697

/**
 * gigaset_isdn_unregister() - unregister from LL
 * @cs:		device descriptor structure.
 *
 * Called by main module to unregister the device from the LL.
 */
void gigaset_isdn_unregister(struct cardstate *cs)
{
	gig_dbg(DEBUG_CMD, "sending UNLOAD");
	gigaset_i4l_cmd(cs, ISDN_STAT_UNLOAD);
	kfree(cs->iif);
	cs->iif = NULL;
}