diff options
Diffstat (limited to 'drivers/input/serio/serio.c')
-rw-r--r-- | drivers/input/serio/serio.c | 107 |
1 files changed, 36 insertions, 71 deletions
diff --git a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c index 615bf62ad46..341824c4852 100644 --- a/drivers/input/serio/serio.c +++ b/drivers/input/serio/serio.c @@ -31,9 +31,10 @@ #include <linux/serio.h> #include <linux/errno.h> #include <linux/wait.h> +#include <linux/completion.h> #include <linux/sched.h> +#include <linux/smp_lock.h> #include <linux/slab.h> -#include <linux/kthread.h> MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); MODULE_DESCRIPTION("Serio abstraction core"); @@ -42,7 +43,6 @@ MODULE_LICENSE("GPL"); EXPORT_SYMBOL(serio_interrupt); EXPORT_SYMBOL(__serio_register_port); EXPORT_SYMBOL(serio_unregister_port); -EXPORT_SYMBOL(serio_unregister_child_port); EXPORT_SYMBOL(__serio_unregister_port_delayed); EXPORT_SYMBOL(__serio_register_driver); EXPORT_SYMBOL(serio_unregister_driver); @@ -68,37 +68,6 @@ static void serio_destroy_port(struct serio *serio); static void serio_reconnect_port(struct serio *serio); static void serio_disconnect_port(struct serio *serio); -static int serio_connect_driver(struct serio *serio, struct serio_driver *drv) -{ - int retval; - - down(&serio->drv_sem); - retval = drv->connect(serio, drv); - up(&serio->drv_sem); - - return retval; -} - -static int serio_reconnect_driver(struct serio *serio) -{ - int retval = -1; - - down(&serio->drv_sem); - if (serio->drv && serio->drv->reconnect) - retval = serio->drv->reconnect(serio); - up(&serio->drv_sem); - - return retval; -} - -static void serio_disconnect_driver(struct serio *serio) -{ - down(&serio->drv_sem); - if (serio->drv) - serio->drv->disconnect(serio); - up(&serio->drv_sem); -} - static int serio_match_port(const struct serio_device_id *ids, struct serio *serio) { while (ids->type || ids->proto) { @@ -122,7 +91,7 @@ static void serio_bind_driver(struct serio *serio, struct serio_driver *drv) if (serio_match_port(drv->id_table, serio)) { serio->dev.driver = &drv->driver; - if (serio_connect_driver(serio, drv)) { + if (drv->connect(serio, drv)) { serio->dev.driver = NULL; goto out; } @@ -169,7 +138,8 @@ struct serio_event { static DEFINE_SPINLOCK(serio_event_lock); /* protects serio_event_list */ static LIST_HEAD(serio_event_list); static DECLARE_WAIT_QUEUE_HEAD(serio_wait); -static struct task_struct *serio_task; +static DECLARE_COMPLETION(serio_exited); +static int serio_pid; static void serio_queue_event(void *object, struct module *owner, enum serio_event_type event_type) @@ -180,12 +150,12 @@ static void serio_queue_event(void *object, struct module *owner, spin_lock_irqsave(&serio_event_lock, flags); /* - * Scan event list for the other events for the same serio port, + * Scan event list for the other events for the same serio port, * starting with the most recent one. If event is the same we * do not need add new one. If event is of different type we * need to add this event and should not look further because * we need to preseve sequence of distinct events. - */ + */ list_for_each_entry_reverse(event, &serio_event_list, node) { if (event->object == object) { if (event->type == event_type) @@ -367,15 +337,20 @@ static struct serio *serio_get_pending_child(struct serio *parent) static int serio_thread(void *nothing) { + lock_kernel(); + daemonize("kseriod"); + allow_signal(SIGTERM); + do { serio_handle_events(); - wait_event_interruptible(serio_wait, - kthread_should_stop() || !list_empty(&serio_event_list)); - try_to_freeze(PF_FREEZE); - } while (!kthread_should_stop()); + wait_event_interruptible(serio_wait, !list_empty(&serio_event_list)); + try_to_freeze(); + } while (!signal_pending(current)); printk(KERN_DEBUG "serio: kseriod exiting\n"); - return 0; + + unlock_kernel(); + complete_and_exit(&serio_exited, 0); } @@ -383,31 +358,31 @@ static int serio_thread(void *nothing) * Serio port operations */ -static ssize_t serio_show_description(struct device *dev, char *buf) +static ssize_t serio_show_description(struct device *dev, struct device_attribute *attr, char *buf) { struct serio *serio = to_serio_port(dev); return sprintf(buf, "%s\n", serio->name); } -static ssize_t serio_show_id_type(struct device *dev, char *buf) +static ssize_t serio_show_id_type(struct device *dev, struct device_attribute *attr, char *buf) { struct serio *serio = to_serio_port(dev); return sprintf(buf, "%02x\n", serio->id.type); } -static ssize_t serio_show_id_proto(struct device *dev, char *buf) +static ssize_t serio_show_id_proto(struct device *dev, struct device_attribute *attr, char *buf) { struct serio *serio = to_serio_port(dev); return sprintf(buf, "%02x\n", serio->id.proto); } -static ssize_t serio_show_id_id(struct device *dev, char *buf) +static ssize_t serio_show_id_id(struct device *dev, struct device_attribute *attr, char *buf) { struct serio *serio = to_serio_port(dev); return sprintf(buf, "%02x\n", serio->id.id); } -static ssize_t serio_show_id_extra(struct device *dev, char *buf) +static ssize_t serio_show_id_extra(struct device *dev, struct device_attribute *attr, char *buf) { struct serio *serio = to_serio_port(dev); return sprintf(buf, "%02x\n", serio->id.extra); @@ -431,7 +406,7 @@ static struct attribute_group serio_id_attr_group = { .attrs = serio_device_id_attrs, }; -static ssize_t serio_rebind_driver(struct device *dev, const char *buf, size_t count) +static ssize_t serio_rebind_driver(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct serio *serio = to_serio_port(dev); struct device_driver *drv; @@ -462,13 +437,13 @@ static ssize_t serio_rebind_driver(struct device *dev, const char *buf, size_t c return retval; } -static ssize_t serio_show_bind_mode(struct device *dev, char *buf) +static ssize_t serio_show_bind_mode(struct device *dev, struct device_attribute *attr, char *buf) { struct serio *serio = to_serio_port(dev); return sprintf(buf, "%s\n", serio->manual_bind ? "manual" : "auto"); } -static ssize_t serio_set_bind_mode(struct device *dev, const char *buf, size_t count) +static ssize_t serio_set_bind_mode(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct serio *serio = to_serio_port(dev); int retval; @@ -582,7 +557,7 @@ static void serio_destroy_port(struct serio *serio) static void serio_reconnect_port(struct serio *serio) { do { - if (serio_reconnect_driver(serio)) { + if (!serio->drv || !serio->drv->reconnect || serio->drv->reconnect(serio)) { serio_disconnect_port(serio); serio_find_driver(serio); /* Ok, old children are now gone, we are done */ @@ -655,19 +630,6 @@ void serio_unregister_port(struct serio *serio) } /* - * Safely unregisters child port if one is present. - */ -void serio_unregister_child_port(struct serio *serio) -{ - down(&serio_sem); - if (serio->child) { - serio_disconnect_port(serio->child); - serio_destroy_port(serio->child); - } - 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. @@ -724,14 +686,15 @@ 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); + return drv->connect(serio, drv); } static int serio_driver_remove(struct device *dev) { struct serio *serio = to_serio_port(dev); + struct serio_driver *drv = to_serio_driver(dev->driver); - serio_disconnect_driver(serio); + drv->disconnect(serio); return 0; } @@ -767,9 +730,11 @@ start_over: 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); } static int serio_bus_match(struct device *dev, struct device_driver *drv) @@ -829,7 +794,7 @@ static int serio_resume(struct device *dev) { struct serio *serio = to_serio_port(dev); - if (serio_reconnect_driver(serio)) { + if (!serio->drv || !serio->drv->reconnect || serio->drv->reconnect(serio)) { /* * Driver re-probing can take a while, so better let kseriod * deal with it. @@ -883,10 +848,9 @@ irqreturn_t serio_interrupt(struct serio *serio, static int __init serio_init(void) { - serio_task = kthread_run(serio_thread, NULL, "kseriod"); - if (IS_ERR(serio_task)) { + if (!(serio_pid = kernel_thread(serio_thread, NULL, CLONE_KERNEL))) { printk(KERN_ERR "serio: Failed to start kseriod\n"); - return PTR_ERR(serio_task); + return -1; } serio_bus.dev_attrs = serio_device_attrs; @@ -902,7 +866,8 @@ static int __init serio_init(void) static void __exit serio_exit(void) { bus_unregister(&serio_bus); - kthread_stop(serio_task); + kill_proc(serio_pid, SIGTERM, 1); + wait_for_completion(&serio_exited); } module_init(serio_init); |