common.c

来自「LINUX 2.6.17.4的源码」· C语言 代码 · 共 1,234 行 · 第 1/2 页

C
1,234
字号
	}	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;	gig_dbg(DEBUG_INIT, "  setting up bcs[%d]->hw", channel);	if (cs->ops->initbcshw(bcs))		return bcs;	gig_dbg(DEBUG_INIT, "  failed");	gig_dbg(DEBUG_INIT, "  freeing bcs[%d]->skb", channel);	if (bcs->skb)		dev_kfree_skb(bcs->skb);	return NULL;}/* gigaset_initcs * 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 * parameters: *	drv		hardware driver the device belongs to *	channels	number of B channels supported by device *	onechannel	!=0: B channel data and AT commands share one *			     communication channel *			==0: B channels have separate communication channels *	ignoreframes	number of frames to ignore after setting up B channel *	cidmode		!=0: start in CallID mode *	modulename	name of driver module (used for I4L registration) * 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 = NULL;	unsigned long flags;	int i;	gig_dbg(DEBUG_INIT, "allocating cs");	cs = alloc_cs(drv);	if (!cs)		goto error;	gig_dbg(DEBUG_INIT, "allocating bcs[0..%d]", channels - 1);	cs->bcs = kmalloc(channels * sizeof(struct bc_state), GFP_KERNEL);	if (!cs->bcs)		goto error;	gig_dbg(DEBUG_INIT, "allocating inbuf");	cs->inbuf = kmalloc(sizeof(struct inbuf_t), GFP_KERNEL);	if (!cs->inbuf)		goto error;	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;	mutex_init(&cs->mutex);	mutex_lock(&cs->mutex);	tasklet_init(&cs->event_tasklet, &gigaset_handle_event,		     (unsigned long) cs);	atomic_set(&cs->commands_pending, 0);	cs->cur_at_seq = 0;	cs->gotfwver = -1;	cs->open_count = 0;	cs->dev = NULL;	cs->tty = NULL;	cs->cidmode = cidmode != 0;	//if(onechannel) { //FIXME		cs->tabnocid = gigaset_tab_nocid_m10x;		cs->tabcid = gigaset_tab_cid_m10x;	//} else {	//	cs->tabnocid = gigaset_tab_nocid;	//	cs->tabcid = gigaset_tab_cid;	//}	init_waitqueue_head(&cs->waitqueue);	cs->waiting = 0;	atomic_set(&cs->mode, M_UNKNOWN);	atomic_set(&cs->mstate, MS_UNINITIALIZED);	for (i = 0; i < channels; ++i) {		gig_dbg(DEBUG_INIT, "setting up bcs[%d].read", i);		if (!gigaset_initbcs(cs->bcs + i, cs, i))			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");	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);	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_register_to_LL(cs, modulename)) {		err("register_isdn failed");		goto error;	}	make_valid(cs, VALID_ID);	++cs->cs_init;	gig_dbg(DEBUG_INIT, "setting up hw");	if (!cs->ops->initcshw(cs))		goto error;	++cs->cs_init;	gigaset_if_init(cs);	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);	/* FIXME: can jiffies increase too much until the timer is added?	 * Same problem(?) with mod_timer() in timer_tick(). */	add_timer(&cs->timer);	gig_dbg(DEBUG_INIT, "cs initialized");	mutex_unlock(&cs->mutex);	return cs;error:	if (cs)		mutex_unlock(&cs->mutex);	gig_dbg(DEBUG_INIT, "failed");	gigaset_freecs(cs);	return NULL;}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->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);	atomic_set(&cs->mode, M_UNKNOWN);	atomic_set(&cs->mstate, MS_UNINITIALIZED);	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;	atomic_set(&cs->inbuf->head, 0);	atomic_set(&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;	atomic_set(&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))			break;			//FIXME error handling	}	if (cs->waiting) {		cs->cmd_result = -ENODEV;		cs->waiting = 0;		wake_up_interruptible(&cs->waitqueue);	}}int gigaset_start(struct cardstate *cs){	unsigned long flags;	if (mutex_lock_interruptible(&cs->mutex))		return 0;	spin_lock_irqsave(&cs->lock, flags);	cs->connected = 1;	spin_unlock_irqrestore(&cs->lock, flags);	if (atomic_read(&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;	} 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;	}	gig_dbg(DEBUG_CMD, "scheduling START");	gigaset_schedule_event(cs);	wait_event(cs->waitqueue, !cs->waiting);	/* set up device sysfs */	gigaset_init_dev_sysfs(cs);	mutex_unlock(&cs->mutex);	return 1;error:	mutex_unlock(&cs->mutex);	return 0;}EXPORT_SYMBOL_GPL(gigaset_start);void gigaset_shutdown(struct cardstate *cs){	mutex_lock(&cs->mutex);	cs->waiting = 1;	if (!gigaset_add_event(cs, &cs->at_state, EV_SHUTDOWN, NULL, 0, NULL)) {		//FIXME what should we do?		goto exit;	}	gig_dbg(DEBUG_CMD, "scheduling SHUTDOWN");	gigaset_schedule_event(cs);	if (wait_event_interruptible(cs->waitqueue, !cs->waiting)) {		warn("%s: aborted", __func__);		//FIXME	}	if (atomic_read(&cs->mstate) != MS_LOCKED) {		//FIXME?		//gigaset_baud_rate(cs, B115200);		//gigaset_set_line_ctrl(cs, CS8);		//gigaset_set_modem_ctrl(cs, TIOCM_DTR|TIOCM_RTS, 0);		//cs->control_state = 0;	} else {		//FIXME use some saved values?	}	cleanup_cs(cs);exit:	mutex_unlock(&cs->mutex);}EXPORT_SYMBOL_GPL(gigaset_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)) {		//FIXME what should we do?		goto exit;	}	gig_dbg(DEBUG_CMD, "scheduling STOP");	gigaset_schedule_event(cs);	if (wait_event_interruptible(cs->waitqueue, !cs->waiting)) {		warn("%s: aborted", __func__);		//FIXME	}	/* clear device sysfs */	gigaset_free_dev_sysfs(cs);	cleanup_cs(cs);exit:	mutex_unlock(&cs->mutex);}EXPORT_SYMBOL_GPL(gigaset_stop);static LIST_HEAD(drivers);static spinlock_t driver_lock = SPIN_LOCK_UNLOCKED;struct cardstate *gigaset_get_cs_by_id(int id){	unsigned long flags;	static struct cardstate *ret = NULL;	static 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) {			if (drv->flags[i] & VALID_ID) {				cs = drv->cs + i;				if (cs->myid == id)					ret = cs;			}			if (ret)				break;		}		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) {		gig_dbg(DEBUG_DRIVER, "driver %p", drv);		spin_lock(&drv->lock);		for (i = 0; i < drv->minors; ++i) {			gig_dbg(DEBUG_DRIVER, "  index %u", i);			gig_dbg(DEBUG_DRIVER, "    flags 0x%02x",				drv->flags[i]);			cs = drv->cs + i;			gig_dbg(DEBUG_DRIVER, "    cardstate %p", cs);			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);		}		spin_unlock(&drv->lock);	}	spin_unlock_irqrestore(&driver_lock, flags);}static struct cardstate *gigaset_get_cs_by_minor(unsigned minor){	unsigned long flags;	static 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->flags[index] & VALID_MINOR)			ret = drv->cs + index;		spin_unlock(&drv->lock);		if (ret)			break;	}	spin_unlock_irqrestore(&driver_lock, flags);	return ret;}struct cardstate *gigaset_get_cs_by_tty(struct tty_struct *tty){	if (tty->index < 0 || tty->index >= tty->driver->num)		return NULL;	return gigaset_get_cs_by_minor(tty->index + tty->driver->minor_start);}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);	module_put(drv->owner);	kfree(drv->cs);	kfree(drv->flags);	kfree(drv);}EXPORT_SYMBOL_GPL(gigaset_freedriver);/* gigaset_initdriver * Allocate and initialize gigaset_driver structure. Initialize interface. * parameters: *	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) *	devfsname	Devfs name of the device files without %d * 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 char *devfsname,					  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;	if (!try_module_get(owner))		goto out1;	drv->cs = 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 out2;	drv->flags = kmalloc(minors * sizeof *drv->flags, GFP_KERNEL);	if (!drv->flags)		goto out3;	for (i = 0; i < minors; ++i) {		drv->flags[i] = 0;		drv->cs[i].driver = drv;		drv->cs[i].ops = drv->ops;		drv->cs[i].minor_index = i;	}	gigaset_if_initdriver(drv, procname, devname, devfsname);	spin_lock_irqsave(&driver_lock, flags);	list_add(&drv->list, &drivers);	spin_unlock_irqrestore(&driver_lock, flags);	return drv;out3:	kfree(drv->cs);out2:	module_put(owner);out1:	kfree(drv);	return NULL;}EXPORT_SYMBOL_GPL(gigaset_initdriver);/* For drivers without fixed assignment device<->cardstate (usb) */struct cardstate *gigaset_getunassignedcs(struct gigaset_driver *drv){	unsigned long flags;	struct cardstate *cs = NULL;	unsigned i;	spin_lock_irqsave(&drv->lock, flags);	if (drv->blocked)		goto exit;	for (i = 0; i < drv->minors; ++i) {		if ((drv->flags[i] & VALID_MINOR) &&		    !(drv->flags[i] & ASSIGNED)) {			drv->flags[i] |= ASSIGNED;			cs = drv->cs + i;			break;		}	}exit:	spin_unlock_irqrestore(&drv->lock, flags);	return cs;}EXPORT_SYMBOL_GPL(gigaset_getunassignedcs);void gigaset_unassign(struct cardstate *cs){	unsigned long flags;	unsigned *minor_flags;	struct gigaset_driver *drv;	if (!cs)		return;	drv = cs->driver;	spin_lock_irqsave(&drv->lock, flags);	minor_flags = drv->flags + cs->minor_index;	if (*minor_flags & VALID_MINOR)		*minor_flags &= ~ASSIGNED;	spin_unlock_irqrestore(&drv->lock, flags);}EXPORT_SYMBOL_GPL(gigaset_unassign);void gigaset_blockdriver(struct gigaset_driver *drv){	unsigned long flags;	spin_lock_irqsave(&drv->lock, flags);	drv->blocked = 1;	spin_unlock_irqrestore(&drv->lock, flags);}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;	info(DRIVER_AUTHOR);	info(DRIVER_DESC);	return 0;}static void __exit gigaset_exit_module(void){}module_init(gigaset_init_module);module_exit(gigaset_exit_module);MODULE_AUTHOR(DRIVER_AUTHOR);MODULE_DESCRIPTION(DRIVER_DESC);MODULE_LICENSE("GPL");

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?