serio.c

来自「linux 内核源代码」· C语言 代码 · 共 1,029 行 · 第 1/2 页

C
1,029
字号
	__ATTR(bind_mode, S_IWUSR | S_IRUGO, serio_show_bind_mode, serio_set_bind_mode),	__ATTR_NULL};static void serio_release_port(struct device *dev){	struct serio *serio = to_serio_port(dev);	kfree(serio);	module_put(THIS_MODULE);}/* * Prepare serio port for registration. */static void serio_init_port(struct serio *serio){	static atomic_t serio_no = ATOMIC_INIT(0);	__module_get(THIS_MODULE);	INIT_LIST_HEAD(&serio->node);	spin_lock_init(&serio->lock);	mutex_init(&serio->drv_mutex);	device_initialize(&serio->dev);	snprintf(serio->dev.bus_id, sizeof(serio->dev.bus_id),		 "serio%ld", (long)atomic_inc_return(&serio_no) - 1);	serio->dev.bus = &serio_bus;	serio->dev.release = serio_release_port;	if (serio->parent) {		serio->dev.parent = &serio->parent->dev;		serio->depth = serio->parent->depth + 1;	} else		serio->depth = 0;	lockdep_set_subclass(&serio->lock, serio->depth);}/* * Complete serio port registration. * Driver core will attempt to find appropriate driver for the port. */static void serio_add_port(struct serio *serio){	int error;	if (serio->parent) {		serio_pause_rx(serio->parent);		serio->parent->child = serio;		serio_continue_rx(serio->parent);	}	list_add_tail(&serio->node, &serio_list);	if (serio->start)		serio->start(serio);	error = device_add(&serio->dev);	if (error)		printk(KERN_ERR			"serio: device_add() failed for %s (%s), error: %d\n",			serio->phys, serio->name, error);	else {		serio->registered = 1;		error = sysfs_create_group(&serio->dev.kobj, &serio_id_attr_group);		if (error)			printk(KERN_ERR				"serio: sysfs_create_group() failed for %s (%s), error: %d\n",				serio->phys, serio->name, error);	}}/* * serio_destroy_port() completes deregistration process and removes * port from the system */static void serio_destroy_port(struct serio *serio){	struct serio *child;	child = serio_get_pending_child(serio);	if (child) {		serio_remove_pending_events(child);		put_device(&child->dev);	}	if (serio->stop)		serio->stop(serio);	if (serio->parent) {		serio_pause_rx(serio->parent);		serio->parent->child = NULL;		serio_continue_rx(serio->parent);		serio->parent = NULL;	}	if (serio->registered) {		sysfs_remove_group(&serio->dev.kobj, &serio_id_attr_group);		device_del(&serio->dev);		serio->registered = 0;	}	list_del_init(&serio->node);	serio_remove_pending_events(serio);	put_device(&serio->dev);}/* * Reconnect serio port and all its children (re-initialize attached devices) */static void serio_reconnect_port(struct serio *serio){	do {		if (serio_reconnect_driver(serio)) {			serio_disconnect_port(serio);			serio_find_driver(serio);			/* Ok, old children are now gone, we are done */			break;		}		serio = serio->child;	} while (serio);}/* * serio_disconnect_port() unbinds a port from its driver. As a side effect * all child ports are unbound and destroyed. */static void serio_disconnect_port(struct serio *serio){	struct serio *s, *parent;	if (serio->child) {		/*		 * Children ports should be disconnected and destroyed		 * first, staring with the leaf one, since we don't want		 * to do recursion		 */		for (s = serio; s->child; s = s->child)			/* empty */;		do {			parent = s->parent;			device_release_driver(&s->dev);			serio_destroy_port(s);		} while ((s = parent) != serio);	}	/*	 * Ok, no children left, now disconnect this port	 */	device_release_driver(&serio->dev);}void serio_rescan(struct serio *serio){	serio_queue_event(serio, NULL, SERIO_RESCAN_PORT);}void serio_reconnect(struct serio *serio){	serio_queue_event(serio, NULL, SERIO_RECONNECT_PORT);}/* * Submits register request to kseriod for subsequent execution. * Note that port registration is always asynchronous. */void __serio_register_port(struct serio *serio, struct module *owner){	serio_init_port(serio);	serio_queue_event(serio, owner, SERIO_REGISTER_PORT);}/* * Synchronously unregisters serio port. */void serio_unregister_port(struct serio *serio){	mutex_lock(&serio_mutex);	serio_disconnect_port(serio);	serio_destroy_port(serio);	mutex_unlock(&serio_mutex);}/* * Safely unregisters child port if one is present. */void serio_unregister_child_port(struct serio *serio){	mutex_lock(&serio_mutex);	if (serio->child) {		serio_disconnect_port(serio->child);		serio_destroy_port(serio->child);	}	mutex_unlock(&serio_mutex);}/* * Serio driver operations */static ssize_t serio_driver_show_description(struct device_driver *drv, char *buf){	struct serio_driver *driver = to_serio_driver(drv);	return sprintf(buf, "%s\n", driver->description ? driver->description : "(none)");}static ssize_t serio_driver_show_bind_mode(struct device_driver *drv, char *buf){	struct serio_driver *serio_drv = to_serio_driver(drv);	return sprintf(buf, "%s\n", serio_drv->manual_bind ? "manual" : "auto");}static ssize_t serio_driver_set_bind_mode(struct device_driver *drv, const char *buf, size_t count){	struct serio_driver *serio_drv = to_serio_driver(drv);	int retval;	retval = count;	if (!strncmp(buf, "manual", count)) {		serio_drv->manual_bind = 1;	} else if (!strncmp(buf, "auto", count)) {		serio_drv->manual_bind = 0;	} else {		retval = -EINVAL;	}	return retval;}static struct driver_attribute serio_driver_attrs[] = {	__ATTR(description, S_IRUGO, serio_driver_show_description, NULL),	__ATTR(bind_mode, S_IWUSR | S_IRUGO,		serio_driver_show_bind_mode, serio_driver_set_bind_mode),	__ATTR_NULL};static int serio_driver_probe(struct device *dev){	struct serio *serio = to_serio_port(dev);	struct serio_driver *drv = to_serio_driver(dev->driver);	return serio_connect_driver(serio, drv);}static int serio_driver_remove(struct device *dev){	struct serio *serio = to_serio_port(dev);	serio_disconnect_driver(serio);	return 0;}static void serio_cleanup(struct serio *serio){	mutex_lock(&serio->drv_mutex);	if (serio->drv && serio->drv->cleanup)		serio->drv->cleanup(serio);	mutex_unlock(&serio->drv_mutex);}static void serio_shutdown(struct device *dev){	struct serio *serio = to_serio_port(dev);	serio_cleanup(serio);}static void serio_attach_driver(struct serio_driver *drv){	int error;	error = driver_attach(&drv->driver);	if (error)		printk(KERN_WARNING			"serio: driver_attach() failed for %s with error %d\n",			drv->driver.name, error);}int __serio_register_driver(struct serio_driver *drv, struct module *owner, const char *mod_name){	int manual_bind = drv->manual_bind;	int error;	drv->driver.bus = &serio_bus;	drv->driver.owner = owner;	drv->driver.mod_name = mod_name;	/*	 * Temporarily disable automatic binding because probing	 * takes long time and we are better off doing it in kseriod	 */	drv->manual_bind = 1;	error = driver_register(&drv->driver);	if (error) {		printk(KERN_ERR			"serio: driver_register() failed for %s, error: %d\n",			drv->driver.name, error);		return error;	}	/*	 * Restore original bind mode and let kseriod bind the	 * driver to free ports	 */	if (!manual_bind) {		drv->manual_bind = 0;		error = serio_queue_event(drv, NULL, SERIO_ATTACH_DRIVER);		if (error) {			driver_unregister(&drv->driver);			return error;		}	}	return 0;}void serio_unregister_driver(struct serio_driver *drv){	struct serio *serio;	mutex_lock(&serio_mutex);	drv->manual_bind = 1;	/* so serio_find_driver ignores it */start_over:	list_for_each_entry(serio, &serio_list, node) {		if (serio->drv == drv) {			serio_disconnect_port(serio);			serio_find_driver(serio);			/* we could've deleted some ports, restart */			goto start_over;		}	}	driver_unregister(&drv->driver);	mutex_unlock(&serio_mutex);}static void serio_set_drv(struct serio *serio, struct serio_driver *drv){	serio_pause_rx(serio);	serio->drv = drv;	serio_continue_rx(serio);}static int serio_bus_match(struct device *dev, struct device_driver *drv){	struct serio *serio = to_serio_port(dev);	struct serio_driver *serio_drv = to_serio_driver(drv);	if (serio->manual_bind || serio_drv->manual_bind)		return 0;	return serio_match_port(serio_drv->id_table, serio);}#ifdef CONFIG_HOTPLUG#define SERIO_ADD_UEVENT_VAR(fmt, val...)				\	do {								\		int err = add_uevent_var(env, fmt, val);		\		if (err)						\			return err;					\	} while (0)static int serio_uevent(struct device *dev, struct kobj_uevent_env *env){	struct serio *serio;	if (!dev)		return -ENODEV;	serio = to_serio_port(dev);	SERIO_ADD_UEVENT_VAR("SERIO_TYPE=%02x", serio->id.type);	SERIO_ADD_UEVENT_VAR("SERIO_PROTO=%02x", serio->id.proto);	SERIO_ADD_UEVENT_VAR("SERIO_ID=%02x", serio->id.id);	SERIO_ADD_UEVENT_VAR("SERIO_EXTRA=%02x", serio->id.extra);	SERIO_ADD_UEVENT_VAR("MODALIAS=serio:ty%02Xpr%02Xid%02Xex%02X",				serio->id.type, serio->id.proto, serio->id.id, serio->id.extra);	return 0;}#undef SERIO_ADD_UEVENT_VAR#elsestatic int serio_uevent(struct device *dev, struct kobj_uevent_env *env){	return -ENODEV;}#endif /* CONFIG_HOTPLUG */#ifdef CONFIG_PMstatic int serio_suspend(struct device *dev, pm_message_t state){	if (dev->power.power_state.event != state.event) {		if (state.event == PM_EVENT_SUSPEND)			serio_cleanup(to_serio_port(dev));		dev->power.power_state = state;	}	return 0;}static int serio_resume(struct device *dev){	struct serio *serio = to_serio_port(dev);	if (dev->power.power_state.event != PM_EVENT_ON &&	    serio_reconnect_driver(serio)) {		/*		 * Driver re-probing can take a while, so better let kseriod		 * deal with it.		 */		serio_rescan(serio);	}	dev->power.power_state = PMSG_ON;	return 0;}#endif /* CONFIG_PM *//* called from serio_driver->connect/disconnect methods under serio_mutex */int serio_open(struct serio *serio, struct serio_driver *drv){	serio_set_drv(serio, drv);	if (serio->open && serio->open(serio)) {		serio_set_drv(serio, NULL);		return -1;	}	return 0;}/* called from serio_driver->connect/disconnect methods under serio_mutex */void serio_close(struct serio *serio){	if (serio->close)		serio->close(serio);	serio_set_drv(serio, NULL);}irqreturn_t serio_interrupt(struct serio *serio,		unsigned char data, unsigned int dfl){	unsigned long flags;	irqreturn_t ret = IRQ_NONE;	spin_lock_irqsave(&serio->lock, flags);        if (likely(serio->drv)) {                ret = serio->drv->interrupt(serio, data, dfl);	} else if (!dfl && serio->registered) {		serio_rescan(serio);		ret = IRQ_HANDLED;	}	spin_unlock_irqrestore(&serio->lock, flags);	return ret;}static struct bus_type serio_bus = {	.name		= "serio",	.dev_attrs	= serio_device_attrs,	.drv_attrs	= serio_driver_attrs,	.match		= serio_bus_match,	.uevent		= serio_uevent,	.probe		= serio_driver_probe,	.remove		= serio_driver_remove,	.shutdown	= serio_shutdown,#ifdef CONFIG_PM	.suspend	= serio_suspend,	.resume		= serio_resume,#endif};static int __init serio_init(void){	int error;	error = bus_register(&serio_bus);	if (error) {		printk(KERN_ERR "serio: failed to register serio bus, error: %d\n", error);		return error;	}	serio_task = kthread_run(serio_thread, NULL, "kseriod");	if (IS_ERR(serio_task)) {		bus_unregister(&serio_bus);		error = PTR_ERR(serio_task);		printk(KERN_ERR "serio: Failed to start kseriod, error: %d\n", error);		return error;	}	return 0;}static void __exit serio_exit(void){	bus_unregister(&serio_bus);	kthread_stop(serio_task);}subsys_initcall(serio_init);module_exit(serio_exit);

⌨️ 快捷键说明

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