From: Thomas H H. <th...@us...> - 2002-04-08 00:37:05
|
Update of /cvsroot/linuxconsole/ruby/linux/drivers/input In directory usw-pr-cvs1:/tmp/cvs-serv4435/linux/drivers/input Modified Files: Tag: thomash-2002_04_07 evdev.c Log Message: BRANCH: thomash-2002_04_07 evdev.c: Added new IOCTL's to get and set the entire keymap in one shot. Added two helper functions for pointer-translation to eliminate some redundancies in the ioctl function. Added a LOT of comments to the file, mostly function headers. input.c: Added new IOCTL constants. Added new structure for use with the bulk-transfer keymap IOCTL constants. STATUS: compiles against 2.5.7 / Code is NOT Tested. Index: evdev.c =================================================================== RCS file: /cvsroot/linuxconsole/ruby/linux/drivers/input/evdev.c,v retrieving revision 1.47 retrieving revision 1.47.2.1 diff -u -d -r1.47 -r1.47.2.1 --- evdev.c 20 Mar 2002 21:43:25 -0000 1.47 +++ evdev.c 8 Apr 2002 00:36:59 -0000 1.47.2.1 @@ -37,6 +37,10 @@ #include <linux/input.h> #include <linux/smp_lock.h> +/* + * This structure defines the event device for devices we have open. These + * represent the /dev/input/eventXXXX devices that the user may open. + */ struct evdev { int exist; int open; @@ -48,6 +52,7 @@ struct evdev_list *list; }; + struct evdev_list { struct input_event buffer[EVDEV_BUFFER_SIZE]; int head; @@ -57,8 +62,22 @@ struct evdev_list *next; }; +/* + * This is our internal list for the event devices (struct evdev) that we + * currently have defined. These will be created when event_connect is + * called for a device that we report events for + */ static struct evdev *evdev_table[EVDEV_MINORS] = { NULL, /* ... */ }; +/* ----------------------------------------------------------------- + * evdev_event + * + * This is defined by the INPUT interface, and is called when an event + * occurs on a device that we have registered a handler for. We create a + * structure (struct input_event), and we add it to the lists associated + * with the device. We then wake any syscalls waiting on data to be + * available. + * ----------------------------------------------------------------- */ static void evdev_event(struct input_handle *handle, unsigned int type, unsigned int code, int value) { struct evdev *evdev = handle->private; @@ -80,6 +99,10 @@ wake_up_interruptible(&evdev->wait); } +/* ----------------------------------------------------------------- + * evdev_fasync + * + * ----------------------------------------------------------------- */ static int evdev_fasync(int fd, struct file *file, int on) { int retval; @@ -88,6 +111,10 @@ return retval < 0 ? retval : 0; } +/* ----------------------------------------------------------------- + * evdev_flush + * + * ----------------------------------------------------------------- */ static int evdev_flush(struct file * file) { struct evdev_list *list = (struct evdev_list*)file->private_data; @@ -95,6 +122,13 @@ return input_flush_device(&list->evdev->handle, file); } +/* ----------------------------------------------------------------- + * evdev_release + * + * This is defined by the KERNEL CHARDEV interface. This is called when a + * process that has an open filehandle on one of our devices uses the + * syscall "close()" on the file descriptor. + * ----------------------------------------------------------------- */ static int evdev_release(struct inode * inode, struct file * file) { struct evdev_list *list = file->private_data; @@ -122,6 +156,12 @@ return 0; } +/* ----------------------------------------------------------------- + * evdev_open + * + * This is defined by the KERNEL CHARDEV interface, and is calle when a + * process uses the syscall "open" on one of our device files. + * ----------------------------------------------------------------- */ static int evdev_open(struct inode * inode, struct file * file) { struct evdev_list *list; @@ -153,6 +193,14 @@ return 0; } +/* ----------------------------------------------------------------- + * evdev_write + * + * This is defined by the KERNEL CHARDEV interface, and is called when a + * process uses the syscall "write" on an open filedescriptor that is + * associated with one of our devices. This can be used to "fake" input + * events on devices. + * ----------------------------------------------------------------- */ static ssize_t evdev_write(struct file * file, const char * buffer, size_t count, loff_t *ppos) { struct evdev_list *list = file->private_data; @@ -172,6 +220,13 @@ return retval; } +/* ----------------------------------------------------------------- + * evdev_read + * + * This is defined by the KERNEL CHARDEV interface, and is called when a + * process uses the syscall "read" on an open filedescriptor that is + * associated with one of our devices. + * ----------------------------------------------------------------- */ static ssize_t evdev_read(struct file * file, char * buffer, size_t count, loff_t *ppos) { DECLARE_WAITQUEUE(wait, current); @@ -219,6 +274,14 @@ } /* No kernel lock - fine */ + +/* ----------------------------------------------------------------- + * evdev_poll + * + * This is defined by the KERNEL CHARDEV interface, and is used by the + * kernel to implement both select() and poll(). This is called when a + * process calls select or poll on one of our devices. + * ----------------------------------------------------------------- */ static unsigned int evdev_poll(struct file *file, poll_table *wait) { struct evdev_list *list = file->private_data; @@ -228,6 +291,44 @@ return 0; } +/* + * key_to_keymap + * + * Helper function to eliminate redundant code in evdev_ioctl + */ +static int key_to_keymap( void *keys, int keysize, int offset, int key ) { + switch( keysize ) { + case 1: *(u8* )(keys + (offset)) = key; break; + case 2: *(u16*)(keys + (offset << 1)) = key; break; + case 4: *(u32*)(keys + (offset << 2)) = key; break; + default: return -EINVAL; + } + return 0; +} + +/* + * keymap_to_key + * + * Helper function to eliminate redundant code in evdev_ioctl + */ +static int keymap_to_key( void *keys, int keysize, int offset, int *key ) { + switch (keysize) { + case 1: *key = *(u8* )(keys + (offset)); break; + case 2: *key = *(u16*)(keys + (offset << 1)); break; + case 4: *key = *(u32*)(keys + (offset << 2)); break; + default: return -EINVAL; + } + return 0; +} + +/* ----------------------------------------------------------------- + * evdev_ioctl + * + * This is defined by the KERNEL CHARDEV interface, and is used by the + * kernel when a process calls "ioctl" on one of our open devices. This + * implements control commands such as getting versions, setting key + * mappings, and the like. + * ----------------------------------------------------------------- */ static int evdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { struct evdev_list *list = file->private_data; @@ -262,12 +363,8 @@ case EVIOCGKEYCODE: if ((retval = get_user(t, ((int *) arg) + 0))) return retval; if (t < 0 || t > dev->keycodemax) return -EINVAL; - switch (dev->keycodesize) { - case 1: u = *(u8*)(dev->keycode + t); break; - case 2: u = *(u16*)(dev->keycode + t * 2); break; - case 4: u = *(u32*)(dev->keycode + t * 4); break; - default: return -EINVAL; - } + if ((retval = keymap_to_key(dev->keycode, dev->keycodesize, t, &u))) + return retval; if ((retval = put_user(u, ((int *) arg) + 1))) return retval; return 0; @@ -275,13 +372,42 @@ if ((retval = get_user(t, ((int *) arg) + 0))) return retval; if (t < 0 || t > dev->keycodemax) return -EINVAL; if ((retval = get_user(u, ((int *) arg) + 1))) return retval; - switch (dev->keycodesize) { - case 1: *(u8*)(dev->keycode + t) = u; break; - case 2: *(u16*)(dev->keycode + t * 2) = u; break; - case 4: *(u32*)(dev->keycode + t * 4) = u; break; - default: return -EINVAL; - } - return 0; + return key_to_keymap( dev->keycode, dev->keycodesize, t, u ); + + case EVIOCGKEYMAP: + if( dev->keycode ) { + struct input_keymap keymap; + + keymap.ik_size = dev->keycodemax; + for( t = 0; t <= dev->keycodemax; t++ ) { + if((retval=keymap_to_key(dev->keycode, + dev->keycodesize, + t, + &(keymap.ik_keys[t])))) + return retval; + } + retval = copy_to_user((void*)(&keymap),(void*)arg,sizeof(keymap)); + return retval; + } + else return -ENOSYS; + + case EVIOCSKEYMAP: + if( dev->keycode) { + struct input_keymap keymap; + + retval = copy_from_user((void*)(&keymap),(void*)arg,sizeof(keymap)); + if(retval) return retval; + if( keymap.ik_size > EVKEYMAP_MAXSIZE ) return -EINVAL; + + for( t = 0; t <= dev->keycodemax; t++ ) { + if((retval=key_to_keymap(dev->keycode, + dev->keycodesize, + t, + keymap.ik_keys[t]))) + return retval; + } + } + else return -ENOSYS; case EVIOCSFF: if (dev->upload_effect) { @@ -395,18 +521,30 @@ return -EINVAL; } +/* + * This is our set of file operations that we use to register ourselves as + * a Character Device Driver. + */ static struct file_operations evdev_fops = { - owner: THIS_MODULE, - read: evdev_read, - write: evdev_write, - poll: evdev_poll, - open: evdev_open, - release: evdev_release, - ioctl: evdev_ioctl, - fasync: evdev_fasync, - flush: evdev_flush + owner: THIS_MODULE, + read: evdev_read, + write: evdev_write, + poll: evdev_poll, + open: evdev_open, + release: evdev_release, + ioctl: evdev_ioctl, + fasync: evdev_fasync, + flush: evdev_flush }; +/* ----------------------------------------------------------------- + * evdev_connect + * + * This is defined by the INPUT interface, and is called when a new input + * device has been connected, and is registered with the input module. We + * return a handler for all devices that are connected, since we are a raw + * interface to all device events. + * ----------------------------------------------------------------- */ static struct input_handle *evdev_connect(struct input_handler *handler, struct input_dev *dev, struct input_device_id *id) { struct evdev *evdev; @@ -441,6 +579,13 @@ return &evdev->handle; } +/* ----------------------------------------------------------------- + * evdev_disconnect + * + * This is defined by the INPUT interface, and is called when a device has + * been removed from the system and has been unregistered with the input + * module. + * ----------------------------------------------------------------- */ static void evdev_disconnect(struct input_handle *handle) { struct evdev *evdev = handle->private; @@ -464,14 +609,17 @@ MODULE_DEVICE_TABLE(input, evdev_ids); +/* + * Used to register ourselves as an input handler + */ static struct input_handler evdev_handler = { - event: evdev_event, - connect: evdev_connect, + event: evdev_event, + connect: evdev_connect, disconnect: evdev_disconnect, - fops: &evdev_fops, - minor: EVDEV_MINOR_BASE, - name: "evdev", - id_table: evdev_ids, + fops: &evdev_fops, + minor: EVDEV_MINOR_BASE, + name: "evdev", + id_table: evdev_ids, }; static int __init evdev_init(void) |