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 + -
显示快捷键?