diff options
Diffstat (limited to 'drivers/input/serio')
-rw-r--r-- | drivers/input/serio/i8042.c | 39 | ||||
-rw-r--r-- | drivers/input/serio/serio.c | 147 | ||||
-rw-r--r-- | drivers/input/serio/serio_raw.c | 3 |
3 files changed, 100 insertions, 89 deletions
diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c index 7e3141f37e3..debe9445488 100644 --- a/drivers/input/serio/i8042.c +++ b/drivers/input/serio/i8042.c @@ -255,25 +255,10 @@ static int i8042_kbd_write(struct serio *port, unsigned char c) static int i8042_aux_write(struct serio *serio, unsigned char c) { struct i8042_port *port = serio->port_data; - int retval; - -/* - * Send the byte out. - */ - - if (port->mux == -1) - retval = i8042_command(&c, I8042_CMD_AUX_SEND); - else - retval = i8042_command(&c, I8042_CMD_MUX_SEND + port->mux); - -/* - * Make sure the interrupt happens and the character is received even - * in the case the IRQ isn't wired, so that we can receive further - * characters later. - */ - i8042_interrupt(0, NULL); - return retval; + return i8042_command(&c, port->mux == -1 ? + I8042_CMD_AUX_SEND : + I8042_CMD_MUX_SEND + port->mux); } /* @@ -337,23 +322,27 @@ static irqreturn_t i8042_interrupt(int irq, void *dev_id) dfl = 0; if (str & I8042_STR_MUXERR) { dbg("MUX error, status is %02x, data is %02x", str, data); - switch (data) { - default: /* * When MUXERR condition is signalled the data register can only contain * 0xfd, 0xfe or 0xff if implementation follows the spec. Unfortunately - * it is not always the case. Some KBC just get confused which port the - * data came from and signal error leaving the data intact. They _do not_ - * revert to legacy mode (actually I've never seen KBC reverting to legacy - * mode yet, when we see one we'll add proper handling). - * Anyway, we will assume that the data came from the same serio last byte + * it is not always the case. Some KBCs also report 0xfc when there is + * nothing connected to the port while others sometimes get confused which + * port the data came from and signal error leaving the data intact. They + * _do not_ revert to legacy mode (actually I've never seen KBC reverting + * to legacy mode yet, when we see one we'll add proper handling). + * Anyway, we process 0xfc, 0xfd, 0xfe and 0xff as timeouts, and for the + * rest assume that the data came from the same serio last byte * was transmitted (if transmission happened not too long ago). */ + + switch (data) { + default: if (time_before(jiffies, last_transmit + HZ/10)) { str = last_str; break; } /* fall through - report timeout */ + case 0xfc: case 0xfd: case 0xfe: dfl = SERIO_TIMEOUT; data = 0xfe; break; case 0xff: dfl = SERIO_PARITY; data = 0xfe; break; diff --git a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c index 5f1d4032fd5..f0ce822c102 100644 --- a/drivers/input/serio/serio.c +++ b/drivers/input/serio/serio.c @@ -45,8 +45,7 @@ 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_register_driver); EXPORT_SYMBOL(serio_unregister_driver); EXPORT_SYMBOL(serio_open); EXPORT_SYMBOL(serio_close); @@ -63,11 +62,10 @@ static LIST_HEAD(serio_list); static struct bus_type serio_bus; -static void serio_add_driver(struct serio_driver *drv); static void serio_add_port(struct serio *serio); -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 void serio_attach_driver(struct serio_driver *drv); static int serio_connect_driver(struct serio *serio, struct serio_driver *drv) { @@ -171,11 +169,10 @@ static void serio_find_driver(struct serio *serio) */ enum serio_event_type { - SERIO_RESCAN, - SERIO_RECONNECT, + SERIO_RESCAN_PORT, + SERIO_RECONNECT_PORT, SERIO_REGISTER_PORT, - SERIO_UNREGISTER_PORT, - SERIO_REGISTER_DRIVER, + SERIO_ATTACH_DRIVER, }; struct serio_event { @@ -190,11 +187,12 @@ static LIST_HEAD(serio_event_list); static DECLARE_WAIT_QUEUE_HEAD(serio_wait); static struct task_struct *serio_task; -static void serio_queue_event(void *object, struct module *owner, - enum serio_event_type event_type) +static int serio_queue_event(void *object, struct module *owner, + enum serio_event_type event_type) { unsigned long flags; struct serio_event *event; + int retval = 0; spin_lock_irqsave(&serio_event_lock, flags); @@ -213,24 +211,34 @@ static void serio_queue_event(void *object, struct module *owner, } } - if ((event = kmalloc(sizeof(struct serio_event), GFP_ATOMIC))) { - if (!try_module_get(owner)) { - printk(KERN_WARNING "serio: Can't get module reference, dropping event %d\n", event_type); - kfree(event); - goto out; - } - - event->type = event_type; - event->object = object; - event->owner = owner; + event = kmalloc(sizeof(struct serio_event), GFP_ATOMIC); + if (!event) { + printk(KERN_ERR + "serio: Not enough memory to queue event %d\n", + event_type); + retval = -ENOMEM; + goto out; + } - list_add_tail(&event->node, &serio_event_list); - wake_up(&serio_wait); - } else { - printk(KERN_ERR "serio: Not enough memory to queue event %d\n", event_type); + if (!try_module_get(owner)) { + printk(KERN_WARNING + "serio: Can't get module reference, dropping event %d\n", + event_type); + kfree(event); + retval = -EINVAL; + goto out; } + + event->type = event_type; + event->object = object; + event->owner = owner; + + list_add_tail(&event->node, &serio_event_list); + wake_up(&serio_wait); + out: spin_unlock_irqrestore(&serio_event_lock, flags); + return retval; } static void serio_free_event(struct serio_event *event) @@ -308,22 +316,17 @@ static void serio_handle_event(void) serio_add_port(event->object); break; - case SERIO_UNREGISTER_PORT: - serio_disconnect_port(event->object); - serio_destroy_port(event->object); - break; - - case SERIO_RECONNECT: + case SERIO_RECONNECT_PORT: serio_reconnect_port(event->object); break; - case SERIO_RESCAN: + case SERIO_RESCAN_PORT: serio_disconnect_port(event->object); serio_find_driver(event->object); break; - case SERIO_REGISTER_DRIVER: - serio_add_driver(event->object); + case SERIO_ATTACH_DRIVER: + serio_attach_driver(event->object); break; default: @@ -675,12 +678,12 @@ static void serio_disconnect_port(struct serio *serio) void serio_rescan(struct serio *serio) { - serio_queue_event(serio, NULL, SERIO_RESCAN); + serio_queue_event(serio, NULL, SERIO_RESCAN_PORT); } void serio_reconnect(struct serio *serio) { - serio_queue_event(serio, NULL, SERIO_RECONNECT); + serio_queue_event(serio, NULL, SERIO_RECONNECT_PORT); } /* @@ -717,16 +720,6 @@ void serio_unregister_child_port(struct serio *serio) mutex_unlock(&serio_mutex); } -/* - * Submits register request to kseriod for subsequent execution. - * Can be used when it is not obvious whether the serio_mutex is - * taken or not and when delayed execution is feasible. - */ -void __serio_unregister_port_delayed(struct serio *serio, struct module *owner) -{ - serio_queue_event(serio, owner, SERIO_UNREGISTER_PORT); -} - /* * Serio driver operations @@ -785,28 +778,52 @@ static int serio_driver_remove(struct device *dev) return 0; } -static struct bus_type serio_bus = { - .name = "serio", - .probe = serio_driver_probe, - .remove = serio_driver_remove, -}; - -static void serio_add_driver(struct serio_driver *drv) +static void serio_attach_driver(struct serio_driver *drv) { int error; - error = driver_register(&drv->driver); + error = driver_attach(&drv->driver); if (error) - printk(KERN_ERR - "serio: driver_register() failed for %s, error: %d\n", + printk(KERN_WARNING + "serio: driver_attach() failed for %s with error %d\n", drv->driver.name, error); } -void __serio_register_driver(struct serio_driver *drv, struct module *owner) +int serio_register_driver(struct serio_driver *drv) { + int manual_bind = drv->manual_bind; + int error; + drv->driver.bus = &serio_bus; - serio_queue_event(drv, owner, SERIO_REGISTER_DRIVER); + /* + * 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) @@ -947,15 +964,21 @@ irqreturn_t serio_interrupt(struct serio *serio, 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, + .resume = serio_resume, +}; + static int __init serio_init(void) { int error; - serio_bus.dev_attrs = serio_device_attrs; - serio_bus.drv_attrs = serio_driver_attrs; - serio_bus.match = serio_bus_match; - serio_bus.uevent = serio_uevent; - serio_bus.resume = serio_resume; error = bus_register(&serio_bus); if (error) { printk(KERN_ERR "serio: failed to register serio bus, error: %d\n", error); diff --git a/drivers/input/serio/serio_raw.c b/drivers/input/serio/serio_raw.c index 7c8d0399ae8..088ebc348ba 100644 --- a/drivers/input/serio/serio_raw.c +++ b/drivers/input/serio/serio_raw.c @@ -389,8 +389,7 @@ static struct serio_driver serio_raw_drv = { static int __init serio_raw_init(void) { - serio_register_driver(&serio_raw_drv); - return 0; + return serio_register_driver(&serio_raw_drv); } static void __exit serio_raw_exit(void) |