common.c 27.7 KB
Newer Older
1 2 3
/*
 * Stuff used by all variants of the driver
 *
4
 * Copyright (c) 2001 by Stefan Eilers,
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
 *                       Hansjoerg Lipp <hjlipp@web.de>,
 *                       Tilman Schmidt <tilman@imap.cc>.
 *
 * =====================================================================
 *	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"
#include <linux/ctype.h>
#include <linux/module.h>
#include <linux/moduleparam.h>

/* Version Information */
22
#define DRIVER_AUTHOR "Hansjoerg Lipp <hjlipp@web.de>, Tilman Schmidt <tilman@imap.cc>, Stefan Eilers"
23 24
#define DRIVER_DESC "Driver for Gigaset 307x"

25 26 27 28 29 30
#ifdef CONFIG_GIGASET_DEBUG
#define DRIVER_DESC_DEBUG " (debug build)"
#else
#define DRIVER_DESC_DEBUG ""
#endif

31 32 33 34 35 36
/* Module parameters */
int gigaset_debuglevel = DEBUG_DEFAULT;
EXPORT_SYMBOL_GPL(gigaset_debuglevel);
module_param_named(debug, gigaset_debuglevel, int, S_IRUGO|S_IWUSR);
MODULE_PARM_DESC(debug, "debug level");

37
/* driver state flags */
38 39
#define VALID_MINOR	0x01
#define VALID_ID	0x02
40

41 42 43 44 45 46 47 48 49 50 51
/**
 * gigaset_dbg_buffer() - dump data in ASCII and hex for debugging
 * @level:	debugging level.
 * @msg:	message prefix.
 * @len:	number of bytes to dump.
 * @buf:	data to dump.
 *
 * If the current debugging level includes one of the bits set in @level,
 * @len bytes starting at @buf are logged to dmesg at KERN_DEBUG prio,
 * prefixed by the text @msg.
 */
52
void gigaset_dbg_buffer(enum debuglevel level, const unsigned char *msg,
53
			size_t len, const unsigned char *buf)
54 55
{
	unsigned char outbuf[80];
56
	unsigned char c;
57 58
	size_t space = sizeof outbuf - 1;
	unsigned char *out = outbuf;
59
	size_t numin = len;
60

61
	while (numin--) {
62 63
		c = *buf++;
		if (c == '~' || c == '^' || c == '\\') {
64
			if (!space--)
65 66 67 68
				break;
			*out++ = '\\';
		}
		if (c & 0x80) {
69
			if (!space--)
70 71 72 73 74
				break;
			*out++ = '~';
			c ^= 0x80;
		}
		if (c < 0x20 || c == 0x7f) {
75
			if (!space--)
76
				break;
77
			*out++ = '^';
78
			c ^= 0x40;
79
		}
80
		if (!space--)
81 82
			break;
		*out++ = c;
83 84 85
	}
	*out = 0;

86
	gig_dbg(level, "%s (%u bytes): %s", msg, (unsigned) len, outbuf);
87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 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
}
EXPORT_SYMBOL_GPL(gigaset_dbg_buffer);

static int setflags(struct cardstate *cs, unsigned flags, unsigned delay)
{
	int r;

	r = cs->ops->set_modem_ctrl(cs, cs->control_state, flags);
	cs->control_state = flags;
	if (r < 0)
		return r;

	if (delay) {
		set_current_state(TASK_INTERRUPTIBLE);
		schedule_timeout(delay * HZ / 1000);
	}

	return 0;
}

int gigaset_enterconfigmode(struct cardstate *cs)
{
	int i, r;

	cs->control_state = TIOCM_RTS; //FIXME

	r = setflags(cs, TIOCM_DTR, 200);
	if (r < 0)
		goto error;
	r = setflags(cs, 0, 200);
	if (r < 0)
		goto error;
	for (i = 0; i < 5; ++i) {
		r = setflags(cs, TIOCM_RTS, 100);
		if (r < 0)
			goto error;
		r = setflags(cs, 0, 100);
		if (r < 0)
			goto error;
	}
	r = setflags(cs, TIOCM_RTS|TIOCM_DTR, 800);
	if (r < 0)
		goto error;

	return 0;

error:
134
	dev_err(cs->dev, "error %d on setuartbits\n", -r);
135 136 137 138 139 140 141 142 143 144 145 146
	cs->control_state = TIOCM_RTS|TIOCM_DTR; // FIXME is this a good value?
	cs->ops->set_modem_ctrl(cs, 0, TIOCM_RTS|TIOCM_DTR);

	return -1; //r
}

static int test_timeout(struct at_state_t *at_state)
{
	if (!at_state->timer_expires)
		return 0;

	if (--at_state->timer_expires) {
147 148
		gig_dbg(DEBUG_MCMD, "decreased timer of %p to %lu",
			at_state, at_state->timer_expires);
149 150 151 152
		return 0;
	}

	if (!gigaset_add_event(at_state->cs, at_state, EV_TIMEOUT, NULL,
153
			       at_state->timer_index, NULL)) {
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
		//FIXME what should we do?
	}

	return 1;
}

static void timer_tick(unsigned long data)
{
	struct cardstate *cs = (struct cardstate *) data;
	unsigned long flags;
	unsigned channel;
	struct at_state_t *at_state;
	int timeout = 0;

	spin_lock_irqsave(&cs->lock, flags);

	for (channel = 0; channel < cs->channels; ++channel)
		if (test_timeout(&cs->bcs[channel].at_state))
			timeout = 1;

	if (test_timeout(&cs->at_state))
		timeout = 1;

	list_for_each_entry(at_state, &cs->temp_at_states, list)
		if (test_timeout(at_state))
			timeout = 1;

181
	if (cs->running) {
182
		mod_timer(&cs->timer, jiffies + msecs_to_jiffies(GIG_TICK));
183
		if (timeout) {
184
			gig_dbg(DEBUG_CMD, "scheduling timeout");
185 186 187 188 189 190 191 192 193 194 195 196
			tasklet_schedule(&cs->event_tasklet);
		}
	}

	spin_unlock_irqrestore(&cs->lock, flags);
}

int gigaset_get_channel(struct bc_state *bcs)
{
	unsigned long flags;

	spin_lock_irqsave(&bcs->cs->lock, flags);
Tilman Schmidt's avatar
Tilman Schmidt committed
197
	if (bcs->use_count || !try_module_get(bcs->cs->driver->owner)) {
198 199
		gig_dbg(DEBUG_ANY, "could not allocate channel %d",
			bcs->channel);
200 201 202 203 204
		spin_unlock_irqrestore(&bcs->cs->lock, flags);
		return 0;
	}
	++bcs->use_count;
	bcs->busy = 1;
205
	gig_dbg(DEBUG_ANY, "allocated channel %d", bcs->channel);
206 207 208 209 210 211 212 213 214 215
	spin_unlock_irqrestore(&bcs->cs->lock, flags);
	return 1;
}

void gigaset_free_channel(struct bc_state *bcs)
{
	unsigned long flags;

	spin_lock_irqsave(&bcs->cs->lock, flags);
	if (!bcs->busy) {
216
		gig_dbg(DEBUG_ANY, "could not free channel %d", bcs->channel);
217 218 219 220 221
		spin_unlock_irqrestore(&bcs->cs->lock, flags);
		return;
	}
	--bcs->use_count;
	bcs->busy = 0;
Tilman Schmidt's avatar
Tilman Schmidt committed
222
	module_put(bcs->cs->driver->owner);
223
	gig_dbg(DEBUG_ANY, "freed channel %d", bcs->channel);
224 225 226 227 228 229 230 231 232 233 234 235
	spin_unlock_irqrestore(&bcs->cs->lock, flags);
}

int gigaset_get_channels(struct cardstate *cs)
{
	unsigned long flags;
	int i;

	spin_lock_irqsave(&cs->lock, flags);
	for (i = 0; i < cs->channels; ++i)
		if (cs->bcs[i].use_count) {
			spin_unlock_irqrestore(&cs->lock, flags);
236
			gig_dbg(DEBUG_ANY, "could not allocate all channels");
237 238 239 240 241 242
			return 0;
		}
	for (i = 0; i < cs->channels; ++i)
		++cs->bcs[i].use_count;
	spin_unlock_irqrestore(&cs->lock, flags);

243
	gig_dbg(DEBUG_ANY, "allocated all channels");
244 245 246 247 248 249 250 251 252

	return 1;
}

void gigaset_free_channels(struct cardstate *cs)
{
	unsigned long flags;
	int i;

253
	gig_dbg(DEBUG_ANY, "unblocking all channels");
254 255 256 257 258 259 260 261 262 263 264
	spin_lock_irqsave(&cs->lock, flags);
	for (i = 0; i < cs->channels; ++i)
		--cs->bcs[i].use_count;
	spin_unlock_irqrestore(&cs->lock, flags);
}

void gigaset_block_channels(struct cardstate *cs)
{
	unsigned long flags;
	int i;

265
	gig_dbg(DEBUG_ANY, "blocking all channels");
266 267 268 269 270 271 272 273 274 275
	spin_lock_irqsave(&cs->lock, flags);
	for (i = 0; i < cs->channels; ++i)
		++cs->bcs[i].use_count;
	spin_unlock_irqrestore(&cs->lock, flags);
}

static void clear_events(struct cardstate *cs)
{
	struct event_t *ev;
	unsigned head, tail;
276
	unsigned long flags;
277

278
	spin_lock_irqsave(&cs->ev_lock, flags);
279

280 281
	head = cs->ev_head;
	tail = cs->ev_tail;
282 283 284 285 286 287 288

	while (tail != head) {
		ev = cs->events + head;
		kfree(ev->ptr);
		head = (head + 1) % MAX_EVENTS;
	}

289 290 291
	cs->ev_head = tail;

	spin_unlock_irqrestore(&cs->ev_lock, flags);
292 293
}

294 295 296 297 298 299 300 301 302 303 304 305 306 307
/**
 * gigaset_add_event() - add event to device event queue
 * @cs:		device descriptor structure.
 * @at_state:	connection state structure.
 * @type:	event type.
 * @ptr:	pointer parameter for event.
 * @parameter:	integer parameter for event.
 * @arg:	pointer parameter for event.
 *
 * Allocate an event queue entry from the device's event queue, and set it up
 * with the parameters given.
 *
 * Return value: added event
 */
308
struct event_t *gigaset_add_event(struct cardstate *cs,
309 310
				  struct at_state_t *at_state, int type,
				  void *ptr, int parameter, void *arg)
311 312 313 314 315 316 317
{
	unsigned long flags;
	unsigned next, tail;
	struct event_t *event = NULL;

	spin_lock_irqsave(&cs->ev_lock, flags);

318
	tail = cs->ev_tail;
319
	next = (tail + 1) % MAX_EVENTS;
320
	if (unlikely(next == cs->ev_head))
321
		dev_err(cs->dev, "event queue full\n");
322 323 324 325 326 327 328 329
	else {
		event = cs->events + tail;
		event->type = type;
		event->at_state = at_state;
		event->cid = -1;
		event->ptr = ptr;
		event->arg = arg;
		event->parameter = parameter;
330
		cs->ev_tail = next;
331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368
	}

	spin_unlock_irqrestore(&cs->ev_lock, flags);

	return event;
}
EXPORT_SYMBOL_GPL(gigaset_add_event);

static void free_strings(struct at_state_t *at_state)
{
	int i;

	for (i = 0; i < STR_NUM; ++i) {
		kfree(at_state->str_var[i]);
		at_state->str_var[i] = NULL;
	}
}

static void clear_at_state(struct at_state_t *at_state)
{
	free_strings(at_state);
}

static void dealloc_at_states(struct cardstate *cs)
{
	struct at_state_t *cur, *next;

	list_for_each_entry_safe(cur, next, &cs->temp_at_states, list) {
		list_del(&cur->list);
		free_strings(cur);
		kfree(cur);
	}
}

static void gigaset_freebcs(struct bc_state *bcs)
{
	int i;

369
	gig_dbg(DEBUG_INIT, "freeing bcs[%d]->hw", bcs->channel);
370
	if (!bcs->cs->ops->freebcshw(bcs)) {
371
		gig_dbg(DEBUG_INIT, "failed");
372 373
	}

374
	gig_dbg(DEBUG_INIT, "clearing bcs[%d]->at_state", bcs->channel);
375
	clear_at_state(&bcs->at_state);
376
	gig_dbg(DEBUG_INIT, "freeing bcs[%d]->skb", bcs->channel);
377 378 379 380 381 382 383 384 385

	if (bcs->skb)
		dev_kfree_skb(bcs->skb);
	for (i = 0; i < AT_NUM; ++i) {
		kfree(bcs->commands[i]);
		bcs->commands[i] = NULL;
	}
}

386 387 388 389
static struct cardstate *alloc_cs(struct gigaset_driver *drv)
{
	unsigned long flags;
	unsigned i;
Tilman Schmidt's avatar
Tilman Schmidt committed
390
	struct cardstate *cs;
391
	struct cardstate *ret = NULL;
392 393

	spin_lock_irqsave(&drv->lock, flags);
Tilman Schmidt's avatar
Tilman Schmidt committed
394 395
	if (drv->blocked)
		goto exit;
396
	for (i = 0; i < drv->minors; ++i) {
Tilman Schmidt's avatar
Tilman Schmidt committed
397 398 399 400
		cs = drv->cs + i;
		if (!(cs->flags & VALID_MINOR)) {
			cs->flags = VALID_MINOR;
			ret = cs;
401
			break;
402
		}
403
	}
Tilman Schmidt's avatar
Tilman Schmidt committed
404
exit:
405 406 407 408 409 410
	spin_unlock_irqrestore(&drv->lock, flags);
	return ret;
}

static void free_cs(struct cardstate *cs)
{
Tilman Schmidt's avatar
Tilman Schmidt committed
411
	cs->flags = 0;
412 413 414 415 416 417 418
}

static void make_valid(struct cardstate *cs, unsigned mask)
{
	unsigned long flags;
	struct gigaset_driver *drv = cs->driver;
	spin_lock_irqsave(&drv->lock, flags);
Tilman Schmidt's avatar
Tilman Schmidt committed
419
	cs->flags |= mask;
420 421 422 423 424 425 426 427
	spin_unlock_irqrestore(&drv->lock, flags);
}

static void make_invalid(struct cardstate *cs, unsigned mask)
{
	unsigned long flags;
	struct gigaset_driver *drv = cs->driver;
	spin_lock_irqsave(&drv->lock, flags);
Tilman Schmidt's avatar
Tilman Schmidt committed
428
	cs->flags &= ~mask;
429 430 431
	spin_unlock_irqrestore(&drv->lock, flags);
}

432 433 434 435 436 437 438 439 440
/**
 * gigaset_freecs() - free all associated ressources of a device
 * @cs:		device descriptor structure.
 *
 * Stops all tasklets and timers, unregisters the device from all
 * subsystems it was registered to, deallocates the device structure
 * @cs and all structures referenced from it.
 * Operations on the device should be stopped before calling this.
 */
441 442 443 444 445 446 447 448
void gigaset_freecs(struct cardstate *cs)
{
	int i;
	unsigned long flags;

	if (!cs)
		return;

449
	mutex_lock(&cs->mutex);
450 451 452 453 454 455 456

	if (!cs->bcs)
		goto f_cs;
	if (!cs->inbuf)
		goto f_bcs;

	spin_lock_irqsave(&cs->lock, flags);
457
	cs->running = 0;
458 459
	spin_unlock_irqrestore(&cs->lock, flags); /* event handler and timer are
						     not rescheduled below */
460 461 462 463 464 465

	tasklet_kill(&cs->event_tasklet);
	del_timer_sync(&cs->timer);

	switch (cs->cs_init) {
	default:
466 467 468 469 470 471
		/* clear B channel structures */
		for (i = 0; i < cs->channels; ++i) {
			gig_dbg(DEBUG_INIT, "clearing bcs[%d]", i);
			gigaset_freebcs(cs->bcs + i);
		}

472 473 474
		/* clear device sysfs */
		gigaset_free_dev_sysfs(cs);

475 476
		gigaset_if_free(cs);

477
		gig_dbg(DEBUG_INIT, "clearing hw");
478 479 480 481 482 483 484 485
		cs->ops->freecshw(cs);

		//FIXME cmdbuf

		/* fall through */
	case 2: /* error in initcshw */
		/* Deregister from LL */
		make_invalid(cs, VALID_ID);
486
		gigaset_isdn_unregister(cs);
487 488

		/* fall through */
489
	case 1: /* error when registering to LL */
490
		gig_dbg(DEBUG_INIT, "clearing at_state");
491 492 493 494
		clear_at_state(&cs->at_state);
		dealloc_at_states(cs);

		/* fall through */
495
	case 0:	/* error in basic setup */
496
		clear_events(cs);
497
		gig_dbg(DEBUG_INIT, "freeing inbuf");
498 499
		kfree(cs->inbuf);
	}
500
f_bcs:	gig_dbg(DEBUG_INIT, "freeing bcs[]");
501
	kfree(cs->bcs);
502
f_cs:	gig_dbg(DEBUG_INIT, "freeing cs");
503
	mutex_unlock(&cs->mutex);
504 505 506 507 508
	free_cs(cs);
}
EXPORT_SYMBOL_GPL(gigaset_freecs);

void gigaset_at_init(struct at_state_t *at_state, struct bc_state *bcs,
509
		     struct cardstate *cs, int cid)
510 511 512 513 514 515 516 517 518
{
	int i;

	INIT_LIST_HEAD(&at_state->list);
	at_state->waiting = 0;
	at_state->getstring = 0;
	at_state->pending_commands = 0;
	at_state->timer_expires = 0;
	at_state->timer_active = 0;
519 520
	at_state->timer_index = 0;
	at_state->seq_index = 0;
521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537
	at_state->ConState = 0;
	for (i = 0; i < STR_NUM; ++i)
		at_state->str_var[i] = NULL;
	at_state->int_var[VAR_ZDLE] = 0;
	at_state->int_var[VAR_ZCTP] = -1;
	at_state->int_var[VAR_ZSAU] = ZSAU_NULL;
	at_state->cs = cs;
	at_state->bcs = bcs;
	at_state->cid = cid;
	if (!cid)
		at_state->replystruct = cs->tabnocid;
	else
		at_state->replystruct = cs->tabcid;
}


static void gigaset_inbuf_init(struct inbuf_t *inbuf, struct bc_state *bcs,
538
			       struct cardstate *cs, int inputstate)
539 540
/* inbuf->read must be allocated before! */
{
Tilman Schmidt's avatar
Tilman Schmidt committed
541 542
	inbuf->head = 0;
	inbuf->tail = 0;
543 544
	inbuf->cs = cs;
	inbuf->bcs = bcs; /*base driver: NULL*/
Tilman Schmidt's avatar
Tilman Schmidt committed
545
	inbuf->rcvbuf = NULL;
546 547 548
	inbuf->inputstate = inputstate;
}

549 550 551 552 553 554
/**
 * gigaset_fill_inbuf() - append received data to input buffer
 * @inbuf:	buffer structure.
 * @src:	received data.
 * @numbytes:	number of bytes received.
 */
555 556 557 558 559 560 561 562 563 564 565
int gigaset_fill_inbuf(struct inbuf_t *inbuf, const unsigned char *src,
		       unsigned numbytes)
{
	unsigned n, head, tail, bytesleft;

	gig_dbg(DEBUG_INTR, "received %u bytes", numbytes);

	if (!numbytes)
		return 0;

	bytesleft = numbytes;
Tilman Schmidt's avatar
Tilman Schmidt committed
566 567
	tail = inbuf->tail;
	head = inbuf->head;
568 569 570 571 572 573 574 575 576 577 578
	gig_dbg(DEBUG_INTR, "buffer state: %u -> %u", head, tail);

	while (bytesleft) {
		if (head > tail)
			n = head - 1 - tail;
		else if (head == 0)
			n = (RBUFSIZE-1) - tail;
		else
			n = RBUFSIZE - tail;
		if (!n) {
			dev_err(inbuf->cs->dev,
579 580
				"buffer overflow (%u bytes lost)\n",
				bytesleft);
581 582 583 584 585 586 587 588 589 590
			break;
		}
		if (n > bytesleft)
			n = bytesleft;
		memcpy(inbuf->data + tail, src, n);
		bytesleft -= n;
		tail = (tail + n) % RBUFSIZE;
		src += n;
	}
	gig_dbg(DEBUG_INTR, "setting tail to %u", tail);
Tilman Schmidt's avatar
Tilman Schmidt committed
591
	inbuf->tail = tail;
592 593 594 595
	return numbytes != bytesleft;
}
EXPORT_SYMBOL_GPL(gigaset_fill_inbuf);

596 597
/* Initialize the b-channel structure */
static struct bc_state *gigaset_initbcs(struct bc_state *bcs,
598
					struct cardstate *cs, int channel)
599 600 601 602 603 604 605 606 607 608 609
{
	int i;

	bcs->tx_skb = NULL; //FIXME -> hw part

	skb_queue_head_init(&bcs->squeue);

	bcs->corrupted = 0;
	bcs->trans_down = 0;
	bcs->trans_up = 0;

610
	gig_dbg(DEBUG_INIT, "setting up bcs[%d]->at_state", channel);
611 612 613 614 615 616
	gigaset_at_init(&bcs->at_state, bcs, cs, -1);

#ifdef CONFIG_GIGASET_DEBUG
	bcs->emptycount = 0;
#endif

617
	gig_dbg(DEBUG_INIT, "allocating bcs[%d]->skb", channel);
618 619 620 621 622
	bcs->fcs = PPP_INITFCS;
	bcs->inputstate = 0;
	if (cs->ignoreframes) {
		bcs->inputstate |= INS_skip_frame;
		bcs->skb = NULL;
623 624 625 626 627 628 629 630
	} else {
		bcs->skb = dev_alloc_skb(SBUFSIZE + cs->hw_hdr_len);
		if (bcs->skb != NULL)
			skb_reserve(bcs->skb, cs->hw_hdr_len);
		else {
			pr_err("out of memory\n");
			bcs->inputstate |= INS_skip_frame;
		}
631 632 633 634 635 636 637 638 639 640 641 642 643
	}

	bcs->channel = channel;
	bcs->cs = cs;

	bcs->chstate = 0;
	bcs->use_count = 1;
	bcs->busy = 0;
	bcs->ignore = cs->ignoreframes;

	for (i = 0; i < AT_NUM; ++i)
		bcs->commands[i] = NULL;

644
	gig_dbg(DEBUG_INIT, "  setting up bcs[%d]->hw", channel);
645 646 647
	if (cs->ops->initbcshw(bcs))
		return bcs;

648
	gig_dbg(DEBUG_INIT, "  failed");
649

650
	gig_dbg(DEBUG_INIT, "  freeing bcs[%d]->skb", channel);
651 652 653 654 655 656
	if (bcs->skb)
		dev_kfree_skb(bcs->skb);

	return NULL;
}

657 658 659 660 661 662 663 664 665 666 667
/**
 * gigaset_initcs() - initialize device structure
 * @drv:	hardware driver the device belongs to
 * @channels:	number of B channels supported by device
 * @onechannel:	!=0 if B channel data and AT commands share one
 *		    communication channel (M10x),
 *		==0 if B channels have separate communication channels (base)
 * @ignoreframes:	number of frames to ignore after setting up B channel
 * @cidmode:	!=0: start in CallID mode
 * @modulename:	name of driver module for LL registration
 *
668 669 670
 * Allocate and initialize cardstate structure for Gigaset driver
 * Calls hardware dependent gigaset_initcshw() function
 * Calls B channel initialization function gigaset_initbcs() for each B channel
671 672
 *
 * Return value:
673 674 675 676 677 678 679
 *	pointer to cardstate structure
 */
struct cardstate *gigaset_initcs(struct gigaset_driver *drv, int channels,
				 int onechannel, int ignoreframes,
				 int cidmode, const char *modulename)
{
	struct cardstate *cs = NULL;
680
	unsigned long flags;
681 682
	int i;

683
	gig_dbg(DEBUG_INIT, "allocating cs");
684
	if (!(cs = alloc_cs(drv))) {
685
		pr_err("maximum number of devices exceeded\n");
686 687 688
		return NULL;
	}

689
	gig_dbg(DEBUG_INIT, "allocating bcs[0..%d]", channels - 1);
690
	cs->bcs = kmalloc(channels * sizeof(struct bc_state), GFP_KERNEL);
691
	if (!cs->bcs) {
692
		pr_err("out of memory\n");
693
		goto error;
694
	}
695
	gig_dbg(DEBUG_INIT, "allocating inbuf");
696
	cs->inbuf = kmalloc(sizeof(struct inbuf_t), GFP_KERNEL);
697
	if (!cs->inbuf) {
698
		pr_err("out of memory\n");
699
		goto error;
700
	}
701 702 703 704 705 706

	cs->cs_init = 0;
	cs->channels = channels;
	cs->onechannel = onechannel;
	cs->ignoreframes = ignoreframes;
	INIT_LIST_HEAD(&cs->temp_at_states);
707
	cs->running = 0;
708 709
	init_timer(&cs->timer); /* clear next & prev */
	spin_lock_init(&cs->ev_lock);
710 711
	cs->ev_tail = 0;
	cs->ev_head = 0;
712

713 714
	tasklet_init(&cs->event_tasklet, &gigaset_handle_event,
		     (unsigned long) cs);
Tilman Schmidt's avatar
Tilman Schmidt committed
715
	cs->commands_pending = 0;
716 717 718
	cs->cur_at_seq = 0;
	cs->gotfwver = -1;
	cs->open_count = 0;
719
	cs->dev = NULL;
720
	cs->tty = NULL;
721
	cs->tty_dev = NULL;
722
	cs->cidmode = cidmode != 0;
723 724
	cs->tabnocid = gigaset_tab_nocid;
	cs->tabcid = gigaset_tab_cid;
725 726 727 728

	init_waitqueue_head(&cs->waitqueue);
	cs->waiting = 0;

Tilman Schmidt's avatar
Tilman Schmidt committed
729 730
	cs->mode = M_UNKNOWN;
	cs->mstate = MS_UNINITIALIZED;
731 732 733

	++cs->cs_init;

734
	gig_dbg(DEBUG_INIT, "setting up at_state");
735 736 737 738 739
	spin_lock_init(&cs->lock);
	gigaset_at_init(&cs->at_state, NULL, cs, 0);
	cs->dle = 0;
	cs->cbytes = 0;

740
	gig_dbg(DEBUG_INIT, "setting up inbuf");
741 742 743 744 745
	if (onechannel) {			//FIXME distinction necessary?
		gigaset_inbuf_init(cs->inbuf, cs->bcs, cs, INS_command);
	} else
		gigaset_inbuf_init(cs->inbuf, NULL,    cs, INS_command);

746 747
	cs->connected = 0;
	cs->isdn_up = 0;
748

749
	gig_dbg(DEBUG_INIT, "setting up cmdbuf");
750 751 752 753 754
	cs->cmdbuf = cs->lastcmdbuf = NULL;
	spin_lock_init(&cs->cmdlock);
	cs->curlen = 0;
	cs->cmdbytes = 0;

755
	gig_dbg(DEBUG_INIT, "setting up iif");
756
	if (!gigaset_isdn_register(cs, modulename)) {
757
		pr_err("error registering ISDN device\n");
758 759 760 761 762
		goto error;
	}

	make_valid(cs, VALID_ID);
	++cs->cs_init;
763
	gig_dbg(DEBUG_INIT, "setting up hw");
764
	if (!cs->ops->initcshw(cs))
765 766 767 768
		goto error;

	++cs->cs_init;

769
	/* set up character device */
770 771
	gigaset_if_init(cs);

772 773 774
	/* set up device sysfs */
	gigaset_init_dev_sysfs(cs);

775 776 777 778 779 780 781 782 783
	/* set up channel data structures */
	for (i = 0; i < channels; ++i) {
		gig_dbg(DEBUG_INIT, "setting up bcs[%d]", i);
		if (!gigaset_initbcs(cs->bcs + i, cs, i)) {
			pr_err("could not allocate channel %d data\n", i);
			goto error;
		}
	}

784 785 786
	spin_lock_irqsave(&cs->lock, flags);
	cs->running = 1;
	spin_unlock_irqrestore(&cs->lock, flags);
787 788
	setup_timer(&cs->timer, timer_tick, (unsigned long) cs);
	cs->timer.expires = jiffies + msecs_to_jiffies(GIG_TICK);
789 790 791 792
	/* FIXME: can jiffies increase too much until the timer is added?
	 * Same problem(?) with mod_timer() in timer_tick(). */
	add_timer(&cs->timer);

793
	gig_dbg(DEBUG_INIT, "cs initialized");
794 795
	return cs;

796
error:
797
	gig_dbg(DEBUG_INIT, "failed");
798 799 800 801 802
	gigaset_freecs(cs);
	return NULL;
}
EXPORT_SYMBOL_GPL(gigaset_initcs);

803
/* ReInitialize the b-channel structure on hangup */
804 805 806 807 808 809 810 811 812
void gigaset_bcs_reinit(struct bc_state *bcs)
{
	struct sk_buff *skb;
	struct cardstate *cs = bcs->cs;
	unsigned long flags;

	while ((skb = skb_dequeue(&bcs->squeue)) != NULL)
		dev_kfree_skb(skb);

813
	spin_lock_irqsave(&cs->lock, flags);
814 815 816 817
	clear_at_state(&bcs->at_state);
	bcs->at_state.ConState = 0;
	bcs->at_state.timer_active = 0;
	bcs->at_state.timer_expires = 0;
818
	bcs->at_state.cid = -1;			/* No CID defined */
819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845
	spin_unlock_irqrestore(&cs->lock, flags);

	bcs->inputstate = 0;

#ifdef CONFIG_GIGASET_DEBUG
	bcs->emptycount = 0;
#endif

	bcs->fcs = PPP_INITFCS;
	bcs->chstate = 0;

	bcs->ignore = cs->ignoreframes;
	if (bcs->ignore)
		bcs->inputstate |= INS_skip_frame;


	cs->ops->reinitbcshw(bcs);
}

static void cleanup_cs(struct cardstate *cs)
{
	struct cmdbuf_t *cb, *tcb;
	int i;
	unsigned long flags;

	spin_lock_irqsave(&cs->lock, flags);

Tilman Schmidt's avatar
Tilman Schmidt committed
846 847
	cs->mode = M_UNKNOWN;
	cs->mstate = MS_UNINITIALIZED;
848 849 850 851 852 853 854 855 856

	clear_at_state(&cs->at_state);
	dealloc_at_states(cs);
	free_strings(&cs->at_state);
	gigaset_at_init(&cs->at_state, NULL, cs, 0);

	kfree(cs->inbuf->rcvbuf);
	cs->inbuf->rcvbuf = NULL;
	cs->inbuf->inputstate = INS_command;
Tilman Schmidt's avatar
Tilman Schmidt committed
857 858
	cs->inbuf->head = 0;
	cs->inbuf->tail = 0;
859 860 861 862 863 864 865 866 867 868 869 870 871

	cb = cs->cmdbuf;
	while (cb) {
		tcb = cb;
		cb = cb->next;
		kfree(tcb);
	}
	cs->cmdbuf = cs->lastcmdbuf = NULL;
	cs->curlen = 0;
	cs->cmdbytes = 0;
	cs->gotfwver = -1;
	cs->dle = 0;
	cs->cur_at_seq = 0;
Tilman Schmidt's avatar
Tilman Schmidt committed
872
	cs->commands_pending = 0;
873 874 875 876 877 878 879
	cs->cbytes = 0;

	spin_unlock_irqrestore(&cs->lock, flags);

	for (i = 0; i < cs->channels; ++i) {
		gigaset_freebcs(cs->bcs + i);
		if (!gigaset_initbcs(cs->bcs + i, cs, i))
880
			pr_err("could not allocate channel %d data\n", i);
881 882 883 884 885 886 887 888 889 890
	}

	if (cs->waiting) {
		cs->cmd_result = -ENODEV;
		cs->waiting = 0;
		wake_up_interruptible(&cs->waitqueue);
	}
}


891 892 893 894 895 896 897 898 899 900 901
/**
 * gigaset_start() - start device operations
 * @cs:		device descriptor structure.
 *
 * Prepares the device for use by setting up communication parameters,
 * scheduling an EV_START event to initiate device initialization, and
 * waiting for completion of the initialization.
 *
 * Return value:
 *	1 - success, 0 - error
 */
902 903
int gigaset_start(struct cardstate *cs)
{
904 905
	unsigned long flags;

906
	if (mutex_lock_interruptible(&cs->mutex))
907 908
		return 0;

909 910 911
	spin_lock_irqsave(&cs->lock, flags);
	cs->connected = 1;
	spin_unlock_irqrestore(&cs->lock, flags);
912

Tilman Schmidt's avatar
Tilman Schmidt committed
913
	if (cs->mstate != MS_LOCKED) {
914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929
		cs->ops->set_modem_ctrl(cs, 0, TIOCM_DTR|TIOCM_RTS);
		cs->ops->baud_rate(cs, B115200);
		cs->ops->set_line_ctrl(cs, CS8);
		cs->control_state = TIOCM_DTR|TIOCM_RTS;
	} else {
		//FIXME use some saved values?
	}

	cs->waiting = 1;

	if (!gigaset_add_event(cs, &cs->at_state, EV_START, NULL, 0, NULL)) {
		cs->waiting = 0;
		//FIXME what should we do?
		goto error;
	}

930
	gig_dbg(DEBUG_CMD, "scheduling START");
931 932 933 934
	gigaset_schedule_event(cs);

	wait_event(cs->waitqueue, !cs->waiting);

935
	mutex_unlock(&cs->mutex);
936 937 938
	return 1;

error:
939
	mutex_unlock(&cs->mutex);
940 941 942 943
	return 0;
}
EXPORT_SYMBOL_GPL(gigaset_start);

944 945 946 947 948 949 950 951 952
/**
 * gigaset_shutdown() - shut down device operations
 * @cs:		device descriptor structure.
 *
 * Deactivates the device by scheduling an EV_SHUTDOWN event and
 * waiting for completion of the shutdown.
 *
 * Return value:
 *	0 - success, -1 - error (no device associated)
Tilman Schmidt's avatar
Tilman Schmidt committed
953 954
 */
int gigaset_shutdown(struct cardstate *cs)
955
{
956
	mutex_lock(&cs->mutex);
957

958 959
	if (!(cs->flags & VALID_MINOR)) {
		mutex_unlock(&cs->mutex);
Tilman Schmidt's avatar
Tilman Schmidt committed
960
		return -1;
961
	}
Tilman Schmidt's avatar
Tilman Schmidt committed
962

963 964 965 966 967 968 969
	cs->waiting = 1;

	if (!gigaset_add_event(cs, &cs->at_state, EV_SHUTDOWN, NULL, 0, NULL)) {
		//FIXME what should we do?
		goto exit;
	}

970
	gig_dbg(DEBUG_CMD, "scheduling SHUTDOWN");
971 972
	gigaset_schedule_event(cs);

973
	wait_event(cs->waitqueue, !cs->waiting);
974 975 976 977

	cleanup_cs(cs);

exit:
978
	mutex_unlock(&cs->mutex);
Tilman Schmidt's avatar
Tilman Schmidt committed
979
	return 0;
980 981 982
}
EXPORT_SYMBOL_GPL(gigaset_shutdown);

983 984 985 986 987 988 989
/**
 * gigaset_stop() - stop device operations
 * @cs:		device descriptor structure.
 *
 * Stops operations on the device by scheduling an EV_STOP event and
 * waiting for completion of the shutdown.
 */
990 991
void gigaset_stop(struct cardstate *cs)
{
992
	mutex_lock(&cs->mutex);
993 994 995 996 997 998 999 1000

	cs->waiting = 1;

	if (!gigaset_add_event(cs, &cs->at_state, EV_STOP, NULL, 0, NULL)) {
		//FIXME what should we do?
		goto exit;
	}

1001
	gig_dbg(DEBUG_CMD, "scheduling STOP");
1002 1003
	gigaset_schedule_event(cs);

1004
	wait_event(cs->waitqueue, !cs->waiting);
1005 1006 1007 1008

	cleanup_cs(cs);

exit:
1009
	mutex_unlock(&cs->mutex);
1010 1011 1012 1013
}
EXPORT_SYMBOL_GPL(gigaset_stop);

static LIST_HEAD(drivers);
1014
static DEFINE_SPINLOCK(driver_lock);
1015 1016 1017 1018

struct cardstate *gigaset_get_cs_by_id(int id)
{
	unsigned long flags;
1019 1020
	struct cardstate *ret = NULL;
	struct cardstate *cs;
1021 1022 1023 1024 1025 1026 1027
	struct gigaset_driver *drv;
	unsigned i;

	spin_lock_irqsave(&driver_lock, flags);
	list_for_each_entry(drv, &drivers, list) {
		spin_lock(&drv->lock);
		for (i = 0; i < drv->minors; ++i) {
Tilman Schmidt's avatar
Tilman Schmidt committed
1028 1029 1030
			cs = drv->cs + i;
			if ((cs->flags & VALID_ID) && cs->myid == id) {
				ret = cs;
1031
				break;
Tilman Schmidt's avatar
Tilman Schmidt committed
1032
			}
1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050
		}
		spin_unlock(&drv->lock);
		if (ret)
			break;
	}
	spin_unlock_irqrestore(&driver_lock, flags);
	return ret;
}

void gigaset_debugdrivers(void)
{
	unsigned long flags;
	static struct cardstate *cs;
	struct gigaset_driver *drv;
	unsigned i;

	spin_lock_irqsave(&driver_lock, flags);
	list_for_each_entry(drv, &drivers, list) {
1051
		gig_dbg(DEBUG_DRIVER, "driver %p", drv);
1052 1053
		spin_lock(&drv->lock);
		for (i = 0; i < drv->minors; ++i) {
1054
			gig_dbg(DEBUG_DRIVER, "  index %u", i);
1055
			cs = drv->cs + i;
1056
			gig_dbg(DEBUG_DRIVER, "    cardstate %p", cs);
Tilman Schmidt's avatar
Tilman Schmidt committed
1057
			gig_dbg(DEBUG_DRIVER, "    flags 0x%02x", cs->flags);
1058 1059 1060 1061
			gig_dbg(DEBUG_DRIVER, "    minor_index %u",
				cs->minor_index);
			gig_dbg(DEBUG_DRIVER, "    driver %p", cs->driver);
			gig_dbg(DEBUG_DRIVER, "    i4l id %d", cs->myid);
1062 1063 1064 1065 1066 1067
		}
		spin_unlock(&drv->lock);
	}
	spin_unlock_irqrestore(&driver_lock, flags);
}

1068
static struct cardstate *gigaset_get_cs_by_minor(unsigned minor)
1069 1070
{
	unsigned long flags;
1071
	struct cardstate *ret = NULL;
1072 1073 1074 1075 1076 1077 1078 1079 1080
	struct gigaset_driver *drv;
	unsigned index;

	spin_lock_irqsave(&driver_lock, flags);
	list_for_each_entry(drv, &drivers, list) {
		if (minor < drv->minor || minor >= drv->minor + drv->minors)
			continue;
		index = minor - drv->minor;
		spin_lock(&drv->lock);
Tilman Schmidt's avatar
Tilman Schmidt committed
1081
		if (drv->cs[index].flags & VALID_MINOR)
1082 1083 1084 1085 1086 1087 1088 1089 1090
			ret = drv->cs + index;
		spin_unlock(&drv->lock);
		if (ret)
			break;
	}
	spin_unlock_irqrestore(&driver_lock, flags);
	return ret;
}

1091 1092 1093 1094 1095