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