i4l.c 18.1 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
#include <linux/isdnif.h>

19 20
#define SBUFSIZE	4096	/* sk_buff payload size */
#define TRANSBUFSIZE	768	/* bytes per skb for transparent receive */
21
#define HW_HDR_LEN	2	/* Header size used to store ack info */
22
#define MAX_BUF_SIZE	(SBUFSIZE - HW_HDR_LEN)	/* max data packet from LL */
23

24
/* == Handling of I4L IO =====================================================*/
25 26 27 28 29 30 31 32 33

/* 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
34 35
 *	ack		if != 0 LL wants to be notified on completion via
 *			statcallb(ISDN_STAT_BSENT)
36 37 38 39 40 41
 *	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)
 */
42 43
static int writebuf_from_LL(int driverID, int channel, int ack,
			    struct sk_buff *skb)
44
{
T
Tilman Schmidt 已提交
45
	struct cardstate *cs = gigaset_get_cs_by_id(driverID);
46
	struct bc_state *bcs;
47
	unsigned char *ack_header;
48 49
	unsigned len;

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

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

68 69 70 71
	gig_dbg(DEBUG_LLDATA,
		"Receiving data from LL (id: %d, ch: %d, ack: %d, sz: %d)",
		driverID, channel, ack, len);

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

84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100
	/* set up acknowledgement header */
	if (skb_headroom(skb) < HW_HDR_LEN) {
		/* should never happen */
		dev_err(cs->dev, "%s: insufficient skb headroom\n", __func__);
		return -ENOMEM;
	}
	skb_set_mac_header(skb, -HW_HDR_LEN);
	skb->mac_len = HW_HDR_LEN;
	ack_header = skb_mac_header(skb);
	if (ack) {
		ack_header[0] = len & 0xff;
		ack_header[1] = len >> 8;
	} else {
		ack_header[0] = ack_header[1] = 0;
	}
	gig_dbg(DEBUG_MCMD, "skb: len=%u, ack=%d: %02x %02x",
		len, ack, ack_header[0], ack_header[1]);
101 102

	/* pass to device-specific module */
103
	return cs->ops->send_skb(bcs, skb);
104 105
}

T
Tilman Schmidt 已提交
106 107 108 109 110 111 112 113
/**
 * 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.
 */
114 115
void gigaset_skb_sent(struct bc_state *bcs, struct sk_buff *skb)
{
116
	isdn_if *iif = bcs->cs->iif;
117
	unsigned char *ack_header = skb_mac_header(skb);
118 119 120 121 122 123
	unsigned len;
	isdn_ctrl response;

	++bcs->trans_up;

	if (skb->len)
124 125
		dev_warn(bcs->cs->dev, "%s: skb->len==%d\n",
			 __func__, skb->len);
126

127
	len = ack_header[0] + ((unsigned) ack_header[1] << 8);
128
	if (len) {
129 130
		gig_dbg(DEBUG_MCMD, "ACKing to LL (id: %d, ch: %d, sz: %u)",
			bcs->cs->myid, bcs->channel, len);
131 132 133 134 135

		response.driver = bcs->cs->myid;
		response.command = ISDN_STAT_BSENT;
		response.arg = bcs->channel;
		response.parm.length = len;
136
		iif->statcallb(&response);
137 138 139 140
	}
}
EXPORT_SYMBOL_GPL(gigaset_skb_sent);

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 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189
/**
 * 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);

190 191 192 193 194 195
/* 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)
{
196
	struct cardstate *cs;
197 198
	struct bc_state *bcs;
	int retval = 0;
199 200 201 202
	char **commands;
	int ch;
	int i;
	size_t l;
203 204 205

	gigaset_debugdrivers();

206 207 208 209 210
	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) {
211
		pr_err("%s: invalid driver ID (%d)\n", __func__, cntrl->driver);
212 213
		return -ENODEV;
	}
214
	ch = cntrl->arg & 0xff;
215 216 217

	switch (cntrl->command) {
	case ISDN_CMD_IOCTL:
218
		dev_warn(cs->dev, "ISDN_CMD_IOCTL not supported\n");
219 220 221
		return -EINVAL;

	case ISDN_CMD_DIAL:
T
Tilman Schmidt 已提交
222
		gig_dbg(DEBUG_CMD,
223
			"ISDN_CMD_DIAL (phone: %s, msn: %s, si1: %d, si2: %d)",
224 225
			cntrl->parm.setup.phone, cntrl->parm.setup.eazmsn,
			cntrl->parm.setup.si1, cntrl->parm.setup.si2);
226

227
		if (ch >= cs->channels) {
228
			dev_err(cs->dev,
229
				"ISDN_CMD_DIAL: invalid channel (%d)\n", ch);
230 231
			return -EINVAL;
		}
232
		bcs = cs->bcs + ch;
233
		if (!gigaset_get_channel(bcs)) {
234
			dev_err(cs->dev, "ISDN_CMD_DIAL: channel not free\n");
235 236
			return -EBUSY;
		}
237 238 239 240 241 242 243 244 245
		switch (bcs->proto2) {
		case L2_HDLC:
			bcs->rx_bufsize = SBUFSIZE;
			break;
		default:			/* assume transparent */
			bcs->rx_bufsize = TRANSBUFSIZE;
		}
		dev_kfree_skb(bcs->rx_skb);
		gigaset_new_rx_skb(bcs);
246

247 248
		commands = kzalloc(AT_NUM*(sizeof *commands), GFP_ATOMIC);
		if (!commands) {
249
			gigaset_free_channel(bcs);
250
			dev_err(cs->dev, "ISDN_CMD_DIAL: out of memory\n");
251 252 253
			return -ENOMEM;
		}

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 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311
		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 已提交
312
				       bcs->at_state.seq_index, NULL)) {
313 314 315
			for (i = 0; i < AT_NUM; ++i)
				kfree(commands[i]);
			kfree(commands);
316 317 318 319 320
			gigaset_free_channel(bcs);
			return -ENOMEM;
		}
		gigaset_schedule_event(cs);
		break;
321
	case ISDN_CMD_ACCEPTD:
T
Tilman Schmidt 已提交
322
		gig_dbg(DEBUG_CMD, "ISDN_CMD_ACCEPTD");
323
		if (ch >= cs->channels) {
324
			dev_err(cs->dev,
325
				"ISDN_CMD_ACCEPTD: invalid channel (%d)\n", ch);
326 327
			return -EINVAL;
		}
328
		bcs = cs->bcs + ch;
329 330 331 332 333 334 335 336 337
		switch (bcs->proto2) {
		case L2_HDLC:
			bcs->rx_bufsize = SBUFSIZE;
			break;
		default:			/* assume transparent */
			bcs->rx_bufsize = TRANSBUFSIZE;
		}
		dev_kfree_skb(bcs->rx_skb);
		gigaset_new_rx_skb(bcs);
338 339
		if (!gigaset_add_event(cs, &bcs->at_state,
				       EV_ACCEPT, NULL, 0, NULL))
340 341 342 343 344
			return -ENOMEM;
		gigaset_schedule_event(cs);

		break;
	case ISDN_CMD_HANGUP:
T
Tilman Schmidt 已提交
345
		gig_dbg(DEBUG_CMD, "ISDN_CMD_HANGUP");
346
		if (ch >= cs->channels) {
347
			dev_err(cs->dev,
348
				"ISDN_CMD_HANGUP: invalid channel (%d)\n", ch);
349 350
			return -EINVAL;
		}
351 352 353
		bcs = cs->bcs + ch;
		if (!gigaset_add_event(cs, &bcs->at_state,
				       EV_HUP, NULL, 0, NULL))
354 355 356 357
			return -ENOMEM;
		gigaset_schedule_event(cs);

		break;
358 359
	case ISDN_CMD_CLREAZ: /* Do not signal incoming signals */
		dev_info(cs->dev, "ignoring ISDN_CMD_CLREAZ\n");
360
		break;
361 362 363
	case ISDN_CMD_SETEAZ: /* Signal incoming calls for given MSN */
		dev_info(cs->dev, "ignoring ISDN_CMD_SETEAZ (%s)\n",
			 cntrl->parm.num);
364
		break;
365
	case ISDN_CMD_SETL2: /* Set L2 to given protocol */
366
		if (ch >= cs->channels) {
367
			dev_err(cs->dev,
368
				"ISDN_CMD_SETL2: invalid channel (%d)\n", ch);
369 370
			return -EINVAL;
		}
371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390
		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;
391 392
		}
		break;
393
	case ISDN_CMD_SETL3: /* Set L3 to given protocol */
T
Tilman Schmidt 已提交
394
		gig_dbg(DEBUG_CMD, "ISDN_CMD_SETL3");
395
		if (ch >= cs->channels) {
396
			dev_err(cs->dev,
397
				"ISDN_CMD_SETL3: invalid channel (%d)\n", ch);
398 399 400 401
			return -EINVAL;
		}

		if (cntrl->arg >> 8 != ISDN_PROTO_L3_TRANS) {
402
			dev_err(cs->dev,
403
				"ISDN_CMD_SETL3: unsupported protocol (%lu)\n",
404
				cntrl->arg >> 8);
405 406 407 408
			return -EINVAL;
		}

		break;
T
Tilman Schmidt 已提交
409

410
	default:
T
Tilman Schmidt 已提交
411
		gig_dbg(DEBUG_CMD, "unknown command %d from LL",
412
			cntrl->command);
413 414 415 416
		return -EINVAL;
	}

	return retval;
417 418 419 420 421

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

427
static void gigaset_i4l_cmd(struct cardstate *cs, int cmd)
428
{
429
	isdn_if *iif = cs->iif;
430 431 432 433 434
	isdn_ctrl command;

	command.driver = cs->myid;
	command.command = cmd;
	command.arg = 0;
435
	iif->statcallb(&command);
436 437
}

438
static void gigaset_i4l_channel_cmd(struct bc_state *bcs, int cmd)
439
{
440
	isdn_if *iif = bcs->cs->iif;
441 442 443 444 445
	isdn_ctrl command;

	command.driver = bcs->cs->myid;
	command.command = cmd;
	command.arg = bcs->channel;
446
	iif->statcallb(&command);
447 448
}

T
Tilman Schmidt 已提交
449 450 451 452 453 454 455 456 457
/**
 * 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_*)
 */
458 459 460 461
int gigaset_isdn_icall(struct at_state_t *at_state)
{
	struct cardstate *cs = at_state->cs;
	struct bc_state *bcs = at_state->bcs;
462
	isdn_if *iif = cs->iif;
463 464 465 466 467 468
	isdn_ctrl response;
	int retval;

	/* fill ICALL structure */
	response.parm.setup.si1 = 0;	/* default: unknown */
	response.parm.setup.si2 = 0;
T
Tilman Schmidt 已提交
469
	response.parm.setup.screen = 0;
470 471 472 473 474 475 476 477 478 479 480 481 482 483 484
	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 {
485
		dev_warn(cs->dev, "RING ignored - unsupported BC %s\n",
486 487 488 489
		     at_state->str_var[STR_ZBC]);
		return ICALL_IGNORE;
	}
	if (at_state->str_var[STR_NMBR]) {
T
Tilman Schmidt 已提交
490 491
		strlcpy(response.parm.setup.phone, at_state->str_var[STR_NMBR],
			sizeof response.parm.setup.phone);
492 493 494
	} else
		response.parm.setup.phone[0] = 0;
	if (at_state->str_var[STR_ZCPN]) {
T
Tilman Schmidt 已提交
495 496
		strlcpy(response.parm.setup.eazmsn, at_state->str_var[STR_ZCPN],
			sizeof response.parm.setup.eazmsn);
497 498 499 500
	} else
		response.parm.setup.eazmsn[0] = 0;

	if (!bcs) {
501
		dev_notice(cs->dev, "no channel for incoming call\n");
502
		response.command = ISDN_STAT_ICALLW;
T
Tilman Schmidt 已提交
503
		response.arg = 0;
504
	} else {
505
		gig_dbg(DEBUG_CMD, "Sending ICALL");
506
		response.command = ISDN_STAT_ICALL;
T
Tilman Schmidt 已提交
507
		response.arg = bcs->channel;
508 509
	}
	response.driver = cs->myid;
510
	retval = iif->statcallb(&response);
511
	gig_dbg(DEBUG_CMD, "Response: %d", retval);
512 513 514 515 516 517 518 519 520
	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 */
521 522
		dev_warn(cs->dev,
		       "LL requested unsupported feature: Incomplete Number\n");
523 524 525 526 527 528 529
		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 */
530 531
		dev_warn(cs->dev,
			 "LL requested unsupported feature: Call Deflection\n");
532 533
		return ICALL_IGNORE;
	default:
534
		dev_err(cs->dev, "LL error %d on ICALL\n", retval);
535 536 537 538
		return ICALL_IGNORE;
	}
}

539 540 541 542 543 544 545 546
/**
 * 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)
547
{
548 549 550
	gig_dbg(DEBUG_CMD, "sending DCONN");
	gigaset_i4l_channel_cmd(bcs, ISDN_STAT_DCONN);
}
551

552 553 554 555 556 557 558 559 560 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
/**
 * 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);
}

/**
618
 * gigaset_isdn_regdev() - register to LL
619 620 621 622 623
 * @cs:		device descriptor structure.
 * @isdnid:	device name.
 *
 * Return value: 1 for success, 0 for failure
 */
624
int gigaset_isdn_regdev(struct cardstate *cs, const char *isdnid)
625 626 627 628 629 630 631 632 633 634
{
	isdn_if *iif;

	pr_info("ISDN4Linux interface\n");

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

	if (snprintf(iif->id, sizeof iif->id, "%s_%u", isdnid, cs->minor_index)
T
Tilman Schmidt 已提交
637 638
	    >= sizeof iif->id) {
		pr_err("ID too long: %s\n", isdnid);
639
		kfree(iif);
T
Tilman Schmidt 已提交
640 641
		return 0;
	}
642 643

	iif->owner = THIS_MODULE;
644
	iif->channels = cs->channels;
645
	iif->maxbufsize = MAX_BUF_SIZE;
646
	iif->features = ISDN_FEATURE_L2_TRANS |
647 648 649 650
		ISDN_FEATURE_L2_HDLC |
		ISDN_FEATURE_L2_X75I |
		ISDN_FEATURE_L3_TRANS |
		ISDN_FEATURE_P_EURO;
651
	iif->hl_hdrlen = HW_HDR_LEN;		/* Area for storing ack */
652 653
	iif->command = command_from_LL;
	iif->writebuf_skb = writebuf_from_LL;
654 655 656 657
	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 */
658

T
Tilman Schmidt 已提交
659 660
	if (!register_isdn(iif)) {
		pr_err("register_isdn failed\n");
661
		kfree(iif);
662
		return 0;
T
Tilman Schmidt 已提交
663
	}
664

665
	cs->iif = iif;
666
	cs->myid = iif->channels;		/* Set my device id */
667
	cs->hw_hdr_len = HW_HDR_LEN;
668 669
	return 1;
}
670 671

/**
672
 * gigaset_isdn_unregdev() - unregister device from LL
673 674
 * @cs:		device descriptor structure.
 */
675
void gigaset_isdn_unregdev(struct cardstate *cs)
676 677 678 679 680 681
{
	gig_dbg(DEBUG_CMD, "sending UNLOAD");
	gigaset_i4l_cmd(cs, ISDN_STAT_UNLOAD);
	kfree(cs->iif);
	cs->iif = NULL;
}
682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697

/**
 * gigaset_isdn_regdrv() - register driver to LL
 */
void gigaset_isdn_regdrv(void)
{
	/* nothing to do */
}

/**
 * gigaset_isdn_unregdrv() - unregister driver from LL
 */
void gigaset_isdn_unregdrv(void)
{
	/* nothing to do */
}