--- linux-2.6.12/drivers/input/evdev.c.orig 2005-08-15 11:12:15.000000000 -0600 +++ linux-2.6.12/drivers/input/evdev.c 2005-08-15 11:12:11.000000000 -0600 @@ -8,8 +8,17 @@ * the Free Software Foundation. */ +/* + * Modified 2005-8-12 Joe Peterson + * + * - Added persistent mixer device "/dev/input/events" + * (analogous to mousedev.c's "/dev/input/mice") + * + */ + #define EVDEV_MINOR_BASE 64 #define EVDEV_MINORS 32 +#define EVDEV_MIX 31 #define EVDEV_BUFFER_SIZE 64 #include @@ -42,11 +51,13 @@ struct evdev_list { struct list_head node; }; +static struct input_handler evdev_handler; + static struct evdev *evdev_table[EVDEV_MINORS]; +static struct evdev evdev_mix; -static void evdev_event(struct input_handle *handle, unsigned int type, unsigned int code, int value) +static void evdev_handle_event(struct evdev *evdev, unsigned int type, unsigned int code, int value) { - struct evdev *evdev = handle->private; struct evdev_list *list; if (evdev->grab) { @@ -74,6 +85,14 @@ static void evdev_event(struct input_han wake_up_interruptible(&evdev->wait); } +static void evdev_event(struct input_handle *handle, unsigned int type, unsigned int code, int value) +{ + struct evdev *evdev = handle->private; + + evdev_handle_event(evdev, type, code, value); + evdev_handle_event(&evdev_mix, type, code, value); +} + static int evdev_fasync(int fd, struct file *file, int on) { int retval; @@ -86,7 +105,10 @@ static int evdev_flush(struct file * fil { struct evdev_list *list = file->private_data; if (!list->evdev->exist) return -ENODEV; - return input_flush_device(&list->evdev->handle, file); + if (list->evdev->handle.dev) + return input_flush_device(&list->evdev->handle, file); + else + return 0; } static void evdev_free(struct evdev *evdev) @@ -95,6 +117,24 @@ static void evdev_free(struct evdev *evd kfree(evdev); } +static int mixdev_release(void) +{ + struct input_handle *handle; + + list_for_each_entry(handle, &evdev_handler.h_list, h_node) { + struct evdev *evdev = handle->private; + + if (!evdev->open) { + if (evdev->exist) + input_close_device(&evdev->handle); + else + evdev_free(evdev); + } + } + + return 0; +} + static int evdev_release(struct inode * inode, struct file * file) { struct evdev_list *list = file->private_data; @@ -108,10 +148,15 @@ static int evdev_release(struct inode * list_del(&list->node); if (!--list->evdev->open) { - if (list->evdev->exist) - input_close_device(&list->evdev->handle); - else - evdev_free(list->evdev); + if (list->evdev->minor == EVDEV_MIX) + return mixdev_release(); + + if (!evdev_mix.open) { + if (list->evdev->exist) + input_close_device(&list->evdev->handle); + else + evdev_free(list->evdev); + } } kfree(list); @@ -121,13 +166,16 @@ static int evdev_release(struct inode * static int evdev_open(struct inode * inode, struct file * file) { struct evdev_list *list; + struct input_handle *handle; + struct evdev *evdev; int i = iminor(inode) - EVDEV_MINOR_BASE; int accept_err; if (i >= EVDEV_MINORS || !evdev_table[i] || !evdev_table[i]->exist) return -ENODEV; - if ((accept_err = input_accept_process(&(evdev_table[i]->handle), file))) + if (evdev_table[i]->handle.dev) + if ((accept_err = input_accept_process(&(evdev_table[i]->handle), file))) return accept_err; if (!(list = kmalloc(sizeof(struct evdev_list), GFP_KERNEL))) @@ -138,10 +186,18 @@ static int evdev_open(struct inode * ino list_add_tail(&list->node, &evdev_table[i]->list); file->private_data = list; - if (!list->evdev->open++) - if (list->evdev->exist) - input_open_device(&list->evdev->handle); - + if (!list->evdev->open++) { + if (list->evdev->minor == EVDEV_MIX) { + list_for_each_entry(handle, &evdev_handler.h_list, h_node) { + evdev = handle->private; + if (!evdev->open && evdev->exist) + input_open_device(handle); + } + } else + if (!evdev_mix.open && list->evdev->exist) + input_open_device(&list->evdev->handle); + } + return 0; } @@ -157,7 +213,8 @@ static ssize_t evdev_write(struct file * if (copy_from_user(&event, buffer + retval, sizeof(struct input_event))) return -EFAULT; - input_event(list->evdev->handle.dev, event.type, event.code, event.value); + if (list->evdev->handle.dev) + input_event(list->evdev->handle.dev, event.type, event.code, event.value); retval += sizeof(struct input_event); } @@ -268,20 +325,24 @@ static int evdev_ioctl(struct inode *ino return 0; case EVIOCGRAB: - if (arg) { + if (evdev->handle.dev) { + if (arg) { if (evdev->grab) return -EBUSY; if (input_grab_device(&evdev->handle)) return -EBUSY; evdev->grab = list; return 0; - } else { + } else { if (evdev->grab != list) return -EINVAL; input_release_device(&evdev->handle); evdev->grab = NULL; return 0; - } + } + } else { + return 0; + } default: @@ -427,6 +488,9 @@ static struct input_handle *evdev_connec evdev->handle.private = evdev; sprintf(evdev->name, "event%d", minor); + if (evdev_mix.open) + input_open_device(&evdev->handle); + evdev_table[minor] = evdev; devfs_mk_cdev(MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + minor), @@ -452,8 +516,11 @@ static void evdev_disconnect(struct inpu wake_up_interruptible(&evdev->wait); list_for_each_entry(list, &evdev->list, node) kill_fasync(&list->fasync, SIGIO, POLL_HUP); - } else + } else { + if (evdev_mix.open) + input_close_device(handle); evdev_free(evdev); + } } static struct input_device_id evdev_ids[] = { @@ -476,11 +543,28 @@ static struct input_handler evdev_handle static int __init evdev_init(void) { input_register_handler(&evdev_handler); + + memset(&evdev_mix, 0, sizeof(struct evdev)); + INIT_LIST_HEAD(&evdev_mix.list); + init_waitqueue_head(&evdev_mix.wait); + evdev_table[EVDEV_MIX] = &evdev_mix; + evdev_mix.exist = 1; + evdev_mix.minor = EVDEV_MIX; + + devfs_mk_cdev(MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + EVDEV_MIX), + S_IFCHR|S_IRUGO|S_IWUSR, "input/events"); + class_simple_device_add(input_class, MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + EVDEV_MIX), + NULL, "events"); + + printk(KERN_INFO "events: event device common for all events\n"); + return 0; } static void __exit evdev_exit(void) { + devfs_remove("input/events"); + class_simple_device_remove(MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + EVDEV_MIX)); input_unregister_handler(&evdev_handler); }