From 2d56f3a32c0e62f99c043d2579840f9731fe5855 Mon Sep 17 00:00:00 2001 From: Philip Langdale Date: Thu, 16 Oct 2008 22:31:42 -0400 Subject: Input: refactor evdev 32bit compat to be shareable with uinput Currently, evdev has working 32bit compatibility and uinput does not. uinput needs the input_event code that evdev uses, so let's refactor it so it can be shared. [dtor@mail.ru: add fix for force feedback compat issues] Signed-off-by: Philip Langdale Signed-off-by: Dmitry Torokhov --- drivers/input/Makefile | 2 +- drivers/input/evdev.c | 197 ++----------------------------------------- drivers/input/input-compat.c | 135 +++++++++++++++++++++++++++++ drivers/input/input-compat.h | 94 +++++++++++++++++++++ drivers/input/misc/uinput.c | 172 +++++++++++++++++++++++++++++++------ 5 files changed, 383 insertions(+), 217 deletions(-) create mode 100644 drivers/input/input-compat.c create mode 100644 drivers/input/input-compat.h diff --git a/drivers/input/Makefile b/drivers/input/Makefile index 98c4f9a77876..4c9c745a7020 100644 --- a/drivers/input/Makefile +++ b/drivers/input/Makefile @@ -5,7 +5,7 @@ # Each configuration option enables a list of files. obj-$(CONFIG_INPUT) += input-core.o -input-core-objs := input.o ff-core.o +input-core-objs := input.o input-compat.o ff-core.o obj-$(CONFIG_INPUT_FF_MEMLESS) += ff-memless.o obj-$(CONFIG_INPUT_POLLDEV) += input-polldev.o diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c index 3524bef62be6..377b2007377e 100644 --- a/drivers/input/evdev.c +++ b/drivers/input/evdev.c @@ -19,7 +19,7 @@ #include #include #include -#include +#include "input-compat.h" struct evdev { int exist; @@ -291,187 +291,6 @@ static int evdev_open(struct inode *inode, struct file *file) return error; } -#ifdef CONFIG_COMPAT - -struct input_event_compat { - struct compat_timeval time; - __u16 type; - __u16 code; - __s32 value; -}; - -struct ff_periodic_effect_compat { - __u16 waveform; - __u16 period; - __s16 magnitude; - __s16 offset; - __u16 phase; - - struct ff_envelope envelope; - - __u32 custom_len; - compat_uptr_t custom_data; -}; - -struct ff_effect_compat { - __u16 type; - __s16 id; - __u16 direction; - struct ff_trigger trigger; - struct ff_replay replay; - - union { - struct ff_constant_effect constant; - struct ff_ramp_effect ramp; - struct ff_periodic_effect_compat periodic; - struct ff_condition_effect condition[2]; /* One for each axis */ - struct ff_rumble_effect rumble; - } u; -}; - -/* 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 is_compat_task() -#elif defined(CONFIG_IA64) -# 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 test_thread_flag(TIF_32BIT_ADDR) -#else -# define COMPAT_TEST test_thread_flag(TIF_32BIT) -#endif - -static inline size_t evdev_event_size(void) -{ - return COMPAT_TEST ? - sizeof(struct input_event_compat) : sizeof(struct input_event); -} - -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; - } - - return 0; -} - -static int evdev_event_to_user(char __user *buffer, - const struct input_event *event) -{ - if (COMPAT_TEST) { - struct input_event_compat compat_event; - - 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; - - if (copy_to_user(buffer, &compat_event, - sizeof(struct input_event_compat))) - return -EFAULT; - - } else { - if (copy_to_user(buffer, event, sizeof(struct input_event))) - return -EFAULT; - } - - return 0; -} - -static int evdev_ff_effect_from_user(const char __user *buffer, size_t size, - struct ff_effect *effect) -{ - if (COMPAT_TEST) { - struct ff_effect_compat *compat_effect; - - if (size != sizeof(struct ff_effect_compat)) - return -EINVAL; - - /* - * It so happens that the pointer which needs to be changed - * is the last field in the structure, so we can copy the - * whole thing and replace just the pointer. - */ - - compat_effect = (struct ff_effect_compat *)effect; - - if (copy_from_user(compat_effect, buffer, - sizeof(struct ff_effect_compat))) - return -EFAULT; - - if (compat_effect->type == FF_PERIODIC && - compat_effect->u.periodic.waveform == FF_CUSTOM) - effect->u.periodic.custom_data = - compat_ptr(compat_effect->u.periodic.custom_data); - } else { - if (size != sizeof(struct ff_effect)) - return -EINVAL; - - if (copy_from_user(effect, buffer, sizeof(struct ff_effect))) - return -EFAULT; - } - - return 0; -} - -#else - -static inline size_t evdev_event_size(void) -{ - return sizeof(struct input_event); -} - -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; - - return 0; -} - -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; - - return 0; -} - -static int evdev_ff_effect_from_user(const char __user *buffer, size_t size, - struct ff_effect *effect) -{ - if (size != sizeof(struct ff_effect)) - return -EINVAL; - - if (copy_from_user(effect, buffer, sizeof(struct ff_effect))) - return -EFAULT; - - return 0; -} - -#endif /* CONFIG_COMPAT */ - static ssize_t evdev_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) { @@ -491,14 +310,14 @@ static ssize_t evdev_write(struct file *file, const char __user *buffer, while (retval < count) { - if (evdev_event_from_user(buffer + retval, &event)) { + if (input_event_from_user(buffer + retval, &event)) { retval = -EFAULT; goto out; } input_inject_event(&evdev->handle, event.type, event.code, event.value); - retval += evdev_event_size(); + retval += input_event_size(); } out: @@ -532,7 +351,7 @@ static ssize_t evdev_read(struct file *file, char __user *buffer, struct input_event event; int retval; - if (count < evdev_event_size()) + if (count < input_event_size()) return -EINVAL; if (client->head == client->tail && evdev->exist && @@ -547,13 +366,13 @@ static ssize_t evdev_read(struct file *file, char __user *buffer, if (!evdev->exist) return -ENODEV; - while (retval + evdev_event_size() <= count && + while (retval + input_event_size() <= count && evdev_fetch_next_event(client, &event)) { - if (evdev_event_to_user(buffer + retval, &event)) + if (input_event_to_user(buffer + retval, &event)) return -EFAULT; - retval += evdev_event_size(); + retval += input_event_size(); } return retval; @@ -824,7 +643,7 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd, if (_IOC_NR(cmd) == _IOC_NR(EVIOCSFF)) { - if (evdev_ff_effect_from_user(p, _IOC_SIZE(cmd), &effect)) + if (input_ff_effect_from_user(p, _IOC_SIZE(cmd), &effect)) return -EFAULT; error = input_ff_upload(dev, &effect, file); diff --git a/drivers/input/input-compat.c b/drivers/input/input-compat.c new file mode 100644 index 000000000000..1accb89ae66f --- /dev/null +++ b/drivers/input/input-compat.c @@ -0,0 +1,135 @@ +/* + * 32bit compatibility wrappers for the input subsystem. + * + * Very heavily based on evdev.c - Copyright (c) 1999-2002 Vojtech Pavlik + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + */ + +#include +#include "input-compat.h" + +#ifdef CONFIG_COMPAT + +int input_event_from_user(const char __user *buffer, + struct input_event *event) +{ + if (INPUT_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; + } + + return 0; +} + +int input_event_to_user(char __user *buffer, + const struct input_event *event) +{ + if (INPUT_COMPAT_TEST) { + struct input_event_compat compat_event; + + 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; + + if (copy_to_user(buffer, &compat_event, + sizeof(struct input_event_compat))) + return -EFAULT; + + } else { + if (copy_to_user(buffer, event, sizeof(struct input_event))) + return -EFAULT; + } + + return 0; +} + +int input_ff_effect_from_user(const char __user *buffer, size_t size, + struct ff_effect *effect) +{ + if (INPUT_COMPAT_TEST) { + struct ff_effect_compat *compat_effect; + + if (size != sizeof(struct ff_effect_compat)) + return -EINVAL; + + /* + * It so happens that the pointer which needs to be changed + * is the last field in the structure, so we can retrieve the + * whole thing and replace just the pointer. + */ + compat_effect = (struct ff_effect_compat *)effect; + + if (copy_from_user(compat_effect, buffer, + sizeof(struct ff_effect_compat))) + return -EFAULT; + + if (compat_effect->type == FF_PERIODIC && + compat_effect->u.periodic.waveform == FF_CUSTOM) + effect->u.periodic.custom_data = + compat_ptr(compat_effect->u.periodic.custom_data); + } else { + if (size != sizeof(struct ff_effect)) + return -EINVAL; + + if (copy_from_user(effect, buffer, sizeof(struct ff_effect))) + return -EFAULT; + } + + return 0; +} + +#else + +int input_event_from_user(const char __user *buffer, + struct input_event *event) +{ + if (copy_from_user(event, buffer, sizeof(struct input_event))) + return -EFAULT; + + return 0; +} + +int input_event_to_user(char __user *buffer, + const struct input_event *event) +{ + if (copy_to_user(buffer, event, sizeof(struct input_event))) + return -EFAULT; + + return 0; +} + +int input_ff_effect_from_user(const char __user *buffer, size_t size, + struct ff_effect *effect) +{ + if (size != sizeof(struct ff_effect)) + return -EINVAL; + + if (copy_from_user(effect, buffer, sizeof(struct ff_effect))) + return -EFAULT; + + return 0; +} + +#endif /* CONFIG_COMPAT */ + +EXPORT_SYMBOL_GPL(input_event_from_user); +EXPORT_SYMBOL_GPL(input_event_to_user); +EXPORT_SYMBOL_GPL(input_ff_effect_from_user); diff --git a/drivers/input/input-compat.h b/drivers/input/input-compat.h new file mode 100644 index 000000000000..47cd9eaee66a --- /dev/null +++ b/drivers/input/input-compat.h @@ -0,0 +1,94 @@ +#ifndef _INPUT_COMPAT_H +#define _INPUT_COMPAT_H + +/* + * 32bit compatibility wrappers for the input subsystem. + * + * Very heavily based on evdev.c - Copyright (c) 1999-2002 Vojtech Pavlik + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + */ + +#include +#include +#include + +#ifdef CONFIG_COMPAT + +/* 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 INPUT_COMPAT_TEST is_compat_task() +#elif defined(CONFIG_IA64) +# define INPUT_COMPAT_TEST IS_IA32_PROCESS(task_pt_regs(current)) +#elif defined(CONFIG_S390) +# define INPUT_COMPAT_TEST test_thread_flag(TIF_31BIT) +#elif defined(CONFIG_MIPS) +# define INPUT_COMPAT_TEST test_thread_flag(TIF_32BIT_ADDR) +#else +# define INPUT_COMPAT_TEST test_thread_flag(TIF_32BIT) +#endif + +struct input_event_compat { + struct compat_timeval time; + __u16 type; + __u16 code; + __s32 value; +}; + +struct ff_periodic_effect_compat { + __u16 waveform; + __u16 period; + __s16 magnitude; + __s16 offset; + __u16 phase; + + struct ff_envelope envelope; + + __u32 custom_len; + compat_uptr_t custom_data; +}; + +struct ff_effect_compat { + __u16 type; + __s16 id; + __u16 direction; + struct ff_trigger trigger; + struct ff_replay replay; + + union { + struct ff_constant_effect constant; + struct ff_ramp_effect ramp; + struct ff_periodic_effect_compat periodic; + struct ff_condition_effect condition[2]; /* One for each axis */ + struct ff_rumble_effect rumble; + } u; +}; + +static inline size_t input_event_size(void) +{ + return INPUT_COMPAT_TEST ? + sizeof(struct input_event_compat) : sizeof(struct input_event); +} + +#else + +static inline size_t input_event_size(void) +{ + return sizeof(struct input_event); +} + +#endif /* CONFIG_COMPAT */ + +int input_event_from_user(const char __user *buffer, + struct input_event *event); + +int input_event_to_user(char __user *buffer, + const struct input_event *event); + +int input_ff_effect_from_user(const char __user *buffer, size_t size, + struct ff_effect *effect); + +#endif /* _INPUT_COMPAT_H */ diff --git a/drivers/input/misc/uinput.c b/drivers/input/misc/uinput.c index 223d56d5555b..46b7caeb2817 100644 --- a/drivers/input/misc/uinput.c +++ b/drivers/input/misc/uinput.c @@ -37,6 +37,7 @@ #include #include #include +#include "../input-compat.h" static int uinput_dev_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) { @@ -78,6 +79,7 @@ static struct uinput_request* uinput_request_find(struct uinput_device *udev, in /* Find an input request, by ID. Returns NULL if the ID isn't valid. */ if (id >= UINPUT_NUM_REQUESTS || id < 0) return NULL; + return udev->requests[id]; } @@ -127,6 +129,17 @@ static int uinput_dev_upload_effect(struct input_dev *dev, struct ff_effect *eff struct uinput_request request; int retval; + /* + * uinput driver does not currently support periodic effects with + * custom waveform since it does not have a way to pass buffer of + * samples (custom_data) to userspace. If ever there is a device + * supporting custom waveforms we would need to define an additional + * ioctl (UI_UPLOAD_SAMPLES) but for now we just bail out. + */ + if (effect->type == FF_PERIODIC && + effect->u.periodic.waveform == FF_CUSTOM) + return -EINVAL; + request.id = -1; init_completion(&request.done); request.code = UI_FF_UPLOAD; @@ -353,15 +366,15 @@ static inline ssize_t uinput_inject_event(struct uinput_device *udev, const char { struct input_event ev; - if (count != sizeof(struct input_event)) + if (count < input_event_size()) return -EINVAL; - if (copy_from_user(&ev, buffer, sizeof(struct input_event))) + if (input_event_from_user(buffer, &ev)) return -EFAULT; input_event(udev->dev, ev.type, ev.code, ev.value); - return sizeof(struct input_event); + return input_event_size(); } static ssize_t uinput_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) @@ -407,13 +420,13 @@ static ssize_t uinput_read(struct file *file, char __user *buffer, size_t count, goto out; } - while (udev->head != udev->tail && retval + sizeof(struct input_event) <= count) { - if (copy_to_user(buffer + retval, &udev->buff[udev->tail], sizeof(struct input_event))) { + while (udev->head != udev->tail && retval + input_event_size() <= count) { + if (input_event_to_user(buffer + retval, &udev->buff[udev->tail])) { retval = -EFAULT; goto out; } udev->tail = (udev->tail + 1) % UINPUT_BUFFER_SIZE; - retval += sizeof(struct input_event); + retval += input_event_size(); } out: @@ -444,6 +457,93 @@ static int uinput_release(struct inode *inode, struct file *file) return 0; } +#ifdef CONFIG_COMPAT +struct uinput_ff_upload_compat { + int request_id; + int retval; + struct ff_effect_compat effect; + struct ff_effect_compat old; +}; + +static int uinput_ff_upload_to_user(char __user *buffer, + const struct uinput_ff_upload *ff_up) +{ + if (INPUT_COMPAT_TEST) { + struct uinput_ff_upload_compat ff_up_compat; + + ff_up_compat.request_id = ff_up->request_id; + ff_up_compat.retval = ff_up->retval; + /* + * It so happens that the pointer that gives us the trouble + * is the last field in the structure. Since we don't support + * custom waveforms in uinput anyway we can just copy the whole + * thing (to the compat size) and ignore the pointer. + */ + memcpy(&ff_up_compat.effect, &ff_up->effect, + sizeof(struct ff_effect_compat)); + memcpy(&ff_up_compat.old, &ff_up->old, + sizeof(struct ff_effect_compat)); + + if (copy_to_user(buffer, &ff_up_compat, + sizeof(struct uinput_ff_upload_compat))) + return -EFAULT; + } else { + if (copy_to_user(buffer, ff_up, + sizeof(struct uinput_ff_upload))) + return -EFAULT; + } + + return 0; +} + +static int uinput_ff_upload_from_user(const char __user *buffer, + struct uinput_ff_upload *ff_up) +{ + if (INPUT_COMPAT_TEST) { + struct uinput_ff_upload_compat ff_up_compat; + + if (copy_from_user(&ff_up_compat, buffer, + sizeof(struct uinput_ff_upload_compat))) + return -EFAULT; + + ff_up->request_id = ff_up_compat.request_id; + ff_up->retval = ff_up_compat.retval; + memcpy(&ff_up->effect, &ff_up_compat.effect, + sizeof(struct ff_effect_compat)); + memcpy(&ff_up->old, &ff_up_compat.old, + sizeof(struct ff_effect_compat)); + + } else { + if (copy_from_user(ff_up, buffer, + sizeof(struct uinput_ff_upload))) + return -EFAULT; + } + + return 0; +} + +#else + +static int uinput_ff_upload_to_user(char __user *buffer, + const struct uinput_ff_upload *ff_up) +{ + if (copy_to_user(buffer, ff_up, sizeof(struct uinput_ff_upload))) + return -EFAULT; + + return 0; +} + +static int uinput_ff_upload_from_user(const char __user *buffer, + struct uinput_ff_upload *ff_up) +{ + if (copy_from_user(ff_up, buffer, sizeof(struct uinput_ff_upload))) + return -EFAULT; + + return 0; +} + +#endif + #define uinput_set_bit(_arg, _bit, _max) \ ({ \ int __ret = 0; \ @@ -455,19 +555,17 @@ static int uinput_release(struct inode *inode, struct file *file) __ret; \ }) -static long uinput_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +static long uinput_ioctl_handler(struct file *file, unsigned int cmd, + unsigned long arg, void __user *p) { int retval; - struct uinput_device *udev; - void __user *p = (void __user *)arg; + struct uinput_device *udev = file->private_data; struct uinput_ff_upload ff_up; struct uinput_ff_erase ff_erase; struct uinput_request *req; int length; char *phys; - udev = file->private_data; - retval = mutex_lock_interruptible(&udev->mutex); if (retval) return retval; @@ -549,26 +647,24 @@ static long uinput_ioctl(struct file *file, unsigned int cmd, unsigned long arg) break; case UI_BEGIN_FF_UPLOAD: - if (copy_from_user(&ff_up, p, sizeof(ff_up))) { - retval = -EFAULT; + retval = uinput_ff_upload_from_user(p, &ff_up); + if (retval) break; - } + req = uinput_request_find(udev, ff_up.request_id); - if (!(req && req->code == UI_FF_UPLOAD && req->u.upload.effect)) { + if (!req || req->code != UI_FF_UPLOAD || !req->u.upload.effect) { retval = -EINVAL; break; } + ff_up.retval = 0; - memcpy(&ff_up.effect, req->u.upload.effect, sizeof(struct ff_effect)); + ff_up.effect = *req->u.upload.effect; if (req->u.upload.old) - memcpy(&ff_up.old, req->u.upload.old, sizeof(struct ff_effect)); + ff_up.old = *req->u.upload.old; else memset(&ff_up.old, 0, sizeof(struct ff_effect)); - if (copy_to_user(p, &ff_up, sizeof(ff_up))) { - retval = -EFAULT; - break; - } + retval = uinput_ff_upload_to_user(p, &ff_up); break; case UI_BEGIN_FF_ERASE: @@ -576,29 +672,34 @@ static long uinput_ioctl(struct file *file, unsigned int cmd, unsigned long arg) retval = -EFAULT; break; } + req = uinput_request_find(udev, ff_erase.request_id); - if (!(req && req->code == UI_FF_ERASE)) { + if (!req || req->code != UI_FF_ERASE) { retval = -EINVAL; break; } + ff_erase.retval = 0; ff_erase.effect_id = req->u.effect_id; if (copy_to_user(p, &ff_erase, sizeof(ff_erase))) { retval = -EFAULT; break; } + break; case UI_END_FF_UPLOAD: - if (copy_from_user(&ff_up, p, sizeof(ff_up))) { - retval = -EFAULT; + retval = uinput_ff_upload_from_user(p, &ff_up); + if (retval) break; - } + req = uinput_request_find(udev, ff_up.request_id); - if (!(req && req->code == UI_FF_UPLOAD && req->u.upload.effect)) { + if (!req || req->code != UI_FF_UPLOAD || + !req->u.upload.effect) { retval = -EINVAL; break; } + req->retval = ff_up.retval; uinput_request_done(udev, req); break; @@ -608,11 +709,13 @@ static long uinput_ioctl(struct file *file, unsigned int cmd, unsigned long arg) retval = -EFAULT; break; } + req = uinput_request_find(udev, ff_erase.request_id); - if (!(req && req->code == UI_FF_ERASE)) { + if (!req || req->code != UI_FF_ERASE) { retval = -EINVAL; break; } + req->retval = ff_erase.retval; uinput_request_done(udev, req); break; @@ -626,6 +729,18 @@ static long uinput_ioctl(struct file *file, unsigned int cmd, unsigned long arg) return retval; } +static long uinput_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + return uinput_ioctl_handler(file, cmd, arg, (void __user *)arg); +} + +#ifdef CONFIG_COMPAT +static long uinput_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + return uinput_ioctl_handler(file, cmd, arg, compat_ptr(arg)); +} +#endif + static const struct file_operations uinput_fops = { .owner = THIS_MODULE, .open = uinput_open, @@ -634,6 +749,9 @@ static const struct file_operations uinput_fops = { .write = uinput_write, .poll = uinput_poll, .unlocked_ioctl = uinput_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = uinput_compat_ioctl, +#endif }; static struct miscdevice uinput_misc = { -- cgit v1.2.3 From b4a3ac9a3c26e82e31f8a8f55cb014bc580b1216 Mon Sep 17 00:00:00 2001 From: John Linn Date: Mon, 27 Oct 2008 22:17:22 -0400 Subject: Input: xilinx_ps2 - various cleanups Review comments were incorporated to improve the driver. 1. Some data was eliminated that was not needed. 2. Renaming of variables for clarity. 3. Removed unneeded type casting. 4. Changed to use dev_err rather than other I/O. 5. Merged together some functions. 6. Added kerneldoc format to functions. Signed-off-by: Sadanand Signed-off-by: John Linn Acked-by: Peter Korsgaard Acked-by: Grant Likely Signed-off-by: Dmitry Torokhov --- drivers/input/serio/xilinx_ps2.c | 220 ++++++++++++++++++++------------------- 1 file changed, 113 insertions(+), 107 deletions(-) diff --git a/drivers/input/serio/xilinx_ps2.c b/drivers/input/serio/xilinx_ps2.c index 765007899d9a..ebb22f88c842 100644 --- a/drivers/input/serio/xilinx_ps2.c +++ b/drivers/input/serio/xilinx_ps2.c @@ -58,23 +58,20 @@ /* Mask for all the Receive Interrupts */ #define XPS2_IPIXR_RX_ALL (XPS2_IPIXR_RX_OVF | XPS2_IPIXR_RX_ERR | \ - XPS2_IPIXR_RX_FULL) + XPS2_IPIXR_RX_FULL) /* Mask for all the Interrupts */ #define XPS2_IPIXR_ALL (XPS2_IPIXR_TX_ALL | XPS2_IPIXR_RX_ALL | \ - XPS2_IPIXR_WDT_TOUT) + XPS2_IPIXR_WDT_TOUT) /* Global Interrupt Enable mask */ #define XPS2_GIER_GIE_MASK 0x80000000 struct xps2data { int irq; - u32 phys_addr; - u32 remap_size; spinlock_t lock; - u8 rxb; /* Rx buffer */ void __iomem *base_address; /* virt. address of control registers */ - unsigned int dfl; + unsigned int flags; struct serio serio; /* serio */ }; @@ -82,8 +79,13 @@ struct xps2data { /* XPS PS/2 data transmission calls */ /************************************/ -/* - * xps2_recv() will attempt to receive a byte of data from the PS/2 port. +/** + * xps2_recv() - attempts to receive a byte from the PS/2 port. + * @drvdata: pointer to ps2 device private data structure + * @byte: address where the read data will be copied + * + * If there is any data available in the PS/2 receiver, this functions reads + * the data, otherwise it returns error. */ static int xps2_recv(struct xps2data *drvdata, u8 *byte) { @@ -116,33 +118,27 @@ static irqreturn_t xps2_interrupt(int irq, void *dev_id) /* Check which interrupt is active */ if (intr_sr & XPS2_IPIXR_RX_OVF) - printk(KERN_WARNING "%s: receive overrun error\n", - drvdata->serio.name); + dev_warn(drvdata->serio.dev.parent, "receive overrun error\n"); if (intr_sr & XPS2_IPIXR_RX_ERR) - drvdata->dfl |= SERIO_PARITY; + drvdata->flags |= SERIO_PARITY; if (intr_sr & (XPS2_IPIXR_TX_NOACK | XPS2_IPIXR_WDT_TOUT)) - drvdata->dfl |= SERIO_TIMEOUT; + drvdata->flags |= SERIO_TIMEOUT; if (intr_sr & XPS2_IPIXR_RX_FULL) { - status = xps2_recv(drvdata, &drvdata->rxb); + status = xps2_recv(drvdata, &c); /* Error, if a byte is not received */ if (status) { - printk(KERN_ERR - "%s: wrong rcvd byte count (%d)\n", - drvdata->serio.name, status); + dev_err(drvdata->serio.dev.parent, + "wrong rcvd byte count (%d)\n", status); } else { - c = drvdata->rxb; - serio_interrupt(&drvdata->serio, c, drvdata->dfl); - drvdata->dfl = 0; + serio_interrupt(&drvdata->serio, c, drvdata->flags); + drvdata->flags = 0; } } - if (intr_sr & XPS2_IPIXR_TX_ACK) - drvdata->dfl = 0; - return IRQ_HANDLED; } @@ -150,8 +146,15 @@ static irqreturn_t xps2_interrupt(int irq, void *dev_id) /* serio callbacks */ /*******************/ -/* - * sxps2_write() sends a byte out through the PS/2 interface. +/** + * sxps2_write() - sends a byte out through the PS/2 port. + * @pserio: pointer to the serio structure of the PS/2 port + * @c: data that needs to be written to the PS/2 port + * + * This function checks if the PS/2 transmitter is empty and sends a byte. + * Otherwise it returns error. Transmission fails only when nothing is connected + * to the PS/2 port. Thats why, we do not try to resend the data in case of a + * failure. */ static int sxps2_write(struct serio *pserio, unsigned char c) { @@ -174,33 +177,39 @@ static int sxps2_write(struct serio *pserio, unsigned char c) return status; } -/* - * sxps2_open() is called when a port is open by the higher layer. +/** + * sxps2_open() - called when a port is opened by the higher layer. + * @pserio: pointer to the serio structure of the PS/2 device + * + * This function requests irq and enables interrupts for the PS/2 device. */ static int sxps2_open(struct serio *pserio) { struct xps2data *drvdata = pserio->port_data; - int retval; + int error; + u8 c; - retval = request_irq(drvdata->irq, &xps2_interrupt, 0, + error = request_irq(drvdata->irq, &xps2_interrupt, 0, DRIVER_NAME, drvdata); - if (retval) { - printk(KERN_ERR - "%s: Couldn't allocate interrupt %d\n", - drvdata->serio.name, drvdata->irq); - return retval; + if (error) { + dev_err(drvdata->serio.dev.parent, + "Couldn't allocate interrupt %d\n", drvdata->irq); + return error; } /* start reception by enabling the interrupts */ out_be32(drvdata->base_address + XPS2_GIER_OFFSET, XPS2_GIER_GIE_MASK); out_be32(drvdata->base_address + XPS2_IPIER_OFFSET, XPS2_IPIXR_RX_ALL); - (void)xps2_recv(drvdata, &drvdata->rxb); + (void)xps2_recv(drvdata, &c); return 0; /* success */ } -/* - * sxps2_close() frees the interrupt. +/** + * sxps2_close() - frees the interrupt. + * @pserio: pointer to the serio structure of the PS/2 device + * + * This function frees the irq and disables interrupts for the PS/2 device. */ static void sxps2_close(struct serio *pserio) { @@ -212,24 +221,41 @@ static void sxps2_close(struct serio *pserio) free_irq(drvdata->irq, drvdata); } -/*********************/ -/* Device setup code */ -/*********************/ - -static int xps2_setup(struct device *dev, struct resource *regs_res, - struct resource *irq_res) +/** + * xps2_of_probe - probe method for the PS/2 device. + * @of_dev: pointer to OF device structure + * @match: pointer to the stucture used for matching a device + * + * This function probes the PS/2 device in the device tree. + * It initializes the driver data structure and the hardware. + * It returns 0, if the driver is bound to the PS/2 device, or a negative + * value if there is an error. + */ +static int __devinit xps2_of_probe(struct of_device *ofdev, + const struct of_device_id *match) { + struct resource r_irq; /* Interrupt resources */ + struct resource r_mem; /* IO mem resources */ struct xps2data *drvdata; struct serio *serio; - unsigned long remap_size; - int retval; + struct device *dev = &ofdev->dev; + resource_size_t remap_size, phys_addr; + int error; + + dev_info(dev, "Device Tree Probing \'%s\'\n", + ofdev->node->name); - if (!dev) - return -EINVAL; + /* Get iospace for the device */ + error = of_address_to_resource(ofdev->node, 0, &r_mem); + if (error) { + dev_err(dev, "invalid address\n"); + return error; + } - if (!regs_res || !irq_res) { - dev_err(dev, "IO resource(s) not found\n"); - return -EINVAL; + /* Get IRQ for the device */ + if (of_irq_to_resource(ofdev->node, 0, &r_irq) == NO_IRQ) { + dev_err(dev, "no IRQ found\n"); + return -ENODEV; } drvdata = kzalloc(sizeof(struct xps2data), GFP_KERNEL); @@ -241,24 +267,23 @@ static int xps2_setup(struct device *dev, struct resource *regs_res, dev_set_drvdata(dev, drvdata); spin_lock_init(&drvdata->lock); - drvdata->irq = irq_res->start; - - remap_size = regs_res->end - regs_res->start + 1; - if (!request_mem_region(regs_res->start, remap_size, DRIVER_NAME)) { - dev_err(dev, "Couldn't lock memory region at 0x%08X\n", - (unsigned int)regs_res->start); - retval = -EBUSY; + drvdata->irq = r_irq.start; + + phys_addr = r_mem.start; + remap_size = r_mem.end - r_mem.start + 1; + if (!request_mem_region(phys_addr, remap_size, DRIVER_NAME)) { + dev_err(dev, "Couldn't lock memory region at 0x%08llX\n", + (unsigned long long)phys_addr); + error = -EBUSY; goto failed1; } /* Fill in configuration data and add them to the list */ - drvdata->phys_addr = regs_res->start; - drvdata->remap_size = remap_size; - drvdata->base_address = ioremap(regs_res->start, remap_size); + drvdata->base_address = ioremap(phys_addr, remap_size); if (drvdata->base_address == NULL) { - dev_err(dev, "Couldn't ioremap memory at 0x%08X\n", - (unsigned int)regs_res->start); - retval = -EFAULT; + dev_err(dev, "Couldn't ioremap memory at 0x%08llX\n", + (unsigned long long)phys_addr); + error = -EFAULT; goto failed2; } @@ -269,8 +294,9 @@ static int xps2_setup(struct device *dev, struct resource *regs_res, * we have the PS2 in a good state */ out_be32(drvdata->base_address + XPS2_SRST_OFFSET, XPS2_SRST_RESET); - dev_info(dev, "Xilinx PS2 at 0x%08X mapped to 0x%p, irq=%d\n", - drvdata->phys_addr, drvdata->base_address, drvdata->irq); + dev_info(dev, "Xilinx PS2 at 0x%08llX mapped to 0x%p, irq=%d\n", + (unsigned long long)phys_addr, drvdata->base_address, + drvdata->irq); serio = &drvdata->serio; serio->id.type = SERIO_8042; @@ -280,71 +306,51 @@ static int xps2_setup(struct device *dev, struct resource *regs_res, serio->port_data = drvdata; serio->dev.parent = dev; snprintf(serio->name, sizeof(serio->name), - "Xilinx XPS PS/2 at %08X", drvdata->phys_addr); + "Xilinx XPS PS/2 at %08llX", (unsigned long long)phys_addr); snprintf(serio->phys, sizeof(serio->phys), - "xilinxps2/serio at %08X", drvdata->phys_addr); + "xilinxps2/serio at %08llX", (unsigned long long)phys_addr); + serio_register_port(serio); return 0; /* success */ failed2: - release_mem_region(regs_res->start, remap_size); + release_mem_region(phys_addr, remap_size); failed1: kfree(drvdata); dev_set_drvdata(dev, NULL); - return retval; -} - -/***************************/ -/* OF Platform Bus Support */ -/***************************/ - -static int __devinit xps2_of_probe(struct of_device *ofdev, const struct - of_device_id * match) -{ - struct resource r_irq; /* Interrupt resources */ - struct resource r_mem; /* IO mem resources */ - int rc = 0; - - printk(KERN_INFO "Device Tree Probing \'%s\'\n", - ofdev->node->name); - - /* Get iospace for the device */ - rc = of_address_to_resource(ofdev->node, 0, &r_mem); - if (rc) { - dev_err(&ofdev->dev, "invalid address\n"); - return rc; - } - - /* Get IRQ for the device */ - rc = of_irq_to_resource(ofdev->node, 0, &r_irq); - if (rc == NO_IRQ) { - dev_err(&ofdev->dev, "no IRQ found\n"); - return rc; - } - - return xps2_setup(&ofdev->dev, &r_mem, &r_irq); + return error; } +/** + * xps2_of_remove - unbinds the driver from the PS/2 device. + * @of_dev: pointer to OF device structure + * + * This function is called if a device is physically removed from the system or + * if the driver module is being unloaded. It frees any resources allocated to + * the device. + */ static int __devexit xps2_of_remove(struct of_device *of_dev) { struct device *dev = &of_dev->dev; - struct xps2data *drvdata; - - if (!dev) - return -EINVAL; - - drvdata = dev_get_drvdata(dev); + struct xps2data *drvdata = dev_get_drvdata(dev); + struct resource r_mem; /* IO mem resources */ serio_unregister_port(&drvdata->serio); iounmap(drvdata->base_address); - release_mem_region(drvdata->phys_addr, drvdata->remap_size); + + /* Get iospace of the device */ + if (of_address_to_resource(of_dev->node, 0, &r_mem)) + dev_err(dev, "invalid address\n"); + else + release_mem_region(r_mem.start, r_mem.end - r_mem.start + 1); + kfree(drvdata); dev_set_drvdata(dev, NULL); - return 0; /* success */ + return 0; } /* Match table for of_platform binding */ -- cgit v1.2.3 From b67b4b117746aef686e527c3205792db0f2c9e16 Mon Sep 17 00:00:00 2001 From: Dominic Curran Date: Mon, 27 Oct 2008 22:30:53 -0400 Subject: Input: gpio-keys - add flag to allow auto repeat This patch adds a flag to gpio-key driver to turn on the input subsystems auto repeat feature if needed. Signed-off-by: Dominic Curran Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/gpio_keys.c | 4 ++++ include/linux/gpio_keys.h | 1 + 2 files changed, 5 insertions(+) diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c index 05f3f43582c2..ad67d763fdbd 100644 --- a/drivers/input/keyboard/gpio_keys.c +++ b/drivers/input/keyboard/gpio_keys.c @@ -98,6 +98,10 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev) input->id.product = 0x0001; input->id.version = 0x0100; + /* Enable auto repeat feature of Linux input subsystem */ + if (pdata->rep) + __set_bit(EV_REP, input->evbit); + ddata->input = input; for (i = 0; i < pdata->nbuttons; i++) { diff --git a/include/linux/gpio_keys.h b/include/linux/gpio_keys.h index ec6ecd74781d..1289fa7623ca 100644 --- a/include/linux/gpio_keys.h +++ b/include/linux/gpio_keys.h @@ -15,6 +15,7 @@ struct gpio_keys_button { struct gpio_keys_platform_data { struct gpio_keys_button *buttons; int nbuttons; + unsigned int rep:1; /* enable input subsystem auto repeat */ }; #endif -- cgit v1.2.3 From 09779678d12482024e06380cacc4c3ff2f129f23 Mon Sep 17 00:00:00 2001 From: Stelian Pop Date: Tue, 28 Oct 2008 23:20:46 -0400 Subject: Input: appletouch - driver refactoring The appletouch driver has grown up from supporting only a couple of touchpads into supporting many touchpads, which can have different number of sensors, different aspect ratios etc. This patch cleans up the current driver code and makes it easy to support the features of each different touchpad. As a side effect, this patch also modifies the 'Y' multiplication factor of the 'geyser3' and 'geyser4' touchpads (found on Core Duo and Core2 Duo MacBook and MacBook Pro laptops) in order to make the touchpad output match the aspect ratio of the touchpad (Y factor changed from 43 to 64). [dtor@mail.ru: make atp_info constant] Signed-off-by: Stelian Pop Acked-by: Johannes Berg Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/appletouch.c | 274 +++++++++++++++++++-------------------- 1 file changed, 136 insertions(+), 138 deletions(-) diff --git a/drivers/input/mouse/appletouch.c b/drivers/input/mouse/appletouch.c index 079816e6b23b..454b96112f03 100644 --- a/drivers/input/mouse/appletouch.c +++ b/drivers/input/mouse/appletouch.c @@ -3,7 +3,7 @@ * * Copyright (C) 2001-2004 Greg Kroah-Hartman (greg@kroah.com) * Copyright (C) 2005-2008 Johannes Berg (johannes@sipsolutions.net) - * Copyright (C) 2005 Stelian Pop (stelian@popies.net) + * Copyright (C) 2005-2008 Stelian Pop (stelian@popies.net) * Copyright (C) 2005 Frank Arnold (frank@scirocco-5v-turbo.de) * Copyright (C) 2005 Peter Osterlund (petero2@telia.com) * Copyright (C) 2005 Michael Hanselmann (linux-kernel@hansmi.ch) @@ -35,16 +35,74 @@ #include #include -/* Type of touchpad */ -enum atp_touchpad_type { - ATP_FOUNTAIN, - ATP_GEYSER1, - ATP_GEYSER2, - ATP_GEYSER3, - ATP_GEYSER4 +/* + * Note: We try to keep the touchpad aspect ratio while still doing only + * simple arithmetics: + * 0 <= x <= (xsensors - 1) * xfact + * 0 <= y <= (ysensors - 1) * yfact + */ +struct atp_info { + int xsensors; /* number of X sensors */ + int xsensors_17; /* 17" models have more sensors */ + int ysensors; /* number of Y sensors */ + int xfact; /* X multiplication factor */ + int yfact; /* Y multiplication factor */ + int datalen; /* size of USB transfers */ + void (*callback)(struct urb *); /* callback function */ +}; + +static void atp_complete_geyser_1_2(struct urb *urb); +static void atp_complete_geyser_3_4(struct urb *urb); + +static const struct atp_info fountain_info = { + .xsensors = 16, + .xsensors_17 = 26, + .ysensors = 16, + .xfact = 64, + .yfact = 43, + .datalen = 81, + .callback = atp_complete_geyser_1_2, +}; + +static const struct atp_info geyser1_info = { + .xsensors = 16, + .xsensors_17 = 26, + .ysensors = 16, + .xfact = 64, + .yfact = 43, + .datalen = 81, + .callback = atp_complete_geyser_1_2, +}; + +static const struct atp_info geyser2_info = { + .xsensors = 15, + .xsensors_17 = 20, + .ysensors = 9, + .xfact = 64, + .yfact = 43, + .datalen = 64, + .callback = atp_complete_geyser_1_2, +}; + +static const struct atp_info geyser3_info = { + .xsensors = 20, + .ysensors = 10, + .xfact = 64, + .yfact = 64, + .datalen = 64, + .callback = atp_complete_geyser_3_4, }; -#define ATP_DEVICE(prod, type) \ +static const struct atp_info geyser4_info = { + .xsensors = 20, + .ysensors = 10, + .xfact = 64, + .yfact = 64, + .datalen = 64, + .callback = atp_complete_geyser_3_4, +}; + +#define ATP_DEVICE(prod, info) \ { \ .match_flags = USB_DEVICE_ID_MATCH_DEVICE | \ USB_DEVICE_ID_MATCH_INT_CLASS | \ @@ -53,7 +111,7 @@ enum atp_touchpad_type { .idProduct = (prod), \ .bInterfaceClass = 0x03, \ .bInterfaceProtocol = 0x02, \ - .driver_info = ATP_ ## type, \ + .driver_info = (unsigned long) &info, \ } /* @@ -62,43 +120,39 @@ enum atp_touchpad_type { * According to Info.plist Geyser IV is the same as Geyser III.) */ -static struct usb_device_id atp_table [] = { +static struct usb_device_id atp_table[] = { /* PowerBooks Feb 2005, iBooks G4 */ - ATP_DEVICE(0x020e, FOUNTAIN), /* FOUNTAIN ANSI */ - ATP_DEVICE(0x020f, FOUNTAIN), /* FOUNTAIN ISO */ - ATP_DEVICE(0x030a, FOUNTAIN), /* FOUNTAIN TP ONLY */ - ATP_DEVICE(0x030b, GEYSER1), /* GEYSER 1 TP ONLY */ + ATP_DEVICE(0x020e, fountain_info), /* FOUNTAIN ANSI */ + ATP_DEVICE(0x020f, fountain_info), /* FOUNTAIN ISO */ + ATP_DEVICE(0x030a, fountain_info), /* FOUNTAIN TP ONLY */ + ATP_DEVICE(0x030b, geyser1_info), /* GEYSER 1 TP ONLY */ /* PowerBooks Oct 2005 */ - ATP_DEVICE(0x0214, GEYSER2), /* GEYSER 2 ANSI */ - ATP_DEVICE(0x0215, GEYSER2), /* GEYSER 2 ISO */ - ATP_DEVICE(0x0216, GEYSER2), /* GEYSER 2 JIS */ + ATP_DEVICE(0x0214, geyser2_info), /* GEYSER 2 ANSI */ + ATP_DEVICE(0x0215, geyser2_info), /* GEYSER 2 ISO */ + ATP_DEVICE(0x0216, geyser2_info), /* GEYSER 2 JIS */ /* Core Duo MacBook & MacBook Pro */ - ATP_DEVICE(0x0217, GEYSER3), /* GEYSER 3 ANSI */ - ATP_DEVICE(0x0218, GEYSER3), /* GEYSER 3 ISO */ - ATP_DEVICE(0x0219, GEYSER3), /* GEYSER 3 JIS */ + ATP_DEVICE(0x0217, geyser3_info), /* GEYSER 3 ANSI */ + ATP_DEVICE(0x0218, geyser3_info), /* GEYSER 3 ISO */ + ATP_DEVICE(0x0219, geyser3_info), /* GEYSER 3 JIS */ /* Core2 Duo MacBook & MacBook Pro */ - ATP_DEVICE(0x021a, GEYSER4), /* GEYSER 4 ANSI */ - ATP_DEVICE(0x021b, GEYSER4), /* GEYSER 4 ISO */ - ATP_DEVICE(0x021c, GEYSER4), /* GEYSER 4 JIS */ + ATP_DEVICE(0x021a, geyser4_info), /* GEYSER 4 ANSI */ + ATP_DEVICE(0x021b, geyser4_info), /* GEYSER 4 ISO */ + ATP_DEVICE(0x021c, geyser4_info), /* GEYSER 4 JIS */ /* Core2 Duo MacBook3,1 */ - ATP_DEVICE(0x0229, GEYSER4), /* GEYSER 4 HF ANSI */ - ATP_DEVICE(0x022a, GEYSER4), /* GEYSER 4 HF ISO */ - ATP_DEVICE(0x022b, GEYSER4), /* GEYSER 4 HF JIS */ + ATP_DEVICE(0x0229, geyser4_info), /* GEYSER 4 HF ANSI */ + ATP_DEVICE(0x022a, geyser4_info), /* GEYSER 4 HF ISO */ + ATP_DEVICE(0x022b, geyser4_info), /* GEYSER 4 HF JIS */ /* Terminating entry */ { } }; MODULE_DEVICE_TABLE(usb, atp_table); -/* - * number of sensors. Note that only 16 instead of 26 X (horizontal) - * sensors exist on 12" and 15" PowerBooks. All models have 16 Y - * (vertical) sensors. - */ +/* maximum number of sensors */ #define ATP_XSENSORS 26 #define ATP_YSENSORS 16 @@ -107,21 +161,6 @@ MODULE_DEVICE_TABLE(usb, atp_table); /* maximum pressure this driver will report */ #define ATP_PRESSURE 300 -/* - * multiplication factor for the X and Y coordinates. - * We try to keep the touchpad aspect ratio while still doing only simple - * arithmetics. - * The factors below give coordinates like: - * - * 0 <= x < 960 on 12" and 15" Powerbooks - * 0 <= x < 1600 on 17" Powerbooks and 17" MacBook Pro - * 0 <= x < 1216 on MacBooks and 15" MacBook Pro - * - * 0 <= y < 646 on all Powerbooks - * 0 <= y < 774 on all MacBooks - */ -#define ATP_XFACT 64 -#define ATP_YFACT 43 /* * Threshold for the touchpad sensors. Any change less than ATP_THRESHOLD is @@ -159,7 +198,7 @@ struct atp { struct urb *urb; /* usb request block */ u8 *data; /* transferred data */ struct input_dev *input; /* input dev */ - enum atp_touchpad_type type; /* type of touchpad */ + const struct atp_info *info; /* touchpad model */ bool open; bool valid; /* are the samples valid? */ bool size_detect_done; @@ -169,7 +208,6 @@ struct atp { signed char xy_cur[ATP_XSENSORS + ATP_YSENSORS]; signed char xy_old[ATP_XSENSORS + ATP_YSENSORS]; int xy_acc[ATP_XSENSORS + ATP_YSENSORS]; - int datalen; /* size of USB transfer */ int idlecount; /* number of empty packets */ struct work_struct work; }; @@ -359,7 +397,7 @@ static int atp_status_check(struct urb *urb) if (!dev->overflow_warned) { printk(KERN_WARNING "appletouch: OVERFLOW with data " "length %d, actual length is %d\n", - dev->datalen, dev->urb->actual_length); + dev->info->datalen, dev->urb->actual_length); dev->overflow_warned = true; } case -ECONNRESET: @@ -377,7 +415,7 @@ static int atp_status_check(struct urb *urb) } /* drop incomplete datasets */ - if (dev->urb->actual_length != dev->datalen) { + if (dev->urb->actual_length != dev->info->datalen) { dprintk("appletouch: incomplete data package" " (first byte: %d, length: %d).\n", dev->data[0], dev->urb->actual_length); @@ -387,6 +425,25 @@ static int atp_status_check(struct urb *urb) return ATP_URB_STATUS_SUCCESS; } +static void atp_detect_size(struct atp *dev) +{ + int i; + + /* 17" Powerbooks have extra X sensors */ + for (i = dev->info->xsensors; i < ATP_XSENSORS; i++) { + if (dev->xy_cur[i]) { + + printk(KERN_INFO "appletouch: 17\" model detected.\n"); + + input_set_abs_params(dev->input, ABS_X, 0, + (dev->info->xsensors_17 - 1) * + dev->info->xfact - 1, + ATP_FUZZ, 0); + break; + } + } +} + /* * USB interrupt callback functions */ @@ -407,7 +464,7 @@ static void atp_complete_geyser_1_2(struct urb *urb) goto exit; /* reorder the sensors values */ - if (dev->type == ATP_GEYSER2) { + if (dev->info == &geyser2_info) { memset(dev->xy_cur, 0, sizeof(dev->xy_cur)); /* @@ -437,8 +494,8 @@ static void atp_complete_geyser_1_2(struct urb *urb) dev->xy_cur[i + 24] = dev->data[5 * i + 44]; /* Y values */ - dev->xy_cur[i + 26] = dev->data[5 * i + 1]; - dev->xy_cur[i + 34] = dev->data[5 * i + 3]; + dev->xy_cur[ATP_XSENSORS + i] = dev->data[5 * i + 1]; + dev->xy_cur[ATP_XSENSORS + i + 8] = dev->data[5 * i + 3]; } } @@ -453,32 +510,8 @@ static void atp_complete_geyser_1_2(struct urb *urb) memcpy(dev->xy_old, dev->xy_cur, sizeof(dev->xy_old)); /* Perform size detection, if not done already */ - if (!dev->size_detect_done) { - - /* 17" Powerbooks have extra X sensors */ - for (i = (dev->type == ATP_GEYSER2 ? 15 : 16); - i < ATP_XSENSORS; i++) { - if (!dev->xy_cur[i]) - continue; - - printk(KERN_INFO - "appletouch: 17\" model detected.\n"); - - if (dev->type == ATP_GEYSER2) - input_set_abs_params(dev->input, ABS_X, - 0, - (20 - 1) * - ATP_XFACT - 1, - ATP_FUZZ, 0); - else - input_set_abs_params(dev->input, ABS_X, - 0, - (26 - 1) * - ATP_XFACT - 1, - ATP_FUZZ, 0); - break; - } - + if (unlikely(!dev->size_detect_done)) { + atp_detect_size(dev); dev->size_detect_done = 1; goto exit; } @@ -499,10 +532,10 @@ static void atp_complete_geyser_1_2(struct urb *urb) dbg_dump("accumulator", dev->xy_acc); x = atp_calculate_abs(dev->xy_acc, ATP_XSENSORS, - ATP_XFACT, &x_z, &x_f); + dev->info->xfact, &x_z, &x_f); y = atp_calculate_abs(dev->xy_acc + ATP_XSENSORS, ATP_YSENSORS, - ATP_YFACT, &y_z, &y_f); - key = dev->data[dev->datalen - 1] & ATP_STATUS_BUTTON; + dev->info->yfact, &y_z, &y_f); + key = dev->data[dev->info->datalen - 1] & ATP_STATUS_BUTTON; if (x && y) { if (dev->x_old != -1) { @@ -583,7 +616,7 @@ static void atp_complete_geyser_3_4(struct urb *urb) dbg_dump("sample", dev->xy_cur); /* Just update the base values (i.e. touchpad in untouched state) */ - if (dev->data[dev->datalen - 1] & ATP_STATUS_BASE_UPDATE) { + if (dev->data[dev->info->datalen - 1] & ATP_STATUS_BASE_UPDATE) { dprintk(KERN_DEBUG "appletouch: updated base values\n"); @@ -610,10 +643,10 @@ static void atp_complete_geyser_3_4(struct urb *urb) dbg_dump("accumulator", dev->xy_acc); x = atp_calculate_abs(dev->xy_acc, ATP_XSENSORS, - ATP_XFACT, &x_z, &x_f); + dev->info->xfact, &x_z, &x_f); y = atp_calculate_abs(dev->xy_acc + ATP_XSENSORS, ATP_YSENSORS, - ATP_YFACT, &y_z, &y_f); - key = dev->data[dev->datalen - 1] & ATP_STATUS_BUTTON; + dev->info->yfact, &y_z, &y_f); + key = dev->data[dev->info->datalen - 1] & ATP_STATUS_BUTTON; if (x && y) { if (dev->x_old != -1) { @@ -705,7 +738,7 @@ static int atp_handle_geyser(struct atp *dev) { struct usb_device *udev = dev->udev; - if (dev->type != ATP_FOUNTAIN) { + if (dev->info != &fountain_info) { /* switch to raw sensor mode */ if (atp_geyser_init(udev)) return -EIO; @@ -726,6 +759,7 @@ static int atp_probe(struct usb_interface *iface, struct usb_endpoint_descriptor *endpoint; int int_in_endpointAddr = 0; int i, error = -ENOMEM; + const struct atp_info *info = (const struct atp_info *)id->driver_info; /* set up the endpoint information */ /* use only the first interrupt-in endpoint */ @@ -753,35 +787,22 @@ static int atp_probe(struct usb_interface *iface, dev->udev = udev; dev->input = input_dev; - dev->type = id->driver_info; + dev->info = info; dev->overflow_warned = false; - if (dev->type == ATP_FOUNTAIN || dev->type == ATP_GEYSER1) - dev->datalen = 81; - else - dev->datalen = 64; dev->urb = usb_alloc_urb(0, GFP_KERNEL); if (!dev->urb) goto err_free_devs; - dev->data = usb_buffer_alloc(dev->udev, dev->datalen, GFP_KERNEL, + dev->data = usb_buffer_alloc(dev->udev, dev->info->datalen, GFP_KERNEL, &dev->urb->transfer_dma); if (!dev->data) goto err_free_urb; - /* Select the USB complete (callback) function */ - if (dev->type == ATP_FOUNTAIN || - dev->type == ATP_GEYSER1 || - dev->type == ATP_GEYSER2) - usb_fill_int_urb(dev->urb, udev, - usb_rcvintpipe(udev, int_in_endpointAddr), - dev->data, dev->datalen, - atp_complete_geyser_1_2, dev, 1); - else - usb_fill_int_urb(dev->urb, udev, - usb_rcvintpipe(udev, int_in_endpointAddr), - dev->data, dev->datalen, - atp_complete_geyser_3_4, dev, 1); + usb_fill_int_urb(dev->urb, udev, + usb_rcvintpipe(udev, int_in_endpointAddr), + dev->data, dev->info->datalen, + dev->info->callback, dev, 1); error = atp_handle_geyser(dev); if (error) @@ -802,35 +823,12 @@ static int atp_probe(struct usb_interface *iface, set_bit(EV_ABS, input_dev->evbit); - if (dev->type == ATP_GEYSER3 || dev->type == ATP_GEYSER4) { - /* - * MacBook have 20 X sensors, 10 Y sensors - */ - input_set_abs_params(input_dev, ABS_X, 0, - ((20 - 1) * ATP_XFACT) - 1, ATP_FUZZ, 0); - input_set_abs_params(input_dev, ABS_Y, 0, - ((10 - 1) * ATP_YFACT) - 1, ATP_FUZZ, 0); - } else if (dev->type == ATP_GEYSER2) { - /* - * Oct 2005 15" PowerBooks have 15 X sensors, 17" are detected - * later. - */ - input_set_abs_params(input_dev, ABS_X, 0, - ((15 - 1) * ATP_XFACT) - 1, ATP_FUZZ, 0); - input_set_abs_params(input_dev, ABS_Y, 0, - ((9 - 1) * ATP_YFACT) - 1, ATP_FUZZ, 0); - } else { - /* - * 12" and 15" Powerbooks only have 16 x sensors, - * 17" models are detected later. - */ - input_set_abs_params(input_dev, ABS_X, 0, - (16 - 1) * ATP_XFACT - 1, - ATP_FUZZ, 0); - input_set_abs_params(input_dev, ABS_Y, 0, - (ATP_YSENSORS - 1) * ATP_YFACT - 1, - ATP_FUZZ, 0); - } + input_set_abs_params(input_dev, ABS_X, 0, + (dev->info->xsensors - 1) * dev->info->xfact - 1, + ATP_FUZZ, 0); + input_set_abs_params(input_dev, ABS_Y, 0, + (dev->info->ysensors - 1) * dev->info->yfact - 1, + ATP_FUZZ, 0); input_set_abs_params(input_dev, ABS_PRESSURE, 0, ATP_PRESSURE, 0, 0); set_bit(EV_KEY, input_dev->evbit); @@ -852,7 +850,7 @@ static int atp_probe(struct usb_interface *iface, return 0; err_free_buffer: - usb_buffer_free(dev->udev, dev->datalen, + usb_buffer_free(dev->udev, dev->info->datalen, dev->data, dev->urb->transfer_dma); err_free_urb: usb_free_urb(dev->urb); @@ -871,7 +869,7 @@ static void atp_disconnect(struct usb_interface *iface) if (dev) { usb_kill_urb(dev->urb); input_unregister_device(dev->input); - usb_buffer_free(dev->udev, dev->datalen, + usb_buffer_free(dev->udev, dev->info->datalen, dev->data, dev->urb->transfer_dma); usb_free_urb(dev->urb); kfree(dev); -- cgit v1.2.3 From 3cf35049d8b2ccab62bbb8991ad1322ff2276840 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 28 Oct 2008 23:53:19 -0400 Subject: Input: omap-keypad - interrupt disable fix The GPIO interrupts are disabled several times after the first key press. No need to disable - again - the interrupts in the omap_kp_scan_keypad function on OMAP2. Signed-off-by: Peter Ujfalusi Signed-off-by: Tony Lindgren Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/omap-keypad.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/input/keyboard/omap-keypad.c b/drivers/input/keyboard/omap-keypad.c index 69e674ecf19a..a016c8d85a3d 100644 --- a/drivers/input/keyboard/omap-keypad.c +++ b/drivers/input/keyboard/omap-keypad.c @@ -122,10 +122,6 @@ static void omap_kp_scan_keypad(struct omap_kp *omap_kp, unsigned char *state) /* read the keypad status */ if (cpu_is_omap24xx()) { - int i; - for (i = 0; i < omap_kp->rows; i++) - disable_irq(OMAP_GPIO_IRQ(row_gpios[i])); - /* read the keypad status */ for (col = 0; col < omap_kp->cols; col++) { set_col_gpio_val(omap_kp, ~(1 << col)); -- cgit v1.2.3 From dde4ac07263161264d089c7556d0295487787b77 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 28 Oct 2008 23:53:25 -0400 Subject: Input: omap-keypad - allow more than 6 rows There is no reason to limit the GPIO rows to 6 for OMAP2. Signed-off-by: Peter Ujfalusi Signed-off-by: Tony Lindgren Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/omap-keypad.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/input/keyboard/omap-keypad.c b/drivers/input/keyboard/omap-keypad.c index a016c8d85a3d..ec0ebee46069 100644 --- a/drivers/input/keyboard/omap-keypad.c +++ b/drivers/input/keyboard/omap-keypad.c @@ -125,7 +125,7 @@ static void omap_kp_scan_keypad(struct omap_kp *omap_kp, unsigned char *state) /* read the keypad status */ for (col = 0; col < omap_kp->cols; col++) { set_col_gpio_val(omap_kp, ~(1 << col)); - state[col] = ~(get_row_gpio_val(omap_kp)) & 0x3f; + state[col] = ~(get_row_gpio_val(omap_kp)) & 0xff; } set_col_gpio_val(omap_kp, 0); -- cgit v1.2.3 From a6c2490f010d9235b1424110c6f414460e41dfe1 Mon Sep 17 00:00:00 2001 From: Kay Sievers Date: Thu, 30 Oct 2008 00:07:50 -0400 Subject: Input: struct device - replace bus_id with dev_name(), dev_set_name() Acked-by: Greg Kroah-Hartman Signed-off-by: Kay Sievers Signed-off-by: Dmitry Torokhov --- drivers/input/evbug.c | 6 +++--- drivers/input/evdev.c | 2 +- drivers/input/gameport/gameport.c | 3 +-- drivers/input/gameport/ns558.c | 2 +- drivers/input/input.c | 4 ++-- drivers/input/joydev.c | 2 +- drivers/input/mousedev.c | 3 +-- drivers/input/serio/pcips2.c | 2 +- drivers/input/serio/serio.c | 4 ++-- drivers/input/touchscreen/ads7846.c | 4 ++-- 10 files changed, 15 insertions(+), 17 deletions(-) diff --git a/drivers/input/evbug.c b/drivers/input/evbug.c index 0353601ac3b5..f7c5c14ec12a 100644 --- a/drivers/input/evbug.c +++ b/drivers/input/evbug.c @@ -39,7 +39,7 @@ MODULE_LICENSE("GPL"); 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", - handle->dev->dev.bus_id, type, code, value); + dev_name(&handle->dev->dev), type, code, value); } static int evbug_connect(struct input_handler *handler, struct input_dev *dev, @@ -65,7 +65,7 @@ static int evbug_connect(struct input_handler *handler, struct input_dev *dev, goto err_unregister_handle; printk(KERN_DEBUG "evbug.c: Connected device: %s (%s at %s)\n", - dev->dev.bus_id, + dev_name(&dev->dev), dev->name ?: "unknown", dev->phys ?: "unknown"); @@ -81,7 +81,7 @@ static int evbug_connect(struct input_handler *handler, struct input_dev *dev, static void evbug_disconnect(struct input_handle *handle) { printk(KERN_DEBUG "evbug.c: Disconnected device: %s\n", - handle->dev->dev.bus_id); + dev_name(&handle->dev->dev)); input_close_device(handle); input_unregister_handle(handle); diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c index 377b2007377e..c69a58fe54d8 100644 --- a/drivers/input/evdev.c +++ b/drivers/input/evdev.c @@ -820,7 +820,7 @@ static int evdev_connect(struct input_handler *handler, struct input_dev *dev, evdev->handle.handler = handler; evdev->handle.private = evdev; - strlcpy(evdev->dev.bus_id, evdev->name, sizeof(evdev->dev.bus_id)); + dev_set_name(&evdev->dev, evdev->name); evdev->dev.devt = MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + minor); evdev->dev.class = &input_class; evdev->dev.parent = &dev->dev; diff --git a/drivers/input/gameport/gameport.c b/drivers/input/gameport/gameport.c index 2880eaae157a..ebf4be5b7c4e 100644 --- a/drivers/input/gameport/gameport.c +++ b/drivers/input/gameport/gameport.c @@ -530,8 +530,7 @@ static void gameport_init_port(struct gameport *gameport) mutex_init(&gameport->drv_mutex); device_initialize(&gameport->dev); - snprintf(gameport->dev.bus_id, sizeof(gameport->dev.bus_id), - "gameport%lu", (unsigned long)atomic_inc_return(&gameport_no) - 1); + dev_set_name(&gameport->dev, "gameport%lu", (unsigned long)atomic_inc_return(&gameport_no) - 1); gameport->dev.bus = &gameport_bus; gameport->dev.release = gameport_release_port; if (gameport->parent) diff --git a/drivers/input/gameport/ns558.c b/drivers/input/gameport/ns558.c index 2b282cde4b89..db556b71ddda 100644 --- a/drivers/input/gameport/ns558.c +++ b/drivers/input/gameport/ns558.c @@ -226,7 +226,7 @@ static int ns558_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *did) ns558->gameport = port; gameport_set_name(port, "NS558 PnP Gameport"); - gameport_set_phys(port, "pnp%s/gameport0", dev->dev.bus_id); + gameport_set_phys(port, "pnp%s/gameport0", dev_name(&dev->dev)); port->dev.parent = &dev->dev; port->io = ioport; diff --git a/drivers/input/input.c b/drivers/input/input.c index c13ced3e0d3d..1730d7331a5d 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c @@ -1389,8 +1389,8 @@ int input_register_device(struct input_dev *dev) if (!dev->setkeycode) dev->setkeycode = input_default_setkeycode; - snprintf(dev->dev.bus_id, sizeof(dev->dev.bus_id), - "input%ld", (unsigned long) atomic_inc_return(&input_no) - 1); + dev_set_name(&dev->dev, "input%ld", + (unsigned long) atomic_inc_return(&input_no) - 1); error = device_add(&dev->dev); if (error) diff --git a/drivers/input/joydev.c b/drivers/input/joydev.c index 65d7077a75a1..f9b876bd378d 100644 --- a/drivers/input/joydev.c +++ b/drivers/input/joydev.c @@ -801,7 +801,7 @@ static int joydev_connect(struct input_handler *handler, struct input_dev *dev, } } - strlcpy(joydev->dev.bus_id, joydev->name, sizeof(joydev->dev.bus_id)); + dev_set_name(&joydev->dev, joydev->name); joydev->dev.devt = MKDEV(INPUT_MAJOR, JOYDEV_MINOR_BASE + minor); joydev->dev.class = &input_class; joydev->dev.parent = &dev->dev; diff --git a/drivers/input/mousedev.c b/drivers/input/mousedev.c index 8137e50ded87..4ab8b28bace8 100644 --- a/drivers/input/mousedev.c +++ b/drivers/input/mousedev.c @@ -879,8 +879,7 @@ static struct mousedev *mousedev_create(struct input_dev *dev, mousedev->handle.handler = handler; mousedev->handle.private = mousedev; - strlcpy(mousedev->dev.bus_id, mousedev->name, - sizeof(mousedev->dev.bus_id)); + dev_set_name(&mousedev->dev, mousedev->name); mousedev->dev.class = &input_class; if (dev) mousedev->dev.parent = &dev->dev; diff --git a/drivers/input/serio/pcips2.c b/drivers/input/serio/pcips2.c index 1b404f9e3bff..1dacbe0d9348 100644 --- a/drivers/input/serio/pcips2.c +++ b/drivers/input/serio/pcips2.c @@ -153,7 +153,7 @@ static int __devinit pcips2_probe(struct pci_dev *dev, const struct pci_device_i serio->open = pcips2_open; serio->close = pcips2_close; strlcpy(serio->name, pci_name(dev), sizeof(serio->name)); - strlcpy(serio->phys, dev->dev.bus_id, sizeof(serio->phys)); + strlcpy(serio->phys, dev_name(&dev->dev), sizeof(serio->phys)); serio->port_data = ps2if; serio->dev.parent = &dev->dev; ps2if->io = serio; diff --git a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c index 2f12d60eee3b..bc033250dfcd 100644 --- a/drivers/input/serio/serio.c +++ b/drivers/input/serio/serio.c @@ -546,8 +546,8 @@ static void serio_init_port(struct serio *serio) spin_lock_init(&serio->lock); mutex_init(&serio->drv_mutex); device_initialize(&serio->dev); - snprintf(serio->dev.bus_id, sizeof(serio->dev.bus_id), - "serio%ld", (long)atomic_inc_return(&serio_no) - 1); + dev_set_name(&serio->dev, "serio%ld", + (long)atomic_inc_return(&serio_no) - 1); serio->dev.bus = &serio_bus; serio->dev.release = serio_release_port; if (serio->parent) { diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c index b9b7fc6ff1eb..6017ea6e994e 100644 --- a/drivers/input/touchscreen/ads7846.c +++ b/drivers/input/touchscreen/ads7846.c @@ -559,7 +559,7 @@ static void ads7846_rx(void *ads) if (packet->tc.ignore || Rt > ts->pressure_max) { #ifdef VERBOSE pr_debug("%s: ignored %d pressure %d\n", - ts->spi->dev.bus_id, packet->tc.ignore, Rt); + dev_name(&ts->spi->dev), packet->tc.ignore, Rt); #endif hrtimer_start(&ts->timer, ktime_set(0, TS_POLL_PERIOD), HRTIMER_MODE_REL); @@ -947,7 +947,7 @@ static int __devinit ads7846_probe(struct spi_device *spi) ts->penirq_recheck_delay_usecs = pdata->penirq_recheck_delay_usecs; - snprintf(ts->phys, sizeof(ts->phys), "%s/input0", spi->dev.bus_id); + snprintf(ts->phys, sizeof(ts->phys), "%s/input0", dev_name(&spi->dev)); input_dev->name = "ADS784x Touchscreen"; input_dev->phys = ts->phys; -- cgit v1.2.3 From 2ec6f246c33a0b830a6ad3171161e9d880e2251e Mon Sep 17 00:00:00 2001 From: Nuno Lucas Date: Tue, 11 Nov 2008 16:48:04 -0500 Subject: Input: usbtouchscreen - fix TSC-10 DM USB controllers without EEPROM The usbtouchscreen module implements a driver for the TSC-10 DM USB touchscreen controllers, but assumes a 2-byte response for the CMD_RESET and CMD_RATE commands, when they can be only a single byte when no EEPROM is connected. The driver worked with an earlier controller revision, but new revisions of the controller fail. It seems the problem is that the early controller had the SEL4/EEPROM-CS pin high, but the new controller has it down, making the response different. Without the fix, the controller would answer the single byte 0x06 (ACK), making the init fail with -ENODEV because buf[1] is 0xFF (as initialized before). As the single byte is the only thing we need to check it was ok, there is no need to verify the second byte. The [0x15 0x01] case is the NAK [0x15] response for when there is no data in the EEPROM [bit-0 of second byte set], so I let that be, as I don't have any controller with an EEPROM. With this patch, both the earlier and latest controller work the same. Note: This was previously submited as BUG #11961 [1] on the bugzilla tracker, but rebased to version 2.6.27.4 and with unnecessary comments and printk's removed. [1] http://bugzilla.kernel.org/show_bug.cgi?id=11961 Signed-off-by: Nuno Lucas Acked-by: Daniel Ritz Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/usbtouchscreen.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/input/touchscreen/usbtouchscreen.c b/drivers/input/touchscreen/usbtouchscreen.c index fdd645c214a2..5080b26ba160 100644 --- a/drivers/input/touchscreen/usbtouchscreen.c +++ b/drivers/input/touchscreen/usbtouchscreen.c @@ -424,7 +424,7 @@ static int dmc_tsc10_init(struct usbtouch_usb *usbtouch) 0, 0, buf, 2, USB_CTRL_SET_TIMEOUT); if (ret < 0) goto err_out; - if (buf[0] != 0x06 || buf[1] != 0x00) { + if (buf[0] != 0x06) { ret = -ENODEV; goto err_out; } @@ -437,8 +437,7 @@ static int dmc_tsc10_init(struct usbtouch_usb *usbtouch) TSC10_RATE_150, 0, buf, 2, USB_CTRL_SET_TIMEOUT); if (ret < 0) goto err_out; - if ((buf[0] != 0x06 || buf[1] != 0x00) && - (buf[0] !