⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 serio.c

📁 h内核
💻 C
📖 第 1 页 / 共 2 页
字号:
static void serio_destroy_port(struct serio *serio){	struct serio_driver *drv = serio->drv;	unsigned long flags;	serio_remove_pending_events(serio);	list_del_init(&serio->node);	if (drv) {		drv->disconnect(serio);		down_write(&serio_bus.subsys.rwsem);		device_release_driver(&serio->dev);		up_write(&serio_bus.subsys.rwsem);		put_driver(&drv->driver);	}	if (serio->parent) {		spin_lock_irqsave(&serio->parent->lock, flags);		serio->parent->child = NULL;		spin_unlock_irqrestore(&serio->parent->lock, flags);	}	device_unregister(&serio->dev);}/* * serio_connect_port() tries to bind the port and possible all its * children to appropriate drivers. If driver passed in the function will not * try otehr drivers when binding parent port. */static void serio_connect_port(struct serio *serio, struct serio_driver *drv){	WARN_ON(serio->drv);	WARN_ON(serio->child);	if (drv)		serio_bind_driver(serio, drv);	else if (!serio->manual_bind)		serio_find_driver(serio);	/* Ok, now bind children, if any */	while (serio->child) {		serio = serio->child;		WARN_ON(serio->drv);		WARN_ON(serio->child);		serio_create_port(serio);		if (!serio->manual_bind) {			/*			 * With children we just _prefer_ passed in driver,			 * but we will try other options in case preferred			 * is not the one			 */			if (!drv || !serio_bind_driver(serio, drv))				serio_find_driver(serio);		}	}}/* * */static void serio_reconnect_port(struct serio *serio){	do {		if (!serio->drv || !serio->drv->reconnect || serio->drv->reconnect(serio)) {			serio_disconnect_port(serio);			serio_connect_port(serio, NULL);			/* 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_driver *drv = serio->drv;	struct serio *s;	if (serio->child) {		/*		 * Children ports should be disconnected and destroyed		 * first, staring with the leaf one, since we don't want		 * to do recursion		 */		do {			s = serio->child;		} while (s->child);		while (s != serio) {			s = s->parent;			serio_destroy_port(s->child);		}	}	/*	 * Ok, no children left, now disconnect this port	 */	if (drv) {		drv->disconnect(serio);		down_write(&serio_bus.subsys.rwsem);		device_release_driver(&serio->dev);		up_write(&serio_bus.subsys.rwsem);		put_driver(&drv->driver);	}}void serio_rescan(struct serio *serio){	serio_queue_event(serio, SERIO_RESCAN);}void serio_reconnect(struct serio *serio){	serio_queue_event(serio, SERIO_RECONNECT);}void serio_register_port(struct serio *serio){	down(&serio_sem);	serio_create_port(serio);	serio_connect_port(serio, NULL);	up(&serio_sem);}/* * Submits register request to kseriod for subsequent execution. * Can be used when it is not obvious whether the serio_sem is * taken or not and when delayed execution is feasible. */void serio_register_port_delayed(struct serio *serio){	serio_queue_event(serio, SERIO_REGISTER_PORT);}void serio_unregister_port(struct serio *serio){	down(&serio_sem);	serio_disconnect_port(serio);	serio_destroy_port(serio);	up(&serio_sem);}/* * Submits unregister request to kseriod for subsequent execution. * Can be used when it is not obvious whether the serio_sem is * taken or not and when delayed execution is feasible. */void serio_unregister_port_delayed(struct serio *serio){	serio_queue_event(serio, SERIO_UNREGISTER_PORT);}/* * 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};void serio_register_driver(struct serio_driver *drv){	struct serio *serio;	down(&serio_sem);	list_add_tail(&drv->node, &serio_driver_list);	drv->driver.bus = &serio_bus;	driver_register(&drv->driver);	if (drv->manual_bind)		goto out;start_over:	list_for_each_entry(serio, &serio_list, node) {		if (!serio->drv) {			serio_connect_port(serio, drv);			/*			 * if new child appeared then the list is changed,			 * we need to start over			 */			if (serio->child)				goto start_over;		}	}out:	up(&serio_sem);}void serio_unregister_driver(struct serio_driver *drv){	struct serio *serio;	down(&serio_sem);	list_del_init(&drv->node);start_over:	list_for_each_entry(serio, &serio_list, node) {		if (serio->drv == drv) {			serio_disconnect_port(serio);			serio_connect_port(serio, NULL);			/* we could've deleted some ports, restart */			goto start_over;		}	}	driver_unregister(&drv->driver);	up(&serio_sem);}static void serio_set_drv(struct serio *serio, struct serio_driver *drv){	down(&serio->drv_sem);	serio_pause_rx(serio);	serio->drv = drv;	serio_continue_rx(serio);	up(&serio->drv_sem);}/* called from serio_driver->connect/disconnect methods under serio_sem */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_sem */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, struct pt_regs *regs){	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, regs);	} else {		if (!dfl) {			if ((serio->type != SERIO_8042 &&			     serio->type != SERIO_8042_XL) || (data == 0xaa)) {				serio_rescan(serio);				ret = IRQ_HANDLED;			}		}	}	spin_unlock_irqrestore(&serio->lock, flags);	return ret;}static int __init serio_init(void){	if (!(serio_pid = kernel_thread(serio_thread, NULL, CLONE_KERNEL))) {		printk(KERN_WARNING "serio: Failed to start kseriod\n");		return -1;	}	serio_bus.dev_attrs = serio_device_attrs;	serio_bus.drv_attrs = serio_driver_attrs;	bus_register(&serio_bus);	return 0;}static void __exit serio_exit(void){	bus_unregister(&serio_bus);	kill_proc(serio_pid, SIGTERM, 1);	wait_for_completion(&serio_exited);}module_init(serio_init);module_exit(serio_exit);

⌨️ 快捷键说明

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