Input: serio - make serio_register_driver() return errors

Perform actual driver registration right in serio_register_driver()
instead of offloading it to kseriod and return proper error code to
callers if driver registration fails.

Note that driver <-> port matching is still done by kseriod to
speed up boot process since probing for PS/2 mice and keyboards
is pretty slow.

Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
This commit is contained in:
Dmitry Torokhov
2006-11-23 23:34:49 -05:00
parent 9d92fe17b6
commit ed7b1f6d6e
2 changed files with 76 additions and 40 deletions

View File

@@ -44,7 +44,7 @@ EXPORT_SYMBOL(serio_interrupt);
EXPORT_SYMBOL(__serio_register_port); EXPORT_SYMBOL(__serio_register_port);
EXPORT_SYMBOL(serio_unregister_port); EXPORT_SYMBOL(serio_unregister_port);
EXPORT_SYMBOL(serio_unregister_child_port); EXPORT_SYMBOL(serio_unregister_child_port);
EXPORT_SYMBOL(__serio_register_driver); EXPORT_SYMBOL(serio_register_driver);
EXPORT_SYMBOL(serio_unregister_driver); EXPORT_SYMBOL(serio_unregister_driver);
EXPORT_SYMBOL(serio_open); EXPORT_SYMBOL(serio_open);
EXPORT_SYMBOL(serio_close); EXPORT_SYMBOL(serio_close);
@@ -61,10 +61,10 @@ static LIST_HEAD(serio_list);
static struct bus_type serio_bus; 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_add_port(struct serio *serio);
static void serio_reconnect_port(struct serio *serio); static void serio_reconnect_port(struct serio *serio);
static void serio_disconnect_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) static int serio_connect_driver(struct serio *serio, struct serio_driver *drv)
{ {
@@ -168,10 +168,10 @@ static void serio_find_driver(struct serio *serio)
*/ */
enum serio_event_type { enum serio_event_type {
SERIO_RESCAN, SERIO_RESCAN_PORT,
SERIO_RECONNECT, SERIO_RECONNECT_PORT,
SERIO_REGISTER_PORT, SERIO_REGISTER_PORT,
SERIO_REGISTER_DRIVER, SERIO_ATTACH_DRIVER,
}; };
struct serio_event { struct serio_event {
@@ -186,11 +186,12 @@ static LIST_HEAD(serio_event_list);
static DECLARE_WAIT_QUEUE_HEAD(serio_wait); static DECLARE_WAIT_QUEUE_HEAD(serio_wait);
static struct task_struct *serio_task; static struct task_struct *serio_task;
static void serio_queue_event(void *object, struct module *owner, static int serio_queue_event(void *object, struct module *owner,
enum serio_event_type event_type) enum serio_event_type event_type)
{ {
unsigned long flags; unsigned long flags;
struct serio_event *event; struct serio_event *event;
int retval = 0;
spin_lock_irqsave(&serio_event_lock, flags); spin_lock_irqsave(&serio_event_lock, flags);
@@ -209,24 +210,34 @@ static void serio_queue_event(void *object, struct module *owner,
} }
} }
if ((event = kmalloc(sizeof(struct serio_event), GFP_ATOMIC))) { event = kmalloc(sizeof(struct serio_event), GFP_ATOMIC);
if (!try_module_get(owner)) { if (!event) {
printk(KERN_WARNING "serio: Can't get module reference, dropping event %d\n", event_type); printk(KERN_ERR
kfree(event); "serio: Not enough memory to queue event %d\n",
goto out; event_type);
} retval = -ENOMEM;
goto out;
event->type = event_type;
event->object = object;
event->owner = owner;
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: out:
spin_unlock_irqrestore(&serio_event_lock, flags); spin_unlock_irqrestore(&serio_event_lock, flags);
return retval;
} }
static void serio_free_event(struct serio_event *event) static void serio_free_event(struct serio_event *event)
@@ -304,17 +315,17 @@ static void serio_handle_event(void)
serio_add_port(event->object); serio_add_port(event->object);
break; break;
case SERIO_RECONNECT: case SERIO_RECONNECT_PORT:
serio_reconnect_port(event->object); serio_reconnect_port(event->object);
break; break;
case SERIO_RESCAN: case SERIO_RESCAN_PORT:
serio_disconnect_port(event->object); serio_disconnect_port(event->object);
serio_find_driver(event->object); serio_find_driver(event->object);
break; break;
case SERIO_REGISTER_DRIVER: case SERIO_ATTACH_DRIVER:
serio_add_driver(event->object); serio_attach_driver(event->object);
break; break;
default: default:
@@ -666,12 +677,12 @@ static void serio_disconnect_port(struct serio *serio)
void serio_rescan(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) void serio_reconnect(struct serio *serio)
{ {
serio_queue_event(serio, NULL, SERIO_RECONNECT); serio_queue_event(serio, NULL, SERIO_RECONNECT_PORT);
} }
/* /*
@@ -766,22 +777,52 @@ static int serio_driver_remove(struct device *dev)
return 0; return 0;
} }
static void serio_add_driver(struct serio_driver *drv) static void serio_attach_driver(struct serio_driver *drv)
{ {
int error; int error;
error = driver_register(&drv->driver); error = driver_attach(&drv->driver);
if (error) if (error)
printk(KERN_ERR printk(KERN_WARNING
"serio: driver_register() failed for %s, error: %d\n", "serio: driver_attach() failed for %s with error %d\n",
drv->driver.name, error); 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; 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) void serio_unregister_driver(struct serio_driver *drv)

View File

@@ -86,12 +86,7 @@ static inline void serio_register_port(struct serio *serio)
void serio_unregister_port(struct serio *serio); void serio_unregister_port(struct serio *serio);
void serio_unregister_child_port(struct serio *serio); void serio_unregister_child_port(struct serio *serio);
void __serio_register_driver(struct serio_driver *drv, struct module *owner); int serio_register_driver(struct serio_driver *drv);
static inline void serio_register_driver(struct serio_driver *drv)
{
__serio_register_driver(drv, THIS_MODULE);
}
void serio_unregister_driver(struct serio_driver *drv); void serio_unregister_driver(struct serio_driver *drv);
static inline int serio_write(struct serio *serio, unsigned char data) static inline int serio_write(struct serio *serio, unsigned char data)