Commit 5b2a0826 authored by Dmitry Torokhov's avatar Dmitry Torokhov
Browse files

Input: rework handle creation code



 - consolidate code for binding handlers to a device
 - return error codes from handlers connect() methods back to input
   core and log failures

Signed-off-by: default avatarDmitry Torokhov <dtor@mail.ru>
parent 6e782584
Loading
Loading
Loading
Loading
+20 −8
Original line number Diff line number Diff line
@@ -41,7 +41,6 @@
#include <linux/input.h>
#include <linux/reboot.h>

static void kbd_disconnect(struct input_handle *handle);
extern void ctrl_alt_del(void);

/*
@@ -1260,11 +1259,11 @@ static void kbd_event(struct input_handle *handle, unsigned int event_type,
 * likes it, it can open it and get events from it. In this (kbd_connect)
 * function, we should decide which VT to bind that keyboard to initially.
 */
static struct input_handle *kbd_connect(struct input_handler *handler,
					struct input_dev *dev,
static int kbd_connect(struct input_handler *handler, struct input_dev *dev,
			const struct input_device_id *id)
{
	struct input_handle *handle;
	int error;
	int i;

	for (i = KEY_RESERVED; i < BTN_MISC; i++)
@@ -1272,24 +1271,37 @@ static struct input_handle *kbd_connect(struct input_handler *handler,
			break;

	if (i == BTN_MISC && !test_bit(EV_SND, dev->evbit))
		return NULL;
		return -ENODEV;

	handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL);
	if (!handle)
		return NULL;
		return -ENOMEM;

	handle->dev = dev;
	handle->handler = handler;
	handle->name = "kbd";

	input_open_device(handle);
	error = input_register_handle(handle);
	if (error)
		goto err_free_handle;

	error = input_open_device(handle);
	if (error)
		goto err_unregister_handle;

	return 0;

	return handle;
 err_unregister_handle:
	input_unregister_handle(handle);
 err_free_handle:
	kfree(handle);
	return error;
}

static void kbd_disconnect(struct input_handle *handle)
{
	input_close_device(handle);
	input_unregister_handle(handle);
	kfree(handle);
}

+22 −10
Original line number Diff line number Diff line
@@ -38,31 +38,43 @@ MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
MODULE_DESCRIPTION("Input driver event debug module");
MODULE_LICENSE("GPL");

static char evbug_name[] = "evbug";

static void evbug_event(struct input_handle *handle, unsigned int type, unsigned int code, int value)
{
	printk(KERN_DEBUG "evbug.c: Event. Dev: %s, Type: %d, Code: %d, Value: %d\n",
		handle->dev->phys, type, code, value);
}

static struct input_handle *evbug_connect(struct input_handler *handler, struct input_dev *dev,
static int evbug_connect(struct input_handler *handler, struct input_dev *dev,
			 const struct input_device_id *id)
{
	struct input_handle *handle;
	int error;

	if (!(handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL)))
		return NULL;
	handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL);
	if (!handle)
		return -ENOMEM;

	handle->dev = dev;
	handle->handler = handler;
	handle->name = evbug_name;
	handle->name = "evbug";

	error = input_register_handle(handle);
	if (error)
		goto err_free_handle;

	input_open_device(handle);
	error = input_open_device(handle);
	if (error)
		goto err_unregister_handle;

	printk(KERN_DEBUG "evbug.c: Connected device: \"%s\", %s\n", dev->name, dev->phys);

	return handle;
	return 0;

 err_unregister_handle:
	input_unregister_handle(handle);
 err_free_handle:
	kfree(handle);
	return error;
}

static void evbug_disconnect(struct input_handle *handle)
@@ -70,7 +82,7 @@ static void evbug_disconnect(struct input_handle *handle)
	printk(KERN_DEBUG "evbug.c: Disconnected device: %s\n", handle->dev->phys);

	input_close_device(handle);

	input_unregister_handle(handle);
	kfree(handle);
}

+36 −11
Original line number Diff line number Diff line
@@ -605,21 +605,24 @@ static const struct file_operations evdev_fops = {
	.flush =	evdev_flush
};

static struct input_handle *evdev_connect(struct input_handler *handler, struct input_dev *dev,
static int evdev_connect(struct input_handler *handler, struct input_dev *dev,
			 const struct input_device_id *id)
{
	struct evdev *evdev;
	struct class_device *cdev;
	dev_t devt;
	int minor;
	int error;

	for (minor = 0; minor < EVDEV_MINORS && evdev_table[minor]; minor++);
	if (minor == EVDEV_MINORS) {
		printk(KERN_ERR "evdev: no more free evdev devices\n");
		return NULL;
		return -ENFILE;
	}

	if (!(evdev = kzalloc(sizeof(struct evdev), GFP_KERNEL)))
		return NULL;
	evdev = kzalloc(sizeof(struct evdev), GFP_KERNEL);
	if (!evdev)
		return -ENOMEM;

	INIT_LIST_HEAD(&evdev->list);
	init_waitqueue_head(&evdev->wait);
@@ -634,15 +637,35 @@ static struct input_handle *evdev_connect(struct input_handler *handler, struct

	evdev_table[minor] = evdev;

	cdev = class_device_create(&input_class, &dev->cdev,
			MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + minor),
	devt = MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + minor),

	cdev = class_device_create(&input_class, &dev->cdev, devt,
				   dev->cdev.dev, evdev->name);
	if (IS_ERR(cdev)) {
		error = PTR_ERR(cdev);
		goto err_free_evdev;
	}

	/* temporary symlink to keep userspace happy */
	sysfs_create_link(&input_class.subsys.kset.kobj, &cdev->kobj,
			  evdev->name);
	error = sysfs_create_link(&input_class.subsys.kset.kobj,
				  &cdev->kobj, evdev->name);
	if (error)
		goto err_cdev_destroy;

	error = input_register_handle(&evdev->handle);
	if (error)
		goto err_remove_link;

	return &evdev->handle;
	return 0;

 err_remove_link:
	sysfs_remove_link(&input_class.subsys.kset.kobj, evdev->name);
 err_cdev_destroy:
	class_device_destroy(&input_class, devt);
 err_free_evdev:
	kfree(evdev);
	evdev_table[minor] = NULL;
	return error;
}

static void evdev_disconnect(struct input_handle *handle)
@@ -650,6 +673,8 @@ static void evdev_disconnect(struct input_handle *handle)
	struct evdev *evdev = handle->private;
	struct evdev_list *list;

	input_unregister_handle(handle);

	sysfs_remove_link(&input_class.subsys.kset.kobj, evdev->name);
	class_device_destroy(&input_class,
			MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + evdev->minor));
+52 −36
Original line number Diff line number Diff line
@@ -380,12 +380,6 @@ static int input_default_setkeycode(struct input_dev *dev,
}


static void input_link_handle(struct input_handle *handle)
{
	list_add_tail(&handle->d_node, &handle->dev->h_list);
	list_add_tail(&handle->h_node, &handle->handler->h_list);
}

#define MATCH_BIT(bit, max) \
		for (i = 0; i < NBITS(max); i++) \
			if ((id->bit[i] & dev->bit[i]) != id->bit[i]) \
@@ -432,6 +426,29 @@ static const struct input_device_id *input_match_device(const struct input_devic
	return NULL;
}

static int input_attach_handler(struct input_dev *dev, struct input_handler *handler)
{
	const struct input_device_id *id;
	int error;

	if (handler->blacklist && input_match_device(handler->blacklist, dev))
		return -ENODEV;

	id = input_match_device(handler->id_table, dev);
	if (!id)
		return -ENODEV;

	error = handler->connect(handler, dev, id);
	if (error && error != -ENODEV)
		printk(KERN_ERR
			"input: failed to attach handler %s to device %s, "
			"error: %d\n",
			handler->name, kobject_name(&dev->cdev.kobj), error);

	return error;
}


#ifdef CONFIG_PROC_FS

static struct proc_dir_entry *proc_bus_input_dir;
@@ -1032,9 +1049,7 @@ EXPORT_SYMBOL(input_free_device);
int input_register_device(struct input_dev *dev)
{
	static atomic_t input_no = ATOMIC_INIT(0);
	struct input_handle *handle;
	struct input_handler *handler;
	const struct input_device_id *id;
	const char *path;
	int error;

@@ -1074,13 +1089,7 @@ int input_register_device(struct input_dev *dev)
	kfree(path);

	list_for_each_entry(handler, &input_handler_list, node)
		if (!handler->blacklist || !input_match_device(handler->blacklist, dev))
			if ((id = input_match_device(handler->id_table, dev)))
				if ((handle = handler->connect(handler, dev, id))) {
					input_link_handle(handle);
					if (handler->start)
						handler->start(handle);
				}
		input_attach_handler(dev, handler);

	input_wakeup_procfs_readers();

@@ -1090,7 +1099,7 @@ EXPORT_SYMBOL(input_register_device);

void input_unregister_device(struct input_dev *dev)
{
	struct list_head *node, *next;
	struct input_handle *handle, *next;
	int code;

	for (code = 0; code <= KEY_MAX; code++)
@@ -1100,12 +1109,9 @@ void input_unregister_device(struct input_dev *dev)

	del_timer_sync(&dev->timer);

	list_for_each_safe(node, next, &dev->h_list) {
		struct input_handle * handle = to_handle(node);
		list_del_init(&handle->d_node);
		list_del_init(&handle->h_node);
	list_for_each_entry_safe(handle, next, &dev->h_list, d_node)
		handle->handler->disconnect(handle);
	}
	WARN_ON(!list_empty(&dev->h_list));

	list_del_init(&dev->node);

@@ -1118,8 +1124,6 @@ EXPORT_SYMBOL(input_unregister_device);
int input_register_handler(struct input_handler *handler)
{
	struct input_dev *dev;
	struct input_handle *handle;
	const struct input_device_id *id;

	INIT_LIST_HEAD(&handler->h_list);

@@ -1133,13 +1137,7 @@ int input_register_handler(struct input_handler *handler)
	list_add_tail(&handler->node, &input_handler_list);

	list_for_each_entry(dev, &input_dev_list, node)
		if (!handler->blacklist || !input_match_device(handler->blacklist, dev))
			if ((id = input_match_device(handler->id_table, dev)))
				if ((handle = handler->connect(handler, dev, id))) {
					input_link_handle(handle);
					if (handler->start)
						handler->start(handle);
				}
		input_attach_handler(dev, handler);

	input_wakeup_procfs_readers();
	return 0;
@@ -1148,14 +1146,11 @@ EXPORT_SYMBOL(input_register_handler);

void input_unregister_handler(struct input_handler *handler)
{
	struct list_head *node, *next;
	struct input_handle *handle, *next;

	list_for_each_safe(node, next, &handler->h_list) {
		struct input_handle * handle = to_handle_h(node);
		list_del_init(&handle->h_node);
		list_del_init(&handle->d_node);
	list_for_each_entry_safe(handle, next, &handler->h_list, h_node)
		handler->disconnect(handle);
	}
	WARN_ON(!list_empty(&handler->h_list));

	list_del_init(&handler->node);

@@ -1166,6 +1161,27 @@ void input_unregister_handler(struct input_handler *handler)
}
EXPORT_SYMBOL(input_unregister_handler);

int input_register_handle(struct input_handle *handle)
{
	struct input_handler *handler = handle->handler;

	list_add_tail(&handle->d_node, &handle->dev->h_list);
	list_add_tail(&handle->h_node, &handler->h_list);

	if (handler->start)
		handler->start(handle);

	return 0;
}
EXPORT_SYMBOL(input_register_handle);

void input_unregister_handle(struct input_handle *handle)
{
	list_del_init(&handle->h_node);
	list_del_init(&handle->d_node);
}
EXPORT_SYMBOL(input_unregister_handle);

static int input_open_file(struct inode *inode, struct file *file)
{
	struct input_handler *handler = input_table[iminor(inode) >> 5];
+37 −11
Original line number Diff line number Diff line
@@ -465,21 +465,24 @@ static const struct file_operations joydev_fops = {
	.fasync =	joydev_fasync,
};

static struct input_handle *joydev_connect(struct input_handler *handler, struct input_dev *dev,
static int joydev_connect(struct input_handler *handler, struct input_dev *dev,
			  const struct input_device_id *id)
{
	struct joydev *joydev;
	struct class_device *cdev;
	dev_t devt;
	int i, j, t, minor;
	int error;

	for (minor = 0; minor < JOYDEV_MINORS && joydev_table[minor]; minor++);
	if (minor == JOYDEV_MINORS) {
		printk(KERN_ERR "joydev: no more free joydev devices\n");
		return NULL;
		return -ENFILE;
	}

	if (!(joydev = kzalloc(sizeof(struct joydev), GFP_KERNEL)))
		return NULL;
	joydev = kzalloc(sizeof(struct joydev), GFP_KERNEL);
	if (!joydev)
		return -ENOMEM;

	INIT_LIST_HEAD(&joydev->list);
	init_waitqueue_head(&joydev->wait);
@@ -534,22 +537,45 @@ static struct input_handle *joydev_connect(struct input_handler *handler, struct

	joydev_table[minor] = joydev;

	cdev = class_device_create(&input_class, &dev->cdev,
			MKDEV(INPUT_MAJOR, JOYDEV_MINOR_BASE + minor),
	devt = MKDEV(INPUT_MAJOR, JOYDEV_MINOR_BASE + minor),

	cdev = class_device_create(&input_class, &dev->cdev, devt,
				   dev->cdev.dev, joydev->name);
	if (IS_ERR(cdev)) {
		error = PTR_ERR(cdev);
		goto err_free_joydev;
	}

	/* temporary symlink to keep userspace happy */
	sysfs_create_link(&input_class.subsys.kset.kobj, &cdev->kobj,
			  joydev->name);
	error = sysfs_create_link(&input_class.subsys.kset.kobj,
				  &cdev->kobj, joydev->name);
	if (error)
		goto err_cdev_destroy;

	error = input_register_handle(&joydev->handle);
	if (error)
		goto err_remove_link;

	return 0;

	return &joydev->handle;
 err_remove_link:
	sysfs_remove_link(&input_class.subsys.kset.kobj, joydev->name);
 err_cdev_destroy:
	class_device_destroy(&input_class, devt);
 err_free_joydev:
	joydev_table[minor] = NULL;
	kfree(joydev);
	return error;
}


static void joydev_disconnect(struct input_handle *handle)
{
	struct joydev *joydev = handle->private;
	struct joydev_list *list;

	input_unregister_handle(handle);

	sysfs_remove_link(&input_class.subsys.kset.kobj, joydev->name);
	class_device_destroy(&input_class, MKDEV(INPUT_MAJOR, JOYDEV_MINOR_BASE + joydev->minor));
	joydev->exist = 0;
Loading