diff options
author | Greg KH <greg@press.(none)> | 2005-06-28 09:07:56 +0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2005-06-28 09:07:56 +0400 |
commit | 8644d2a42bdba2d513f71c07eaf1b6f9b718b8eb (patch) | |
tree | c43b6c2fdf1b68b66906a2de69446dcec0f9af6b /drivers/input | |
parent | 1cde8a16815bd85c8137d1ea556398983c597c11 (diff) | |
parent | 99f95e5286df2f69edab8a04c7080d986ee4233b (diff) | |
download | linux-8644d2a42bdba2d513f71c07eaf1b6f9b718b8eb.tar.xz |
Merge rsync://rsync.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6
Diffstat (limited to 'drivers/input')
47 files changed, 1389 insertions, 1105 deletions
diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c index 556264b43425..374f404e81da 100644 --- a/drivers/input/evdev.c +++ b/drivers/input/evdev.c @@ -21,6 +21,7 @@ #include <linux/smp_lock.h> #include <linux/device.h> #include <linux/devfs_fs_kernel.h> +#include <linux/compat.h> struct evdev { int exist; @@ -145,6 +146,41 @@ static int evdev_open(struct inode * inode, struct file * file) return 0; } +#ifdef CONFIG_COMPAT +struct input_event_compat { + struct compat_timeval time; + __u16 type; + __u16 code; + __s32 value; +}; + +#ifdef CONFIG_X86_64 +# define COMPAT_TEST test_thread_flag(TIF_IA32) +#elif defined(CONFIG_IA64) +# define COMPAT_TEST IS_IA32_PROCESS(ia64_task_regs(current)) +#elif defined(CONFIG_ARCH_S390) +# define COMPAT_TEST test_thread_flag(TIF_31BIT) +#else +# define COMPAT_TEST test_thread_flag(TIF_32BIT) +#endif + +static ssize_t evdev_write_compat(struct file * file, const char __user * buffer, size_t count, loff_t *ppos) +{ + struct evdev_list *list = file->private_data; + struct input_event_compat event; + int retval = 0; + + while (retval < count) { + if (copy_from_user(&event, buffer + retval, sizeof(struct input_event_compat))) + return -EFAULT; + input_event(list->evdev->handle.dev, event.type, event.code, event.value); + retval += sizeof(struct input_event_compat); + } + + return retval; +} +#endif + static ssize_t evdev_write(struct file * file, const char __user * buffer, size_t count, loff_t *ppos) { struct evdev_list *list = file->private_data; @@ -153,6 +189,11 @@ static ssize_t evdev_write(struct file * file, const char __user * buffer, size_ if (!list->evdev->exist) return -ENODEV; +#ifdef CONFIG_COMPAT + if (COMPAT_TEST) + return evdev_write_compat(file, buffer, count, ppos); +#endif + while (retval < count) { if (copy_from_user(&event, buffer + retval, sizeof(struct input_event))) @@ -164,11 +205,56 @@ static ssize_t evdev_write(struct file * file, const char __user * buffer, size_ return retval; } +#ifdef CONFIG_COMPAT +static ssize_t evdev_read_compat(struct file * file, char __user * buffer, size_t count, loff_t *ppos) +{ + struct evdev_list *list = file->private_data; + int retval; + + if (count < sizeof(struct input_event_compat)) + return -EINVAL; + + if (list->head == list->tail && list->evdev->exist && (file->f_flags & O_NONBLOCK)) + return -EAGAIN; + + retval = wait_event_interruptible(list->evdev->wait, + list->head != list->tail || (!list->evdev->exist)); + + if (retval) + return retval; + + if (!list->evdev->exist) + return -ENODEV; + + while (list->head != list->tail && retval + sizeof(struct input_event_compat) <= count) { + struct input_event *event = (struct input_event *) list->buffer + list->tail; + struct input_event_compat event_compat; + event_compat.time.tv_sec = event->time.tv_sec; + event_compat.time.tv_usec = event->time.tv_usec; + event_compat.type = event->type; + event_compat.code = event->code; + event_compat.value = event->value; + + if (copy_to_user(buffer + retval, &event_compat, + sizeof(struct input_event_compat))) return -EFAULT; + list->tail = (list->tail + 1) & (EVDEV_BUFFER_SIZE - 1); + retval += sizeof(struct input_event_compat); + } + + return retval; +} +#endif + static ssize_t evdev_read(struct file * file, char __user * buffer, size_t count, loff_t *ppos) { struct evdev_list *list = file->private_data; int retval; +#ifdef CONFIG_COMPAT + if (COMPAT_TEST) + return evdev_read_compat(file, buffer, count, ppos); +#endif + if (count < sizeof(struct input_event)) return -EINVAL; @@ -186,7 +272,7 @@ static ssize_t evdev_read(struct file * file, char __user * buffer, size_t count while (list->head != list->tail && retval + sizeof(struct input_event) <= count) { if (copy_to_user(buffer + retval, list->buffer + list->tail, - sizeof(struct input_event))) return -EFAULT; + sizeof(struct input_event))) return -EFAULT; list->tail = (list->tail + 1) & (EVDEV_BUFFER_SIZE - 1); retval += sizeof(struct input_event); } @@ -203,7 +289,7 @@ static unsigned int evdev_poll(struct file *file, poll_table *wait) (list->evdev->exist ? 0 : (POLLHUP | POLLERR)); } -static int evdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) +static long evdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { struct evdev_list *list = file->private_data; struct evdev *evdev = list->evdev; @@ -285,109 +371,267 @@ static int evdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, default: - if (_IOC_TYPE(cmd) != 'E' || _IOC_DIR(cmd) != _IOC_READ) + if (_IOC_TYPE(cmd) != 'E') return -EINVAL; - if ((_IOC_NR(cmd) & ~EV_MAX) == _IOC_NR(EVIOCGBIT(0,0))) { - - long *bits; - int len; - - switch (_IOC_NR(cmd) & EV_MAX) { - case 0: bits = dev->evbit; len = EV_MAX; break; - case EV_KEY: bits = dev->keybit; len = KEY_MAX; break; - case EV_REL: bits = dev->relbit; len = REL_MAX; break; - case EV_ABS: bits = dev->absbit; len = ABS_MAX; break; - case EV_MSC: bits = dev->mscbit; len = MSC_MAX; break; - case EV_LED: bits = dev->ledbit; len = LED_MAX; break; - case EV_SND: bits = dev->sndbit; len = SND_MAX; break; - case EV_FF: bits = dev->ffbit; len = FF_MAX; break; - default: return -EINVAL; + if (_IOC_DIR(cmd) == _IOC_READ) { + + if ((_IOC_NR(cmd) & ~EV_MAX) == _IOC_NR(EVIOCGBIT(0,0))) { + + long *bits; + int len; + + switch (_IOC_NR(cmd) & EV_MAX) { + case 0: bits = dev->evbit; len = EV_MAX; break; + case EV_KEY: bits = dev->keybit; len = KEY_MAX; break; + case EV_REL: bits = dev->relbit; len = REL_MAX; break; + case EV_ABS: bits = dev->absbit; len = ABS_MAX; break; + case EV_MSC: bits = dev->mscbit; len = MSC_MAX; break; + case EV_LED: bits = dev->ledbit; len = LED_MAX; break; + case EV_SND: bits = dev->sndbit; len = SND_MAX; break; + case EV_FF: bits = dev->ffbit; len = FF_MAX; break; + default: return -EINVAL; + } + len = NBITS(len) * sizeof(long); + if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd); + return copy_to_user(p, bits, len) ? -EFAULT : len; } - len = NBITS(len) * sizeof(long); - if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd); - return copy_to_user(p, bits, len) ? -EFAULT : len; - } - if (_IOC_NR(cmd) == _IOC_NR(EVIOCGKEY(0))) { - int len; - len = NBITS(KEY_MAX) * sizeof(long); - if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd); - return copy_to_user(p, dev->key, len) ? -EFAULT : len; - } + if (_IOC_NR(cmd) == _IOC_NR(EVIOCGKEY(0))) { + int len; + len = NBITS(KEY_MAX) * sizeof(long); + if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd); + return copy_to_user(p, dev->key, len) ? -EFAULT : len; + } - if (_IOC_NR(cmd) == _IOC_NR(EVIOCGLED(0))) { - int len; - len = NBITS(LED_MAX) * sizeof(long); - if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd); - return copy_to_user(p, dev->led, len) ? -EFAULT : len; - } + if (_IOC_NR(cmd) == _IOC_NR(EVIOCGLED(0))) { + int len; + len = NBITS(LED_MAX) * sizeof(long); + if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd); + return copy_to_user(p, dev->led, len) ? -EFAULT : len; + } - if (_IOC_NR(cmd) == _IOC_NR(EVIOCGSND(0))) { - int len; - len = NBITS(SND_MAX) * sizeof(long); - if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd); - return copy_to_user(p, dev->snd, len) ? -EFAULT : len; - } + if (_IOC_NR(cmd) == _IOC_NR(EVIOCGSND(0))) { + int len; + len = NBITS(SND_MAX) * sizeof(long); + if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd); + return copy_to_user(p, dev->snd, len) ? -EFAULT : len; + } - if (_IOC_NR(cmd) == _IOC_NR(EVIOCGNAME(0))) { - int len; - if (!dev->name) return -ENOENT; - len = strlen(dev->name) + 1; - if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd); - return copy_to_user(p, dev->name, len) ? -EFAULT : len; - } + if (_IOC_NR(cmd) == _IOC_NR(EVIOCGNAME(0))) { + int len; + if (!dev->name) return -ENOENT; + len = strlen(dev->name) + 1; + if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd); + return copy_to_user(p, dev->name, len) ? -EFAULT : len; + } + + if (_IOC_NR(cmd) == _IOC_NR(EVIOCGPHYS(0))) { + int len; + if (!dev->phys) return -ENOENT; + len = strlen(dev->phys) + 1; + if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd); + return copy_to_user(p, dev->phys, len) ? -EFAULT : len; + } + + if (_IOC_NR(cmd) == _IOC_NR(EVIOCGUNIQ(0))) { + int len; + if (!dev->uniq) return -ENOENT; + len = strlen(dev->uniq) + 1; + if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd); + return copy_to_user(p, dev->uniq, len) ? -EFAULT : len; + } + + if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCGABS(0))) { + + int t = _IOC_NR(cmd) & ABS_MAX; + + abs.value = dev->abs[t]; + abs.minimum = dev->absmin[t]; + abs.maximum = dev->absmax[t]; + abs.fuzz = dev->absfuzz[t]; + abs.flat = dev->absflat[t]; + + if (copy_to_user(p, &abs, sizeof(struct input_absinfo))) + return -EFAULT; + + return 0; + } - if (_IOC_NR(cmd) == _IOC_NR(EVIOCGPHYS(0))) { - int len; - if (!dev->phys) return -ENOENT; - len = strlen(dev->phys) + 1; - if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd); - return copy_to_user(p, dev->phys, len) ? -EFAULT : len; } - if (_IOC_NR(cmd) == _IOC_NR(EVIOCGUNIQ(0))) { - int len; - if (!dev->uniq) return -ENOENT; - len = strlen(dev->uniq) + 1; - if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd); - return copy_to_user(p, dev->uniq, len) ? -EFAULT : len; + if (_IOC_DIR(cmd) == _IOC_WRITE) { + + if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCSABS(0))) { + + int t = _IOC_NR(cmd) & ABS_MAX; + + if (copy_from_user(&abs, p, sizeof(struct input_absinfo))) + return -EFAULT; + + dev->abs[t] = abs.value; + dev->absmin[t] = abs.minimum; + dev->absmax[t] = abs.maximum; + dev->absfuzz[t] = abs.fuzz; + dev->absflat[t] = abs.flat; + + return 0; + } } + } + return -EINVAL; +} - if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCGABS(0))) { +#ifdef CONFIG_COMPAT + +#define BITS_PER_LONG_COMPAT (sizeof(compat_long_t) * 8) +#define NBITS_COMPAT(x) ((((x)-1)/BITS_PER_LONG_COMPAT)+1) +#define OFF_COMPAT(x) ((x)%BITS_PER_LONG_COMPAT) +#define BIT_COMPAT(x) (1UL<<OFF_COMPAT(x)) +#define LONG_COMPAT(x) ((x)/BITS_PER_LONG_COMPAT) +#define test_bit_compat(bit, array) ((array[LONG_COMPAT(bit)] >> OFF_COMPAT(bit)) & 1) + +#ifdef __BIG_ENDIAN +#define bit_to_user(bit, max) \ +do { \ + int i; \ + int len = NBITS_COMPAT((max)) * sizeof(compat_long_t); \ + if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd); \ + for (i = 0; i < len / sizeof(compat_long_t); i++) \ + if (copy_to_user((compat_long_t*) p + i, \ + (compat_long_t*) (bit) + i + 1 - ((i % 2) << 1), \ + sizeof(compat_long_t))) \ + return -EFAULT; \ + return len; \ +} while (0) +#else +#define bit_to_user(bit, max) \ +do { \ + int len = NBITS_COMPAT((max)) * sizeof(compat_long_t); \ + if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd); \ + return copy_to_user(p, (bit), len) ? -EFAULT : len; \ +} while (0) +#endif + +static long evdev_ioctl_compat(struct file *file, unsigned int cmd, unsigned long arg) +{ + struct evdev_list *list = file->private_data; + struct evdev *evdev = list->evdev; + struct input_dev *dev = evdev->handle.dev; + struct input_absinfo abs; + void __user *p = compat_ptr(arg); - int t = _IOC_NR(cmd) & ABS_MAX; + if (!evdev->exist) return -ENODEV; - abs.value = dev->abs[t]; - abs.minimum = dev->absmin[t]; - abs.maximum = dev->absmax[t]; - abs.fuzz = dev->absfuzz[t]; - abs.flat = dev->absflat[t]; + switch (cmd) { - if (copy_to_user(p, &abs, sizeof(struct input_absinfo))) - return -EFAULT; + case EVIOCGVERSION: + case EVIOCGID: + case EVIOCGKEYCODE: + case EVIOCSKEYCODE: + case EVIOCSFF: + case EVIOCRMFF: + case EVIOCGEFFECTS: + case EVIOCGRAB: + return evdev_ioctl(file, cmd, (unsigned long) p); - return 0; + default: + + if (_IOC_TYPE(cmd) != 'E') + return -EINVAL; + + if (_IOC_DIR(cmd) == _IOC_READ) { + + if ((_IOC_NR(cmd) & ~EV_MAX) == _IOC_NR(EVIOCGBIT(0,0))) { + long *bits; + int max; + + switch (_IOC_NR(cmd) & EV_MAX) { + case 0: bits = dev->evbit; max = EV_MAX; break; + case EV_KEY: bits = dev->keybit; max = KEY_MAX; break; + case EV_REL: bits = dev->relbit; max = REL_MAX; break; + case EV_ABS: bits = dev->absbit; max = ABS_MAX; break; + case EV_MSC: bits = dev->mscbit; max = MSC_MAX; break; + case EV_LED: bits = dev->ledbit; max = LED_MAX; break; + case EV_SND: bits = dev->sndbit; max = SND_MAX; break; + case EV_FF: bits = dev->ffbit; max = FF_MAX; break; + default: return -EINVAL; + } + bit_to_user(bits, max); + } + + if (_IOC_NR(cmd) == _IOC_NR(EVIOCGKEY(0))) + bit_to_user(dev->key, KEY_MAX); + + if (_IOC_NR(cmd) == _IOC_NR(EVIOCGLED(0))) + bit_to_user(dev->led, LED_MAX); + + if (_IOC_NR(cmd) == _IOC_NR(EVIOCGSND(0))) + bit_to_user(dev->snd, SND_MAX); + + if (_IOC_NR(cmd) == _IOC_NR(EVIOCGNAME(0))) { + int len; + if (!dev->name) return -ENOENT; + len = strlen(dev->name) + 1; + if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd); + return copy_to_user(p, dev->name, len) ? -EFAULT : len; + } + + if (_IOC_NR(cmd) == _IOC_NR(EVIOCGPHYS(0))) { + int len; + if (!dev->phys) return -ENOENT; + len = strlen(dev->phys) + 1; + if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd); + return copy_to_user(p, dev->phys, len) ? -EFAULT : len; + } + + if (_IOC_NR(cmd) == _IOC_NR(EVIOCGUNIQ(0))) { + int len; + if (!dev->uniq) return -ENOENT; + len = strlen(dev->uniq) + 1; + if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd); + return copy_to_user(p, dev->uniq, len) ? -EFAULT : len; + } + + if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCGABS(0))) { + + int t = _IOC_NR(cmd) & ABS_MAX; + + abs.value = dev->abs[t]; + abs.minimum = dev->absmin[t]; + abs.maximum = dev->absmax[t]; + abs.fuzz = dev->absfuzz[t]; + abs.flat = dev->absflat[t]; + + if (copy_to_user(p, &abs, sizeof(struct input_absinfo))) + return -EFAULT; + + return 0; + } } - if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCSABS(0))) { + if (_IOC_DIR(cmd) == _IOC_WRITE) { - int t = _IOC_NR(cmd) & ABS_MAX; + if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCSABS(0))) { - if (copy_from_user(&abs, p, sizeof(struct input_absinfo))) - return -EFAULT; + int t = _IOC_NR(cmd) & ABS_MAX; - dev->abs[t] = abs.value; - dev->absmin[t] = abs.minimum; - dev->absmax[t] = abs.maximum; - dev->absfuzz[t] = abs.fuzz; - dev->absflat[t] = abs.flat; + if (copy_from_user(&abs, p, sizeof(struct input_absinfo))) + return -EFAULT; - return 0; + dev->abs[t] = abs.value; + dev->absmin[t] = abs.minimum; + dev->absmax[t] = abs.maximum; + dev->absfuzz[t] = abs.fuzz; + dev->absflat[t] = abs.flat; + + return 0; + } } } return -EINVAL; } +#endif static struct file_operations evdev_fops = { .owner = THIS_MODULE, @@ -396,7 +640,10 @@ static struct file_operations evdev_fops = { .poll = evdev_poll, .open = evdev_open, .release = evdev_release, - .ioctl = evdev_ioctl, + .unlocked_ioctl = evdev_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = evdev_ioctl_compat, +#endif .fasync = evdev_fasync, .flush = evdev_flush }; diff --git a/drivers/input/gameport/Kconfig b/drivers/input/gameport/Kconfig index 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 c77a82e46055..3e72c9b1461e 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>*/ @@ -238,8 +237,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 +248,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 +430,15 @@ static struct gameport *gameport_get_pending_child(struct gameport *parent) static int gameport_thread(void *nothing) { - lock_kernel(); - daemonize("kgameportd"); - allow_signal(SIGTERM); - do { gameport_handle_events(); - wait_event_interruptible(gameport_wait, !list_empty(&gameport_event_list)); + wait_event_interruptible(gameport_wait, + kthread_should_stop() || !list_empty(&gameport_event_list)); try_to_freeze(); - } while (!signal_pending(current)); + } while (!kthread_should_stop()); printk(KERN_DEBUG "gameport: kgameportd exiting\n"); - - unlock_kernel(); - complete_and_exit(&gameport_exited, 0); + return 0; } @@ -773,9 +766,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 +783,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..7c4b4d37b3e6 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c @@ -219,10 +219,24 @@ void input_release_device(struct input_handle *handle) int input_open_device(struct input_handle *handle) { + struct input_dev *dev = handle->dev; + int err; + + err = down_interruptible(&dev->sem); + if (err) + return err; + handle->open++; - if (handle->dev->open) - return handle->dev->open(handle->dev); - return 0; + + if (!dev->users++ && dev->open) + err = dev->open(dev); + + if (err) + handle->open--; + + up(&dev->sem); + + return err; } int input_flush_device(struct input_handle* handle, struct file* file) @@ -235,10 +249,17 @@ int input_flush_device(struct input_handle* handle, struct file* file) void input_close_device(struct input_handle *handle) { + struct input_dev *dev = handle->dev; + input_release_device(handle); - if (handle->dev->close) - handle->dev->close(handle->dev); + + down(&dev->sem); + + if (!--dev->users && dev->close) + dev->close(dev); handle->open--; + + up(&dev->sem); } static void input_link_handle(struct input_handle *handle) @@ -415,6 +436,8 @@ void input_register_device(struct input_dev *dev) set_bit(EV_SYN, dev->evbit); + init_MUTEX(&dev->sem); + /* * If delay and period are pre-set by the driver, then autorepeating * is handled by the driver itself and we don't do it in input.c. @@ -674,6 +697,8 @@ static int input_handlers_read(char *buf, char **start, off_t pos, int count, in return (count > cnt) ? cnt : count; } +static struct file_operations input_fileops; + static int __init input_proc_init(void) { struct proc_dir_entry *entry; @@ -688,6 +713,8 @@ static int __init input_proc_init(void) return -ENOMEM; } entry->owner = THIS_MODULE; + input_fileops = *entry->proc_fops; + entry->proc_fops = &input_fileops; entry->proc_fops->poll = input_devices_poll; entry = create_proc_read_entry("handlers", 0, proc_bus_input_dir, input_handlers_read, NULL); if (entry == NULL) { diff --git a/drivers/input/joydev.c b/drivers/input/joydev.c index 39775fc380c7..ff8e1bbd0e13 100644 --- a/drivers/input/joydev.c +++ b/drivers/input/joydev.c @@ -285,48 +285,33 @@ static unsigned int joydev_poll(struct file *file, poll_table *wait) (POLLIN | POLLRDNORM) : 0) | (list->joydev->exist ? 0 : (POLLHUP | POLLERR)); } -static int joydev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) +static int joydev_ioctl_common(struct joydev *joydev, unsigned int cmd, void __user *argp) { - struct joydev_list *list = file->private_data; - struct joydev *joydev = list->joydev; struct input_dev *dev = joydev->handle.dev; - void __user *argp = (void __user *)arg; int i, j; - if (!joydev->exist) return -ENODEV; - switch (cmd) { case JS_SET_CAL: return copy_from_user(&joydev->glue.JS_CORR, argp, - sizeof(struct JS_DATA_TYPE)) ? -EFAULT : 0; + sizeof(joydev->glue.JS_CORR)) ? -EFAULT : 0; case JS_GET_CAL: return copy_to_user(argp, &joydev->glue.JS_CORR, - sizeof(struct JS_DATA_TYPE)) ? -EFAULT : 0; + sizeof(joydev->glue.JS_CORR)) ? -EFAULT : 0; case JS_SET_TIMEOUT: - return get_user(joydev->glue.JS_TIMEOUT, (int __user *) arg); + return get_user(joydev->glue.JS_TIMEOUT, (s32 __user *) argp); case JS_GET_TIMEOUT: - return put_user(joydev->glue.JS_TIMEOUT, (int __user *) arg); - case JS_SET_TIMELIMIT: - return get_user(joydev->glue.JS_TIMELIMIT, (long __user *) arg); - case JS_GET_TIMELIMIT: - return put_user(joydev->glue.JS_TIMELIMIT, (long __user *) arg); - case JS_SET_ALL: - return copy_from_user(&joydev->glue, argp, - sizeof(struct JS_DATA_SAVE_TYPE)) ? -EFAULT : 0; - case JS_GET_ALL: - return copy_to_user(argp, &joydev->glue, - sizeof(struct JS_DATA_SAVE_TYPE)) ? -EFAULT : 0; + return put_user(joydev->glue.JS_TIMEOUT, (s32 __user *) argp); case JSIOCGVERSION: - return put_user(JS_VERSION, (__u32 __user *) arg); + return put_user(JS_VERSION, (__u32 __user *) argp); case JSIOCGAXES: - return put_user(joydev->nabs, (__u8 __user *) arg); + return put_user(joydev->nabs, (__u8 __user *) argp); case JSIOCGBUTTONS: - return put_user(joydev->nkey, (__u8 __user *) arg); + return put_user(joydev->nkey, (__u8 __user *) argp); case JSIOCSCORR: if (copy_from_user(joydev->corr, argp, - sizeof(struct js_corr) * joydev->nabs)) + sizeof(joydev->corr[0]) * joydev->nabs)) return -EFAULT; for (i = 0; i < joydev->nabs; i++) { j = joydev->abspam[i]; @@ -335,7 +320,7 @@ static int joydev_ioctl(struct inode *inode, struct file *file, unsigned int cmd return 0; case JSIOCGCORR: return copy_to_user(argp, joydev->corr, - sizeof(struct js_corr) * joydev->nabs) ? -EFAULT : 0; + sizeof(joydev->corr[0]) * joydev->nabs) ? -EFAULT : 0; case JSIOCSAXMAP: if (copy_from_user(joydev->abspam, argp, sizeof(__u8) * (ABS_MAX + 1))) return -EFAULT; @@ -371,6 +356,84 @@ static int joydev_ioctl(struct inode *inode, struct file *file, unsigned int cmd return -EINVAL; } +#ifdef CONFIG_COMPAT +static long joydev_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + struct joydev_list *list = file->private_data; + struct joydev *joydev = list->joydev; + void __user *argp = (void __user *)arg; + s32 tmp32; + struct JS_DATA_SAVE_TYPE_32 ds32; + int err; + + if (!joydev->exist) return -ENODEV; + switch(cmd) { + case JS_SET_TIMELIMIT: + err = get_user(tmp32, (s32 __user *) arg); + if (err == 0) + joydev->glue.JS_TIMELIMIT = tmp32; + break; + case JS_GET_TIMELIMIT: + tmp32 = joydev->glue.JS_TIMELIMIT; + err = put_user(tmp32, (s32 __user *) arg); + break; + + case JS_SET_ALL: + err = copy_from_user(&ds32, argp, + sizeof(ds32)) ? -EFAULT : 0; + if (err == 0) { + joydev->glue.JS_TIMEOUT = ds32.JS_TIMEOUT; + joydev->glue.BUSY = ds32.BUSY; + joydev->glue.JS_EXPIRETIME = ds32.JS_EXPIRETIME; + joydev->glue.JS_TIMELIMIT = ds32.JS_TIMELIMIT; + joydev->glue.JS_SAVE = ds32.JS_SAVE; + joydev->glue.JS_CORR = ds32.JS_CORR; + } + break; + + case JS_GET_ALL: + ds32.JS_TIMEOUT = joydev->glue.JS_TIMEOUT; + ds32.BUSY = joydev->glue.BUSY; + ds32.JS_EXPIRETIME = joydev->glue.JS_EXPIRETIME; + ds32.JS_TIMELIMIT = joydev->glue.JS_TIMELIMIT; + ds32.JS_SAVE = joydev->glue.JS_SAVE; + ds32.JS_CORR = joydev->glue.JS_CORR; + + err = copy_to_user(argp, &ds32, + sizeof(ds32)) ? -EFAULT : 0; + break; + + default: + err = joydev_ioctl_common(joydev, cmd, argp); + } + return err; +} +#endif /* CONFIG_COMPAT */ + +static int joydev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) +{ + struct joydev_list *list = file->private_data; + struct joydev *joydev = list->joydev; + void __user *argp = (void __user *)arg; + + if (!joydev->exist) return -ENODEV; + + switch(cmd) { + case JS_SET_TIMELIMIT: + return get_user(joydev->glue.JS_TIMELIMIT, (long __user *) arg); + case JS_GET_TIMELIMIT: + return put_user(joydev->glue.JS_TIMELIMIT, (long __user *) arg); + case JS_SET_ALL: + return copy_from_user(&joydev->glue, argp, + sizeof(joydev->glue)) ? -EFAULT : 0; + case JS_GET_ALL: + return copy_to_user(argp, &joydev->glue, + sizeof(joydev->glue)) ? -EFAULT : 0; + default: + return joydev_ioctl_common(joydev, cmd, argp); + } +} + static struct file_operations joydev_fops = { .owner = THIS_MODULE, .read = joydev_read, @@ -379,6 +442,9 @@ static struct file_operations joydev_fops = { .open = joydev_open, .release = joydev_release, .ioctl = joydev_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = joydev_compat_ioctl, +#endif .fasync = joydev_fasync, }; diff --git a/drivers/input/joystick/a3d.c b/drivers/input/joystick/a3d.c index 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..033456bb9fe0 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(&amijoysem); + 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/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..98710997aaaa 100644 --- a/drivers/input/misc/uinput.c +++ b/drivers/input/misc/uinput.c @@ -298,9 +298,11 @@ static int uinput_alloc_device(struct file *file, const char __user *buffer, siz /* check if absmin/absmax/absfuzz/absflat are filled as * told in Documentation/input/input-programming.txt */ if (test_bit(EV_ABS, dev->evbit)) { - retval = uinput_validate_absbits(dev); - if (retval < 0) + int err = uinput_validate_absbits(dev); + if (err < 0) { + retval = err; kfree(dev->name); + } } exit: diff --git a/drivers/input/mouse/Makefile b/drivers/input/mouse/Makefile index 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..a12e98158a75 100644 --- a/drivers/input/mouse/alps.c +++ b/drivers/input/mouse/alps.c @@ -30,10 +30,11 @@ #define ALPS_DUALPOINT 0x01 #define ALPS_WHEEL 0x02 -#define ALPS_FW_BK 0x04 +#define ALPS_FW_BK_1 0x04 #define ALPS_4BTN 0x08 #define ALPS_OLDPROTO 0x10 #define ALPS_PASS 0x20 +#define ALPS_FW_BK_2 0x40 static struct alps_model_info alps_model_data[] = { { { 0x33, 0x02, 0x0a }, 0x88, 0xf8, ALPS_OLDPROTO }, /* UMAX-530T */ @@ -43,11 +44,11 @@ static struct alps_model_info alps_model_data[] = { { { 0x63, 0x02, 0x14 }, 0xf8, 0xf8, 0 }, { { 0x63, 0x02, 0x28 }, 0xf8, 0xf8, 0 }, { { 0x63, 0x02, 0x3c }, 0x8f, 0x8f, ALPS_WHEEL }, /* Toshiba Satellite S2400-103 */ - { { 0x63, 0x02, 0x50 }, 0xef, 0xef, ALPS_FW_BK }, /* NEC Versa L320 */ + { { 0x63, 0x02, 0x50 }, 0xef, 0xef, ALPS_FW_BK_1 }, /* NEC Versa L320 */ { { 0x63, 0x02, 0x64 }, 0xf8, 0xf8, 0 }, { { 0x63, 0x03, 0xc8 }, 0xf8, 0xf8, ALPS_PASS }, /* Dell Latitude D800 */ { { 0x73, 0x02, 0x0a }, 0xf8, 0xf8, 0 }, - { { 0x73, 0x02, 0x14 }, 0xf8, 0xf8, 0 }, + { { 0x73, 0x02, 0x14 }, 0xf8, 0xf8, ALPS_FW_BK_2 }, /* Ahtec Laptop */ { { 0x20, 0x02, 0x0e }, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, /* XXX */ { { 0x22, 0x02, 0x0a }, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, { { 0x22, 0x02, 0x14 }, 0xff, 0xff, ALPS_PASS | ALPS_DUALPOINT }, /* Dell Latitude D600 */ @@ -61,11 +62,11 @@ static struct alps_model_info alps_model_data[] = { /* * ALPS abolute Mode - new format - * - * byte 0: 1 ? ? ? 1 ? ? ? + * + * byte 0: 1 ? ? ? 1 ? ? ? * byte 1: 0 x6 x5 x4 x3 x2 x1 x0 * byte 2: 0 x10 x9 x8 x7 ? fin ges - * byte 3: 0 y9 y8 y7 1 M R L + * byte 3: 0 y9 y8 y7 1 M R L * byte 4: 0 y6 y5 y4 y3 y2 y1 y0 * byte 5: 0 z6 z5 z4 z3 z2 z1 z0 * @@ -81,11 +82,12 @@ static void alps_process_packet(struct psmouse *psmouse, struct pt_regs *regs) struct input_dev *dev = &psmouse->dev; struct input_dev *dev2 = &priv->dev2; int x, y, z, ges, fin, left, right, middle; + int back = 0, forward = 0; input_regs(dev, regs); if ((packet[0] & 0xc8) == 0x08) { /* 3-byte PS/2 packet */ - input_report_key(dev2, BTN_LEFT, packet[0] & 1); + input_report_key(dev2, BTN_LEFT, packet[0] & 1); input_report_key(dev2, BTN_RIGHT, packet[0] & 2); input_report_key(dev2, BTN_MIDDLE, packet[0] & 4); input_report_rel(dev2, REL_X, @@ -112,6 +114,18 @@ static void alps_process_packet(struct psmouse *psmouse, struct pt_regs *regs) z = packet[5]; } + if (priv->i->flags & ALPS_FW_BK_1) { + back = packet[2] & 4; + forward = packet[0] & 0x10; + } + + if (priv->i->flags & ALPS_FW_BK_2) { + back = packet[3] & 4; + forward = packet[2] & 4; + if ((middle = forward && back)) + forward = back = 0; + } + ges = packet[2] & 1; fin = packet[2] & 2; @@ -155,13 +169,12 @@ static void alps_process_packet(struct psmouse *psmouse, struct pt_regs *regs) input_report_abs(dev, ABS_PRESSURE, z); input_report_key(dev, BTN_TOOL_FINGER, z > 0); - if (priv->i->flags & ALPS_WHEEL) input_report_rel(dev, REL_WHEEL, ((packet[0] >> 4) & 0x07) | ((packet[2] >> 2) & 0x08)); - if (priv->i->flags & ALPS_FW_BK) { - input_report_key(dev, BTN_FORWARD, packet[0] & 0x10); - input_report_key(dev, BTN_BACK, packet[2] & 0x04); + if (priv->i->flags & (ALPS_FW_BK_1 | ALPS_FW_BK_2)) { + input_report_key(dev, BTN_FORWARD, forward); + input_report_key(dev, BTN_BACK, back); } input_sync(dev); @@ -257,7 +270,6 @@ static struct alps_model_info *alps_get_model(struct psmouse *psmouse, int *vers static int alps_passthrough_mode(struct psmouse *psmouse, int enable) { struct ps2dev *ps2dev = &psmouse->ps2dev; - unsigned char param[3]; int cmd = enable ? PSMOUSE_CMD_SETSCALE21 : PSMOUSE_CMD_SETSCALE11; if (ps2_command(ps2dev, NULL, cmd) || @@ -267,7 +279,7 @@ static int alps_passthrough_mode(struct psmouse *psmouse, int enable) return -1; /* we may get 3 more bytes, just ignore them */ - ps2_command(ps2dev, param, 0x0300); + ps2_drain(ps2dev, 3, 100); return 0; } @@ -425,7 +437,7 @@ int alps_init(struct psmouse *psmouse) psmouse->dev.relbit[LONG(REL_WHEEL)] |= BIT(REL_WHEEL); } - if (priv->i->flags & ALPS_FW_BK) { + if (priv->i->flags & (ALPS_FW_BK_1 | ALPS_FW_BK_2)) { psmouse->dev.keybit[LONG(BTN_FORWARD)] |= BIT(BTN_FORWARD); psmouse->dev.keybit[LONG(BTN_BACK)] |= BIT(BTN_BACK); } @@ -436,8 +448,8 @@ int alps_init(struct psmouse *psmouse) priv->dev2.id.bustype = BUS_I8042; priv->dev2.id.vendor = 0x0002; priv->dev2.id.product = PSMOUSE_ALPS; - priv->dev2.id.version = 0x0000; - + priv->dev2.id.version = 0x0000; + priv->dev2.evbit[0] = BIT(EV_KEY) | BIT(EV_REL); priv->dev2.relbit[LONG(REL_X)] |= BIT(REL_X) | BIT(REL_Y); priv->dev2.keybit[LONG(BTN_LEFT)] |= BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT); @@ -461,17 +473,15 @@ init_fail: int alps_detect(struct psmouse *psmouse, int set_properties) { int version; - struct alps_model_info *model; + struct alps_model_info *model; if (!(model = alps_get_model(psmouse, &version))) return -1; if (set_properties) { psmouse->vendor = "ALPS"; - if (model->flags & ALPS_DUALPOINT) - psmouse->name = "DualPoint TouchPad"; - else - psmouse->name = "GlidePoint"; + psmouse->name = model->flags & ALPS_DUALPOINT ? + "DualPoint TouchPad" : "GlidePoint"; psmouse->model = version; } return 0; diff --git a/drivers/input/mouse/amimouse.c b/drivers/input/mouse/amimouse.c index 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/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..19785a6c5abd 100644 --- a/drivers/input/mouse/psmouse-base.c +++ b/drivers/input/mouse/psmouse-base.c @@ -24,6 +24,7 @@ #include "synaptics.h" #include "logips2pp.h" #include "alps.h" +#include "lifebook.h" #define DRIVER_DESC "PS/2 mouse driver" @@ -31,10 +32,9 @@ MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>"); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); -static unsigned int psmouse_max_proto = -1U; +static unsigned int psmouse_max_proto = PSMOUSE_AUTO; static int psmouse_set_maxproto(const char *val, struct kernel_param *kp); static int psmouse_get_maxproto(char *buffer, struct kernel_param *kp); -static char *psmouse_proto_abbrev[] = { NULL, "bare", NULL, NULL, NULL, "imps", "exps", NULL, NULL, NULL }; #define param_check_proto_abbrev(name, p) __param_check(name, p, unsigned int) #define param_set_proto_abbrev psmouse_set_maxproto #define param_get_proto_abbrev psmouse_get_maxproto @@ -57,6 +57,7 @@ static unsigned int psmouse_resetafter; module_param_named(resetafter, psmouse_resetafter, uint, 0644); MODULE_PARM_DESC(resetafter, "Reset device after so many bad packets (0 = never)."); +PSMOUSE_DEFINE_ATTR(protocol); PSMOUSE_DEFINE_ATTR(rate); PSMOUSE_DEFINE_ATTR(resolution); PSMOUSE_DEFINE_ATTR(resetafter); @@ -67,7 +68,23 @@ __obsolete_setup("psmouse_smartscroll="); __obsolete_setup("psmouse_resetafter="); __obsolete_setup("psmouse_rate="); -static char *psmouse_protocols[] = { "None", "PS/2", "PS2++", "ThinkPS/2", "GenPS/2", "ImPS/2", "ImExPS/2", "SynPS/2", "AlpsPS/2" }; +/* + * psmouse_sem protects all operations changing state of mouse + * (connecting, disconnecting, changing rate or resolution via + * sysfs). We could use a per-device semaphore but since there + * rarely more than one PS/2 mouse connected and since semaphore + * is taken in "slow" paths it is not worth it. + */ +static DECLARE_MUTEX(psmouse_sem); + +struct psmouse_protocol { + enum psmouse_type type; + char *name; + char *alias; + int maxproto; + int (*detect)(struct psmouse *, int); + int (*init)(struct psmouse *); +}; /* * psmouse_process_byte() analyzes the PS/2 data stream and reports @@ -407,12 +424,15 @@ static int thinking_detect(struct psmouse *psmouse, int set_properties) */ static int ps2bare_detect(struct psmouse *psmouse, int set_properties) { - if (!psmouse->vendor) psmouse->vendor = "Generic"; - if (!psmouse->name) psmouse->name = "Mouse"; + if (set_properties) { + if (!psmouse->vendor) psmouse->vendor = "Generic"; + if (!psmouse->name) psmouse->name = "Mouse"; + } return 0; } + /* * psmouse_extensions() probes for any extensions to the basic PS/2 protocol * the mouse may have. @@ -424,6 +444,17 @@ static int psmouse_extensions(struct psmouse *psmouse, int synaptics_hardware = 0; /* + * We always check for lifebook because it does not disturb mouse + * (it only checks DMI information). + */ + if (lifebook_detect(psmouse, set_properties) == 0) { + if (max_proto > PSMOUSE_IMEX) { + if (!set_properties || lifebook_init(psmouse) == 0) + return PSMOUSE_LIFEBOOK; + } + } + +/* * Try Kensington ThinkingMouse (we try first, because synaptics probe * upsets the thinkingmouse). */ @@ -506,6 +537,103 @@ static int psmouse_extensions(struct psmouse *psmouse, return PSMOUSE_PS2; } +static struct psmouse_protocol psmouse_protocols[] = { + { + .type = PSMOUSE_PS2, + .name = "PS/2", + .alias = "bare", + .maxproto = 1, + .detect = ps2bare_detect, + }, + { + .type = PSMOUSE_PS2PP, + .name = "PS2++", + .alias = "logitech", + .detect = ps2pp_init, + }, + { + .type = PSMOUSE_THINKPS, + .name = "ThinkPS/2", + .alias = "thinkps", + .detect = thinking_detect, + }, + { + .type = PSMOUSE_GENPS, + .name = "GenPS/2", + .alias = "genius", + .detect = genius_detect, + }, + { + .type = PSMOUSE_IMPS, + .name = "ImPS/2", + .alias = "imps", + .maxproto = 1, + .detect = intellimouse_detect, + }, + { + .type = PSMOUSE_IMEX, + .name = "ImExPS/2", + .alias = "exps", + .maxproto = 1, + .detect = im_explorer_detect, + }, + { + .type = PSMOUSE_SYNAPTICS, + .name = "SynPS/2", + .alias = "synaptics", + .detect = synaptics_detect, + .init = synaptics_init, + }, + { + .type = PSMOUSE_ALPS, + .name = "AlpsPS/2", + .alias = "alps", + .detect = alps_detect, + .init = alps_init, + }, + { + .type = PSMOUSE_LIFEBOOK, + .name = "LBPS/2", + .alias = "lifebook", + .init = lifebook_init, + }, + { + .type = PSMOUSE_AUTO, + .name = "auto", + .alias = "any", + .maxproto = 1, + }, +}; + +static struct psmouse_protocol *psmouse_protocol_by_type(enum psmouse_type type) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(psmouse_protocols); i++) + if (psmouse_protocols[i].type == type) + return &psmouse_protocols[i]; + + WARN_ON(1); + return &psmouse_protocols[0]; +} + +static struct psmouse_protocol *psmouse_protocol_by_name(const char *name, size_t len) +{ + struct psmouse_protocol *p; + int i; + + for (i = 0; i < ARRAY_SIZE(psmouse_protocols); i++) { + p = &psmouse_protocols[i]; + + if ((strlen(p->name) == len && !strncmp(p->name, name, len)) || + (strlen(p->alias) == len && !strncmp(p->alias, name, len))) + return &psmouse_protocols[i]; + } + + return NULL; +} + + /* * psmouse_probe() probes for a PS/2 mouse. */ @@ -653,30 +781,84 @@ static void psmouse_cleanup(struct serio *serio) static void psmouse_disconnect(struct serio *serio) { - struct psmouse *psmouse, *parent; + struct psmouse *psmouse, *parent = NULL; + psmouse = serio_get_drvdata(serio); + + device_remove_file(&serio->dev, &psmouse_attr_protocol); device_remove_file(&serio->dev, &psmouse_attr_rate); device_remove_file(&serio->dev, &psmouse_attr_resolution); device_remove_file(&serio->dev, &psmouse_attr_resetafter); - psmouse = serio_get_drvdata(serio); + down(&psmouse_sem); + psmouse_set_state(psmouse, PSMOUSE_CMD_MODE); if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) { parent = serio_get_drvdata(serio->parent); - if (parent->pt_deactivate) - parent->pt_deactivate(parent); + psmouse_deactivate(parent); } if (psmouse->disconnect) psmouse->disconnect(psmouse); + if (parent && parent->pt_deactivate) + parent->pt_deactivate(parent); + psmouse_set_state(psmouse, PSMOUSE_IGNORE); input_unregister_device(&psmouse->dev); serio_close(serio); serio_set_drvdata(serio, NULL); kfree(psmouse); + + if (parent) + psmouse_activate(parent); + + up(&psmouse_sem); +} + +static int psmouse_switch_protocol(struct psmouse *psmouse, struct psmouse_protocol *proto) +{ + memset(&psmouse->dev, 0, sizeof(struct input_dev)); + + init_input_dev(&psmouse->dev); + + psmouse->dev.private = psmouse; + psmouse->dev.dev = &psmouse->ps2dev.serio->dev; + + psmouse->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REL); + psmouse->dev.keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT); + psmouse->dev.relbit[0] = BIT(REL_X) | BIT(REL_Y); + + psmouse->set_rate = psmouse_set_rate; + psmouse->set_resolution = psmouse_set_resolution; + psmouse->protocol_handler = psmouse_process_byte; + psmouse->pktsize = 3; + + if (proto && (proto->detect || proto->init)) { + if (proto->detect && proto->detect(psmouse, 1) < 0) + return -1; + + if (proto->init && proto->init(psmouse) < 0) + return -1; + + psmouse->type = proto->type; + } + else + psmouse->type = psmouse_extensions(psmouse, psmouse_max_proto, 1); + + sprintf(psmouse->devname, "%s %s %s", + psmouse_protocol_by_type(psmouse->type)->name, psmouse->vendor, psmouse->name); + + psmouse->dev.name = psmouse->devname; + psmouse->dev.phys = psmouse->phys; + psmouse->dev.id.bustype = BUS_I8042; + psmouse->dev.id.vendor = 0x0002; + psmouse->dev.id.product = psmouse->type; + psmouse->dev.id.version = psmouse->model; + + return 0; } /* @@ -688,6 +870,8 @@ static int psmouse_connect(struct serio *serio, struct serio_driver *drv) struct psmouse *psmouse, *parent = NULL; int retval; + down(&psmouse_sem); + /* * If this is a pass-through port deactivate parent so the device * connected to this port can be successfully identified @@ -697,20 +881,14 @@ static int psmouse_connect(struct serio *serio, struct serio_driver *drv) psmouse_deactivate(parent); } - if (!(psmouse = kmalloc(sizeof(struct psmouse), GFP_KERNEL))) { + if (!(psmouse = kcalloc(1, sizeof(struct psmouse), GFP_KERNEL))) { retval = -ENOMEM; goto out; } - memset(psmouse, 0, sizeof(struct psmouse)); - ps2_init(&psmouse->ps2dev, serio); sprintf(psmouse->phys, "%s/input0", serio->phys); - psmouse->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REL); - psmouse->dev.keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT); - psmouse->dev.relbit[0] = BIT(REL_X) | BIT(REL_Y); - psmouse->dev.private = psmouse; - psmouse->dev.dev = &serio->dev; + psmouse_set_state(psmouse, PSMOUSE_INITIALIZING); serio_set_drvdata(serio, psmouse); @@ -734,25 +912,10 @@ static int psmouse_connect(struct serio *serio, struct serio_driver *drv) psmouse->resolution = psmouse_resolution; psmouse->resetafter = psmouse_resetafter; psmouse->smartscroll = psmouse_smartscroll; - psmouse->set_rate = psmouse_set_rate; - psmouse->set_resolution = psmouse_set_resolution; - psmouse->protocol_handler = psmouse_process_byte; - psmouse->pktsize = 3; - psmouse->type = psmouse_extensions(psmouse, psmouse_max_proto, 1); - - sprintf(psmouse->devname, "%s %s %s", - psmouse_protocols[psmouse->type], psmouse->vendor, psmouse->name); - - psmouse->dev.name = psmouse->devname; - psmouse->dev.phys = psmouse->phys; - psmouse->dev.id.bustype = BUS_I8042; - psmouse->dev.id.vendor = 0x0002; - psmouse->dev.id.product = psmouse->type; - psmouse->dev.id.version = psmouse->model; + psmouse_switch_protocol(psmouse, NULL); input_register_device(&psmouse->dev); - printk(KERN_INFO "input: %s on %s\n", psmouse->devname, serio->phys); psmouse_set_state(psmouse, PSMOUSE_CMD_MODE); @@ -762,6 +925,7 @@ static int psmouse_connect(struct serio *serio, struct serio_driver *drv) if (parent && parent->pt_activate) parent->pt_activate(parent); + device_create_file(&serio->dev, &psmouse_attr_protocol); device_create_file(&serio->dev, &psmouse_attr_rate); device_create_file(&serio->dev, &psmouse_attr_resolution); device_create_file(&serio->dev, &psmouse_attr_resetafter); @@ -771,10 +935,11 @@ static int psmouse_connect(struct serio *serio, struct serio_driver *drv) retval = 0; out: - /* If this is a pass-through port the parent awaits to be activated */ + /* If this is a pass-through port the parent needs to be re-activated */ if (parent) psmouse_activate(parent); + up(&psmouse_sem); return retval; } @@ -791,6 +956,8 @@ static int psmouse_reconnect(struct serio *serio) return -1; } + down(&psmouse_sem); + if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) { parent = serio_get_drvdata(serio->parent); psmouse_deactivate(parent); @@ -823,6 +990,7 @@ out: if (parent) psmouse_activate(parent); + up(&psmouse_sem); return rc; } @@ -893,26 +1061,109 @@ ssize_t psmouse_attr_set_helper(struct device *dev, const char *buf, size_t coun if (serio->drv != &psmouse_drv) { retval = -ENODEV; - goto out; + goto out_unpin; + } + + retval = down_interruptible(&psmouse_sem); + if (retval) + goto out_unpin; + + if (psmouse->state == PSMOUSE_IGNORE) { + retval = -ENODEV; + goto out_up; } if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) { parent = serio_get_drvdata(serio->parent); psmouse_deactivate(parent); } + psmouse_deactivate(psmouse); retval = handler(psmouse, buf, count); - psmouse_activate(psmouse); + if (retval != -ENODEV) + psmouse_activate(psmouse); + if (parent) psmouse_activate(parent); -out: + out_up: + up(&psmouse_sem); + out_unpin: serio_unpin_driver(serio); return retval; } +static ssize_t psmouse_attr_show_protocol(struct psmouse *psmouse, char *buf) +{ + return sprintf(buf, "%s\n", psmouse_protocol_by_type(psmouse->type)->name); +} + +static ssize_t psmouse_attr_set_protocol(struct psmouse *psmouse, const char *buf, size_t count) +{ + struct serio *serio = psmouse->ps2dev.serio; + struct psmouse *parent = NULL; + struct psmouse_protocol *proto; + int retry = 0; + + if (!(proto = psmouse_protocol_by_name(buf, count))) + return -EINVAL; + + if (psmouse->type == proto->type) + return count; + + while (serio->child) { + if (++retry > 3) { + printk(KERN_WARNING "psmouse: failed to destroy child port, protocol change aborted.\n"); + return -EIO; + } + + up(&psmouse_sem); + serio_unpin_driver(serio); + serio_unregister_child_port(serio); + serio_pin_driver_uninterruptible(serio); + down(&psmouse_sem); + + if (serio->drv != &psmouse_drv) + return -ENODEV; + + if (psmouse->type == proto->type) + return count; /* switched by other thread */ + } + + if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) { + parent = serio_get_drvdata(serio->parent); + if (parent->pt_deactivate) + parent->pt_deactivate(parent); + } + + if (psmouse->disconnect) + psmouse->disconnect(psmouse); + + psmouse_set_state(psmouse, PSMOUSE_IGNORE); + input_unregister_device(&psmouse->dev); + + psmouse_set_state(psmouse, PSMOUSE_INITIALIZING); + + if (psmouse_switch_protocol(psmouse, proto) < 0) { + psmouse_reset(psmouse); + /* default to PSMOUSE_PS2 */ + psmouse_switch_protocol(psmouse, &psmouse_protocols[0]); + } + + psmouse_initialize(psmouse); + psmouse_set_state(psmouse, PSMOUSE_CMD_MODE); + + input_register_device(&psmouse->dev); + printk(KERN_INFO "input: %s on %s\n", psmouse->devname, serio->phys); + + if (parent && parent->pt_activate) + parent->pt_activate(parent); + + return count; +} + static ssize_t psmouse_attr_show_rate(struct psmouse *psmouse, char *buf) { return sprintf(buf, "%d\n", psmouse->rate); @@ -969,34 +1220,26 @@ static ssize_t psmouse_attr_set_resetafter(struct psmouse *psmouse, const char * static int psmouse_set_maxproto(const char *val, struct kernel_param *kp) { - int i; + struct psmouse_protocol *proto; if (!val) return -EINVAL; - if (!strncmp(val, "any", 3)) { - *((unsigned int *)kp->arg) = -1U; - return 0; - } + proto = psmouse_protocol_by_name(val, strlen(val)); - for (i = 0; i < ARRAY_SIZE(psmouse_proto_abbrev); i++) { - if (!psmouse_proto_abbrev[i]) - continue; + if (!proto || !proto->maxproto) + return -EINVAL; - if (!strncmp(val, psmouse_proto_abbrev[i], strlen(psmouse_proto_abbrev[i]))) { - *((unsigned int *)kp->arg) = i; - return 0; - } - } + *((unsigned int *)kp->arg) = proto->type; - return -EINVAL; \ + return 0; \ } static int psmouse_get_maxproto(char *buffer, struct kernel_param *kp) { - return sprintf(buffer, "%s\n", - psmouse_max_proto < ARRAY_SIZE(psmouse_proto_abbrev) ? - psmouse_proto_abbrev[psmouse_max_proto] : "any"); + int type = *((unsigned int *)kp->arg); + + return sprintf(buffer, "%s\n", psmouse_protocol_by_type(type)->name); } static int __init psmouse_init(void) diff --git a/drivers/input/mouse/psmouse.h b/drivers/input/mouse/psmouse.h index 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/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/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 341824c48529..f367695e69b5 100644 --- a/drivers/input/serio/serio.c +++ b/drivers/input/serio/serio.c @@ -31,10 +31,9 @@ #include <linux/serio.h> #include <linux/errno.h> #include <linux/wait.h> -#include <linux/completion.h> #include <linux/sched.h> -#include <linux/smp_lock.h> #include <linux/slab.h> +#include <linux/kthread.h> MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); MODULE_DESCRIPTION("Serio abstraction core"); @@ -43,6 +42,7 @@ MODULE_LICENSE("GPL"); EXPORT_SYMBOL(serio_interrupt); EXPORT_SYMBOL(__serio_register_port); EXPORT_SYMBOL(serio_unregister_port); +EXPORT_SYMBOL(serio_unregister_child_port); EXPORT_SYMBOL(__serio_unregister_port_delayed); EXPORT_SYMBOL(__serio_register_driver); EXPORT_SYMBOL(serio_unregister_driver); @@ -68,6 +68,37 @@ static void serio_destroy_port(struct serio *serio); static void serio_reconnect_port(struct serio *serio); static void serio_disconnect_port(struct serio *serio); +static int serio_connect_driver(struct serio *serio, struct serio_driver *drv) +{ + int retval; + + down(&serio->drv_sem); + retval = drv->connect(serio, drv); + up(&serio->drv_sem); + + return retval; +} + +static int serio_reconnect_driver(struct serio *serio) +{ + int retval = -1; + + down(&serio->drv_sem); + if (serio->drv && serio->drv->reconnect) + retval = serio->drv->reconnect(serio); + up(&serio->drv_sem); + + return retval; +} + +static void serio_disconnect_driver(struct serio *serio) +{ + down(&serio->drv_sem); + if (serio->drv) + serio->drv->disconnect(serio); + up(&serio->drv_sem); +} + static int serio_match_port(const struct serio_device_id *ids, struct serio *serio) { while (ids->type || ids->proto) { @@ -91,7 +122,7 @@ static void serio_bind_driver(struct serio *serio, struct serio_driver *drv) if (serio_match_port(drv->id_table, serio)) { serio->dev.driver = &drv->driver; - if (drv->connect(serio, drv)) { + if (serio_connect_driver(serio, drv)) { serio->dev.driver = NULL; goto out; } @@ -138,8 +169,7 @@ struct serio_event { static DEFINE_SPINLOCK(serio_event_lock); /* protects serio_event_list */ static LIST_HEAD(serio_event_list); static DECLARE_WAIT_QUEUE_HEAD(serio_wait); -static DECLARE_COMPLETION(serio_exited); -static int serio_pid; +static struct task_struct *serio_task; static void serio_queue_event(void *object, struct module *owner, enum serio_event_type event_type) @@ -150,12 +180,12 @@ static void serio_queue_event(void *object, struct module *owner, spin_lock_irqsave(&serio_event_lock, flags); /* - * Scan event list for the other events for the same serio port, + * Scan event list for the other events for the same serio port, * starting with the most recent one. If event is the same we * do not need add new one. If event is of different type we * need to add this event and should not look further because * we need to preseve sequence of distinct events. - */ + */ list_for_each_entry_reverse(event, &serio_event_list, node) { if (event->object == object) { if (event->type == event_type) @@ -337,20 +367,15 @@ static struct serio *serio_get_pending_child(struct serio *parent) static int serio_thread(void *nothing) { - lock_kernel(); - daemonize("kseriod"); - allow_signal(SIGTERM); - do { serio_handle_events(); - wait_event_interruptible(serio_wait, !list_empty(&serio_event_list)); + wait_event_interruptible(serio_wait, + kthread_should_stop() || !list_empty(&serio_event_list)); try_to_freeze(); - } while (!signal_pending(current)); + } while (!kthread_should_stop()); printk(KERN_DEBUG "serio: kseriod exiting\n"); - - unlock_kernel(); - complete_and_exit(&serio_exited, 0); + return 0; } @@ -557,7 +582,7 @@ static void serio_destroy_port(struct serio *serio) static void serio_reconnect_port(struct serio *serio) { do { - if (!serio->drv || !serio->drv->reconnect || serio->drv->reconnect(serio)) { + if (serio_reconnect_driver(serio)) { serio_disconnect_port(serio); serio_find_driver(serio); /* Ok, old children are now gone, we are done */ @@ -630,6 +655,19 @@ void serio_unregister_port(struct serio *serio) } /* + * Safely unregisters child port if one is present. + */ +void serio_unregister_child_port(struct serio *serio) +{ + down(&serio_sem); + if (serio->child) { + serio_disconnect_port(serio->child); + serio_destroy_port(serio->child); + } + up(&serio_sem); +} + +/* * Submits register request to kseriod for subsequent execution. * Can be used when it is not obvious whether the serio_sem is * taken or not and when delayed execution is feasible. @@ -686,15 +724,14 @@ static int serio_driver_probe(struct device *dev) struct serio *serio = to_serio_port(dev); struct serio_driver *drv = to_serio_driver(dev->driver); - return drv->connect(serio, drv); + return serio_connect_driver(serio, drv); } static int serio_driver_remove(struct device *dev) { struct serio *serio = to_serio_port(dev); - struct serio_driver *drv = to_serio_driver(dev->driver); - drv->disconnect(serio); + serio_disconnect_driver(serio); return 0; } @@ -730,11 +767,9 @@ start_over: static void serio_set_drv(struct serio *serio, struct serio_driver *drv) { - down(&serio->drv_sem); serio_pause_rx(serio); serio->drv = drv; serio_continue_rx(serio); - up(&serio->drv_sem); } static int serio_bus_match(struct device *dev, struct device_driver *drv) @@ -794,7 +829,7 @@ static int serio_resume(struct device *dev) { struct serio *serio = to_serio_port(dev); - if (!serio->drv || !serio->drv->reconnect || serio->drv->reconnect(serio)) { + if (serio_reconnect_driver(serio)) { /* * Driver re-probing can take a while, so better let kseriod * deal with it. @@ -848,9 +883,10 @@ irqreturn_t serio_interrupt(struct serio *serio, static int __init serio_init(void) { - if (!(serio_pid = kernel_thread(serio_thread, NULL, CLONE_KERNEL))) { + serio_task = kthread_run(serio_thread, NULL, "kseriod"); + if (IS_ERR(serio_task)) { printk(KERN_ERR "serio: Failed to start kseriod\n"); - return -1; + return PTR_ERR(serio_task); } serio_bus.dev_attrs = serio_device_attrs; @@ -866,8 +902,7 @@ static int __init serio_init(void) static void __exit serio_exit(void) { bus_unregister(&serio_bus); - kill_proc(serio_pid, SIGTERM, 1); - wait_for_completion(&serio_exited); + kthread_stop(serio_task); } module_init(serio_init); diff --git a/drivers/input/touchscreen/elo.c b/drivers/input/touchscreen/elo.c index 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); } |