Pull bugzilla-5452 into release branch
[pandora-kernel.git] / drivers / input / evdev.c
index 9f2352b..ba325f1 100644 (file)
@@ -130,9 +130,8 @@ static int evdev_open(struct inode * inode, struct file * file)
        if ((accept_err = input_accept_process(&(evdev_table[i]->handle), file)))
                return accept_err;
 
-       if (!(list = kmalloc(sizeof(struct evdev_list), GFP_KERNEL)))
+       if (!(list = kzalloc(sizeof(struct evdev_list), GFP_KERNEL)))
                return -ENOMEM;
-       memset(list, 0, sizeof(struct evdev_list));
 
        list->evdev = evdev_table[i];
        list_add_tail(&list->node, &evdev_table[i]->list);
@@ -146,6 +145,7 @@ static int evdev_open(struct inode * inode, struct file * file)
 }
 
 #ifdef CONFIG_COMPAT
+
 struct input_event_compat {
        struct compat_timeval time;
        __u16 type;
@@ -153,11 +153,13 @@ struct input_event_compat {
        __s32 value;
 };
 
+/* Note to the author of this code: did it ever occur to
+   you why the ifdefs are needed? Think about it again. -AK */
 #ifdef CONFIG_X86_64
-#  define COMPAT_TEST test_thread_flag(TIF_IA32)
+#  define COMPAT_TEST is_compat_task()
 #elif defined(CONFIG_IA64)
-#  define COMPAT_TEST IS_IA32_PROCESS(ia64_task_regs(current))
-#elif defined(CONFIG_ARCH_S390)
+#  define COMPAT_TEST IS_IA32_PROCESS(task_pt_regs(current))
+#elif defined(CONFIG_S390)
 #  define COMPAT_TEST test_thread_flag(TIF_31BIT)
 #elif defined(CONFIG_MIPS)
 #  define COMPAT_TEST (current->thread.mflags & MF_32BIT_ADDR)
@@ -165,98 +167,107 @@ struct input_event_compat {
 #  define COMPAT_TEST test_thread_flag(TIF_32BIT)
 #endif
 
-static ssize_t evdev_write_compat(struct file * file, const char __user * buffer, size_t count, loff_t *ppos)
+static inline size_t evdev_event_size(void)
 {
-       struct evdev_list *list = file->private_data;
-       struct input_event_compat event;
-       int retval = 0;
+       return COMPAT_TEST ?
+               sizeof(struct input_event_compat) : sizeof(struct input_event);
+}
 
-       while (retval < count) {
-               if (copy_from_user(&event, buffer + retval, sizeof(struct input_event_compat)))
+static int evdev_event_from_user(const char __user *buffer, struct input_event *event)
+{
+       if (COMPAT_TEST) {
+               struct input_event_compat compat_event;
+
+               if (copy_from_user(&compat_event, buffer, sizeof(struct input_event_compat)))
+                       return -EFAULT;
+
+               event->time.tv_sec = compat_event.time.tv_sec;
+               event->time.tv_usec = compat_event.time.tv_usec;
+               event->type = compat_event.type;
+               event->code = compat_event.code;
+               event->value = compat_event.value;
+
+       } else {
+               if (copy_from_user(event, buffer, sizeof(struct input_event)))
                        return -EFAULT;
-               input_event(list->evdev->handle.dev, event.type, event.code, event.value);
-               retval += sizeof(struct input_event_compat);
        }
 
-       return retval;
+       return 0;
 }
-#endif
 
-static ssize_t evdev_write(struct file * file, const char __user * buffer, size_t count, loff_t *ppos)
+static int evdev_event_to_user(char __user *buffer, const struct input_event *event)
 {
-       struct evdev_list *list = file->private_data;
-       struct input_event event;
-       int retval = 0;
-
-       if (!list->evdev->exist) return -ENODEV;
+       if (COMPAT_TEST) {
+               struct input_event_compat compat_event;
 
-#ifdef CONFIG_COMPAT
-       if (COMPAT_TEST)
-               return evdev_write_compat(file, buffer, count, ppos);
-#endif
+               compat_event.time.tv_sec = event->time.tv_sec;
+               compat_event.time.tv_usec = event->time.tv_usec;
+               compat_event.type = event->type;
+               compat_event.code = event->code;
+               compat_event.value = event->value;
 
-       while (retval < count) {
+               if (copy_to_user(buffer, &compat_event, sizeof(struct input_event_compat)))
+                       return -EFAULT;
 
-               if (copy_from_user(&event, buffer + retval, sizeof(struct input_event)))
+       } else {
+               if (copy_to_user(buffer, event, sizeof(struct input_event)))
                        return -EFAULT;
-               input_event(list->evdev->handle.dev, event.type, event.code, event.value);
-               retval += sizeof(struct input_event);
        }
 
-       return retval;
+       return 0;
 }
 
-#ifdef CONFIG_COMPAT
-static ssize_t evdev_read_compat(struct file * file, char __user * buffer, size_t count, loff_t *ppos)
+#else
+
+static inline size_t evdev_event_size(void)
 {
-       struct evdev_list *list = file->private_data;
-       int retval;
+       return sizeof(struct input_event);
+}
 
-       if (count < sizeof(struct input_event_compat))
-               return -EINVAL;
+static int evdev_event_from_user(const char __user *buffer, struct input_event *event)
+{
+       if (copy_from_user(event, buffer, sizeof(struct input_event)))
+               return -EFAULT;
 
-       if (list->head == list->tail && list->evdev->exist && (file->f_flags & O_NONBLOCK))
-               return -EAGAIN;
+       return 0;
+}
 
-       retval = wait_event_interruptible(list->evdev->wait,
-               list->head != list->tail || (!list->evdev->exist));
+static int evdev_event_to_user(char __user *buffer, const struct input_event *event)
+{
+       if (copy_to_user(buffer, event, sizeof(struct input_event)))
+               return -EFAULT;
 
-       if (retval)
-               return retval;
+       return 0;
+}
+
+#endif /* CONFIG_COMPAT */
+
+static ssize_t evdev_write(struct file * file, const char __user * buffer, size_t count, loff_t *ppos)
+{
+       struct evdev_list *list = file->private_data;
+       struct input_event event;
+       int retval = 0;
 
        if (!list->evdev->exist)
                return -ENODEV;
 
-       while (list->head != list->tail && retval + sizeof(struct input_event_compat) <= count) {
-               struct input_event *event = (struct input_event *) list->buffer + list->tail;
-               struct input_event_compat event_compat;
-               event_compat.time.tv_sec = event->time.tv_sec;
-               event_compat.time.tv_usec = event->time.tv_usec;
-               event_compat.type = event->type;
-               event_compat.code = event->code;
-               event_compat.value = event->value;
-
-               if (copy_to_user(buffer + retval, &event_compat,
-                       sizeof(struct input_event_compat))) return -EFAULT;
-               list->tail = (list->tail + 1) & (EVDEV_BUFFER_SIZE - 1);
-               retval += sizeof(struct input_event_compat);
+       while (retval < count) {
+
+               if (evdev_event_from_user(buffer + retval, &event))
+                       return -EFAULT;
+               input_event(list->evdev->handle.dev, event.type, event.code, event.value);
+               retval += evdev_event_size();
        }
 
        return retval;
 }
-#endif
 
 static ssize_t evdev_read(struct file * file, char __user * buffer, size_t count, loff_t *ppos)
 {
        struct evdev_list *list = file->private_data;
        int retval;
 
-#ifdef CONFIG_COMPAT
-       if (COMPAT_TEST)
-               return evdev_read_compat(file, buffer, count, ppos);
-#endif
-
-       if (count < sizeof(struct input_event))
+       if (count < evdev_event_size())
                return -EINVAL;
 
        if (list->head == list->tail && list->evdev->exist && (file->f_flags & O_NONBLOCK))
@@ -271,11 +282,15 @@ static ssize_t evdev_read(struct file * file, char __user * buffer, size_t count
        if (!list->evdev->exist)
                return -ENODEV;
 
-       while (list->head != list->tail && retval + sizeof(struct input_event) <= count) {
-               if (copy_to_user(buffer + retval, list->buffer + list->tail,
-                       sizeof(struct input_event))) return -EFAULT;
+       while (list->head != list->tail && retval + evdev_event_size() <= count) {
+
+               struct input_event *event = (struct input_event *) list->buffer + list->tail;
+
+               if (evdev_event_to_user(buffer + retval, event))
+                       return -EFAULT;
+
                list->tail = (list->tail + 1) & (EVDEV_BUFFER_SIZE - 1);
-               retval += sizeof(struct input_event);
+               retval += evdev_event_size();
        }
 
        return retval;
@@ -290,17 +305,95 @@ static unsigned int evdev_poll(struct file *file, poll_table *wait)
                (list->evdev->exist ? 0 : (POLLHUP | POLLERR));
 }
 
-static long evdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+#ifdef CONFIG_COMPAT
+
+#define BITS_PER_LONG_COMPAT (sizeof(compat_long_t) * 8)
+#define NBITS_COMPAT(x) ((((x) - 1) / BITS_PER_LONG_COMPAT) + 1)
+
+#ifdef __BIG_ENDIAN
+static int bits_to_user(unsigned long *bits, unsigned int maxbit,
+                       unsigned int maxlen, void __user *p, int compat)
+{
+       int len, i;
+
+       if (compat) {
+               len = NBITS_COMPAT(maxbit) * sizeof(compat_long_t);
+               if (len < maxlen)
+                       len = maxlen;
+
+               for (i = 0; i < len / sizeof(compat_long_t); i++)
+                       if (copy_to_user((compat_long_t __user *) p + i,
+                                        (compat_long_t *) bits +
+                                               i + 1 - ((i % 2) << 1),
+                                        sizeof(compat_long_t)))
+                               return -EFAULT;
+       } else {
+               len = NBITS(maxbit) * sizeof(long);
+               if (len > maxlen)
+                       len = maxlen;
+
+               if (copy_to_user(p, bits, len))
+                       return -EFAULT;
+       }
+
+       return len;
+}
+#else
+static int bits_to_user(unsigned long *bits, unsigned int maxbit,
+                       unsigned int maxlen, void __user *p, int compat)
+{
+       int len = compat ?
+                       NBITS_COMPAT(maxbit) * sizeof(compat_long_t) :
+                       NBITS(maxbit) * sizeof(long);
+
+       if (len > maxlen)
+               len = maxlen;
+
+       return copy_to_user(p, bits, len) ? -EFAULT : len;
+}
+#endif /* __BIG_ENDIAN */
+
+#else
+
+static int bits_to_user(unsigned long *bits, unsigned int maxbit,
+                       unsigned int maxlen, void __user *p, int compat)
+{
+       int len = NBITS(maxbit) * sizeof(long);
+
+       if (len > maxlen)
+               len = maxlen;
+
+       return copy_to_user(p, bits, len) ? -EFAULT : len;
+}
+
+#endif /* CONFIG_COMPAT */
+
+static int str_to_user(const char *str, unsigned int maxlen, void __user *p)
+{
+       int len;
+
+       if (!str)
+               return -ENOENT;
+
+       len = strlen(str) + 1;
+       if (len > maxlen)
+               len = maxlen;
+
+       return copy_to_user(p, str, len) ? -EFAULT : len;
+}
+
+static long evdev_ioctl_handler(struct file *file, unsigned int cmd,
+                               void __user *p, int compat_mode)
 {
        struct evdev_list *list = file->private_data;
        struct evdev *evdev = list->evdev;
        struct input_dev *dev = evdev->handle.dev;
        struct input_absinfo abs;
-       void __user *p = (void __user *)arg;
-       int __user *ip = (int __user *)arg;
+       int __user *ip = (int __user *)p;
        int i, t, u, v;
 
-       if (!evdev->exist) return -ENODEV;
+       if (!evdev->exist)
+               return -ENODEV;
 
        switch (cmd) {
 
@@ -308,26 +401,60 @@ static long evdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
                        return put_user(EV_VERSION, ip);
 
                case EVIOCGID:
-                       return copy_to_user(p, &dev->id, sizeof(struct input_id)) ? -EFAULT : 0;
+                       if (copy_to_user(p, &dev->id, sizeof(struct input_id)))
+                               return -EFAULT;
+                       return 0;
+
+               case EVIOCGREP:
+                       if (!test_bit(EV_REP, dev->evbit))
+                               return -ENOSYS;
+                       if (put_user(dev->rep[REP_DELAY], ip))
+                               return -EFAULT;
+                       if (put_user(dev->rep[REP_PERIOD], ip + 1))
+                               return -EFAULT;
+                       return 0;
+
+               case EVIOCSREP:
+                       if (!test_bit(EV_REP, dev->evbit))
+                               return -ENOSYS;
+                       if (get_user(u, ip))
+                               return -EFAULT;
+                       if (get_user(v, ip + 1))
+                               return -EFAULT;
+
+                       input_event(dev, EV_REP, REP_DELAY, u);
+                       input_event(dev, EV_REP, REP_PERIOD, v);
+
+                       return 0;
 
                case EVIOCGKEYCODE:
-                       if (get_user(t, ip)) return -EFAULT;
-                       if (t < 0 || t >= dev->keycodemax || !dev->keycodesize) return -EINVAL;
-                       if (put_user(INPUT_KEYCODE(dev, t), ip + 1)) return -EFAULT;
+                       if (get_user(t, ip))
+                               return -EFAULT;
+                       if (t < 0 || t >= dev->keycodemax || !dev->keycodesize)
+                               return -EINVAL;
+                       if (put_user(INPUT_KEYCODE(dev, t), ip + 1))
+                               return -EFAULT;
                        return 0;
 
                case EVIOCSKEYCODE:
-                       if (get_user(t, ip)) return -EFAULT;
-                       if (t < 0 || t >= dev->keycodemax || !dev->keycodesize) return -EINVAL;
-                       if (get_user(v, ip + 1)) return -EFAULT;
-                       if (v < 0 || v > KEY_MAX) return -EINVAL;
-                       if (dev->keycodesize < sizeof(v) && (v >> (dev->keycodesize * 8))) return -EINVAL;
+                       if (get_user(t, ip))
+                               return -EFAULT;
+                       if (t < 0 || t >= dev->keycodemax || !dev->keycodesize)
+                               return -EINVAL;
+                       if (get_user(v, ip + 1))
+                               return -EFAULT;
+                       if (v < 0 || v > KEY_MAX)
+                               return -EINVAL;
+                       if (dev->keycodesize < sizeof(v) && (v >> (dev->keycodesize * 8)))
+                               return -EINVAL;
+
                        u = SET_INPUT_KEYCODE(dev, t, v);
                        clear_bit(u, dev->keybit);
                        set_bit(v, dev->keybit);
                        for (i = 0; i < dev->keycodemax; i++)
-                               if (INPUT_KEYCODE(dev,i) == u)
+                               if (INPUT_KEYCODE(dev, i) == u)
                                        set_bit(u, dev->keybit);
+
                        return 0;
 
                case EVIOCSFF:
@@ -338,17 +465,17 @@ static long evdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
                                if (copy_from_user(&effect, p, sizeof(effect)))
                                        return -EFAULT;
                                err = dev->upload_effect(dev, &effect);
-                               if (put_user(effect.id, &(((struct ff_effect __user *)arg)->id)))
+                               if (put_user(effect.id, &(((struct ff_effect __user *)p)->id)))
                                        return -EFAULT;
                                return err;
-                       }
-                       else return -ENOSYS;
+                       } else
+                               return -ENOSYS;
 
                case EVIOCRMFF:
-                       if (dev->erase_effect) {
-                               return dev->erase_effect(dev, (int)arg);
-                       }
-                       else return -ENOSYS;
+                       if (!dev->erase_effect)
+                               return -ENOSYS;
+
+                       return dev->erase_effect(dev, (int)(unsigned long) p);
 
                case EVIOCGEFFECTS:
                        if (put_user(dev->ff_effects_max, ip))
@@ -356,7 +483,7 @@ static long evdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
                        return 0;
 
                case EVIOCGRAB:
-                       if (arg) {
+                       if (p) {
                                if (evdev->grab)
                                        return -EBUSY;
                                if (input_grab_device(&evdev->handle))
@@ -395,62 +522,33 @@ static long evdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
                                                case EV_SW:  bits = dev->swbit;  len = SW_MAX;  break;
                                                default: return -EINVAL;
                                        }
-                                       len = NBITS(len) * sizeof(long);
-                                       if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
-                                       return copy_to_user(p, bits, len) ? -EFAULT : len;
+                                       return bits_to_user(bits, len, _IOC_SIZE(cmd), p, compat_mode);
                                }
 
-                               if (_IOC_NR(cmd) == _IOC_NR(EVIOCGKEY(0))) {
-                                       int len;
-                                       len = NBITS(KEY_MAX) * sizeof(long);
-                                       if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
-                                       return copy_to_user(p, dev->key, len) ? -EFAULT : len;
-                               }
+                               if (_IOC_NR(cmd) == _IOC_NR(EVIOCGKEY(0)))
+                                       return bits_to_user(dev->key, KEY_MAX, _IOC_SIZE(cmd),
+                                                           p, compat_mode);
 
-                               if (_IOC_NR(cmd) == _IOC_NR(EVIOCGLED(0))) {
-                                       int len;
-                                       len = NBITS(LED_MAX) * sizeof(long);
-                                       if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
-                                       return copy_to_user(p, dev->led, len) ? -EFAULT : len;
-                               }
+                               if (_IOC_NR(cmd) == _IOC_NR(EVIOCGLED(0)))
+                                       return bits_to_user(dev->led, LED_MAX, _IOC_SIZE(cmd),
+                                                           p, compat_mode);
 
-                               if (_IOC_NR(cmd) == _IOC_NR(EVIOCGSND(0))) {
-                                       int len;
-                                       len = NBITS(SND_MAX) * sizeof(long);
-                                       if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
-                                       return copy_to_user(p, dev->snd, len) ? -EFAULT : len;
-                               }
+                               if (_IOC_NR(cmd) == _IOC_NR(EVIOCGSND(0)))
+                                       return bits_to_user(dev->snd, SND_MAX, _IOC_SIZE(cmd),
+                                                           p, compat_mode);
 
-                               if (_IOC_NR(cmd) == _IOC_NR(EVIOCGSW(0))) {
-                                       int len;
-                                       len = NBITS(SW_MAX) * sizeof(long);
-                                       if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
-                                       return copy_to_user(p, dev->sw, len) ? -EFAULT : len;
-                               }
+                               if (_IOC_NR(cmd) == _IOC_NR(EVIOCGSW(0)))
+                                       return bits_to_user(dev->sw, SW_MAX, _IOC_SIZE(cmd),
+                                                           p, compat_mode);
 
-                               if (_IOC_NR(cmd) == _IOC_NR(EVIOCGNAME(0))) {
-                                       int len;
-                                       if (!dev->name) return -ENOENT;
-                                       len = strlen(dev->name) + 1;
-                                       if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
-                                       return copy_to_user(p, dev->name, len) ? -EFAULT : len;
-                               }
+                               if (_IOC_NR(cmd) == _IOC_NR(EVIOCGNAME(0)))
+                                       return str_to_user(dev->name, _IOC_SIZE(cmd), p);
 
-                               if (_IOC_NR(cmd) == _IOC_NR(EVIOCGPHYS(0))) {
-                                       int len;
-                                       if (!dev->phys) return -ENOENT;
-                                       len = strlen(dev->phys) + 1;
-                                       if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
-                                       return copy_to_user(p, dev->phys, len) ? -EFAULT : len;
-                               }
+                               if (_IOC_NR(cmd) == _IOC_NR(EVIOCGPHYS(0)))
+                                       return str_to_user(dev->phys, _IOC_SIZE(cmd), p);
 
-                               if (_IOC_NR(cmd) == _IOC_NR(EVIOCGUNIQ(0))) {
-                                       int len;
-                                       if (!dev->uniq) return -ENOENT;
-                                       len = strlen(dev->uniq) + 1;
-                                       if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
-                                       return copy_to_user(p, dev->uniq, len) ? -EFAULT : len;
-                               }
+                               if (_IOC_NR(cmd) == _IOC_NR(EVIOCGUNIQ(0)))
+                                       return str_to_user(dev->uniq, _IOC_SIZE(cmd), p);
 
                                if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCGABS(0))) {
 
@@ -492,158 +590,15 @@ static long evdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
        return -EINVAL;
 }
 
-#ifdef CONFIG_COMPAT
-
-#define BITS_PER_LONG_COMPAT (sizeof(compat_long_t) * 8)
-#define NBITS_COMPAT(x) ((((x)-1)/BITS_PER_LONG_COMPAT)+1)
-#define OFF_COMPAT(x)  ((x)%BITS_PER_LONG_COMPAT)
-#define BIT_COMPAT(x)  (1UL<<OFF_COMPAT(x))
-#define LONG_COMPAT(x) ((x)/BITS_PER_LONG_COMPAT)
-#define test_bit_compat(bit, array) ((array[LONG_COMPAT(bit)] >> OFF_COMPAT(bit)) & 1)
-
-#ifdef __BIG_ENDIAN
-#define bit_to_user(bit, max) \
-do { \
-       int i; \
-       int len = NBITS_COMPAT((max)) * sizeof(compat_long_t); \
-       if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd); \
-       for (i = 0; i < len / sizeof(compat_long_t); i++) \
-               if (copy_to_user((compat_long_t __user *) p + i, \
-                                (compat_long_t*) (bit) + i + 1 - ((i % 2) << 1), \
-                                sizeof(compat_long_t))) \
-                       return -EFAULT; \
-       return len; \
-} while (0)
-#else
-#define bit_to_user(bit, max) \
-do { \
-       int len = NBITS_COMPAT((max)) * sizeof(compat_long_t); \
-       if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd); \
-       return copy_to_user(p, (bit), len) ? -EFAULT : len; \
-} while (0)
-#endif
+static long evdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+       return evdev_ioctl_handler(file, cmd, (void __user *)arg, 0);
+}
 
+#ifdef CONFIG_COMPAT
 static long evdev_ioctl_compat(struct file *file, unsigned int cmd, unsigned long arg)
 {
-       struct evdev_list *list = file->private_data;
-       struct evdev *evdev = list->evdev;
-       struct input_dev *dev = evdev->handle.dev;
-       struct input_absinfo abs;
-       void __user *p = compat_ptr(arg);
-
-       if (!evdev->exist) return -ENODEV;
-
-       switch (cmd) {
-
-               case EVIOCGVERSION:
-               case EVIOCGID:
-               case EVIOCGKEYCODE:
-               case EVIOCSKEYCODE:
-               case EVIOCSFF:
-               case EVIOCRMFF:
-               case EVIOCGEFFECTS:
-               case EVIOCGRAB:
-                       return evdev_ioctl(file, cmd, (unsigned long) p);
-
-               default:
-
-                       if (_IOC_TYPE(cmd) != 'E')
-                               return -EINVAL;
-
-                       if (_IOC_DIR(cmd) == _IOC_READ) {
-
-                               if ((_IOC_NR(cmd) & ~EV_MAX) == _IOC_NR(EVIOCGBIT(0,0))) {
-                                       long *bits;
-                                       int max;
-
-                                       switch (_IOC_NR(cmd) & EV_MAX) {
-                                               case      0: bits = dev->evbit;  max = EV_MAX;  break;
-                                               case EV_KEY: bits = dev->keybit; max = KEY_MAX; break;
-                                               case EV_REL: bits = dev->relbit; max = REL_MAX; break;
-                                               case EV_ABS: bits = dev->absbit; max = ABS_MAX; break;
-                                               case EV_MSC: bits = dev->mscbit; max = MSC_MAX; break;
-                                               case EV_LED: bits = dev->ledbit; max = LED_MAX; break;
-                                               case EV_SND: bits = dev->sndbit; max = SND_MAX; break;
-                                               case EV_FF:  bits = dev->ffbit;  max = FF_MAX;  break;
-                                               case EV_SW:  bits = dev->swbit;  max = SW_MAX;  break;
-                                               default: return -EINVAL;
-                                       }
-                                       bit_to_user(bits, max);
-                               }
-
-                               if (_IOC_NR(cmd) == _IOC_NR(EVIOCGKEY(0)))
-                                       bit_to_user(dev->key, KEY_MAX);
-
-                               if (_IOC_NR(cmd) == _IOC_NR(EVIOCGLED(0)))
-                                       bit_to_user(dev->led, LED_MAX);
-
-                               if (_IOC_NR(cmd) == _IOC_NR(EVIOCGSND(0)))
-                                       bit_to_user(dev->snd, SND_MAX);
-
-                               if (_IOC_NR(cmd) == _IOC_NR(EVIOCGSW(0)))
-                                       bit_to_user(dev->sw, SW_MAX);
-
-                               if (_IOC_NR(cmd) == _IOC_NR(EVIOCGNAME(0))) {
-                                       int len;
-                                       if (!dev->name) return -ENOENT;
-                                       len = strlen(dev->name) + 1;
-                                       if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
-                                       return copy_to_user(p, dev->name, len) ? -EFAULT : len;
-                               }
-
-                               if (_IOC_NR(cmd) == _IOC_NR(EVIOCGPHYS(0))) {
-                                       int len;
-                                       if (!dev->phys) return -ENOENT;
-                                       len = strlen(dev->phys) + 1;
-                                       if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
-                                       return copy_to_user(p, dev->phys, len) ? -EFAULT : len;
-                               }
-
-                               if (_IOC_NR(cmd) == _IOC_NR(EVIOCGUNIQ(0))) {
-                                       int len;
-                                       if (!dev->uniq) return -ENOENT;
-                                       len = strlen(dev->uniq) + 1;
-                                       if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
-                                       return copy_to_user(p, dev->uniq, len) ? -EFAULT : len;
-                               }
-
-                               if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCGABS(0))) {
-
-                                       int t = _IOC_NR(cmd) & ABS_MAX;
-
-                                       abs.value = dev->abs[t];
-                                       abs.minimum = dev->absmin[t];
-                                       abs.maximum = dev->absmax[t];
-                                       abs.fuzz = dev->absfuzz[t];
-                                       abs.flat = dev->absflat[t];
-
-                                       if (copy_to_user(p, &abs, sizeof(struct input_absinfo)))
-                                               return -EFAULT;
-
-                                       return 0;
-                               }
-                       }
-
-                       if (_IOC_DIR(cmd) == _IOC_WRITE) {
-
-                               if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCSABS(0))) {
-
-                                       int t = _IOC_NR(cmd) & ABS_MAX;
-
-                                       if (copy_from_user(&abs, p, sizeof(struct input_absinfo)))
-                                               return -EFAULT;
-
-                                       dev->abs[t] = abs.value;
-                                       dev->absmin[t] = abs.minimum;
-                                       dev->absmax[t] = abs.maximum;
-                                       dev->absfuzz[t] = abs.fuzz;
-                                       dev->absflat[t] = abs.flat;
-
-                                       return 0;
-                               }
-                       }
-       }
-       return -EINVAL;
+       return evdev_ioctl_handler(file, cmd, compat_ptr(arg), 1);
 }
 #endif
 
@@ -674,9 +629,8 @@ static struct input_handle *evdev_connect(struct input_handler *handler, struct
                return NULL;
        }
 
-       if (!(evdev = kmalloc(sizeof(struct evdev), GFP_KERNEL)))
+       if (!(evdev = kzalloc(sizeof(struct evdev), GFP_KERNEL)))
                return NULL;
-       memset(evdev, 0, sizeof(struct evdev));
 
        INIT_LIST_HEAD(&evdev->list);
        init_waitqueue_head(&evdev->wait);