diff options
author | Jeff Garzik <jgarzik@pobox.com> | 2005-08-10 19:46:28 +0200 |
---|---|---|
committer | Jeff Garzik <jgarzik@pobox.com> | 2005-08-10 19:46:28 +0200 |
commit | 2f058256cb64e346f4fb4499ff4e0f1c2791a4b4 (patch) | |
tree | 91e06602f4d3abb6812ea8c9bc9ba4501e14c84e /drivers/input | |
parent | libata: Update 'passthru' branch for latest libata (diff) | |
parent | [PATCH] Fix ide-disk.c oops caused by hwif == NULL (diff) | |
download | linux-2f058256cb64e346f4fb4499ff4e0f1c2791a4b4.tar.xz linux-2f058256cb64e346f4fb4499ff4e0f1c2791a4b4.zip |
Merge /spare/repo/linux-2.6/
Diffstat (limited to 'drivers/input')
56 files changed, 1780 insertions, 1466 deletions
diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c index 556264b43425..20e3a165989f 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; @@ -234,6 +320,7 @@ static int evdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, if (t < 0 || t >= dev->keycodemax || !dev->keycodesize) return -EINVAL; if (get_user(v, ip + 1)) return -EFAULT; if (v < 0 || v > KEY_MAX) return -EINVAL; + if (v >> (dev->keycodesize * 8)) return -EINVAL; u = SET_INPUT_KEYCODE(dev, t, v); clear_bit(u, dev->keybit); set_bit(v, dev->keybit); @@ -285,109 +372,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 +641,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 1d93f5092904..7524bd7d8b8f 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 5367b4267adf..b6f6097bd8c4 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 d4013ff98623..000000000000 --- 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 e152d0fa0cdd..ab09cf4093e3 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)); - try_to_freeze(PF_FREEZE); - } while (!signal_pending(current)); + wait_event_interruptible(gameport_wait, + kthread_should_stop() || !list_empty(&gameport_event_list)); + try_to_freeze(); + } 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 7c5c6318eeb9..1ab5f2dc8a2a 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 36b0309c8bf6..000000000000 --- 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 83c77c990dda..a275211c8e1e 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c @@ -48,12 +48,6 @@ static LIST_HEAD(input_handler_list); static struct input_handler *input_table[8]; -#ifdef CONFIG_PROC_FS -static struct proc_dir_entry *proc_bus_input_dir; -static DECLARE_WAIT_QUEUE_HEAD(input_devices_poll_wait); -static int input_devices_state; -#endif - void input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) { struct input_handle *handle; @@ -219,10 +213,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 +243,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) @@ -291,6 +306,7 @@ static struct input_device_id *input_match_device(struct input_device_id *id, st return NULL; } + /* * Input hotplugging interface - loading event handlers based on * device bitfields. @@ -407,6 +423,177 @@ static void input_call_hotplug(char *verb, struct input_dev *dev) #endif +#ifdef CONFIG_PROC_FS + +static struct proc_dir_entry *proc_bus_input_dir; +static DECLARE_WAIT_QUEUE_HEAD(input_devices_poll_wait); +static int input_devices_state; + +static inline void input_wakeup_procfs_readers(void) +{ + input_devices_state++; + wake_up(&input_devices_poll_wait); +} + +static unsigned int input_devices_poll(struct file *file, poll_table *wait) +{ + int state = input_devices_state; + poll_wait(file, &input_devices_poll_wait, wait); + if (state != input_devices_state) + return POLLIN | POLLRDNORM; + return 0; +} + +#define SPRINTF_BIT_B(bit, name, max) \ + do { \ + len += sprintf(buf + len, "B: %s", name); \ + for (i = NBITS(max) - 1; i >= 0; i--) \ + if (dev->bit[i]) break; \ + for (; i >= 0; i--) \ + len += sprintf(buf + len, "%lx ", dev->bit[i]); \ + len += sprintf(buf + len, "\n"); \ + } while (0) + +#define SPRINTF_BIT_B2(bit, name, max, ev) \ + do { \ + if (test_bit(ev, dev->evbit)) \ + SPRINTF_BIT_B(bit, name, max); \ + } while (0) + +static int input_devices_read(char *buf, char **start, off_t pos, int count, int *eof, void *data) +{ + struct input_dev *dev; + struct input_handle *handle; + + off_t at = 0; + int i, len, cnt = 0; + + list_for_each_entry(dev, &input_dev_list, node) { + + len = sprintf(buf, "I: Bus=%04x Vendor=%04x Product=%04x Version=%04x\n", + dev->id.bustype, dev->id.vendor, dev->id.product, dev->id.version); + + len += sprintf(buf + len, "N: Name=\"%s\"\n", dev->name ? dev->name : ""); + len += sprintf(buf + len, "P: Phys=%s\n", dev->phys ? dev->phys : ""); + len += sprintf(buf + len, "H: Handlers="); + + list_for_each_entry(handle, &dev->h_list, d_node) + len += sprintf(buf + len, "%s ", handle->name); + + len += sprintf(buf + len, "\n"); + + SPRINTF_BIT_B(evbit, "EV=", EV_MAX); + SPRINTF_BIT_B2(keybit, "KEY=", KEY_MAX, EV_KEY); + SPRINTF_BIT_B2(relbit, "REL=", REL_MAX, EV_REL); + SPRINTF_BIT_B2(absbit, "ABS=", ABS_MAX, EV_ABS); + SPRINTF_BIT_B2(mscbit, "MSC=", MSC_MAX, EV_MSC); + SPRINTF_BIT_B2(ledbit, "LED=", LED_MAX, EV_LED); + SPRINTF_BIT_B2(sndbit, "SND=", SND_MAX, EV_SND); + SPRINTF_BIT_B2(ffbit, "FF=", FF_MAX, EV_FF); + + len += sprintf(buf + len, "\n"); + + at += len; + + if (at >= pos) { + if (!*start) { + *start = buf + (pos - (at - len)); + cnt = at - pos; + } else cnt += len; + buf += len; + if (cnt >= count) + break; + } + } + + if (&dev->node == &input_dev_list) + *eof = 1; + + return (count > cnt) ? cnt : count; +} + +static int input_handlers_read(char *buf, char **start, off_t pos, int count, int *eof, void *data) +{ + struct input_handler *handler; + + off_t at = 0; + int len = 0, cnt = 0; + int i = 0; + + list_for_each_entry(handler, &input_handler_list, node) { + + if (handler->fops) + len = sprintf(buf, "N: Number=%d Name=%s Minor=%d\n", + i++, handler->name, handler->minor); + else + len = sprintf(buf, "N: Number=%d Name=%s\n", + i++, handler->name); + + at += len; + + if (at >= pos) { + if (!*start) { + *start = buf + (pos - (at - len)); + cnt = at - pos; + } else cnt += len; + buf += len; + if (cnt >= count) + break; + } + } + if (&handler->node == &input_handler_list) + *eof = 1; + + return (count > cnt) ? cnt : count; +} + +static struct file_operations input_fileops; + +static int __init input_proc_init(void) +{ + struct proc_dir_entry *entry; + + proc_bus_input_dir = proc_mkdir("input", proc_bus); + if (!proc_bus_input_dir) + return -ENOMEM; + + proc_bus_input_dir->owner = THIS_MODULE; + + entry = create_proc_read_entry("devices", 0, proc_bus_input_dir, input_devices_read, NULL); + if (!entry) + goto fail1; + + 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) + goto fail2; + + entry->owner = THIS_MODULE; + + return 0; + + fail2: remove_proc_entry("devices", proc_bus_input_dir); + fail1: remove_proc_entry("input", proc_bus); + return -ENOMEM; +} + +static void input_proc_exit(void) +{ + remove_proc_entry("devices", proc_bus_input_dir); + remove_proc_entry("handlers", proc_bus_input_dir); + remove_proc_entry("input", proc_bus); +} + +#else /* !CONFIG_PROC_FS */ +static inline void input_wakeup_procfs_readers(void) { } +static inline int input_proc_init(void) { return 0; } +static inline void input_proc_exit(void) { } +#endif + void input_register_device(struct input_dev *dev) { struct input_handle *handle; @@ -415,6 +602,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. @@ -441,10 +630,7 @@ void input_register_device(struct input_dev *dev) input_call_hotplug("add", dev); #endif -#ifdef CONFIG_PROC_FS - input_devices_state++; - wake_up(&input_devices_poll_wait); -#endif + input_wakeup_procfs_readers(); } void input_unregister_device(struct input_dev *dev) @@ -468,10 +654,7 @@ void input_unregister_device(struct input_dev *dev) list_del_init(&dev->node); -#ifdef CONFIG_PROC_FS - input_devices_state++; - wake_up(&input_devices_poll_wait); -#endif + input_wakeup_procfs_readers(); } void input_register_handler(struct input_handler *handler) @@ -495,10 +678,7 @@ void input_register_handler(struct input_handler *handler) if ((handle = handler->connect(handler, dev, id))) input_link_handle(handle); -#ifdef CONFIG_PROC_FS - input_devices_state++; - wake_up(&input_devices_poll_wait); -#endif + input_wakeup_procfs_readers(); } void input_unregister_handler(struct input_handler *handler) @@ -517,10 +697,7 @@ void input_unregister_handler(struct input_handler *handler) if (handler->fops != NULL) input_table[handler->minor >> 5] = NULL; -#ifdef CONFIG_PROC_FS - input_devices_state++; - wake_up(&input_devices_poll_wait); -#endif + input_wakeup_procfs_readers(); } static int input_open_file(struct inode *inode, struct file *file) @@ -559,186 +736,43 @@ static struct file_operations input_fops = { .open = input_open_file, }; -#ifdef CONFIG_PROC_FS - -#define SPRINTF_BIT_B(bit, name, max) \ - do { \ - len += sprintf(buf + len, "B: %s", name); \ - for (i = NBITS(max) - 1; i >= 0; i--) \ - if (dev->bit[i]) break; \ - for (; i >= 0; i--) \ - len += sprintf(buf + len, "%lx ", dev->bit[i]); \ - len += sprintf(buf + len, "\n"); \ - } while (0) - -#define SPRINTF_BIT_B2(bit, name, max, ev) \ - do { \ - if (test_bit(ev, dev->evbit)) \ - SPRINTF_BIT_B(bit, name, max); \ - } while (0) - - -static unsigned int input_devices_poll(struct file *file, poll_table *wait) -{ - int state = input_devices_state; - poll_wait(file, &input_devices_poll_wait, wait); - if (state != input_devices_state) - return POLLIN | POLLRDNORM; - return 0; -} +struct class *input_class; -static int input_devices_read(char *buf, char **start, off_t pos, int count, int *eof, void *data) +static int __init input_init(void) { - struct input_dev *dev; - struct input_handle *handle; - - off_t at = 0; - int i, len, cnt = 0; - - list_for_each_entry(dev, &input_dev_list, node) { - - len = sprintf(buf, "I: Bus=%04x Vendor=%04x Product=%04x Version=%04x\n", - dev->id.bustype, dev->id.vendor, dev->id.product, dev->id.version); - - len += sprintf(buf + len, "N: Name=\"%s\"\n", dev->name ? dev->name : ""); - len += sprintf(buf + len, "P: Phys=%s\n", dev->phys ? dev->phys : ""); - len += sprintf(buf + len, "H: Handlers="); - - list_for_each_entry(handle, &dev->h_list, d_node) - len += sprintf(buf + len, "%s ", handle->name); - - len += sprintf(buf + len, "\n"); - - SPRINTF_BIT_B(evbit, "EV=", EV_MAX); - SPRINTF_BIT_B2(keybit, "KEY=", KEY_MAX, EV_KEY); - SPRINTF_BIT_B2(relbit, "REL=", REL_MAX, EV_REL); - SPRINTF_BIT_B2(absbit, "ABS=", ABS_MAX, EV_ABS); - SPRINTF_BIT_B2(mscbit, "MSC=", MSC_MAX, EV_MSC); - SPRINTF_BIT_B2(ledbit, "LED=", LED_MAX, EV_LED); - SPRINTF_BIT_B2(sndbit, "SND=", SND_MAX, EV_SND); - SPRINTF_BIT_B2(ffbit, "FF=", FF_MAX, EV_FF); - - len += sprintf(buf + len, "\n"); - - at += len; + int err; - if (at >= pos) { - if (!*start) { - *start = buf + (pos - (at - len)); - cnt = at - pos; - } else cnt += len; - buf += len; - if (cnt >= count) - break; - } + input_class = class_create(THIS_MODULE, "input"); + if (IS_ERR(input_class)) { + printk(KERN_ERR "input: unable to register input class\n"); + return PTR_ERR(input_class); } - if (&dev->node == &input_dev_list) - *eof = 1; - - return (count > cnt) ? cnt : count; -} + err = input_proc_init(); + if (err) + goto fail1; -static int input_handlers_read(char *buf, char **start, off_t pos, int count, int *eof, void *data) -{ - struct input_handler *handler; - - off_t at = 0; - int len = 0, cnt = 0; - int i = 0; - - list_for_each_entry(handler, &input_handler_list, node) { - - if (handler->fops) - len = sprintf(buf, "N: Number=%d Name=%s Minor=%d\n", - i++, handler->name, handler->minor); - else - len = sprintf(buf, "N: Number=%d Name=%s\n", - i++, handler->name); - - at += len; - - if (at >= pos) { - if (!*start) { - *start = buf + (pos - (at - len)); - cnt = at - pos; - } else cnt += len; - buf += len; - if (cnt >= count) - break; - } + err = register_chrdev(INPUT_MAJOR, "input", &input_fops); + if (err) { + printk(KERN_ERR "input: unable to register char major %d", INPUT_MAJOR); + goto fail2; } - if (&handler->node == &input_handler_list) - *eof = 1; - return (count > cnt) ? cnt : count; -} + err = devfs_mk_dir("input"); + if (err) + goto fail3; -static int __init input_proc_init(void) -{ - struct proc_dir_entry *entry; - - proc_bus_input_dir = proc_mkdir("input", proc_bus); - if (proc_bus_input_dir == NULL) - return -ENOMEM; - proc_bus_input_dir->owner = THIS_MODULE; - entry = create_proc_read_entry("devices", 0, proc_bus_input_dir, input_devices_read, NULL); - if (entry == NULL) { - remove_proc_entry("input", proc_bus); - return -ENOMEM; - } - entry->owner = THIS_MODULE; - 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) { - remove_proc_entry("devices", proc_bus_input_dir); - remove_proc_entry("input", proc_bus); - return -ENOMEM; - } - entry->owner = THIS_MODULE; return 0; -} -#else /* !CONFIG_PROC_FS */ -static inline int input_proc_init(void) { return 0; } -#endif -struct class *input_class; - -static int __init input_init(void) -{ - int retval = -ENOMEM; - - input_class = class_create(THIS_MODULE, "input"); - if (IS_ERR(input_class)) - return PTR_ERR(input_class); - input_proc_init(); - retval = register_chrdev(INPUT_MAJOR, "input", &input_fops); - if (retval) { - printk(KERN_ERR "input: unable to register char major %d", INPUT_MAJOR); - remove_proc_entry("devices", proc_bus_input_dir); - remove_proc_entry("handlers", proc_bus_input_dir); - remove_proc_entry("input", proc_bus); - class_destroy(input_class); - return retval; - } - - retval = devfs_mk_dir("input"); - if (retval) { - remove_proc_entry("devices", proc_bus_input_dir); - remove_proc_entry("handlers", proc_bus_input_dir); - remove_proc_entry("input", proc_bus); - unregister_chrdev(INPUT_MAJOR, "input"); - class_destroy(input_class); - } - return retval; + fail3: unregister_chrdev(INPUT_MAJOR, "input"); + fail2: input_proc_exit(); + fail1: class_destroy(input_class); + return err; } static void __exit input_exit(void) { - remove_proc_entry("devices", proc_bus_input_dir); - remove_proc_entry("handlers", proc_bus_input_dir); - remove_proc_entry("input", proc_bus); - + input_proc_exit(); devfs_remove("input"); unregister_chrdev(INPUT_MAJOR, "input"); class_destroy(input_class); diff --git a/drivers/input/joydev.c b/drivers/input/joydev.c index 39775fc380c7..e0938d1d3ad7 100644 --- a/drivers/input/joydev.c +++ b/drivers/input/joydev.c @@ -37,8 +37,6 @@ MODULE_LICENSE("GPL"); #define JOYDEV_MINORS 16 #define JOYDEV_BUFFER_SIZE 64 -#define MSECS(t) (1000 * ((t) / HZ) + 1000 * ((t) % HZ) / HZ) - struct joydev { int exist; int open; @@ -117,7 +115,7 @@ static void joydev_event(struct input_handle *handle, unsigned int type, unsigne return; } - event.time = MSECS(jiffies); + event.time = jiffies_to_msecs(jiffies); list_for_each_entry(list, &joydev->list, node) { @@ -245,7 +243,7 @@ static ssize_t joydev_read(struct file *file, char __user *buf, size_t count, lo struct js_event event; - event.time = MSECS(jiffies); + event.time = jiffies_to_msecs(jiffies); if (list->startup < joydev->nkey) { event.type = JS_EVENT_BUTTON | JS_EVENT_INIT; @@ -285,48 +283,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 +318,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 +354,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 +440,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 ad39fe4bf35f..bf34f75b9467 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 83f6dafc1716..265962956c63 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 cf36ca9b92f3..e996183c5b06 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 504b7d550567..c3a5739030c3 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 cfdd3acf06a1..fbd3eed07f90 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 8732f52bdd08..95bbdd302aad 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 ad13f09a4e71..7d969420066c 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 42e5005d621f..0da7bd133ccf 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 028f3513629a..e31b7b93fde2 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 617c0b0e5a39..6369a24684fe 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 ec0a2a64d49c..a436f2220856 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 874367bfab08..01fd2e4791ae 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 aaee52ceb920..9eb9954cac6e 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 dd88b9cb49fa..28100d461cb7 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 82fad9a23ace..4d4985b59abf 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 0f1220a0ceb5..a8551711e8d6 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 2694ff2b5beb..098963c7cdd6 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 d3e9dd6a13cd..8935290256b3 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 859ed771ee0a..eecbde294f1f 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 158c8e845ff9..d5c5b32045af 100644 --- a/drivers/input/misc/uinput.c +++ b/drivers/input/misc/uinput.c @@ -36,16 +36,6 @@ #include <linux/miscdevice.h> #include <linux/uinput.h> -static int uinput_dev_open(struct input_dev *dev) -{ - return 0; -} - -static void uinput_dev_close(struct input_dev *dev) -{ - -} - static int uinput_dev_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) { struct uinput_device *udev; @@ -63,22 +53,24 @@ static int uinput_dev_event(struct input_dev *dev, unsigned int type, unsigned i return 0; } -static int uinput_request_alloc_id(struct input_dev *dev, struct uinput_request *request) +static int uinput_request_alloc_id(struct uinput_device *udev, struct uinput_request *request) { /* Atomically allocate an ID for the given request. Returns 0 on success. */ - struct uinput_device *udev = dev->private; int id; + int err = -1; - down(&udev->requests_sem); - for (id=0; id<UINPUT_NUM_REQUESTS; id++) + spin_lock(&udev->requests_lock); + + for (id = 0; id < UINPUT_NUM_REQUESTS; id++) if (!udev->requests[id]) { - udev->requests[id] = request; request->id = id; - up(&udev->requests_sem); - return 0; + udev->requests[id] = request; + err = 0; + break; } - up(&udev->requests_sem); - return -1; + + spin_unlock(&udev->requests_lock); + return err; } static struct uinput_request* uinput_request_find(struct uinput_device *udev, int id) @@ -86,70 +78,78 @@ static struct uinput_request* uinput_request_find(struct uinput_device *udev, in /* Find an input request, by ID. Returns NULL if the ID isn't valid. */ if (id >= UINPUT_NUM_REQUESTS || id < 0) return NULL; - if (udev->requests[id]->completed) - return NULL; return udev->requests[id]; } -static void uinput_request_init(struct input_dev *dev, struct uinput_request *request, int code) +static inline int uinput_request_reserve_slot(struct uinput_device *udev, struct uinput_request *request) { - struct uinput_device *udev = dev->private; + /* Allocate slot. If none are available right away, wait. */ + return wait_event_interruptible(udev->requests_waitq, + !uinput_request_alloc_id(udev, request)); +} - memset(request, 0, sizeof(struct uinput_request)); - request->code = code; - init_waitqueue_head(&request->waitq); +static void uinput_request_done(struct uinput_device *udev, struct uinput_request *request) +{ + complete(&request->done); - /* Allocate an ID. If none are available right away, wait. */ - request->retval = wait_event_interruptible(udev->requests_waitq, - !uinput_request_alloc_id(dev, request)); + /* Mark slot as available */ + udev->requests[request->id] = NULL; + wake_up_interruptible(&udev->requests_waitq); } -static void uinput_request_submit(struct input_dev *dev, struct uinput_request *request) +static int uinput_request_submit(struct input_dev *dev, struct uinput_request *request) { - struct uinput_device *udev = dev->private; int retval; /* Tell our userspace app about this new request by queueing an input event */ uinput_dev_event(dev, EV_UINPUT, request->code, request->id); /* Wait for the request to complete */ - retval = wait_event_interruptible(request->waitq, request->completed); - if (retval) - request->retval = retval; + retval = wait_for_completion_interruptible(&request->done); + if (!retval) + retval = request->retval; - /* Release this request's ID, let others know it's available */ - udev->requests[request->id] = NULL; - wake_up_interruptible(&udev->requests_waitq); + return retval; } static int uinput_dev_upload_effect(struct input_dev *dev, struct ff_effect *effect) { struct uinput_request request; + int retval; if (!test_bit(EV_FF, dev->evbit)) return -ENOSYS; - uinput_request_init(dev, &request, UI_FF_UPLOAD); - if (request.retval) - return request.retval; + request.id = -1; + init_completion(&request.done); + request.code = UI_FF_UPLOAD; request.u.effect = effect; - uinput_request_submit(dev, &request); - return request.retval; + + retval = uinput_request_reserve_slot(dev->private, &request); + if (!retval) + retval = uinput_request_submit(dev, &request); + + return retval; } static int uinput_dev_erase_effect(struct input_dev *dev, int effect_id) { struct uinput_request request; + int retval; if (!test_bit(EV_FF, dev->evbit)) return -ENOSYS; - uinput_request_init(dev, &request, UI_FF_ERASE); - if (request.retval) - return request.retval; + request.id = -1; + init_completion(&request.done); + request.code = UI_FF_ERASE; request.u.effect_id = effect_id; - uinput_request_submit(dev, &request); - return request.retval; + + retval = uinput_request_reserve_slot(dev->private, &request); + if (!retval) + retval = uinput_request_submit(dev, &request); + + return retval; } static int uinput_create_device(struct uinput_device *udev) @@ -159,32 +159,30 @@ static int uinput_create_device(struct uinput_device *udev) return -EINVAL; } - udev->dev->open = uinput_dev_open; - udev->dev->close = uinput_dev_close; udev->dev->event = uinput_dev_event; udev->dev->upload_effect = uinput_dev_upload_effect; udev->dev->erase_effect = uinput_dev_erase_effect; udev->dev->private = udev; - init_waitqueue_head(&(udev->waitq)); + init_waitqueue_head(&udev->waitq); input_register_device(udev->dev); - set_bit(UIST_CREATED, &(udev->state)); + set_bit(UIST_CREATED, &udev->state); return 0; } static int uinput_destroy_device(struct uinput_device *udev) { - if (!test_bit(UIST_CREATED, &(udev->state))) { + if (!test_bit(UIST_CREATED, &udev->state)) { printk(KERN_WARNING "%s: create the device first\n", UINPUT_NAME); return -EINVAL; } input_unregister_device(udev->dev); - clear_bit(UIST_CREATED, &(udev->state)); + clear_bit(UIST_CREATED, &udev->state); return 0; } @@ -198,7 +196,7 @@ static int uinput_open(struct inode *inode, struct file *file) if (!newdev) goto error; memset(newdev, 0, sizeof(struct uinput_device)); - init_MUTEX(&newdev->requests_sem); + spin_lock_init(&newdev->requests_lock); init_waitqueue_head(&newdev->requests_waitq); newinput = kmalloc(sizeof(struct input_dev), GFP_KERNEL); @@ -253,15 +251,16 @@ static int uinput_alloc_device(struct file *file, const char __user *buffer, siz struct uinput_user_dev *user_dev; struct input_dev *dev; struct uinput_device *udev; - int size, - retval; + char *name; + int size; + int retval; retval = count; udev = file->private_data; dev = udev->dev; - user_dev = kmalloc(sizeof(*user_dev), GFP_KERNEL); + user_dev = kmalloc(sizeof(struct uinput_user_dev), GFP_KERNEL); if (!user_dev) { retval = -ENOMEM; goto exit; @@ -272,17 +271,17 @@ static int uinput_alloc_device(struct file *file, const char __user *buffer, siz goto exit; } - if (NULL != dev->name) + if (dev->name) kfree(dev->name); size = strnlen(user_dev->name, UINPUT_MAX_NAME_SIZE) + 1; - dev->name = kmalloc(size, GFP_KERNEL); - if (!dev->name) { + dev->name = name = kmalloc(size, GFP_KERNEL); + if (!name) { retval = -ENOMEM; goto exit; } + strlcpy(name, user_dev->name, size); - strlcpy(dev->name, user_dev->name, size); dev->id.bustype = user_dev->id.bustype; dev->id.vendor = user_dev->id.vendor; dev->id.product = user_dev->id.product; @@ -298,9 +297,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: @@ -312,14 +313,13 @@ static ssize_t uinput_write(struct file *file, const char __user *buffer, size_t { struct uinput_device *udev = file->private_data; - if (test_bit(UIST_CREATED, &(udev->state))) { + if (test_bit(UIST_CREATED, &udev->state)) { struct input_event ev; if (copy_from_user(&ev, buffer, sizeof(struct input_event))) return -EFAULT; input_event(udev->dev, ev.type, ev.code, ev.value); - } - else + } else count = uinput_alloc_device(file, buffer, count); return count; @@ -330,26 +330,24 @@ static ssize_t uinput_read(struct file *file, char __user *buffer, size_t count, struct uinput_device *udev = file->private_data; int retval = 0; - if (!test_bit(UIST_CREATED, &(udev->state))) + if (!test_bit(UIST_CREATED, &udev->state)) return -ENODEV; - if ((udev->head == udev->tail) && (file->f_flags & O_NONBLOCK)) + if (udev->head == udev->tail && (file->f_flags & O_NONBLOCK)) return -EAGAIN; retval = wait_event_interruptible(udev->waitq, - (udev->head != udev->tail) || - !test_bit(UIST_CREATED, &(udev->state))); - + udev->head != udev->tail || !test_bit(UIST_CREATED, &udev->state)); if (retval) return retval; - if (!test_bit(UIST_CREATED, &(udev->state))) + if (!test_bit(UIST_CREATED, &udev->state)) return -ENODEV; while ((udev->head != udev->tail) && (retval + sizeof(struct input_event) <= count)) { - if (copy_to_user(buffer + retval, &(udev->buff[udev->tail]), - sizeof(struct input_event))) return -EFAULT; + if (copy_to_user(buffer + retval, &udev->buff[udev->tail], sizeof(struct input_event))) + return -EFAULT; udev->tail = (udev->tail + 1) % UINPUT_BUFFER_SIZE; retval += sizeof(struct input_event); } @@ -371,12 +369,12 @@ static unsigned int uinput_poll(struct file *file, poll_table *wait) static int uinput_burn_device(struct uinput_device *udev) { - if (test_bit(UIST_CREATED, &(udev->state))) + if (test_bit(UIST_CREATED, &udev->state)) uinput_destroy_device(udev); - if (NULL != udev->dev->name) + if (udev->dev->name) kfree(udev->dev->name); - if (NULL != udev->dev->phys) + if (udev->dev->phys) kfree(udev->dev->phys); kfree(udev->dev); @@ -387,7 +385,8 @@ static int uinput_burn_device(struct uinput_device *udev) static int uinput_close(struct inode *inode, struct file *file) { - return uinput_burn_device(file->private_data); + uinput_burn_device(file->private_data); + return 0; } static int uinput_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) @@ -399,6 +398,7 @@ static int uinput_ioctl(struct inode *inode, struct file *file, unsigned int cmd struct uinput_ff_erase ff_erase; struct uinput_request *req; int length; + char *phys; udev = file->private_data; @@ -413,7 +413,7 @@ static int uinput_ioctl(struct inode *inode, struct file *file, unsigned int cmd case UI_SET_SNDBIT: case UI_SET_FFBIT: case UI_SET_PHYS: - if (test_bit(UIST_CREATED, &(udev->state))) + if (test_bit(UIST_CREATED, &udev->state)) return -EINVAL; } @@ -496,20 +496,19 @@ static int uinput_ioctl(struct inode *inode, struct file *file, unsigned int cmd retval = -EFAULT; break; } - if (NULL != udev->dev->phys) - kfree(udev->dev->phys); - udev->dev->phys = kmalloc(length, GFP_KERNEL); - if (!udev->dev->phys) { + kfree(udev->dev->phys); + udev->dev->phys = phys = kmalloc(length, GFP_KERNEL); + if (!phys) { retval = -ENOMEM; break; } - if (copy_from_user(udev->dev->phys, p, length)) { - retval = -EFAULT; - kfree(udev->dev->phys); + if (copy_from_user(phys, p, length)) { udev->dev->phys = NULL; + kfree(phys); + retval = -EFAULT; break; } - udev->dev->phys[length-1] = '\0'; + phys[length - 1] = '\0'; break; case UI_BEGIN_FF_UPLOAD: @@ -518,7 +517,7 @@ static int uinput_ioctl(struct inode *inode, struct file *file, unsigned int cmd break; } req = uinput_request_find(udev, ff_up.request_id); - if (!(req && req->code==UI_FF_UPLOAD && req->u.effect)) { + if (!(req && req->code == UI_FF_UPLOAD && req->u.effect)) { retval = -EINVAL; break; } @@ -536,7 +535,7 @@ static int uinput_ioctl(struct inode *inode, struct file *file, unsigned int cmd break; } req = uinput_request_find(udev, ff_erase.request_id); - if (!(req && req->code==UI_FF_ERASE)) { + if (!(req && req->code == UI_FF_ERASE)) { retval = -EINVAL; break; } @@ -554,14 +553,13 @@ static int uinput_ioctl(struct inode *inode, struct file *file, unsigned int cmd break; } req = uinput_request_find(udev, ff_up.request_id); - if (!(req && req->code==UI_FF_UPLOAD && req->u.effect)) { + if (!(req && req->code == UI_FF_UPLOAD && req->u.effect)) { retval = -EINVAL; break; } req->retval = ff_up.retval; memcpy(req->u.effect, &ff_up.effect, sizeof(struct ff_effect)); - req->completed = 1; - wake_up_interruptible(&req->waitq); + uinput_request_done(udev, req); break; case UI_END_FF_ERASE: @@ -570,13 +568,12 @@ static int uinput_ioctl(struct inode *inode, struct file *file, unsigned int cmd break; } req = uinput_request_find(udev, ff_erase.request_id); - if (!(req && req->code==UI_FF_ERASE)) { + if (!(req && req->code == UI_FF_ERASE)) { retval = -EINVAL; break; } req->retval = ff_erase.retval; - req->completed = 1; - wake_up_interruptible(&req->waitq); + uinput_request_done(udev, req); break; default: diff --git a/drivers/input/mouse/Makefile b/drivers/input/mouse/Makefile index a7864195806a..c4909b49337d 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 7bf4be733e9a..0d68e5e0182a 100644 --- a/drivers/input/mouse/alps.c +++ b/drivers/input/mouse/alps.c @@ -2,7 +2,7 @@ * ALPS touchpad PS/2 mouse driver * * Copyright (c) 2003 Neil Brown <neilb@cse.unsw.edu.au> - * Copyright (c) 2003 Peter Osterlund <petero2@telia.com> + * Copyright (c) 2003-2005 Peter Osterlund <petero2@telia.com> * Copyright (c) 2004 Dmitry Torokhov <dtor@mail.ru> * Copyright (c) 2005 Vojtech Pavlik <vojtech@suse.cz> * @@ -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; } @@ -338,7 +350,6 @@ static int alps_tap_mode(struct psmouse *psmouse, int enable) static int alps_reconnect(struct psmouse *psmouse) { struct alps_data *priv = psmouse->private; - unsigned char param[4]; int version; psmouse_reset(psmouse); @@ -346,21 +357,20 @@ static int alps_reconnect(struct psmouse *psmouse) if (!(priv->i = alps_get_model(psmouse, &version))) return -1; - if (priv->i->flags & ALPS_PASS && alps_passthrough_mode(psmouse, 1)) + if ((priv->i->flags & ALPS_PASS) && alps_passthrough_mode(psmouse, 1)) return -1; - if (alps_get_status(psmouse, param)) + if (alps_tap_mode(psmouse, 1)) { + printk(KERN_WARNING "alps.c: Failed to reenable hardware tapping\n"); return -1; - - if (!(param[0] & 0x04)) - alps_tap_mode(psmouse, 1); + } if (alps_absolute_mode(psmouse)) { - printk(KERN_ERR "alps.c: Failed to enable absolute mode\n"); + printk(KERN_ERR "alps.c: Failed to reenable absolute mode\n"); return -1; } - if (priv->i->flags == ALPS_PASS && alps_passthrough_mode(psmouse, 0)) + if ((priv->i->flags & ALPS_PASS) && alps_passthrough_mode(psmouse, 0)) return -1; return 0; @@ -377,7 +387,6 @@ static void alps_disconnect(struct psmouse *psmouse) int alps_init(struct psmouse *psmouse) { struct alps_data *priv; - unsigned char param[4]; int version; psmouse->private = priv = kmalloc(sizeof(struct alps_data), GFP_KERNEL); @@ -391,16 +400,8 @@ int alps_init(struct psmouse *psmouse) if ((priv->i->flags & ALPS_PASS) && alps_passthrough_mode(psmouse, 1)) goto init_fail; - if (alps_get_status(psmouse, param)) { - printk(KERN_ERR "alps.c: touchpad status report request failed\n"); - goto init_fail; - } - - if (param[0] & 0x04) { - printk(KERN_INFO "alps.c: Enabling hardware tapping\n"); - if (alps_tap_mode(psmouse, 1)) - printk(KERN_WARNING "alps.c: Failed to enable hardware tapping\n"); - } + if (alps_tap_mode(psmouse, 1)) + printk(KERN_WARNING "alps.c: Failed to enable hardware tapping\n"); if (alps_absolute_mode(psmouse)) { printk(KERN_ERR "alps.c: Failed to enable absolute mode\n"); @@ -425,7 +426,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 +437,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 +462,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 7baa09cca7c5..e994849efb8f 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 ca4e96886627..1f62c0134010 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 000000000000..bd9df9b28325 --- /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, ¶m, 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, ¶ms[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 000000000000..be1c0943825d --- /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 77eb83e87f61..8b5243167227 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/logips2pp.c b/drivers/input/mouse/logips2pp.c index 5ab1bd7d529d..48d2b20d2642 100644 --- a/drivers/input/mouse/logips2pp.c +++ b/drivers/input/mouse/logips2pp.c @@ -385,8 +385,6 @@ int ps2pp_init(struct psmouse *psmouse, int set_properties) if (buttons < 3) clear_bit(BTN_MIDDLE, psmouse->dev.keybit); - if (buttons < 2) - clear_bit(BTN_RIGHT, psmouse->dev.keybit); if (model_info) ps2pp_set_model_properties(psmouse, model_info, use_ps2pp); diff --git a/drivers/input/mouse/maplemouse.c b/drivers/input/mouse/maplemouse.c index 12dc0ef5020f..e90c60cbbf05 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 0c74918fe254..93393d5c0078 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 019034b21a0b..2bb2fe78bdca 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 @@ -327,6 +344,7 @@ static int intellimouse_detect(struct psmouse *psmouse, int set_properties) return -1; if (set_properties) { + set_bit(BTN_MIDDLE, psmouse->dev.keybit); set_bit(REL_WHEEL, psmouse->dev.relbit); if (!psmouse->vendor) psmouse->vendor = "Generic"; @@ -359,6 +377,7 @@ static int im_explorer_detect(struct psmouse *psmouse, int set_properties) return -1; if (set_properties) { + set_bit(BTN_MIDDLE, psmouse->dev.keybit); set_bit(REL_WHEEL, psmouse->dev.relbit); set_bit(BTN_SIDE, psmouse->dev.keybit); set_bit(BTN_EXTRA, psmouse->dev.keybit); @@ -407,12 +426,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 +446,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 +539,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 +783,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 +872,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 +883,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 +914,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 +927,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 +937,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 +958,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 +992,7 @@ out: if (parent) psmouse_activate(parent); + up(&psmouse_sem); return rc; } @@ -893,26 +1063,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 +1222,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 79e17a0c4664..86691cf43433 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 7280f68afcee..8fe1212b8fd7 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/synaptics.c b/drivers/input/mouse/synaptics.c index 36c721227b68..029309422409 100644 --- a/drivers/input/mouse/synaptics.c +++ b/drivers/input/mouse/synaptics.c @@ -219,7 +219,7 @@ static void synaptics_pass_pt_packet(struct serio *ptport, unsigned char *packet serio_interrupt(ptport, packet[1], 0, NULL); serio_interrupt(ptport, packet[4], 0, NULL); serio_interrupt(ptport, packet[5], 0, NULL); - if (child->type >= PSMOUSE_GENPS) + if (child->pktsize == 4) serio_interrupt(ptport, packet[2], 0, NULL); } else serio_interrupt(ptport, packet[1], 0, NULL); @@ -233,7 +233,7 @@ static void synaptics_pt_activate(struct psmouse *psmouse) /* adjust the touchpad to child's choice of protocol */ if (child) { - if (child->type >= PSMOUSE_GENPS) + if (child->pktsize == 4) priv->mode |= SYN_BIT_FOUR_BYTE_CLIENT; else priv->mode &= ~SYN_BIT_FOUR_BYTE_CLIENT; @@ -608,6 +608,13 @@ static struct dmi_system_id toshiba_dmi_table[] = { DMI_MATCH(DMI_PRODUCT_NAME , "Satellite"), }, }, + { + .ident = "Toshiba Dynabook", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), + DMI_MATCH(DMI_PRODUCT_NAME , "dynabook"), + }, + }, { } }; #endif @@ -656,7 +663,8 @@ int synaptics_init(struct psmouse *psmouse) * thye same as rate of standard PS/2 mouse. */ if (psmouse->rate >= 80 && dmi_check_system(toshiba_dmi_table)) { - printk(KERN_INFO "synaptics: Toshiba Satellite detected, limiting rate to 40pps.\n"); + printk(KERN_INFO "synaptics: Toshiba %s detected, limiting rate to 40pps.\n", + dmi_get_system_info(DMI_PRODUCT_NAME)); psmouse->rate = 40; } #endif diff --git a/drivers/input/mouse/vsxxxaa.c b/drivers/input/mouse/vsxxxaa.c index b2cb101c8110..f024be9b44d2 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 062848ac7e6b..c6194a9dd174 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/Kconfig b/drivers/input/serio/Kconfig index b3710733b36b..98acf170252c 100644 --- a/drivers/input/serio/Kconfig +++ b/drivers/input/serio/Kconfig @@ -175,7 +175,7 @@ config SERIO_RAW allocating minor 1 (that historically corresponds to /dev/psaux) first. To bind this driver to a serio port use sysfs interface: - echo -n "serio_raw" > /sys/bus/serio/devices/serioX/driver + echo -n "serio_raw" > /sys/bus/serio/devices/serioX/drvctl To compile this driver as a module, choose M here: the module will be called serio_raw. diff --git a/drivers/input/serio/i8042-x86ia64io.h b/drivers/input/serio/i8042-x86ia64io.h index 0487ecbb8a49..03877c84e6ff 100644 --- a/drivers/input/serio/i8042-x86ia64io.h +++ b/drivers/input/serio/i8042-x86ia64io.h @@ -131,12 +131,26 @@ static struct dmi_system_id __initdata i8042_dmi_nomux_table[] = { }, }, { + .ident = "Fujitsu-Siemens Lifebook T3010", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), + DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK T3010"), + }, + }, + { .ident = "Toshiba P10", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), DMI_MATCH(DMI_PRODUCT_NAME, "Satellite P10"), }, }, + { + .ident = "Alienware Sentia", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ALIENWARE"), + DMI_MATCH(DMI_PRODUCT_NAME, "Sentia"), + }, + }, { } }; diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c index 5900de3c3f4f..708a1d3beab9 100644 --- a/drivers/input/serio/i8042.c +++ b/drivers/input/serio/i8042.c @@ -100,7 +100,7 @@ struct i8042_port { static struct i8042_port i8042_ports[I8042_NUM_PORTS] = { { .disable = I8042_CTR_KBDDIS, - .irqen = I8042_CTR_KBDINT, + .irqen = I8042_CTR_KBDINT, .mux = -1, .name = "KBD", }, @@ -191,41 +191,45 @@ static int i8042_flush(void) static int i8042_command(unsigned char *param, int command) { unsigned long flags; - int retval = 0, i = 0; + int i, retval, auxerr = 0; if (i8042_noloop && command == I8042_CMD_AUX_LOOP) return -1; spin_lock_irqsave(&i8042_lock, flags); - retval = i8042_wait_write(); - if (!retval) { - dbg("%02x -> i8042 (command)", command & 0xff); - i8042_write_command(command & 0xff); + if ((retval = i8042_wait_write())) + goto out; + + dbg("%02x -> i8042 (command)", command & 0xff); + i8042_write_command(command & 0xff); + + for (i = 0; i < ((command >> 12) & 0xf); i++) { + if ((retval = i8042_wait_write())) + goto out; + dbg("%02x -> i8042 (parameter)", param[i]); + i8042_write_data(param[i]); } - if (!retval) - for (i = 0; i < ((command >> 12) & 0xf); i++) { - if ((retval = i8042_wait_write())) break; - dbg("%02x -> i8042 (parameter)", param[i]); - i8042_write_data(param[i]); - } + for (i = 0; i < ((command >> 8) & 0xf); i++) { + if ((retval = i8042_wait_read())) + goto out; - if (!retval) - for (i = 0; i < ((command >> 8) & 0xf); i++) { - if ((retval = i8042_wait_read())) break; - if (i8042_read_status() & I8042_STR_AUXDATA) - param[i] = ~i8042_read_data(); - else - param[i] = i8042_read_data(); - dbg("%02x <- i8042 (return)", param[i]); + if (command == I8042_CMD_AUX_LOOP && + !(i8042_read_status() & I8042_STR_AUXDATA)) { + retval = auxerr = -1; + goto out; } - spin_unlock_irqrestore(&i8042_lock, flags); + param[i] = i8042_read_data(); + dbg("%02x <- i8042 (return)", param[i]); + } if (retval) - dbg(" -- i8042 (timeout)"); + dbg(" -- i8042 (%s)", auxerr ? "auxerr" : "timeout"); + out: + spin_unlock_irqrestore(&i8042_lock, flags); return retval; } @@ -396,7 +400,7 @@ static void i8042_stop(struct serio *serio) struct i8042_port *port = serio->port_data; port->exists = 0; - synchronize_kernel(); + synchronize_sched(); port->serio = NULL; } @@ -507,17 +511,17 @@ static int i8042_set_mux_mode(unsigned int mode, unsigned char *mux_version) */ param = 0xf0; - if (i8042_command(¶m, I8042_CMD_AUX_LOOP) || param != 0x0f) + if (i8042_command(¶m, I8042_CMD_AUX_LOOP) || param != 0xf0) return -1; param = mode ? 0x56 : 0xf6; - if (i8042_command(¶m, I8042_CMD_AUX_LOOP) || param != (mode ? 0xa9 : 0x09)) + if (i8042_command(¶m, I8042_CMD_AUX_LOOP) || param != (mode ? 0x56 : 0xf6)) return -1; param = mode ? 0xa4 : 0xa5; - if (i8042_command(¶m, I8042_CMD_AUX_LOOP) || param == (mode ? 0x5b : 0x5a)) + if (i8042_command(¶m, I8042_CMD_AUX_LOOP) || param == (mode ? 0xa4 : 0xa5)) return -1; if (mux_version) - *mux_version = ~param; + *mux_version = param; return 0; } @@ -619,7 +623,7 @@ static int __init i8042_check_aux(void) */ param = 0x5a; - if (i8042_command(¶m, I8042_CMD_AUX_LOOP) || param != 0xa5) { + if (i8042_command(¶m, I8042_CMD_AUX_LOOP) || param != 0x5a) { /* * External connection test - filters out AT-soldered PS/2 i8042's @@ -630,7 +634,7 @@ static int __init i8042_check_aux(void) */ if (i8042_command(¶m, I8042_CMD_AUX_TEST) - || (param && param != 0xfa && param != 0xff)) + || (param && param != 0xfa && param != 0xff)) return -1; } diff --git a/drivers/input/serio/libps2.c b/drivers/input/serio/libps2.c index c978657068c5..d4c990f7c85e 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 feab4970406e..edd15db17715 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)); - try_to_freeze(PF_FREEZE); - } while (!signal_pending(current)); + wait_event_interruptible(serio_wait, + kthread_should_stop() || !list_empty(&serio_event_list)); + try_to_freeze(); + } while (!kthread_should_stop()); printk(KERN_DEBUG "serio: kseriod exiting\n"); - - unlock_kernel(); - complete_and_exit(&serio_exited, 0); + return 0; } @@ -364,6 +389,14 @@ static ssize_t serio_show_description(struct device *dev, struct device_attribut return sprintf(buf, "%s\n", serio->name); } +static ssize_t serio_show_modalias(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct serio *serio = to_serio_port(dev); + + return sprintf(buf, "serio:ty%02Xpr%02Xid%02Xex%02X\n", + serio->id.type, serio->id.proto, serio->id.id, serio->id.extra); +} + static ssize_t serio_show_id_type(struct device *dev, struct device_attribute *attr, char *buf) { struct serio *serio = to_serio_port(dev); @@ -462,6 +495,7 @@ static ssize_t serio_set_bind_mode(struct device *dev, struct device_attribute * static struct device_attribute serio_device_attrs[] = { __ATTR(description, S_IRUGO, serio_show_description, NULL), + __ATTR(modalias, S_IRUGO, serio_show_modalias, NULL), __ATTR(drvctl, S_IWUSR, NULL, serio_rebind_driver), __ATTR(bind_mode, S_IWUSR | S_IRUGO, serio_show_bind_mode, serio_set_bind_mode), __ATTR_NULL @@ -557,7 +591,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 +664,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 +733,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 +776,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) @@ -750,36 +794,37 @@ static int serio_bus_match(struct device *dev, struct device_driver *drv) #ifdef CONFIG_HOTPLUG -#define PUT_ENVP(fmt, val) \ -do { \ - envp[i++] = buffer; \ - length += snprintf(buffer, buffer_size - length, fmt, val); \ - if (buffer_size - length <= 0 || i >= num_envp) \ - return -ENOMEM; \ - length++; \ - buffer += length; \ -} while (0) +#define SERIO_ADD_HOTPLUG_VAR(fmt, val...) \ + do { \ + int err = add_hotplug_env_var(envp, num_envp, &i, \ + buffer, buffer_size, &len, \ + fmt, val); \ + if (err) \ + return err; \ + } while (0) + static int serio_hotplug(struct device *dev, char **envp, int num_envp, char *buffer, int buffer_size) { struct serio *serio; int i = 0; - int length = 0; + int len = 0; if (!dev) return -ENODEV; serio = to_serio_port(dev); - PUT_ENVP("SERIO_TYPE=%02x", serio->id.type); - PUT_ENVP("SERIO_PROTO=%02x", serio->id.proto); - PUT_ENVP("SERIO_ID=%02x", serio->id.id); - PUT_ENVP("SERIO_EXTRA=%02x", serio->id.extra); - + SERIO_ADD_HOTPLUG_VAR("SERIO_TYPE=%02x", serio->id.type); + SERIO_ADD_HOTPLUG_VAR("SERIO_PROTO=%02x", serio->id.proto); + SERIO_ADD_HOTPLUG_VAR("SERIO_ID=%02x", serio->id.id); + SERIO_ADD_HOTPLUG_VAR("SERIO_EXTRA=%02x", serio->id.extra); + SERIO_ADD_HOTPLUG_VAR("MODALIAS=serio:ty%02Xpr%02Xid%02Xex%02X", + serio->id.type, serio->id.proto, serio->id.id, serio->id.extra); envp[i] = NULL; return 0; } -#undef PUT_ENVP +#undef SERIO_ADD_HOTPLUG_VAR #else @@ -794,7 +839,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 +893,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 +912,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/serio/serio_raw.c b/drivers/input/serio/serio_raw.c index d914e7e93db4..47e08de18d07 100644 --- a/drivers/input/serio/serio_raw.c +++ b/drivers/input/serio/serio_raw.c @@ -299,6 +299,7 @@ static int serio_raw_connect(struct serio *serio, struct serio_driver *drv) serio_raw->dev.minor = PSMOUSE_MINOR; serio_raw->dev.name = serio_raw->name; + serio_raw->dev.dev = &serio->dev; serio_raw->dev.fops = &serio_raw_fops; err = misc_register(&serio_raw->dev); diff --git a/drivers/input/serio/serport.c b/drivers/input/serio/serport.c index f6b85222ba3d..79ca38469159 100644 --- a/drivers/input/serio/serport.c +++ b/drivers/input/serio/serport.c @@ -257,7 +257,7 @@ static int __init serport_init(void) static void __exit serport_exit(void) { - tty_register_ldisc(N_MOUSE, NULL); + tty_unregister_ldisc(N_MOUSE); } module_init(serport_init); diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index 7e991274ea40..0489af5a80c9 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -58,7 +58,7 @@ config TOUCHSCREEN_ELO If unsure, say N. To compile this driver as a module, choose M here: the - module will be called gunze. + module will be called elo. config TOUCHSCREEN_MTOUCH tristate "MicroTouch serial touchscreens" diff --git a/drivers/input/touchscreen/elo.c b/drivers/input/touchscreen/elo.c index 546ce599334e..3cdc9cab688d 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 acb9137a0226..bcfa1e36f957 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 2d14a57a05e5..afaaebe5225b 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); } |