|
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)
|