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

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
...@@ -41,7 +41,6 @@ ...@@ -41,7 +41,6 @@
#include <linux/input.h> #include <linux/input.h>
#include <linux/reboot.h> #include <linux/reboot.h>
static void kbd_disconnect(struct input_handle *handle);
extern void ctrl_alt_del(void); extern void ctrl_alt_del(void);
/* /*
...@@ -1260,11 +1259,11 @@ static void kbd_event(struct input_handle *handle, unsigned int event_type, ...@@ -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) * 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. * function, we should decide which VT to bind that keyboard to initially.
*/ */
static struct input_handle *kbd_connect(struct input_handler *handler, static int kbd_connect(struct input_handler *handler, struct input_dev *dev,
struct input_dev *dev, const struct input_device_id *id)
const struct input_device_id *id)
{ {
struct input_handle *handle; struct input_handle *handle;
int error;
int i; int i;
for (i = KEY_RESERVED; i < BTN_MISC; i++) for (i = KEY_RESERVED; i < BTN_MISC; i++)
...@@ -1272,24 +1271,37 @@ static struct input_handle *kbd_connect(struct input_handler *handler, ...@@ -1272,24 +1271,37 @@ static struct input_handle *kbd_connect(struct input_handler *handler,
break; break;
if (i == BTN_MISC && !test_bit(EV_SND, dev->evbit)) if (i == BTN_MISC && !test_bit(EV_SND, dev->evbit))
return NULL; return -ENODEV;
handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL); handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL);
if (!handle) if (!handle)
return NULL; return -ENOMEM;
handle->dev = dev; handle->dev = dev;
handle->handler = handler; handle->handler = handler;
handle->name = "kbd"; 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) static void kbd_disconnect(struct input_handle *handle)
{ {
input_close_device(handle); input_close_device(handle);
input_unregister_handle(handle);
kfree(handle); kfree(handle);
} }
......
...@@ -38,31 +38,43 @@ MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); ...@@ -38,31 +38,43 @@ MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
MODULE_DESCRIPTION("Input driver event debug module"); MODULE_DESCRIPTION("Input driver event debug module");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
static char evbug_name[] = "evbug";
static void evbug_event(struct input_handle *handle, unsigned int type, unsigned int code, int value) 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", printk(KERN_DEBUG "evbug.c: Event. Dev: %s, Type: %d, Code: %d, Value: %d\n",
handle->dev->phys, type, code, value); 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) const struct input_device_id *id)
{ {
struct input_handle *handle; struct input_handle *handle;
int error;
if (!(handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL))) handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL);
return NULL; if (!handle)
return -ENOMEM;
handle->dev = dev; handle->dev = dev;
handle->handler = handler; 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); 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) static void evbug_disconnect(struct input_handle *handle)
...@@ -70,7 +82,7 @@ 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); printk(KERN_DEBUG "evbug.c: Disconnected device: %s\n", handle->dev->phys);
input_close_device(handle); input_close_device(handle);
input_unregister_handle(handle);
kfree(handle); kfree(handle);
} }
......
...@@ -605,21 +605,24 @@ static const struct file_operations evdev_fops = { ...@@ -605,21 +605,24 @@ static const struct file_operations evdev_fops = {
.flush = evdev_flush .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) const struct input_device_id *id)
{ {
struct evdev *evdev; struct evdev *evdev;
struct class_device *cdev; struct class_device *cdev;
dev_t devt;
int minor; int minor;
int error;
for (minor = 0; minor < EVDEV_MINORS && evdev_table[minor]; minor++); for (minor = 0; minor < EVDEV_MINORS && evdev_table[minor]; minor++);
if (minor == EVDEV_MINORS) { if (minor == EVDEV_MINORS) {
printk(KERN_ERR "evdev: no more free evdev devices\n"); printk(KERN_ERR "evdev: no more free evdev devices\n");
return NULL; return -ENFILE;
} }
if (!(evdev = kzalloc(sizeof(struct evdev), GFP_KERNEL))) evdev = kzalloc(sizeof(struct evdev), GFP_KERNEL);
return NULL; if (!evdev)
return -ENOMEM;
INIT_LIST_HEAD(&evdev->list); INIT_LIST_HEAD(&evdev->list);
init_waitqueue_head(&evdev->wait); init_waitqueue_head(&evdev->wait);
...@@ -634,15 +637,35 @@ static struct input_handle *evdev_connect(struct input_handler *handler, struct ...@@ -634,15 +637,35 @@ static struct input_handle *evdev_connect(struct input_handler *handler, struct
evdev_table[minor] = evdev; evdev_table[minor] = evdev;
cdev = class_device_create(&input_class, &dev->cdev, devt = MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + minor),
MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + minor),
dev->cdev.dev, evdev->name); 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 */ /* temporary symlink to keep userspace happy */
sysfs_create_link(&input_class.subsys.kset.kobj, &cdev->kobj, error = sysfs_create_link(&input_class.subsys.kset.kobj,
evdev->name); &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) static void evdev_disconnect(struct input_handle *handle)
...@@ -650,6 +673,8 @@ 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 *evdev = handle->private;
struct evdev_list *list; struct evdev_list *list;
input_unregister_handle(handle);
sysfs_remove_link(&input_class.subsys.kset.kobj, evdev->name); sysfs_remove_link(&input_class.subsys.kset.kobj, evdev->name);
class_device_destroy(&input_class, class_device_destroy(&input_class,
MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + evdev->minor)); MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + evdev->minor));
......
...@@ -380,12 +380,6 @@ static int input_default_setkeycode(struct input_dev *dev, ...@@ -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) \ #define MATCH_BIT(bit, max) \
for (i = 0; i < NBITS(max); i++) \ for (i = 0; i < NBITS(max); i++) \
if ((id->bit[i] & dev->bit[i]) != id->bit[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 ...@@ -432,6 +426,29 @@ static const struct input_device_id *input_match_device(const struct input_devic
return NULL; 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 #ifdef CONFIG_PROC_FS
static struct proc_dir_entry *proc_bus_input_dir; static struct proc_dir_entry *proc_bus_input_dir;
...@@ -1032,9 +1049,7 @@ EXPORT_SYMBOL(input_free_device); ...@@ -1032,9 +1049,7 @@ EXPORT_SYMBOL(input_free_device);
int input_register_device(struct input_dev *dev) int input_register_device(struct input_dev *dev)
{ {
static atomic_t input_no = ATOMIC_INIT(0); static atomic_t input_no = ATOMIC_INIT(0);
struct input_handle *handle;
struct input_handler *handler; struct input_handler *handler;
const struct input_device_id *id;
const char *path; const char *path;
int error; int error;
...@@ -1074,13 +1089,7 @@ int input_register_device(struct input_dev *dev) ...@@ -1074,13 +1089,7 @@ int input_register_device(struct input_dev *dev)
kfree(path); kfree(path);
list_for_each_entry(handler, &input_handler_list, node) list_for_each_entry(handler, &input_handler_list, node)
if (!handler->blacklist || !input_match_device(handler->blacklist, dev)) input_attach_handler(dev, handler);
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_wakeup_procfs_readers(); input_wakeup_procfs_readers();
...@@ -1090,7 +1099,7 @@ EXPORT_SYMBOL(input_register_device); ...@@ -1090,7 +1099,7 @@ EXPORT_SYMBOL(input_register_device);
void input_unregister_device(struct input_dev *dev) void input_unregister_device(struct input_dev *dev)
{ {
struct list_head *node, *next; struct input_handle *handle, *next;
int code; int code;
for (code = 0; code <= KEY_MAX; code++) for (code = 0; code <= KEY_MAX; code++)
...@@ -1100,12 +1109,9 @@ void input_unregister_device(struct input_dev *dev) ...@@ -1100,12 +1109,9 @@ void input_unregister_device(struct input_dev *dev)
del_timer_sync(&dev->timer); del_timer_sync(&dev->timer);
list_for_each_safe(node, next, &dev->h_list) { list_for_each_entry_safe(handle, next, &dev->h_list, d_node)
struct input_handle * handle = to_handle(node);
list_del_init(&handle->d_node);
list_del_init(&handle->h_node);
handle->handler->disconnect(handle); handle->handler->disconnect(handle);
} WARN_ON(!list_empty(&dev->h_list));
list_del_init(&dev->node); list_del_init(&dev->node);
...@@ -1118,8 +1124,6 @@ EXPORT_SYMBOL(input_unregister_device); ...@@ -1118,8 +1124,6 @@ EXPORT_SYMBOL(input_unregister_device);
int input_register_handler(struct input_handler *handler) int input_register_handler(struct input_handler *handler)
{ {
struct input_dev *dev; struct input_dev *dev;
struct input_handle *handle;
const struct input_device_id *id;
INIT_LIST_HEAD(&handler->h_list); INIT_LIST_HEAD(&handler->h_list);
...@@ -1133,13 +1137,7 @@ int input_register_handler(struct input_handler *handler) ...@@ -1133,13 +1137,7 @@ int input_register_handler(struct input_handler *handler)
list_add_tail(&handler->node, &input_handler_list); list_add_tail(&handler->node, &input_handler_list);
list_for_each_entry(dev, &input_dev_list, node) list_for_each_entry(dev, &input_dev_list, node)
if (!handler->blacklist || !input_match_device(handler->blacklist, dev)) input_attach_handler(dev, handler);
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_wakeup_procfs_readers(); input_wakeup_procfs_readers();
return 0; return 0;
...@@ -1148,14 +1146,11 @@ EXPORT_SYMBOL(input_register_handler); ...@@ -1148,14 +1146,11 @@ EXPORT_SYMBOL(input_register_handler);
void input_unregister_handler(struct input_handler *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) { list_for_each_entry_safe(handle, next, &handler->h_list, h_node)
struct input_handle * handle = to_handle_h(node);
list_del_init(&handle->h_node);
list_del_init(&handle->d_node);
handler->disconnect(handle); handler->disconnect(handle);
} WARN_ON(!list_empty(&handler->h_list));
list_del_init(&handler->node); list_del_init(&handler->node);
...@@ -1166,6 +1161,27 @@ void input_unregister_handler(struct input_handler *handler) ...@@ -1166,6 +1161,27 @@ void input_unregister_handler(struct input_handler *handler)
} }
EXPORT_SYMBOL(input_unregister_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) static int input_open_file(struct inode *inode, struct file *file)
{ {
struct input_handler *handler = input_table[iminor(inode) >> 5]; struct input_handler *handler = input_table[iminor(inode) >> 5];
......
...@@ -465,21 +465,24 @@ static const struct file_operations joydev_fops = { ...@@ -465,21 +465,24 @@ static const struct file_operations joydev_fops = {
.fasync = joydev_fasync, .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) const struct input_device_id *id)
{ {
struct joydev *joydev; struct joydev *joydev;
struct class_device *cdev; struct class_device *cdev;
dev_t devt;
int i, j, t, minor; int i, j, t, minor;
int error;
for (minor = 0; minor < JOYDEV_MINORS && joydev_table[minor]; minor++); for (minor = 0; minor < JOYDEV_MINORS && joydev_table[minor]; minor++);
if (minor == JOYDEV_MINORS) { if (minor == JOYDEV_MINORS) {
printk(KERN_ERR "joydev: no more free joydev devices\n"); printk(KERN_ERR "joydev: no more free joydev devices\n");
return NULL; return -ENFILE;
} }
if (!(joydev = kzalloc(sizeof(struct joydev), GFP_KERNEL))) joydev = kzalloc(sizeof(struct joydev), GFP_KERNEL);
return NULL; if (!joydev)
return -ENOMEM;
INIT_LIST_HEAD(&joydev->list); INIT_LIST_HEAD(&joydev->list);
init_waitqueue_head(&joydev->wait); init_waitqueue_head(&joydev->wait);
...@@ -534,22 +537,45 @@ static struct input_handle *joydev_connect(struct input_handler *handler, struct ...@@ -534,22 +537,45 @@ static struct input_handle *joydev_connect(struct input_handler *handler, struct
joydev_table[minor] = joydev; joydev_table[minor] = joydev;
cdev = class_device_create(&input_class, &dev->cdev, devt = MKDEV(INPUT_MAJOR, JOYDEV_MINOR_BASE + minor),
MKDEV(INPUT_MAJOR, JOYDEV_MINOR_BASE + minor),
dev->cdev.dev, joydev->name); 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 */ /* temporary symlink to keep userspace happy */
sysfs_create_link(&input_class.subsys.kset.kobj, &cdev->kobj, error = sysfs_create_link(&input_class.subsys.kset.kobj,
joydev->name); &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) static void joydev_disconnect(struct input_handle *handle)
{ {
struct joydev *joydev = handle->private; struct joydev *joydev = handle->private;
struct joydev_list *list; struct joydev_list *list;
input_unregister_handle(handle);
sysfs_remove_link(&input_class.subsys.kset.kobj, joydev->name); sysfs_remove_link(&input_class.subsys.kset.kobj, joydev->name);
class_device_destroy(&input_class, MKDEV(INPUT_MAJOR, JOYDEV_MINOR_BASE + joydev->minor)); class_device_destroy(&input_class, MKDEV(INPUT_MAJOR, JOYDEV_MINOR_BASE + joydev->minor));
joydev->exist = 0; joydev->exist = 0;
......
...@@ -624,23 +624,27 @@ static const struct file_operations mousedev_fops = { ...@@ -624,23 +624,27 @@ static const struct file_operations mousedev_fops = {
.fasync = mousedev_fasync, .fasync = mousedev_fasync,
}; };
static struct input_handle *mousedev_connect(struct input_handler *handler, struct input_dev *dev, static int mousedev_connect(struct input_handler *handler, struct input_dev *dev,
const struct input_device_id *id) const struct input_device_id *id)
{ {
struct mousedev *mousedev; struct mousedev *mousedev;
struct class_device *cdev; struct class_device *cdev;
int minor = 0; dev_t devt;
int minor;
int error;
for (minor = 0; minor < MOUSEDEV_MINORS && mousedev_table[minor]; minor++); for (minor = 0; minor < MOUSEDEV_MINORS && mousedev_table[minor]; minor++);
if (minor == MOUSEDEV_MINORS) { if (minor == MOUSEDEV_MINORS) {
printk(KERN_ERR "mousedev: no more free mousedev devices\n"); printk(KERN_ERR "mousedev: no more free mousedev devices\n");
return NULL; return -ENFILE;
} }
if (!(mousedev = kzalloc(sizeof(struct mousedev), GFP_KERNEL))) mousedev = kzalloc(sizeof(struct mousedev), GFP_KERNEL);
return NULL; if (!mousedev)
return -ENOMEM;
INIT_LIST_HEAD(&mousedev->list); INIT_LIST_HEAD(&mousedev->list);
INIT_LIST_HEAD(&mousedev->mixdev_node);
init_waitqueue_head(&mousedev->wait); init_waitqueue_head(&mousedev->wait);
mousedev->minor = minor; mousedev->minor = minor;
...@@ -651,20 +655,45 @@ static struct input_handle *mousedev_connect(struct input_handler *handler, stru ...@@ -651,20 +655,45 @@ static struct input_handle *mousedev_connect(struct input_handler *handler, stru
mousedev->handle.private = mousedev; mousedev->handle.private = mousedev;
sprintf(mousedev->name, "mouse%d", minor); sprintf(mousedev->name, "mouse%d", minor);
if (mousedev_mix.open)
input_open_device(&mousedev->handle);
mousedev_table[minor] = mousedev; mousedev_table[minor] = mousedev;
cdev = class_device_create(&input_class, &dev->cdev, devt = MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + minor),
MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + minor),
dev->cdev.dev, mousedev->name); cdev = class_device_create(&input_class, &dev->cdev, devt,
dev->cdev.dev, mousedev->name);
if (IS_ERR(cdev)) {
error = PTR_ERR(cdev);
goto err_free_mousedev;
}
/* temporary symlink to keep userspace happy */ /* temporary symlink to keep userspace happy */
sysfs_create_link(&input_class.subsys.kset.kobj, &cdev->kobj, error = sysfs_create_link(&input_class.subsys.kset.kobj,
mousedev->name); &cdev->kobj, mousedev->name);
if (error)
goto err_cdev_destroy;
return &mousedev->handle; error = input_register_handle(&mousedev->handle);
if (error)
goto err_remove_link;
if (mousedev_mix.open) {
error = input_open_device(&mousedev->handle);
if (error)
goto err_unregister_handle;
}
return 0;
err_unregister_handle:
input_unregister_handle(&mousedev->handle);
err_remove_link:
sysfs_remove_link(&input_class.subsys.kset.kobj, mousedev->name);
err_cdev_destroy:
class_device_destroy(&input_class, devt);
err_free_mousedev:
mousedev_table[minor] = NULL;
kfree(mousedev);
return error;
} }
static void mousedev_disconnect(struct input_handle *handle) static void mousedev_disconnect(struct input_handle *handle)
...@@ -672,6 +701,8 @@ static void mousedev_disconnect(struct input_handle *handle) ...@@ -672,6 +701,8 @@ static void mousedev_disconnect(struct input_handle *handle)
struct mousedev *mousedev = handle->private; struct mousedev *mousedev = handle->private;
struct mousedev_list *list; struct mousedev_list *list;
input_unregister_handle(handle);
sysfs_remove_link(&input_class.subsys.kset.kobj, mousedev->name); sysfs_remove_link(&input_class.subsys.kset.kobj, mousedev->name);
class_device_destroy(&input_class, class_device_destroy(&input_class,
MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + mousedev->minor)); MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + mousedev->minor));
......
...@@ -41,14 +41,14 @@ static struct input_handler power_handler; ...@@ -41,14 +41,14 @@ static struct input_handler power_handler;
* Power management can't be done in a interrupt context. So we have to * Power management can't be done in a interrupt context. So we have to
* use keventd. * use keventd.
*/ */
static int suspend_button_pushed = 0; static int suspend_button_pushed;
static void suspend_button_task_handler(void *data) static void suspend_button_task_handler(struct work_struct *work)
{ {
udelay(200); /* debounce */ udelay(200); /* debounce */
suspend_button_pushed = 0; suspend_button_pushed = 0;
} }
static DECLARE_WORK(suspend_button_task, suspend_button_task_handler, NULL); static DECLARE_WORK(suspend_button_task, suspend_button_task_handler);
static void power_event(struct input_handle *handle, unsigned int type, static void power_event(struct input_handle *handle, unsigned int type,
unsigned int code, int down) unsigned int code, int down)
...@@ -63,9 +63,9 @@ static void power_event(struct input_handle *handle, unsigned int type, ...@@ -63,9 +63,9 @@ static void power_event(struct input_handle *handle, unsigned int type,
printk("Powering down entire device\n"); printk("Powering down entire device\n");
if (!suspend_button_pushed) { if (!suspend_button_pushed) {
suspend_button_pushed = 1; suspend_button_pushed = 1;
schedule_work(&suspend_button_task); schedule_work(&suspend_button_task);
} }
break; break;
case KEY_POWER: case KEY_POWER:
/* Hum power down the machine. */ /* Hum power down the machine. */
...@@ -84,7 +84,7 @@ static void power_event(struct input_handle *handle, unsigned int type, ...@@ -84,7 +84,7 @@ static void power_event(struct input_handle *handle, unsigned int type,
dev->state = PM_RESUME; dev->state = PM_RESUME;
else else
dev->state = PM_SUSPEND; dev->state = PM_SUSPEND;
pm_send(dev->pm_dev, dev->state, dev); /* pm_send(dev->pm_dev, dev->state, dev); */
break; break;
case KEY_POWER: case KEY_POWER:
/* Turn the input device off completely ? */ /* Turn the input device off completely ? */
...@@ -96,27 +96,41 @@ static void power_event(struct input_handle *handle, unsigned int type, ...@@ -96,27 +96,41 @@ static void power_event(struct input_handle *handle, unsigned int type,
return; return;
} }
static struct input_handle *power_connect(struct input_handler *handler, static int power_connect(struct input_handler *handler, struct input_dev *dev,
struct input_dev *dev, const struct input_device_id *id)
const struct input_device_id *id)
{ {
struct input_handle *handle; struct input_handle *handle;
int error;
if (!(handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL))) handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL);
return NULL; if (!handle)
return -ENOMEM;
handle->dev = dev; handle->dev = dev;
handle->handler = handler; handle->handler = handler;
handle->name = "power";
input_open_device(handle); error = input_register_handle(handle);
if (error)
goto err_free_handle;
printk(KERN_INFO "power.c: Adding power management to input layer\n"); error = input_open_device(handle);
return handle; if (error)
goto err_unregister_handle;
return 0;
err_unregister_handle:
input_unregister_handle(handle);
err_free_handle:
kfree(handle);
return error;
} }
static void power_disconnect(struct input_handle *handle) static void power_disconnect(struct input_handle *handle)
{ {
input_close_device(handle); input_close_device(handle);
input_unregister_handle(handle);
kfree(handle); kfree(handle);
} }
...@@ -135,7 +149,7 @@ static const struct input_device_id power_ids[] = { ...@@ -135,7 +149,7 @@ static const struct input_device_id power_ids[] = {
.flags = INPUT_DEVICE_ID_MATCH_EVBIT, .flags = INPUT_DEVICE_ID_MATCH_EVBIT,
.evbit = { BIT(EV_PWR) }, .evbit = { BIT(EV_PWR) },
}, },
{ }, /* Terminating entry */ { }, /* Terminating entry */
}; };
MODULE_DEVICE_TABLE(input, power_ids); MODULE_DEVICE_TABLE(input, power_ids);
......
...@@ -155,7 +155,7 @@ static int tsdev_open(struct inode *inode, struct file *file) ...@@ -155,7 +155,7 @@ static int tsdev_open(struct inode *inode, struct file *file)
"for removal.\nSee Documentation/feature-removal-schedule.txt " "for removal.\nSee Documentation/feature-removal-schedule.txt "
"for details.\n"); "for details.\n");
if (i >= TSDEV_MINORS || !tsdev_table[i & TSDEV_MINOR_MASK]) if (i >= TSDEV_MINORS)
return -ENODEV; return -ENODEV;
if (!(list = kzalloc(sizeof(struct tsdev_list), GFP_KERNEL))) if (!(list = kzalloc(sizeof(struct tsdev_list), GFP_KERNEL)))
...@@ -246,14 +246,14 @@ static int tsdev_ioctl(struct inode *inode, struct file *file, ...@@ -246,14 +246,14 @@ static int tsdev_ioctl(struct inode *inode, struct file *file,
switch (cmd) { switch (cmd) {
case TS_GET_CAL: case TS_GET_CAL:
if (copy_to_user ((void __user *)arg, &tsdev->cal, if (copy_to_user((void __user *)arg, &tsdev->cal,
sizeof (struct ts_calibration))) sizeof (struct ts_calibration)))
retval = -EFAULT; retval = -EFAULT;
break; break;
case TS_SET_CAL: case TS_SET_CAL:
if (copy_from_user (&tsdev->cal, (void __user *)arg, if (copy_from_user(&tsdev->cal, (void __user *)arg,
sizeof (struct ts_calibration))) sizeof (struct ts_calibration)))
retval = -EFAULT; retval = -EFAULT;
break; break;
...@@ -370,23 +370,25 @@ static void tsdev_event(struct input_handle *handle, unsigned int type, ...@@ -370,23 +370,25 @@ static void tsdev_event(struct input_handle *handle, unsigned int type,
wake_up_interruptible(&tsdev->wait); wake_up_interruptible(&tsdev->wait);
} }
static struct input_handle *tsdev_connect(struct input_handler *handler, static int tsdev_connect(struct input_handler *handler, struct input_dev *dev,
struct input_dev *dev, const struct input_device_id *id)
const struct input_device_id *id)
{ {
struct tsdev *tsdev; struct tsdev *tsdev;
struct class_device *cdev; struct class_device *cdev;
dev_t devt;
int minor, delta; int minor, delta;
int error;
for (minor = 0; minor < TSDEV_MINORS / 2 && tsdev_table[minor]; minor++); for (minor = 0; minor < TSDEV_MINORS / 2 && tsdev_table[minor]; minor++);
if (minor >= TSDEV_MINORS / 2) { if (minor >= TSDEV_MINORS / 2) {
printk(KERN_ERR printk(KERN_ERR
"tsdev: You have way too many touchscreens\n"); "tsdev: You have way too many touchscreens\n");
return NULL; return -ENFILE;
} }
if (!(tsdev = kzalloc(sizeof(struct tsdev), GFP_KERNEL))) tsdev = kzalloc(sizeof(struct tsdev), GFP_KERNEL);
return NULL; if (!tsdev)
return -ENOMEM;
INIT_LIST_HEAD(&tsdev->list); INIT_LIST_HEAD(&tsdev->list);
init_waitqueue_head(&tsdev->wait); init_waitqueue_head(&tsdev->wait);
...@@ -415,15 +417,35 @@ static struct input_handle *tsdev_connect(struct input_handler *handler, ...@@ -415,15 +417,35 @@ static struct input_handle *tsdev_connect(struct input_handler *handler,
tsdev_table[minor] = tsdev; tsdev_table[minor] = tsdev;
cdev = class_device_create(&input_class, &dev->cdev, devt = MKDEV(INPUT_MAJOR, TSDEV_MINOR_BASE + minor),
MKDEV(INPUT_MAJOR, TSDEV_MINOR_BASE + minor),
dev->cdev.dev, tsdev->name); cdev = class_device_create(&input_class, &dev->cdev, devt,
dev->cdev.dev, tsdev->name);
if (IS_ERR(cdev)) {
error = PTR_ERR(cdev);
goto err_free_tsdev;
}
/* temporary symlink to keep userspace happy */ /* temporary symlink to keep userspace happy */
sysfs_create_link(&input_class.subsys.kset.kobj, &cdev->kobj, error = sysfs_create_link(&input_class.subsys.kset.kobj,
tsdev->name); &cdev->kobj, tsdev->name);
if (error)
goto err_cdev_destroy;
return &tsdev->handle; error = input_register_handle(&tsdev->handle);
if (error)
goto err_remove_link;
return 0;
err_remove_link:
sysfs_remove_link(&input_class.subsys.kset.kobj, tsdev->name);
err_cdev_destroy:
class_device_destroy(&input_class, devt);
err_free_tsdev:
tsdev_table[minor] = NULL;
kfree(tsdev);
return error;
} }
static void tsdev_disconnect(struct input_handle *handle) static void tsdev_disconnect(struct input_handle *handle)
...@@ -431,6 +453,8 @@ static void tsdev_disconnect(struct input_handle *handle) ...@@ -431,6 +453,8 @@ static void tsdev_disconnect(struct input_handle *handle)
struct tsdev *tsdev = handle->private; struct tsdev *tsdev = handle->private;
struct tsdev_list *list; struct tsdev_list *list;
input_unregister_handle(handle);
sysfs_remove_link(&input_class.subsys.kset.kobj, tsdev->name); sysfs_remove_link(&input_class.subsys.kset.kobj, tsdev->name);
class_device_destroy(&input_class, class_device_destroy(&input_class,
MKDEV(INPUT_MAJOR, TSDEV_MINOR_BASE + tsdev->minor)); MKDEV(INPUT_MAJOR, TSDEV_MINOR_BASE + tsdev->minor));
......
...@@ -1049,7 +1049,7 @@ struct input_handler { ...@@ -1049,7 +1049,7 @@ struct input_handler {
void *private; void *private;
void (*event)(struct input_handle *handle, unsigned int type, unsigned int code, int value); void (*event)(struct input_handle *handle, unsigned int type, unsigned int code, int value);
struct input_handle* (*connect)(struct input_handler *handler, struct input_dev *dev, const struct input_device_id *id); int (*connect)(struct input_handler *handler, struct input_dev *dev, const struct input_device_id *id);
void (*disconnect)(struct input_handle *handle); void (*disconnect)(struct input_handle *handle);
void (*start)(struct input_handle *handle); void (*start)(struct input_handle *handle);
...@@ -1102,6 +1102,9 @@ void input_unregister_device(struct input_dev *); ...@@ -1102,6 +1102,9 @@ void input_unregister_device(struct input_dev *);
int input_register_handler(struct input_handler *); int input_register_handler(struct input_handler *);
void input_unregister_handler(struct input_handler *); void input_unregister_handler(struct input_handler *);
int input_register_handle(struct input_handle *);
void input_unregister_handle(struct input_handle *);
int input_grab_device(struct input_handle *); int input_grab_device(struct input_handle *);
void input_release_device(struct input_handle *); void input_release_device(struct input_handle *);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment