Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ed7b1f6d authored by Dmitry Torokhov's avatar Dmitry Torokhov
Browse files

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: default avatarDmitry Torokhov <dtor@mail.ru>
parent 9d92fe17
Loading
Loading
Loading
Loading
+74 −33
Original line number Original line Diff line number Diff line
@@ -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,10 +210,21 @@ 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 (!event) {
		printk(KERN_ERR
			"serio: Not enough memory to queue event %d\n",
			event_type);
		retval = -ENOMEM;
		goto out;
	}

	if (!try_module_get(owner)) {
	if (!try_module_get(owner)) {
			printk(KERN_WARNING "serio: Can't get module reference, dropping event %d\n", event_type);
		printk(KERN_WARNING
			"serio: Can't get module reference, dropping event %d\n",
			event_type);
		kfree(event);
		kfree(event);
		retval = -EINVAL;
		goto out;
		goto out;
	}
	}


@@ -222,11 +234,10 @@ static void serio_queue_event(void *object, struct module *owner,


	list_add_tail(&event->node, &serio_event_list);
	list_add_tail(&event->node, &serio_event_list);
	wake_up(&serio_wait);
	wake_up(&serio_wait);
	} else {

		printk(KERN_ERR "serio: Not enough memory to queue event %d\n", event_type);
	}
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)
+1 −6
Original line number Original line Diff line number Diff line
@@ -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)