Release 4.7 drivers/isdn/gigaset/common.c
  
  
/*
 * Stuff used by all variants of the driver
 *
 * Copyright (c) 2001 by Stefan Eilers,
 *                       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/module.h>
#include <linux/moduleparam.h>
/* Version Information */
#define DRIVER_AUTHOR "Hansjoerg Lipp <hjlipp@web.de>, Tilman Schmidt <tilman@imap.cc>, Stefan Eilers"
#define DRIVER_DESC "Driver for Gigaset 307x"
#ifdef CONFIG_GIGASET_DEBUG
#define DRIVER_DESC_DEBUG " (debug build)"
#else
#define DRIVER_DESC_DEBUG ""
#endif
/* Module parameters */
int gigaset_debuglevel;
EXPORT_SYMBOL_GPL(gigaset_debuglevel);
module_param_named(debug, gigaset_debuglevel, int, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(debug, "debug level");
/* driver state flags */
#define VALID_MINOR	0x01
#define VALID_ID	0x02
/**
 * 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.
 */
void gigaset_dbg_buffer(enum debuglevel level, const unsigned char *msg,
			size_t len, const unsigned char *buf)
{
	unsigned char outbuf[80];
	unsigned char c;
	size_t space = sizeof outbuf - 1;
	unsigned char *out = outbuf;
	size_t numin = len;
	while (numin--) {
		c = *buf++;
		if (c == '~' || c == '^' || c == '\\') {
			if (!space--)
				break;
			*out++ = '\\';
		}
		if (c & 0x80) {
			if (!space--)
				break;
			*out++ = '~';
			c ^= 0x80;
		}
		if (c < 0x20 || c == 0x7f) {
			if (!space--)
				break;
			*out++ = '^';
			c ^= 0x40;
		}
		if (!space--)
			break;
		*out++ = c;
	}
	*out = 0;
	gig_dbg(level, "%s (%u bytes): %s", msg, (unsigned) len, outbuf);
}
Contributors
 | Person | Tokens | Prop | Commits | CommitProp | 
| hansjoerg lipp | hansjoerg lipp | 100 | 54.05% | 1 | 33.33% | 
| tilman schmidt | tilman schmidt | 85 | 45.95% | 2 | 66.67% | 
 | Total | 185 | 100.00% | 3 | 100.00% | 
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;
}
Contributors
 | Person | Tokens | Prop | Commits | CommitProp | 
| hansjoerg lipp | hansjoerg lipp | 75 | 100.00% | 1 | 100.00% | 
 | Total | 75 | 100.00% | 1 | 100.00% | 
int gigaset_enterconfigmode(struct cardstate *cs)
{
	int i, r;
	cs->control_state = TIOCM_RTS;
	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:
	dev_err(cs->dev, "error %d on setuartbits\n", -r);
	cs->control_state = TIOCM_RTS | TIOCM_DTR;
	cs->ops->set_modem_ctrl(cs, 0, TIOCM_RTS | TIOCM_DTR);
	return -1;
}
Contributors
 | Person | Tokens | Prop | Commits | CommitProp | 
| hansjoerg lipp | hansjoerg lipp | 176 | 96.70% | 1 | 50.00% | 
| tilman schmidt | tilman schmidt | 6 | 3.30% | 1 | 50.00% | 
 | Total | 182 | 100.00% | 2 | 100.00% | 
static int test_timeout(struct at_state_t *at_state)
{
	if (!at_state->timer_expires)
		return 0;
	if (--at_state->timer_expires) {
		gig_dbg(DEBUG_MCMD, "decreased timer of %p to %lu",
			at_state, at_state->timer_expires);
		return 0;
	}
	gigaset_add_event(at_state->cs, at_state, EV_TIMEOUT, NULL,
			  at_state->timer_index, NULL);
	return 1;
}
Contributors
 | Person | Tokens | Prop | Commits | CommitProp | 
| hansjoerg lipp | hansjoerg lipp | 66 | 97.06% | 1 | 33.33% | 
| tilman schmidt | tilman schmidt | 2 | 2.94% | 2 | 66.67% | 
 | Total | 68 | 100.00% | 3 | 100.00% | 
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;
	if (cs->running) {
		mod_timer(&cs->timer, jiffies + msecs_to_jiffies(GIG_TICK));
		if (timeout) {
			gig_dbg(DEBUG_EVENT, "scheduling timeout");
			tasklet_schedule(&cs->event_tasklet);
		}
	}
	spin_unlock_irqrestore(&cs->lock, flags);
}
Contributors
 | Person | Tokens | Prop | Commits | CommitProp | 
| hansjoerg lipp | hansjoerg lipp | 165 | 97.06% | 1 | 25.00% | 
| tilman schmidt | tilman schmidt | 5 | 2.94% | 3 | 75.00% | 
 | Total | 170 | 100.00% | 4 | 100.00% | 
int gigaset_get_channel(struct bc_state *bcs)
{
	unsigned long flags;
	spin_lock_irqsave(&bcs->cs->lock, flags);
	if (bcs->use_count || !try_module_get(bcs->cs->driver->owner)) {
		gig_dbg(DEBUG_CHANNEL, "could not allocate channel %d",
			bcs->channel);
		spin_unlock_irqrestore(&bcs->cs->lock, flags);
		return -EBUSY;
	}
	++bcs->use_count;
	bcs->busy = 1;
	gig_dbg(DEBUG_CHANNEL, "allocated channel %d", bcs->channel);
	spin_unlock_irqrestore(&bcs->cs->lock, flags);
	return 0;
}
Contributors
 | Person | Tokens | Prop | Commits | CommitProp | 
| hansjoerg lipp | hansjoerg lipp | 91 | 82.73% | 1 | 20.00% | 
| tilman schmidt | tilman schmidt | 19 | 17.27% | 4 | 80.00% | 
 | Total | 110 | 100.00% | 5 | 100.00% | 
struct bc_state *gigaset_get_free_channel(struct cardstate *cs)
{
	unsigned long flags;
	int i;
	spin_lock_irqsave(&cs->lock, flags);
	if (!try_module_get(cs->driver->owner)) {
		gig_dbg(DEBUG_CHANNEL,
			"could not get module for allocating channel");
		spin_unlock_irqrestore(&cs->lock, flags);
		return NULL;
	}
	for (i = 0; i < cs->channels; ++i)
		if (!cs->bcs[i].use_count) {
			++cs->bcs[i].use_count;
			cs->bcs[i].busy = 1;
			spin_unlock_irqrestore(&cs->lock, flags);
			gig_dbg(DEBUG_CHANNEL, "allocated channel %d", i);
			return cs->bcs + i;
		}
	module_put(cs->driver->owner);
	spin_unlock_irqrestore(&cs->lock, flags);
	gig_dbg(DEBUG_CHANNEL, "no free channel");
	return NULL;
}
Contributors
 | Person | Tokens | Prop | Commits | CommitProp | 
| tilman schmidt | tilman schmidt | 168 | 100.00% | 2 | 100.00% | 
 | Total | 168 | 100.00% | 2 | 100.00% | 
void gigaset_free_channel(struct bc_state *bcs)
{
	unsigned long flags;
	spin_lock_irqsave(&bcs->cs->lock, flags);
	if (!bcs->busy) {
		gig_dbg(DEBUG_CHANNEL, "could not free channel %d",
			bcs->channel);
		spin_unlock_irqrestore(&bcs->cs->lock, flags);
		return;
	}
	--bcs->use_count;
	bcs->busy = 0;
	module_put(bcs->cs->driver->owner);
	gig_dbg(DEBUG_CHANNEL, "freed channel %d", bcs->channel);
	spin_unlock_irqrestore(&bcs->cs->lock, flags);
}
Contributors
 | Person | Tokens | Prop | Commits | CommitProp | 
| hansjoerg lipp | hansjoerg lipp | 89 | 85.58% | 1 | 25.00% | 
| tilman schmidt | tilman schmidt | 15 | 14.42% | 3 | 75.00% | 
 | Total | 104 | 100.00% | 4 | 100.00% | 
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);
			gig_dbg(DEBUG_CHANNEL,
				"could not allocate all channels");
			return -EBUSY;
		}
	for (i = 0; i < cs->channels; ++i)
		++cs->bcs[i].use_count;
	spin_unlock_irqrestore(&cs->lock, flags);
	gig_dbg(DEBUG_CHANNEL, "allocated all channels");
	return 0;
}
Contributors
 | Person | Tokens | Prop | Commits | CommitProp | 
| hansjoerg lipp | hansjoerg lipp | 113 | 93.39% | 1 | 25.00% | 
| tilman schmidt | tilman schmidt | 8 | 6.61% | 3 | 75.00% | 
 | Total | 121 | 100.00% | 4 | 100.00% | 
void gigaset_free_channels(struct cardstate *cs)
{
	unsigned long flags;
	int i;
	gig_dbg(DEBUG_CHANNEL, "unblocking all channels");
	spin_lock_irqsave(&cs->lock, flags);
	for (i = 0; i < cs->channels; ++i)
		--cs->bcs[i].use_count;
	spin_unlock_irqrestore(&cs->lock, flags);
}
Contributors
 | Person | Tokens | Prop | Commits | CommitProp | 
| hansjoerg lipp | hansjoerg lipp | 67 | 97.10% | 1 | 33.33% | 
| tilman schmidt | tilman schmidt | 2 | 2.90% | 2 | 66.67% | 
 | Total | 69 | 100.00% | 3 | 100.00% | 
void gigaset_block_channels(struct cardstate *cs)
{
	unsigned long flags;
	int i;
	gig_dbg(DEBUG_CHANNEL, "blocking all channels");
	spin_lock_irqsave(&cs->lock, flags);
	for (i = 0; i < cs->channels; ++i)
		++cs->bcs[i].use_count;
	spin_unlock_irqrestore(&cs->lock, flags);
}
Contributors
 | Person | Tokens | Prop | Commits | CommitProp | 
| hansjoerg lipp | hansjoerg lipp | 67 | 97.10% | 1 | 33.33% | 
| tilman schmidt | tilman schmidt | 2 | 2.90% | 2 | 66.67% | 
 | Total | 69 | 100.00% | 3 | 100.00% | 
static void clear_events(struct cardstate *cs)
{
	struct event_t *ev;
	unsigned head, tail;
	unsigned long flags;
	spin_lock_irqsave(&cs->ev_lock, flags);
	head = cs->ev_head;
	tail = cs->ev_tail;
	while (tail != head) {
		ev = cs->events + head;
		kfree(ev->ptr);
		head = (head + 1) % MAX_EVENTS;
	}
	cs->ev_head = tail;
	spin_unlock_irqrestore(&cs->ev_lock, flags);
}
Contributors
 | Person | Tokens | Prop | Commits | CommitProp | 
| hansjoerg lipp | hansjoerg lipp | 73 | 76.04% | 1 | 50.00% | 
| tilman schmidt | tilman schmidt | 23 | 23.96% | 1 | 50.00% | 
 | Total | 96 | 100.00% | 2 | 100.00% | 
/**
 * 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
 */
struct event_t *gigaset_add_event(struct cardstate *cs,
				  struct at_state_t *at_state, int type,
				  void *ptr, int parameter, void *arg)
{
	unsigned long flags;
	unsigned next, tail;
	struct event_t *event = NULL;
	gig_dbg(DEBUG_EVENT, "queueing event %d", type);
	spin_lock_irqsave(&cs->ev_lock, flags);
	tail = cs->ev_tail;
	next = (tail + 1) % MAX_EVENTS;
	if (unlikely(next == cs->ev_head))
		dev_err(cs->dev, "event queue full\n");
	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;
		cs->ev_tail = next;
	}
	spin_unlock_irqrestore(&cs->ev_lock, flags);
	return event;
}
Contributors
 | Person | Tokens | Prop | Commits | CommitProp | 
| hansjoerg lipp | hansjoerg lipp | 153 | 90.53% | 1 | 25.00% | 
| tilman schmidt | tilman schmidt | 16 | 9.47% | 3 | 75.00% | 
 | Total | 169 | 100.00% | 4 | 100.00% | 
EXPORT_SYMBOL_GPL(gigaset_add_event);
static void clear_at_state(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;
	}
}
Contributors
 | Person | Tokens | Prop | Commits | CommitProp | 
| hansjoerg lipp | hansjoerg lipp | 47 | 97.92% | 1 | 50.00% | 
| tilman schmidt | tilman schmidt | 1 | 2.08% | 1 | 50.00% | 
 | Total | 48 | 100.00% | 2 | 100.00% | 
static void dealloc_temp_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);
		clear_at_state(cur);
		kfree(cur);
	}
}
Contributors
 | Person | Tokens | Prop | Commits | CommitProp | 
| hansjoerg lipp | hansjoerg lipp | 47 | 95.92% | 1 | 50.00% | 
| tilman schmidt | tilman schmidt | 2 | 4.08% | 1 | 50.00% | 
 | Total | 49 | 100.00% | 2 | 100.00% | 
static void gigaset_freebcs(struct bc_state *bcs)
{
	int i;
	gig_dbg(DEBUG_INIT, "freeing bcs[%d]->hw", bcs->channel);
	bcs->cs->ops->freebcshw(bcs);
	gig_dbg(DEBUG_INIT, "clearing bcs[%d]->at_state", bcs->channel);
	clear_at_state(&bcs->at_state);
	gig_dbg(DEBUG_INIT, "freeing bcs[%d]->skb", bcs->channel);
	dev_kfree_skb(bcs->rx_skb);
	bcs->rx_skb = NULL;
	for (i = 0; i < AT_NUM; ++i) {
		kfree(bcs->commands[i]);
		bcs->commands[i] = NULL;
	}
}
Contributors
 | Person | Tokens | Prop | Commits | CommitProp | 
| hansjoerg lipp | hansjoerg lipp | 103 | 91.15% | 1 | 25.00% | 
| tilman schmidt | tilman schmidt | 10 | 8.85% | 3 | 75.00% | 
 | Total | 113 | 100.00% | 4 | 100.00% | 
static struct cardstate *alloc_cs(struct gigaset_driver *drv)
{
	unsigned long flags;
	unsigned i;
	struct cardstate *cs;
	struct cardstate *ret = NULL;
	spin_lock_irqsave(&drv->lock, flags);
	if (drv->blocked)
		goto exit;
	for (i = 0; i < drv->minors; ++i) {
		cs = drv->cs + i;
		if (!(cs->flags & VALID_MINOR)) {
			cs->flags = VALID_MINOR;
			ret = cs;
			break;
		}
	}
exit:
	spin_unlock_irqrestore(&drv->lock, flags);
	return ret;
}
Contributors
 | Person | Tokens | Prop | Commits | CommitProp | 
| tilman schmidt | tilman schmidt | 88 | 76.52% | 3 | 75.00% | 
| hansjoerg lipp | hansjoerg lipp | 27 | 23.48% | 1 | 25.00% | 
 | Total | 115 | 100.00% | 4 | 100.00% | 
static void free_cs(struct cardstate *cs)
{
	cs->flags = 0;
}
Contributors
 | Person | Tokens | Prop | Commits | CommitProp | 
| tilman schmidt | tilman schmidt | 16 | 94.12% | 2 | 66.67% | 
| hansjoerg lipp | hansjoerg lipp | 1 | 5.88% | 1 | 33.33% | 
 | Total | 17 | 100.00% | 3 | 100.00% | 
static void make_valid(struct cardstate *cs, unsigned mask)
{
	unsigned long flags;
	struct gigaset_driver *drv = cs->driver;
	spin_lock_irqsave(&drv->lock, flags);
	cs->flags |= mask;
	spin_unlock_irqrestore(&drv->lock, flags);
}
Contributors
 | Person | Tokens | Prop | Commits | CommitProp | 
| tilman schmidt | tilman schmidt | 48 | 90.57% | 2 | 66.67% | 
| hansjoerg lipp | hansjoerg lipp | 5 | 9.43% | 1 | 33.33% | 
 | Total | 53 | 100.00% | 3 | 100.00% | 
static void make_invalid(struct cardstate *cs, unsigned mask)
{
	unsigned long flags;
	struct gigaset_driver *drv = cs->driver;
	spin_lock_irqsave(&drv->lock, flags);
	cs->flags &= ~mask;
	spin_unlock_irqrestore(&drv->lock, flags);
}
Contributors
 | Person | Tokens | Prop | Commits | CommitProp | 
| tilman schmidt | tilman schmidt | 54 | 100.00% | 2 | 100.00% | 
 | Total | 54 | 100.00% | 2 | 100.00% | 
/**
 * 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.
 */
void gigaset_freecs(struct cardstate *cs)
{
	int i;
	unsigned long flags;
	if (!cs)
		return;
	mutex_lock(&cs->mutex);
	spin_lock_irqsave(&cs->lock, flags);
	cs->running = 0;
	spin_unlock_irqrestore(&cs->lock, flags); /* event handler and timer are
                                                     not rescheduled below */
	tasklet_kill(&cs->event_tasklet);
	del_timer_sync(&cs->timer);
	switch (cs->cs_init) {
	default:
		/* clear B channel structures */
		for (i = 0; i < cs->channels; ++i) {
			gig_dbg(DEBUG_INIT, "clearing bcs[%d]", i);
			gigaset_freebcs(cs->bcs + i);
		}
		/* clear device sysfs */
		gigaset_free_dev_sysfs(cs);
		gigaset_if_free(cs);
		gig_dbg(DEBUG_INIT, "clearing hw");
		cs->ops->freecshw(cs);
		/* fall through */
	case 2: /* error in initcshw */
		/* Deregister from LL */
		make_invalid(cs, VALID_ID);
		gigaset_isdn_unregdev(cs);
		/* fall through */
	case 1: /* error when registering to LL */
		gig_dbg(DEBUG_INIT, "clearing at_state");
		clear_at_state(&cs->at_state);
		dealloc_temp_at_states(cs);
		clear_events(cs);
		tty_port_destroy(&cs->port);
		/* fall through */
	case 0:	/* error in basic setup */
		gig_dbg(DEBUG_INIT, "freeing inbuf");
		kfree(cs->inbuf);
		kfree(cs->bcs);
	}
	mutex_unlock(&cs->mutex);
	free_cs(cs);
}
Contributors
 | Person | Tokens | Prop | Commits | CommitProp | 
| tilman schmidt | tilman schmidt | 141 | 58.51% | 8 | 72.73% | 
| hansjoerg lipp | hansjoerg lipp | 92 | 38.17% | 2 | 18.18% | 
| jiri slaby | jiri slaby | 8 | 3.32% | 1 | 9.09% | 
 | Total | 241 | 100.00% | 11 | 100.00% | 
EXPORT_SYMBOL_GPL(gigaset_freecs);
void gigaset_at_init(struct at_state_t *at_state, struct bc_state *bcs,
		     struct cardstate *cs, int cid)
{
	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;
	at_state->timer_index = 0;
	at_state->seq_index = 0;
	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;
}
Contributors
 | Person | Tokens | Prop | Commits | CommitProp | 
| hansjoerg lipp | hansjoerg lipp | 170 | 98.84% | 1 | 50.00% | 
| tilman schmidt | tilman schmidt | 2 | 1.16% | 1 | 50.00% | 
 | Total | 172 | 100.00% | 2 | 100.00% | 
static void gigaset_inbuf_init(struct inbuf_t *inbuf, struct cardstate *cs)
/* inbuf->read must be allocated before! */
{
	inbuf->head = 0;
	inbuf->tail = 0;
	inbuf->cs = cs;
	inbuf->inputstate = INS_command;
}
Contributors
 | Person | Tokens | Prop | Commits | CommitProp | 
| hansjoerg lipp | hansjoerg lipp | 38 | 92.68% | 1 | 33.33% | 
| tilman schmidt | tilman schmidt | 3 | 7.32% | 2 | 66.67% | 
 | Total | 41 | 100.00% | 3 | 100.00% | 
/**
 * gigaset_fill_inbuf() - append received data to input buffer
 * @inbuf:      buffer structure.
 * @src:        received data.
 * @numbytes:   number of bytes received.
 *
 * Return value: !=0 if some data was appended
 */
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;
	tail = inbuf->tail;
	head = inbuf->head;
	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,
				"buffer overflow (%u bytes lost)\n",
				bytesleft);
			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);
	inbuf->tail = tail;
	return numbytes != bytesleft;
}
Contributors
 | Person | Tokens | Prop | Commits | CommitProp | 
| tilman schmidt | tilman schmidt | 197 | 99.49% | 2 | 66.67% | 
| joe perches | joe perches | 1 | 0.51% | 1 | 33.33% | 
 | Total | 198 | 100.00% | 3 | 100.00% | 
EXPORT_SYMBOL_GPL(gigaset_fill_inbuf);
/* Initialize the b-channel structure */
static int gigaset_initbcs(struct bc_state *bcs, struct cardstate *cs,
			   int channel)
{
	int i;
	bcs->tx_skb = NULL;
	skb_queue_head_init(&bcs->squeue);
	bcs->corrupted = 0;
	bcs->trans_down = 0;
	bcs->trans_up = 0;
	gig_dbg(DEBUG_INIT, "setting up bcs[%d]->at_state", channel);
	gigaset_at_init(&bcs->at_state, bcs, cs, -1);
#ifdef CONFIG_GIGASET_DEBUG
	bcs->emptycount = 0;
#endif
	bcs->rx_bufsize = 0;
	bcs->rx_skb = NULL;
	bcs->rx_fcs = PPP_INITFCS;
	bcs->inputstate = 0;
	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;
	spin_lock_init(&bcs->aplock);
	bcs->ap = NULL;
	bcs->apconnstate = 0;
	gig_dbg(DEBUG_INIT, "  setting up bcs[%d]->hw", channel);
	return cs->ops->initbcshw(bcs);
}
Contributors
 | Person | Tokens | Prop | Commits | CommitProp | 
| hansjoerg lipp | hansjoerg lipp | 178 | 83.96% | 1 | 16.67% | 
| tilman schmidt | tilman schmidt | 34 | 16.04% | 5 | 83.33% | 
 | Total | 212 | 100.00% | 6 | 100.00% | 
/**
 * 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
 *
 * 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
 *
 * Return value:
 *      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;
	unsigned long flags;
	int i;
	gig_dbg(DEBUG_INIT, "allocating cs");
	cs = alloc_cs(drv);
	if (!cs) {
		pr_err("maximum number of devices exceeded\n");
		return NULL;
	}
	cs->cs_init = 0;
	cs->channels = channels;
	cs->onechannel = onechannel;
	cs->ignoreframes = ignoreframes;
	INIT_LIST_HEAD(&cs->temp_at_states);
	cs->running = 0;
	init_timer(&cs->timer); /* clear next & prev */
	spin_lock_init(&cs->ev_lock);
	cs->ev_tail = 0;
	cs->ev_head = 0;
	tasklet_init(&cs->event_tasklet, gigaset_handle_event,
		     (unsigned long) cs);
	tty_port_init(&cs->port);
	cs->commands_pending = 0;
	cs->cur_at_seq = 0;
	cs->gotfwver = -1;
	cs->dev = NULL;
	cs->tty_dev = NULL;
	cs->cidmode = cidmode != 0;
	cs->tabnocid = gigaset_tab_nocid;
	cs->tabcid = gigaset_tab_cid;
	init_waitqueue_head(&cs->waitqueue);
	cs->waiting = 0;
	cs->mode = M_UNKNOWN;
	cs->mstate = MS_UNINITIALIZED;
	cs->bcs = kmalloc(channels * sizeof(struct bc_state), GFP_KERNEL);
	cs->inbuf = kmalloc(sizeof(struct inbuf_t), GFP_KERNEL);
	if (!cs->bcs || !cs->inbuf) {
		pr_err("out of memory\n");
		goto error;
	}
	++cs->cs_init;
	gig_dbg(DEBUG_INIT, "setting up at_state");
	spin_lock_init(&cs->lock);
	gigaset_at_init(&cs->at_state, NULL, cs, 0);
	cs->dle = 0;
	cs->cbytes = 0;
	gig_dbg(DEBUG_INIT, "setting up inbuf");
	gigaset_inbuf_init(cs->inbuf, cs);
	cs->connected = 0;
	cs->isdn_up = 0;
	gig_dbg(DEBUG_INIT, "setting up cmdbuf");
	cs->cmdbuf = cs->lastcmdbuf = NULL;
	spin_lock_init(&cs->cmdlock);
	cs->curlen = 0;
	cs->cmdbytes = 0;
	gig_dbg(DEBUG_INIT, "setting up iif");
	if (gigaset_isdn_regdev(cs, modulename) < 0) {
		pr_err("error registering ISDN device\n");
		goto error;
	}
	make_valid(cs, VALID_ID);
	++cs->cs_init;
	gig_dbg(DEBUG_INIT, "setting up hw");
	if (cs->ops->initcshw(cs) < 0)
		goto error;
	++cs->cs_init;
	/* set up character device */
	gigaset_if_init(cs);
	/* set up device sysfs */
	gigaset_init_dev_sysfs(cs);
	/* 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) < 0) {
			pr_err("could not allocate channel %d data\n", i);
			goto error;
		}
	}
	spin_lock_irqsave(&cs->lock, flags);
	cs->running = 1;
	spin_unlock_irqrestore(&cs->lock, flags);
	setup_timer(&cs->timer, timer_tick, (unsigned long) cs);
	cs->timer.expires = jiffies + msecs_to_jiffies(GIG_TICK);
	add_timer(&cs->timer);
	gig_dbg(DEBUG_INIT, "cs initialized");
	return cs;
error:
	gig_dbg(DEBUG_INIT, "failed");
	gigaset_freecs(cs);
	return NULL;
}
Contributors
 | Person | Tokens | Prop | Commits | CommitProp | 
| hansjoerg lipp | hansjoerg lipp | 422 | 67.30% | 2 | 11.11% | 
| tilman schmidt | tilman schmidt | 193 | 30.78% | 13 | 72.22% | 
| jiri slaby | jiri slaby | 11 | 1.75% | 2 | 11.11% | 
| greg kroah-hartman | greg kroah-hartman | 1 | 0.16% | 1 | 5.56% | 
 | Total | 627 | 100.00% | 18 | 100.00% | 
EXPORT_SYMBOL_GPL(gigaset_initcs);
/* ReInitialize the b-channel structure on hangup */
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);
	spin_lock_irqsave(&cs->lock, flags);
	clear_at_state(&bcs->at_state);
	bcs->at_state.ConState = 0;
	bcs->at_state.timer_active = 0;
	bcs->at_state.timer_expires = 0;
	bcs->at_state.cid = -1;			/* No CID defined */
	spin_unlock_irqrestore(&cs->lock, flags);
	bcs->inputstate = 0;
#ifdef CONFIG_GIGASET_DEBUG
	bcs->emptycount = 0;
#endif
	bcs->rx_fcs = PPP_INITFCS;
	bcs->chstate = 0;
	bcs->ignore = cs->ignoreframes;
	dev_kfree_skb(bcs->rx_skb);
	bcs->rx_skb = NULL;
	cs->ops->reinitbcshw(bcs);
}
Contributors
 | Person | Tokens | Prop | Commits | CommitProp | 
| hansjoerg lipp | hansjoerg lipp | 159 | 93.53% | 1 | 33.33% | 
| tilman schmidt | tilman schmidt | 11 | 6.47% | 2 | 66.67% | 
 | Total | 170 | 100.00% | 3 | 100.00% | 
static void cleanup_cs(struct cardstate *cs)
{
	struct cmdbuf_t *cb, *tcb;
	int i;
	unsigned long flags;
	spin_lock_irqsave(&cs->lock, flags);
	cs->mode = M_UNKNOWN;
	cs->mstate = MS_UNINITIALIZED;
	clear_at_state(&cs->at_state);
	dealloc_temp_at_states(cs);
	gigaset_at_init(&cs->at_state, NULL, cs, 0);
	cs->inbuf->inputstate = INS_command;
	cs->inbuf->head = 0;
	cs->inbuf->tail = 0;
	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;
	cs->commands_pending = 0;
	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) < 0)
			pr_err("could not allocate channel %d data\n", i);
	}
	if (cs->waiting) {
		cs->cmd_result = -ENODEV;
		cs->waiting = 0;
		wake_up_interruptible(&cs->waitqueue);
	}
}
Contributors
 | Person | Tokens | Prop | Commits | CommitProp | 
| hansjoerg lipp | hansjoerg lipp | 253 | 94.40% | 1 | 20.00% | 
| tilman schmidt | tilman schmidt | 15 | 5.60% | 4 | 80.00% | 
 | Total | 268 | 100.00% | 5 | 100.00% | 
/**
 * 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:
 *      0 on success, error code < 0 on failure
 */
int gigaset_start(struct cardstate *cs)
{
	unsigned long flags;
	if (mutex_lock_interruptible(&cs->mutex))
		return -EBUSY;
	spin_lock_irqsave(&cs->lock, flags);
	cs->connected = 1;
	spin_unlock_irqrestore(&cs->lock, flags);
	if (cs->mstate != MS_LOCKED) {
		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;
	}
	cs->waiting = 1;
	if (!gigaset_add_event(cs, &cs->at_state, EV_START, NULL, 0, NULL)) {
		cs->waiting = 0;
		goto error;
	}
	gigaset_schedule_event(cs);
	wait_event(cs->waitqueue, !cs->waiting);
	mutex_unlock(&cs->mutex);
	return 0;
error:
	mutex_unlock(&cs->mutex);
	return -ENOMEM;
}
Contributors
 | Person | Tokens | Prop | Commits | CommitProp | 
| hansjoerg lipp | hansjoerg lipp | 156 | 82.54% | 1 | 25.00% | 
| tilman schmidt | tilman schmidt | 33 | 17.46% | 3 | 75.00% | 
 | Total | 189 | 100.00% | 4 | 100.00% | 
EXPORT_SYMBOL_GPL(gigaset_start);
/**
 * 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, -ENODEV - error (no device associated)
 */
int gigaset_shutdown(struct cardstate *cs)
{
	mutex_lock(&cs->mutex);
	if (!(cs->flags & VALID_MINOR)) {
		mutex_unlock(&cs->mutex);
		return -ENODEV;
	}
	cs->waiting = 1;
	if (!gigaset_add_event(cs, &cs->at_state, EV_SHUTDOWN, NULL, 0, NULL))
		goto exit;
	gigaset_schedule_event(cs);
	wait_event(cs->waitqueue, !cs->waiting);
	cleanup_cs(cs);
exit:
	mutex_unlock(&cs->mutex);
	return 0;
}
Contributors
 | Person | Tokens | Prop | Commits | CommitProp | 
| hansjoerg lipp | hansjoerg lipp | 74 | 68.52% | 1 | 16.67% | 
| tilman schmidt | tilman schmidt | 34 | 31.48% | 5 | 83.33% | 
 | Total | 108 | 100.00% | 6 | 100.00% | 
EXPORT_SYMBOL_GPL(gigaset_shutdown);
/**
 * 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.
 */
void gigaset_stop(struct cardstate *cs)
{
	mutex_lock(&cs->mutex);
	cs->waiting = 1;
	if (!gigaset_add_event(cs, &cs->at_state, EV_STOP, NULL, 0, NULL))
		goto exit;
	gigaset_schedule_event(cs);
	wait_event(cs->waitqueue, !cs->waiting);
	cleanup_cs(cs);
exit:
	mutex_unlock(&cs->mutex);
}
Contributors
 | Person | Tokens | Prop | Commits | CommitProp | 
| hansjoerg lipp | hansjoerg lipp | 75 | 93.75% | 1 | 33.33% | 
| tilman schmidt | tilman schmidt | 5 | 6.25% | 2 | 66.67% | 
 | Total | 80 | 100.00% | 3 | 100.00% | 
EXPORT_SYMBOL_GPL(gigaset_stop);
static LIST_HEAD(drivers);
static DEFINE_SPINLOCK(driver_lock);
struct cardstate *gigaset_get_cs_by_id(int id)
{
	unsigned long flags;
	struct cardstate *ret = NULL;
	struct cardstate *cs;
	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) {
			cs = drv->cs + i;
			if ((cs->flags & VALID_ID) && cs->myid == id) {
				ret = cs;
				break;
			}
		}
		spin_unlock(&drv->lock);
		if (ret)
			break;
	}
	spin_unlock_irqrestore(&driver_lock, flags);
	return ret;
}
Contributors
 | Person | Tokens | Prop | Commits | CommitProp | 
| hansjoerg lipp | hansjoerg lipp | 122 | 92.42% | 1 | 50.00% | 
| tilman schmidt | tilman schmidt | 10 | 7.58% | 1 | 50.00% | 
 | Total | 132 | 100.00% | 2 | 100.00% | 
static struct cardstate *gigaset_get_cs_by_minor(unsigned minor)
{
	unsigned long flags;
	struct cardstate *ret = NULL;
	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);
		if (drv->cs[index].flags & VALID_MINOR)
			ret = drv->cs + index;
		spin_unlock(&drv->lock);
		if (ret)
			break;
	}
	spin_unlock_irqrestore(&driver_lock, flags);
	return ret;
}
Contributors
 | Person | Tokens | Prop | Commits | CommitProp | 
| hansjoerg lipp | hansjoerg lipp | 124 | 96.88% | 1 | 33.33% | 
| tilman schmidt | tilman schmidt | 3 | 2.34% | 1 | 33.33% | 
| adrian bunk | adrian bunk | 1 | 0.78% | 1 | 33.33% | 
 | Total | 128 | 100.00% | 3 | 100.00% | 
struct cardstate *gigaset_get_cs_by_tty(struct tty_struct *tty)
{
	return gigaset_get_cs_by_minor(tty->index + tty->driver->minor_start);
}
Contributors
 | Person | Tokens | Prop | Commits | CommitProp | 
| adrian bunk | adrian bunk | 26 | 100.00% | 1 | 100.00% | 
 | Total | 26 | 100.00% | 1 | 100.00% | 
/**
 * gigaset_freedriver() - free all associated ressources of a driver
 * @drv:        driver descriptor structure.
 *
 * Unregisters the driver from the system and deallocates the driver
 * structure @drv and all structures referenced from it.
 * All devices should be shut down before calling this.
 */
void gigaset_freedriver(struct gigaset_driver *drv)
{
	unsigned long flags;
	spin_lock_irqsave(&driver_lock, flags);
	list_del(&drv->list);
	spin_unlock_irqrestore(&driver_lock, flags);
	gigaset_if_freedriver(drv);
	kfree(drv->cs);
	kfree(drv);
}
Contributors
 | Person | Tokens | Prop | Commits | CommitProp | 
| hansjoerg lipp | hansjoerg lipp | 55 | 100.00% | 1 | 100.00% | 
 | Total | 55 | 100.00% | 1 | 100.00% | 
EXPORT_SYMBOL_GPL(gigaset_freedriver);
/**
 * gigaset_initdriver() - initialize driver structure
 * @minor:      First minor number
 * @minors:     Number of minors this driver can handle
 * @procname:   Name of the driver
 * @devname:    Name of the device files (prefix without minor number)
 *
 * Allocate and initialize gigaset_driver structure. Initialize interface.
 *
 * Return value:
 *      Pointer to the gigaset_driver structure on success, NULL on failure.
 */
struct gigaset_driver *gigaset_initdriver(unsigned minor, unsigned minors,
					  const char *procname,
					  const char *devname,
					  const struct gigaset_ops *ops,
					  struct module *owner)
{
	struct gigaset_driver *drv;
	unsigned long flags;
	unsigned i;
	drv = kmalloc(sizeof *drv, GFP_KERNEL);
	if (!drv)
		return NULL;
	drv->have_tty = 0;
	drv->minor = minor;
	drv->minors = minors;
	spin_lock_init(&drv->lock);
	drv->blocked = 0;
	drv->ops = ops;
	drv->owner = owner;
	INIT_LIST_HEAD(&drv->list);
	drv->cs = kmalloc(minors * sizeof *drv->cs, GFP_KERNEL);
	if (!drv->cs)
		goto error;
	for (i = 0; i < minors; ++i) {
		drv->cs[i].flags = 0;
		drv->cs[i].driver = drv;
		drv->cs[i].ops = drv->ops;
		drv->cs[i].minor_index = i;
		mutex_init(&drv->cs[i].mutex);
	}
	gigaset_if_initdriver(drv, procname, devname);
	spin_lock_irqsave(&driver_lock, flags);
	list_add(&drv->list, &drivers);
	spin_unlock_irqrestore(&driver_lock, flags);
	return drv;
error:
	kfree(drv);
	return NULL;
}
Contributors
 | Person | Tokens | Prop | Commits | CommitProp | 
| hansjoerg lipp | hansjoerg lipp | 249 | 93.26% | 1 | 25.00% | 
| tilman schmidt | tilman schmidt | 18 | 6.74% | 3 | 75.00% | 
 | Total | 267 | 100.00% | 4 | 100.00% | 
EXPORT_SYMBOL_GPL(gigaset_initdriver);
/**
 * gigaset_blockdriver() - block driver
 * @drv:        driver descriptor structure.
 *
 * Prevents the driver from attaching new devices, in preparation for
 * deregistration.
 */
void gigaset_blockdriver(struct gigaset_driver *drv)
{
	drv->blocked = 1;
}
Contributors
 | Person | Tokens | Prop | Commits | CommitProp | 
| hansjoerg lipp | hansjoerg lipp | 16 | 100.00% | 1 | 100.00% | 
 | Total | 16 | 100.00% | 1 | 100.00% | 
EXPORT_SYMBOL_GPL(gigaset_blockdriver);
static int __init gigaset_init_module(void)
{
	/* in accordance with the principle of least astonishment,
         * setting the 'debug' parameter to 1 activates a sensible
         * set of default debug levels
         */
	if (gigaset_debuglevel == 1)
		gigaset_debuglevel = DEBUG_DEFAULT;
	pr_info(DRIVER_DESC DRIVER_DESC_DEBUG "\n");
	gigaset_isdn_regdrv();
	return 0;
}
Contributors
 | Person | Tokens | Prop | Commits | CommitProp | 
| hansjoerg lipp | hansjoerg lipp | 25 | 78.12% | 1 | 20.00% | 
| tilman schmidt | tilman schmidt | 7 | 21.88% | 4 | 80.00% | 
 | Total | 32 | 100.00% | 5 | 100.00% | 
static void __exit gigaset_exit_module(void)
{
	gigaset_isdn_unregdrv();
}
Contributors
 | Person | Tokens | Prop | Commits | CommitProp | 
| hansjoerg lipp | hansjoerg lipp | 7 | 58.33% | 1 | 50.00% | 
| tilman schmidt | tilman schmidt | 5 | 41.67% | 1 | 50.00% | 
 | Total | 12 | 100.00% | 2 | 100.00% | 
module_init(gigaset_init_module);
module_exit(gigaset_exit_module);
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");
Overall Contributors
 | Person | Tokens | Prop | Commits | CommitProp | 
| hansjoerg lipp | hansjoerg lipp | 3818 | 73.62% | 2 | 5.13% | 
| tilman schmidt | tilman schmidt | 1316 | 25.38% | 31 | 79.49% | 
| adrian bunk | adrian bunk | 27 | 0.52% | 1 | 2.56% | 
| jiri slaby | jiri slaby | 19 | 0.37% | 2 | 5.13% | 
| ingo molnar | ingo molnar | 4 | 0.08% | 1 | 2.56% | 
| greg kroah-hartman | greg kroah-hartman | 1 | 0.02% | 1 | 2.56% | 
| joe perches | joe perches | 1 | 0.02% | 1 | 2.56% | 
 | Total | 5186 | 100.00% | 39 | 100.00% | 
  
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.