aboutsummaryrefslogtreecommitdiff
path: root/drivers/input
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/input')
-rw-r--r--drivers/input/evdev.c407
-rw-r--r--drivers/input/gameport/Kconfig14
-rw-r--r--drivers/input/gameport/Makefile2
-rw-r--r--drivers/input/gameport/cs461x.c322
-rw-r--r--drivers/input/gameport/gameport.c34
-rw-r--r--drivers/input/gameport/ns558.c12
-rw-r--r--drivers/input/gameport/vortex.c186
-rw-r--r--drivers/input/input.c37
-rw-r--r--drivers/input/joydev.c116
-rw-r--r--drivers/input/joystick/a3d.c2
-rw-r--r--drivers/input/joystick/adi.c4
-rw-r--r--drivers/input/joystick/amijoy.c29
-rw-r--r--drivers/input/joystick/analog.c4
-rw-r--r--drivers/input/joystick/db9.c17
-rw-r--r--drivers/input/joystick/gamecon.c29
-rw-r--r--drivers/input/joystick/gf2k.c2
-rw-r--r--drivers/input/joystick/grip_mp.c2
-rw-r--r--drivers/input/joystick/iforce/iforce-main.c1
-rw-r--r--drivers/input/joystick/iforce/iforce-usb.c1
-rw-r--r--drivers/input/joystick/spaceball.c4
-rw-r--r--drivers/input/joystick/spaceorb.c2
-rw-r--r--drivers/input/joystick/tmdc.c2
-rw-r--r--drivers/input/joystick/turbografx.c35
-rw-r--r--drivers/input/keyboard/atkbd.c6
-rw-r--r--drivers/input/keyboard/corgikbd.c6
-rw-r--r--drivers/input/keyboard/lkkbd.c8
-rw-r--r--drivers/input/keyboard/locomokbd.c28
-rw-r--r--drivers/input/keyboard/maple_keyb.c22
-rw-r--r--drivers/input/misc/uinput.c6
-rw-r--r--drivers/input/mouse/Makefile2
-rw-r--r--drivers/input/mouse/alps.c52
-rw-r--r--drivers/input/mouse/amimouse.c8
-rw-r--r--drivers/input/mouse/inport.c38
-rw-r--r--drivers/input/mouse/lifebook.c134
-rw-r--r--drivers/input/mouse/lifebook.h17
-rw-r--r--drivers/input/mouse/logibm.c17
-rw-r--r--drivers/input/mouse/maplemouse.c75
-rw-r--r--drivers/input/mouse/pc110pad.c21
-rw-r--r--drivers/input/mouse/psmouse-base.c351
-rw-r--r--drivers/input/mouse/psmouse.h4
-rw-r--r--drivers/input/mouse/rpcmouse.c2
-rw-r--r--drivers/input/mouse/vsxxxaa.c4
-rw-r--r--drivers/input/mousedev.c8
-rw-r--r--drivers/input/serio/libps2.c136
-rw-r--r--drivers/input/serio/serio.c89
-rw-r--r--drivers/input/touchscreen/elo.c2
-rw-r--r--drivers/input/touchscreen/h3600_ts_input.c180
-rw-r--r--drivers/input/touchscreen/mk712.c21
48 files changed, 1394 insertions, 1107 deletions
diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c
index 556264b4342..374f404e81d 100644
--- a/drivers/input/evdev.c
+++ b/drivers/input/evdev.c
@@ -21,6 +21,7 @@
#include <linux/smp_lock.h>
#include <linux/device.h>
#include <linux/devfs_fs_kernel.h>
+#include <linux/compat.h>
struct evdev {
int exist;
@@ -145,6 +146,41 @@ static int evdev_open(struct inode * inode, struct file * file)
return 0;
}
+#ifdef CONFIG_COMPAT
+struct input_event_compat {
+ struct compat_timeval time;
+ __u16 type;
+ __u16 code;
+ __s32 value;
+};
+
+#ifdef CONFIG_X86_64
+# define COMPAT_TEST test_thread_flag(TIF_IA32)
+#elif defined(CONFIG_IA64)
+# define COMPAT_TEST IS_IA32_PROCESS(ia64_task_regs(current))
+#elif defined(CONFIG_ARCH_S390)
+# define COMPAT_TEST test_thread_flag(TIF_31BIT)
+#else
+# 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)
+{
+ struct evdev_list *list = file->private_data;
+ struct input_event_compat event;
+ int retval = 0;
+
+ while (retval < count) {
+ if (copy_from_user(&event, buffer + retval, sizeof(struct input_event_compat)))
+ return -EFAULT;
+ input_event(list->evdev->handle.dev, event.type, event.code, event.value);
+ retval += sizeof(struct input_event_compat);
+ }
+
+ return retval;
+}
+#endif
+
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;
@@ -153,6 +189,11 @@ static ssize_t evdev_write(struct file * file, const char __user * buffer, size_
if (!list->evdev->exist) return -ENODEV;
+#ifdef CONFIG_COMPAT
+ if (COMPAT_TEST)
+ return evdev_write_compat(file, buffer, count, ppos);
+#endif
+
while (retval < count) {
if (copy_from_user(&event, buffer + retval, sizeof(struct input_event)))
@@ -164,11 +205,56 @@ static ssize_t evdev_write(struct file * file, const char __user * buffer, size_
return retval;
}
+#ifdef CONFIG_COMPAT
+static ssize_t evdev_read_compat(struct file * file, char __user * buffer, size_t count, loff_t *ppos)
+{
+ struct evdev_list *list = file->private_data;
+ int retval;
+
+ if (count < sizeof(struct input_event_compat))
+ return -EINVAL;
+
+ if (list->head == list->tail && list->evdev->exist && (file->f_flags & O_NONBLOCK))
+ return -EAGAIN;
+
+ retval = wait_event_interruptible(list->evdev->wait,
+ list->head != list->tail || (!list->evdev->exist));
+
+ if (retval)
+ return retval;
+
+ 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);
+ }
+
+ 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))
return -EINVAL;
@@ -186,7 +272,7 @@ static ssize_t evdev_read(struct file * file, char __user * buffer, size_t count
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;
+ sizeof(struct input_event))) return -EFAULT;
list->tail = (list->tail + 1) & (EVDEV_BUFFER_SIZE - 1);
retval += sizeof(struct input_event);
}
@@ -203,7 +289,7 @@ static unsigned int evdev_poll(struct file *file, poll_table *wait)
(list->evdev->exist ? 0 : (POLLHUP | POLLERR));
}
-static int evdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+static long evdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
struct evdev_list *list = file->private_data;
struct evdev *evdev = list->evdev;
@@ -285,109 +371,267 @@ static int evdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
default:
- if (_IOC_TYPE(cmd) != 'E' || _IOC_DIR(cmd) != _IOC_READ)
+ if (_IOC_TYPE(cmd) != 'E')
return -EINVAL;
- if ((_IOC_NR(cmd) & ~EV_MAX) == _IOC_NR(EVIOCGBIT(0,0))) {
-
- long *bits;
- int len;
-
- switch (_IOC_NR(cmd) & EV_MAX) {
- case 0: bits = dev->evbit; len = EV_MAX; break;
- case EV_KEY: bits = dev->keybit; len = KEY_MAX; break;
- case EV_REL: bits = dev->relbit; len = REL_MAX; break;
- case EV_ABS: bits = dev->absbit; len = ABS_MAX; break;
- case EV_MSC: bits = dev->mscbit; len = MSC_MAX; break;
- case EV_LED: bits = dev->ledbit; len = LED_MAX; break;
- case EV_SND: bits = dev->sndbit; len = SND_MAX; break;
- case EV_FF: bits = dev->ffbit; len = FF_MAX; break;
- default: return -EINVAL;
+ if (_IOC_DIR(cmd) == _IOC_READ) {
+
+ if ((_IOC_NR(cmd) & ~EV_MAX) == _IOC_NR(EVIOCGBIT(0,0))) {
+
+ long *bits;
+ int len;
+
+ switch (_IOC_NR(cmd) & EV_MAX) {
+ case 0: bits = dev->evbit; len = EV_MAX; break;
+ case EV_KEY: bits = dev->keybit; len = KEY_MAX; break;
+ case EV_REL: bits = dev->relbit; len = REL_MAX; break;
+ case EV_ABS: bits = dev->absbit; len = ABS_MAX; break;
+ case EV_MSC: bits = dev->mscbit; len = MSC_MAX; break;
+ case EV_LED: bits = dev->ledbit; len = LED_MAX; break;
+ case EV_SND: bits = dev->sndbit; len = SND_MAX; break;
+ case EV_FF: bits = dev->ffbit; len = FF_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;
}
- len = NBITS(len) * sizeof(long);
- if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
- return copy_to_user(p, bits, len) ? -EFAULT : len;
- }
- 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))) {
+ 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(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))) {
+ 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(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))) {
+ 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(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))) {
+ 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_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_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;
+}
- if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCGABS(0))) {
+#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*) 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_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);
- int t = _IOC_NR(cmd) & ABS_MAX;
+ if (!evdev->exist) return -ENODEV;
- 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];
+ switch (cmd) {
- if (copy_to_user(p, &abs, sizeof(struct input_absinfo)))
- return -EFAULT;
+ case EVIOCGVERSION:
+ case EVIOCGID:
+ case EVIOCGKEYCODE:
+ case EVIOCSKEYCODE:
+ case EVIOCSFF:
+ case EVIOCRMFF:
+ case EVIOCGEFFECTS:
+ case EVIOCGRAB:
+ return evdev_ioctl(file, cmd, (unsigned long) p);
- return 0;
+ 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;
+ 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(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_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCSABS(0))) {
+ if (_IOC_DIR(cmd) == _IOC_WRITE) {
- int t = _IOC_NR(cmd) & ABS_MAX;
+ if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCSABS(0))) {
- if (copy_from_user(&abs, p, sizeof(struct input_absinfo)))
- return -EFAULT;
+ int t = _IOC_NR(cmd) & ABS_MAX;
- 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;
+ if (copy_from_user(&abs, p, sizeof(struct input_absinfo)))
+ return -EFAULT;
- return 0;
+ 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;
}
+#endif
static struct file_operations evdev_fops = {
.owner = THIS_MODULE,
@@ -396,7 +640,10 @@ static struct file_operations evdev_fops = {
.poll = evdev_poll,
.open = evdev_open,
.release = evdev_release,
- .ioctl = evdev_ioctl,
+ .unlocked_ioctl = evdev_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = evdev_ioctl_compat,
+#endif
.fasync = evdev_fasync,
.flush = evdev_flush
};
diff --git a/drivers/input/gameport/Kconfig b/drivers/input/gameport/Kconfig
index 1d93f509290..7524bd7d8b8 100644
--- a/drivers/input/gameport/Kconfig
+++ b/drivers/input/gameport/Kconfig
@@ -49,22 +49,8 @@ config GAMEPORT_EMU10K1
To compile this driver as a module, choose M here: the
module will be called emu10k1-gp.
-config GAMEPORT_VORTEX
- tristate "Aureal Vortex, Vortex 2 gameport support"
- depends on PCI
- help
- Say Y here if you have an Aureal Vortex 1 or 2 card and want
- to use its gameport.
-
- To compile this driver as a module, choose M here: the
- module will be called vortex.
-
config GAMEPORT_FM801
tristate "ForteMedia FM801 gameport support"
depends on PCI
-config GAMEPORT_CS461X
- tristate "Crystal SoundFusion gameport support"
- depends on PCI
-
endif
diff --git a/drivers/input/gameport/Makefile b/drivers/input/gameport/Makefile
index 5367b4267ad..b6f6097bd8c 100644
--- a/drivers/input/gameport/Makefile
+++ b/drivers/input/gameport/Makefile
@@ -5,9 +5,7 @@
# Each configuration option enables a list of files.
obj-$(CONFIG_GAMEPORT) += gameport.o
-obj-$(CONFIG_GAMEPORT_CS461X) += cs461x.o
obj-$(CONFIG_GAMEPORT_EMU10K1) += emu10k1-gp.o
obj-$(CONFIG_GAMEPORT_FM801) += fm801-gp.o
obj-$(CONFIG_GAMEPORT_L4) += lightning.o
obj-$(CONFIG_GAMEPORT_NS558) += ns558.o
-obj-$(CONFIG_GAMEPORT_VORTEX) += vortex.o
diff --git a/drivers/input/gameport/cs461x.c b/drivers/input/gameport/cs461x.c
deleted file mode 100644
index d4013ff9862..00000000000
--- a/drivers/input/gameport/cs461x.c
+++ /dev/null
@@ -1,322 +0,0 @@
-/*
- The all defines and part of code (such as cs461x_*) are
- contributed from ALSA 0.5.8 sources.
- See http://www.alsa-project.org/ for sources
-
- Tested on Linux 686 2.4.0-test9, ALSA 0.5.8a and CS4610
-*/
-
-#include <asm/io.h>
-
-#include <linux/module.h>
-#include <linux/ioport.h>
-#include <linux/config.h>
-#include <linux/init.h>
-#include <linux/gameport.h>
-#include <linux/slab.h>
-#include <linux/pci.h>
-
-MODULE_AUTHOR("Victor Krapivin");
-MODULE_LICENSE("GPL");
-
-/*
- These options are experimental
-
-#define CS461X_FULL_MAP
-*/
-
-
-#ifndef PCI_VENDOR_ID_CIRRUS
-#define PCI_VENDOR_ID_CIRRUS 0x1013
-#endif
-#ifndef PCI_DEVICE_ID_CIRRUS_4610
-#define PCI_DEVICE_ID_CIRRUS_4610 0x6001
-#endif
-#ifndef PCI_DEVICE_ID_CIRRUS_4612
-#define PCI_DEVICE_ID_CIRRUS_4612 0x6003
-#endif
-#ifndef PCI_DEVICE_ID_CIRRUS_4615
-#define PCI_DEVICE_ID_CIRRUS_4615 0x6004
-#endif
-
-/* Registers */
-
-#define BA0_JSPT 0x00000480
-#define BA0_JSCTL 0x00000484
-#define BA0_JSC1 0x00000488
-#define BA0_JSC2 0x0000048C
-#define BA0_JSIO 0x000004A0
-
-/* Bits for JSPT */
-
-#define JSPT_CAX 0x00000001
-#define JSPT_CAY 0x00000002
-#define JSPT_CBX 0x00000004
-#define JSPT_CBY 0x00000008
-#define JSPT_BA1 0x00000010
-#define JSPT_BA2 0x00000020
-#define JSPT_BB1 0x00000040
-#define JSPT_BB2 0x00000080
-
-/* Bits for JSCTL */
-
-#define JSCTL_SP_MASK 0x00000003
-#define JSCTL_SP_SLOW 0x00000000
-#define JSCTL_SP_MEDIUM_SLOW 0x00000001
-#define JSCTL_SP_MEDIUM_FAST 0x00000002
-#define JSCTL_SP_FAST 0x00000003
-#define JSCTL_ARE 0x00000004
-
-/* Data register pairs masks */
-
-#define JSC1_Y1V_MASK 0x0000FFFF
-#define JSC1_X1V_MASK 0xFFFF0000
-#define JSC1_Y1V_SHIFT 0
-#define JSC1_X1V_SHIFT 16
-#define JSC2_Y2V_MASK 0x0000FFFF
-#define JSC2_X2V_MASK 0xFFFF0000
-#define JSC2_Y2V_SHIFT 0
-#define JSC2_X2V_SHIFT 16
-
-/* JS GPIO */
-
-#define JSIO_DAX 0x00000001
-#define JSIO_DAY 0x00000002
-#define JSIO_DBX 0x00000004
-#define JSIO_DBY 0x00000008
-#define JSIO_AXOE 0x00000010
-#define JSIO_AYOE 0x00000020
-#define JSIO_BXOE 0x00000040
-#define JSIO_BYOE 0x00000080
-
-/*
- The card initialization code is obfuscated; the module cs461x
- need to be loaded after ALSA modules initialized and something
- played on the CS 4610 chip (see sources for details of CS4610
- initialization code from ALSA)
-*/
-
-/* Card specific definitions */
-
-#define CS461X_BA0_SIZE 0x2000
-#define CS461X_BA1_DATA0_SIZE 0x3000
-#define CS461X_BA1_DATA1_SIZE 0x3800
-#define CS461X_BA1_PRG_SIZE 0x7000
-#define CS461X_BA1_REG_SIZE 0x0100
-
-#define BA1_SP_DMEM0 0x00000000
-#define BA1_SP_DMEM1 0x00010000
-#define BA1_SP_PMEM 0x00020000
-#define BA1_SP_REG 0x00030000
-
-#define BA1_DWORD_SIZE (13 * 1024 + 512)
-#define BA1_MEMORY_COUNT 3
-
-/*
- Only one CS461x card is still suppoted; the code requires
- redesign to avoid this limitatuion.
-*/
-
-static unsigned long ba0_addr;
-static unsigned int __iomem *ba0;
-
-#ifdef CS461X_FULL_MAP
-static unsigned long ba1_addr;
-static union ba1_t {
- struct {
- unsigned int __iomem *data0;
- unsigned int __iomem *data1;
- unsigned int __iomem *pmem;
- unsigned int __iomem *reg;
- } name;
- unsigned int __iomem *idx[4];
-} ba1;
-
-static void cs461x_poke(unsigned long reg, unsigned int val)
-{
- writel(val, &ba1.idx[(reg >> 16) & 3][(reg >> 2) & 0x3fff]);
-}
-
-static unsigned int cs461x_peek(unsigned long reg)
-{
- return readl(&ba1.idx[(reg >> 16) & 3][(reg >> 2) & 0x3fff]);
-}
-
-#endif
-
-static void cs461x_pokeBA0(unsigned long reg, unsigned int val)
-{
- writel(val, &ba0[reg >> 2]);
-}
-
-static unsigned int cs461x_peekBA0(unsigned long reg)
-{
- return readl(&ba0[reg >> 2]);
-}
-
-static int cs461x_free(struct pci_dev *pdev)
-{
- struct gameport *port = pci_get_drvdata(pdev);
-
- if (port)
- gameport_unregister_port(port);
-
- if (ba0) iounmap(ba0);
-#ifdef CS461X_FULL_MAP
- if (ba1.name.data0) iounmap(ba1.name.data0);
- if (ba1.name.data1) iounmap(ba1.name.data1);
- if (ba1.name.pmem) iounmap(ba1.name.pmem);
- if (ba1.name.reg) iounmap(ba1.name.reg);
-#endif
- return 0;
-}
-
-static void cs461x_gameport_trigger(struct gameport *gameport)
-{
- cs461x_pokeBA0(BA0_JSPT, 0xFF); //outb(gameport->io, 0xFF);
-}
-
-static unsigned char cs461x_gameport_read(struct gameport *gameport)
-{
- return cs461x_peekBA0(BA0_JSPT); //inb(gameport->io);
-}
-
-static int cs461x_gameport_cooked_read(struct gameport *gameport, int *axes, int *buttons)
-{
- unsigned js1, js2, jst;
-
- js1 = cs461x_peekBA0(BA0_JSC1);
- js2 = cs461x_peekBA0(BA0_JSC2);
- jst = cs461x_peekBA0(BA0_JSPT);
-
- *buttons = (~jst >> 4) & 0x0F;
-
- axes[0] = ((js1 & JSC1_Y1V_MASK) >> JSC1_Y1V_SHIFT) & 0xFFFF;
- axes[1] = ((js1 & JSC1_X1V_MASK) >> JSC1_X1V_SHIFT) & 0xFFFF;
- axes[2] = ((js2 & JSC2_Y2V_MASK) >> JSC2_Y2V_SHIFT) & 0xFFFF;
- axes[3] = ((js2 & JSC2_X2V_MASK) >> JSC2_X2V_SHIFT) & 0xFFFF;
-
- for(jst=0;jst<4;++jst)
- if(axes[jst]==0xFFFF) axes[jst] = -1;
- return 0;
-}
-
-static int cs461x_gameport_open(struct gameport *gameport, int mode)
-{
- switch (mode) {
- case GAMEPORT_MODE_COOKED:
- case GAMEPORT_MODE_RAW:
- return 0;
- default:
- return -1;
- }
- return 0;
-}
-
-static struct pci_device_id cs461x_pci_tbl[] = {
- { PCI_VENDOR_ID_CIRRUS, 0x6001, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* Cirrus CS4610 */
- { PCI_VENDOR_ID_CIRRUS, 0x6003, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* Cirrus CS4612 */
- { PCI_VENDOR_ID_CIRRUS, 0x6005, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* Cirrus CS4615 */
- { 0, }
-};
-MODULE_DEVICE_TABLE(pci, cs461x_pci_tbl);
-
-static int __devinit cs461x_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
-{
- int rc;
- struct gameport* port;
-
- rc = pci_enable_device(pdev);
- if (rc) {
- printk(KERN_ERR "cs461x: Cannot enable PCI gameport (bus %d, devfn %d) error=%d\n",
- pdev->bus->number, pdev->devfn, rc);
- return rc;
- }
-
- ba0_addr = pci_resource_start(pdev, 0);
-#ifdef CS461X_FULL_MAP
- ba1_addr = pci_resource_start(pdev, 1);
-#endif
- if (ba0_addr == 0 || ba0_addr == ~0
-#ifdef CS461X_FULL_MAP
- || ba1_addr == 0 || ba1_addr == ~0
-#endif
- ) {
- printk(KERN_ERR "cs461x: wrong address - ba0 = 0x%lx\n", ba0_addr);
-#ifdef CS461X_FULL_MAP
- printk(KERN_ERR "cs461x: wrong address - ba1 = 0x%lx\n", ba1_addr);
-#endif
- cs461x_free(pdev);
- return -ENOMEM;
- }
-
- ba0 = ioremap(ba0_addr, CS461X_BA0_SIZE);
-#ifdef CS461X_FULL_MAP
- ba1.name.data0 = ioremap(ba1_addr + BA1_SP_DMEM0, CS461X_BA1_DATA0_SIZE);
- ba1.name.data1 = ioremap(ba1_addr + BA1_SP_DMEM1, CS461X_BA1_DATA1_SIZE);
- ba1.name.pmem = ioremap(ba1_addr + BA1_SP_PMEM, CS461X_BA1_PRG_SIZE);
- ba1.name.reg = ioremap(ba1_addr + BA1_SP_REG, CS461X_BA1_REG_SIZE);
-
- if (ba0 == NULL || ba1.name.data0 == NULL ||
- ba1.name.data1 == NULL || ba1.name.pmem == NULL ||
- ba1.name.reg == NULL) {
- cs461x_free(pdev);
- return -ENOMEM;
- }
-#else
- if (ba0 == NULL) {
- cs461x_free(pdev);
- return -ENOMEM;
- }
-#endif
-
- if (!(port = gameport_allocate_port())) {
- printk(KERN_ERR "cs461x: Memory allocation failed\n");
- cs461x_free(pdev);
- return -ENOMEM;
- }
-
- pci_set_drvdata(pdev, port);
-
- port->open = cs461x_gameport_open;
- port->trigger = cs461x_gameport_trigger;
- port->read = cs461x_gameport_read;
- port->cooked_read = cs461x_gameport_cooked_read;
-
- gameport_set_name(port, "CS416x");
- gameport_set_phys(port, "pci%s/gameport0", pci_name(pdev));
- port->dev.parent = &pdev->dev;
-
- cs461x_pokeBA0(BA0_JSIO, 0xFF); // ?
- cs461x_pokeBA0(BA0_JSCTL, JSCTL_SP_MEDIUM_SLOW);
-
- gameport_register_port(port);
-
- return 0;
-}
-
-static void __devexit cs461x_pci_remove(struct pci_dev *pdev)
-{
- cs461x_free(pdev);
-}
-
-static struct pci_driver cs461x_pci_driver = {
- .name = "CS461x_gameport",
- .id_table = cs461x_pci_tbl,
- .probe = cs461x_pci_probe,
- .remove = __devexit_p(cs461x_pci_remove),
-};
-
-static int __init cs461x_init(void)
-{
- return pci_register_driver(&cs461x_pci_driver);
-}
-
-static void __exit cs461x_exit(void)
-{
- pci_unregister_driver(&cs461x_pci_driver);
-}
-
-module_init(cs461x_init);
-module_exit(cs461x_exit);
-
diff --git a/drivers/input/gameport/gameport.c b/drivers/input/gameport/gameport.c
index c77a82e4605..ab09cf4093e 100644
--- a/drivers/input/gameport/gameport.c
+++ b/drivers/input/gameport/gameport.c
@@ -17,11 +17,10 @@
#include <linux/init.h>
#include <linux/gameport.h>
#include <linux/wait.h>
-#include <linux/completion.h>
#include <linux/sched.h>
-#include <linux/smp_lock.h>
#include <linux/slab.h>
#include <linux/delay.h>
+#include <linux/kthread.h>
/*#include <asm/io.h>*/
@@ -61,12 +60,13 @@ static void gameport_disconnect_port(struct gameport *gameport);
#if defined(__i386__)
+#include <asm/i8253.h>
+
#define DELTA(x,y) ((y)-(x)+((y)<(x)?1193182/HZ:0))
#define GET_TIME(x) do { x = get_time_pit(); } while (0)
static unsigned int get_time_pit(void)
{
- extern spinlock_t i8253_lock;
unsigned long flags;
unsigned int count;
@@ -238,8 +238,7 @@ struct gameport_event {
static DEFINE_SPINLOCK(gameport_event_lock); /* protects gameport_event_list */
static LIST_HEAD(gameport_event_list);
static DECLARE_WAIT_QUEUE_HEAD(gameport_wait);
-static DECLARE_COMPLETION(gameport_exited);
-static int gameport_pid;
+static struct task_struct *gameport_task;
static void gameport_queue_event(void *object, struct module *owner,
enum gameport_event_type event_type)
@@ -250,12 +249,12 @@ static void gameport_queue_event(void *object, struct module *owner,
spin_lock_irqsave(&gameport_event_lock, flags);
/*
- * Scan event list for the other events for the same gameport port,
+ * Scan event list for the other events for the same gameport port,
* starting with the most recent one. If event is the same we
* do not need add new one. If event is of different type we
* need to add this event and should not look further because
* we need to preseve sequence of distinct events.
- */
+ */
list_for_each_entry_reverse(event, &gameport_event_list, node) {
if (event->object == object) {
if (event->type == event_type)
@@ -432,20 +431,15 @@ static struct gameport *gameport_get_pending_child(struct gameport *parent)
static int gameport_thread(void *nothing)
{
- lock_kernel();
- daemonize("kgameportd");
- allow_signal(SIGTERM);
-
do {
gameport_handle_events();
- wait_event_interruptible(gameport_wait, !list_empty(&gameport_event_list));
+ wait_event_interruptible(gameport_wait,
+ kthread_should_stop() || !list_empty(&gameport_event_list));
try_to_freeze();
- } while (!signal_pending(current));
+ } while (!kthread_should_stop());
printk(KERN_DEBUG "gameport: kgameportd exiting\n");
-
- unlock_kernel();
- complete_and_exit(&gameport_exited, 0);
+ return 0;
}
@@ -773,9 +767,10 @@ void gameport_close(struct gameport *gameport)
static int __init gameport_init(void)
{
- if (!(gameport_pid = kernel_thread(gameport_thread, NULL, CLONE_KERNEL))) {
+ gameport_task = kthread_run(gameport_thread, NULL, "kgameportd");
+ if (IS_ERR(gameport_task)) {
printk(KERN_ERR "gameport: Failed to start kgameportd\n");
- return -1;
+ return PTR_ERR(gameport_task);
}
gameport_bus.dev_attrs = gameport_device_attrs;
@@ -789,8 +784,7 @@ static int __init gameport_init(void)
static void __exit gameport_exit(void)
{
bus_unregister(&gameport_bus);
- kill_proc(gameport_pid, SIGTERM, 1);
- wait_for_completion(&gameport_exited);
+ kthread_stop(gameport_task);
}
module_init(gameport_init);
diff --git a/drivers/input/gameport/ns558.c b/drivers/input/gameport/ns558.c
index 7c5c6318eeb..1ab5f2dc8a2 100644
--- a/drivers/input/gameport/ns558.c
+++ b/drivers/input/gameport/ns558.c
@@ -258,18 +258,18 @@ static int __init ns558_init(void)
{
int i = 0;
+ if (pnp_register_driver(&ns558_pnp_driver) >= 0)
+ pnp_registered = 1;
+
/*
- * Probe ISA ports first so that PnP gets to choose free port addresses
- * not occupied by the ISA ports.
+ * Probe ISA ports after PnP, so that PnP ports that are already
+ * enabled get detected as PnP. This may be suboptimal in multi-device
+ * configurations, but saves hassle with simple setups.
*/
while (ns558_isa_portlist[i])
ns558_isa_probe(ns558_isa_portlist[i++]);
- if (pnp_register_driver(&ns558_pnp_driver) >= 0)
- pnp_registered = 1;
-
-
return (list_empty(&ns558_list) && !pnp_registered) ? -ENODEV : 0;
}
diff --git a/drivers/input/gameport/vortex.c b/drivers/input/gameport/vortex.c
deleted file mode 100644
index 36b0309c8bf..00000000000
--- a/drivers/input/gameport/vortex.c
+++ /dev/null
@@ -1,186 +0,0 @@
-/*
- * $Id: vortex.c,v 1.5 2002/07/01 15:39:30 vojtech Exp $
- *
- * Copyright (c) 2000-2001 Vojtech Pavlik
- *
- * Based on the work of:
- * Raymond Ingles
- */
-
-/*
- * Trident 4DWave and Aureal Vortex gameport driver for Linux
- */
-
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Should you need to contact me, the author, you can do so either by
- * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
- * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
- */
-
-#include <asm/io.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/ioport.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/delay.h>
-#include <linux/gameport.h>
-
-MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
-MODULE_DESCRIPTION("Aureal Vortex and Vortex2 gameport driver");
-MODULE_LICENSE("GPL");
-
-#define VORTEX_GCR 0x0c /* Gameport control register */
-#define VORTEX_LEG 0x08 /* Legacy port location */
-#define VORTEX_AXD 0x10 /* Axes start */
-#define VORTEX_DATA_WAIT 20 /* 20 ms */
-
-struct vortex {
- struct gameport *gameport;
- struct pci_dev *dev;
- unsigned char __iomem *base;
- unsigned char __iomem *io;
-};
-
-static unsigned char vortex_read(struct gameport *gameport)
-{
- struct vortex *vortex = gameport->port_data;
- return readb(vortex->io + VORTEX_LEG);
-}
-
-static void vortex_trigger(struct gameport *gameport)
-{
- struct vortex *vortex = gameport->port_data;
- writeb(0xff, vortex->io + VORTEX_LEG);
-}
-
-static int vortex_cooked_read(struct gameport *gameport, int *axes, int *buttons)
-{
- struct vortex *vortex = gameport->port_data;
- int i;
-
- *buttons = (~readb(vortex->base + VORTEX_LEG) >> 4) & 0xf;
-
- for (i = 0; i < 4; i++) {
- axes[i] = readw(vortex->io + VORTEX_AXD + i * sizeof(u32));
- if (axes[i] == 0x1fff) axes[i] = -1;
- }
-
- return 0;
-}
-
-static int vortex_open(struct gameport *gameport, int mode)
-{
- struct vortex *vortex = gameport->port_data;
-
- switch (mode) {
- case GAMEPORT_MODE_COOKED:
- writeb(0x40, vortex->io + VORTEX_GCR);
- msleep(VORTEX_DATA_WAIT);
- return 0;
- case GAMEPORT_MODE_RAW:
- writeb(0x00, vortex->io + VORTEX_GCR);
- return 0;
- default:
- return -1;
- }
-
- return 0;
-}
-
-static int __devinit vortex_probe(struct pci_dev *dev, const struct pci_device_id *id)
-{
- struct vortex *vortex;
- struct gameport *port;
- int i;
-
- vortex = kcalloc(1, sizeof(struct vortex), GFP_KERNEL);
- port = gameport_allocate_port();
- if (!vortex || !port) {
- printk(KERN_ERR "vortex: Memory allocation failed.\n");
- kfree(vortex);
- gameport_free_port(port);
- return -ENOMEM;
- }
-
- for (i = 0; i < 6; i++)
- if (~pci_resource_flags(dev, i) & IORESOURCE_IO)
- break;
-
- pci_enable_device(dev);
-
- vortex->dev = dev;
- vortex->gameport = port;
- vortex->base = ioremap(pci_resource_start(vortex->dev, i),
- pci_resource_len(vortex->dev, i));
- vortex->io = vortex->base + id->driver_data;
-
- pci_set_drvdata(dev, vortex);
-
- port->port_data = vortex;
- port->fuzz = 64;
-
- gameport_set_name(port, "AU88x0");
- gameport_set_phys(port, "pci%s/gameport0", pci_name(dev));
- port->dev.parent = &dev->dev;
- port->read = vortex_read;
- port->trigger = vortex_trigger;
- port->cooked_read = vortex_cooked_read;
- port->open = vortex_open;
-
- gameport_register_port(port);
-
- return 0;
-}
-
-static void __devexit vortex_remove(struct pci_dev *dev)
-{
- struct vortex *vortex = pci_get_drvdata(dev);
-
- gameport_unregister_port(vortex->gameport);
- iounmap(vortex->base);
- kfree(vortex);
-}
-
-static struct pci_device_id vortex_id_table[] = {
- { 0x12eb, 0x0001, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0x11000 },
- { 0x12eb, 0x0002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0x28800 },
- { 0 }
-};
-
-static struct pci_driver vortex_driver = {
- .name = "vortex_gameport",
- .id_table = vortex_id_table,
- .probe = vortex_probe,
- .remove = __devexit_p(vortex_remove),
-};
-
-static int __init vortex_init(void)
-{
- return pci_register_driver(&vortex_driver);
-}
-
-static void __exit vortex_exit(void)
-{
- pci_unregister_driver(&vortex_driver);
-}
-
-module_init(vortex_init);
-module_exit(vortex_exit);
diff --git a/drivers/input/input.c b/drivers/input/input.c
index 83c77c990dd..7c4b4d37b3e 100644
--- a/drivers/input/input.c
+++ b/drivers/input/input.c
@@ -219,10 +219,24 @@ void input_release_device(struct input_handle *handle)
int input_open_device(struct input_handle *handle)
{
+ struct input_dev *dev = handle->dev;
+ int err;
+
+ err = down_interruptible(&dev->sem);
+ if (err)
+ return err;
+
handle->open++;
- if (handle->dev->open)
- return handle->dev->open(handle->dev);
- return 0;
+
+ if (!dev->users++ && dev->open)
+ err = dev->open(dev);
+
+ if (err)
+ handle->open--;
+
+ up(&dev->sem);
+
+ return err;
}
int input_flush_device(struct input_handle* handle, struct file* file)
@@ -235,10 +249,17 @@ int input_flush_device(struct input_handle* handle, struct file* file)
void input_close_device(struct input_handle *handle)
{
+ struct input_dev *dev = handle->dev;
+
input_release_device(handle);
- if (handle->dev->close)
- handle->dev->close(handle->dev);
+
+ down(&dev->sem);
+
+ if (!--dev->users && dev->close)
+ dev->close(dev);
handle->open--;
+
+ up(&dev->sem);
}
static void input_link_handle(struct input_handle *handle)
@@ -415,6 +436,8 @@ void input_register_device(struct input_dev *dev)
set_bit(EV_SYN, dev->evbit);
+ init_MUTEX(&dev->sem);
+
/*
* If delay and period are pre-set by the driver, then autorepeating
* is handled by the driver itself and we don't do it in input.c.
@@ -674,6 +697,8 @@ static int input_handlers_read(char *buf, char **start, off_t pos, int count, in
return (count > cnt) ? cnt : count;
}
+static struct file_operations input_fileops;
+
static int __init input_proc_init(void)
{
struct proc_dir_entry *entry;
@@ -688,6 +713,8 @@ static int __init input_proc_init(void)
return -ENOMEM;
}
entry->owner = THIS_MODULE;
+ input_fileops = *entry->proc_fops;
+ entry->proc_fops = &input_fileops;
entry->proc_fops->poll = input_devices_poll;
entry = create_proc_read_entry("handlers", 0, proc_bus_input_dir, input_handlers_read, NULL);
if (entry == NULL) {
diff --git a/drivers/input/joydev.c b/drivers/input/joydev.c
index 39775fc380c..ff8e1bbd0e1 100644
--- a/drivers/input/joydev.c
+++ b/drivers/input/joydev.c
@@ -285,48 +285,33 @@ static unsigned int joydev_poll(struct file *file, poll_table *wait)
(POLLIN | POLLRDNORM) : 0) | (list->joydev->exist ? 0 : (POLLHUP | POLLERR));
}
-static int joydev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+static int joydev_ioctl_common(struct joydev *joydev, unsigned int cmd, void __user *argp)
{
- struct joydev_list *list = file->private_data;
- struct joydev *joydev = list->joydev;
struct input_dev *dev = joydev->handle.dev;
- void __user *argp = (void __user *)arg;
int i, j;
- if (!joydev->exist) return -ENODEV;
-
switch (cmd) {
case JS_SET_CAL:
return copy_from_user(&joydev->glue.JS_CORR, argp,
- sizeof(struct JS_DATA_TYPE)) ? -EFAULT : 0;
+ sizeof(joydev->glue.JS_CORR)) ? -EFAULT : 0;
case JS_GET_CAL:
return copy_to_user(argp, &joydev->glue.JS_CORR,
- sizeof(struct JS_DATA_TYPE)) ? -EFAULT : 0;
+ sizeof(joydev->glue.JS_CORR)) ? -EFAULT : 0;
case JS_SET_TIMEOUT:
- return get_user(joydev->glue.JS_TIMEOUT, (int __user *) arg);
+ return get_user(joydev->glue.JS_TIMEOUT, (s32 __user *) argp);
case JS_GET_TIMEOUT:
- return put_user(joydev->glue.JS_TIMEOUT, (int __user *) arg);
- case JS_SET_TIMELIMIT:
- return get_user(joydev->glue.JS_TIMELIMIT, (long __user *) arg);
- case JS_GET_TIMELIMIT:
- return put_user(joydev->glue.JS_TIMELIMIT, (long __user *) arg);
- case JS_SET_ALL:
- return copy_from_user(&joydev->glue, argp,
- sizeof(struct JS_DATA_SAVE_TYPE)) ? -EFAULT : 0;
- case JS_GET_ALL:
- return copy_to_user(argp, &joydev->glue,
- sizeof(struct JS_DATA_SAVE_TYPE)) ? -EFAULT : 0;
+ return put_user(joydev->glue.JS_TIMEOUT, (s32 __user *) argp);
case JSIOCGVERSION:
- return put_user(JS_VERSION, (__u32 __user *) arg);
+ return put_user(JS_VERSION, (__u32 __user *) argp);
case JSIOCGAXES:
- return put_user(joydev->nabs, (__u8 __user *) arg);
+ return put_user(joydev->nabs, (__u8 __user *) argp);
case JSIOCGBUTTONS:
- return put_user(joydev->nkey, (__u8 __user *) arg);
+ return put_user(joydev->nkey, (__u8 __user *) argp);
case JSIOCSCORR:
if (copy_from_user(joydev->corr, argp,
- sizeof(struct js_corr) * joydev->nabs))
+ sizeof(joydev->corr[0]) * joydev->nabs))
return -EFAULT;
for (i = 0; i < joydev->nabs; i++) {
j = joydev->abspam[i];
@@ -335,7 +320,7 @@ static int joydev_ioctl(struct inode *inode, struct file *file, unsigned int cmd
return 0;
case JSIOCGCORR:
return copy_to_user(argp, joydev->corr,
- sizeof(struct js_corr) * joydev->nabs) ? -EFAULT : 0;
+ sizeof(joydev->corr[0]) * joydev->nabs) ? -EFAULT : 0;
case JSIOCSAXMAP:
if (copy_from_user(joydev->abspam, argp, sizeof(__u8) * (ABS_MAX + 1)))
return -EFAULT;
@@ -371,6 +356,84 @@ static int joydev_ioctl(struct inode *inode, struct file *file, unsigned int cmd
return -EINVAL;
}
+#ifdef CONFIG_COMPAT
+static long joydev_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ struct joydev_list *list = file->private_data;
+ struct joydev *joydev = list->joydev;
+ void __user *argp = (void __user *)arg;
+ s32 tmp32;
+ struct JS_DATA_SAVE_TYPE_32 ds32;
+ int err;
+
+ if (!joydev->exist) return -ENODEV;
+ switch(cmd) {
+ case JS_SET_TIMELIMIT:
+ err = get_user(tmp32, (s32 __user *) arg);
+ if (err == 0)
+ joydev->glue.JS_TIMELIMIT = tmp32;
+ break;
+ case JS_GET_TIMELIMIT:
+ tmp32 = joydev->glue.JS_TIMELIMIT;
+ err = put_user(tmp32, (s32 __user *) arg);
+ break;
+
+ case JS_SET_ALL:
+ err = copy_from_user(&ds32, argp,
+ sizeof(ds32)) ? -EFAULT : 0;
+ if (err == 0) {
+ joydev->glue.JS_TIMEOUT = ds32.JS_TIMEOUT;
+ joydev->glue.BUSY = ds32.BUSY;
+ joydev->glue.JS_EXPIRETIME = ds32.JS_EXPIRETIME;
+ joydev->glue.JS_TIMELIMIT = ds32.JS_TIMELIMIT;
+ joydev->glue.JS_SAVE = ds32.JS_SAVE;
+ joydev->glue.JS_CORR = ds32.JS_CORR;
+ }
+ break;
+
+ case JS_GET_ALL:
+ ds32.JS_TIMEOUT = joydev->glue.JS_TIMEOUT;
+ ds32.BUSY = joydev->glue.BUSY;
+ ds32.JS_EXPIRETIME = joydev->glue.JS_EXPIRETIME;
+ ds32.JS_TIMELIMIT = joydev->glue.JS_TIMELIMIT;
+ ds32.JS_SAVE = joydev->glue.JS_SAVE;
+ ds32.JS_CORR = joydev->glue.JS_CORR;
+
+ err = copy_to_user(argp, &ds32,
+ sizeof(ds32)) ? -EFAULT : 0;
+ break;
+
+ default:
+ err = joydev_ioctl_common(joydev, cmd, argp);
+ }
+ return err;
+}
+#endif /* CONFIG_COMPAT */
+
+static int joydev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+ struct joydev_list *list = file->private_data;
+ struct joydev *joydev = list->joydev;
+ void __user *argp = (void __user *)arg;
+
+ if (!joydev->exist) return -ENODEV;
+
+ switch(cmd) {
+ case JS_SET_TIMELIMIT:
+ return get_user(joydev->glue.JS_TIMELIMIT, (long __user *) arg);
+ case JS_GET_TIMELIMIT:
+ return put_user(joydev->glue.JS_TIMELIMIT, (long __user *) arg);
+ case JS_SET_ALL:
+ return copy_from_user(&joydev->glue, argp,
+ sizeof(joydev->glue)) ? -EFAULT : 0;
+ case JS_GET_ALL:
+ return copy_to_user(argp, &joydev->glue,
+ sizeof(joydev->glue)) ? -EFAULT : 0;
+ default:
+ return joydev_ioctl_common(joydev, cmd, argp);
+ }
+}
+
static struct file_operations joydev_fops = {
.owner = THIS_MODULE,
.read = joydev_read,
@@ -379,6 +442,9 @@ static struct file_operations joydev_fops = {
.open = joydev_open,
.release = joydev_release,
.ioctl = joydev_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = joydev_compat_ioctl,
+#endif
.fasync = joydev_fasync,
};
diff --git a/drivers/input/joystick/a3d.c b/drivers/input/joystick/a3d.c
index ad39fe4bf35..bf34f75b946 100644
--- a/drivers/input/joystick/a3d.c
+++ b/drivers/input/joystick/a3d.c
@@ -185,7 +185,7 @@ static void a3d_poll(struct gameport *gameport)
a3d->reads++;
if (a3d_read_packet(a3d->gameport, a3d->length, data) != a3d->length ||
data[0] != a3d->mode || a3d_csum(data, a3d->length))
- a3d->bads++;
+ a3d->bads++;
else
a3d_read(a3d, data);
}
diff --git a/drivers/input/joystick/adi.c b/drivers/input/joystick/adi.c
index 83f6dafc171..265962956c6 100644
--- a/drivers/input/joystick/adi.c
+++ b/drivers/input/joystick/adi.c
@@ -82,7 +82,7 @@ static char adi_cm2_abs[] = { ABS_X, ABS_Y, ABS_Z, ABS_RX, ABS_RY, ABS_RZ };
static char adi_wmf_abs[] = { ABS_WHEEL, ABS_GAS, ABS_BRAKE, ABS_HAT0X, ABS_HAT0Y, ABS_HAT1X, ABS_HAT1Y, ABS_HAT2X, ABS_HAT2Y };
static short adi_wmgpe_key[] = { BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_TL, BTN_TR, BTN_START, BTN_MODE, BTN_SELECT };
-static short adi_wmi_key[] = { BTN_TRIGGER, BTN_TOP, BTN_THUMB, BTN_TOP2, BTN_BASE, BTN_BASE2, BTN_BASE3, BTN_BASE4, BTN_EXTRA };
+static short adi_wmi_key[] = { BTN_TRIGGER, BTN_TOP, BTN_THUMB, BTN_TOP2, BTN_BASE, BTN_BASE2, BTN_BASE3, BTN_BASE4, BTN_EXTRA };
static short adi_wmed3d_key[] = { BTN_TRIGGER, BTN_THUMB, BTN_THUMB2, BTN_TOP, BTN_TOP2, BTN_BASE, BTN_BASE2 };
static short adi_cm2_key[] = { BTN_1, BTN_2, BTN_3, BTN_4, BTN_5, BTN_6, BTN_7, BTN_8 };
@@ -183,7 +183,7 @@ static void adi_move_bits(struct adi_port *port, int length)
int i;
struct adi *adi = port->adi;
- adi[0].idx = adi[1].idx = 0;
+ adi[0].idx = adi[1].idx = 0;
if (adi[0].ret <= 0 || adi[1].ret <= 0) return;
if (adi[0].data[0] & 0x20 || ~adi[1].data[0] & 0x20) return;
diff --git a/drivers/input/joystick/amijoy.c b/drivers/input/joystick/amijoy.c
index cf36ca9b92f..e996183c5b0 100644
--- a/drivers/input/joystick/amijoy.c
+++ b/drivers/input/joystick/amijoy.c
@@ -51,7 +51,8 @@ MODULE_PARM_DESC(map, "Map of attached joysticks in form of <a>,<b> (default is
__obsolete_setup("amijoy=");
-static int amijoy_used[2] = { 0, 0 };
+static int amijoy_used;
+static DECLARE_MUTEX(amijoy_sem);
static struct input_dev amijoy_dev[2];
static char *amijoy_phys[2] = { "amijoy/input0", "amijoy/input1" };
@@ -84,26 +85,30 @@ static irqreturn_t amijoy_interrupt(int irq, void *dummy, struct pt_regs *fp)
static int amijoy_open(struct input_dev *dev)
{
- int *used = dev->private;
+ int err;
- if ((*used)++)
- return 0;
+ err = down_interruptible(&amijoy_sem);
+ if (err)
+ return err;
- if (request_irq(IRQ_AMIGA_VERTB, amijoy_interrupt, 0, "amijoy", amijoy_interrupt)) {
- (*used)--;
+ if (!amijoy_used && request_irq(IRQ_AMIGA_VERTB, amijoy_interrupt, 0, "amijoy", amijoy_interrupt)) {
printk(KERN_ERR "amijoy.c: Can't allocate irq %d\n", IRQ_AMIGA_VERTB);
- return -EBUSY;
+ err = -EBUSY;
+ goto out;
}
- return 0;
+ amijoy_used++;
+out:
+ up(&amijoy_sem);
+ return err;
}
static void amijoy_close(struct input_dev *dev)
{
- int *used = dev->private;
-
- if (!--(*used))
+ down(&amijoy_sem);
+ if (!--amijoy_used)
free_irq(IRQ_AMIGA_VERTB, amijoy_interrupt);
+ up(&amijoy_sem);
}
static int __init amijoy_init(void)
@@ -138,8 +143,6 @@ static int __init amijoy_init(void)
amijoy_dev[i].id.product = 0x0003;
amijoy_dev[i].id.version = 0x0100;
- amijoy_dev[i].private = amijoy_used + i;
-
input_register_device(amijoy_dev + i);
printk(KERN_INFO "input: %s at joy%ddat\n", amijoy_name, i);
}
diff --git a/drivers/input/joystick/analog.c b/drivers/input/joystick/analog.c
index 504b7d55056..c3a5739030c 100644
--- a/drivers/input/joystick/analog.c
+++ b/drivers/input/joystick/analog.c
@@ -140,12 +140,14 @@ struct analog_port {
*/
#ifdef __i386__
+
+#include <asm/i8253.h>
+
#define GET_TIME(x) do { if (cpu_has_tsc) rdtscl(x); else x = get_time_pit(); } while (0)
#define DELTA(x,y) (cpu_has_tsc ? ((y) - (x)) : ((x) - (y) + ((x) < (y) ? CLOCK_TICK_RATE / HZ : 0)))
#define TIME_NAME (cpu_has_tsc?"TSC":"PIT")
static unsigned int get_time_pit(void)
{
- extern spinlock_t i8253_lock;
unsigned long flags;
unsigned int count;
diff --git a/drivers/input/joystick/db9.c b/drivers/input/joystick/db9.c
index cfdd3acf06a..fbd3eed07f9 100644
--- a/drivers/input/joystick/db9.c
+++ b/drivers/input/joystick/db9.c
@@ -87,7 +87,7 @@ __obsolete_setup("db9_3=");
#define DB9_NORMAL 0x0a
#define DB9_NOSELECT 0x08
-#define DB9_MAX_DEVICES 2
+#define DB9_MAX_DEVICES 2
#define DB9_GENESIS6_DELAY 14
#define DB9_REFRESH_TIME HZ/100
@@ -98,6 +98,7 @@ struct db9 {
struct pardevice *pd;
int mode;
int used;
+ struct semaphore sem;
char phys[2][32];
};
@@ -503,6 +504,11 @@ static int db9_open(struct input_dev *dev)
{
struct db9 *db9 = dev->private;
struct parport *port = db9->pd->port;
+ int err;
+
+ err = down_interruptible(&db9->sem);
+ if (err)
+ return err;
if (!db9->used++) {
parport_claim(db9->pd);
@@ -514,6 +520,7 @@ static int db9_open(struct input_dev *dev)
mod_timer(&db9->timer, jiffies + DB9_REFRESH_TIME);
}
+ up(&db9->sem);
return 0;
}
@@ -522,12 +529,14 @@ static void db9_close(struct input_dev *dev)
struct db9 *db9 = dev->private;
struct parport *port = db9->pd->port;
+ down(&db9->sem);
if (!--db9->used) {
- del_timer(&db9->timer);
+ del_timer_sync(&db9->timer);
parport_write_control(port, 0x00);
parport_data_forward(port);
parport_release(db9->pd);
}
+ up(&db9->sem);
}
static struct db9 __init *db9_probe(int *config, int nargs)
@@ -563,12 +572,12 @@ static struct db9 __init *db9_probe(int *config, int nargs)
}
}
- if (!(db9 = kmalloc(sizeof(struct db9), GFP_KERNEL))) {
+ if (!(db9 = kcalloc(1, sizeof(struct db9), GFP_KERNEL))) {
parport_put_port(pp);
return NULL;
}
- memset(db9, 0, sizeof(struct db9));
+ init_MUTEX(&db9->sem);
db9->mode = config[1];
init_timer(&db9->timer);
db9->timer.data = (long) db9;
diff --git a/drivers/input/joystick/gamecon.c b/drivers/input/joystick/gamecon.c
index 8732f52bdd0..95bbdd302aa 100644
--- a/drivers/input/joystick/gamecon.c
+++ b/drivers/input/joystick/gamecon.c
@@ -1,12 +1,12 @@
/*
* NES, SNES, N64, MultiSystem, PSX gamepad driver for Linux
*
- * Copyright (c) 1999-2004 Vojtech Pavlik <vojtech@suse.cz>
- * Copyright (c) 2004 Peter Nelson <rufus-kernel@hackish.org>
+ * Copyright (c) 1999-2004 Vojtech Pavlik <vojtech@suse.cz>
+ * Copyright (c) 2004 Peter Nelson <rufus-kernel@hackish.org>
*
* Based on the work of:
- * Andree Borrmann John Dahlstrom
- * David Kuder Nathan Hand
+ * Andree Borrmann John Dahlstrom
+ * David Kuder Nathan Hand
*/
/*
@@ -81,6 +81,7 @@ struct gc {
struct timer_list timer;
unsigned char pads[GC_MAX + 1];
int used;
+ struct semaphore sem;
char phys[5][32];
};
@@ -433,7 +434,7 @@ static void gc_timer(unsigned long private)
gc_psx_read_packet(gc, data_psx, data);
for (i = 0; i < 5; i++) {
- switch (data[i]) {
+ switch (data[i]) {
case GC_PSX_RUMBLE:
@@ -503,22 +504,33 @@ static void gc_timer(unsigned long private)
static int gc_open(struct input_dev *dev)
{
struct gc *gc = dev->private;
+ int err;
+
+ err = down_interruptible(&gc->sem);
+ if (err)
+ return err;
+
if (!gc->used++) {
parport_claim(gc->pd);
parport_write_control(gc->pd->port, 0x04);
mod_timer(&gc->timer, jiffies + GC_REFRESH_TIME);
}
+
+ up(&gc->sem);
return 0;
}
static void gc_close(struct input_dev *dev)
{
struct gc *gc = dev->private;
+
+ down(&gc->sem);
if (!--gc->used) {
- del_timer(&gc->timer);
+ del_timer_sync(&gc->timer);
parport_write_control(gc->pd->port, 0x00);
parport_release(gc->pd);
}
+ up(&gc->sem);
}
static struct gc __init *gc_probe(int *config, int nargs)
@@ -542,11 +554,12 @@ static struct gc __init *gc_probe(int *config, int nargs)
return NULL;
}
- if (!(gc = kmalloc(sizeof(struct gc), GFP_KERNEL))) {
+ if (!(gc = kcalloc(1, sizeof(struct gc), GFP_KERNEL))) {
parport_put_port(pp);
return NULL;
}
- memset(gc, 0, sizeof(struct gc));
+
+ init_MUTEX(&gc->sem);
gc->pd = parport_register_device(pp, "gamecon", NULL, NULL, NULL, PARPORT_DEV_EXCL, NULL);
diff --git a/drivers/input/joystick/gf2k.c b/drivers/input/joystick/gf2k.c
index ad13f09a4e7..7d969420066 100644
--- a/drivers/input/joystick/gf2k.c
+++ b/drivers/input/joystick/gf2k.c
@@ -329,7 +329,7 @@ static int gf2k_connect(struct gameport *gameport, struct gameport_driver *drv)
for (i = 0; i < gf2k_axes[gf2k->id]; i++) {
gf2k->dev.absmax[gf2k_abs[i]] = (i < 2) ? gf2k->dev.abs[gf2k_abs[i]] * 2 - 32 :
- gf2k->dev.abs[gf2k_abs[0]] + gf2k->dev.abs[gf2k_abs[1]] - 32;
+ gf2k->dev.abs[gf2k_abs[0]] + gf2k->dev.abs[gf2k_abs[1]] - 32;
gf2k->dev.absmin[gf2k_abs[i]] = 32;
gf2k->dev.absfuzz[gf2k_abs[i]] = 8;
gf2k->dev.absflat[gf2k_abs[i]] = (i < 2) ? 24 : 0;
diff --git a/drivers/input/joystick/grip_mp.c b/drivers/input/joystick/grip_mp.c
index 42e5005d621..0da7bd133cc 100644
--- a/drivers/input/joystick/grip_mp.c
+++ b/drivers/input/joystick/grip_mp.c
@@ -171,7 +171,7 @@ static int mp_io(struct gameport* gameport, int sendflags, int sendcode, u32 *pa
*packet = 0;
raw_data = gameport_read(gameport);
if (raw_data & 1)
- return IO_RETRY;
+ return IO_RETRY;
for (i = 0; i < 64; i++) {
raw_data = gameport_read(gameport);
diff --git a/drivers/input/joystick/iforce/iforce-main.c b/drivers/input/joystick/iforce/iforce-main.c
index 028f3513629..e31b7b93fde 100644
--- a/drivers/input/joystick/iforce/iforce-main.c
+++ b/drivers/input/joystick/iforce/iforce-main.c
@@ -78,6 +78,7 @@ static struct iforce_device iforce_device[] = {
{ 0x061c, 0xc0a4, "ACT LABS Force RS", btn_wheel, abs_wheel, ff_iforce }, //?
{ 0x06f8, 0x0001, "Guillemot Race Leader Force Feedback", btn_wheel, abs_wheel, ff_iforce }, //?
{ 0x06f8, 0x0004, "Guillemot Force Feedback Racing Wheel", btn_wheel, abs_wheel, ff_iforce }, //?
+ { 0x06f8, 0x0004, "Gullemot Jet Leader 3D", btn_joystick, abs_joystick, ff_iforce }, //?
{ 0x0000, 0x0000, "Unknown I-Force Device [%04x:%04x]", btn_joystick, abs_joystick, ff_iforce }
};
diff --git a/drivers/input/joystick/iforce/iforce-usb.c b/drivers/input/joystick/iforce/iforce-usb.c
index 617c0b0e5a3..6369a24684f 100644
--- a/drivers/input/joystick/iforce/iforce-usb.c
+++ b/drivers/input/joystick/iforce/iforce-usb.c
@@ -229,6 +229,7 @@ static struct usb_device_id iforce_usb_ids [] = {
{ USB_DEVICE(0x061c, 0xc0a4) }, /* ACT LABS Force RS */
{ USB_DEVICE(0x06f8, 0x0001) }, /* Guillemot Race Leader Force Feedback */
{ USB_DEVICE(0x06f8, 0x0004) }, /* Guillemot Force Feedback Racing Wheel */
+ { USB_DEVICE(0x06f8, 0xa302) }, /* Guillemot Jet Leader 3D */
{ } /* Terminating entry */
};
diff --git a/drivers/input/joystick/spaceball.c b/drivers/input/joystick/spaceball.c
index ec0a2a64d49..a436f222085 100644
--- a/drivers/input/joystick/spaceball.c
+++ b/drivers/input/joystick/spaceball.c
@@ -4,8 +4,8 @@
* Copyright (c) 1999-2001 Vojtech Pavlik
*
* Based on the work of:
- * David Thompson
- * Joseph Krahn
+ * David Thompson
+ * Joseph Krahn
*/
/*
diff --git a/drivers/input/joystick/spaceorb.c b/drivers/input/joystick/spaceorb.c
index 874367bfab0..01fd2e4791a 100644
--- a/drivers/input/joystick/spaceorb.c
+++ b/drivers/input/joystick/spaceorb.c
@@ -4,7 +4,7 @@
* Copyright (c) 1999-2001 Vojtech Pavlik
*
* Based on the work of:
- * David Thompson
+ * David Thompson
*/
/*
diff --git a/drivers/input/joystick/tmdc.c b/drivers/input/joystick/tmdc.c
index aaee52ceb92..9eb9954cac6 100644
--- a/drivers/input/joystick/tmdc.c
+++ b/drivers/input/joystick/tmdc.c
@@ -79,7 +79,7 @@ static short tmdc_btn_pad[TMDC_BTN] =
{ BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_START, BTN_SELECT, BTN_TL, BTN_TR };
static short tmdc_btn_joy[TMDC_BTN] =
{ BTN_TRIGGER, BTN_THUMB, BTN_TOP, BTN_TOP2, BTN_BASE, BTN_BASE2, BTN_THUMB2, BTN_PINKIE,
- BTN_BASE3, BTN_BASE4, BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z };
+ BTN_BASE3, BTN_BASE4, BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z };
static short tmdc_btn_fm[TMDC_BTN] =
{ BTN_TRIGGER, BTN_C, BTN_B, BTN_A, BTN_THUMB, BTN_X, BTN_Y, BTN_Z, BTN_TOP, BTN_TOP2 };
static short tmdc_btn_at[TMDC_BTN] =
diff --git a/drivers/input/joystick/turbografx.c b/drivers/input/joystick/turbografx.c
index dd88b9cb49f..28100d461cb 100644
--- a/drivers/input/joystick/turbografx.c
+++ b/drivers/input/joystick/turbografx.c
@@ -84,6 +84,7 @@ static struct tgfx {
char phys[7][32];
int sticks;
int used;
+ struct semaphore sem;
} *tgfx_base[3];
/*
@@ -99,7 +100,7 @@ static void tgfx_timer(unsigned long private)
for (i = 0; i < 7; i++)
if (tgfx->sticks & (1 << i)) {
- dev = tgfx->dev + i;
+ dev = tgfx->dev + i;
parport_write_data(tgfx->pd->port, ~(1 << i));
data1 = parport_read_status(tgfx->pd->port) ^ 0x7f;
@@ -122,23 +123,34 @@ static void tgfx_timer(unsigned long private)
static int tgfx_open(struct input_dev *dev)
{
- struct tgfx *tgfx = dev->private;
- if (!tgfx->used++) {
+ struct tgfx *tgfx = dev->private;
+ int err;
+
+ err = down_interruptible(&tgfx->sem);
+ if (err)
+ return err;
+
+ if (!tgfx->used++) {
parport_claim(tgfx->pd);
parport_write_control(tgfx->pd->port, 0x04);
- mod_timer(&tgfx->timer, jiffies + TGFX_REFRESH_TIME);
+ mod_timer(&tgfx->timer, jiffies + TGFX_REFRESH_TIME);
}
- return 0;
+
+ up(&tgfx->sem);
+ return 0;
}
static void tgfx_close(struct input_dev *dev)
{
- struct tgfx *tgfx = dev->private;
- if (!--tgfx->used) {
- del_timer(&tgfx->timer);
+ struct tgfx *tgfx = dev->private;
+
+ down(&tgfx->sem);
+ if (!--tgfx->used) {
+ del_timer_sync(&tgfx->timer);
parport_write_control(tgfx->pd->port, 0x00);
- parport_release(tgfx->pd);
+ parport_release(tgfx->pd);
}
+ up(&tgfx->sem);
}
/*
@@ -166,11 +178,12 @@ static struct tgfx __init *tgfx_probe(int *config, int nargs)
return NULL;
}
- if (!(tgfx = kmalloc(sizeof(struct tgfx), GFP_KERNEL))) {
+ if (!(tgfx = kcalloc(1, sizeof(struct tgfx), GFP_KERNEL))) {
parport_put_port(pp);
return NULL;
}
- memset(tgfx, 0, sizeof(struct tgfx));
+
+ init_MUTEX(&tgfx->sem);
tgfx->pd = parport_register_device(pp, "turbografx", NULL, NULL, NULL, PARPORT_DEV_EXCL, NULL);
diff --git a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c
index 82fad9a23ac..4d4985b59ab 100644
--- a/drivers/input/keyboard/atkbd.c
+++ b/drivers/input/keyboard/atkbd.c
@@ -227,7 +227,7 @@ static ssize_t atkbd_do_set_##_name(struct device *d, struct device_attribute *a
{ \
return atkbd_attr_set_helper(d, b, s, atkbd_set_##_name); \
} \
-static struct device_attribute atkbd_attr_##_name = \
+static struct device_attribute atkbd_attr_##_name = \
__ATTR(_name, S_IWUSR | S_IRUGO, atkbd_do_show_##_name, atkbd_do_set_##_name);
ATKBD_DEFINE_ATTR(extra);
@@ -388,7 +388,7 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data,
value = atkbd->release ? 0 :
(1 + (!atkbd->softrepeat && test_bit(atkbd->keycode[code], atkbd->dev.key)));
- switch (value) { /* Workaround Toshiba laptop multiple keypress */
+ switch (value) { /* Workaround Toshiba laptop multiple keypress */
case 0:
atkbd->last = 0;
break;
@@ -894,7 +894,7 @@ static int atkbd_reconnect(struct serio *serio)
if (atkbd->write) {
param[0] = (test_bit(LED_SCROLLL, atkbd->dev.led) ? 1 : 0)
| (test_bit(LED_NUML, atkbd->dev.led) ? 2 : 0)
- | (test_bit(LED_CAPSL, atkbd->dev.led) ? 4 : 0);
+ | (test_bit(LED_CAPSL, atkbd->dev.led) ? 4 : 0);
if (atkbd_probe(atkbd))
return -1;
diff --git a/drivers/input/keyboard/corgikbd.c b/drivers/input/keyboard/corgikbd.c
index 0f1220a0ceb..a8551711e8d 100644
--- a/drivers/input/keyboard/corgikbd.c
+++ b/drivers/input/keyboard/corgikbd.c
@@ -39,6 +39,7 @@
#define CORGI_KEY_CALENDER KEY_F1
#define CORGI_KEY_ADDRESS KEY_F2
#define CORGI_KEY_FN KEY_F3
+#define CORGI_KEY_CANCEL KEY_F4
#define CORGI_KEY_OFF KEY_SUSPEND
#define CORGI_KEY_EXOK KEY_F5
#define CORGI_KEY_EXCANCEL KEY_F6
@@ -46,6 +47,7 @@
#define CORGI_KEY_EXJOGUP KEY_F8
#define CORGI_KEY_JAP1 KEY_LEFTCTRL
#define CORGI_KEY_JAP2 KEY_LEFTALT
+#define CORGI_KEY_MAIL KEY_F10
#define CORGI_KEY_OK KEY_F11
#define CORGI_KEY_MENU KEY_F12
#define CORGI_HINGE_0 KEY_KP0
@@ -59,8 +61,8 @@ static unsigned char corgikbd_keycode[NR_SCANCODES] = {
KEY_TAB, KEY_Q, KEY_E, KEY_T, KEY_G, KEY_U, KEY_J, KEY_K, 0, 0, 0, 0, 0, 0, 0, 0, /* 33-48 */
CORGI_KEY_CALENDER, KEY_W, KEY_S, KEY_F, KEY_V, KEY_H, KEY_M, KEY_L, 0, KEY_RIGHTSHIFT, 0, 0, 0, 0, 0, 0, /* 49-64 */
CORGI_KEY_ADDRESS, KEY_A, KEY_D, KEY_C, KEY_B, KEY_N, KEY_DOT, 0, KEY_ENTER, 0, KEY_LEFTSHIFT, 0, 0, 0, 0, 0, /* 65-80 */
- KEY_MAIL, KEY_Z, KEY_X, KEY_MINUS, KEY_SPACE, KEY_COMMA, 0, KEY_UP, 0, 0, 0, CORGI_KEY_FN, 0, 0, 0, 0, /* 81-96 */
- KEY_SYSRQ, CORGI_KEY_JAP1, CORGI_KEY_JAP2, KEY_CANCEL, CORGI_KEY_OK, CORGI_KEY_MENU, KEY_LEFT, KEY_DOWN, KEY_RIGHT, 0, 0, 0, 0, 0, 0, 0, /* 97-112 */
+ CORGI_KEY_MAIL, KEY_Z, KEY_X, KEY_MINUS, KEY_SPACE, KEY_COMMA, 0, KEY_UP, 0, 0, 0, CORGI_KEY_FN, 0, 0, 0, 0, /* 81-96 */
+ KEY_SYSRQ, CORGI_KEY_JAP1, CORGI_KEY_JAP2, CORGI_KEY_CANCEL, CORGI_KEY_OK, CORGI_KEY_MENU, KEY_LEFT, KEY_DOWN, KEY_RIGHT, 0, 0, 0, 0, 0, 0, 0, /* 97-112 */
CORGI_KEY_OFF, CORGI_KEY_EXOK, CORGI_KEY_EXCANCEL, CORGI_KEY_EXJOGDOWN, CORGI_KEY_EXJOGUP, 0, 0, 0, 0, 0, 0, 0, /* 113-124 */
CORGI_HINGE_0, CORGI_HINGE_1, CORGI_HINGE_2 /* 125-127 */
};
diff --git a/drivers/input/keyboard/lkkbd.c b/drivers/input/keyboard/lkkbd.c
index 2694ff2b5be..098963c7cdd 100644
--- a/drivers/input/keyboard/lkkbd.c
+++ b/drivers/input/keyboard/lkkbd.c
@@ -15,10 +15,10 @@
* information given below, I will _not_ be liable!
*
* RJ10 pinout: To DE9: Or DB25:
- * 1 - RxD <----> Pin 3 (TxD) <-> Pin 2 (TxD)
- * 2 - GND <----> Pin 5 (GND) <-> Pin 7 (GND)
- * 4 - TxD <----> Pin 2 (RxD) <-> Pin 3 (RxD)
- * 3 - +12V (from HDD drive connector), DON'T connect to DE9 or DB25!!!
+ * 1 - RxD <----> Pin 3 (TxD) <-> Pin 2 (TxD)
+ * 2 - GND <----> Pin 5 (GND) <-> Pin 7 (GND)
+ * 4 - TxD <----> Pin 2 (RxD) <-> Pin 3 (RxD)
+ * 3 - +12V (from HDD drive connector), DON'T connect to DE9 or DB25!!!
*
* Pin numbers for DE9 and DB25 are noted on the plug (quite small:). For
* RJ10, it's like this:
diff --git a/drivers/input/keyboard/locomokbd.c b/drivers/input/keyboard/locomokbd.c
index d3e9dd6a13c..8935290256b 100644
--- a/drivers/input/keyboard/locomokbd.c
+++ b/drivers/input/keyboard/locomokbd.c
@@ -42,7 +42,7 @@ MODULE_AUTHOR("John Lenz <lenz@cs.wisc.edu>");
MODULE_DESCRIPTION("LoCoMo keyboard driver");
MODULE_LICENSE("GPL");
-#define LOCOMOKBD_NUMKEYS 128
+#define LOCOMOKBD_NUMKEYS 128
#define KEY_ACTIVITY KEY_F16
#define KEY_CONTACT KEY_F18
@@ -61,7 +61,7 @@ static unsigned char locomokbd_keycode[LOCOMOKBD_NUMKEYS] = {
KEY_G, KEY_F, KEY_X, KEY_S, 0, 0, 0, 0, 0, 0, /* 90 - 99 */
0, 0, KEY_DOT, 0, KEY_COMMA, KEY_N, KEY_B, KEY_C, KEY_Z, KEY_A, /* 100 - 109 */
KEY_LEFTSHIFT, KEY_TAB, KEY_LEFTCTRL, 0, 0, 0, 0, 0, 0, 0, /* 110 - 119 */
- KEY_M, KEY_SPACE, KEY_V, KEY_APOSTROPHE, KEY_SLASH, 0, 0, 0 /* 120 - 128 */
+ KEY_M, KEY_SPACE, KEY_V, KEY_APOSTROPHE, KEY_SLASH, 0, 0, 0 /* 120 - 128 */
};
#define KB_ROWS 16
@@ -82,7 +82,7 @@ struct locomokbd {
struct locomo_dev *ldev;
unsigned long base;
spinlock_t lock;
-
+
struct timer_list timer;
};
@@ -95,7 +95,7 @@ static inline void locomokbd_charge_all(unsigned long membase)
static inline void locomokbd_activate_all(unsigned long membase)
{
unsigned long r;
-
+
locomo_writel(0, membase + LOCOMO_KSC);
r = locomo_readl(membase + LOCOMO_KIC);
r &= 0xFEFF;
@@ -127,7 +127,7 @@ static inline void locomokbd_reset_col(unsigned long membase, int col)
*/
/* Scan the hardware keyboard and push any changes up through the input layer */
-static void locomokbd_scankeyboard(struct locomokbd *locomokbd, struct pt_regs *regs)
+static void locomokbd_scankeyboard(struct locomokbd *locomokbd, struct pt_regs *regs)
{
unsigned int row, col, rowd, scancode;
unsigned long flags;
@@ -138,7 +138,7 @@ static void locomokbd_scankeyboard(struct locomokbd *locomokbd, struct pt_regs *
if (regs)
input_regs(&locomokbd->input, regs);
-
+
locomokbd_charge_all(membase);
num_pressed = 0;
@@ -146,9 +146,9 @@ static void locomokbd_scankeyboard(struct locomokbd *locomokbd, struct pt_regs *
locomokbd_activate_col(membase, col);
udelay(KB_DELAY);
-
+
rowd = ~locomo_readl(membase + LOCOMO_KIB);
- for (row = 0; row < KB_ROWS; row++ ) {
+ for (row = 0; row < KB_ROWS; row++) {
scancode = SCANCODE(col, row);
if (rowd & KB_ROWMASK(row)) {
num_pressed += 1;
@@ -170,7 +170,7 @@ static void locomokbd_scankeyboard(struct locomokbd *locomokbd, struct pt_regs *
spin_unlock_irqrestore(&locomokbd->lock, flags);
}
-/*
+/*
* LoCoMo keyboard interrupt handler.
*/
static irqreturn_t locomokbd_interrupt(int irq, void *dev_id, struct pt_regs *regs)
@@ -205,8 +205,8 @@ static int locomokbd_probe(struct locomo_dev *dev)
memset(locomokbd, 0, sizeof(struct locomokbd));
/* try and claim memory region */
- if (!request_mem_region((unsigned long) dev->mapbase,
- dev->length,
+ if (!request_mem_region((unsigned long) dev->mapbase,
+ dev->length,
LOCOMO_DRIVER_NAME(dev))) {
ret = -EBUSY;
printk(KERN_ERR "locomokbd: Can't acquire access to io memory for keyboard\n");
@@ -225,7 +225,7 @@ static int locomokbd_probe(struct locomo_dev *dev)
locomokbd->timer.data = (unsigned long) locomokbd;
locomokbd->input.evbit[0] = BIT(EV_KEY) | BIT(EV_REP);
-
+
init_input_dev(&locomokbd->input);
locomokbd->input.keycode = locomokbd->keycode;
locomokbd->input.keycodesize = sizeof(unsigned char);
@@ -271,11 +271,11 @@ free:
static int locomokbd_remove(struct locomo_dev *dev)
{
struct locomokbd *locomokbd = locomo_get_drvdata(dev);
-
+
free_irq(dev->irq[0], locomokbd);
del_timer_sync(&locomokbd->timer);
-
+
input_unregister_device(&locomokbd->input);
locomo_set_drvdata(dev, NULL);
diff --git a/drivers/input/keyboard/maple_keyb.c b/drivers/input/keyboard/maple_keyb.c
index 859ed771ee0..eecbde294f1 100644
--- a/drivers/input/keyboard/maple_keyb.c
+++ b/drivers/input/keyboard/maple_keyb.c
@@ -1,6 +1,6 @@
/*
* $Id: maple_keyb.c,v 1.4 2004/03/22 01:18:15 lethal Exp $
- * SEGA Dreamcast keyboard driver
+ * SEGA Dreamcast keyboard driver
* Based on drivers/usb/usbkbd.c
*/
@@ -40,7 +40,6 @@ struct dc_kbd {
struct input_dev dev;
unsigned char new[8];
unsigned char old[8];
- int open;
};
@@ -95,22 +94,6 @@ static void dc_kbd_callback(struct mapleq *mq)
}
}
-
-static int dc_kbd_open(struct input_dev *dev)
-{
- struct dc_kbd *kbd = dev->private;
- kbd->open++;
- return 0;
-}
-
-
-static void dc_kbd_close(struct input_dev *dev)
-{
- struct dc_kbd *kbd = dev->private;
- kbd->open--;
-}
-
-
static int dc_kbd_connect(struct maple_device *dev)
{
int i;
@@ -133,9 +116,6 @@ static int dc_kbd_connect(struct maple_device *dev)
clear_bit(0, kbd->dev.keybit);
kbd->dev.private = kbd;
- kbd->dev.open = dc_kbd_open;
- kbd->dev.close = dc_kbd_close;
- kbd->dev.event = NULL;
kbd->dev.name = dev->product_name;
kbd->dev.id.bustype = BUS_MAPLE;
diff --git a/drivers/input/misc/uinput.c b/drivers/input/misc/uinput.c
index 158c8e845ff..98710997aaa 100644
--- a/drivers/input/misc/uinput.c
+++ b/drivers/input/misc/uinput.c
@@ -298,9 +298,11 @@ static int uinput_alloc_device(struct file *file, const char __user *buffer, siz
/* check if absmin/absmax/absfuzz/absflat are filled as
* told in Documentation/input/input-programming.txt */
if (test_bit(EV_ABS, dev->evbit)) {
- retval = uinput_validate_absbits(dev);
- if (retval < 0)
+ int err = uinput_validate_absbits(dev);
+ if (err < 0) {
+ retval = err;
kfree(dev->name);
+ }
}
exit:
diff --git a/drivers/input/mouse/Makefile b/drivers/input/mouse/Makefile
index a7864195806..c4909b49337 100644
--- a/drivers/input/mouse/Makefile
+++ b/drivers/input/mouse/Makefile
@@ -15,4 +15,4 @@ obj-$(CONFIG_MOUSE_SERIAL) += sermouse.o
obj-$(CONFIG_MOUSE_HIL) += hil_ptr.o
obj-$(CONFIG_MOUSE_VSXXXAA) += vsxxxaa.o
-psmouse-objs := psmouse-base.o alps.o logips2pp.o synaptics.o
+psmouse-objs := psmouse-base.o alps.o logips2pp.o synaptics.o lifebook.o
diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c
index 7bf4be733e9..a12e98158a7 100644
--- a/drivers/input/mouse/alps.c
+++ b/drivers/input/mouse/alps.c
@@ -30,10 +30,11 @@
#define ALPS_DUALPOINT 0x01
#define ALPS_WHEEL 0x02
-#define ALPS_FW_BK 0x04
+#define ALPS_FW_BK_1 0x04
#define ALPS_4BTN 0x08
#define ALPS_OLDPROTO 0x10
#define ALPS_PASS 0x20
+#define ALPS_FW_BK_2 0x40
static struct alps_model_info alps_model_data[] = {
{ { 0x33, 0x02, 0x0a }, 0x88, 0xf8, ALPS_OLDPROTO }, /* UMAX-530T */
@@ -43,11 +44,11 @@ static struct alps_model_info alps_model_data[] = {
{ { 0x63, 0x02, 0x14 }, 0xf8, 0xf8, 0 },
{ { 0x63, 0x02, 0x28 }, 0xf8, 0xf8, 0 },
{ { 0x63, 0x02, 0x3c }, 0x8f, 0x8f, ALPS_WHEEL }, /* Toshiba Satellite S2400-103 */
- { { 0x63, 0x02, 0x50 }, 0xef, 0xef, ALPS_FW_BK }, /* NEC Versa L320 */
+ { { 0x63, 0x02, 0x50 }, 0xef, 0xef, ALPS_FW_BK_1 }, /* NEC Versa L320 */
{ { 0x63, 0x02, 0x64 }, 0xf8, 0xf8, 0 },
{ { 0x63, 0x03, 0xc8 }, 0xf8, 0xf8, ALPS_PASS }, /* Dell Latitude D800 */
{ { 0x73, 0x02, 0x0a }, 0xf8, 0xf8, 0 },
- { { 0x73, 0x02, 0x14 }, 0xf8, 0xf8, 0 },
+ { { 0x73, 0x02, 0x14 }, 0xf8, 0xf8, ALPS_FW_BK_2 }, /* Ahtec Laptop */
{ { 0x20, 0x02, 0x0e }, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, /* XXX */
{ { 0x22, 0x02, 0x0a }, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT },
{ { 0x22, 0x02, 0x14 }, 0xff, 0xff, ALPS_PASS | ALPS_DUALPOINT }, /* Dell Latitude D600 */
@@ -61,11 +62,11 @@ static struct alps_model_info alps_model_data[] = {
/*
* ALPS abolute Mode - new format
- *
- * byte 0: 1 ? ? ? 1 ? ? ?
+ *
+ * byte 0: 1 ? ? ? 1 ? ? ?
* byte 1: 0 x6 x5 x4 x3 x2 x1 x0
* byte 2: 0 x10 x9 x8 x7 ? fin ges
- * byte 3: 0 y9 y8 y7 1 M R L
+ * byte 3: 0 y9 y8 y7 1 M R L
* byte 4: 0 y6 y5 y4 y3 y2 y1 y0
* byte 5: 0 z6 z5 z4 z3 z2 z1 z0
*
@@ -81,11 +82,12 @@ static void alps_process_packet(struct psmouse *psmouse, struct pt_regs *regs)
struct input_dev *dev = &psmouse->dev;
struct input_dev *dev2 = &priv->dev2;
int x, y, z, ges, fin, left, right, middle;
+ int back = 0, forward = 0;
input_regs(dev, regs);
if ((packet[0] & 0xc8) == 0x08) { /* 3-byte PS/2 packet */
- input_report_key(dev2, BTN_LEFT, packet[0] & 1);
+ input_report_key(dev2, BTN_LEFT, packet[0] & 1);
input_report_key(dev2, BTN_RIGHT, packet[0] & 2);
input_report_key(dev2, BTN_MIDDLE, packet[0] & 4);
input_report_rel(dev2, REL_X,
@@ -112,6 +114,18 @@ static void alps_process_packet(struct psmouse *psmouse, struct pt_regs *regs)
z = packet[5];
}
+ if (priv->i->flags & ALPS_FW_BK_1) {
+ back = packet[2] & 4;
+ forward = packet[0] & 0x10;
+ }
+
+ if (priv->i->flags & ALPS_FW_BK_2) {
+ back = packet[3] & 4;
+ forward = packet[2] & 4;
+ if ((middle = forward && back))
+ forward = back = 0;
+ }
+
ges = packet[2] & 1;
fin = packet[2] & 2;
@@ -155,13 +169,12 @@ static void alps_process_packet(struct psmouse *psmouse, struct pt_regs *regs)
input_report_abs(dev, ABS_PRESSURE, z);
input_report_key(dev, BTN_TOOL_FINGER, z > 0);
-
if (priv->i->flags & ALPS_WHEEL)
input_report_rel(dev, REL_WHEEL, ((packet[0] >> 4) & 0x07) | ((packet[2] >> 2) & 0x08));
- if (priv->i->flags & ALPS_FW_BK) {
- input_report_key(dev, BTN_FORWARD, packet[0] & 0x10);
- input_report_key(dev, BTN_BACK, packet[2] & 0x04);
+ if (priv->i->flags & (ALPS_FW_BK_1 | ALPS_FW_BK_2)) {
+ input_report_key(dev, BTN_FORWARD, forward);
+ input_report_key(dev, BTN_BACK, back);
}
input_sync(dev);
@@ -257,7 +270,6 @@ static struct alps_model_info *alps_get_model(struct psmouse *psmouse, int *vers
static int alps_passthrough_mode(struct psmouse *psmouse, int enable)
{
struct ps2dev *ps2dev = &psmouse->ps2dev;
- unsigned char param[3];
int cmd = enable ? PSMOUSE_CMD_SETSCALE21 : PSMOUSE_CMD_SETSCALE11;
if (ps2_command(ps2dev, NULL, cmd) ||
@@ -267,7 +279,7 @@ static int alps_passthrough_mode(struct psmouse *psmouse, int enable)
return -1;
/* we may get 3 more bytes, just ignore them */
- ps2_command(ps2dev, param, 0x0300);
+ ps2_drain(ps2dev, 3, 100);
return 0;
}
@@ -425,7 +437,7 @@ int alps_init(struct psmouse *psmouse)
psmouse->dev.relbit[LONG(REL_WHEEL)] |= BIT(REL_WHEEL);
}
- if (priv->i->flags & ALPS_FW_BK) {
+ if (priv->i->flags & (ALPS_FW_BK_1 | ALPS_FW_BK_2)) {
psmouse->dev.keybit[LONG(BTN_FORWARD)] |= BIT(BTN_FORWARD);
psmouse->dev.keybit[LONG(BTN_BACK)] |= BIT(BTN_BACK);
}
@@ -436,8 +448,8 @@ int alps_init(struct psmouse *psmouse)
priv->dev2.id.bustype = BUS_I8042;
priv->dev2.id.vendor = 0x0002;
priv->dev2.id.product = PSMOUSE_ALPS;
- priv->dev2.id.version = 0x0000;
-
+ priv->dev2.id.version = 0x0000;
+
priv->dev2.evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
priv->dev2.relbit[LONG(REL_X)] |= BIT(REL_X) | BIT(REL_Y);
priv->dev2.keybit[LONG(BTN_LEFT)] |= BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT);
@@ -461,17 +473,15 @@ init_fail:
int alps_detect(struct psmouse *psmouse, int set_properties)
{
int version;
- struct alps_model_info *model;
+ struct alps_model_info *model;
if (!(model = alps_get_model(psmouse, &version)))
return -1;
if (set_properties) {
psmouse->vendor = "ALPS";
- if (model->flags & ALPS_DUALPOINT)
- psmouse->name = "DualPoint TouchPad";
- else
- psmouse->name = "GlidePoint";
+ psmouse->name = model->flags & ALPS_DUALPOINT ?
+ "DualPoint TouchPad" : "GlidePoint";
psmouse->model = version;
}
return 0;
diff --git a/drivers/input/mouse/amimouse.c b/drivers/input/mouse/amimouse.c
index 7baa09cca7c..e994849efb8 100644
--- a/drivers/input/mouse/amimouse.c
+++ b/drivers/input/mouse/amimouse.c
@@ -33,7 +33,6 @@ MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
MODULE_DESCRIPTION("Amiga mouse driver");
MODULE_LICENSE("GPL");
-static int amimouse_used = 0;
static int amimouse_lastx, amimouse_lasty;
static struct input_dev amimouse_dev;
@@ -81,16 +80,12 @@ static int amimouse_open(struct input_dev *dev)
{
unsigned short joy0dat;
- if (amimouse_used++)
- return 0;
-
joy0dat = custom.joy0dat;
amimouse_lastx = joy0dat & 0xff;
amimouse_lasty = joy0dat >> 8;
if (request_irq(IRQ_AMIGA_VERTB, amimouse_interrupt, 0, "amimouse", amimouse_interrupt)) {
- amimouse_used--;
printk(KERN_ERR "amimouse.c: Can't allocate irq %d\n", IRQ_AMIGA_VERTB);
return -EBUSY;
}
@@ -100,8 +95,7 @@ static int amimouse_open(struct input_dev *dev)
static void amimouse_close(struct input_dev *dev)
{
- if (!--amimouse_used)
- free_irq(IRQ_AMIGA_VERTB, amimouse_interrupt);
+ free_irq(IRQ_AMIGA_VERTB, amimouse_interrupt);
}
static int __init amimouse_init(void)
diff --git a/drivers/input/mouse/inport.c b/drivers/input/mouse/inport.c
index ca4e9688662..1f62c013401 100644
--- a/drivers/input/mouse/inport.c
+++ b/drivers/input/mouse/inport.c
@@ -17,18 +17,18 @@
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
+ * the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
- *
+ *
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
+ *
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
+ *
* Should you need to contact me, the author, you can do so either by
* e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
@@ -87,29 +87,23 @@ MODULE_PARM_DESC(irq, "IRQ number (5=default)");
__obsolete_setup("inport_irq=");
-static int inport_used;
-
static irqreturn_t inport_interrupt(int irq, void *dev_id, struct pt_regs *regs);
static int inport_open(struct input_dev *dev)
{
- if (!inport_used++) {
- if (request_irq(inport_irq, inport_interrupt, 0, "inport", NULL))
- return -EBUSY;
- outb(INPORT_REG_MODE, INPORT_CONTROL_PORT);
- outb(INPORT_MODE_IRQ | INPORT_MODE_BASE, INPORT_DATA_PORT);
- }
+ if (request_irq(inport_irq, inport_interrupt, 0, "inport", NULL))
+ return -EBUSY;
+ outb(INPORT_REG_MODE, INPORT_CONTROL_PORT);
+ outb(INPORT_MODE_IRQ | INPORT_MODE_BASE, INPORT_DATA_PORT);
return 0;
}
static void inport_close(struct input_dev *dev)
{
- if (!--inport_used) {
- outb(INPORT_REG_MODE, INPORT_CONTROL_PORT);
- outb(INPORT_MODE_BASE, INPORT_DATA_PORT);
- free_irq(inport_irq, NULL);
- }
+ outb(INPORT_REG_MODE, INPORT_CONTROL_PORT);
+ outb(INPORT_MODE_BASE, INPORT_DATA_PORT);
+ free_irq(inport_irq, NULL);
}
static struct input_dev inport_dev = {
@@ -120,11 +114,11 @@ static struct input_dev inport_dev = {
.close = inport_close,
.name = INPORT_NAME,
.phys = "isa023c/input0",
- .id = {
- .bustype = BUS_ISA,
- .vendor = INPORT_VENDOR,
- .product = 0x0001,
- .version = 0x0100,
+ .id = {
+ .bustype = BUS_ISA,
+ .vendor = INPORT_VENDOR,
+ .product = 0x0001,
+ .version = 0x0100,
},
};
diff --git a/drivers/input/mouse/lifebook.c b/drivers/input/mouse/lifebook.c
new file mode 100644
index 00000000000..bd9df9b2832
--- /dev/null
+++ b/drivers/input/mouse/lifebook.c
@@ -0,0 +1,134 @@
+/*
+ * Fujitsu B-series Lifebook PS/2 TouchScreen driver
+ *
+ * Copyright (c) 2005 Vojtech Pavlik <vojtech@suse.cz>
+ * Copyright (c) 2005 Kenan Esau <kenan.esau@conan.de>
+ *
+ * TouchScreen detection, absolute mode setting and packet layout is taken from
+ * Harald Hoyer's description of the device.
+ *
+ * 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 <linux/input.h>
+#include <linux/serio.h>
+#include <linux/libps2.h>
+#include <linux/dmi.h>
+
+#include "psmouse.h"
+#include "lifebook.h"
+
+static struct dmi_system_id lifebook_dmi_table[] = {
+ {
+ .ident = "Lifebook B",
+ .matches = {
+ DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK B Series"),
+ },
+ },
+ { }
+};
+
+
+static psmouse_ret_t lifebook_process_byte(struct psmouse *psmouse, struct pt_regs *regs)
+{
+ unsigned char *packet = psmouse->packet;
+ struct input_dev *dev = &psmouse->dev;
+
+ if (psmouse->pktcnt != 3)
+ return PSMOUSE_GOOD_DATA;
+
+ input_regs(dev, regs);
+
+ /* calculate X and Y */
+ if ((packet[0] & 0x08) == 0x00) {
+ input_report_abs(dev, ABS_X,
+ (packet[1] | ((packet[0] & 0x30) << 4)));
+ input_report_abs(dev, ABS_Y,
+ 1024 - (packet[2] | ((packet[0] & 0xC0) << 2)));
+ } else {
+ input_report_rel(dev, REL_X,
+ ((packet[0] & 0x10) ? packet[1] - 256 : packet[1]));
+ input_report_rel(dev, REL_Y,
+ -(int)((packet[0] & 0x20) ? packet[2] - 256 : packet[2]));
+ }
+
+ input_report_key(dev, BTN_LEFT, packet[0] & 0x01);
+ input_report_key(dev, BTN_RIGHT, packet[0] & 0x02);
+ input_report_key(dev, BTN_TOUCH, packet[0] & 0x04);
+
+ input_sync(dev);
+
+ return PSMOUSE_FULL_PACKET;
+}
+
+static int lifebook_absolute_mode(struct psmouse *psmouse)
+{
+ struct ps2dev *ps2dev = &psmouse->ps2dev;
+ unsigned char param;
+
+ if (psmouse_reset(psmouse))
+ return -1;
+
+ /*
+ Enable absolute output -- ps2_command fails always but if
+ you leave this call out the touchsreen will never send
+ absolute coordinates
+ */
+ param = 0x07;
+ ps2_command(ps2dev, &param, PSMOUSE_CMD_SETRES);
+
+ return 0;
+}
+
+static void lifebook_set_resolution(struct psmouse *psmouse, unsigned int resolution)
+{
+ unsigned char params[] = { 0, 1, 2, 2, 3 };
+
+ if (resolution == 0 || resolution > 400)
+ resolution = 400;
+
+ ps2_command(&psmouse->ps2dev, &params[resolution / 100], PSMOUSE_CMD_SETRES);
+ psmouse->resolution = 50 << params[resolution / 100];
+}
+
+static void lifebook_disconnect(struct psmouse *psmouse)
+{
+ psmouse_reset(psmouse);
+}
+
+int lifebook_detect(struct psmouse *psmouse, int set_properties)
+{
+ if (!dmi_check_system(lifebook_dmi_table))
+ return -1;
+
+ if (set_properties) {
+ psmouse->vendor = "Fujitsu";
+ psmouse->name = "Lifebook TouchScreen";
+ }
+
+ return 0;
+}
+
+int lifebook_init(struct psmouse *psmouse)
+{
+ if (lifebook_absolute_mode(psmouse))
+ return -1;
+
+ psmouse->dev.evbit[0] = BIT(EV_ABS) | BIT(EV_KEY) | BIT(EV_REL);
+ psmouse->dev.keybit[LONG(BTN_LEFT)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT);
+ psmouse->dev.keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH);
+ psmouse->dev.relbit[0] = BIT(REL_X) | BIT(REL_Y);
+ input_set_abs_params(&psmouse->dev, ABS_X, 0, 1024, 0, 0);
+ input_set_abs_params(&psmouse->dev, ABS_Y, 0, 1024, 0, 0);
+
+ psmouse->protocol_handler = lifebook_process_byte;
+ psmouse->set_resolution = lifebook_set_resolution;
+ psmouse->disconnect = lifebook_disconnect;
+ psmouse->reconnect = lifebook_absolute_mode;
+ psmouse->pktsize = 3;
+
+ return 0;
+}
+
diff --git a/drivers/input/mouse/lifebook.h b/drivers/input/mouse/lifebook.h
new file mode 100644
index 00000000000..be1c0943825
--- /dev/null
+++ b/drivers/input/mouse/lifebook.h
@@ -0,0 +1,17 @@
+/*
+ * Fujitsu B-series Lifebook PS/2 TouchScreen driver
+ *
+ * Copyright (c) 2005 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.
+ */
+
+#ifndef _LIFEBOOK_H
+#define _LIFEBOOK_H
+
+int lifebook_detect(struct psmouse *psmouse, int set_properties);
+int lifebook_init(struct psmouse *psmouse);
+
+#endif
diff --git a/drivers/input/mouse/logibm.c b/drivers/input/mouse/logibm.c
index 77eb83e87f6..8b524316722 100644
--- a/drivers/input/mouse/logibm.c
+++ b/drivers/input/mouse/logibm.c
@@ -18,18 +18,18 @@
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
+ * the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
- *
+ *
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
+ *
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
+ *
* Should you need to contact me, the author, you can do so either by
* e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
@@ -77,16 +77,11 @@ MODULE_PARM_DESC(irq, "IRQ number (5=default)");
__obsolete_setup("logibm_irq=");
-static int logibm_used = 0;
-
static irqreturn_t logibm_interrupt(int irq, void *dev_id, struct pt_regs *regs);
static int logibm_open(struct input_dev *dev)
{
- if (logibm_used++)
- return 0;
if (request_irq(logibm_irq, logibm_interrupt, 0, "logibm", NULL)) {
- logibm_used--;
printk(KERN_ERR "logibm.c: Can't allocate irq %d\n", logibm_irq);
return -EBUSY;
}
@@ -96,8 +91,6 @@ static int logibm_open(struct input_dev *dev)
static void logibm_close(struct input_dev *dev)
{
- if (--logibm_used)
- return;
outb(LOGIBM_DISABLE_IRQ, LOGIBM_CONTROL_PORT);
free_irq(logibm_irq, NULL);
}
@@ -167,7 +160,7 @@ static int __init logibm_init(void)
outb(LOGIBM_DISABLE_IRQ, LOGIBM_CONTROL_PORT);
input_register_device(&logibm_dev);
-
+
printk(KERN_INFO "input: Logitech bus mouse at %#x irq %d\n", LOGIBM_BASE, logibm_irq);
return 0;
diff --git a/drivers/input/mouse/maplemouse.c b/drivers/input/mouse/maplemouse.c
index 12dc0ef5020..e90c60cbbf0 100644
--- a/drivers/input/mouse/maplemouse.c
+++ b/drivers/input/mouse/maplemouse.c
@@ -1,6 +1,6 @@
/*
* $Id: maplemouse.c,v 1.2 2004/03/22 01:18:15 lethal Exp $
- * SEGA Dreamcast mouse driver
+ * SEGA Dreamcast mouse driver
* Based on drivers/usb/usbmouse.c
*/
@@ -15,80 +15,51 @@
MODULE_AUTHOR("YAEGASHI Takeshi <t@keshi.org>");
MODULE_DESCRIPTION("SEGA Dreamcast mouse driver");
-struct dc_mouse {
- struct input_dev dev;
- int open;
-};
-
-
static void dc_mouse_callback(struct mapleq *mq)
{
int buttons, relx, rely, relz;
struct maple_device *mapledev = mq->dev;
- struct dc_mouse *mouse = mapledev->private_data;
- struct input_dev *dev = &mouse->dev;
+ struct input_dev *dev = mapledev->private_data;
unsigned char *res = mq->recvbuf;
buttons = ~res[8];
- relx=*(unsigned short *)(res+12)-512;
- rely=*(unsigned short *)(res+14)-512;
- relz=*(unsigned short *)(res+16)-512;
+ relx = *(unsigned short *)(res + 12) - 512;
+ rely = *(unsigned short *)(res + 14) - 512;
+ relz = *(unsigned short *)(res + 16) - 512;
- input_report_key(dev, BTN_LEFT, buttons&4);
- input_report_key(dev, BTN_MIDDLE, buttons&9);
- input_report_key(dev, BTN_RIGHT, buttons&2);
+ input_report_key(dev, BTN_LEFT, buttons & 4);
+ input_report_key(dev, BTN_MIDDLE, buttons & 9);
+ input_report_key(dev, BTN_RIGHT, buttons & 2);
input_report_rel(dev, REL_X, relx);
input_report_rel(dev, REL_Y, rely);
input_report_rel(dev, REL_WHEEL, relz);
input_sync(dev);
}
-
-static int dc_mouse_open(struct input_dev *dev)
-{
- struct dc_mouse *mouse = dev->private;
- mouse->open++;
- return 0;
-}
-
-
-static void dc_mouse_close(struct input_dev *dev)
-{
- struct dc_mouse *mouse = dev->private;
- mouse->open--;
-}
-
-
static int dc_mouse_connect(struct maple_device *dev)
{
unsigned long data = be32_to_cpu(dev->devinfo.function_data[0]);
- struct dc_mouse *mouse;
+ struct input_dev *input_dev;
- if (!(mouse = kmalloc(sizeof(struct dc_mouse), GFP_KERNEL)))
+ if (!(input_dev = kmalloc(sizeof(struct input_dev), GFP_KERNEL)))
return -1;
- memset(mouse, 0, sizeof(struct dc_mouse));
-
- dev->private_data = mouse;
- mouse->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
- mouse->dev.keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE);
- mouse->dev.relbit[0] = BIT(REL_X) | BIT(REL_Y) | BIT(REL_WHEEL);
+ dev->private_data = input_dev;
- init_input_dev(&mouse->dev);
+ memset(input_dev, 0, sizeof(struct dc_mouse));
+ init_input_dev(input_dev);
+ input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
+ input_dev->keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE);
+ input_dev->relbit[0] = BIT(REL_X) | BIT(REL_Y) | BIT(REL_WHEEL);
- mouse->dev.private = mouse;
- mouse->dev.open = dc_mouse_open;
- mouse->dev.close = dc_mouse_close;
- mouse->dev.event = NULL;
+ input_dev->name = dev->product_name;
+ input_dev->id.bustype = BUS_MAPLE;
- mouse->dev.name = dev->product_name;
- mouse->dev.id.bustype = BUS_MAPLE;
-
- input_register_device(&mouse->dev);
+ input_register_device(input_dev);
maple_getcond_callback(dev, dc_mouse_callback, 1, MAPLE_FUNC_MOUSE);
- printk(KERN_INFO "input: mouse(0x%lx): %s\n", data, mouse->dev.name);
+ printk(KERN_INFO "input: mouse(0x%lx): %s\n", data, input_dev->name);
return 0;
}
@@ -96,10 +67,10 @@ static int dc_mouse_connect(struct maple_device *dev)
static void dc_mouse_disconnect(struct maple_device *dev)
{
- struct dc_mouse *mouse = dev->private_data;
+ struct input_dev *input_dev = dev->private_data;
- input_unregister_device(&mouse->dev);
- kfree(mouse);
+ input_unregister_device(input_dev);
+ kfree(input_dev);
}
diff --git a/drivers/input/mouse/pc110pad.c b/drivers/input/mouse/pc110pad.c
index 0c74918fe25..93393d5c007 100644
--- a/drivers/input/mouse/pc110pad.c
+++ b/drivers/input/mouse/pc110pad.c
@@ -4,7 +4,7 @@
* Copyright (c) 2000-2001 Vojtech Pavlik
*
* Based on the work of:
- * Alan Cox Robin O'Leary
+ * Alan Cox Robin O'Leary
*/
/*
@@ -56,7 +56,6 @@ static int pc110pad_io = 0x15e0;
static struct input_dev pc110pad_dev;
static int pc110pad_data[3];
static int pc110pad_count;
-static int pc110pad_used;
static char *pc110pad_name = "IBM PC110 TouchPad";
static char *pc110pad_phys = "isa15e0/input0";
@@ -74,7 +73,7 @@ static irqreturn_t pc110pad_interrupt(int irq, void *ptr, struct pt_regs *regs)
if (pc110pad_count < 3)
return IRQ_HANDLED;
-
+
input_regs(&pc110pad_dev, regs);
input_report_key(&pc110pad_dev, BTN_TOUCH,
pc110pad_data[0] & 0x01);
@@ -90,15 +89,11 @@ static irqreturn_t pc110pad_interrupt(int irq, void *ptr, struct pt_regs *regs)
static void pc110pad_close(struct input_dev *dev)
{
- if (!--pc110pad_used)
- outb(PC110PAD_OFF, pc110pad_io + 2);
+ outb(PC110PAD_OFF, pc110pad_io + 2);
}
static int pc110pad_open(struct input_dev *dev)
{
- if (pc110pad_used++)
- return 0;
-
pc110pad_interrupt(0,NULL,NULL);
pc110pad_interrupt(0,NULL,NULL);
pc110pad_interrupt(0,NULL,NULL);
@@ -145,7 +140,7 @@ static int __init pc110pad_init(void)
pc110pad_dev.absmax[ABS_X] = 0x1ff;
pc110pad_dev.absmax[ABS_Y] = 0x0ff;
-
+
pc110pad_dev.open = pc110pad_open;
pc110pad_dev.close = pc110pad_close;
@@ -156,17 +151,17 @@ static int __init pc110pad_init(void)
pc110pad_dev.id.product = 0x0001;
pc110pad_dev.id.version = 0x0100;
- input_register_device(&pc110pad_dev);
+ input_register_device(&pc110pad_dev);
printk(KERN_INFO "input: %s at %#x irq %d\n",
pc110pad_name, pc110pad_io, pc110pad_irq);
-
+
return 0;
}
-
+
static void __exit pc110pad_exit(void)
{
- input_unregister_device(&pc110pad_dev);
+ input_unregister_device(&pc110pad_dev);
outb(PC110PAD_OFF, pc110pad_io + 2);
diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c
index 019034b21a0..19785a6c5ab 100644
--- a/drivers/input/mouse/psmouse-base.c
+++ b/drivers/input/mouse/psmouse-base.c
@@ -24,6 +24,7 @@
#include "synaptics.h"
#include "logips2pp.h"
#include "alps.h"
+#include "lifebook.h"
#define DRIVER_DESC "PS/2 mouse driver"
@@ -31,10 +32,9 @@ MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");
-static unsigned int psmouse_max_proto = -1U;
+static unsigned int psmouse_max_proto = PSMOUSE_AUTO;
static int psmouse_set_maxproto(const char *val, struct kernel_param *kp);
static int psmouse_get_maxproto(char *buffer, struct kernel_param *kp);
-static char *psmouse_proto_abbrev[] = { NULL, "bare", NULL, NULL, NULL, "imps", "exps", NULL, NULL, NULL };
#define param_check_proto_abbrev(name, p) __param_check(name, p, unsigned int)
#define param_set_proto_abbrev psmouse_set_maxproto
#define param_get_proto_abbrev psmouse_get_maxproto
@@ -57,6 +57,7 @@ static unsigned int psmouse_resetafter;
module_param_named(resetafter, psmouse_resetafter, uint, 0644);
MODULE_PARM_DESC(resetafter, "Reset device after so many bad packets (0 = never).");
+PSMOUSE_DEFINE_ATTR(protocol);
PSMOUSE_DEFINE_ATTR(rate);
PSMOUSE_DEFINE_ATTR(resolution);
PSMOUSE_DEFINE_ATTR(resetafter);
@@ -67,7 +68,23 @@ __obsolete_setup("psmouse_smartscroll=");
__obsolete_setup("psmouse_resetafter=");
__obsolete_setup("psmouse_rate=");
-static char *psmouse_protocols[] = { "None", "PS/2", "PS2++", "ThinkPS/2", "GenPS/2", "ImPS/2", "ImExPS/2", "SynPS/2", "AlpsPS/2" };
+/*
+ * psmouse_sem protects all operations changing state of mouse
+ * (connecting, disconnecting, changing rate or resolution via
+ * sysfs). We could use a per-device semaphore but since there
+ * rarely more than one PS/2 mouse connected and since semaphore
+ * is taken in "slow" paths it is not worth it.
+ */
+static DECLARE_MUTEX(psmouse_sem);
+
+struct psmouse_protocol {
+ enum psmouse_type type;
+ char *name;
+ char *alias;
+ int maxproto;
+ int (*detect)(struct psmouse *, int);
+ int (*init)(struct psmouse *);
+};
/*
* psmouse_process_byte() analyzes the PS/2 data stream and reports
@@ -407,12 +424,15 @@ static int thinking_detect(struct psmouse *psmouse, int set_properties)
*/
static int ps2bare_detect(struct psmouse *psmouse, int set_properties)
{
- if (!psmouse->vendor) psmouse->vendor = "Generic";
- if (!psmouse->name) psmouse->name = "Mouse";
+ if (set_properties) {
+ if (!psmouse->vendor) psmouse->vendor = "Generic";
+ if (!psmouse->name) psmouse->name = "Mouse";
+ }
return 0;
}
+
/*
* psmouse_extensions() probes for any extensions to the basic PS/2 protocol
* the mouse may have.
@@ -424,6 +444,17 @@ static int psmouse_extensions(struct psmouse *psmouse,
int synaptics_hardware = 0;
/*
+ * We always check for lifebook because it does not disturb mouse
+ * (it only checks DMI information).
+ */
+ if (lifebook_detect(psmouse, set_properties) == 0) {
+ if (max_proto > PSMOUSE_IMEX) {
+ if (!set_properties || lifebook_init(psmouse) == 0)
+ return PSMOUSE_LIFEBOOK;
+ }
+ }
+
+/*
* Try Kensington ThinkingMouse (we try first, because synaptics probe
* upsets the thinkingmouse).
*/
@@ -506,6 +537,103 @@ static int psmouse_extensions(struct psmouse *psmouse,
return PSMOUSE_PS2;
}
+static struct psmouse_protocol psmouse_protocols[] = {
+ {
+ .type = PSMOUSE_PS2,
+ .name = "PS/2",
+ .alias = "bare",
+ .maxproto = 1,
+ .detect = ps2bare_detect,
+ },
+ {
+ .type = PSMOUSE_PS2PP,
+ .name = "PS2++",
+ .alias = "logitech",
+ .detect = ps2pp_init,
+ },
+ {
+ .type = PSMOUSE_THINKPS,
+ .name = "ThinkPS/2",
+ .alias = "thinkps",
+ .detect = thinking_detect,
+ },
+ {
+ .type = PSMOUSE_GENPS,
+ .name = "GenPS/2",
+ .alias = "genius",
+ .detect = genius_detect,
+ },
+ {
+ .type = PSMOUSE_IMPS,
+ .name = "ImPS/2",
+ .alias = "imps",
+ .maxproto = 1,
+ .detect = intellimouse_detect,
+ },
+ {
+ .type = PSMOUSE_IMEX,
+ .name = "ImExPS/2",
+ .alias = "exps",
+ .maxproto = 1,
+ .detect = im_explorer_detect,
+ },
+ {
+ .type = PSMOUSE_SYNAPTICS,
+ .name = "SynPS/2",
+ .alias = "synaptics",
+ .detect = synaptics_detect,
+ .init = synaptics_init,
+ },
+ {
+ .type = PSMOUSE_ALPS,
+ .name = "AlpsPS/2",
+ .alias = "alps",
+ .detect = alps_detect,
+ .init = alps_init,
+ },
+ {
+ .type = PSMOUSE_LIFEBOOK,
+ .name = "LBPS/2",
+ .alias = "lifebook",
+ .init = lifebook_init,
+ },
+ {
+ .type = PSMOUSE_AUTO,
+ .name = "auto",
+ .alias = "any",
+ .maxproto = 1,
+ },
+};
+
+static struct psmouse_protocol *psmouse_protocol_by_type(enum psmouse_type type)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(psmouse_protocols); i++)
+ if (psmouse_protocols[i].type == type)
+ return &psmouse_protocols[i];
+
+ WARN_ON(1);
+ return &psmouse_protocols[0];
+}
+
+static struct psmouse_protocol *psmouse_protocol_by_name(const char *name, size_t len)
+{
+ struct psmouse_protocol *p;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(psmouse_protocols); i++) {
+ p = &psmouse_protocols[i];
+
+ if ((strlen(p->name) == len && !strncmp(p->name, name, len)) ||
+ (strlen(p->alias) == len && !strncmp(p->alias, name, len)))
+ return &psmouse_protocols[i];
+ }
+
+ return NULL;
+}
+
+
/*
* psmouse_probe() probes for a PS/2 mouse.
*/
@@ -653,30 +781,84 @@ static void psmouse_cleanup(struct serio *serio)
static void psmouse_disconnect(struct serio *serio)
{
- struct psmouse *psmouse, *parent;
+ struct psmouse *psmouse, *parent = NULL;
+ psmouse = serio_get_drvdata(serio);
+
+ device_remove_file(&serio->dev, &psmouse_attr_protocol);
device_remove_file(&serio->dev, &psmouse_attr_rate);
device_remove_file(&serio->dev, &psmouse_attr_resolution);
device_remove_file(&serio->dev, &psmouse_attr_resetafter);
- psmouse = serio_get_drvdata(serio);
+ down(&psmouse_sem);
+
psmouse_set_state(psmouse, PSMOUSE_CMD_MODE);
if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) {
parent = serio_get_drvdata(serio->parent);
- if (parent->pt_deactivate)
- parent->pt_deactivate(parent);
+ psmouse_deactivate(parent);
}
if (psmouse->disconnect)
psmouse->disconnect(psmouse);
+ if (parent && parent->pt_deactivate)
+ parent->pt_deactivate(parent);
+
psmouse_set_state(psmouse, PSMOUSE_IGNORE);
input_unregister_device(&psmouse->dev);
serio_close(serio);
serio_set_drvdata(serio, NULL);
kfree(psmouse);
+
+ if (parent)
+ psmouse_activate(parent);
+
+ up(&psmouse_sem);
+}
+
+static int psmouse_switch_protocol(struct psmouse *psmouse, struct psmouse_protocol *proto)
+{
+ memset(&psmouse->dev, 0, sizeof(struct input_dev));
+
+ init_input_dev(&psmouse->dev);
+
+ psmouse->dev.private = psmouse;
+ psmouse->dev.dev = &psmouse->ps2dev.serio->dev;
+
+ psmouse->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
+ psmouse->dev.keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT);
+ psmouse->dev.relbit[0] = BIT(REL_X) | BIT(REL_Y);
+
+ psmouse->set_rate = psmouse_set_rate;
+ psmouse->set_resolution = psmouse_set_resolution;
+ psmouse->protocol_handler = psmouse_process_byte;
+ psmouse->pktsize = 3;
+
+ if (proto && (proto->detect || proto->init)) {
+ if (proto->detect && proto->detect(psmouse, 1) < 0)
+ return -1;
+
+ if (proto->init && proto->init(psmouse) < 0)
+ return -1;
+
+ psmouse->type = proto->type;
+ }
+ else
+ psmouse->type = psmouse_extensions(psmouse, psmouse_max_proto, 1);
+
+ sprintf(psmouse->devname, "%s %s %s",
+ psmouse_protocol_by_type(psmouse->type)->name, psmouse->vendor, psmouse->name);
+
+ psmouse->dev.name = psmouse->devname;
+ psmouse->dev.phys = psmouse->phys;
+ psmouse->dev.id.bustype = BUS_I8042;
+ psmouse->dev.id.vendor = 0x0002;
+ psmouse->dev.id.product = psmouse->type;
+ psmouse->dev.id.version = psmouse->model;
+
+ return 0;
}
/*
@@ -688,6 +870,8 @@ static int psmouse_connect(struct serio *serio, struct serio_driver *drv)
struct psmouse *psmouse, *parent = NULL;
int retval;
+ down(&psmouse_sem);
+
/*
* If this is a pass-through port deactivate parent so the device
* connected to this port can be successfully identified
@@ -697,20 +881,14 @@ static int psmouse_connect(struct serio *serio, struct serio_driver *drv)
psmouse_deactivate(parent);
}
- if (!(psmouse = kmalloc(sizeof(struct psmouse), GFP_KERNEL))) {
+ if (!(psmouse = kcalloc(1, sizeof(struct psmouse), GFP_KERNEL))) {
retval = -ENOMEM;
goto out;
}
- memset(psmouse, 0, sizeof(struct psmouse));
-
ps2_init(&psmouse->ps2dev, serio);
sprintf(psmouse->phys, "%s/input0", serio->phys);
- psmouse->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
- psmouse->dev.keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT);
- psmouse->dev.relbit[0] = BIT(REL_X) | BIT(REL_Y);
- psmouse->dev.private = psmouse;
- psmouse->dev.dev = &serio->dev;
+
psmouse_set_state(psmouse, PSMOUSE_INITIALIZING);
serio_set_drvdata(serio, psmouse);
@@ -734,25 +912,10 @@ static int psmouse_connect(struct serio *serio, struct serio_driver *drv)
psmouse->resolution = psmouse_resolution;
psmouse->resetafter = psmouse_resetafter;
psmouse->smartscroll = psmouse_smartscroll;
- psmouse->set_rate = psmouse_set_rate;
- psmouse->set_resolution = psmouse_set_resolution;
- psmouse->protocol_handler = psmouse_process_byte;
- psmouse->pktsize = 3;
- psmouse->type = psmouse_extensions(psmouse, psmouse_max_proto, 1);
-
- sprintf(psmouse->devname, "%s %s %s",
- psmouse_protocols[psmouse->type], psmouse->vendor, psmouse->name);
-
- psmouse->dev.name = psmouse->devname;
- psmouse->dev.phys = psmouse->phys;
- psmouse->dev.id.bustype = BUS_I8042;
- psmouse->dev.id.vendor = 0x0002;
- psmouse->dev.id.product = psmouse->type;
- psmouse->dev.id.version = psmouse->model;
+ psmouse_switch_protocol(psmouse, NULL);
input_register_device(&psmouse->dev);
-
printk(KERN_INFO "input: %s on %s\n", psmouse->devname, serio->phys);
psmouse_set_state(psmouse, PSMOUSE_CMD_MODE);
@@ -762,6 +925,7 @@ static int psmouse_connect(struct serio *serio, struct serio_driver *drv)
if (parent && parent->pt_activate)
parent->pt_activate(parent);
+ device_create_file(&serio->dev, &psmouse_attr_protocol);
device_create_file(&serio->dev, &psmouse_attr_rate);
device_create_file(&serio->dev, &psmouse_attr_resolution);
device_create_file(&serio->dev, &psmouse_attr_resetafter);
@@ -771,10 +935,11 @@ static int psmouse_connect(struct serio *serio, struct serio_driver *drv)
retval = 0;
out:
- /* If this is a pass-through port the parent awaits to be activated */
+ /* If this is a pass-through port the parent needs to be re-activated */
if (parent)
psmouse_activate(parent);
+ up(&psmouse_sem);
return retval;
}
@@ -791,6 +956,8 @@ static int psmouse_reconnect(struct serio *serio)
return -1;
}
+ down(&psmouse_sem);
+
if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) {
parent = serio_get_drvdata(serio->parent);
psmouse_deactivate(parent);
@@ -823,6 +990,7 @@ out:
if (parent)
psmouse_activate(parent);
+ up(&psmouse_sem);
return rc;
}
@@ -893,26 +1061,109 @@ ssize_t psmouse_attr_set_helper(struct device *dev, const char *buf, size_t coun
if (serio->drv != &psmouse_drv) {
retval = -ENODEV;
- goto out;
+ goto out_unpin;
+ }
+
+ retval = down_interruptible(&psmouse_sem);
+ if (retval)
+ goto out_unpin;
+
+ if (psmouse->state == PSMOUSE_IGNORE) {
+ retval = -ENODEV;
+ goto out_up;
}
if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) {
parent = serio_get_drvdata(serio->parent);
psmouse_deactivate(parent);
}
+
psmouse_deactivate(psmouse);
retval = handler(psmouse, buf, count);
- psmouse_activate(psmouse);
+ if (retval != -ENODEV)
+ psmouse_activate(psmouse);
+
if (parent)
psmouse_activate(parent);
-out:
+ out_up:
+ up(&psmouse_sem);
+ out_unpin:
serio_unpin_driver(serio);
return retval;
}
+static ssize_t psmouse_attr_show_protocol(struct psmouse *psmouse, char *buf)
+{
+ return sprintf(buf, "%s\n", psmouse_protocol_by_type(psmouse->type)->name);
+}
+
+static ssize_t psmouse_attr_set_protocol(struct psmouse *psmouse, const char *buf, size_t count)
+{
+ struct serio *serio = psmouse->ps2dev.serio;
+ struct psmouse *parent = NULL;
+ struct psmouse_protocol *proto;
+ int retry = 0;
+
+ if (!(proto = psmouse_protocol_by_name(buf, count)))
+ return -EINVAL;
+
+ if (psmouse->type == proto->type)
+ return count;
+
+ while (serio->child) {
+ if (++retry > 3) {
+ printk(KERN_WARNING "psmouse: failed to destroy child port, protocol change aborted.\n");
+ return -EIO;
+ }
+
+ up(&psmouse_sem);
+ serio_unpin_driver(serio);
+ serio_unregister_child_port(serio);
+ serio_pin_driver_uninterruptible(serio);
+ down(&psmouse_sem);
+
+ if (serio->drv != &psmouse_drv)
+ return -ENODEV;
+
+ if (psmouse->type == proto->type)
+ return count; /* switched by other thread */
+ }
+
+ if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) {
+ parent = serio_get_drvdata(serio->parent);
+ if (parent->pt_deactivate)
+ parent->pt_deactivate(parent);
+ }
+
+ if (psmouse->disconnect)
+ psmouse->disconnect(psmouse);
+
+ psmouse_set_state(psmouse, PSMOUSE_IGNORE);
+ input_unregister_device(&psmouse->dev);
+
+ psmouse_set_state(psmouse, PSMOUSE_INITIALIZING);
+
+ if (psmouse_switch_protocol(psmouse, proto) < 0) {
+ psmouse_reset(psmouse);
+ /* default to PSMOUSE_PS2 */
+ psmouse_switch_protocol(psmouse, &psmouse_protocols[0]);
+ }
+
+ psmouse_initialize(psmouse);
+ psmouse_set_state(psmouse, PSMOUSE_CMD_MODE);
+
+ input_register_device(&psmouse->dev);
+ printk(KERN_INFO "input: %s on %s\n", psmouse->devname, serio->phys);
+
+ if (parent && parent->pt_activate)
+ parent->pt_activate(parent);
+
+ return count;
+}
+
static ssize_t psmouse_attr_show_rate(struct psmouse *psmouse, char *buf)
{
return sprintf(buf, "%d\n", psmouse->rate);
@@ -969,34 +1220,26 @@ static ssize_t psmouse_attr_set_resetafter(struct psmouse *psmouse, const char *
static int psmouse_set_maxproto(const char *val, struct kernel_param *kp)
{
- int i;
+ struct psmouse_protocol *proto;
if (!val)
return -EINVAL;
- if (!strncmp(val, "any", 3)) {
- *((unsigned int *)kp->arg) = -1U;
- return 0;
- }
+ proto = psmouse_protocol_by_name(val, strlen(val));
- for (i = 0; i < ARRAY_SIZE(psmouse_proto_abbrev); i++) {
- if (!psmouse_proto_abbrev[i])
- continue;
+ if (!proto || !proto->maxproto)
+ return -EINVAL;
- if (!strncmp(val, psmouse_proto_abbrev[i], strlen(psmouse_proto_abbrev[i]))) {
- *((unsigned int *)kp->arg) = i;
- return 0;
- }
- }
+ *((unsigned int *)kp->arg) = proto->type;
- return -EINVAL; \
+ return 0; \
}
static int psmouse_get_maxproto(char *buffer, struct kernel_param *kp)
{
- return sprintf(buffer, "%s\n",
- psmouse_max_proto < ARRAY_SIZE(psmouse_proto_abbrev) ?
- psmouse_proto_abbrev[psmouse_max_proto] : "any");
+ int type = *((unsigned int *)kp->arg);
+
+ return sprintf(buffer, "%s\n", psmouse_protocol_by_type(type)->name);
}
static int __init psmouse_init(void)
diff --git a/drivers/input/mouse/psmouse.h b/drivers/input/mouse/psmouse.h
index 79e17a0c466..86691cf4343 100644
--- a/drivers/input/mouse/psmouse.h
+++ b/drivers/input/mouse/psmouse.h
@@ -77,6 +77,8 @@ enum psmouse_type {
PSMOUSE_IMEX,
PSMOUSE_SYNAPTICS,
PSMOUSE_ALPS,
+ PSMOUSE_LIFEBOOK,
+ PSMOUSE_AUTO /* This one should always be last */
};
int psmouse_sliced_command(struct psmouse *psmouse, unsigned char command);
@@ -99,7 +101,7 @@ static ssize_t psmouse_do_set_##_name(struct device *d, struct device_attribute
{ \
return psmouse_attr_set_helper(d, b, s, psmouse_attr_set_##_name); \
} \
-static struct device_attribute psmouse_attr_##_name = \
+static struct device_attribute psmouse_attr_##_name = \
__ATTR(_name, S_IWUSR | S_IRUGO, \
psmouse_do_show_##_name, psmouse_do_set_##_name);
diff --git a/drivers/input/mouse/rpcmouse.c b/drivers/input/mouse/rpcmouse.c
index 7280f68afce..8fe1212b8fd 100644
--- a/drivers/input/mouse/rpcmouse.c
+++ b/drivers/input/mouse/rpcmouse.c
@@ -59,7 +59,7 @@ static irqreturn_t rpcmouse_irq(int irq, void *dev_id, struct pt_regs *regs)
b = (short) (__raw_readl(0xe0310000) ^ 0x70);
dx = x - rpcmouse_lastx;
- dy = y - rpcmouse_lasty;
+ dy = y - rpcmouse_lasty;
rpcmouse_lastx = x;
rpcmouse_lasty = y;
diff --git a/drivers/input/mouse/vsxxxaa.c b/drivers/input/mouse/vsxxxaa.c
index b2cb101c811..f024be9b44d 100644
--- a/drivers/input/mouse/vsxxxaa.c
+++ b/drivers/input/mouse/vsxxxaa.c
@@ -1,7 +1,7 @@
/*
* Driver for DEC VSXXX-AA mouse (hockey-puck mouse, ball or two rollers)
- * DEC VSXXX-GA mouse (rectangular mouse, with ball)
- * DEC VSXXX-AB tablet (digitizer with hair cross or stylus)
+ * DEC VSXXX-GA mouse (rectangular mouse, with ball)
+ * DEC VSXXX-AB tablet (digitizer with hair cross or stylus)
*
* Copyright (C) 2003-2004 by Jan-Benedict Glaw <jbglaw@lug-owl.de>
*
diff --git a/drivers/input/mousedev.c b/drivers/input/mousedev.c
index 062848ac7e6..c6194a9dd17 100644
--- a/drivers/input/mousedev.c
+++ b/drivers/input/mousedev.c
@@ -220,6 +220,7 @@ static void mousedev_notify_readers(struct mousedev *mousedev, struct mousedev_h
struct mousedev_list *list;
struct mousedev_motion *p;
unsigned long flags;
+ int wake_readers = 0;
list_for_each_entry(list, &mousedev->list, node) {
spin_lock_irqsave(&list->packet_lock, flags);
@@ -255,11 +256,14 @@ static void mousedev_notify_readers(struct mousedev *mousedev, struct mousedev_h
spin_unlock_irqrestore(&list->packet_lock, flags);
- if (list->ready)
+ if (list->ready) {
kill_fasync(&list->fasync, SIGIO, POLL_IN);
+ wake_readers = 1;
+ }
}
- wake_up_interruptible(&mousedev->wait);
+ if (wake_readers)
+ wake_up_interruptible(&mousedev->wait);
}
static void mousedev_touchpad_touch(struct mousedev *mousedev, int value)
diff --git a/drivers/input/serio/libps2.c b/drivers/input/serio/libps2.c
index c978657068c..d4c990f7c85 100644
--- a/drivers/input/serio/libps2.c
+++ b/drivers/input/serio/libps2.c
@@ -29,6 +29,7 @@ MODULE_LICENSE("GPL");
EXPORT_SYMBOL(ps2_init);
EXPORT_SYMBOL(ps2_sendbyte);
+EXPORT_SYMBOL(ps2_drain);
EXPORT_SYMBOL(ps2_command);
EXPORT_SYMBOL(ps2_schedule_command);
EXPORT_SYMBOL(ps2_handle_ack);
@@ -45,11 +46,11 @@ struct ps2work {
/*
- * ps2_sendbyte() sends a byte to the mouse, and waits for acknowledge.
- * It doesn't handle retransmission, though it could - because when there would
- * be need for retransmissions, the mouse has to be replaced anyway.
+ * ps2_sendbyte() sends a byte to the device and waits for acknowledge.
+ * It doesn't handle retransmission, though it could - because if there
+ * is a need for retransmissions device has to be replaced anyway.
*
- * ps2_sendbyte() can only be called from a process context
+ * ps2_sendbyte() can only be called from a process context.
*/
int ps2_sendbyte(struct ps2dev *ps2dev, unsigned char byte, int timeout)
@@ -72,6 +73,91 @@ int ps2_sendbyte(struct ps2dev *ps2dev, unsigned char byte, int timeout)
}
/*
+ * ps2_drain() waits for device to transmit requested number of bytes
+ * and discards them.
+ */
+
+void ps2_drain(struct ps2dev *ps2dev, int maxbytes, int timeout)
+{
+ if (maxbytes > sizeof(ps2dev->cmdbuf)) {
+ WARN_ON(1);
+ maxbytes = sizeof(ps2dev->cmdbuf);
+ }
+
+ down(&ps2dev->cmd_sem);
+
+ serio_pause_rx(ps2dev->serio);
+ ps2dev->flags = PS2_FLAG_CMD;
+ ps2dev->cmdcnt = maxbytes;
+ serio_continue_rx(ps2dev->serio);
+
+ wait_event_timeout(ps2dev->wait,
+ !(ps2dev->flags & PS2_FLAG_CMD),
+ msecs_to_jiffies(timeout));
+ up(&ps2dev->cmd_sem);
+}
+
+/*
+ * ps2_is_keyboard_id() checks received ID byte against the list of
+ * known keyboard IDs.
+ */
+
+static inline int ps2_is_keyboard_id(char id_byte)
+{
+ static char keyboard_ids[] = {
+ 0xab, /* Regular keyboards */
+ 0xac, /* NCD Sun keyboard */
+ 0x2b, /* Trust keyboard, translated */
+ 0x5d, /* Trust keyboard */
+ 0x60, /* NMB SGI keyboard, translated */
+ 0x47, /* NMB SGI keyboard */
+ };
+
+ return memchr(keyboard_ids, id_byte, sizeof(keyboard_ids)) != NULL;
+}
+
+/*
+ * ps2_adjust_timeout() is called after receiving 1st byte of command
+ * response and tries to reduce remaining timeout to speed up command
+ * completion.
+ */
+
+static int ps2_adjust_timeout(struct ps2dev *ps2dev, int command, int timeout)
+{
+ switch (command) {
+ case PS2_CMD_RESET_BAT:
+ /*
+ * Device has sent the first response byte after
+ * reset command, reset is thus done, so we can
+ * shorten the timeout.
+ * The next byte will come soon (keyboard) or not
+ * at all (mouse).
+ */
+ if (timeout > msecs_to_jiffies(100))
+ timeout = msecs_to_jiffies(100);
+ break;
+
+ case PS2_CMD_GETID:
+ /*
+ * If device behind the port is not a keyboard there
+ * won't be 2nd byte of ID response.
+ */
+ if (!ps2_is_keyboard_id(ps2dev->cmdbuf[1])) {
+ serio_pause_rx(ps2dev->serio);
+ ps2dev->flags = ps2dev->cmdcnt = 0;
+ serio_continue_rx(ps2dev->serio);
+ timeout = 0;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return timeout;
+}
+
+/*
* ps2_command() sends a command and its parameters to the mouse,
* then waits for the response and puts it in the param array.
*
@@ -86,6 +172,11 @@ int ps2_command(struct ps2dev *ps2dev, unsigned char *param, int command)
int rc = -1;
int i;
+ if (receive > sizeof(ps2dev->cmdbuf)) {
+ WARN_ON(1);
+ return -1;
+ }
+
down(&ps2dev->cmd_sem);
serio_pause_rx(ps2dev->serio);
@@ -101,10 +192,9 @@ int ps2_command(struct ps2dev *ps2dev, unsigned char *param, int command)
* ACKing the reset command, and so it can take a long
* time before the ACK arrrives.
*/
- if (command & 0xff)
- if (ps2_sendbyte(ps2dev, command & 0xff,
- command == PS2_CMD_RESET_BAT ? 1000 : 200))
- goto out;
+ if (ps2_sendbyte(ps2dev, command & 0xff,
+ command == PS2_CMD_RESET_BAT ? 1000 : 200))
+ goto out;
for (i = 0; i < send; i++)
if (ps2_sendbyte(ps2dev, param[i], 200))
@@ -120,33 +210,7 @@ int ps2_command(struct ps2dev *ps2dev, unsigned char *param, int command)
if (ps2dev->cmdcnt && timeout > 0) {
- if (command == PS2_CMD_RESET_BAT && timeout > msecs_to_jiffies(100)) {
- /*
- * Device has sent the first response byte
- * after a reset command, reset is thus done,
- * shorten the timeout. The next byte will come
- * soon (keyboard) or not at all (mouse).
- */
- timeout = msecs_to_jiffies(100);
- }
-
- if (command == PS2_CMD_GETID &&
- ps2dev->cmdbuf[receive - 1] != 0xab && /* Regular keyboards */
- ps2dev->cmdbuf[receive - 1] != 0xac && /* NCD Sun keyboard */
- ps2dev->cmdbuf[receive - 1] != 0x2b && /* Trust keyboard, translated */
- ps2dev->cmdbuf[receive - 1] != 0x5d && /* Trust keyboard */
- ps2dev->cmdbuf[receive - 1] != 0x60 && /* NMB SGI keyboard, translated */
- ps2dev->cmdbuf[receive - 1] != 0x47) { /* NMB SGI keyboard */
- /*
- * Device behind the port is not a keyboard
- * so we don't need to wait for the 2nd byte
- * of ID response.
- */
- serio_pause_rx(ps2dev->serio);
- ps2dev->flags = ps2dev->cmdcnt = 0;
- serio_continue_rx(ps2dev->serio);
- }
-
+ timeout = ps2_adjust_timeout(ps2dev, command, timeout);
wait_event_timeout(ps2dev->wait,
!(ps2dev->flags & PS2_FLAG_CMD), timeout);
}
@@ -160,7 +224,7 @@ int ps2_command(struct ps2dev *ps2dev, unsigned char *param, int command)
rc = 0;
-out:
+ out:
serio_pause_rx(ps2dev->serio);
ps2dev->flags = 0;
serio_continue_rx(ps2dev->serio);
diff --git a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c
index 341824c4852..f367695e69b 100644
--- a/drivers/input/serio/serio.c
+++ b/drivers/input/serio/serio.c
@@ -31,10 +31,9 @@
#include <linux/serio.h>
#include <linux/errno.h>
#include <linux/wait.h>
-#include <linux/completion.h>
#include <linux/sched.h>
-#include <linux/smp_lock.h>
#include <linux/slab.h>
+#include <linux/kthread.h>
MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
MODULE_DESCRIPTION("Serio abstraction core");
@@ -43,6 +42,7 @@ MODULE_LICENSE("GPL");
EXPORT_SYMBOL(serio_interrupt);
EXPORT_SYMBOL(__serio_register_port);
EXPORT_SYMBOL(serio_unregister_port);
+EXPORT_SYMBOL(serio_unregister_child_port);
EXPORT_SYMBOL(__serio_unregister_port_delayed);
EXPORT_SYMBOL(__serio_register_driver);
EXPORT_SYMBOL(serio_unregister_driver);
@@ -68,6 +68,37 @@ static void serio_destroy_port(struct serio *serio);
static void serio_reconnect_port(struct serio *serio);
static void serio_disconnect_port(struct serio *serio);
+static int serio_connect_driver(struct serio *serio, struct serio_driver *drv)
+{
+ int retval;
+
+ down(&serio->drv_sem);
+ retval = drv->connect(serio, drv);
+ up(&serio->drv_sem);
+
+ return retval;
+}
+
+static int serio_reconnect_driver(struct serio *serio)
+{
+ int retval = -1;
+
+ down(&serio->drv_sem);
+ if (serio->drv && serio->drv->reconnect)
+ retval = serio->drv->reconnect(serio);
+ up(&serio->drv_sem);
+
+ return retval;
+}
+
+static void serio_disconnect_driver(struct serio *serio)
+{
+ down(&serio->drv_sem);
+ if (serio->drv)
+ serio->drv->disconnect(serio);
+ up(&serio->drv_sem);
+}
+
static int serio_match_port(const struct serio_device_id *ids, struct serio *serio)
{
while (ids->type || ids->proto) {
@@ -91,7 +122,7 @@ static void serio_bind_driver(struct serio *serio, struct serio_driver *drv)
if (serio_match_port(drv->id_table, serio)) {
serio->dev.driver = &drv->driver;
- if (drv->connect(serio, drv)) {
+ if (serio_connect_driver(serio, drv)) {
serio->dev.driver = NULL;
goto out;
}
@@ -138,8 +169,7 @@ struct serio_event {
static DEFINE_SPINLOCK(serio_event_lock); /* protects serio_event_list */
static LIST_HEAD(serio_event_list);
static DECLARE_WAIT_QUEUE_HEAD(serio_wait);
-static DECLARE_COMPLETION(serio_exited);
-static int serio_pid;
+static struct task_struct *serio_task;
static void serio_queue_event(void *object, struct module *owner,
enum serio_event_type event_type)
@@ -150,12 +180,12 @@ static void serio_queue_event(void *object, struct module *owner,
spin_lock_irqsave(&serio_event_lock, flags);
/*
- * Scan event list for the other events for the same serio port,
+ * Scan event list for the other events for the same serio port,
* starting with the most recent one. If event is the same we
* do not need add new one. If event is of different type we
* need to add this event and should not look further because
* we need to preseve sequence of distinct events.
- */
+ */
list_for_each_entry_reverse(event, &serio_event_list, node) {
if (event->object == object) {
if (event->type == event_type)
@@ -337,20 +367,15 @@ static struct serio *serio_get_pending_child(struct serio *parent)
static int serio_thread(void *nothing)
{
- lock_kernel();
- daemonize("kseriod");
- allow_signal(SIGTERM);
-
do {
serio_handle_events();
- wait_event_interruptible(serio_wait, !list_empty(&serio_event_list));
+ wait_event_interruptible(serio_wait,
+ kthread_should_stop() || !list_empty(&serio_event_list));
try_to_freeze();
- } while (!signal_pending(current));
+ } while (!kthread_should_stop());
printk(KERN_DEBUG "serio: kseriod exiting\n");
-
- unlock_kernel();
- complete_and_exit(&serio_exited, 0);
+ return 0;
}
@@ -557,7 +582,7 @@ static void serio_destroy_port(struct serio *serio)
static void serio_reconnect_port(struct serio *serio)
{
do {
- if (!serio->drv || !serio->drv->reconnect || serio->drv->reconnect(serio)) {
+ if (serio_reconnect_driver(serio)) {
serio_disconnect_port(serio);
serio_find_driver(serio);
/* Ok, old children are now gone, we are done */
@@ -630,6 +655,19 @@ void serio_unregister_port(struct serio *serio)
}
/*
+ * Safely unregisters child port if one is present.
+ */
+void serio_unregister_child_port(struct serio *serio)
+{
+ down(&serio_sem);
+ if (serio->child) {
+ serio_disconnect_port(serio->child);
+ serio_destroy_port(serio->child);
+ }
+ up(&serio_sem);
+}
+
+/*
* Submits register request to kseriod for subsequent execution.
* Can be used when it is not obvious whether the serio_sem is
* taken or not and when delayed execution is feasible.
@@ -686,15 +724,14 @@ static int serio_driver_probe(struct device *dev)
struct serio *serio = to_serio_port(dev);
struct serio_driver *drv = to_serio_driver(dev->driver);
- return drv->connect(serio, drv);
+ return serio_connect_driver(serio, drv);
}
static int serio_driver_remove(struct device *dev)
{
struct serio *serio = to_serio_port(dev);
- struct serio_driver *drv = to_serio_driver(dev->driver);
- drv->disconnect(serio);
+ serio_disconnect_driver(serio);
return 0;
}
@@ -730,11 +767,9 @@ start_over:
static void serio_set_drv(struct serio *serio, struct serio_driver *drv)
{
- down(&serio->drv_sem);
serio_pause_rx(serio);
serio->drv = drv;
serio_continue_rx(serio);
- up(&serio->drv_sem);
}
static int serio_bus_match(struct device *dev, struct device_driver *drv)
@@ -794,7 +829,7 @@ static int serio_resume(struct device *dev)
{
struct serio *serio = to_serio_port(dev);
- if (!serio->drv || !serio->drv->reconnect || serio->drv->reconnect(serio)) {
+ if (serio_reconnect_driver(serio)) {
/*
* Driver re-probing can take a while, so better let kseriod
* deal with it.
@@ -848,9 +883,10 @@ irqreturn_t serio_interrupt(struct serio *serio,
static int __init serio_init(void)
{
- if (!(serio_pid = kernel_thread(serio_thread, NULL, CLONE_KERNEL))) {
+ serio_task = kthread_run(serio_thread, NULL, "kseriod");
+ if (IS_ERR(serio_task)) {
printk(KERN_ERR "serio: Failed to start kseriod\n");
- return -1;
+ return PTR_ERR(serio_task);
}
serio_bus.dev_attrs = serio_device_attrs;
@@ -866,8 +902,7 @@ static int __init serio_init(void)
static void __exit serio_exit(void)
{
bus_unregister(&serio_bus);
- kill_proc(serio_pid, SIGTERM, 1);
- wait_for_completion(&serio_exited);
+ kthread_stop(serio_task);
}
module_init(serio_init);
diff --git a/drivers/input/touchscreen/elo.c b/drivers/input/touchscreen/elo.c
index 546ce599334..3cdc9cab688 100644
--- a/drivers/input/touchscreen/elo.c
+++ b/drivers/input/touchscreen/elo.c
@@ -226,7 +226,7 @@ static int elo_connect(struct serio *serio, struct serio_driver *drv)
input_set_abs_params(&elo->dev, ABS_Y, 96, 4000, 0, 0);
input_set_abs_params(&elo->dev, ABS_PRESSURE, 0, 255, 0, 0);
break;
-
+
case 1: /* 6-byte protocol */
input_set_abs_params(&elo->dev, ABS_PRESSURE, 0, 15, 0, 0);
diff --git a/drivers/input/touchscreen/h3600_ts_input.c b/drivers/input/touchscreen/h3600_ts_input.c
index acb9137a022..bcfa1e36f95 100644
--- a/drivers/input/touchscreen/h3600_ts_input.c
+++ b/drivers/input/touchscreen/h3600_ts_input.c
@@ -89,9 +89,9 @@ MODULE_LICENSE("GPL");
#define H3600_SCANCODE_Q 4 /* 4 -> Q button */
#define H3600_SCANCODE_START 5 /* 5 -> start menu */
#define H3600_SCANCODE_UP 6 /* 6 -> up */
-#define H3600_SCANCODE_RIGHT 7 /* 7 -> right */
-#define H3600_SCANCODE_LEFT 8 /* 8 -> left */
-#define H3600_SCANCODE_DOWN 9 /* 9 -> down */
+#define H3600_SCANCODE_RIGHT 7 /* 7 -> right */
+#define H3600_SCANCODE_LEFT 8 /* 8 -> left */
+#define H3600_SCANCODE_DOWN 9 /* 9 -> down */
static char *h3600_name = "H3600 TouchScreen";
@@ -113,7 +113,7 @@ struct h3600_dev {
static irqreturn_t action_button_handler(int irq, void *dev_id, struct pt_regs *regs)
{
- int down = (GPLR & GPIO_BITSY_ACTION_BUTTON) ? 0 : 1;
+ int down = (GPLR & GPIO_BITSY_ACTION_BUTTON) ? 0 : 1;
struct input_dev *dev = (struct input_dev *) dev_id;
input_regs(dev, regs);
@@ -125,7 +125,7 @@ static irqreturn_t action_button_handler(int irq, void *dev_id, struct pt_regs *
static irqreturn_t npower_button_handler(int irq, void *dev_id, struct pt_regs *regs)
{
- int down = (GPLR & GPIO_BITSY_NPOWER_BUTTON) ? 0 : 1;
+ int down = (GPLR & GPIO_BITSY_NPOWER_BUTTON) ? 0 : 1;
struct input_dev *dev = (struct input_dev *) dev_id;
/*
@@ -145,8 +145,8 @@ static irqreturn_t npower_button_handler(int irq, void *dev_id, struct pt_regs *
static int flite_brightness = 25;
enum flite_pwr {
- FLITE_PWR_OFF = 0,
- FLITE_PWR_ON = 1
+ FLITE_PWR_OFF = 0,
+ FLITE_PWR_ON = 1
};
/*
@@ -157,9 +157,9 @@ unsigned int h3600_flite_power(struct input_dev *dev, enum flite_pwr pwr)
struct h3600_dev *ts = dev->private;
/* Must be in this order */
- ts->serio->write(ts->serio, 1);
+ ts->serio->write(ts->serio, 1);
ts->serio->write(ts->serio, pwr);
- ts->serio->write(ts->serio, brightness);
+ ts->serio->write(ts->serio, brightness);
return 0;
}
@@ -169,26 +169,26 @@ static int h3600ts_pm_callback(struct pm_dev *pm_dev, pm_request_t req,
{
struct input_dev *dev = (struct input_dev *) data;
- switch (req) {
- case PM_SUSPEND: /* enter D1-D3 */
- suspended = 1;
- h3600_flite_power(dev, FLITE_PWR_OFF);
- break;
- case PM_BLANK:
- if (!suspended)
- h3600_flite_power(dev, FLITE_PWR_OFF);
- break;
- case PM_RESUME: /* enter D0 */
- /* same as unblank */
- case PM_UNBLANK:
- if (suspended) {
- //initSerial();
- suspended = 0;
- }
- h3600_flite_power(dev, FLITE_PWR_ON);
- break;
- }
- return 0;
+ switch (req) {
+ case PM_SUSPEND: /* enter D1-D3 */
+ suspended = 1;
+ h3600_flite_power(dev, FLITE_PWR_OFF);
+ break;
+ case PM_BLANK:
+ if (!suspended)
+ h3600_flite_power(dev, FLITE_PWR_OFF);
+ break;
+ case PM_RESUME: /* enter D0 */
+ /* same as unblank */
+ case PM_UNBLANK:
+ if (suspended) {
+ //initSerial();
+ suspended = 0;
+ }
+ h3600_flite_power(dev, FLITE_PWR_ON);
+ break;
+ }
+ return 0;
}
#endif
@@ -199,25 +199,25 @@ static int h3600ts_pm_callback(struct pm_dev *pm_dev, pm_request_t req,
*/
static void h3600ts_process_packet(struct h3600_dev *ts, struct pt_regs *regs)
{
- struct input_dev *dev = &ts->dev;
+ struct input_dev *dev = &ts->dev;
static int touched = 0;
int key, down = 0;
input_regs(dev, regs);
- switch (ts->event) {
- /*
- Buttons - returned as a single byte
- 7 6 5 4 3 2 1 0
- S x x x N N N N
+ switch (ts->event) {
+ /*
+ Buttons - returned as a single byte
+ 7 6 5 4 3 2 1 0
+ S x x x N N N N
- S switch state ( 0=pressed 1=released)
- x Unused.
- NNNN switch number 0-15
+ S switch state ( 0=pressed 1=released)
+ x Unused.
+ NNNN switch number 0-15
- Note: This is true for non interrupt generated key events.
- */
- case KEYBD_ID:
+ Note: This is true for non interrupt generated key events.
+ */
+ case KEYBD_ID:
down = (ts->buf[0] & 0x80) ? 0 : 1;
switch (ts->buf[0] & 0x7f) {
@@ -229,40 +229,40 @@ static void h3600ts_process_packet(struct h3600_dev *ts, struct pt_regs *regs)
break;
case H3600_SCANCODE_CONTACTS:
key = KEY_PROG2;
- break;
+ break;
case H3600_SCANCODE_Q:
key = KEY_Q;
- break;
+ break;
case H3600_SCANCODE_START:
key = KEY_PROG3;
- break;
+ break;
case H3600_SCANCODE_UP:
key = KEY_UP;
- break;
+ break;
case H3600_SCANCODE_RIGHT:
key = KEY_RIGHT;
- break;
+ break;
case H3600_SCANCODE_LEFT:
key = KEY_LEFT;
- break;
+ break;
case H3600_SCANCODE_DOWN:
key = KEY_DOWN;
- break;
+ break;
default:
key = 0;
}
- if (key)
- input_report_key(dev, key, down);
- break;
- /*
- * Native touchscreen event data is formatted as shown below:-
- *
- * +-------+-------+-------+-------+
- * | Xmsb | Xlsb | Ymsb | Ylsb |
- * +-------+-------+-------+-------+
- * byte 0 1 2 3
- */
- case TOUCHS_ID:
+ if (key)
+ input_report_key(dev, key, down);
+ break;
+ /*
+ * Native touchscreen event data is formatted as shown below:-
+ *
+ * +-------+-------+-------+-------+
+ * | Xmsb | Xlsb | Ymsb | Ylsb |
+ * +-------+-------+-------+-------+
+ * byte 0 1 2 3
+ */
+ case TOUCHS_ID:
if (!touched) {
input_report_key(dev, BTN_TOUCH, 1);
touched = 1;
@@ -272,19 +272,19 @@ static void h3600ts_process_packet(struct h3600_dev *ts, struct pt_regs *regs)
unsigned short x, y;
x = ts->buf[0]; x <<= 8; x += ts->buf[1];
- y = ts->buf[2]; y <<= 8; y += ts->buf[3];
+ y = ts->buf[2]; y <<= 8; y += ts->buf[3];
- input_report_abs(dev, ABS_X, x);
- input_report_abs(dev, ABS_Y, y);
+ input_report_abs(dev, ABS_X, x);
+ input_report_abs(dev, ABS_Y, y);
} else {
- input_report_key(dev, BTN_TOUCH, 0);
+ input_report_key(dev, BTN_TOUCH, 0);
touched = 0;
}
- break;
+ break;
default:
/* Send a non input event elsewhere */
break;
- }
+ }
input_sync(dev);
}
@@ -293,7 +293,7 @@ static void h3600ts_process_packet(struct h3600_dev *ts, struct pt_regs *regs)
* h3600ts_event() handles events from the input module.
*/
static int h3600ts_event(struct input_dev *dev, unsigned int type,
- unsigned int code, int value)
+ unsigned int code, int value)
{
struct h3600_dev *ts = dev->private;
@@ -332,41 +332,41 @@ static int state;
static irqreturn_t h3600ts_interrupt(struct serio *serio, unsigned char data,
unsigned int flags, struct pt_regs *regs)
{
- struct h3600_dev *ts = serio_get_drvdata(serio);
+ struct h3600_dev *ts = serio_get_drvdata(serio);
/*
- * We have a new frame coming in.
- */
+ * We have a new frame coming in.
+ */
switch (state) {
case STATE_SOF:
- if (data == CHAR_SOF)
- state = STATE_ID;
+ if (data == CHAR_SOF)
+ state = STATE_ID;
break;
- case STATE_ID:
+ case STATE_ID:
ts->event = (data & 0xf0) >> 4;
ts->len = (data & 0xf);
ts->idx = 0;
if (ts->event >= MAX_ID) {
state = STATE_SOF;
- break;
+ break;
}
ts->chksum = data;
- state = (ts->len > 0) ? STATE_DATA : STATE_EOF;
+ state = (ts->len > 0) ? STATE_DATA : STATE_EOF;
break;
case STATE_DATA:
ts->chksum += data;
ts->buf[ts->idx]= data;
- if(++ts->idx == ts->len)
- state = STATE_EOF;
+ if (++ts->idx == ts->len)
+ state = STATE_EOF;
break;
case STATE_EOF:
- state = STATE_SOF;
- if (data == CHAR_EOF || data == ts->chksum)
+ state = STATE_SOF;
+ if (data == CHAR_EOF || data == ts->chksum)
h3600ts_process_packet(ts, regs);
- break;
- default:
- printk("Error3\n");
- break;
+ break;
+ default:
+ printk("Error3\n");
+ break;
}
return IRQ_HANDLED;
@@ -390,10 +390,10 @@ static int h3600ts_connect(struct serio *serio, struct serio_driver *drv)
init_input_dev(&ts->dev);
/* Device specific stuff */
- set_GPIO_IRQ_edge(GPIO_BITSY_ACTION_BUTTON, GPIO_BOTH_EDGES);
- set_GPIO_IRQ_edge(GPIO_BITSY_NPOWER_BUTTON, GPIO_RISING_EDGE);
+ set_GPIO_IRQ_edge(GPIO_BITSY_ACTION_BUTTON, GPIO_BOTH_EDGES);
+ set_GPIO_IRQ_edge(GPIO_BITSY_NPOWER_BUTTON, GPIO_RISING_EDGE);
- if (request_irq(IRQ_GPIO_BITSY_ACTION_BUTTON, action_button_handler,
+ if (request_irq(IRQ_GPIO_BITSY_ACTION_BUTTON, action_button_handler,
SA_SHIRQ | SA_INTERRUPT | SA_SAMPLE_RANDOM,
"h3600_action", &ts->dev)) {
printk(KERN_ERR "h3600ts.c: Could not allocate Action Button IRQ!\n");
@@ -401,7 +401,7 @@ static int h3600ts_connect(struct serio *serio, struct serio_driver *drv)
return -EBUSY;
}
- if (request_irq(IRQ_GPIO_BITSY_NPOWER_BUTTON, npower_button_handler,
+ if (request_irq(IRQ_GPIO_BITSY_NPOWER_BUTTON, npower_button_handler,
SA_SHIRQ | SA_INTERRUPT | SA_SAMPLE_RANDOM,
"h3600_suspend", &ts->dev)) {
free_irq(IRQ_GPIO_BITSY_ACTION_BUTTON, &ts->dev);
@@ -433,7 +433,7 @@ static int h3600ts_connect(struct serio *serio, struct serio_driver *drv)
sprintf(ts->phys, "%s/input0", serio->phys);
- ts->dev.event = h3600ts_event;
+ ts->dev.event = h3600ts_event;
ts->dev.private = ts;
ts->dev.name = h3600_name;
ts->dev.phys = ts->phys;
@@ -446,8 +446,8 @@ static int h3600ts_connect(struct serio *serio, struct serio_driver *drv)
err = serio_open(serio, drv);
if (err) {
- free_irq(IRQ_GPIO_BITSY_ACTION_BUTTON, ts);
- free_irq(IRQ_GPIO_BITSY_NPOWER_BUTTON, ts);
+ free_irq(IRQ_GPIO_BITSY_ACTION_BUTTON, ts);
+ free_irq(IRQ_GPIO_BITSY_NPOWER_BUTTON, ts);
serio_set_drvdata(serio, NULL);
kfree(ts);
return err;
diff --git a/drivers/input/touchscreen/mk712.c b/drivers/input/touchscreen/mk712.c
index 2d14a57a05e..afaaebe5225 100644
--- a/drivers/input/touchscreen/mk712.c
+++ b/drivers/input/touchscreen/mk712.c
@@ -17,7 +17,7 @@
* found in Gateway AOL Connected Touchpad computers.
*
* Documentation for ICS MK712 can be found at:
- * http://www.icst.com/pdf/mk712.pdf
+ * http://www.icst.com/pdf/mk712.pdf
*/
/*
@@ -77,7 +77,6 @@ MODULE_PARM_DESC(irq, "IRQ of MK712 touchscreen controller");
#define MK712_READ_ONE_POINT 0x20
#define MK712_POWERUP 0x40
-static int mk712_used = 0;
static struct input_dev mk712_dev;
static DEFINE_SPINLOCK(mk712_lock);
@@ -130,17 +129,14 @@ static int mk712_open(struct input_dev *dev)
spin_lock_irqsave(&mk712_lock, flags);
- if (!mk712_used++) {
+ outb(0, mk712_io + MK712_CONTROL); /* Reset */
- outb(0, mk712_io + MK712_CONTROL); /* Reset */
+ outb(MK712_ENABLE_INT | MK712_INT_ON_CONVERSION_COMPLETE |
+ MK712_INT_ON_CHANGE_IN_TOUCH_STATUS |
+ MK712_ENABLE_PERIODIC_CONVERSIONS |
+ MK712_POWERUP, mk712_io + MK712_CONTROL);
- outb(MK712_ENABLE_INT | MK712_INT_ON_CONVERSION_COMPLETE |
- MK712_INT_ON_CHANGE_IN_TOUCH_STATUS |
- MK712_ENABLE_PERIODIC_CONVERSIONS |
- MK712_POWERUP, mk712_io + MK712_CONTROL);
-
- outb(10, mk712_io + MK712_RATE); /* 187 points per second */
- }
+ outb(10, mk712_io + MK712_RATE); /* 187 points per second */
spin_unlock_irqrestore(&mk712_lock, flags);
@@ -153,8 +149,7 @@ static void mk712_close(struct input_dev *dev)
spin_lock_irqsave(&mk712_lock, flags);
- if (!--mk712_used)
- outb(0, mk712_io + MK712_CONTROL);
+ outb(0, mk712_io + MK712_CONTROL);
spin_unlock_irqrestore(&mk712_lock, flags);
}