Merge rsync://rsync.kernel.org/pub/scm/linux/kernel/git/dtor/input.git manually

Some manual fixups required due to clashes with the PF_FREEZE cleanups.
This commit is contained in:
Linus Torvalds 2005-06-27 14:47:31 -07:00
commit 3e0777b8fa
79 changed files with 2783 additions and 1933 deletions

View file

@ -1115,7 +1115,7 @@ running once the system is up.
See Documentation/ramdisk.txt. See Documentation/ramdisk.txt.
psmouse.proto= [HW,MOUSE] Highest PS2 mouse protocol extension to psmouse.proto= [HW,MOUSE] Highest PS2 mouse protocol extension to
probe for (bare|imps|exps). probe for (bare|imps|exps|lifebook|any).
psmouse.rate= [HW,MOUSE] Set desired mouse report rate, in reports psmouse.rate= [HW,MOUSE] Set desired mouse report rate, in reports
per second. per second.
psmouse.resetafter= psmouse.resetafter=

View file

@ -21,6 +21,7 @@
#include <linux/smp_lock.h> #include <linux/smp_lock.h>
#include <linux/device.h> #include <linux/device.h>
#include <linux/devfs_fs_kernel.h> #include <linux/devfs_fs_kernel.h>
#include <linux/compat.h>
struct evdev { struct evdev {
int exist; int exist;
@ -145,6 +146,41 @@ static int evdev_open(struct inode * inode, struct file * file)
return 0; 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) static ssize_t evdev_write(struct file * file, const char __user * buffer, size_t count, loff_t *ppos)
{ {
struct evdev_list *list = file->private_data; struct 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; if (!list->evdev->exist) return -ENODEV;
#ifdef CONFIG_COMPAT
if (COMPAT_TEST)
return evdev_write_compat(file, buffer, count, ppos);
#endif
while (retval < count) { while (retval < count) {
if (copy_from_user(&event, buffer + retval, sizeof(struct input_event))) 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; 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) static ssize_t evdev_read(struct file * file, char __user * buffer, size_t count, loff_t *ppos)
{ {
struct evdev_list *list = file->private_data; struct evdev_list *list = file->private_data;
int retval; int retval;
#ifdef CONFIG_COMPAT
if (COMPAT_TEST)
return evdev_read_compat(file, buffer, count, ppos);
#endif
if (count < sizeof(struct input_event)) if (count < sizeof(struct input_event))
return -EINVAL; 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) { while (list->head != list->tail && retval + sizeof(struct input_event) <= count) {
if (copy_to_user(buffer + retval, list->buffer + list->tail, 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); list->tail = (list->tail + 1) & (EVDEV_BUFFER_SIZE - 1);
retval += sizeof(struct input_event); 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)); (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_list *list = file->private_data;
struct evdev *evdev = list->evdev; struct evdev *evdev = list->evdev;
@ -285,110 +371,268 @@ static int evdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
default: default:
if (_IOC_TYPE(cmd) != 'E' || _IOC_DIR(cmd) != _IOC_READ) if (_IOC_TYPE(cmd) != 'E')
return -EINVAL; return -EINVAL;
if ((_IOC_NR(cmd) & ~EV_MAX) == _IOC_NR(EVIOCGBIT(0,0))) { if (_IOC_DIR(cmd) == _IOC_READ) {
long *bits; if ((_IOC_NR(cmd) & ~EV_MAX) == _IOC_NR(EVIOCGBIT(0,0))) {
int len;
switch (_IOC_NR(cmd) & EV_MAX) { long *bits;
case 0: bits = dev->evbit; len = EV_MAX; break; int len;
case EV_KEY: bits = dev->keybit; len = KEY_MAX; break;
case EV_REL: bits = dev->relbit; len = REL_MAX; break; switch (_IOC_NR(cmd) & EV_MAX) {
case EV_ABS: bits = dev->absbit; len = ABS_MAX; break; case 0: bits = dev->evbit; len = EV_MAX; break;
case EV_MSC: bits = dev->mscbit; len = MSC_MAX; break; case EV_KEY: bits = dev->keybit; len = KEY_MAX; break;
case EV_LED: bits = dev->ledbit; len = LED_MAX; break; case EV_REL: bits = dev->relbit; len = REL_MAX; break;
case EV_SND: bits = dev->sndbit; len = SND_MAX; break; case EV_ABS: bits = dev->absbit; len = ABS_MAX; break;
case EV_FF: bits = dev->ffbit; len = FF_MAX; break; case EV_MSC: bits = dev->mscbit; len = MSC_MAX; break;
default: return -EINVAL; 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); if (_IOC_NR(cmd) == _IOC_NR(EVIOCGKEY(0))) {
return copy_to_user(p, bits, len) ? -EFAULT : len; 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(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(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(EVIOCGKEY(0))) { if (_IOC_DIR(cmd) == _IOC_WRITE) {
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))) { if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCSABS(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 t = _IOC_NR(cmd) & ABS_MAX;
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))) { if (copy_from_user(&abs, p, sizeof(struct input_absinfo)))
int len; return -EFAULT;
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))) { dev->abs[t] = abs.value;
int len; dev->absmin[t] = abs.minimum;
if (!dev->phys) return -ENOENT; dev->absmax[t] = abs.maximum;
len = strlen(dev->phys) + 1; dev->absfuzz[t] = abs.fuzz;
if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd); dev->absflat[t] = abs.flat;
return copy_to_user(p, dev->phys, len) ? -EFAULT : len;
}
if (_IOC_NR(cmd) == _IOC_NR(EVIOCGUNIQ(0))) { return 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))) {
int t = _IOC_NR(cmd) & ABS_MAX;
if (copy_from_user(&abs, p, sizeof(struct input_absinfo)))
return -EFAULT;
dev->abs[t] = abs.value;
dev->absmin[t] = abs.minimum;
dev->absmax[t] = abs.maximum;
dev->absfuzz[t] = abs.fuzz;
dev->absflat[t] = abs.flat;
return 0;
} }
} }
return -EINVAL; return -EINVAL;
} }
#ifdef CONFIG_COMPAT
#define BITS_PER_LONG_COMPAT (sizeof(compat_long_t) * 8)
#define NBITS_COMPAT(x) ((((x)-1)/BITS_PER_LONG_COMPAT)+1)
#define OFF_COMPAT(x) ((x)%BITS_PER_LONG_COMPAT)
#define BIT_COMPAT(x) (1UL<<OFF_COMPAT(x))
#define LONG_COMPAT(x) ((x)/BITS_PER_LONG_COMPAT)
#define test_bit_compat(bit, array) ((array[LONG_COMPAT(bit)] >> OFF_COMPAT(bit)) & 1)
#ifdef __BIG_ENDIAN
#define bit_to_user(bit, max) \
do { \
int i; \
int len = NBITS_COMPAT((max)) * sizeof(compat_long_t); \
if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd); \
for (i = 0; i < len / sizeof(compat_long_t); i++) \
if (copy_to_user((compat_long_t*) 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);
if (!evdev->exist) return -ENODEV;
switch (cmd) {
case EVIOCGVERSION:
case EVIOCGID:
case EVIOCGKEYCODE:
case EVIOCSKEYCODE:
case EVIOCSFF:
case EVIOCRMFF:
case EVIOCGEFFECTS:
case EVIOCGRAB:
return evdev_ioctl(file, cmd, (unsigned long) p);
default:
if (_IOC_TYPE(cmd) != 'E')
return -EINVAL;
if (_IOC_DIR(cmd) == _IOC_READ) {
if ((_IOC_NR(cmd) & ~EV_MAX) == _IOC_NR(EVIOCGBIT(0,0))) {
long *bits;
int max;
switch (_IOC_NR(cmd) & EV_MAX) {
case 0: bits = dev->evbit; max = EV_MAX; break;
case EV_KEY: bits = dev->keybit; max = KEY_MAX; break;
case EV_REL: bits = dev->relbit; max = REL_MAX; break;
case EV_ABS: bits = dev->absbit; max = ABS_MAX; break;
case EV_MSC: bits = dev->mscbit; max = MSC_MAX; break;
case EV_LED: bits = dev->ledbit; max = LED_MAX; break;
case EV_SND: bits = dev->sndbit; max = SND_MAX; break;
case EV_FF: bits = dev->ffbit; max = FF_MAX; break;
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_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;
}
#endif
static struct file_operations evdev_fops = { static struct file_operations evdev_fops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.read = evdev_read, .read = evdev_read,
@ -396,7 +640,10 @@ static struct file_operations evdev_fops = {
.poll = evdev_poll, .poll = evdev_poll,
.open = evdev_open, .open = evdev_open,
.release = evdev_release, .release = evdev_release,
.ioctl = evdev_ioctl, .unlocked_ioctl = evdev_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl = evdev_ioctl_compat,
#endif
.fasync = evdev_fasync, .fasync = evdev_fasync,
.flush = evdev_flush .flush = evdev_flush
}; };

View file

@ -49,22 +49,8 @@ config GAMEPORT_EMU10K1
To compile this driver as a module, choose M here: the To compile this driver as a module, choose M here: the
module will be called emu10k1-gp. 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 config GAMEPORT_FM801
tristate "ForteMedia FM801 gameport support" tristate "ForteMedia FM801 gameport support"
depends on PCI depends on PCI
config GAMEPORT_CS461X
tristate "Crystal SoundFusion gameport support"
depends on PCI
endif endif

View file

@ -5,9 +5,7 @@
# Each configuration option enables a list of files. # Each configuration option enables a list of files.
obj-$(CONFIG_GAMEPORT) += gameport.o obj-$(CONFIG_GAMEPORT) += gameport.o
obj-$(CONFIG_GAMEPORT_CS461X) += cs461x.o
obj-$(CONFIG_GAMEPORT_EMU10K1) += emu10k1-gp.o obj-$(CONFIG_GAMEPORT_EMU10K1) += emu10k1-gp.o
obj-$(CONFIG_GAMEPORT_FM801) += fm801-gp.o obj-$(CONFIG_GAMEPORT_FM801) += fm801-gp.o
obj-$(CONFIG_GAMEPORT_L4) += lightning.o obj-$(CONFIG_GAMEPORT_L4) += lightning.o
obj-$(CONFIG_GAMEPORT_NS558) += ns558.o obj-$(CONFIG_GAMEPORT_NS558) += ns558.o
obj-$(CONFIG_GAMEPORT_VORTEX) += vortex.o

View file

@ -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);

View file

@ -258,18 +258,18 @@ static int __init ns558_init(void)
{ {
int i = 0; 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 * Probe ISA ports after PnP, so that PnP ports that are already
* not occupied by the ISA ports. * enabled get detected as PnP. This may be suboptimal in multi-device
* configurations, but saves hassle with simple setups.
*/ */
while (ns558_isa_portlist[i]) while (ns558_isa_portlist[i])
ns558_isa_probe(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; return (list_empty(&ns558_list) && !pnp_registered) ? -ENODEV : 0;
} }

View file

@ -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);

View file

@ -219,10 +219,24 @@ void input_release_device(struct input_handle *handle)
int input_open_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++; handle->open++;
if (handle->dev->open)
return handle->dev->open(handle->dev); if (!dev->users++ && dev->open)
return 0; err = dev->open(dev);
if (err)
handle->open--;
up(&dev->sem);
return err;
} }
int input_flush_device(struct input_handle* handle, struct file* file) 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) void input_close_device(struct input_handle *handle)
{ {
struct input_dev *dev = handle->dev;
input_release_device(handle); 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--; handle->open--;
up(&dev->sem);
} }
static void input_link_handle(struct input_handle *handle) 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); set_bit(EV_SYN, dev->evbit);
init_MUTEX(&dev->sem);
/* /*
* If delay and period are pre-set by the driver, then autorepeating * 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. * 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; return (count > cnt) ? cnt : count;
} }
static struct file_operations input_fileops;
static int __init input_proc_init(void) static int __init input_proc_init(void)
{ {
struct proc_dir_entry *entry; struct proc_dir_entry *entry;
@ -688,6 +713,8 @@ static int __init input_proc_init(void)
return -ENOMEM; return -ENOMEM;
} }
entry->owner = THIS_MODULE; entry->owner = THIS_MODULE;
input_fileops = *entry->proc_fops;
entry->proc_fops = &input_fileops;
entry->proc_fops->poll = input_devices_poll; entry->proc_fops->poll = input_devices_poll;
entry = create_proc_read_entry("handlers", 0, proc_bus_input_dir, input_handlers_read, NULL); entry = create_proc_read_entry("handlers", 0, proc_bus_input_dir, input_handlers_read, NULL);
if (entry == NULL) { if (entry == NULL) {

View file

@ -285,48 +285,33 @@ static unsigned int joydev_poll(struct file *file, poll_table *wait)
(POLLIN | POLLRDNORM) : 0) | (list->joydev->exist ? 0 : (POLLHUP | POLLERR)); (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; struct input_dev *dev = joydev->handle.dev;
void __user *argp = (void __user *)arg;
int i, j; int i, j;
if (!joydev->exist) return -ENODEV;
switch (cmd) { switch (cmd) {
case JS_SET_CAL: case JS_SET_CAL:
return copy_from_user(&joydev->glue.JS_CORR, argp, 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: case JS_GET_CAL:
return copy_to_user(argp, &joydev->glue.JS_CORR, 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: 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: case JS_GET_TIMEOUT:
return put_user(joydev->glue.JS_TIMEOUT, (int __user *) arg); return put_user(joydev->glue.JS_TIMEOUT, (s32 __user *) argp);
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;
case JSIOCGVERSION: case JSIOCGVERSION:
return put_user(JS_VERSION, (__u32 __user *) arg); return put_user(JS_VERSION, (__u32 __user *) argp);
case JSIOCGAXES: case JSIOCGAXES:
return put_user(joydev->nabs, (__u8 __user *) arg); return put_user(joydev->nabs, (__u8 __user *) argp);
case JSIOCGBUTTONS: case JSIOCGBUTTONS:
return put_user(joydev->nkey, (__u8 __user *) arg); return put_user(joydev->nkey, (__u8 __user *) argp);
case JSIOCSCORR: case JSIOCSCORR:
if (copy_from_user(joydev->corr, argp, if (copy_from_user(joydev->corr, argp,
sizeof(struct js_corr) * joydev->nabs)) sizeof(joydev->corr[0]) * joydev->nabs))
return -EFAULT; return -EFAULT;
for (i = 0; i < joydev->nabs; i++) { for (i = 0; i < joydev->nabs; i++) {
j = joydev->abspam[i]; j = joydev->abspam[i];
@ -335,7 +320,7 @@ static int joydev_ioctl(struct inode *inode, struct file *file, unsigned int cmd
return 0; return 0;
case JSIOCGCORR: case JSIOCGCORR:
return copy_to_user(argp, joydev->corr, 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: case JSIOCSAXMAP:
if (copy_from_user(joydev->abspam, argp, sizeof(__u8) * (ABS_MAX + 1))) if (copy_from_user(joydev->abspam, argp, sizeof(__u8) * (ABS_MAX + 1)))
return -EFAULT; return -EFAULT;
@ -371,6 +356,84 @@ static int joydev_ioctl(struct inode *inode, struct file *file, unsigned int cmd
return -EINVAL; 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 = { static struct file_operations joydev_fops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.read = joydev_read, .read = joydev_read,
@ -379,6 +442,9 @@ static struct file_operations joydev_fops = {
.open = joydev_open, .open = joydev_open,
.release = joydev_release, .release = joydev_release,
.ioctl = joydev_ioctl, .ioctl = joydev_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl = joydev_compat_ioctl,
#endif
.fasync = joydev_fasync, .fasync = joydev_fasync,
}; };

View file

@ -185,7 +185,7 @@ static void a3d_poll(struct gameport *gameport)
a3d->reads++; a3d->reads++;
if (a3d_read_packet(a3d->gameport, a3d->length, data) != a3d->length || if (a3d_read_packet(a3d->gameport, a3d->length, data) != a3d->length ||
data[0] != a3d->mode || a3d_csum(data, a3d->length)) data[0] != a3d->mode || a3d_csum(data, a3d->length))
a3d->bads++; a3d->bads++;
else else
a3d_read(a3d, data); a3d_read(a3d, data);
} }

View file

@ -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 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_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_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 }; 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; int i;
struct adi *adi = port->adi; 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].ret <= 0 || adi[1].ret <= 0) return;
if (adi[0].data[0] & 0x20 || ~adi[1].data[0] & 0x20) return; if (adi[0].data[0] & 0x20 || ~adi[1].data[0] & 0x20) return;

View file

@ -51,7 +51,8 @@ MODULE_PARM_DESC(map, "Map of attached joysticks in form of <a>,<b> (default is
__obsolete_setup("amijoy="); __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 struct input_dev amijoy_dev[2];
static char *amijoy_phys[2] = { "amijoy/input0", "amijoy/input1" }; 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) static int amijoy_open(struct input_dev *dev)
{ {
int *used = dev->private; int err;
if ((*used)++) err = down_interruptible(&amijoy_sem);
return 0; if (err)
return err;
if (request_irq(IRQ_AMIGA_VERTB, amijoy_interrupt, 0, "amijoy", amijoy_interrupt)) { if (!amijoy_used && request_irq(IRQ_AMIGA_VERTB, amijoy_interrupt, 0, "amijoy", amijoy_interrupt)) {
(*used)--;
printk(KERN_ERR "amijoy.c: Can't allocate irq %d\n", IRQ_AMIGA_VERTB); 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) static void amijoy_close(struct input_dev *dev)
{ {
int *used = dev->private; down(&amijoysem);
if (!--amijoy_used)
if (!--(*used))
free_irq(IRQ_AMIGA_VERTB, amijoy_interrupt); free_irq(IRQ_AMIGA_VERTB, amijoy_interrupt);
up(&amijoy_sem);
} }
static int __init amijoy_init(void) 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.product = 0x0003;
amijoy_dev[i].id.version = 0x0100; amijoy_dev[i].id.version = 0x0100;
amijoy_dev[i].private = amijoy_used + i;
input_register_device(amijoy_dev + i); input_register_device(amijoy_dev + i);
printk(KERN_INFO "input: %s at joy%ddat\n", amijoy_name, i); printk(KERN_INFO "input: %s at joy%ddat\n", amijoy_name, i);
} }

View file

@ -87,7 +87,7 @@ __obsolete_setup("db9_3=");
#define DB9_NORMAL 0x0a #define DB9_NORMAL 0x0a
#define DB9_NOSELECT 0x08 #define DB9_NOSELECT 0x08
#define DB9_MAX_DEVICES 2 #define DB9_MAX_DEVICES 2
#define DB9_GENESIS6_DELAY 14 #define DB9_GENESIS6_DELAY 14
#define DB9_REFRESH_TIME HZ/100 #define DB9_REFRESH_TIME HZ/100
@ -98,6 +98,7 @@ struct db9 {
struct pardevice *pd; struct pardevice *pd;
int mode; int mode;
int used; int used;
struct semaphore sem;
char phys[2][32]; char phys[2][32];
}; };
@ -503,6 +504,11 @@ static int db9_open(struct input_dev *dev)
{ {
struct db9 *db9 = dev->private; struct db9 *db9 = dev->private;
struct parport *port = db9->pd->port; struct parport *port = db9->pd->port;
int err;
err = down_interruptible(&db9->sem);
if (err)
return err;
if (!db9->used++) { if (!db9->used++) {
parport_claim(db9->pd); parport_claim(db9->pd);
@ -514,6 +520,7 @@ static int db9_open(struct input_dev *dev)
mod_timer(&db9->timer, jiffies + DB9_REFRESH_TIME); mod_timer(&db9->timer, jiffies + DB9_REFRESH_TIME);
} }
up(&db9->sem);
return 0; return 0;
} }
@ -522,12 +529,14 @@ static void db9_close(struct input_dev *dev)
struct db9 *db9 = dev->private; struct db9 *db9 = dev->private;
struct parport *port = db9->pd->port; struct parport *port = db9->pd->port;
down(&db9->sem);
if (!--db9->used) { if (!--db9->used) {
del_timer(&db9->timer); del_timer_sync(&db9->timer);
parport_write_control(port, 0x00); parport_write_control(port, 0x00);
parport_data_forward(port); parport_data_forward(port);
parport_release(db9->pd); parport_release(db9->pd);
} }
up(&db9->sem);
} }
static struct db9 __init *db9_probe(int *config, int nargs) 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); parport_put_port(pp);
return NULL; return NULL;
} }
memset(db9, 0, sizeof(struct db9));
init_MUTEX(&db9->sem);
db9->mode = config[1]; db9->mode = config[1];
init_timer(&db9->timer); init_timer(&db9->timer);
db9->timer.data = (long) db9; db9->timer.data = (long) db9;

View file

@ -1,12 +1,12 @@
/* /*
* NES, SNES, N64, MultiSystem, PSX gamepad driver for Linux * NES, SNES, N64, MultiSystem, PSX gamepad driver for Linux
* *
* Copyright (c) 1999-2004 Vojtech Pavlik <vojtech@suse.cz> * Copyright (c) 1999-2004 Vojtech Pavlik <vojtech@suse.cz>
* Copyright (c) 2004 Peter Nelson <rufus-kernel@hackish.org> * Copyright (c) 2004 Peter Nelson <rufus-kernel@hackish.org>
* *
* Based on the work of: * Based on the work of:
* Andree Borrmann John Dahlstrom * Andree Borrmann John Dahlstrom
* David Kuder Nathan Hand * David Kuder Nathan Hand
*/ */
/* /*
@ -81,6 +81,7 @@ struct gc {
struct timer_list timer; struct timer_list timer;
unsigned char pads[GC_MAX + 1]; unsigned char pads[GC_MAX + 1];
int used; int used;
struct semaphore sem;
char phys[5][32]; char phys[5][32];
}; };
@ -433,7 +434,7 @@ static void gc_timer(unsigned long private)
gc_psx_read_packet(gc, data_psx, data); gc_psx_read_packet(gc, data_psx, data);
for (i = 0; i < 5; i++) { for (i = 0; i < 5; i++) {
switch (data[i]) { switch (data[i]) {
case GC_PSX_RUMBLE: case GC_PSX_RUMBLE:
@ -503,22 +504,33 @@ static void gc_timer(unsigned long private)
static int gc_open(struct input_dev *dev) static int gc_open(struct input_dev *dev)
{ {
struct gc *gc = dev->private; struct gc *gc = dev->private;
int err;
err = down_interruptible(&gc->sem);
if (err)
return err;
if (!gc->used++) { if (!gc->used++) {
parport_claim(gc->pd); parport_claim(gc->pd);
parport_write_control(gc->pd->port, 0x04); parport_write_control(gc->pd->port, 0x04);
mod_timer(&gc->timer, jiffies + GC_REFRESH_TIME); mod_timer(&gc->timer, jiffies + GC_REFRESH_TIME);
} }
up(&gc->sem);
return 0; return 0;
} }
static void gc_close(struct input_dev *dev) static void gc_close(struct input_dev *dev)
{ {
struct gc *gc = dev->private; struct gc *gc = dev->private;
down(&gc->sem);
if (!--gc->used) { if (!--gc->used) {
del_timer(&gc->timer); del_timer_sync(&gc->timer);
parport_write_control(gc->pd->port, 0x00); parport_write_control(gc->pd->port, 0x00);
parport_release(gc->pd); parport_release(gc->pd);
} }
up(&gc->sem);
} }
static struct gc __init *gc_probe(int *config, int nargs) 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; return NULL;
} }
if (!(gc = kmalloc(sizeof(struct gc), GFP_KERNEL))) { if (!(gc = kcalloc(1, sizeof(struct gc), GFP_KERNEL))) {
parport_put_port(pp); parport_put_port(pp);
return NULL; 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); gc->pd = parport_register_device(pp, "gamecon", NULL, NULL, NULL, PARPORT_DEV_EXCL, NULL);

View file

@ -329,7 +329,7 @@ static int gf2k_connect(struct gameport *gameport, struct gameport_driver *drv)
for (i = 0; i < gf2k_axes[gf2k->id]; i++) { 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.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.absmin[gf2k_abs[i]] = 32;
gf2k->dev.absfuzz[gf2k_abs[i]] = 8; gf2k->dev.absfuzz[gf2k_abs[i]] = 8;
gf2k->dev.absflat[gf2k_abs[i]] = (i < 2) ? 24 : 0; gf2k->dev.absflat[gf2k_abs[i]] = (i < 2) ? 24 : 0;

View file

@ -171,7 +171,7 @@ static int mp_io(struct gameport* gameport, int sendflags, int sendcode, u32 *pa
*packet = 0; *packet = 0;
raw_data = gameport_read(gameport); raw_data = gameport_read(gameport);
if (raw_data & 1) if (raw_data & 1)
return IO_RETRY; return IO_RETRY;
for (i = 0; i < 64; i++) { for (i = 0; i < 64; i++) {
raw_data = gameport_read(gameport); raw_data = gameport_read(gameport);

View file

@ -78,6 +78,7 @@ static struct iforce_device iforce_device[] = {
{ 0x061c, 0xc0a4, "ACT LABS Force RS", btn_wheel, abs_wheel, ff_iforce }, //? { 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, 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, "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 } { 0x0000, 0x0000, "Unknown I-Force Device [%04x:%04x]", btn_joystick, abs_joystick, ff_iforce }
}; };

View file

@ -229,6 +229,7 @@ static struct usb_device_id iforce_usb_ids [] = {
{ USB_DEVICE(0x061c, 0xc0a4) }, /* ACT LABS Force RS */ { USB_DEVICE(0x061c, 0xc0a4) }, /* ACT LABS Force RS */
{ USB_DEVICE(0x06f8, 0x0001) }, /* Guillemot Race Leader Force Feedback */ { USB_DEVICE(0x06f8, 0x0001) }, /* Guillemot Race Leader Force Feedback */
{ USB_DEVICE(0x06f8, 0x0004) }, /* Guillemot Force Feedback Racing Wheel */ { USB_DEVICE(0x06f8, 0x0004) }, /* Guillemot Force Feedback Racing Wheel */
{ USB_DEVICE(0x06f8, 0xa302) }, /* Guillemot Jet Leader 3D */
{ } /* Terminating entry */ { } /* Terminating entry */
}; };

View file

@ -4,8 +4,8 @@
* Copyright (c) 1999-2001 Vojtech Pavlik * Copyright (c) 1999-2001 Vojtech Pavlik
* *
* Based on the work of: * Based on the work of:
* David Thompson * David Thompson
* Joseph Krahn * Joseph Krahn
*/ */
/* /*

View file

@ -4,7 +4,7 @@
* Copyright (c) 1999-2001 Vojtech Pavlik * Copyright (c) 1999-2001 Vojtech Pavlik
* *
* Based on the work of: * Based on the work of:
* David Thompson * David Thompson
*/ */
/* /*

View file

@ -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 }; { 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] = static short tmdc_btn_joy[TMDC_BTN] =
{ BTN_TRIGGER, BTN_THUMB, BTN_TOP, BTN_TOP2, BTN_BASE, BTN_BASE2, BTN_THUMB2, BTN_PINKIE, { 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] = 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 }; { 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] = static short tmdc_btn_at[TMDC_BTN] =

View file

@ -84,6 +84,7 @@ static struct tgfx {
char phys[7][32]; char phys[7][32];
int sticks; int sticks;
int used; int used;
struct semaphore sem;
} *tgfx_base[3]; } *tgfx_base[3];
/* /*
@ -99,7 +100,7 @@ static void tgfx_timer(unsigned long private)
for (i = 0; i < 7; i++) for (i = 0; i < 7; i++)
if (tgfx->sticks & (1 << i)) { if (tgfx->sticks & (1 << i)) {
dev = tgfx->dev + i; dev = tgfx->dev + i;
parport_write_data(tgfx->pd->port, ~(1 << i)); parport_write_data(tgfx->pd->port, ~(1 << i));
data1 = parport_read_status(tgfx->pd->port) ^ 0x7f; 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) static int tgfx_open(struct input_dev *dev)
{ {
struct tgfx *tgfx = dev->private; struct tgfx *tgfx = dev->private;
if (!tgfx->used++) { int err;
err = down_interruptible(&tgfx->sem);
if (err)
return err;
if (!tgfx->used++) {
parport_claim(tgfx->pd); parport_claim(tgfx->pd);
parport_write_control(tgfx->pd->port, 0x04); 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) static void tgfx_close(struct input_dev *dev)
{ {
struct tgfx *tgfx = dev->private; struct tgfx *tgfx = dev->private;
if (!--tgfx->used) {
del_timer(&tgfx->timer); down(&tgfx->sem);
if (!--tgfx->used) {
del_timer_sync(&tgfx->timer);
parport_write_control(tgfx->pd->port, 0x00); 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; return NULL;
} }
if (!(tgfx = kmalloc(sizeof(struct tgfx), GFP_KERNEL))) { if (!(tgfx = kcalloc(1, sizeof(struct tgfx), GFP_KERNEL))) {
parport_put_port(pp); parport_put_port(pp);
return NULL; 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); tgfx->pd = parport_register_device(pp, "turbografx", NULL, NULL, NULL, PARPORT_DEV_EXCL, NULL);

View file

@ -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); \ 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); __ATTR(_name, S_IWUSR | S_IRUGO, atkbd_do_show_##_name, atkbd_do_set_##_name);
ATKBD_DEFINE_ATTR(extra); ATKBD_DEFINE_ATTR(extra);
@ -388,7 +388,7 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data,
value = atkbd->release ? 0 : value = atkbd->release ? 0 :
(1 + (!atkbd->softrepeat && test_bit(atkbd->keycode[code], atkbd->dev.key))); (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: case 0:
atkbd->last = 0; atkbd->last = 0;
break; break;
@ -894,7 +894,7 @@ static int atkbd_reconnect(struct serio *serio)
if (atkbd->write) { if (atkbd->write) {
param[0] = (test_bit(LED_SCROLLL, atkbd->dev.led) ? 1 : 0) param[0] = (test_bit(LED_SCROLLL, atkbd->dev.led) ? 1 : 0)
| (test_bit(LED_NUML, atkbd->dev.led) ? 2 : 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)) if (atkbd_probe(atkbd))
return -1; return -1;

View file

@ -39,6 +39,7 @@
#define CORGI_KEY_CALENDER KEY_F1 #define CORGI_KEY_CALENDER KEY_F1
#define CORGI_KEY_ADDRESS KEY_F2 #define CORGI_KEY_ADDRESS KEY_F2
#define CORGI_KEY_FN KEY_F3 #define CORGI_KEY_FN KEY_F3
#define CORGI_KEY_CANCEL KEY_F4
#define CORGI_KEY_OFF KEY_SUSPEND #define CORGI_KEY_OFF KEY_SUSPEND
#define CORGI_KEY_EXOK KEY_F5 #define CORGI_KEY_EXOK KEY_F5
#define CORGI_KEY_EXCANCEL KEY_F6 #define CORGI_KEY_EXCANCEL KEY_F6
@ -46,6 +47,7 @@
#define CORGI_KEY_EXJOGUP KEY_F8 #define CORGI_KEY_EXJOGUP KEY_F8
#define CORGI_KEY_JAP1 KEY_LEFTCTRL #define CORGI_KEY_JAP1 KEY_LEFTCTRL
#define CORGI_KEY_JAP2 KEY_LEFTALT #define CORGI_KEY_JAP2 KEY_LEFTALT
#define CORGI_KEY_MAIL KEY_F10
#define CORGI_KEY_OK KEY_F11 #define CORGI_KEY_OK KEY_F11
#define CORGI_KEY_MENU KEY_F12 #define CORGI_KEY_MENU KEY_F12
#define CORGI_HINGE_0 KEY_KP0 #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 */ 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_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 */ 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 */ 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, KEY_CANCEL, CORGI_KEY_OK, CORGI_KEY_MENU, KEY_LEFT, KEY_DOWN, KEY_RIGHT, 0, 0, 0, 0, 0, 0, 0, /* 97-112 */ 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_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 */ CORGI_HINGE_0, CORGI_HINGE_1, CORGI_HINGE_2 /* 125-127 */
}; };

View file

@ -15,10 +15,10 @@
* information given below, I will _not_ be liable! * information given below, I will _not_ be liable!
* *
* RJ10 pinout: To DE9: Or DB25: * RJ10 pinout: To DE9: Or DB25:
* 1 - RxD <----> Pin 3 (TxD) <-> Pin 2 (TxD) * 1 - RxD <----> Pin 3 (TxD) <-> Pin 2 (TxD)
* 2 - GND <----> Pin 5 (GND) <-> Pin 7 (GND) * 2 - GND <----> Pin 5 (GND) <-> Pin 7 (GND)
* 4 - TxD <----> Pin 2 (RxD) <-> Pin 3 (RxD) * 4 - TxD <----> Pin 2 (RxD) <-> Pin 3 (RxD)
* 3 - +12V (from HDD drive connector), DON'T connect to DE9 or DB25!!! * 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 * Pin numbers for DE9 and DB25 are noted on the plug (quite small:). For
* RJ10, it's like this: * RJ10, it's like this:

View file

@ -42,7 +42,7 @@ MODULE_AUTHOR("John Lenz <lenz@cs.wisc.edu>");
MODULE_DESCRIPTION("LoCoMo keyboard driver"); MODULE_DESCRIPTION("LoCoMo keyboard driver");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
#define LOCOMOKBD_NUMKEYS 128 #define LOCOMOKBD_NUMKEYS 128
#define KEY_ACTIVITY KEY_F16 #define KEY_ACTIVITY KEY_F16
#define KEY_CONTACT KEY_F18 #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 */ 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 */ 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_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 #define KB_ROWS 16
@ -82,7 +82,7 @@ struct locomokbd {
struct locomo_dev *ldev; struct locomo_dev *ldev;
unsigned long base; unsigned long base;
spinlock_t lock; spinlock_t lock;
struct timer_list timer; 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) static inline void locomokbd_activate_all(unsigned long membase)
{ {
unsigned long r; unsigned long r;
locomo_writel(0, membase + LOCOMO_KSC); locomo_writel(0, membase + LOCOMO_KSC);
r = locomo_readl(membase + LOCOMO_KIC); r = locomo_readl(membase + LOCOMO_KIC);
r &= 0xFEFF; 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 */ /* 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 int row, col, rowd, scancode;
unsigned long flags; unsigned long flags;
@ -138,7 +138,7 @@ static void locomokbd_scankeyboard(struct locomokbd *locomokbd, struct pt_regs *
if (regs) if (regs)
input_regs(&locomokbd->input, regs); input_regs(&locomokbd->input, regs);
locomokbd_charge_all(membase); locomokbd_charge_all(membase);
num_pressed = 0; num_pressed = 0;
@ -146,9 +146,9 @@ static void locomokbd_scankeyboard(struct locomokbd *locomokbd, struct pt_regs *
locomokbd_activate_col(membase, col); locomokbd_activate_col(membase, col);
udelay(KB_DELAY); udelay(KB_DELAY);
rowd = ~locomo_readl(membase + LOCOMO_KIB); rowd = ~locomo_readl(membase + LOCOMO_KIB);
for (row = 0; row < KB_ROWS; row++ ) { for (row = 0; row < KB_ROWS; row++) {
scancode = SCANCODE(col, row); scancode = SCANCODE(col, row);
if (rowd & KB_ROWMASK(row)) { if (rowd & KB_ROWMASK(row)) {
num_pressed += 1; num_pressed += 1;
@ -170,7 +170,7 @@ static void locomokbd_scankeyboard(struct locomokbd *locomokbd, struct pt_regs *
spin_unlock_irqrestore(&locomokbd->lock, flags); spin_unlock_irqrestore(&locomokbd->lock, flags);
} }
/* /*
* LoCoMo keyboard interrupt handler. * LoCoMo keyboard interrupt handler.
*/ */
static irqreturn_t locomokbd_interrupt(int irq, void *dev_id, struct pt_regs *regs) 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)); memset(locomokbd, 0, sizeof(struct locomokbd));
/* try and claim memory region */ /* try and claim memory region */
if (!request_mem_region((unsigned long) dev->mapbase, if (!request_mem_region((unsigned long) dev->mapbase,
dev->length, dev->length,
LOCOMO_DRIVER_NAME(dev))) { LOCOMO_DRIVER_NAME(dev))) {
ret = -EBUSY; ret = -EBUSY;
printk(KERN_ERR "locomokbd: Can't acquire access to io memory for keyboard\n"); 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->timer.data = (unsigned long) locomokbd;
locomokbd->input.evbit[0] = BIT(EV_KEY) | BIT(EV_REP); locomokbd->input.evbit[0] = BIT(EV_KEY) | BIT(EV_REP);
init_input_dev(&locomokbd->input); init_input_dev(&locomokbd->input);
locomokbd->input.keycode = locomokbd->keycode; locomokbd->input.keycode = locomokbd->keycode;
locomokbd->input.keycodesize = sizeof(unsigned char); locomokbd->input.keycodesize = sizeof(unsigned char);
@ -271,11 +271,11 @@ free:
static int locomokbd_remove(struct locomo_dev *dev) static int locomokbd_remove(struct locomo_dev *dev)
{ {
struct locomokbd *locomokbd = locomo_get_drvdata(dev); struct locomokbd *locomokbd = locomo_get_drvdata(dev);
free_irq(dev->irq[0], locomokbd); free_irq(dev->irq[0], locomokbd);
del_timer_sync(&locomokbd->timer); del_timer_sync(&locomokbd->timer);
input_unregister_device(&locomokbd->input); input_unregister_device(&locomokbd->input);
locomo_set_drvdata(dev, NULL); locomo_set_drvdata(dev, NULL);

View file

@ -1,6 +1,6 @@
/* /*
* $Id: maple_keyb.c,v 1.4 2004/03/22 01:18:15 lethal Exp $ * $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 * Based on drivers/usb/usbkbd.c
*/ */
@ -40,7 +40,6 @@ struct dc_kbd {
struct input_dev dev; struct input_dev dev;
unsigned char new[8]; unsigned char new[8];
unsigned char old[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) static int dc_kbd_connect(struct maple_device *dev)
{ {
int i; int i;
@ -133,9 +116,6 @@ static int dc_kbd_connect(struct maple_device *dev)
clear_bit(0, kbd->dev.keybit); clear_bit(0, kbd->dev.keybit);
kbd->dev.private = kbd; 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.name = dev->product_name;
kbd->dev.id.bustype = BUS_MAPLE; kbd->dev.id.bustype = BUS_MAPLE;

View file

@ -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 /* check if absmin/absmax/absfuzz/absflat are filled as
* told in Documentation/input/input-programming.txt */ * told in Documentation/input/input-programming.txt */
if (test_bit(EV_ABS, dev->evbit)) { if (test_bit(EV_ABS, dev->evbit)) {
retval = uinput_validate_absbits(dev); int err = uinput_validate_absbits(dev);
if (retval < 0) if (err < 0) {
retval = err;
kfree(dev->name); kfree(dev->name);
}
} }
exit: exit:

View file

@ -15,4 +15,4 @@ obj-$(CONFIG_MOUSE_SERIAL) += sermouse.o
obj-$(CONFIG_MOUSE_HIL) += hil_ptr.o obj-$(CONFIG_MOUSE_HIL) += hil_ptr.o
obj-$(CONFIG_MOUSE_VSXXXAA) += vsxxxaa.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

View file

@ -30,10 +30,11 @@
#define ALPS_DUALPOINT 0x01 #define ALPS_DUALPOINT 0x01
#define ALPS_WHEEL 0x02 #define ALPS_WHEEL 0x02
#define ALPS_FW_BK 0x04 #define ALPS_FW_BK_1 0x04
#define ALPS_4BTN 0x08 #define ALPS_4BTN 0x08
#define ALPS_OLDPROTO 0x10 #define ALPS_OLDPROTO 0x10
#define ALPS_PASS 0x20 #define ALPS_PASS 0x20
#define ALPS_FW_BK_2 0x40
static struct alps_model_info alps_model_data[] = { static struct alps_model_info alps_model_data[] = {
{ { 0x33, 0x02, 0x0a }, 0x88, 0xf8, ALPS_OLDPROTO }, /* UMAX-530T */ { { 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, 0x14 }, 0xf8, 0xf8, 0 },
{ { 0x63, 0x02, 0x28 }, 0xf8, 0xf8, 0 }, { { 0x63, 0x02, 0x28 }, 0xf8, 0xf8, 0 },
{ { 0x63, 0x02, 0x3c }, 0x8f, 0x8f, ALPS_WHEEL }, /* Toshiba Satellite S2400-103 */ { { 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, 0x02, 0x64 }, 0xf8, 0xf8, 0 },
{ { 0x63, 0x03, 0xc8 }, 0xf8, 0xf8, ALPS_PASS }, /* Dell Latitude D800 */ { { 0x63, 0x03, 0xc8 }, 0xf8, 0xf8, ALPS_PASS }, /* Dell Latitude D800 */
{ { 0x73, 0x02, 0x0a }, 0xf8, 0xf8, 0 }, { { 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 */ { { 0x20, 0x02, 0x0e }, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, /* XXX */
{ { 0x22, 0x02, 0x0a }, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, { { 0x22, 0x02, 0x0a }, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT },
{ { 0x22, 0x02, 0x14 }, 0xff, 0xff, ALPS_PASS | ALPS_DUALPOINT }, /* Dell Latitude D600 */ { { 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 * ALPS abolute Mode - new format
* *
* byte 0: 1 ? ? ? 1 ? ? ? * byte 0: 1 ? ? ? 1 ? ? ?
* byte 1: 0 x6 x5 x4 x3 x2 x1 x0 * byte 1: 0 x6 x5 x4 x3 x2 x1 x0
* byte 2: 0 x10 x9 x8 x7 ? fin ges * 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 4: 0 y6 y5 y4 y3 y2 y1 y0
* byte 5: 0 z6 z5 z4 z3 z2 z1 z0 * 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 *dev = &psmouse->dev;
struct input_dev *dev2 = &priv->dev2; struct input_dev *dev2 = &priv->dev2;
int x, y, z, ges, fin, left, right, middle; int x, y, z, ges, fin, left, right, middle;
int back = 0, forward = 0;
input_regs(dev, regs); input_regs(dev, regs);
if ((packet[0] & 0xc8) == 0x08) { /* 3-byte PS/2 packet */ 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_RIGHT, packet[0] & 2);
input_report_key(dev2, BTN_MIDDLE, packet[0] & 4); input_report_key(dev2, BTN_MIDDLE, packet[0] & 4);
input_report_rel(dev2, REL_X, 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]; 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; ges = packet[2] & 1;
fin = packet[2] & 2; 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_abs(dev, ABS_PRESSURE, z);
input_report_key(dev, BTN_TOOL_FINGER, z > 0); input_report_key(dev, BTN_TOOL_FINGER, z > 0);
if (priv->i->flags & ALPS_WHEEL) if (priv->i->flags & ALPS_WHEEL)
input_report_rel(dev, REL_WHEEL, ((packet[0] >> 4) & 0x07) | ((packet[2] >> 2) & 0x08)); input_report_rel(dev, REL_WHEEL, ((packet[0] >> 4) & 0x07) | ((packet[2] >> 2) & 0x08));
if (priv->i->flags & ALPS_FW_BK) { if (priv->i->flags & (ALPS_FW_BK_1 | ALPS_FW_BK_2)) {
input_report_key(dev, BTN_FORWARD, packet[0] & 0x10); input_report_key(dev, BTN_FORWARD, forward);
input_report_key(dev, BTN_BACK, packet[2] & 0x04); input_report_key(dev, BTN_BACK, back);
} }
input_sync(dev); 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) static int alps_passthrough_mode(struct psmouse *psmouse, int enable)
{ {
struct ps2dev *ps2dev = &psmouse->ps2dev; struct ps2dev *ps2dev = &psmouse->ps2dev;
unsigned char param[3];
int cmd = enable ? PSMOUSE_CMD_SETSCALE21 : PSMOUSE_CMD_SETSCALE11; int cmd = enable ? PSMOUSE_CMD_SETSCALE21 : PSMOUSE_CMD_SETSCALE11;
if (ps2_command(ps2dev, NULL, cmd) || if (ps2_command(ps2dev, NULL, cmd) ||
@ -267,7 +279,7 @@ static int alps_passthrough_mode(struct psmouse *psmouse, int enable)
return -1; return -1;
/* we may get 3 more bytes, just ignore them */ /* we may get 3 more bytes, just ignore them */
ps2_command(ps2dev, param, 0x0300); ps2_drain(ps2dev, 3, 100);
return 0; return 0;
} }
@ -425,7 +437,7 @@ int alps_init(struct psmouse *psmouse)
psmouse->dev.relbit[LONG(REL_WHEEL)] |= BIT(REL_WHEEL); 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_FORWARD)] |= BIT(BTN_FORWARD);
psmouse->dev.keybit[LONG(BTN_BACK)] |= BIT(BTN_BACK); 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.bustype = BUS_I8042;
priv->dev2.id.vendor = 0x0002; priv->dev2.id.vendor = 0x0002;
priv->dev2.id.product = PSMOUSE_ALPS; 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.evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
priv->dev2.relbit[LONG(REL_X)] |= BIT(REL_X) | BIT(REL_Y); 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); 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 alps_detect(struct psmouse *psmouse, int set_properties)
{ {
int version; int version;
struct alps_model_info *model; struct alps_model_info *model;
if (!(model = alps_get_model(psmouse, &version))) if (!(model = alps_get_model(psmouse, &version)))
return -1; return -1;
if (set_properties) { if (set_properties) {
psmouse->vendor = "ALPS"; psmouse->vendor = "ALPS";
if (model->flags & ALPS_DUALPOINT) psmouse->name = model->flags & ALPS_DUALPOINT ?
psmouse->name = "DualPoint TouchPad"; "DualPoint TouchPad" : "GlidePoint";
else
psmouse->name = "GlidePoint";
psmouse->model = version; psmouse->model = version;
} }
return 0; return 0;

View file

@ -33,7 +33,6 @@ MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
MODULE_DESCRIPTION("Amiga mouse driver"); MODULE_DESCRIPTION("Amiga mouse driver");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
static int amimouse_used = 0;
static int amimouse_lastx, amimouse_lasty; static int amimouse_lastx, amimouse_lasty;
static struct input_dev amimouse_dev; static struct input_dev amimouse_dev;
@ -81,16 +80,12 @@ static int amimouse_open(struct input_dev *dev)
{ {
unsigned short joy0dat; unsigned short joy0dat;
if (amimouse_used++)
return 0;
joy0dat = custom.joy0dat; joy0dat = custom.joy0dat;
amimouse_lastx = joy0dat & 0xff; amimouse_lastx = joy0dat & 0xff;
amimouse_lasty = joy0dat >> 8; amimouse_lasty = joy0dat >> 8;
if (request_irq(IRQ_AMIGA_VERTB, amimouse_interrupt, 0, "amimouse", amimouse_interrupt)) { 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); printk(KERN_ERR "amimouse.c: Can't allocate irq %d\n", IRQ_AMIGA_VERTB);
return -EBUSY; return -EBUSY;
} }
@ -100,8 +95,7 @@ static int amimouse_open(struct input_dev *dev)
static void amimouse_close(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) static int __init amimouse_init(void)

View file

@ -17,18 +17,18 @@
/* /*
* This program is free software; you can redistribute it and/or modify * 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 * 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. * (at your option) any later version.
* *
* This program is distributed in the hope that it will be useful, * This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * GNU General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * 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 * 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: * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic * 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="); __obsolete_setup("inport_irq=");
static int inport_used;
static irqreturn_t inport_interrupt(int irq, void *dev_id, struct pt_regs *regs); static irqreturn_t inport_interrupt(int irq, void *dev_id, struct pt_regs *regs);
static int inport_open(struct input_dev *dev) static int inport_open(struct input_dev *dev)
{ {
if (!inport_used++) { if (request_irq(inport_irq, inport_interrupt, 0, "inport", NULL))
if (request_irq(inport_irq, inport_interrupt, 0, "inport", NULL)) return -EBUSY;
return -EBUSY; outb(INPORT_REG_MODE, INPORT_CONTROL_PORT);
outb(INPORT_REG_MODE, INPORT_CONTROL_PORT); outb(INPORT_MODE_IRQ | INPORT_MODE_BASE, INPORT_DATA_PORT);
outb(INPORT_MODE_IRQ | INPORT_MODE_BASE, INPORT_DATA_PORT);
}
return 0; return 0;
} }
static void inport_close(struct input_dev *dev) static void inport_close(struct input_dev *dev)
{ {
if (!--inport_used) { outb(INPORT_REG_MODE, INPORT_CONTROL_PORT);
outb(INPORT_REG_MODE, INPORT_CONTROL_PORT); outb(INPORT_MODE_BASE, INPORT_DATA_PORT);
outb(INPORT_MODE_BASE, INPORT_DATA_PORT); free_irq(inport_irq, NULL);
free_irq(inport_irq, NULL);
}
} }
static struct input_dev inport_dev = { static struct input_dev inport_dev = {
@ -120,11 +114,11 @@ static struct input_dev inport_dev = {
.close = inport_close, .close = inport_close,
.name = INPORT_NAME, .name = INPORT_NAME,
.phys = "isa023c/input0", .phys = "isa023c/input0",
.id = { .id = {
.bustype = BUS_ISA, .bustype = BUS_ISA,
.vendor = INPORT_VENDOR, .vendor = INPORT_VENDOR,
.product = 0x0001, .product = 0x0001,
.version = 0x0100, .version = 0x0100,
}, },
}; };

View file

@ -0,0 +1,134 @@
/*
* Fujitsu B-series Lifebook PS/2 TouchScreen driver
*
* Copyright (c) 2005 Vojtech Pavlik <vojtech@suse.cz>
* Copyright (c) 2005 Kenan Esau <kenan.esau@conan.de>
*
* TouchScreen detection, absolute mode setting and packet layout is taken from
* Harald Hoyer's description of the device.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation.
*/
#include <linux/input.h>
#include <linux/serio.h>
#include <linux/libps2.h>
#include <linux/dmi.h>
#include "psmouse.h"
#include "lifebook.h"
static struct dmi_system_id lifebook_dmi_table[] = {
{
.ident = "Lifebook B",
.matches = {
DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK B Series"),
},
},
{ }
};
static psmouse_ret_t lifebook_process_byte(struct psmouse *psmouse, struct pt_regs *regs)
{
unsigned char *packet = psmouse->packet;
struct input_dev *dev = &psmouse->dev;
if (psmouse->pktcnt != 3)
return PSMOUSE_GOOD_DATA;
input_regs(dev, regs);
/* calculate X and Y */
if ((packet[0] & 0x08) == 0x00) {
input_report_abs(dev, ABS_X,
(packet[1] | ((packet[0] & 0x30) << 4)));
input_report_abs(dev, ABS_Y,
1024 - (packet[2] | ((packet[0] & 0xC0) << 2)));
} else {
input_report_rel(dev, REL_X,
((packet[0] & 0x10) ? packet[1] - 256 : packet[1]));
input_report_rel(dev, REL_Y,
-(int)((packet[0] & 0x20) ? packet[2] - 256 : packet[2]));
}
input_report_key(dev, BTN_LEFT, packet[0] & 0x01);
input_report_key(dev, BTN_RIGHT, packet[0] & 0x02);
input_report_key(dev, BTN_TOUCH, packet[0] & 0x04);
input_sync(dev);
return PSMOUSE_FULL_PACKET;
}
static int lifebook_absolute_mode(struct psmouse *psmouse)
{
struct ps2dev *ps2dev = &psmouse->ps2dev;
unsigned char param;
if (psmouse_reset(psmouse))
return -1;
/*
Enable absolute output -- ps2_command fails always but if
you leave this call out the touchsreen will never send
absolute coordinates
*/
param = 0x07;
ps2_command(ps2dev, &param, PSMOUSE_CMD_SETRES);
return 0;
}
static void lifebook_set_resolution(struct psmouse *psmouse, unsigned int resolution)
{
unsigned char params[] = { 0, 1, 2, 2, 3 };
if (resolution == 0 || resolution > 400)
resolution = 400;
ps2_command(&psmouse->ps2dev, &params[resolution / 100], PSMOUSE_CMD_SETRES);
psmouse->resolution = 50 << params[resolution / 100];
}
static void lifebook_disconnect(struct psmouse *psmouse)
{
psmouse_reset(psmouse);
}
int lifebook_detect(struct psmouse *psmouse, int set_properties)
{
if (!dmi_check_system(lifebook_dmi_table))
return -1;
if (set_properties) {
psmouse->vendor = "Fujitsu";
psmouse->name = "Lifebook TouchScreen";
}
return 0;
}
int lifebook_init(struct psmouse *psmouse)
{
if (lifebook_absolute_mode(psmouse))
return -1;
psmouse->dev.evbit[0] = BIT(EV_ABS) | BIT(EV_KEY) | BIT(EV_REL);
psmouse->dev.keybit[LONG(BTN_LEFT)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT);
psmouse->dev.keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH);
psmouse->dev.relbit[0] = BIT(REL_X) | BIT(REL_Y);
input_set_abs_params(&psmouse->dev, ABS_X, 0, 1024, 0, 0);
input_set_abs_params(&psmouse->dev, ABS_Y, 0, 1024, 0, 0);
psmouse->protocol_handler = lifebook_process_byte;
psmouse->set_resolution = lifebook_set_resolution;
psmouse->disconnect = lifebook_disconnect;
psmouse->reconnect = lifebook_absolute_mode;
psmouse->pktsize = 3;
return 0;
}

View file

@ -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

View file

@ -18,18 +18,18 @@
/* /*
* This program is free software; you can redistribute it and/or modify * 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 * 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. * (at your option) any later version.
* *
* This program is distributed in the hope that it will be useful, * This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * GNU General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * 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 * 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: * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic * 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="); __obsolete_setup("logibm_irq=");
static int logibm_used = 0;
static irqreturn_t logibm_interrupt(int irq, void *dev_id, struct pt_regs *regs); static irqreturn_t logibm_interrupt(int irq, void *dev_id, struct pt_regs *regs);
static int logibm_open(struct input_dev *dev) static int logibm_open(struct input_dev *dev)
{ {
if (logibm_used++)
return 0;
if (request_irq(logibm_irq, logibm_interrupt, 0, "logibm", NULL)) { 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); printk(KERN_ERR "logibm.c: Can't allocate irq %d\n", logibm_irq);
return -EBUSY; return -EBUSY;
} }
@ -96,8 +91,6 @@ static int logibm_open(struct input_dev *dev)
static void logibm_close(struct input_dev *dev) static void logibm_close(struct input_dev *dev)
{ {
if (--logibm_used)
return;
outb(LOGIBM_DISABLE_IRQ, LOGIBM_CONTROL_PORT); outb(LOGIBM_DISABLE_IRQ, LOGIBM_CONTROL_PORT);
free_irq(logibm_irq, NULL); free_irq(logibm_irq, NULL);
} }
@ -167,7 +160,7 @@ static int __init logibm_init(void)
outb(LOGIBM_DISABLE_IRQ, LOGIBM_CONTROL_PORT); outb(LOGIBM_DISABLE_IRQ, LOGIBM_CONTROL_PORT);
input_register_device(&logibm_dev); input_register_device(&logibm_dev);
printk(KERN_INFO "input: Logitech bus mouse at %#x irq %d\n", LOGIBM_BASE, logibm_irq); printk(KERN_INFO "input: Logitech bus mouse at %#x irq %d\n", LOGIBM_BASE, logibm_irq);
return 0; return 0;

View file

@ -1,6 +1,6 @@
/* /*
* $Id: maplemouse.c,v 1.2 2004/03/22 01:18:15 lethal Exp $ * $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 * Based on drivers/usb/usbmouse.c
*/ */
@ -15,80 +15,51 @@
MODULE_AUTHOR("YAEGASHI Takeshi <t@keshi.org>"); MODULE_AUTHOR("YAEGASHI Takeshi <t@keshi.org>");
MODULE_DESCRIPTION("SEGA Dreamcast mouse driver"); MODULE_DESCRIPTION("SEGA Dreamcast mouse driver");
struct dc_mouse {
struct input_dev dev;
int open;
};
static void dc_mouse_callback(struct mapleq *mq) static void dc_mouse_callback(struct mapleq *mq)
{ {
int buttons, relx, rely, relz; int buttons, relx, rely, relz;
struct maple_device *mapledev = mq->dev; struct maple_device *mapledev = mq->dev;
struct dc_mouse *mouse = mapledev->private_data; struct input_dev *dev = mapledev->private_data;
struct input_dev *dev = &mouse->dev;
unsigned char *res = mq->recvbuf; unsigned char *res = mq->recvbuf;
buttons = ~res[8]; buttons = ~res[8];
relx=*(unsigned short *)(res+12)-512; relx = *(unsigned short *)(res + 12) - 512;
rely=*(unsigned short *)(res+14)-512; rely = *(unsigned short *)(res + 14) - 512;
relz=*(unsigned short *)(res+16)-512; relz = *(unsigned short *)(res + 16) - 512;
input_report_key(dev, BTN_LEFT, buttons&4); input_report_key(dev, BTN_LEFT, buttons & 4);
input_report_key(dev, BTN_MIDDLE, buttons&9); input_report_key(dev, BTN_MIDDLE, buttons & 9);
input_report_key(dev, BTN_RIGHT, buttons&2); input_report_key(dev, BTN_RIGHT, buttons & 2);
input_report_rel(dev, REL_X, relx); input_report_rel(dev, REL_X, relx);
input_report_rel(dev, REL_Y, rely); input_report_rel(dev, REL_Y, rely);
input_report_rel(dev, REL_WHEEL, relz); input_report_rel(dev, REL_WHEEL, relz);
input_sync(dev); 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) static int dc_mouse_connect(struct maple_device *dev)
{ {
unsigned long data = be32_to_cpu(dev->devinfo.function_data[0]); 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; return -1;
memset(mouse, 0, sizeof(struct dc_mouse));
dev->private_data = mouse; dev->private_data = input_dev;
mouse->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REL); memset(input_dev, 0, sizeof(struct dc_mouse));
mouse->dev.keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE); init_input_dev(input_dev);
mouse->dev.relbit[0] = BIT(REL_X) | BIT(REL_Y) | BIT(REL_WHEEL); 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);
init_input_dev(&mouse->dev); input_dev->name = dev->product_name;
input_dev->id.bustype = BUS_MAPLE;
mouse->dev.private = mouse; input_register_device(input_dev);
mouse->dev.open = dc_mouse_open;
mouse->dev.close = dc_mouse_close;
mouse->dev.event = NULL;
mouse->dev.name = dev->product_name;
mouse->dev.id.bustype = BUS_MAPLE;
input_register_device(&mouse->dev);
maple_getcond_callback(dev, dc_mouse_callback, 1, MAPLE_FUNC_MOUSE); 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; return 0;
} }
@ -96,10 +67,10 @@ static int dc_mouse_connect(struct maple_device *dev)
static void dc_mouse_disconnect(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); input_unregister_device(input_dev);
kfree(mouse); kfree(input_dev);
} }

View file

@ -4,7 +4,7 @@
* Copyright (c) 2000-2001 Vojtech Pavlik * Copyright (c) 2000-2001 Vojtech Pavlik
* *
* Based on the work of: * 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 struct input_dev pc110pad_dev;
static int pc110pad_data[3]; static int pc110pad_data[3];
static int pc110pad_count; static int pc110pad_count;
static int pc110pad_used;
static char *pc110pad_name = "IBM PC110 TouchPad"; static char *pc110pad_name = "IBM PC110 TouchPad";
static char *pc110pad_phys = "isa15e0/input0"; 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) if (pc110pad_count < 3)
return IRQ_HANDLED; return IRQ_HANDLED;
input_regs(&pc110pad_dev, regs); input_regs(&pc110pad_dev, regs);
input_report_key(&pc110pad_dev, BTN_TOUCH, input_report_key(&pc110pad_dev, BTN_TOUCH,
pc110pad_data[0] & 0x01); 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) 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) 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); 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_X] = 0x1ff;
pc110pad_dev.absmax[ABS_Y] = 0x0ff; pc110pad_dev.absmax[ABS_Y] = 0x0ff;
pc110pad_dev.open = pc110pad_open; pc110pad_dev.open = pc110pad_open;
pc110pad_dev.close = pc110pad_close; pc110pad_dev.close = pc110pad_close;
@ -156,17 +151,17 @@ static int __init pc110pad_init(void)
pc110pad_dev.id.product = 0x0001; pc110pad_dev.id.product = 0x0001;
pc110pad_dev.id.version = 0x0100; 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", printk(KERN_INFO "input: %s at %#x irq %d\n",
pc110pad_name, pc110pad_io, pc110pad_irq); pc110pad_name, pc110pad_io, pc110pad_irq);
return 0; return 0;
} }
static void __exit pc110pad_exit(void) static void __exit pc110pad_exit(void)
{ {
input_unregister_device(&pc110pad_dev); input_unregister_device(&pc110pad_dev);
outb(PC110PAD_OFF, pc110pad_io + 2); outb(PC110PAD_OFF, pc110pad_io + 2);

View file

@ -24,6 +24,7 @@
#include "synaptics.h" #include "synaptics.h"
#include "logips2pp.h" #include "logips2pp.h"
#include "alps.h" #include "alps.h"
#include "lifebook.h"
#define DRIVER_DESC "PS/2 mouse driver" #define DRIVER_DESC "PS/2 mouse driver"
@ -31,10 +32,9 @@ MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
MODULE_DESCRIPTION(DRIVER_DESC); MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL"); 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_set_maxproto(const char *val, struct kernel_param *kp);
static int psmouse_get_maxproto(char *buffer, 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_check_proto_abbrev(name, p) __param_check(name, p, unsigned int)
#define param_set_proto_abbrev psmouse_set_maxproto #define param_set_proto_abbrev psmouse_set_maxproto
#define param_get_proto_abbrev psmouse_get_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_param_named(resetafter, psmouse_resetafter, uint, 0644);
MODULE_PARM_DESC(resetafter, "Reset device after so many bad packets (0 = never)."); MODULE_PARM_DESC(resetafter, "Reset device after so many bad packets (0 = never).");
PSMOUSE_DEFINE_ATTR(protocol);
PSMOUSE_DEFINE_ATTR(rate); PSMOUSE_DEFINE_ATTR(rate);
PSMOUSE_DEFINE_ATTR(resolution); PSMOUSE_DEFINE_ATTR(resolution);
PSMOUSE_DEFINE_ATTR(resetafter); PSMOUSE_DEFINE_ATTR(resetafter);
@ -67,7 +68,23 @@ __obsolete_setup("psmouse_smartscroll=");
__obsolete_setup("psmouse_resetafter="); __obsolete_setup("psmouse_resetafter=");
__obsolete_setup("psmouse_rate="); __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 * 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) static int ps2bare_detect(struct psmouse *psmouse, int set_properties)
{ {
if (!psmouse->vendor) psmouse->vendor = "Generic"; if (set_properties) {
if (!psmouse->name) psmouse->name = "Mouse"; if (!psmouse->vendor) psmouse->vendor = "Generic";
if (!psmouse->name) psmouse->name = "Mouse";
}
return 0; return 0;
} }
/* /*
* psmouse_extensions() probes for any extensions to the basic PS/2 protocol * psmouse_extensions() probes for any extensions to the basic PS/2 protocol
* the mouse may have. * the mouse may have.
@ -423,6 +443,17 @@ static int psmouse_extensions(struct psmouse *psmouse,
{ {
int synaptics_hardware = 0; 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 * Try Kensington ThinkingMouse (we try first, because synaptics probe
* upsets the thinkingmouse). * upsets the thinkingmouse).
@ -506,6 +537,103 @@ static int psmouse_extensions(struct psmouse *psmouse,
return PSMOUSE_PS2; 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. * 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) 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_rate);
device_remove_file(&serio->dev, &psmouse_attr_resolution); device_remove_file(&serio->dev, &psmouse_attr_resolution);
device_remove_file(&serio->dev, &psmouse_attr_resetafter); device_remove_file(&serio->dev, &psmouse_attr_resetafter);
psmouse = serio_get_drvdata(serio); down(&psmouse_sem);
psmouse_set_state(psmouse, PSMOUSE_CMD_MODE); psmouse_set_state(psmouse, PSMOUSE_CMD_MODE);
if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) { if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) {
parent = serio_get_drvdata(serio->parent); parent = serio_get_drvdata(serio->parent);
if (parent->pt_deactivate) psmouse_deactivate(parent);
parent->pt_deactivate(parent);
} }
if (psmouse->disconnect) if (psmouse->disconnect)
psmouse->disconnect(psmouse); psmouse->disconnect(psmouse);
if (parent && parent->pt_deactivate)
parent->pt_deactivate(parent);
psmouse_set_state(psmouse, PSMOUSE_IGNORE); psmouse_set_state(psmouse, PSMOUSE_IGNORE);
input_unregister_device(&psmouse->dev); input_unregister_device(&psmouse->dev);
serio_close(serio); serio_close(serio);
serio_set_drvdata(serio, NULL); serio_set_drvdata(serio, NULL);
kfree(psmouse); 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; struct psmouse *psmouse, *parent = NULL;
int retval; int retval;
down(&psmouse_sem);
/* /*
* If this is a pass-through port deactivate parent so the device * If this is a pass-through port deactivate parent so the device
* connected to this port can be successfully identified * 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); psmouse_deactivate(parent);
} }
if (!(psmouse = kmalloc(sizeof(struct psmouse), GFP_KERNEL))) { if (!(psmouse = kcalloc(1, sizeof(struct psmouse), GFP_KERNEL))) {
retval = -ENOMEM; retval = -ENOMEM;
goto out; goto out;
} }
memset(psmouse, 0, sizeof(struct psmouse));
ps2_init(&psmouse->ps2dev, serio); ps2_init(&psmouse->ps2dev, serio);
sprintf(psmouse->phys, "%s/input0", serio->phys); 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); psmouse_set_state(psmouse, PSMOUSE_INITIALIZING);
serio_set_drvdata(serio, psmouse); 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->resolution = psmouse_resolution;
psmouse->resetafter = psmouse_resetafter; psmouse->resetafter = psmouse_resetafter;
psmouse->smartscroll = psmouse_smartscroll; 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); psmouse_switch_protocol(psmouse, NULL);
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;
input_register_device(&psmouse->dev); input_register_device(&psmouse->dev);
printk(KERN_INFO "input: %s on %s\n", psmouse->devname, serio->phys); printk(KERN_INFO "input: %s on %s\n", psmouse->devname, serio->phys);
psmouse_set_state(psmouse, PSMOUSE_CMD_MODE); 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) if (parent && parent->pt_activate)
parent->pt_activate(parent); 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_rate);
device_create_file(&serio->dev, &psmouse_attr_resolution); device_create_file(&serio->dev, &psmouse_attr_resolution);
device_create_file(&serio->dev, &psmouse_attr_resetafter); 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; retval = 0;
out: 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) if (parent)
psmouse_activate(parent); psmouse_activate(parent);
up(&psmouse_sem);
return retval; return retval;
} }
@ -791,6 +956,8 @@ static int psmouse_reconnect(struct serio *serio)
return -1; return -1;
} }
down(&psmouse_sem);
if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) { if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) {
parent = serio_get_drvdata(serio->parent); parent = serio_get_drvdata(serio->parent);
psmouse_deactivate(parent); psmouse_deactivate(parent);
@ -823,6 +990,7 @@ out:
if (parent) if (parent)
psmouse_activate(parent); psmouse_activate(parent);
up(&psmouse_sem);
return rc; 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) { if (serio->drv != &psmouse_drv) {
retval = -ENODEV; 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) { if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) {
parent = serio_get_drvdata(serio->parent); parent = serio_get_drvdata(serio->parent);
psmouse_deactivate(parent); psmouse_deactivate(parent);
} }
psmouse_deactivate(psmouse); psmouse_deactivate(psmouse);
retval = handler(psmouse, buf, count); retval = handler(psmouse, buf, count);
psmouse_activate(psmouse); if (retval != -ENODEV)
psmouse_activate(psmouse);
if (parent) if (parent)
psmouse_activate(parent); psmouse_activate(parent);
out: out_up:
up(&psmouse_sem);
out_unpin:
serio_unpin_driver(serio); serio_unpin_driver(serio);
return retval; 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) static ssize_t psmouse_attr_show_rate(struct psmouse *psmouse, char *buf)
{ {
return sprintf(buf, "%d\n", psmouse->rate); 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) static int psmouse_set_maxproto(const char *val, struct kernel_param *kp)
{ {
int i; struct psmouse_protocol *proto;
if (!val) if (!val)
return -EINVAL; return -EINVAL;
if (!strncmp(val, "any", 3)) { proto = psmouse_protocol_by_name(val, strlen(val));
*((unsigned int *)kp->arg) = -1U;
return 0;
}
for (i = 0; i < ARRAY_SIZE(psmouse_proto_abbrev); i++) { if (!proto || !proto->maxproto)
if (!psmouse_proto_abbrev[i]) return -EINVAL;
continue;
if (!strncmp(val, psmouse_proto_abbrev[i], strlen(psmouse_proto_abbrev[i]))) { *((unsigned int *)kp->arg) = proto->type;
*((unsigned int *)kp->arg) = i;
return 0;
}
}
return -EINVAL; \ return 0; \
} }
static int psmouse_get_maxproto(char *buffer, struct kernel_param *kp) static int psmouse_get_maxproto(char *buffer, struct kernel_param *kp)
{ {
return sprintf(buffer, "%s\n", int type = *((unsigned int *)kp->arg);
psmouse_max_proto < ARRAY_SIZE(psmouse_proto_abbrev) ?
psmouse_proto_abbrev[psmouse_max_proto] : "any"); return sprintf(buffer, "%s\n", psmouse_protocol_by_type(type)->name);
} }
static int __init psmouse_init(void) static int __init psmouse_init(void)

View file

@ -77,6 +77,8 @@ enum psmouse_type {
PSMOUSE_IMEX, PSMOUSE_IMEX,
PSMOUSE_SYNAPTICS, PSMOUSE_SYNAPTICS,
PSMOUSE_ALPS, PSMOUSE_ALPS,
PSMOUSE_LIFEBOOK,
PSMOUSE_AUTO /* This one should always be last */
}; };
int psmouse_sliced_command(struct psmouse *psmouse, unsigned char command); 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); \ 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, \ __ATTR(_name, S_IWUSR | S_IRUGO, \
psmouse_do_show_##_name, psmouse_do_set_##_name); psmouse_do_show_##_name, psmouse_do_set_##_name);

View file

@ -59,7 +59,7 @@ static irqreturn_t rpcmouse_irq(int irq, void *dev_id, struct pt_regs *regs)
b = (short) (__raw_readl(0xe0310000) ^ 0x70); b = (short) (__raw_readl(0xe0310000) ^ 0x70);
dx = x - rpcmouse_lastx; dx = x - rpcmouse_lastx;
dy = y - rpcmouse_lasty; dy = y - rpcmouse_lasty;
rpcmouse_lastx = x; rpcmouse_lastx = x;
rpcmouse_lasty = y; rpcmouse_lasty = y;

View file

@ -1,7 +1,7 @@
/* /*
* Driver for DEC VSXXX-AA mouse (hockey-puck mouse, ball or two rollers) * Driver for DEC VSXXX-AA mouse (hockey-puck mouse, ball or two rollers)
* DEC VSXXX-GA mouse (rectangular mouse, with ball) * DEC VSXXX-GA mouse (rectangular mouse, with ball)
* DEC VSXXX-AB tablet (digitizer with hair cross or stylus) * DEC VSXXX-AB tablet (digitizer with hair cross or stylus)
* *
* Copyright (C) 2003-2004 by Jan-Benedict Glaw <jbglaw@lug-owl.de> * Copyright (C) 2003-2004 by Jan-Benedict Glaw <jbglaw@lug-owl.de>
* *

View file

@ -220,6 +220,7 @@ static void mousedev_notify_readers(struct mousedev *mousedev, struct mousedev_h
struct mousedev_list *list; struct mousedev_list *list;
struct mousedev_motion *p; struct mousedev_motion *p;
unsigned long flags; unsigned long flags;
int wake_readers = 0;
list_for_each_entry(list, &mousedev->list, node) { list_for_each_entry(list, &mousedev->list, node) {
spin_lock_irqsave(&list->packet_lock, flags); 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); spin_unlock_irqrestore(&list->packet_lock, flags);
if (list->ready) if (list->ready) {
kill_fasync(&list->fasync, SIGIO, POLL_IN); 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) static void mousedev_touchpad_touch(struct mousedev *mousedev, int value)

View file

@ -29,6 +29,7 @@ MODULE_LICENSE("GPL");
EXPORT_SYMBOL(ps2_init); EXPORT_SYMBOL(ps2_init);
EXPORT_SYMBOL(ps2_sendbyte); EXPORT_SYMBOL(ps2_sendbyte);
EXPORT_SYMBOL(ps2_drain);
EXPORT_SYMBOL(ps2_command); EXPORT_SYMBOL(ps2_command);
EXPORT_SYMBOL(ps2_schedule_command); EXPORT_SYMBOL(ps2_schedule_command);
EXPORT_SYMBOL(ps2_handle_ack); EXPORT_SYMBOL(ps2_handle_ack);
@ -45,11 +46,11 @@ struct ps2work {
/* /*
* ps2_sendbyte() sends a byte to the mouse, and waits for acknowledge. * ps2_sendbyte() sends a byte to the device and waits for acknowledge.
* It doesn't handle retransmission, though it could - because when there would * It doesn't handle retransmission, though it could - because if there
* be need for retransmissions, the mouse has to be replaced anyway. * 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) int ps2_sendbyte(struct ps2dev *ps2dev, unsigned char byte, int timeout)
@ -71,6 +72,91 @@ int ps2_sendbyte(struct ps2dev *ps2dev, unsigned char byte, int timeout)
return -ps2dev->nak; return -ps2dev->nak;
} }
/*
* 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, * ps2_command() sends a command and its parameters to the mouse,
* then waits for the response and puts it in the param array. * 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 rc = -1;
int i; int i;
if (receive > sizeof(ps2dev->cmdbuf)) {
WARN_ON(1);
return -1;
}
down(&ps2dev->cmd_sem); down(&ps2dev->cmd_sem);
serio_pause_rx(ps2dev->serio); 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 * ACKing the reset command, and so it can take a long
* time before the ACK arrrives. * time before the ACK arrrives.
*/ */
if (command & 0xff) if (ps2_sendbyte(ps2dev, command & 0xff,
if (ps2_sendbyte(ps2dev, command & 0xff, command == PS2_CMD_RESET_BAT ? 1000 : 200))
command == PS2_CMD_RESET_BAT ? 1000 : 200)) goto out;
goto out;
for (i = 0; i < send; i++) for (i = 0; i < send; i++)
if (ps2_sendbyte(ps2dev, param[i], 200)) 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 (ps2dev->cmdcnt && timeout > 0) {
if (command == PS2_CMD_RESET_BAT && timeout > msecs_to_jiffies(100)) { timeout = ps2_adjust_timeout(ps2dev, command, timeout);
/*
* 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);
}
wait_event_timeout(ps2dev->wait, wait_event_timeout(ps2dev->wait,
!(ps2dev->flags & PS2_FLAG_CMD), timeout); !(ps2dev->flags & PS2_FLAG_CMD), timeout);
} }
@ -160,7 +224,7 @@ int ps2_command(struct ps2dev *ps2dev, unsigned char *param, int command)
rc = 0; rc = 0;
out: out:
serio_pause_rx(ps2dev->serio); serio_pause_rx(ps2dev->serio);
ps2dev->flags = 0; ps2dev->flags = 0;
serio_continue_rx(ps2dev->serio); serio_continue_rx(ps2dev->serio);

View file

@ -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_Y, 96, 4000, 0, 0);
input_set_abs_params(&elo->dev, ABS_PRESSURE, 0, 255, 0, 0); input_set_abs_params(&elo->dev, ABS_PRESSURE, 0, 255, 0, 0);
break; break;
case 1: /* 6-byte protocol */ case 1: /* 6-byte protocol */
input_set_abs_params(&elo->dev, ABS_PRESSURE, 0, 15, 0, 0); input_set_abs_params(&elo->dev, ABS_PRESSURE, 0, 15, 0, 0);

View file

@ -89,9 +89,9 @@ MODULE_LICENSE("GPL");
#define H3600_SCANCODE_Q 4 /* 4 -> Q button */ #define H3600_SCANCODE_Q 4 /* 4 -> Q button */
#define H3600_SCANCODE_START 5 /* 5 -> start menu */ #define H3600_SCANCODE_START 5 /* 5 -> start menu */
#define H3600_SCANCODE_UP 6 /* 6 -> up */ #define H3600_SCANCODE_UP 6 /* 6 -> up */
#define H3600_SCANCODE_RIGHT 7 /* 7 -> right */ #define H3600_SCANCODE_RIGHT 7 /* 7 -> right */
#define H3600_SCANCODE_LEFT 8 /* 8 -> left */ #define H3600_SCANCODE_LEFT 8 /* 8 -> left */
#define H3600_SCANCODE_DOWN 9 /* 9 -> down */ #define H3600_SCANCODE_DOWN 9 /* 9 -> down */
static char *h3600_name = "H3600 TouchScreen"; 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) 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; struct input_dev *dev = (struct input_dev *) dev_id;
input_regs(dev, regs); 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) 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; 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; static int flite_brightness = 25;
enum flite_pwr { enum flite_pwr {
FLITE_PWR_OFF = 0, FLITE_PWR_OFF = 0,
FLITE_PWR_ON = 1 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; struct h3600_dev *ts = dev->private;
/* Must be in this order */ /* 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, pwr);
ts->serio->write(ts->serio, brightness); ts->serio->write(ts->serio, brightness);
return 0; 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; struct input_dev *dev = (struct input_dev *) data;
switch (req) { switch (req) {
case PM_SUSPEND: /* enter D1-D3 */ case PM_SUSPEND: /* enter D1-D3 */
suspended = 1; suspended = 1;
h3600_flite_power(dev, FLITE_PWR_OFF); h3600_flite_power(dev, FLITE_PWR_OFF);
break; break;
case PM_BLANK: case PM_BLANK:
if (!suspended) if (!suspended)
h3600_flite_power(dev, FLITE_PWR_OFF); h3600_flite_power(dev, FLITE_PWR_OFF);
break; break;
case PM_RESUME: /* enter D0 */ case PM_RESUME: /* enter D0 */
/* same as unblank */ /* same as unblank */
case PM_UNBLANK: case PM_UNBLANK:
if (suspended) { if (suspended) {
//initSerial(); //initSerial();
suspended = 0; suspended = 0;
} }
h3600_flite_power(dev, FLITE_PWR_ON); h3600_flite_power(dev, FLITE_PWR_ON);
break; break;
} }
return 0; return 0;
} }
#endif #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) 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; static int touched = 0;
int key, down = 0; int key, down = 0;
input_regs(dev, regs); input_regs(dev, regs);
switch (ts->event) { switch (ts->event) {
/* /*
Buttons - returned as a single byte Buttons - returned as a single byte
7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0
S x x x N N N N S x x x N N N N
S switch state ( 0=pressed 1=released) S switch state ( 0=pressed 1=released)
x Unused. x Unused.
NNNN switch number 0-15 NNNN switch number 0-15
Note: This is true for non interrupt generated key events. Note: This is true for non interrupt generated key events.
*/ */
case KEYBD_ID: case KEYBD_ID:
down = (ts->buf[0] & 0x80) ? 0 : 1; down = (ts->buf[0] & 0x80) ? 0 : 1;
switch (ts->buf[0] & 0x7f) { switch (ts->buf[0] & 0x7f) {
@ -229,40 +229,40 @@ static void h3600ts_process_packet(struct h3600_dev *ts, struct pt_regs *regs)
break; break;
case H3600_SCANCODE_CONTACTS: case H3600_SCANCODE_CONTACTS:
key = KEY_PROG2; key = KEY_PROG2;
break; break;
case H3600_SCANCODE_Q: case H3600_SCANCODE_Q:
key = KEY_Q; key = KEY_Q;
break; break;
case H3600_SCANCODE_START: case H3600_SCANCODE_START:
key = KEY_PROG3; key = KEY_PROG3;
break; break;
case H3600_SCANCODE_UP: case H3600_SCANCODE_UP:
key = KEY_UP; key = KEY_UP;
break; break;
case H3600_SCANCODE_RIGHT: case H3600_SCANCODE_RIGHT:
key = KEY_RIGHT; key = KEY_RIGHT;
break; break;
case H3600_SCANCODE_LEFT: case H3600_SCANCODE_LEFT:
key = KEY_LEFT; key = KEY_LEFT;
break; break;
case H3600_SCANCODE_DOWN: case H3600_SCANCODE_DOWN:
key = KEY_DOWN; key = KEY_DOWN;
break; break;
default: default:
key = 0; key = 0;
} }
if (key) if (key)
input_report_key(dev, key, down); input_report_key(dev, key, down);
break; break;
/* /*
* Native touchscreen event data is formatted as shown below:- * Native touchscreen event data is formatted as shown below:-
* *
* +-------+-------+-------+-------+ * +-------+-------+-------+-------+
* | Xmsb | Xlsb | Ymsb | Ylsb | * | Xmsb | Xlsb | Ymsb | Ylsb |
* +-------+-------+-------+-------+ * +-------+-------+-------+-------+
* byte 0 1 2 3 * byte 0 1 2 3
*/ */
case TOUCHS_ID: case TOUCHS_ID:
if (!touched) { if (!touched) {
input_report_key(dev, BTN_TOUCH, 1); input_report_key(dev, BTN_TOUCH, 1);
touched = 1; touched = 1;
@ -272,19 +272,19 @@ static void h3600ts_process_packet(struct h3600_dev *ts, struct pt_regs *regs)
unsigned short x, y; unsigned short x, y;
x = ts->buf[0]; x <<= 8; x += ts->buf[1]; 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_X, x);
input_report_abs(dev, ABS_Y, y); input_report_abs(dev, ABS_Y, y);
} else { } else {
input_report_key(dev, BTN_TOUCH, 0); input_report_key(dev, BTN_TOUCH, 0);
touched = 0; touched = 0;
} }
break; break;
default: default:
/* Send a non input event elsewhere */ /* Send a non input event elsewhere */
break; break;
} }
input_sync(dev); 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. * h3600ts_event() handles events from the input module.
*/ */
static int h3600ts_event(struct input_dev *dev, unsigned int type, 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; struct h3600_dev *ts = dev->private;
@ -332,41 +332,41 @@ static int state;
static irqreturn_t h3600ts_interrupt(struct serio *serio, unsigned char data, static irqreturn_t h3600ts_interrupt(struct serio *serio, unsigned char data,
unsigned int flags, struct pt_regs *regs) 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) { switch (state) {
case STATE_SOF: case STATE_SOF:
if (data == CHAR_SOF) if (data == CHAR_SOF)
state = STATE_ID; state = STATE_ID;
break; break;
case STATE_ID: case STATE_ID:
ts->event = (data & 0xf0) >> 4; ts->event = (data & 0xf0) >> 4;
ts->len = (data & 0xf); ts->len = (data & 0xf);
ts->idx = 0; ts->idx = 0;
if (ts->event >= MAX_ID) { if (ts->event >= MAX_ID) {
state = STATE_SOF; state = STATE_SOF;
break; break;
} }
ts->chksum = data; ts->chksum = data;
state = (ts->len > 0) ? STATE_DATA : STATE_EOF; state = (ts->len > 0) ? STATE_DATA : STATE_EOF;
break; break;
case STATE_DATA: case STATE_DATA:
ts->chksum += data; ts->chksum += data;
ts->buf[ts->idx]= data; ts->buf[ts->idx]= data;
if(++ts->idx == ts->len) if (++ts->idx == ts->len)
state = STATE_EOF; state = STATE_EOF;
break; break;
case STATE_EOF: case STATE_EOF:
state = STATE_SOF; state = STATE_SOF;
if (data == CHAR_EOF || data == ts->chksum) if (data == CHAR_EOF || data == ts->chksum)
h3600ts_process_packet(ts, regs); h3600ts_process_packet(ts, regs);
break; break;
default: default:
printk("Error3\n"); printk("Error3\n");
break; break;
} }
return IRQ_HANDLED; return IRQ_HANDLED;
@ -390,10 +390,10 @@ static int h3600ts_connect(struct serio *serio, struct serio_driver *drv)
init_input_dev(&ts->dev); init_input_dev(&ts->dev);
/* Device specific stuff */ /* Device specific stuff */
set_GPIO_IRQ_edge(GPIO_BITSY_ACTION_BUTTON, GPIO_BOTH_EDGES); 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_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, SA_SHIRQ | SA_INTERRUPT | SA_SAMPLE_RANDOM,
"h3600_action", &ts->dev)) { "h3600_action", &ts->dev)) {
printk(KERN_ERR "h3600ts.c: Could not allocate Action Button IRQ!\n"); 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; 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, SA_SHIRQ | SA_INTERRUPT | SA_SAMPLE_RANDOM,
"h3600_suspend", &ts->dev)) { "h3600_suspend", &ts->dev)) {
free_irq(IRQ_GPIO_BITSY_ACTION_BUTTON, &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); sprintf(ts->phys, "%s/input0", serio->phys);
ts->dev.event = h3600ts_event; ts->dev.event = h3600ts_event;
ts->dev.private = ts; ts->dev.private = ts;
ts->dev.name = h3600_name; ts->dev.name = h3600_name;
ts->dev.phys = ts->phys; 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); err = serio_open(serio, drv);
if (err) { if (err) {
free_irq(IRQ_GPIO_BITSY_ACTION_BUTTON, ts); free_irq(IRQ_GPIO_BITSY_ACTION_BUTTON, ts);
free_irq(IRQ_GPIO_BITSY_NPOWER_BUTTON, ts); free_irq(IRQ_GPIO_BITSY_NPOWER_BUTTON, ts);
serio_set_drvdata(serio, NULL); serio_set_drvdata(serio, NULL);
kfree(ts); kfree(ts);
return err; return err;

View file

@ -17,7 +17,7 @@
* found in Gateway AOL Connected Touchpad computers. * found in Gateway AOL Connected Touchpad computers.
* *
* Documentation for ICS MK712 can be found at: * 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_READ_ONE_POINT 0x20
#define MK712_POWERUP 0x40 #define MK712_POWERUP 0x40
static int mk712_used = 0;
static struct input_dev mk712_dev; static struct input_dev mk712_dev;
static DEFINE_SPINLOCK(mk712_lock); static DEFINE_SPINLOCK(mk712_lock);
@ -130,17 +129,14 @@ static int mk712_open(struct input_dev *dev)
spin_lock_irqsave(&mk712_lock, flags); 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 | outb(10, mk712_io + MK712_RATE); /* 187 points per second */
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 */
}
spin_unlock_irqrestore(&mk712_lock, flags); spin_unlock_irqrestore(&mk712_lock, flags);
@ -153,8 +149,7 @@ static void mk712_close(struct input_dev *dev)
spin_lock_irqsave(&mk712_lock, flags); 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); spin_unlock_irqrestore(&mk712_lock, flags);
} }

View file

@ -31,6 +31,7 @@ obj-$(CONFIG_USB_MOUSE) += input/
obj-$(CONFIG_USB_MTOUCH) += input/ obj-$(CONFIG_USB_MTOUCH) += input/
obj-$(CONFIG_USB_POWERMATE) += input/ obj-$(CONFIG_USB_POWERMATE) += input/
obj-$(CONFIG_USB_WACOM) += input/ obj-$(CONFIG_USB_WACOM) += input/
obj-$(CONFIG_USB_ACECAD) += input/
obj-$(CONFIG_USB_XPAD) += input/ obj-$(CONFIG_USB_XPAD) += input/
obj-$(CONFIG_USB_DABUSB) += media/ obj-$(CONFIG_USB_DABUSB) += media/

View file

@ -151,6 +151,18 @@ config USB_WACOM
To compile this driver as a module, choose M here: the To compile this driver as a module, choose M here: the
module will be called wacom. module will be called wacom.
config USB_ACECAD
tristate "Acecad Flair tablet support"
depends on USB && INPUT
help
Say Y here if you want to use the USB version of the Acecad Flair
tablet. Make sure to say Y to "Mouse support"
(CONFIG_INPUT_MOUSEDEV) and/or "Event interface support"
(CONFIG_INPUT_EVDEV) as well.
To compile this driver as a module, choose M here: the
module will be called acecad.
config USB_KBTAB config USB_KBTAB
tristate "KB Gear JamStudio tablet support" tristate "KB Gear JamStudio tablet support"
depends on USB && INPUT depends on USB && INPUT
@ -190,6 +202,18 @@ config USB_MTOUCH
To compile this driver as a module, choose M here: the To compile this driver as a module, choose M here: the
module will be called mtouchusb. module will be called mtouchusb.
config USB_ITMTOUCH
tristate "ITM Touch USB Touchscreen Driver"
depends on USB && INPUT
---help---
Say Y here if you want to use a ITM Touch USB
Touchscreen controller.
This touchscreen is used in LG 1510SF monitors.
To compile this driver as a module, choose M here: the
module will be called itmtouch.
config USB_EGALAX config USB_EGALAX
tristate "eGalax TouchKit USB Touchscreen Driver" tristate "eGalax TouchKit USB Touchscreen Driver"
depends on USB && INPUT depends on USB && INPUT

View file

@ -33,7 +33,9 @@ obj-$(CONFIG_USB_KBD) += usbkbd.o
obj-$(CONFIG_USB_KBTAB) += kbtab.o obj-$(CONFIG_USB_KBTAB) += kbtab.o
obj-$(CONFIG_USB_MOUSE) += usbmouse.o obj-$(CONFIG_USB_MOUSE) += usbmouse.o
obj-$(CONFIG_USB_MTOUCH) += mtouchusb.o obj-$(CONFIG_USB_MTOUCH) += mtouchusb.o
obj-$(CONFIG_USB_ITMTOUCH) += itmtouch.o
obj-$(CONFIG_USB_EGALAX) += touchkitusb.o obj-$(CONFIG_USB_EGALAX) += touchkitusb.o
obj-$(CONFIG_USB_POWERMATE) += powermate.o obj-$(CONFIG_USB_POWERMATE) += powermate.o
obj-$(CONFIG_USB_WACOM) += wacom.o obj-$(CONFIG_USB_WACOM) += wacom.o
obj-$(CONFIG_USB_ACECAD) += acecad.o
obj-$(CONFIG_USB_XPAD) += xpad.o obj-$(CONFIG_USB_XPAD) += xpad.o

285
drivers/usb/input/acecad.c Normal file
View file

@ -0,0 +1,285 @@
/*
* Copyright (c) 2001-2005 Edouard TISSERANT <edouard.tisserant@wanadoo.fr>
* Copyright (c) 2004-2005 Stephane VOLTZ <svoltz@numericable.fr>
*
* USB Acecad "Acecad Flair" tablet support
*
* Changelog:
* v3.2 - Added sysfs support
*/
/*
* 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
*
*/
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/input.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/usb.h>
/*
* Version Information
*/
#define DRIVER_VERSION "v3.2"
#define DRIVER_DESC "USB Acecad Flair tablet driver"
#define DRIVER_LICENSE "GPL"
#define DRIVER_AUTHOR "Edouard TISSERANT <edouard.tisserant@wanadoo.fr>"
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE(DRIVER_LICENSE);
#define USB_VENDOR_ID_ACECAD 0x0460
#define USB_DEVICE_ID_FLAIR 0x0004
#define USB_DEVICE_ID_302 0x0008
struct usb_acecad {
char name[128];
char phys[64];
struct usb_device *usbdev;
struct input_dev dev;
struct urb *irq;
signed char *data;
dma_addr_t data_dma;
};
static void usb_acecad_irq(struct urb *urb, struct pt_regs *regs)
{
struct usb_acecad *acecad = urb->context;
unsigned char *data = acecad->data;
struct input_dev *dev = &acecad->dev;
int prox, status;
switch (urb->status) {
case 0:
/* success */
break;
case -ECONNRESET:
case -ENOENT:
case -ESHUTDOWN:
/* this urb is terminated, clean up */
dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status);
return;
default:
dbg("%s - nonzero urb status received: %d", __FUNCTION__, urb->status);
goto resubmit;
}
prox = (data[0] & 0x04) >> 2;
input_report_key(dev, BTN_TOOL_PEN, prox);
if (prox) {
int x = data[1] | (data[2] << 8);
int y = data[3] | (data[4] << 8);
/*Pressure should compute the same way for flair and 302*/
int pressure = data[5] | ((int)data[6] << 8);
int touch = data[0] & 0x01;
int stylus = (data[0] & 0x10) >> 4;
int stylus2 = (data[0] & 0x20) >> 5;
input_report_abs(dev, ABS_X, x);
input_report_abs(dev, ABS_Y, y);
input_report_abs(dev, ABS_PRESSURE, pressure);
input_report_key(dev, BTN_TOUCH, touch);
input_report_key(dev, BTN_STYLUS, stylus);
input_report_key(dev, BTN_STYLUS2, stylus2);
}
/* event termination */
input_sync(dev);
resubmit:
status = usb_submit_urb (urb, GFP_ATOMIC);
if (status)
err ("can't resubmit intr, %s-%s/input0, status %d",
acecad->usbdev->bus->bus_name, acecad->usbdev->devpath, status);
}
static int usb_acecad_open(struct input_dev *dev)
{
struct usb_acecad *acecad = dev->private;
acecad->irq->dev = acecad->usbdev;
if (usb_submit_urb(acecad->irq, GFP_KERNEL))
return -EIO;
return 0;
}
static void usb_acecad_close(struct input_dev *dev)
{
struct usb_acecad *acecad = dev->private;
usb_kill_urb(acecad->irq);
}
static int usb_acecad_probe(struct usb_interface *intf, const struct usb_device_id *id)
{
struct usb_device *dev = interface_to_usbdev(intf);
struct usb_host_interface *interface = intf->cur_altsetting;
struct usb_endpoint_descriptor *endpoint;
struct usb_acecad *acecad;
int pipe, maxp;
char path[64];
if (interface->desc.bNumEndpoints != 1)
return -ENODEV;
endpoint = &interface->endpoint[0].desc;
if (!(endpoint->bEndpointAddress & 0x80))
return -ENODEV;
if ((endpoint->bmAttributes & 3) != 3)
return -ENODEV;
pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);
maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe));
acecad = kcalloc(1, sizeof(struct usb_acecad), GFP_KERNEL);
if (!acecad)
return -ENOMEM;
acecad->data = usb_buffer_alloc(dev, 8, SLAB_KERNEL, &acecad->data_dma);
if (!acecad->data)
goto fail1;
acecad->irq = usb_alloc_urb(0, GFP_KERNEL);
if (!acecad->irq)
goto fail2;
if (dev->manufacturer)
strlcpy(acecad->name, dev->manufacturer, sizeof(acecad->name));
if (dev->product) {
if (dev->manufacturer)
strlcat(acecad->name, " ", sizeof(acecad->name));
strlcat(acecad->name, dev->product, sizeof(acecad->name));
}
usb_make_path(dev, path, sizeof(path));
snprintf(acecad->phys, sizeof(acecad->phys), "%s/input0", path);
acecad->usbdev = dev;
acecad->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
acecad->dev.absbit[0] = BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE);
acecad->dev.keybit[LONG(BTN_LEFT)] = BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE);
acecad->dev.keybit[LONG(BTN_DIGI)] = BIT(BTN_TOOL_PEN) |BIT(BTN_TOUCH) | BIT(BTN_STYLUS) | BIT(BTN_STYLUS2);
switch (id->driver_info) {
case 0:
acecad->dev.absmax[ABS_X] = 5000;
acecad->dev.absmax[ABS_Y] = 3750;
acecad->dev.absmax[ABS_PRESSURE] = 512;
if (!strlen(acecad->name))
snprintf(acecad->name, sizeof(acecad->name),
"USB Acecad Flair Tablet %04x:%04x",
dev->descriptor.idVendor, dev->descriptor.idProduct);
break;
case 1:
acecad->dev.absmax[ABS_X] = 3000;
acecad->dev.absmax[ABS_Y] = 2250;
acecad->dev.absmax[ABS_PRESSURE] = 1024;
if (!strlen(acecad->name))
snprintf(acecad->name, sizeof(acecad->name),
"USB Acecad 302 Tablet %04x:%04x",
dev->descriptor.idVendor, dev->descriptor.idProduct);
break;
}
acecad->dev.absfuzz[ABS_X] = 4;
acecad->dev.absfuzz[ABS_Y] = 4;
acecad->dev.private = acecad;
acecad->dev.open = usb_acecad_open;
acecad->dev.close = usb_acecad_close;
acecad->dev.name = acecad->name;
acecad->dev.phys = acecad->phys;
acecad->dev.id.bustype = BUS_USB;
acecad->dev.id.vendor = le16_to_cpu(dev->descriptor.idVendor);
acecad->dev.id.product = le16_to_cpu(dev->descriptor.idProduct);
acecad->dev.id.version = le16_to_cpu(dev->descriptor.bcdDevice);
acecad->dev.dev = &intf->dev;
usb_fill_int_urb(acecad->irq, dev, pipe,
acecad->data, maxp > 8 ? 8 : maxp,
usb_acecad_irq, acecad, endpoint->bInterval);
acecad->irq->transfer_dma = acecad->data_dma;
acecad->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
input_register_device(&acecad->dev);
printk(KERN_INFO "input: %s with packet size %d on %s\n",
acecad->name, maxp, path);
usb_set_intfdata(intf, acecad);
return 0;
fail2: usb_buffer_free(dev, 8, acecad->data, acecad->data_dma);
fail1: kfree(acecad);
return -ENOMEM;
}
static void usb_acecad_disconnect(struct usb_interface *intf)
{
struct usb_acecad *acecad = usb_get_intfdata(intf);
usb_set_intfdata(intf, NULL);
if (acecad) {
usb_kill_urb(acecad->irq);
input_unregister_device(&acecad->dev);
usb_free_urb(acecad->irq);
usb_buffer_free(interface_to_usbdev(intf), 10, acecad->data, acecad->data_dma);
kfree(acecad);
}
}
static struct usb_device_id usb_acecad_id_table [] = {
{ USB_DEVICE(USB_VENDOR_ID_ACECAD, USB_DEVICE_ID_FLAIR), .driver_info = 0 },
{ USB_DEVICE(USB_VENDOR_ID_ACECAD, USB_DEVICE_ID_302), .driver_info = 1 },
{ }
};
MODULE_DEVICE_TABLE(usb, usb_acecad_id_table);
static struct usb_driver usb_acecad_driver = {
.owner = THIS_MODULE,
.name = "usb_acecad",
.probe = usb_acecad_probe,
.disconnect = usb_acecad_disconnect,
.id_table = usb_acecad_id_table,
};
static int __init usb_acecad_init(void)
{
int result = usb_register(&usb_acecad_driver);
if (result == 0)
info(DRIVER_VERSION ":" DRIVER_DESC);
return result;
}
static void __exit usb_acecad_exit(void)
{
usb_deregister(&usb_acecad_driver);
}
module_init(usb_acecad_init);
module_exit(usb_acecad_exit);

View file

@ -1,7 +1,7 @@
/* /*
* Native support for the Aiptek HyperPen USB Tablets * Native support for the Aiptek HyperPen USB Tablets
* (4000U/5000U/6000U/8000U/12000U) * (4000U/5000U/6000U/8000U/12000U)
* *
* Copyright (c) 2001 Chris Atenasio <chris@crud.net> * Copyright (c) 2001 Chris Atenasio <chris@crud.net>
* Copyright (c) 2002-2004 Bryan W. Headley <bwheadley@earthlink.net> * Copyright (c) 2002-2004 Bryan W. Headley <bwheadley@earthlink.net>
* *
@ -31,7 +31,7 @@
* - Added support for the sysfs interface, deprecating the * - Added support for the sysfs interface, deprecating the
* procfs interface for 2.5.x kernel. Also added support for * procfs interface for 2.5.x kernel. Also added support for
* Wheel command. Bryan W. Headley July-15-2003. * Wheel command. Bryan W. Headley July-15-2003.
* v1.2 - Reworked jitter timer as a kernel thread. * v1.2 - Reworked jitter timer as a kernel thread.
* Bryan W. Headley November-28-2003/Jan-10-2004. * Bryan W. Headley November-28-2003/Jan-10-2004.
* v1.3 - Repaired issue of kernel thread going nuts on single-processor * v1.3 - Repaired issue of kernel thread going nuts on single-processor
* machines, introduced programmableDelay as a command line * machines, introduced programmableDelay as a command line
@ -49,10 +49,10 @@
* NOTE: * NOTE:
* This kernel driver is augmented by the "Aiptek" XFree86 input * This kernel driver is augmented by the "Aiptek" XFree86 input
* driver for your X server, as well as the Gaiptek GUI Front-end * driver for your X server, as well as the Gaiptek GUI Front-end
* "Tablet Manager". * "Tablet Manager".
* These three products are highly interactive with one another, * These three products are highly interactive with one another,
* so therefore it's easier to document them all as one subsystem. * so therefore it's easier to document them all as one subsystem.
* Please visit the project's "home page", located at, * Please visit the project's "home page", located at,
* http://aiptektablet.sourceforge.net. * http://aiptektablet.sourceforge.net.
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
@ -156,7 +156,7 @@
* Command/Data Description Return Bytes Return Value * Command/Data Description Return Bytes Return Value
* 0x10/0x00 SwitchToMouse 0 * 0x10/0x00 SwitchToMouse 0
* 0x10/0x01 SwitchToTablet 0 * 0x10/0x01 SwitchToTablet 0
* 0x18/0x04 SetResolution 0 * 0x18/0x04 SetResolution 0
* 0x12/0xFF AutoGainOn 0 * 0x12/0xFF AutoGainOn 0
* 0x17/0x00 FilterOn 0 * 0x17/0x00 FilterOn 0
* 0x01/0x00 GetXExtension 2 MaxX * 0x01/0x00 GetXExtension 2 MaxX
@ -247,7 +247,7 @@
#define AIPTEK_DIAGNOSTIC_SENDING_ABSOLUTE_IN_RELATIVE 2 #define AIPTEK_DIAGNOSTIC_SENDING_ABSOLUTE_IN_RELATIVE 2
#define AIPTEK_DIAGNOSTIC_TOOL_DISALLOWED 3 #define AIPTEK_DIAGNOSTIC_TOOL_DISALLOWED 3
/* Time to wait (in ms) to help mask hand jittering /* Time to wait (in ms) to help mask hand jittering
* when pressing the stylus buttons. * when pressing the stylus buttons.
*/ */
#define AIPTEK_JITTER_DELAY_DEFAULT 50 #define AIPTEK_JITTER_DELAY_DEFAULT 50
@ -324,7 +324,6 @@ struct aiptek {
struct aiptek_settings curSetting; /* tablet's current programmable */ struct aiptek_settings curSetting; /* tablet's current programmable */
struct aiptek_settings newSetting; /* ... and new param settings */ struct aiptek_settings newSetting; /* ... and new param settings */
unsigned int ifnum; /* interface number for IO */ unsigned int ifnum; /* interface number for IO */
int openCount; /* module use counter */
int diagnostic; /* tablet diagnostic codes */ int diagnostic; /* tablet diagnostic codes */
unsigned long eventCount; /* event count */ unsigned long eventCount; /* event count */
int inDelay; /* jitter: in jitter delay? */ int inDelay; /* jitter: in jitter delay? */
@ -791,7 +790,7 @@ exit:
* specific Aiptek model numbers, because there has been overlaps, * specific Aiptek model numbers, because there has been overlaps,
* use, and reuse of id's in existing models. Certain models have * use, and reuse of id's in existing models. Certain models have
* been known to use more than one ID, indicative perhaps of * been known to use more than one ID, indicative perhaps of
* manufacturing revisions. In any event, we consider these * manufacturing revisions. In any event, we consider these
* IDs to not be model-specific nor unique. * IDs to not be model-specific nor unique.
*/ */
static const struct usb_device_id aiptek_ids[] = { static const struct usb_device_id aiptek_ids[] = {
@ -814,15 +813,9 @@ static int aiptek_open(struct input_dev *inputdev)
{ {
struct aiptek *aiptek = inputdev->private; struct aiptek *aiptek = inputdev->private;
if (aiptek->openCount++ > 0) {
return 0;
}
aiptek->urb->dev = aiptek->usbdev; aiptek->urb->dev = aiptek->usbdev;
if (usb_submit_urb(aiptek->urb, GFP_KERNEL) != 0) { if (usb_submit_urb(aiptek->urb, GFP_KERNEL) != 0)
aiptek->openCount--;
return -EIO; return -EIO;
}
return 0; return 0;
} }
@ -834,13 +827,11 @@ static void aiptek_close(struct input_dev *inputdev)
{ {
struct aiptek *aiptek = inputdev->private; struct aiptek *aiptek = inputdev->private;
if (--aiptek->openCount == 0) { usb_kill_urb(aiptek->urb);
usb_kill_urb(aiptek->urb);
}
} }
/*********************************************************************** /***********************************************************************
* aiptek_set_report and aiptek_get_report() are borrowed from Linux 2.4.x, * aiptek_set_report and aiptek_get_report() are borrowed from Linux 2.4.x,
* where they were known as usb_set_report and usb_get_report. * where they were known as usb_set_report and usb_get_report.
*/ */
static int static int
@ -2252,7 +2243,6 @@ static void aiptek_disconnect(struct usb_interface *intf)
AIPTEK_PACKET_LENGTH, AIPTEK_PACKET_LENGTH,
aiptek->data, aiptek->data_dma); aiptek->data, aiptek->data_dma);
kfree(aiptek); kfree(aiptek);
aiptek = NULL;
} }
} }

View file

@ -1,15 +1,15 @@
/* /*
* USB ATI Remote support * USB ATI Remote support
* *
* Version 2.2.0 Copyright (c) 2004 Torrey Hoffman <thoffman@arnor.net> * Version 2.2.0 Copyright (c) 2004 Torrey Hoffman <thoffman@arnor.net>
* Version 2.1.1 Copyright (c) 2002 Vladimir Dergachev * Version 2.1.1 Copyright (c) 2002 Vladimir Dergachev
* *
* This 2.2.0 version is a rewrite / cleanup of the 2.1.1 driver, including * This 2.2.0 version is a rewrite / cleanup of the 2.1.1 driver, including
* porting to the 2.6 kernel interfaces, along with other modification * porting to the 2.6 kernel interfaces, along with other modification
* to better match the style of the existing usb/input drivers. However, the * to better match the style of the existing usb/input drivers. However, the
* protocol and hardware handling is essentially unchanged from 2.1.1. * protocol and hardware handling is essentially unchanged from 2.1.1.
* *
* The 2.1.1 driver was derived from the usbati_remote and usbkbd drivers by * The 2.1.1 driver was derived from the usbati_remote and usbkbd drivers by
* Vojtech Pavlik. * Vojtech Pavlik.
* *
* Changes: * Changes:
@ -23,64 +23,64 @@
* Added support for the "Lola" remote contributed by: * Added support for the "Lola" remote contributed by:
* Seth Cohn <sethcohn@yahoo.com> * Seth Cohn <sethcohn@yahoo.com>
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* This program is free software; you can redistribute it and/or modify * 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 * 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. * (at your option) any later version.
* *
* This program is distributed in the hope that it will be useful, * This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * GNU General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* Hardware & software notes * Hardware & software notes
* *
* These remote controls are distributed by ATI as part of their * These remote controls are distributed by ATI as part of their
* "All-In-Wonder" video card packages. The receiver self-identifies as a * "All-In-Wonder" video card packages. The receiver self-identifies as a
* "USB Receiver" with manufacturer "X10 Wireless Technology Inc". * "USB Receiver" with manufacturer "X10 Wireless Technology Inc".
* *
* The "Lola" remote is available from X10. See: * The "Lola" remote is available from X10. See:
* http://www.x10.com/products/lola_sg1.htm * http://www.x10.com/products/lola_sg1.htm
* The Lola is similar to the ATI remote but has no mouse support, and slightly * The Lola is similar to the ATI remote but has no mouse support, and slightly
* different keys. * different keys.
* *
* It is possible to use multiple receivers and remotes on multiple computers * It is possible to use multiple receivers and remotes on multiple computers
* simultaneously by configuring them to use specific channels. * simultaneously by configuring them to use specific channels.
* *
* The RF protocol used by the remote supports 16 distinct channels, 1 to 16. * The RF protocol used by the remote supports 16 distinct channels, 1 to 16.
* Actually, it may even support more, at least in some revisions of the * Actually, it may even support more, at least in some revisions of the
* hardware. * hardware.
* *
* Each remote can be configured to transmit on one channel as follows: * Each remote can be configured to transmit on one channel as follows:
* - Press and hold the "hand icon" button. * - Press and hold the "hand icon" button.
* - When the red LED starts to blink, let go of the "hand icon" button. * - When the red LED starts to blink, let go of the "hand icon" button.
* - When it stops blinking, input the channel code as two digits, from 01 * - When it stops blinking, input the channel code as two digits, from 01
* to 16, and press the hand icon again. * to 16, and press the hand icon again.
* *
* The timing can be a little tricky. Try loading the module with debug=1 * The timing can be a little tricky. Try loading the module with debug=1
* to have the kernel print out messages about the remote control number * to have the kernel print out messages about the remote control number
* and mask. Note: debugging prints remote numbers as zero-based hexadecimal. * and mask. Note: debugging prints remote numbers as zero-based hexadecimal.
* *
* The driver has a "channel_mask" parameter. This bitmask specifies which * The driver has a "channel_mask" parameter. This bitmask specifies which
* channels will be ignored by the module. To mask out channels, just add * channels will be ignored by the module. To mask out channels, just add
* all the 2^channel_number values together. * all the 2^channel_number values together.
* *
* For instance, set channel_mask = 2^4 = 16 (binary 10000) to make ati_remote * For instance, set channel_mask = 2^4 = 16 (binary 10000) to make ati_remote
* ignore signals coming from remote controls transmitting on channel 4, but * ignore signals coming from remote controls transmitting on channel 4, but
* accept all other channels. * accept all other channels.
* *
* Or, set channel_mask = 65533, (0xFFFD), and all channels except 1 will be * Or, set channel_mask = 65533, (0xFFFD), and all channels except 1 will be
* ignored. * ignored.
* *
* The default is 0 (respond to all channels). Bit 0 and bits 17-32 of this * The default is 0 (respond to all channels). Bit 0 and bits 17-32 of this
* parameter are unused. * parameter are unused.
* *
*/ */
@ -99,13 +99,13 @@
/* /*
* Module and Version Information, Module Parameters * Module and Version Information, Module Parameters
*/ */
#define ATI_REMOTE_VENDOR_ID 0x0bc7 #define ATI_REMOTE_VENDOR_ID 0x0bc7
#define ATI_REMOTE_PRODUCT_ID 0x004 #define ATI_REMOTE_PRODUCT_ID 0x004
#define LOLA_REMOTE_PRODUCT_ID 0x002 #define LOLA_REMOTE_PRODUCT_ID 0x002
#define MEDION_REMOTE_PRODUCT_ID 0x006 #define MEDION_REMOTE_PRODUCT_ID 0x006
#define DRIVER_VERSION "2.2.1" #define DRIVER_VERSION "2.2.1"
#define DRIVER_AUTHOR "Torrey Hoffman <thoffman@arnor.net>" #define DRIVER_AUTHOR "Torrey Hoffman <thoffman@arnor.net>"
#define DRIVER_DESC "ATI/X10 RF USB Remote Control" #define DRIVER_DESC "ATI/X10 RF USB Remote Control"
@ -113,18 +113,18 @@
#define DATA_BUFSIZE 63 /* size of URB data buffers */ #define DATA_BUFSIZE 63 /* size of URB data buffers */
#define ATI_INPUTNUM 1 /* Which input device to register as */ #define ATI_INPUTNUM 1 /* Which input device to register as */
static unsigned long channel_mask = 0; static unsigned long channel_mask;
module_param(channel_mask, ulong, 0444); module_param(channel_mask, ulong, 0444);
MODULE_PARM_DESC(channel_mask, "Bitmask of remote control channels to ignore"); MODULE_PARM_DESC(channel_mask, "Bitmask of remote control channels to ignore");
static int debug = 0; static int debug;
module_param(debug, int, 0444); module_param(debug, int, 0444);
MODULE_PARM_DESC(debug, "Enable extra debug messages and information"); MODULE_PARM_DESC(debug, "Enable extra debug messages and information");
#define dbginfo(dev, format, arg...) do { if (debug) dev_info(dev , format , ## arg); } while (0) #define dbginfo(dev, format, arg...) do { if (debug) dev_info(dev , format , ## arg); } while (0)
#undef err #undef err
#define err(format, arg...) printk(KERN_ERR format , ## arg) #define err(format, arg...) printk(KERN_ERR format , ## arg)
static struct usb_device_id ati_remote_table[] = { static struct usb_device_id ati_remote_table[] = {
{ USB_DEVICE(ATI_REMOTE_VENDOR_ID, ATI_REMOTE_PRODUCT_ID) }, { USB_DEVICE(ATI_REMOTE_VENDOR_ID, ATI_REMOTE_PRODUCT_ID) },
{ USB_DEVICE(ATI_REMOTE_VENDOR_ID, LOLA_REMOTE_PRODUCT_ID) }, { USB_DEVICE(ATI_REMOTE_VENDOR_ID, LOLA_REMOTE_PRODUCT_ID) },
@ -148,7 +148,7 @@ static char init2[] = { 0x01, 0x00, 0x20, 0x14, 0x20, 0x20, 0x20 };
/* Acceleration curve for directional control pad */ /* Acceleration curve for directional control pad */
static char accel[] = { 1, 2, 4, 6, 9, 13, 20 }; static char accel[] = { 1, 2, 4, 6, 9, 13, 20 };
/* Duplicate event filtering time. /* Duplicate event filtering time.
* Sequential, identical KIND_FILTERED inputs with less than * Sequential, identical KIND_FILTERED inputs with less than
* FILTER_TIME jiffies between them are considered as repeat * FILTER_TIME jiffies between them are considered as repeat
* events. The hardware generates 5 events for the first keypress * events. The hardware generates 5 events for the first keypress
@ -161,10 +161,10 @@ static char accel[] = { 1, 2, 4, 6, 9, 13, 20 };
static DECLARE_MUTEX(disconnect_sem); static DECLARE_MUTEX(disconnect_sem);
struct ati_remote { struct ati_remote {
struct input_dev idev; struct input_dev idev;
struct usb_device *udev; struct usb_device *udev;
struct usb_interface *interface; struct usb_interface *interface;
struct urb *irq_urb; struct urb *irq_urb;
struct urb *out_urb; struct urb *out_urb;
struct usb_endpoint_descriptor *endpoint_in; struct usb_endpoint_descriptor *endpoint_in;
@ -174,13 +174,11 @@ struct ati_remote {
dma_addr_t inbuf_dma; dma_addr_t inbuf_dma;
dma_addr_t outbuf_dma; dma_addr_t outbuf_dma;
int open; /* open counter */
unsigned char old_data[2]; /* Detect duplicate events */ unsigned char old_data[2]; /* Detect duplicate events */
unsigned long old_jiffies; unsigned long old_jiffies;
unsigned long acc_jiffies; /* handle acceleration */ unsigned long acc_jiffies; /* handle acceleration */
unsigned int repeat_count; unsigned int repeat_count;
char name[NAME_BUFSIZE]; char name[NAME_BUFSIZE];
char phys[NAME_BUFSIZE]; char phys[NAME_BUFSIZE];
@ -206,14 +204,14 @@ static struct
int type; int type;
unsigned int code; unsigned int code;
int value; int value;
} ati_remote_tbl[] = } ati_remote_tbl[] =
{ {
/* Directional control pad axes */ /* Directional control pad axes */
{KIND_ACCEL, 0x35, 0x70, EV_REL, REL_X, -1}, /* left */ {KIND_ACCEL, 0x35, 0x70, EV_REL, REL_X, -1}, /* left */
{KIND_ACCEL, 0x36, 0x71, EV_REL, REL_X, 1}, /* right */ {KIND_ACCEL, 0x36, 0x71, EV_REL, REL_X, 1}, /* right */
{KIND_ACCEL, 0x37, 0x72, EV_REL, REL_Y, -1}, /* up */ {KIND_ACCEL, 0x37, 0x72, EV_REL, REL_Y, -1}, /* up */
{KIND_ACCEL, 0x38, 0x73, EV_REL, REL_Y, 1}, /* down */ {KIND_ACCEL, 0x38, 0x73, EV_REL, REL_Y, 1}, /* down */
/* Directional control pad diagonals */ /* Directional control pad diagonals */
{KIND_LU, 0x39, 0x74, EV_REL, 0, 0}, /* left up */ {KIND_LU, 0x39, 0x74, EV_REL, 0, 0}, /* left up */
{KIND_RU, 0x3a, 0x75, EV_REL, 0, 0}, /* right up */ {KIND_RU, 0x3a, 0x75, EV_REL, 0, 0}, /* right up */
{KIND_LD, 0x3c, 0x77, EV_REL, 0, 0}, /* left down */ {KIND_LD, 0x3c, 0x77, EV_REL, 0, 0}, /* left down */
@ -225,7 +223,7 @@ static struct
{KIND_LITERAL, 0x41, 0x7c, EV_KEY, BTN_RIGHT, 1},/* right btn down */ {KIND_LITERAL, 0x41, 0x7c, EV_KEY, BTN_RIGHT, 1},/* right btn down */
{KIND_LITERAL, 0x42, 0x7d, EV_KEY, BTN_RIGHT, 0},/* right btn up */ {KIND_LITERAL, 0x42, 0x7d, EV_KEY, BTN_RIGHT, 0},/* right btn up */
/* Artificial "doubleclick" events are generated by the hardware. /* Artificial "doubleclick" events are generated by the hardware.
* They are mapped to the "side" and "extra" mouse buttons here. */ * They are mapped to the "side" and "extra" mouse buttons here. */
{KIND_FILTERED, 0x3f, 0x7a, EV_KEY, BTN_SIDE, 1}, /* left dblclick */ {KIND_FILTERED, 0x3f, 0x7a, EV_KEY, BTN_SIDE, 1}, /* left dblclick */
{KIND_FILTERED, 0x43, 0x7e, EV_KEY, BTN_EXTRA, 1},/* right dblclick */ {KIND_FILTERED, 0x43, 0x7e, EV_KEY, BTN_EXTRA, 1},/* right dblclick */
@ -273,15 +271,15 @@ static struct
{KIND_FILTERED, 0xea, 0x25, EV_KEY, KEY_PLAY, 1}, /* ( >) */ {KIND_FILTERED, 0xea, 0x25, EV_KEY, KEY_PLAY, 1}, /* ( >) */
{KIND_FILTERED, 0xe9, 0x24, EV_KEY, KEY_REWIND, 1}, /* (<<) */ {KIND_FILTERED, 0xe9, 0x24, EV_KEY, KEY_REWIND, 1}, /* (<<) */
{KIND_FILTERED, 0xeb, 0x26, EV_KEY, KEY_FORWARD, 1}, /* (>>) */ {KIND_FILTERED, 0xeb, 0x26, EV_KEY, KEY_FORWARD, 1}, /* (>>) */
{KIND_FILTERED, 0xed, 0x28, EV_KEY, KEY_STOP, 1}, /* ([]) */ {KIND_FILTERED, 0xed, 0x28, EV_KEY, KEY_STOP, 1}, /* ([]) */
{KIND_FILTERED, 0xee, 0x29, EV_KEY, KEY_PAUSE, 1}, /* ('') */ {KIND_FILTERED, 0xee, 0x29, EV_KEY, KEY_PAUSE, 1}, /* ('') */
{KIND_FILTERED, 0xf0, 0x2b, EV_KEY, KEY_PREVIOUS, 1}, /* (<-) */ {KIND_FILTERED, 0xf0, 0x2b, EV_KEY, KEY_PREVIOUS, 1}, /* (<-) */
{KIND_FILTERED, 0xef, 0x2a, EV_KEY, KEY_NEXT, 1}, /* (>+) */ {KIND_FILTERED, 0xef, 0x2a, EV_KEY, KEY_NEXT, 1}, /* (>+) */
{KIND_FILTERED, 0xf2, 0x2D, EV_KEY, KEY_INFO, 1}, /* PLAYING */ {KIND_FILTERED, 0xf2, 0x2D, EV_KEY, KEY_INFO, 1}, /* PLAYING */
{KIND_FILTERED, 0xf3, 0x2E, EV_KEY, KEY_HOME, 1}, /* TOP */ {KIND_FILTERED, 0xf3, 0x2E, EV_KEY, KEY_HOME, 1}, /* TOP */
{KIND_FILTERED, 0xf4, 0x2F, EV_KEY, KEY_END, 1}, /* END */ {KIND_FILTERED, 0xf4, 0x2F, EV_KEY, KEY_END, 1}, /* END */
{KIND_FILTERED, 0xf5, 0x30, EV_KEY, KEY_SELECT, 1}, /* SELECT */ {KIND_FILTERED, 0xf5, 0x30, EV_KEY, KEY_SELECT, 1}, /* SELECT */
{KIND_END, 0x00, 0x00, EV_MAX + 1, 0, 0} {KIND_END, 0x00, 0x00, EV_MAX + 1, 0, 0}
}; };
@ -315,7 +313,7 @@ static void ati_remote_dump(unsigned char *data, unsigned int len)
if ((len == 1) && (data[0] != (unsigned char)0xff) && (data[0] != 0x00)) if ((len == 1) && (data[0] != (unsigned char)0xff) && (data[0] != 0x00))
warn("Weird byte 0x%02x", data[0]); warn("Weird byte 0x%02x", data[0]);
else if (len == 4) else if (len == 4)
warn("Weird key %02x %02x %02x %02x", warn("Weird key %02x %02x %02x %02x",
data[0], data[1], data[2], data[3]); data[0], data[1], data[2], data[3]);
else else
warn("Weird data, len=%d %02x %02x %02x %02x %02x %02x ...", warn("Weird data, len=%d %02x %02x %02x %02x %02x %02x ...",
@ -328,25 +326,16 @@ static void ati_remote_dump(unsigned char *data, unsigned int len)
static int ati_remote_open(struct input_dev *inputdev) static int ati_remote_open(struct input_dev *inputdev)
{ {
struct ati_remote *ati_remote = inputdev->private; struct ati_remote *ati_remote = inputdev->private;
int retval = 0;
down(&disconnect_sem);
if (ati_remote->open++)
goto exit;
/* On first open, submit the read urb which was set up previously. */ /* On first open, submit the read urb which was set up previously. */
ati_remote->irq_urb->dev = ati_remote->udev; ati_remote->irq_urb->dev = ati_remote->udev;
if (usb_submit_urb(ati_remote->irq_urb, GFP_KERNEL)) { if (usb_submit_urb(ati_remote->irq_urb, GFP_KERNEL)) {
dev_err(&ati_remote->interface->dev, dev_err(&ati_remote->interface->dev,
"%s: usb_submit_urb failed!\n", __FUNCTION__); "%s: usb_submit_urb failed!\n", __FUNCTION__);
ati_remote->open--; return -EIO;
retval = -EIO;
} }
exit: return 0;
up(&disconnect_sem);
return retval;
} }
/* /*
@ -355,9 +344,8 @@ exit:
static void ati_remote_close(struct input_dev *inputdev) static void ati_remote_close(struct input_dev *inputdev)
{ {
struct ati_remote *ati_remote = inputdev->private; struct ati_remote *ati_remote = inputdev->private;
if (!--ati_remote->open) usb_kill_urb(ati_remote->irq_urb);
usb_kill_urb(ati_remote->irq_urb);
} }
/* /*
@ -366,13 +354,13 @@ static void ati_remote_close(struct input_dev *inputdev)
static void ati_remote_irq_out(struct urb *urb, struct pt_regs *regs) static void ati_remote_irq_out(struct urb *urb, struct pt_regs *regs)
{ {
struct ati_remote *ati_remote = urb->context; struct ati_remote *ati_remote = urb->context;
if (urb->status) { if (urb->status) {
dev_dbg(&ati_remote->interface->dev, "%s: status %d\n", dev_dbg(&ati_remote->interface->dev, "%s: status %d\n",
__FUNCTION__, urb->status); __FUNCTION__, urb->status);
return; return;
} }
ati_remote->send_flags |= SEND_FLAG_COMPLETE; ati_remote->send_flags |= SEND_FLAG_COMPLETE;
wmb(); wmb();
wake_up(&ati_remote->wait); wake_up(&ati_remote->wait);
@ -380,16 +368,16 @@ static void ati_remote_irq_out(struct urb *urb, struct pt_regs *regs)
/* /*
* ati_remote_sendpacket * ati_remote_sendpacket
* *
* Used to send device initialization strings * Used to send device initialization strings
*/ */
static int ati_remote_sendpacket(struct ati_remote *ati_remote, u16 cmd, unsigned char *data) static int ati_remote_sendpacket(struct ati_remote *ati_remote, u16 cmd, unsigned char *data)
{ {
int retval = 0; int retval = 0;
/* Set up out_urb */ /* Set up out_urb */
memcpy(ati_remote->out_urb->transfer_buffer + 1, data, LO(cmd)); memcpy(ati_remote->out_urb->transfer_buffer + 1, data, LO(cmd));
((char *) ati_remote->out_urb->transfer_buffer)[0] = HI(cmd); ((char *) ati_remote->out_urb->transfer_buffer)[0] = HI(cmd);
ati_remote->out_urb->transfer_buffer_length = LO(cmd) + 1; ati_remote->out_urb->transfer_buffer_length = LO(cmd) + 1;
ati_remote->out_urb->dev = ati_remote->udev; ati_remote->out_urb->dev = ati_remote->udev;
@ -397,17 +385,17 @@ static int ati_remote_sendpacket(struct ati_remote *ati_remote, u16 cmd, unsigne
retval = usb_submit_urb(ati_remote->out_urb, GFP_ATOMIC); retval = usb_submit_urb(ati_remote->out_urb, GFP_ATOMIC);
if (retval) { if (retval) {
dev_dbg(&ati_remote->interface->dev, dev_dbg(&ati_remote->interface->dev,
"sendpacket: usb_submit_urb failed: %d\n", retval); "sendpacket: usb_submit_urb failed: %d\n", retval);
return retval; return retval;
} }
wait_event_timeout(ati_remote->wait, wait_event_timeout(ati_remote->wait,
((ati_remote->out_urb->status != -EINPROGRESS) || ((ati_remote->out_urb->status != -EINPROGRESS) ||
(ati_remote->send_flags & SEND_FLAG_COMPLETE)), (ati_remote->send_flags & SEND_FLAG_COMPLETE)),
HZ); HZ);
usb_kill_urb(ati_remote->out_urb); usb_kill_urb(ati_remote->out_urb);
return retval; return retval;
} }
@ -419,15 +407,15 @@ static int ati_remote_event_lookup(int rem, unsigned char d1, unsigned char d2)
int i; int i;
for (i = 0; ati_remote_tbl[i].kind != KIND_END; i++) { for (i = 0; ati_remote_tbl[i].kind != KIND_END; i++) {
/* /*
* Decide if the table entry matches the remote input. * Decide if the table entry matches the remote input.
*/ */
if ((((ati_remote_tbl[i].data1 & 0x0f) == (d1 & 0x0f))) && if ((((ati_remote_tbl[i].data1 & 0x0f) == (d1 & 0x0f))) &&
((((ati_remote_tbl[i].data1 >> 4) - ((((ati_remote_tbl[i].data1 >> 4) -
(d1 >> 4) + rem) & 0x0f) == 0x0f) && (d1 >> 4) + rem) & 0x0f) == 0x0f) &&
(ati_remote_tbl[i].data2 == d2)) (ati_remote_tbl[i].data2 == d2))
return i; return i;
} }
return -1; return -1;
} }
@ -435,16 +423,16 @@ static int ati_remote_event_lookup(int rem, unsigned char d1, unsigned char d2)
/* /*
* ati_remote_report_input * ati_remote_report_input
*/ */
static void ati_remote_input_report(struct urb *urb, struct pt_regs *regs) static void ati_remote_input_report(struct urb *urb, struct pt_regs *regs)
{ {
struct ati_remote *ati_remote = urb->context; struct ati_remote *ati_remote = urb->context;
unsigned char *data= ati_remote->inbuf; unsigned char *data= ati_remote->inbuf;
struct input_dev *dev = &ati_remote->idev; struct input_dev *dev = &ati_remote->idev;
int index, acc; int index, acc;
int remote_num; int remote_num;
/* Deal with strange looking inputs */ /* Deal with strange looking inputs */
if ( (urb->actual_length != 4) || (data[0] != 0x14) || if ( (urb->actual_length != 4) || (data[0] != 0x14) ||
((data[3] & 0x0f) != 0x00) ) { ((data[3] & 0x0f) != 0x00) ) {
ati_remote_dump(data, urb->actual_length); ati_remote_dump(data, urb->actual_length);
return; return;
@ -453,7 +441,7 @@ static void ati_remote_input_report(struct urb *urb, struct pt_regs *regs)
/* Mask unwanted remote channels. */ /* Mask unwanted remote channels. */
/* note: remote_num is 0-based, channel 1 on remote == 0 here */ /* note: remote_num is 0-based, channel 1 on remote == 0 here */
remote_num = (data[3] >> 4) & 0x0f; remote_num = (data[3] >> 4) & 0x0f;
if (channel_mask & (1 << (remote_num + 1))) { if (channel_mask & (1 << (remote_num + 1))) {
dbginfo(&ati_remote->interface->dev, dbginfo(&ati_remote->interface->dev,
"Masked input from channel 0x%02x: data %02x,%02x, mask= 0x%02lx\n", "Masked input from channel 0x%02x: data %02x,%02x, mask= 0x%02lx\n",
remote_num, data[1], data[2], channel_mask); remote_num, data[1], data[2], channel_mask);
@ -463,37 +451,36 @@ static void ati_remote_input_report(struct urb *urb, struct pt_regs *regs)
/* Look up event code index in translation table */ /* Look up event code index in translation table */
index = ati_remote_event_lookup(remote_num, data[1], data[2]); index = ati_remote_event_lookup(remote_num, data[1], data[2]);
if (index < 0) { if (index < 0) {
dev_warn(&ati_remote->interface->dev, dev_warn(&ati_remote->interface->dev,
"Unknown input from channel 0x%02x: data %02x,%02x\n", "Unknown input from channel 0x%02x: data %02x,%02x\n",
remote_num, data[1], data[2]); remote_num, data[1], data[2]);
return; return;
} }
dbginfo(&ati_remote->interface->dev, dbginfo(&ati_remote->interface->dev,
"channel 0x%02x; data %02x,%02x; index %d; keycode %d\n", "channel 0x%02x; data %02x,%02x; index %d; keycode %d\n",
remote_num, data[1], data[2], index, ati_remote_tbl[index].code); remote_num, data[1], data[2], index, ati_remote_tbl[index].code);
if (ati_remote_tbl[index].kind == KIND_LITERAL) { if (ati_remote_tbl[index].kind == KIND_LITERAL) {
input_regs(dev, regs); input_regs(dev, regs);
input_event(dev, ati_remote_tbl[index].type, input_event(dev, ati_remote_tbl[index].type,
ati_remote_tbl[index].code, ati_remote_tbl[index].code,
ati_remote_tbl[index].value); ati_remote_tbl[index].value);
input_sync(dev); input_sync(dev);
ati_remote->old_jiffies = jiffies; ati_remote->old_jiffies = jiffies;
return; return;
} }
if (ati_remote_tbl[index].kind == KIND_FILTERED) { if (ati_remote_tbl[index].kind == KIND_FILTERED) {
/* Filter duplicate events which happen "too close" together. */ /* Filter duplicate events which happen "too close" together. */
if ((ati_remote->old_data[0] == data[1]) && if ((ati_remote->old_data[0] == data[1]) &&
(ati_remote->old_data[1] == data[2]) && (ati_remote->old_data[1] == data[2]) &&
((ati_remote->old_jiffies + FILTER_TIME) > jiffies)) { ((ati_remote->old_jiffies + FILTER_TIME) > jiffies)) {
ati_remote->repeat_count++; ati_remote->repeat_count++;
} } else {
else {
ati_remote->repeat_count = 0; ati_remote->repeat_count = 0;
} }
ati_remote->old_data[0] = data[1]; ati_remote->old_data[0] = data[1];
ati_remote->old_data[1] = data[2]; ati_remote->old_data[1] = data[2];
ati_remote->old_jiffies = jiffies; ati_remote->old_jiffies = jiffies;
@ -501,7 +488,7 @@ static void ati_remote_input_report(struct urb *urb, struct pt_regs *regs)
if ((ati_remote->repeat_count > 0) if ((ati_remote->repeat_count > 0)
&& (ati_remote->repeat_count < 5)) && (ati_remote->repeat_count < 5))
return; return;
input_regs(dev, regs); input_regs(dev, regs);
input_event(dev, ati_remote_tbl[index].type, input_event(dev, ati_remote_tbl[index].type,
@ -511,13 +498,13 @@ static void ati_remote_input_report(struct urb *urb, struct pt_regs *regs)
input_sync(dev); input_sync(dev);
return; return;
} }
/* /*
* Other event kinds are from the directional control pad, and have an * Other event kinds are from the directional control pad, and have an
* acceleration factor applied to them. Without this acceleration, the * acceleration factor applied to them. Without this acceleration, the
* control pad is mostly unusable. * control pad is mostly unusable.
* *
* If elapsed time since last event is > 1/4 second, user "stopped", * If elapsed time since last event is > 1/4 second, user "stopped",
* so reset acceleration. Otherwise, user is probably holding the control * so reset acceleration. Otherwise, user is probably holding the control
* pad down, so we increase acceleration, ramping up over two seconds to * pad down, so we increase acceleration, ramping up over two seconds to
@ -559,7 +546,7 @@ static void ati_remote_input_report(struct urb *urb, struct pt_regs *regs)
input_report_rel(dev, REL_Y, acc); input_report_rel(dev, REL_Y, acc);
break; break;
default: default:
dev_dbg(&ati_remote->interface->dev, "ati_remote kind=%d\n", dev_dbg(&ati_remote->interface->dev, "ati_remote kind=%d\n",
ati_remote_tbl[index].kind); ati_remote_tbl[index].kind);
} }
input_sync(dev); input_sync(dev);
@ -586,12 +573,12 @@ static void ati_remote_irq_in(struct urb *urb, struct pt_regs *regs)
case -ESHUTDOWN: case -ESHUTDOWN:
dev_dbg(&ati_remote->interface->dev, "%s: urb error status, unlink? \n", dev_dbg(&ati_remote->interface->dev, "%s: urb error status, unlink? \n",
__FUNCTION__); __FUNCTION__);
return; return;
default: /* error */ default: /* error */
dev_dbg(&ati_remote->interface->dev, "%s: Nonzero urb status %d\n", dev_dbg(&ati_remote->interface->dev, "%s: Nonzero urb status %d\n",
__FUNCTION__, urb->status); __FUNCTION__, urb->status);
} }
retval = usb_submit_urb(urb, SLAB_ATOMIC); retval = usb_submit_urb(urb, SLAB_ATOMIC);
if (retval) if (retval)
dev_err(&ati_remote->interface->dev, "%s: usb_submit_urb()=%d\n", dev_err(&ati_remote->interface->dev, "%s: usb_submit_urb()=%d\n",
@ -603,8 +590,6 @@ static void ati_remote_irq_in(struct urb *urb, struct pt_regs *regs)
*/ */
static void ati_remote_delete(struct ati_remote *ati_remote) static void ati_remote_delete(struct ati_remote *ati_remote)
{ {
if (!ati_remote) return;
if (ati_remote->irq_urb) if (ati_remote->irq_urb)
usb_kill_urb(ati_remote->irq_urb); usb_kill_urb(ati_remote->irq_urb);
@ -614,16 +599,16 @@ static void ati_remote_delete(struct ati_remote *ati_remote)
input_unregister_device(&ati_remote->idev); input_unregister_device(&ati_remote->idev);
if (ati_remote->inbuf) if (ati_remote->inbuf)
usb_buffer_free(ati_remote->udev, DATA_BUFSIZE, usb_buffer_free(ati_remote->udev, DATA_BUFSIZE,
ati_remote->inbuf, ati_remote->inbuf_dma); ati_remote->inbuf, ati_remote->inbuf_dma);
if (ati_remote->outbuf) if (ati_remote->outbuf)
usb_buffer_free(ati_remote->udev, DATA_BUFSIZE, usb_buffer_free(ati_remote->udev, DATA_BUFSIZE,
ati_remote->outbuf, ati_remote->outbuf_dma); ati_remote->outbuf, ati_remote->outbuf_dma);
if (ati_remote->irq_urb) if (ati_remote->irq_urb)
usb_free_urb(ati_remote->irq_urb); usb_free_urb(ati_remote->irq_urb);
if (ati_remote->out_urb) if (ati_remote->out_urb)
usb_free_urb(ati_remote->out_urb); usb_free_urb(ati_remote->out_urb);
@ -636,21 +621,21 @@ static void ati_remote_input_init(struct ati_remote *ati_remote)
int i; int i;
idev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL); idev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
idev->keybit[LONG(BTN_MOUSE)] = ( BIT(BTN_LEFT) | BIT(BTN_RIGHT) | idev->keybit[LONG(BTN_MOUSE)] = ( BIT(BTN_LEFT) | BIT(BTN_RIGHT) |
BIT(BTN_SIDE) | BIT(BTN_EXTRA) ); BIT(BTN_SIDE) | BIT(BTN_EXTRA) );
idev->relbit[0] = BIT(REL_X) | BIT(REL_Y); idev->relbit[0] = BIT(REL_X) | BIT(REL_Y);
for (i = 0; ati_remote_tbl[i].kind != KIND_END; i++) for (i = 0; ati_remote_tbl[i].kind != KIND_END; i++)
if (ati_remote_tbl[i].type == EV_KEY) if (ati_remote_tbl[i].type == EV_KEY)
set_bit(ati_remote_tbl[i].code, idev->keybit); set_bit(ati_remote_tbl[i].code, idev->keybit);
idev->private = ati_remote; idev->private = ati_remote;
idev->open = ati_remote_open; idev->open = ati_remote_open;
idev->close = ati_remote_close; idev->close = ati_remote_close;
idev->name = ati_remote->name; idev->name = ati_remote->name;
idev->phys = ati_remote->phys; idev->phys = ati_remote->phys;
idev->id.bustype = BUS_USB; idev->id.bustype = BUS_USB;
idev->id.vendor = le16_to_cpu(ati_remote->udev->descriptor.idVendor); idev->id.vendor = le16_to_cpu(ati_remote->udev->descriptor.idVendor);
idev->id.product = le16_to_cpu(ati_remote->udev->descriptor.idProduct); idev->id.product = le16_to_cpu(ati_remote->udev->descriptor.idProduct);
idev->id.version = le16_to_cpu(ati_remote->udev->descriptor.bcdDevice); idev->id.version = le16_to_cpu(ati_remote->udev->descriptor.bcdDevice);
@ -660,27 +645,27 @@ static int ati_remote_initialize(struct ati_remote *ati_remote)
{ {
struct usb_device *udev = ati_remote->udev; struct usb_device *udev = ati_remote->udev;
int pipe, maxp; int pipe, maxp;
init_waitqueue_head(&ati_remote->wait); init_waitqueue_head(&ati_remote->wait);
/* Set up irq_urb */ /* Set up irq_urb */
pipe = usb_rcvintpipe(udev, ati_remote->endpoint_in->bEndpointAddress); pipe = usb_rcvintpipe(udev, ati_remote->endpoint_in->bEndpointAddress);
maxp = usb_maxpacket(udev, pipe, usb_pipeout(pipe)); maxp = usb_maxpacket(udev, pipe, usb_pipeout(pipe));
maxp = (maxp > DATA_BUFSIZE) ? DATA_BUFSIZE : maxp; maxp = (maxp > DATA_BUFSIZE) ? DATA_BUFSIZE : maxp;
usb_fill_int_urb(ati_remote->irq_urb, udev, pipe, ati_remote->inbuf, usb_fill_int_urb(ati_remote->irq_urb, udev, pipe, ati_remote->inbuf,
maxp, ati_remote_irq_in, ati_remote, maxp, ati_remote_irq_in, ati_remote,
ati_remote->endpoint_in->bInterval); ati_remote->endpoint_in->bInterval);
ati_remote->irq_urb->transfer_dma = ati_remote->inbuf_dma; ati_remote->irq_urb->transfer_dma = ati_remote->inbuf_dma;
ati_remote->irq_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; ati_remote->irq_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
/* Set up out_urb */ /* Set up out_urb */
pipe = usb_sndintpipe(udev, ati_remote->endpoint_out->bEndpointAddress); pipe = usb_sndintpipe(udev, ati_remote->endpoint_out->bEndpointAddress);
maxp = usb_maxpacket(udev, pipe, usb_pipeout(pipe)); maxp = usb_maxpacket(udev, pipe, usb_pipeout(pipe));
maxp = (maxp > DATA_BUFSIZE) ? DATA_BUFSIZE : maxp; maxp = (maxp > DATA_BUFSIZE) ? DATA_BUFSIZE : maxp;
usb_fill_int_urb(ati_remote->out_urb, udev, pipe, ati_remote->outbuf, usb_fill_int_urb(ati_remote->out_urb, udev, pipe, ati_remote->outbuf,
maxp, ati_remote_irq_out, ati_remote, maxp, ati_remote_irq_out, ati_remote,
ati_remote->endpoint_out->bInterval); ati_remote->endpoint_out->bInterval);
ati_remote->out_urb->transfer_dma = ati_remote->outbuf_dma; ati_remote->out_urb->transfer_dma = ati_remote->outbuf_dma;
ati_remote->out_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; ati_remote->out_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
@ -688,11 +673,11 @@ static int ati_remote_initialize(struct ati_remote *ati_remote)
/* send initialization strings */ /* send initialization strings */
if ((ati_remote_sendpacket(ati_remote, 0x8004, init1)) || if ((ati_remote_sendpacket(ati_remote, 0x8004, init1)) ||
(ati_remote_sendpacket(ati_remote, 0x8007, init2))) { (ati_remote_sendpacket(ati_remote, 0x8007, init2))) {
dev_err(&ati_remote->interface->dev, dev_err(&ati_remote->interface->dev,
"Initializing ati_remote hardware failed.\n"); "Initializing ati_remote hardware failed.\n");
return 1; return 1;
} }
return 0; return 0;
} }
@ -769,7 +754,7 @@ static int ati_remote_probe(struct usb_interface *interface, const struct usb_de
if (!strlen(ati_remote->name)) if (!strlen(ati_remote->name))
sprintf(ati_remote->name, DRIVER_DESC "(%04x,%04x)", sprintf(ati_remote->name, DRIVER_DESC "(%04x,%04x)",
le16_to_cpu(ati_remote->udev->descriptor.idVendor), le16_to_cpu(ati_remote->udev->descriptor.idVendor),
le16_to_cpu(ati_remote->udev->descriptor.idProduct)); le16_to_cpu(ati_remote->udev->descriptor.idProduct));
/* Device Hardware Initialization - fills in ati_remote->idev from udev. */ /* Device Hardware Initialization - fills in ati_remote->idev from udev. */
@ -781,11 +766,11 @@ static int ati_remote_probe(struct usb_interface *interface, const struct usb_de
ati_remote_input_init(ati_remote); ati_remote_input_init(ati_remote);
input_register_device(&ati_remote->idev); input_register_device(&ati_remote->idev);
dev_info(&ati_remote->interface->dev, "Input registered: %s on %s\n", dev_info(&ati_remote->interface->dev, "Input registered: %s on %s\n",
ati_remote->name, path); ati_remote->name, path);
usb_set_intfdata(interface, ati_remote); usb_set_intfdata(interface, ati_remote);
error: error:
if (retval) if (retval)
ati_remote_delete(ati_remote); ati_remote_delete(ati_remote);
@ -800,18 +785,14 @@ static void ati_remote_disconnect(struct usb_interface *interface)
{ {
struct ati_remote *ati_remote; struct ati_remote *ati_remote;
down(&disconnect_sem);
ati_remote = usb_get_intfdata(interface); ati_remote = usb_get_intfdata(interface);
usb_set_intfdata(interface, NULL); usb_set_intfdata(interface, NULL);
if (!ati_remote) { if (!ati_remote) {
warn("%s - null device?\n", __FUNCTION__); warn("%s - null device?\n", __FUNCTION__);
return; return;
} }
ati_remote_delete(ati_remote);
up(&disconnect_sem); ati_remote_delete(ati_remote);
} }
/* /*
@ -820,7 +801,7 @@ static void ati_remote_disconnect(struct usb_interface *interface)
static int __init ati_remote_init(void) static int __init ati_remote_init(void)
{ {
int result; int result;
result = usb_register(&ati_remote_driver); result = usb_register(&ati_remote_driver);
if (result) if (result)
err("usb_register error #%d\n", result); err("usb_register error #%d\n", result);
@ -838,8 +819,8 @@ static void __exit ati_remote_exit(void)
usb_deregister(&ati_remote_driver); usb_deregister(&ati_remote_driver);
} }
/* /*
* module specification * module specification
*/ */
module_init(ati_remote_init); module_init(ati_remote_init);

View file

@ -232,7 +232,7 @@ static int hid_add_field(struct hid_parser *parser, unsigned report_type, unsign
report->size += parser->global.report_size * parser->global.report_count; report->size += parser->global.report_size * parser->global.report_count;
if (!parser->local.usage_index) /* Ignore padding fields */ if (!parser->local.usage_index) /* Ignore padding fields */
return 0; return 0;
usages = max_t(int, parser->local.usage_index, parser->global.report_count); usages = max_t(int, parser->local.usage_index, parser->global.report_count);
@ -765,7 +765,7 @@ static __inline__ __u32 s32ton(__s32 value, unsigned n)
static __inline__ __u32 extract(__u8 *report, unsigned offset, unsigned n) static __inline__ __u32 extract(__u8 *report, unsigned offset, unsigned n)
{ {
report += (offset >> 5) << 2; offset &= 31; report += (offset >> 5) << 2; offset &= 31;
return (le64_to_cpu(get_unaligned((__le64*)report)) >> offset) & ((1 << n) - 1); return (le64_to_cpu(get_unaligned((__le64*)report)) >> offset) & ((1ULL << n) - 1);
} }
static __inline__ void implement(__u8 *report, unsigned offset, unsigned n, __u32 value) static __inline__ void implement(__u8 *report, unsigned offset, unsigned n, __u32 value)
@ -1233,6 +1233,13 @@ int hid_wait_io(struct hid_device *hid)
return 0; return 0;
} }
static int hid_set_idle(struct usb_device *dev, int ifnum, int report, int idle)
{
return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
HID_REQ_SET_IDLE, USB_TYPE_CLASS | USB_RECIP_INTERFACE, (idle << 8) | report,
ifnum, NULL, 0, USB_CTRL_SET_TIMEOUT);
}
static int hid_get_class_descriptor(struct usb_device *dev, int ifnum, static int hid_get_class_descriptor(struct usb_device *dev, int ifnum,
unsigned char type, void *buf, int size) unsigned char type, void *buf, int size)
{ {
@ -1301,10 +1308,6 @@ void hid_init_reports(struct hid_device *hid)
if (err) if (err)
warn("timeout initializing reports\n"); warn("timeout initializing reports\n");
usb_control_msg(hid->dev, usb_sndctrlpipe(hid->dev, 0),
HID_REQ_SET_IDLE, USB_TYPE_CLASS | USB_RECIP_INTERFACE, 0,
hid->ifnum, NULL, 0, USB_CTRL_SET_TIMEOUT);
} }
#define USB_VENDOR_ID_WACOM 0x056a #define USB_VENDOR_ID_WACOM 0x056a
@ -1318,6 +1321,10 @@ void hid_init_reports(struct hid_device *hid)
#define USB_DEVICE_ID_WACOM_INTUOS3 0x00B0 #define USB_DEVICE_ID_WACOM_INTUOS3 0x00B0
#define USB_DEVICE_ID_WACOM_CINTIQ 0x003F #define USB_DEVICE_ID_WACOM_CINTIQ 0x003F
#define USB_VENDOR_ID_ACECAD 0x0460
#define USB_DEVICE_ID_ACECAD_FLAIR 0x0004
#define USB_DEVICE_ID_ACECAD_302 0x0008
#define USB_VENDOR_ID_KBGEAR 0x084e #define USB_VENDOR_ID_KBGEAR 0x084e
#define USB_DEVICE_ID_KBGEAR_JAMSTUDIO 0x1001 #define USB_DEVICE_ID_KBGEAR_JAMSTUDIO 0x1001
@ -1502,6 +1509,9 @@ static struct hid_blacklist {
{ USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_4_PHIDGETSERVO_20, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_4_PHIDGETSERVO_20, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_1_PHIDGETSERVO_20, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_1_PHIDGETSERVO_20, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_ACECAD, USB_DEVICE_ID_ACECAD_FLAIR, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_ACECAD, USB_DEVICE_ID_ACECAD_302, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_UC100KM, HID_QUIRK_NOGET }, { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_UC100KM, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_CS124U, HID_QUIRK_NOGET }, { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_CS124U, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_2PORTKVM, HID_QUIRK_NOGET }, { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_2PORTKVM, HID_QUIRK_NOGET },
@ -1590,6 +1600,8 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf)
return NULL; return NULL;
} }
hid_set_idle(dev, interface->desc.bInterfaceNumber, 0, 0);
if ((n = hid_get_class_descriptor(dev, interface->desc.bInterfaceNumber, HID_DT_REPORT, rdesc, rsize)) < 0) { if ((n = hid_get_class_descriptor(dev, interface->desc.bInterfaceNumber, HID_DT_REPORT, rdesc, rsize)) < 0) {
dbg("reading report descriptor failed"); dbg("reading report descriptor failed");
kfree(rdesc); kfree(rdesc);
@ -1635,7 +1647,7 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf)
/* Change the polling interval of mice. */ /* Change the polling interval of mice. */
if (hid->collection->usage == HID_GD_MOUSE && hid_mousepoll_interval > 0) if (hid->collection->usage == HID_GD_MOUSE && hid_mousepoll_interval > 0)
interval = hid_mousepoll_interval; interval = hid_mousepoll_interval;
if (endpoint->bEndpointAddress & USB_DIR_IN) { if (endpoint->bEndpointAddress & USB_DIR_IN) {
if (hid->urbin) if (hid->urbin)
continue; continue;

View file

@ -67,7 +67,7 @@ static const struct hid_usage_entry hid_usage_table[] = {
{0, 0x44, "Vbry"}, {0, 0x44, "Vbry"},
{0, 0x45, "Vbrz"}, {0, 0x45, "Vbrz"},
{0, 0x46, "Vno"}, {0, 0x46, "Vno"},
{0, 0x80, "SystemControl"}, {0, 0x80, "SystemControl"},
{0, 0x81, "SystemPowerDown"}, {0, 0x81, "SystemPowerDown"},
{0, 0x82, "SystemSleep"}, {0, 0x82, "SystemSleep"},
{0, 0x83, "SystemWakeUp"}, {0, 0x83, "SystemWakeUp"},
@ -347,7 +347,7 @@ __inline__ static void tab(int n) {
static void hid_dump_field(struct hid_field *field, int n) { static void hid_dump_field(struct hid_field *field, int n) {
int j; int j;
if (field->physical) { if (field->physical) {
tab(n); tab(n);
printk("Physical("); printk("Physical(");
@ -408,7 +408,7 @@ static void hid_dump_field(struct hid_field *field, int n) {
printk("%s", units[sys][i]); printk("%s", units[sys][i]);
if(nibble != 1) { if(nibble != 1) {
/* This is a _signed_ nibble(!) */ /* This is a _signed_ nibble(!) */
int val = nibble & 0x7; int val = nibble & 0x7;
if(nibble & 0x08) if(nibble & 0x08)
val = -((0x7 & ~val) +1); val = -((0x7 & ~val) +1);
@ -443,7 +443,7 @@ static void __attribute__((unused)) hid_dump_device(struct hid_device *device) {
struct list_head *list; struct list_head *list;
unsigned i,k; unsigned i,k;
static char *table[] = {"INPUT", "OUTPUT", "FEATURE"}; static char *table[] = {"INPUT", "OUTPUT", "FEATURE"};
for (i = 0; i < HID_REPORT_TYPES; i++) { for (i = 0; i < HID_REPORT_TYPES; i++) {
report_enum = device->report_enum + i; report_enum = device->report_enum + i;
list = report_enum->report_list.next; list = report_enum->report_list.next;
@ -664,8 +664,8 @@ static char *keys[KEY_MAX + 1] = {
static char *relatives[REL_MAX + 1] = { static char *relatives[REL_MAX + 1] = {
[REL_X] = "X", [REL_Y] = "Y", [REL_X] = "X", [REL_Y] = "Y",
[REL_Z] = "Z", [REL_HWHEEL] = "HWheel", [REL_Z] = "Z", [REL_HWHEEL] = "HWheel",
[REL_DIAL] = "Dial", [REL_WHEEL] = "Wheel", [REL_DIAL] = "Dial", [REL_WHEEL] = "Wheel",
[REL_MISC] = "Misc", [REL_MISC] = "Misc",
}; };
static char *absolutes[ABS_MAX + 1] = { static char *absolutes[ABS_MAX + 1] = {
@ -690,9 +690,9 @@ static char *misc[MSC_MAX + 1] = {
}; };
static char *leds[LED_MAX + 1] = { static char *leds[LED_MAX + 1] = {
[LED_NUML] = "NumLock", [LED_CAPSL] = "CapsLock", [LED_NUML] = "NumLock", [LED_CAPSL] = "CapsLock",
[LED_SCROLLL] = "ScrollLock", [LED_COMPOSE] = "Compose", [LED_SCROLLL] = "ScrollLock", [LED_COMPOSE] = "Compose",
[LED_KANA] = "Kana", [LED_SLEEP] = "Sleep", [LED_KANA] = "Kana", [LED_SLEEP] = "Sleep",
[LED_SUSPEND] = "Suspend", [LED_MUTE] = "Mute", [LED_SUSPEND] = "Suspend", [LED_MUTE] = "Mute",
[LED_MISC] = "Misc", [LED_MISC] = "Misc",
}; };

View file

@ -164,7 +164,7 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
case HID_GD_X: case HID_GD_Y: case HID_GD_Z: case HID_GD_X: case HID_GD_Y: case HID_GD_Z:
case HID_GD_RX: case HID_GD_RY: case HID_GD_RZ: case HID_GD_RX: case HID_GD_RY: case HID_GD_RZ:
case HID_GD_SLIDER: case HID_GD_DIAL: case HID_GD_WHEEL: case HID_GD_SLIDER: case HID_GD_DIAL: case HID_GD_WHEEL:
if (field->flags & HID_MAIN_ITEM_RELATIVE) if (field->flags & HID_MAIN_ITEM_RELATIVE)
map_rel(usage->hid & 0xf); map_rel(usage->hid & 0xf);
else else
map_abs(usage->hid & 0xf); map_abs(usage->hid & 0xf);
@ -297,7 +297,7 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
case HID_UP_MSVENDOR: case HID_UP_MSVENDOR:
goto ignore; goto ignore;
case HID_UP_PID: case HID_UP_PID:
set_bit(EV_FF, input->evbit); set_bit(EV_FF, input->evbit);
@ -349,7 +349,7 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
goto ignore; goto ignore;
if ((device->quirks & (HID_QUIRK_2WHEEL_MOUSE_HACK_7 | HID_QUIRK_2WHEEL_MOUSE_HACK_5)) && if ((device->quirks & (HID_QUIRK_2WHEEL_MOUSE_HACK_7 | HID_QUIRK_2WHEEL_MOUSE_HACK_5)) &&
(usage->type == EV_REL) && (usage->code == REL_WHEEL)) (usage->type == EV_REL) && (usage->code == REL_WHEEL))
set_bit(REL_HWHEEL, bit); set_bit(REL_HWHEEL, bit);
if (((device->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_5) && (usage->hid == 0x00090005)) if (((device->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_5) && (usage->hid == 0x00090005))
@ -365,11 +365,11 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
a = field->logical_minimum = 0; a = field->logical_minimum = 0;
b = field->logical_maximum = 255; b = field->logical_maximum = 255;
} }
if (field->application == HID_GD_GAMEPAD || field->application == HID_GD_JOYSTICK) if (field->application == HID_GD_GAMEPAD || field->application == HID_GD_JOYSTICK)
input_set_abs_params(input, usage->code, a, b, (b - a) >> 8, (b - a) >> 4); input_set_abs_params(input, usage->code, a, b, (b - a) >> 8, (b - a) >> 4);
else input_set_abs_params(input, usage->code, a, b, 0, 0); else input_set_abs_params(input, usage->code, a, b, 0, 0);
} }
if (usage->hat_min < usage->hat_max || usage->hat_dir) { if (usage->hat_min < usage->hat_max || usage->hat_dir) {
@ -420,7 +420,7 @@ void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct
return; return;
} }
if (usage->hat_min < usage->hat_max || usage->hat_dir) { if (usage->hat_min < usage->hat_max || usage->hat_dir) {
int hat_dir = usage->hat_dir; int hat_dir = usage->hat_dir;
if (!hat_dir) if (!hat_dir)
hat_dir = (value - usage->hat_min) * 8 / (usage->hat_max - usage->hat_min + 1) + 1; hat_dir = (value - usage->hat_min) * 8 / (usage->hat_max - usage->hat_min + 1) + 1;
@ -551,7 +551,7 @@ int hidinput_connect(struct hid_device *hid)
for (i = 0; i < hid->maxcollection; i++) for (i = 0; i < hid->maxcollection; i++)
if (hid->collection[i].type == HID_COLLECTION_APPLICATION || if (hid->collection[i].type == HID_COLLECTION_APPLICATION ||
hid->collection[i].type == HID_COLLECTION_PHYSICAL) hid->collection[i].type == HID_COLLECTION_PHYSICAL)
if (IS_INPUT_APPLICATION(hid->collection[i].usage)) if (IS_INPUT_APPLICATION(hid->collection[i].usage))
break; break;
if (i == hid->maxcollection) if (i == hid->maxcollection)
@ -592,7 +592,7 @@ int hidinput_connect(struct hid_device *hid)
for (j = 0; j < report->field[i]->maxusage; j++) for (j = 0; j < report->field[i]->maxusage; j++)
hidinput_configure_usage(hidinput, report->field[i], hidinput_configure_usage(hidinput, report->field[i],
report->field[i]->usage + j); report->field[i]->usage + j);
if (hid->quirks & HID_QUIRK_MULTI_INPUT) { if (hid->quirks & HID_QUIRK_MULTI_INPUT) {
/* This will leave hidinput NULL, so that it /* This will leave hidinput NULL, so that it
* allocates another one if we have more inputs on * allocates another one if we have more inputs on

View file

@ -94,7 +94,7 @@ struct lgff_device {
isn't really necessary */ isn't really necessary */
unsigned long flags[1]; /* Contains various information about the unsigned long flags[1]; /* Contains various information about the
state of the driver for this device */ state of the driver for this device */
struct timer_list timer; struct timer_list timer;
}; };
@ -234,7 +234,7 @@ static struct hid_report* hid_lgff_duplicate_report(struct hid_report* report)
kfree(ret); kfree(ret);
return NULL; return NULL;
} }
memset(ret->field[0]->value, 0, sizeof(s32[8])); memset(ret->field[0]->value, 0, sizeof(s32[8]));
return ret; return ret;
} }
@ -295,11 +295,11 @@ static int hid_lgff_event(struct hid_device *hid, struct input_dev* input,
unsigned long flags; unsigned long flags;
if (type != EV_FF) return -EINVAL; if (type != EV_FF) return -EINVAL;
if (!LGFF_CHECK_OWNERSHIP(code, lgff)) return -EACCES; if (!LGFF_CHECK_OWNERSHIP(code, lgff)) return -EACCES;
if (value < 0) return -EINVAL; if (value < 0) return -EINVAL;
spin_lock_irqsave(&lgff->lock, flags); spin_lock_irqsave(&lgff->lock, flags);
if (value > 0) { if (value > 0) {
if (test_bit(EFFECT_STARTED, effect->flags)) { if (test_bit(EFFECT_STARTED, effect->flags)) {
spin_unlock_irqrestore(&lgff->lock, flags); spin_unlock_irqrestore(&lgff->lock, flags);
@ -345,7 +345,7 @@ static int hid_lgff_flush(struct input_dev *dev, struct file *file)
and perform ioctls on the same fd all at the same time */ and perform ioctls on the same fd all at the same time */
if ( current->pid == lgff->effects[i].owner if ( current->pid == lgff->effects[i].owner
&& test_bit(EFFECT_USED, lgff->effects[i].flags)) { && test_bit(EFFECT_USED, lgff->effects[i].flags)) {
if (hid_lgff_erase(dev, i)) if (hid_lgff_erase(dev, i))
warn("erase effect %d failed", i); warn("erase effect %d failed", i);
} }
@ -378,7 +378,7 @@ static int hid_lgff_upload_effect(struct input_dev* input,
struct lgff_effect new; struct lgff_effect new;
int id; int id;
unsigned long flags; unsigned long flags;
dbg("ioctl rumble"); dbg("ioctl rumble");
if (!test_bit(effect->type, input->ffbit)) return -EINVAL; if (!test_bit(effect->type, input->ffbit)) return -EINVAL;
@ -441,7 +441,7 @@ static void hid_lgff_timer(unsigned long timer_data)
spin_lock_irqsave(&lgff->lock, flags); spin_lock_irqsave(&lgff->lock, flags);
for (i=0; i<LGFF_EFFECTS; ++i) { for (i=0; i<LGFF_EFFECTS; ++i) {
struct lgff_effect* effect = lgff->effects +i; struct lgff_effect* effect = lgff->effects +i;
if (test_bit(EFFECT_PLAYING, effect->flags)) { if (test_bit(EFFECT_PLAYING, effect->flags)) {
@ -491,7 +491,7 @@ static void hid_lgff_timer(unsigned long timer_data)
set_bit(EFFECT_PLAYING, lgff->effects[i].flags); set_bit(EFFECT_PLAYING, lgff->effects[i].flags);
} }
} }
} }
#define CLAMP(x) if (x < 0) x = 0; if (x > 0xff) x = 0xff #define CLAMP(x) if (x < 0) x = 0; if (x > 0xff) x = 0xff
@ -524,5 +524,5 @@ static void hid_lgff_timer(unsigned long timer_data)
add_timer(&lgff->timer); add_timer(&lgff->timer);
} }
spin_unlock_irqrestore(&lgff->lock, flags); spin_unlock_irqrestore(&lgff->lock, flags);
} }

View file

@ -118,7 +118,7 @@ struct hid_item {
#define HID_MAIN_ITEM_CONSTANT 0x001 #define HID_MAIN_ITEM_CONSTANT 0x001
#define HID_MAIN_ITEM_VARIABLE 0x002 #define HID_MAIN_ITEM_VARIABLE 0x002
#define HID_MAIN_ITEM_RELATIVE 0x004 #define HID_MAIN_ITEM_RELATIVE 0x004
#define HID_MAIN_ITEM_WRAP 0x008 #define HID_MAIN_ITEM_WRAP 0x008
#define HID_MAIN_ITEM_NONLINEAR 0x010 #define HID_MAIN_ITEM_NONLINEAR 0x010
#define HID_MAIN_ITEM_NO_PREFERRED 0x020 #define HID_MAIN_ITEM_NO_PREFERRED 0x020
#define HID_MAIN_ITEM_NULL_STATE 0x040 #define HID_MAIN_ITEM_NULL_STATE 0x040
@ -172,14 +172,14 @@ struct hid_item {
#define HID_USAGE_PAGE 0xffff0000 #define HID_USAGE_PAGE 0xffff0000
#define HID_UP_UNDEFINED 0x00000000 #define HID_UP_UNDEFINED 0x00000000
#define HID_UP_GENDESK 0x00010000 #define HID_UP_GENDESK 0x00010000
#define HID_UP_KEYBOARD 0x00070000 #define HID_UP_KEYBOARD 0x00070000
#define HID_UP_LED 0x00080000 #define HID_UP_LED 0x00080000
#define HID_UP_BUTTON 0x00090000 #define HID_UP_BUTTON 0x00090000
#define HID_UP_ORDINAL 0x000a0000 #define HID_UP_ORDINAL 0x000a0000
#define HID_UP_CONSUMER 0x000c0000 #define HID_UP_CONSUMER 0x000c0000
#define HID_UP_DIGITIZER 0x000d0000 #define HID_UP_DIGITIZER 0x000d0000
#define HID_UP_PID 0x000f0000 #define HID_UP_PID 0x000f0000
#define HID_UP_HPVENDOR 0xff7f0000 #define HID_UP_HPVENDOR 0xff7f0000
#define HID_UP_MSVENDOR 0xff000000 #define HID_UP_MSVENDOR 0xff000000
@ -406,7 +406,7 @@ struct hid_device { /* device report descriptor */
dma_addr_t outbuf_dma; /* Output buffer dma */ dma_addr_t outbuf_dma; /* Output buffer dma */
spinlock_t outlock; /* Output fifo spinlock */ spinlock_t outlock; /* Output fifo spinlock */
unsigned claimed; /* Claimed by hidinput, hiddev? */ unsigned claimed; /* Claimed by hidinput, hiddev? */
unsigned quirks; /* Various quirks the device can pull on us */ unsigned quirks; /* Various quirks the device can pull on us */
struct list_head inputs; /* The list of inputs */ struct list_head inputs; /* The list of inputs */

View file

@ -95,7 +95,7 @@ hiddev_lookup_report(struct hid_device *hid, struct hiddev_report_info *rinfo)
return NULL; return NULL;
rinfo->report_id = ((struct hid_report *) list)->id; rinfo->report_id = ((struct hid_report *) list)->id;
break; break;
case HID_REPORT_ID_NEXT: case HID_REPORT_ID_NEXT:
list = (struct list_head *) list = (struct list_head *)
report_enum->report_id_hash[rinfo->report_id & HID_REPORT_ID_MASK]; report_enum->report_id_hash[rinfo->report_id & HID_REPORT_ID_MASK];
@ -106,7 +106,7 @@ hiddev_lookup_report(struct hid_device *hid, struct hiddev_report_info *rinfo)
return NULL; return NULL;
rinfo->report_id = ((struct hid_report *) list)->id; rinfo->report_id = ((struct hid_report *) list)->id;
break; break;
default: default:
return NULL; return NULL;
} }
@ -158,7 +158,7 @@ static void hiddev_send_event(struct hid_device *hid,
if (uref->field_index != HID_FIELD_INDEX_NONE || if (uref->field_index != HID_FIELD_INDEX_NONE ||
(list->flags & HIDDEV_FLAG_REPORT) != 0) { (list->flags & HIDDEV_FLAG_REPORT) != 0) {
list->buffer[list->head] = *uref; list->buffer[list->head] = *uref;
list->head = (list->head + 1) & list->head = (list->head + 1) &
(HIDDEV_BUFFER_SIZE - 1); (HIDDEV_BUFFER_SIZE - 1);
kill_fasync(&list->fasync, SIGIO, POLL_IN); kill_fasync(&list->fasync, SIGIO, POLL_IN);
} }
@ -179,9 +179,9 @@ void hiddev_hid_event(struct hid_device *hid, struct hid_field *field,
unsigned type = field->report_type; unsigned type = field->report_type;
struct hiddev_usage_ref uref; struct hiddev_usage_ref uref;
uref.report_type = uref.report_type =
(type == HID_INPUT_REPORT) ? HID_REPORT_TYPE_INPUT : (type == HID_INPUT_REPORT) ? HID_REPORT_TYPE_INPUT :
((type == HID_OUTPUT_REPORT) ? HID_REPORT_TYPE_OUTPUT : ((type == HID_OUTPUT_REPORT) ? HID_REPORT_TYPE_OUTPUT :
((type == HID_FEATURE_REPORT) ? HID_REPORT_TYPE_FEATURE:0)); ((type == HID_FEATURE_REPORT) ? HID_REPORT_TYPE_FEATURE:0));
uref.report_id = field->report->id; uref.report_id = field->report->id;
uref.field_index = field->index; uref.field_index = field->index;
@ -199,9 +199,9 @@ void hiddev_report_event(struct hid_device *hid, struct hid_report *report)
struct hiddev_usage_ref uref; struct hiddev_usage_ref uref;
memset(&uref, 0, sizeof(uref)); memset(&uref, 0, sizeof(uref));
uref.report_type = uref.report_type =
(type == HID_INPUT_REPORT) ? HID_REPORT_TYPE_INPUT : (type == HID_INPUT_REPORT) ? HID_REPORT_TYPE_INPUT :
((type == HID_OUTPUT_REPORT) ? HID_REPORT_TYPE_OUTPUT : ((type == HID_OUTPUT_REPORT) ? HID_REPORT_TYPE_OUTPUT :
((type == HID_FEATURE_REPORT) ? HID_REPORT_TYPE_FEATURE:0)); ((type == HID_FEATURE_REPORT) ? HID_REPORT_TYPE_FEATURE:0));
uref.report_id = report->id; uref.report_id = report->id;
uref.field_index = HID_FIELD_INDEX_NONE; uref.field_index = HID_FIELD_INDEX_NONE;
@ -236,7 +236,7 @@ static int hiddev_release(struct inode * inode, struct file * file)
*listptr = (*listptr)->next; *listptr = (*listptr)->next;
if (!--list->hiddev->open) { if (!--list->hiddev->open) {
if (list->hiddev->exist) if (list->hiddev->exist)
hid_close(list->hiddev->hid); hid_close(list->hiddev->hid);
else else
kfree(list->hiddev); kfree(list->hiddev);
@ -303,7 +303,7 @@ static ssize_t hiddev_read(struct file * file, char __user * buffer, size_t coun
if (list->head == list->tail) { if (list->head == list->tail) {
add_wait_queue(&list->hiddev->wait, &wait); add_wait_queue(&list->hiddev->wait, &wait);
set_current_state(TASK_INTERRUPTIBLE); set_current_state(TASK_INTERRUPTIBLE);
while (list->head == list->tail) { while (list->head == list->tail) {
if (file->f_flags & O_NONBLOCK) { if (file->f_flags & O_NONBLOCK) {
retval = -EAGAIN; retval = -EAGAIN;
@ -317,7 +317,7 @@ static ssize_t hiddev_read(struct file * file, char __user * buffer, size_t coun
retval = -EIO; retval = -EIO;
break; break;
} }
schedule(); schedule();
} }
@ -329,7 +329,7 @@ static ssize_t hiddev_read(struct file * file, char __user * buffer, size_t coun
return retval; return retval;
while (list->head != list->tail && while (list->head != list->tail &&
retval + event_size <= count) { retval + event_size <= count) {
if ((list->flags & HIDDEV_FLAG_UREF) == 0) { if ((list->flags & HIDDEV_FLAG_UREF) == 0) {
if (list->buffer[list->tail].field_index != if (list->buffer[list->tail].field_index !=
@ -405,10 +405,10 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd
return -EINVAL; return -EINVAL;
for (i = 0; i < hid->maxcollection; i++) for (i = 0; i < hid->maxcollection; i++)
if (hid->collection[i].type == if (hid->collection[i].type ==
HID_COLLECTION_APPLICATION && arg-- == 0) HID_COLLECTION_APPLICATION && arg-- == 0)
break; break;
if (i == hid->maxcollection) if (i == hid->maxcollection)
return -EINVAL; return -EINVAL;
@ -562,7 +562,7 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd
if (!uref_multi) if (!uref_multi)
return -ENOMEM; return -ENOMEM;
uref = &uref_multi->uref; uref = &uref_multi->uref;
if (copy_from_user(uref, user_arg, sizeof(*uref))) if (copy_from_user(uref, user_arg, sizeof(*uref)))
goto fault; goto fault;
rinfo.report_type = uref->report_type; rinfo.report_type = uref->report_type;
@ -595,7 +595,7 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd
return -ENOMEM; return -ENOMEM;
uref = &uref_multi->uref; uref = &uref_multi->uref;
if (cmd == HIDIOCGUSAGES || cmd == HIDIOCSUSAGES) { if (cmd == HIDIOCGUSAGES || cmd == HIDIOCSUSAGES) {
if (copy_from_user(uref_multi, user_arg, if (copy_from_user(uref_multi, user_arg,
sizeof(*uref_multi))) sizeof(*uref_multi)))
goto fault; goto fault;
} else { } else {
@ -603,7 +603,7 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd
goto fault; goto fault;
} }
if (cmd != HIDIOCGUSAGE && if (cmd != HIDIOCGUSAGE &&
cmd != HIDIOCGUSAGES && cmd != HIDIOCGUSAGES &&
uref->report_type == HID_REPORT_TYPE_INPUT) uref->report_type == HID_REPORT_TYPE_INPUT)
goto inval; goto inval;
@ -651,16 +651,16 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd
return field->usage[uref->usage_index].collection_index; return field->usage[uref->usage_index].collection_index;
case HIDIOCGUSAGES: case HIDIOCGUSAGES:
for (i = 0; i < uref_multi->num_values; i++) for (i = 0; i < uref_multi->num_values; i++)
uref_multi->values[i] = uref_multi->values[i] =
field->value[uref->usage_index + i]; field->value[uref->usage_index + i];
if (copy_to_user(user_arg, uref_multi, if (copy_to_user(user_arg, uref_multi,
sizeof(*uref_multi))) sizeof(*uref_multi)))
goto fault; goto fault;
goto goodreturn; goto goodreturn;
case HIDIOCSUSAGES: case HIDIOCSUSAGES:
for (i = 0; i < uref_multi->num_values; i++) for (i = 0; i < uref_multi->num_values; i++)
field->value[uref->usage_index + i] = field->value[uref->usage_index + i] =
uref_multi->values[i]; uref_multi->values[i];
goto goodreturn; goto goodreturn;
} }
@ -670,7 +670,7 @@ goodreturn:
fault: fault:
kfree(uref_multi); kfree(uref_multi);
return -EFAULT; return -EFAULT;
inval: inval:
kfree(uref_multi); kfree(uref_multi);
return -EINVAL; return -EINVAL;
@ -734,7 +734,7 @@ static struct usb_class_driver hiddev_class = {
.name = "usb/hid/hiddev%d", .name = "usb/hid/hiddev%d",
.fops = &hiddev_fops, .fops = &hiddev_fops,
.mode = S_IFCHR | S_IRUGO | S_IWUSR, .mode = S_IFCHR | S_IRUGO | S_IWUSR,
.minor_base = HIDDEV_MINOR_BASE, .minor_base = HIDDEV_MINOR_BASE,
}; };
/* /*
@ -747,7 +747,7 @@ int hiddev_connect(struct hid_device *hid)
int retval; int retval;
for (i = 0; i < hid->maxcollection; i++) for (i = 0; i < hid->maxcollection; i++)
if (hid->collection[i].type == if (hid->collection[i].type ==
HID_COLLECTION_APPLICATION && HID_COLLECTION_APPLICATION &&
!IS_INPUT_APPLICATION(hid->collection[i].usage)) !IS_INPUT_APPLICATION(hid->collection[i].usage))
break; break;
@ -755,11 +755,11 @@ int hiddev_connect(struct hid_device *hid)
if (i == hid->maxcollection && (hid->quirks & HID_QUIRK_HIDDEV) == 0) if (i == hid->maxcollection && (hid->quirks & HID_QUIRK_HIDDEV) == 0)
return -1; return -1;
if (!(hiddev = kmalloc(sizeof(struct hiddev), GFP_KERNEL))) if (!(hiddev = kmalloc(sizeof(struct hiddev), GFP_KERNEL)))
return -1; return -1;
memset(hiddev, 0, sizeof(struct hiddev)); memset(hiddev, 0, sizeof(struct hiddev));
retval = usb_register_dev(hid->intf, &hiddev_class); retval = usb_register_dev(hid->intf, &hiddev_class);
if (retval) { if (retval) {
err("Not able to get a minor for this device."); err("Not able to get a minor for this device.");
kfree(hiddev); kfree(hiddev);
@ -768,12 +768,12 @@ int hiddev_connect(struct hid_device *hid)
init_waitqueue_head(&hiddev->wait); init_waitqueue_head(&hiddev->wait);
hiddev_table[hid->intf->minor - HIDDEV_MINOR_BASE] = hiddev; hiddev_table[hid->intf->minor - HIDDEV_MINOR_BASE] = hiddev;
hiddev->hid = hid; hiddev->hid = hid;
hiddev->exist = 1; hiddev->exist = 1;
hid->minor = hid->intf->minor; hid->minor = hid->intf->minor;
hid->hiddev = hiddev; hid->hiddev = hiddev;
return 0; return 0;
@ -818,7 +818,7 @@ void hiddev_disconnect(struct hid_device *hid)
/* We never attach in this manner, and rely on HID to connect us. This /* We never attach in this manner, and rely on HID to connect us. This
* is why there is no disconnect routine defined in the usb_driver either. * is why there is no disconnect routine defined in the usb_driver either.
*/ */
static int hiddev_usbd_probe(struct usb_interface *intf, static int hiddev_usbd_probe(struct usb_interface *intf,
const struct usb_device_id *hiddev_info) const struct usb_device_id *hiddev_info)
{ {
return -ENODEV; return -ENODEV;

View file

@ -0,0 +1,268 @@
/******************************************************************************
* itmtouch.c -- Driver for ITM touchscreen panel
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* Based upon original work by Chris Collins <xfire-itmtouch@xware.cx>.
*
* Kudos to ITM for providing me with the datasheet for the panel,
* even though it was a day later than I had finished writing this
* driver.
*
* It has meant that I've been able to correct my interpretation of the
* protocol packets however.
*
* CC -- 2003/9/29
*
* History
* 1.0 & 1.1 2003 (CC) vojtech@suse.cz
* Original version for 2.4.x kernels
*
* 1.2 02/03/2005 (HCE) hc@mivu.no
* Complete rewrite to support Linux 2.6.10, thanks to mtouchusb.c for hints.
* Unfortunately no calibration support at this time.
*
* 1.2.1 09/03/2005 (HCE) hc@mivu.no
* Code cleanup and adjusting syntax to start matching kernel standards
*
*****************************************************************************/
#include <linux/config.h>
#ifdef CONFIG_USB_DEBUG
#define DEBUG
#else
#undef DEBUG
#endif
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/input.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/usb.h>
/* only an 8 byte buffer necessary for a single packet */
#define ITM_BUFSIZE 8
#define PATH_SIZE 64
#define USB_VENDOR_ID_ITMINC 0x0403
#define USB_PRODUCT_ID_TOUCHPANEL 0xf9e9
#define DRIVER_AUTHOR "Hans-Christian Egtvedt <hc@mivu.no>"
#define DRIVER_VERSION "v1.2.1"
#define DRIVER_DESC "USB ITM Inc Touch Panel Driver"
#define DRIVER_LICENSE "GPL"
MODULE_AUTHOR( DRIVER_AUTHOR );
MODULE_DESCRIPTION( DRIVER_DESC );
MODULE_LICENSE( DRIVER_LICENSE );
struct itmtouch_dev {
struct usb_device *usbdev; /* usb device */
struct input_dev inputdev; /* input device */
struct urb *readurb; /* urb */
char rbuf[ITM_BUFSIZE]; /* data */
int users;
char name[128];
char phys[64];
};
static struct usb_device_id itmtouch_ids [] = {
{ USB_DEVICE(USB_VENDOR_ID_ITMINC, USB_PRODUCT_ID_TOUCHPANEL) },
{ }
};
static void itmtouch_irq(struct urb *urb, struct pt_regs *regs)
{
struct itmtouch_dev * itmtouch = urb->context;
unsigned char *data = urb->transfer_buffer;
struct input_dev *dev = &itmtouch->inputdev;
int retval;
switch (urb->status) {
case 0:
/* success */
break;
case -ETIMEDOUT:
/* this urb is timing out */
dbg("%s - urb timed out - was the device unplugged?",
__FUNCTION__);
return;
case -ECONNRESET:
case -ENOENT:
case -ESHUTDOWN:
/* this urb is terminated, clean up */
dbg("%s - urb shutting down with status: %d",
__FUNCTION__, urb->status);
return;
default:
dbg("%s - nonzero urb status received: %d",
__FUNCTION__, urb->status);
goto exit;
}
input_regs(dev, regs);
/* if pressure has been released, then don't report X/Y */
if (data[7] & 0x20) {
input_report_abs(dev, ABS_X, (data[0] & 0x1F) << 7 | (data[3] & 0x7F));
input_report_abs(dev, ABS_Y, (data[1] & 0x1F) << 7 | (data[4] & 0x7F));
}
input_report_abs(dev, ABS_PRESSURE, (data[2] & 1) << 7 | (data[5] & 0x7F));
input_report_key(dev, BTN_TOUCH, ~data[7] & 0x20);
input_sync(dev);
exit:
retval = usb_submit_urb (urb, GFP_ATOMIC);
if (retval)
printk(KERN_ERR "%s - usb_submit_urb failed with result: %d",
__FUNCTION__, retval);
}
static int itmtouch_open(struct input_dev *input)
{
struct itmtouch_dev *itmtouch = input->private;
itmtouch->readurb->dev = itmtouch->usbdev;
if (usb_submit_urb(itmtouch->readurb, GFP_KERNEL))
return -EIO;
return 0;
}
static void itmtouch_close(struct input_dev *input)
{
struct itmtouch_dev *itmtouch = input->private;
usb_kill_urb(itmtouch->readurb);
}
static int itmtouch_probe(struct usb_interface *intf, const struct usb_device_id *id)
{
struct itmtouch_dev *itmtouch;
struct usb_host_interface *interface;
struct usb_endpoint_descriptor *endpoint;
struct usb_device *udev = interface_to_usbdev(intf);
unsigned int pipe;
unsigned int maxp;
char path[PATH_SIZE];
interface = intf->cur_altsetting;
endpoint = &interface->endpoint[0].desc;
if (!(itmtouch = kcalloc(1, sizeof(struct itmtouch_dev), GFP_KERNEL))) {
err("%s - Out of memory.", __FUNCTION__);
return -ENOMEM;
}
itmtouch->usbdev = udev;
itmtouch->inputdev.private = itmtouch;
itmtouch->inputdev.open = itmtouch_open;
itmtouch->inputdev.close = itmtouch_close;
usb_make_path(udev, path, PATH_SIZE);
itmtouch->inputdev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
itmtouch->inputdev.absbit[0] = BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE);
itmtouch->inputdev.keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH);
itmtouch->inputdev.name = itmtouch->name;
itmtouch->inputdev.phys = itmtouch->phys;
itmtouch->inputdev.id.bustype = BUS_USB;
itmtouch->inputdev.id.vendor = udev->descriptor.idVendor;
itmtouch->inputdev.id.product = udev->descriptor.idProduct;
itmtouch->inputdev.id.version = udev->descriptor.bcdDevice;
itmtouch->inputdev.dev = &intf->dev;
if (!strlen(itmtouch->name))
sprintf(itmtouch->name, "USB ITM touchscreen");
/* device limits */
/* as specified by the ITM datasheet, X and Y are 12bit,
* Z (pressure) is 8 bit. However, the fields are defined up
* to 14 bits for future possible expansion.
*/
input_set_abs_params(&itmtouch->inputdev, ABS_X, 0, 0x0FFF, 2, 0);
input_set_abs_params(&itmtouch->inputdev, ABS_Y, 0, 0x0FFF, 2, 0);
input_set_abs_params(&itmtouch->inputdev, ABS_PRESSURE, 0, 0xFF, 2, 0);
/* initialise the URB so we can read from the transport stream */
pipe = usb_rcvintpipe(itmtouch->usbdev, endpoint->bEndpointAddress);
maxp = usb_maxpacket(udev, pipe, usb_pipeout(pipe));
if (maxp > ITM_BUFSIZE)
maxp = ITM_BUFSIZE;
itmtouch->readurb = usb_alloc_urb(0, GFP_KERNEL);
if (!itmtouch->readurb) {
dbg("%s - usb_alloc_urb failed: itmtouch->readurb", __FUNCTION__);
kfree(itmtouch);
return -ENOMEM;
}
usb_fill_int_urb(itmtouch->readurb, itmtouch->usbdev, pipe, itmtouch->rbuf,
maxp, itmtouch_irq, itmtouch, endpoint->bInterval);
input_register_device(&itmtouch->inputdev);
printk(KERN_INFO "itmtouch: %s registered on %s\n", itmtouch->name, path);
usb_set_intfdata(intf, itmtouch);
return 0;
}
static void itmtouch_disconnect(struct usb_interface *intf)
{
struct itmtouch_dev *itmtouch = usb_get_intfdata(intf);
usb_set_intfdata(intf, NULL);
if (itmtouch) {
input_unregister_device(&itmtouch->inputdev);
usb_kill_urb(itmtouch->readurb);
usb_free_urb(itmtouch->readurb);
kfree(itmtouch);
}
}
MODULE_DEVICE_TABLE(usb, itmtouch_ids);
static struct usb_driver itmtouch_driver = {
.owner = THIS_MODULE,
.name = "itmtouch",
.probe = itmtouch_probe,
.disconnect = itmtouch_disconnect,
.id_table = itmtouch_ids,
};
static int __init itmtouch_init(void)
{
info(DRIVER_DESC " " DRIVER_VERSION);
info(DRIVER_AUTHOR);
return usb_register(&itmtouch_driver);
}
static void __exit itmtouch_exit(void)
{
usb_deregister(&itmtouch_driver);
}
module_init(itmtouch_init);
module_exit(itmtouch_exit);

View file

@ -36,7 +36,6 @@ struct kbtab {
struct input_dev dev; struct input_dev dev;
struct usb_device *usbdev; struct usb_device *usbdev;
struct urb *irq; struct urb *irq;
int open;
int x, y; int x, y;
int button; int button;
int pressure; int pressure;
@ -79,12 +78,12 @@ static void kbtab_irq(struct urb *urb, struct pt_regs *regs)
/*input_report_key(dev, BTN_TOUCH , data[0] & 0x01);*/ /*input_report_key(dev, BTN_TOUCH , data[0] & 0x01);*/
input_report_key(dev, BTN_RIGHT, data[0] & 0x02); input_report_key(dev, BTN_RIGHT, data[0] & 0x02);
if( -1 == kb_pressure_click){ if (-1 == kb_pressure_click) {
input_report_abs(dev, ABS_PRESSURE, kbtab->pressure); input_report_abs(dev, ABS_PRESSURE, kbtab->pressure);
} else { } else {
input_report_key(dev, BTN_LEFT, (kbtab->pressure > kb_pressure_click) ? 1 : 0); input_report_key(dev, BTN_LEFT, (kbtab->pressure > kb_pressure_click) ? 1 : 0);
}; };
input_sync(dev); input_sync(dev);
exit: exit:
@ -105,14 +104,9 @@ static int kbtab_open(struct input_dev *dev)
{ {
struct kbtab *kbtab = dev->private; struct kbtab *kbtab = dev->private;
if (kbtab->open++)
return 0;
kbtab->irq->dev = kbtab->usbdev; kbtab->irq->dev = kbtab->usbdev;
if (usb_submit_urb(kbtab->irq, GFP_KERNEL)) { if (usb_submit_urb(kbtab->irq, GFP_KERNEL))
kbtab->open--;
return -EIO; return -EIO;
}
return 0; return 0;
} }
@ -121,8 +115,7 @@ static void kbtab_close(struct input_dev *dev)
{ {
struct kbtab *kbtab = dev->private; struct kbtab *kbtab = dev->private;
if (!--kbtab->open) usb_kill_urb(kbtab->irq);
usb_kill_urb(kbtab->irq);
} }
static int kbtab_probe(struct usb_interface *intf, const struct usb_device_id *id) static int kbtab_probe(struct usb_interface *intf, const struct usb_device_id *id)
@ -161,7 +154,7 @@ static int kbtab_probe(struct usb_interface *intf, const struct usb_device_id *i
kbtab->dev.absmax[ABS_X] = 0x2000; kbtab->dev.absmax[ABS_X] = 0x2000;
kbtab->dev.absmax[ABS_Y] = 0x1750; kbtab->dev.absmax[ABS_Y] = 0x1750;
kbtab->dev.absmax[ABS_PRESSURE] = 0xff; kbtab->dev.absmax[ABS_PRESSURE] = 0xff;
kbtab->dev.absfuzz[ABS_X] = 4; kbtab->dev.absfuzz[ABS_X] = 4;
kbtab->dev.absfuzz[ABS_Y] = 4; kbtab->dev.absfuzz[ABS_Y] = 4;

View file

@ -42,9 +42,9 @@
#include <linux/config.h> #include <linux/config.h>
#ifdef CONFIG_USB_DEBUG #ifdef CONFIG_USB_DEBUG
#define DEBUG #define DEBUG
#else #else
#undef DEBUG #undef DEBUG
#endif #endif
#include <linux/kernel.h> #include <linux/kernel.h>
@ -93,275 +93,255 @@ module_param(raw_coordinates, bool, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(raw_coordinates, "report raw coordinate values (y, default) or hardware-calibrated coordinate values (n)"); MODULE_PARM_DESC(raw_coordinates, "report raw coordinate values (y, default) or hardware-calibrated coordinate values (n)");
struct mtouch_usb { struct mtouch_usb {
unsigned char *data; unsigned char *data;
dma_addr_t data_dma; dma_addr_t data_dma;
struct urb *irq; struct urb *irq;
struct usb_device *udev; struct usb_device *udev;
struct input_dev input; struct input_dev input;
int open; char name[128];
char name[128]; char phys[64];
char phys[64];
}; };
static struct usb_device_id mtouchusb_devices [] = { static struct usb_device_id mtouchusb_devices[] = {
{ USB_DEVICE(0x0596, 0x0001) }, { USB_DEVICE(0x0596, 0x0001) },
{ } { }
}; };
static void mtouchusb_irq(struct urb *urb, struct pt_regs *regs) static void mtouchusb_irq(struct urb *urb, struct pt_regs *regs)
{ {
struct mtouch_usb *mtouch = urb->context; struct mtouch_usb *mtouch = urb->context;
int retval; int retval;
switch (urb->status) { switch (urb->status) {
case 0: case 0:
/* success */ /* success */
break; break;
case -ETIMEDOUT: case -ETIMEDOUT:
/* this urb is timing out */ /* this urb is timing out */
dbg("%s - urb timed out - was the device unplugged?", dbg("%s - urb timed out - was the device unplugged?",
__FUNCTION__); __FUNCTION__);
return; return;
case -ECONNRESET: case -ECONNRESET:
case -ENOENT: case -ENOENT:
case -ESHUTDOWN: case -ESHUTDOWN:
/* this urb is terminated, clean up */ /* this urb is terminated, clean up */
dbg("%s - urb shutting down with status: %d", dbg("%s - urb shutting down with status: %d",
__FUNCTION__, urb->status); __FUNCTION__, urb->status);
return; return;
default: default:
dbg("%s - nonzero urb status received: %d", dbg("%s - nonzero urb status received: %d",
__FUNCTION__, urb->status); __FUNCTION__, urb->status);
goto exit; goto exit;
} }
input_regs(&mtouch->input, regs); input_regs(&mtouch->input, regs);
input_report_key(&mtouch->input, BTN_TOUCH, input_report_key(&mtouch->input, BTN_TOUCH,
MTOUCHUSB_GET_TOUCHED(mtouch->data)); MTOUCHUSB_GET_TOUCHED(mtouch->data));
input_report_abs(&mtouch->input, ABS_X, input_report_abs(&mtouch->input, ABS_X, MTOUCHUSB_GET_XC(mtouch->data));
MTOUCHUSB_GET_XC(mtouch->data)); input_report_abs(&mtouch->input, ABS_Y,
input_report_abs(&mtouch->input, ABS_Y,
(raw_coordinates ? MTOUCHUSB_MAX_RAW_YC : MTOUCHUSB_MAX_CALIB_YC) (raw_coordinates ? MTOUCHUSB_MAX_RAW_YC : MTOUCHUSB_MAX_CALIB_YC)
- MTOUCHUSB_GET_YC(mtouch->data)); - MTOUCHUSB_GET_YC(mtouch->data));
input_sync(&mtouch->input); input_sync(&mtouch->input);
exit: exit:
retval = usb_submit_urb (urb, GFP_ATOMIC); retval = usb_submit_urb(urb, GFP_ATOMIC);
if (retval) if (retval)
err ("%s - usb_submit_urb failed with result: %d", err("%s - usb_submit_urb failed with result: %d",
__FUNCTION__, retval); __FUNCTION__, retval);
} }
static int mtouchusb_open (struct input_dev *input) static int mtouchusb_open(struct input_dev *input)
{ {
struct mtouch_usb *mtouch = input->private; struct mtouch_usb *mtouch = input->private;
if (mtouch->open++) mtouch->irq->dev = mtouch->udev;
return 0;
mtouch->irq->dev = mtouch->udev; if (usb_submit_urb(mtouch->irq, GFP_ATOMIC))
return -EIO;
if (usb_submit_urb (mtouch->irq, GFP_ATOMIC)) { return 0;
mtouch->open--;
return -EIO;
}
return 0;
} }
static void mtouchusb_close (struct input_dev *input) static void mtouchusb_close(struct input_dev *input)
{ {
struct mtouch_usb *mtouch = input->private; struct mtouch_usb *mtouch = input->private;
if (!--mtouch->open) usb_kill_urb(mtouch->irq);
usb_kill_urb (mtouch->irq);
} }
static int mtouchusb_alloc_buffers(struct usb_device *udev, struct mtouch_usb *mtouch) static int mtouchusb_alloc_buffers(struct usb_device *udev, struct mtouch_usb *mtouch)
{ {
dbg("%s - called", __FUNCTION__); dbg("%s - called", __FUNCTION__);
mtouch->data = usb_buffer_alloc(udev, MTOUCHUSB_REPORT_DATA_SIZE, mtouch->data = usb_buffer_alloc(udev, MTOUCHUSB_REPORT_DATA_SIZE,
SLAB_ATOMIC, &mtouch->data_dma); SLAB_ATOMIC, &mtouch->data_dma);
if (!mtouch->data) if (!mtouch->data)
return -1; return -1;
return 0; return 0;
} }
static void mtouchusb_free_buffers(struct usb_device *udev, struct mtouch_usb *mtouch) static void mtouchusb_free_buffers(struct usb_device *udev, struct mtouch_usb *mtouch)
{ {
dbg("%s - called", __FUNCTION__); dbg("%s - called", __FUNCTION__);
if (mtouch->data) if (mtouch->data)
usb_buffer_free(udev, MTOUCHUSB_REPORT_DATA_SIZE, usb_buffer_free(udev, MTOUCHUSB_REPORT_DATA_SIZE,
mtouch->data, mtouch->data_dma); mtouch->data, mtouch->data_dma);
} }
static int mtouchusb_probe(struct usb_interface *intf, const struct usb_device_id *id) static int mtouchusb_probe(struct usb_interface *intf, const struct usb_device_id *id)
{ {
struct mtouch_usb *mtouch; struct mtouch_usb *mtouch;
struct usb_host_interface *interface; struct usb_host_interface *interface;
struct usb_endpoint_descriptor *endpoint; struct usb_endpoint_descriptor *endpoint;
struct usb_device *udev = interface_to_usbdev (intf); struct usb_device *udev = interface_to_usbdev(intf);
char path[64]; char path[64];
int nRet; int nRet;
dbg("%s - called", __FUNCTION__); dbg("%s - called", __FUNCTION__);
dbg("%s - setting interface", __FUNCTION__); dbg("%s - setting interface", __FUNCTION__);
interface = intf->cur_altsetting; interface = intf->cur_altsetting;
dbg("%s - setting endpoint", __FUNCTION__); dbg("%s - setting endpoint", __FUNCTION__);
endpoint = &interface->endpoint[0].desc; endpoint = &interface->endpoint[0].desc;
if (!(mtouch = kmalloc (sizeof (struct mtouch_usb), GFP_KERNEL))) { if (!(mtouch = kmalloc(sizeof(struct mtouch_usb), GFP_KERNEL))) {
err("%s - Out of memory.", __FUNCTION__); err("%s - Out of memory.", __FUNCTION__);
return -ENOMEM; return -ENOMEM;
} }
memset(mtouch, 0, sizeof(struct mtouch_usb)); memset(mtouch, 0, sizeof(struct mtouch_usb));
mtouch->udev = udev; mtouch->udev = udev;
dbg("%s - allocating buffers", __FUNCTION__); dbg("%s - allocating buffers", __FUNCTION__);
if (mtouchusb_alloc_buffers(udev, mtouch)) { if (mtouchusb_alloc_buffers(udev, mtouch)) {
mtouchusb_free_buffers(udev, mtouch); mtouchusb_free_buffers(udev, mtouch);
kfree(mtouch); kfree(mtouch);
return -ENOMEM; return -ENOMEM;
} }
mtouch->input.private = mtouch; mtouch->input.private = mtouch;
mtouch->input.open = mtouchusb_open; mtouch->input.open = mtouchusb_open;
mtouch->input.close = mtouchusb_close; mtouch->input.close = mtouchusb_close;
usb_make_path(udev, path, 64); usb_make_path(udev, path, 64);
sprintf(mtouch->phys, "%s/input0", path); sprintf(mtouch->phys, "%s/input0", path);
mtouch->input.name = mtouch->name; mtouch->input.name = mtouch->name;
mtouch->input.phys = mtouch->phys; mtouch->input.phys = mtouch->phys;
mtouch->input.id.bustype = BUS_USB; mtouch->input.id.bustype = BUS_USB;
mtouch->input.id.vendor = le16_to_cpu(udev->descriptor.idVendor); mtouch->input.id.vendor = le16_to_cpu(udev->descriptor.idVendor);
mtouch->input.id.product = le16_to_cpu(udev->descriptor.idProduct); mtouch->input.id.product = le16_to_cpu(udev->descriptor.idProduct);
mtouch->input.id.version = le16_to_cpu(udev->descriptor.bcdDevice); mtouch->input.id.version = le16_to_cpu(udev->descriptor.bcdDevice);
mtouch->input.dev = &intf->dev; mtouch->input.dev = &intf->dev;
mtouch->input.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); mtouch->input.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
mtouch->input.absbit[0] = BIT(ABS_X) | BIT(ABS_Y); mtouch->input.absbit[0] = BIT(ABS_X) | BIT(ABS_Y);
mtouch->input.keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH); mtouch->input.keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH);
/* Used to Scale Compensated Data and Flip Y */ /* Used to Scale Compensated Data and Flip Y */
mtouch->input.absmin[ABS_X] = MTOUCHUSB_MIN_XC; mtouch->input.absmin[ABS_X] = MTOUCHUSB_MIN_XC;
mtouch->input.absmax[ABS_X] = raw_coordinates ? \ mtouch->input.absmax[ABS_X] = raw_coordinates ?
MTOUCHUSB_MAX_RAW_XC : MTOUCHUSB_MAX_CALIB_XC; MTOUCHUSB_MAX_RAW_XC : MTOUCHUSB_MAX_CALIB_XC;
mtouch->input.absfuzz[ABS_X] = MTOUCHUSB_XC_FUZZ; mtouch->input.absfuzz[ABS_X] = MTOUCHUSB_XC_FUZZ;
mtouch->input.absflat[ABS_X] = MTOUCHUSB_XC_FLAT; mtouch->input.absflat[ABS_X] = MTOUCHUSB_XC_FLAT;
mtouch->input.absmin[ABS_Y] = MTOUCHUSB_MIN_YC; mtouch->input.absmin[ABS_Y] = MTOUCHUSB_MIN_YC;
mtouch->input.absmax[ABS_Y] = raw_coordinates ? \ mtouch->input.absmax[ABS_Y] = raw_coordinates ?
MTOUCHUSB_MAX_RAW_YC : MTOUCHUSB_MAX_CALIB_YC; MTOUCHUSB_MAX_RAW_YC : MTOUCHUSB_MAX_CALIB_YC;
mtouch->input.absfuzz[ABS_Y] = MTOUCHUSB_YC_FUZZ; mtouch->input.absfuzz[ABS_Y] = MTOUCHUSB_YC_FUZZ;
mtouch->input.absflat[ABS_Y] = MTOUCHUSB_YC_FLAT; mtouch->input.absflat[ABS_Y] = MTOUCHUSB_YC_FLAT;
if (udev->manufacturer) if (udev->manufacturer)
strcat(mtouch->name, udev->manufacturer); strcat(mtouch->name, udev->manufacturer);
if (udev->product) if (udev->product)
sprintf(mtouch->name, "%s %s", mtouch->name, udev->product); sprintf(mtouch->name, "%s %s", mtouch->name, udev->product);
if (!strlen(mtouch->name)) if (!strlen(mtouch->name))
sprintf(mtouch->name, "USB Touchscreen %04x:%04x", sprintf(mtouch->name, "USB Touchscreen %04x:%04x",
mtouch->input.id.vendor, mtouch->input.id.product); mtouch->input.id.vendor, mtouch->input.id.product);
nRet = usb_control_msg(mtouch->udev, nRet = usb_control_msg(mtouch->udev, usb_rcvctrlpipe(udev, 0),
usb_rcvctrlpipe(udev, 0), MTOUCHUSB_RESET,
MTOUCHUSB_RESET, USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, 1, 0, NULL, 0, USB_CTRL_SET_TIMEOUT);
1, dbg("%s - usb_control_msg - MTOUCHUSB_RESET - bytes|err: %d",
0, __FUNCTION__, nRet);
NULL,
0,
USB_CTRL_SET_TIMEOUT);
dbg("%s - usb_control_msg - MTOUCHUSB_RESET - bytes|err: %d",
__FUNCTION__, nRet);
dbg("%s - usb_alloc_urb: mtouch->irq", __FUNCTION__); dbg("%s - usb_alloc_urb: mtouch->irq", __FUNCTION__);
mtouch->irq = usb_alloc_urb(0, GFP_KERNEL); mtouch->irq = usb_alloc_urb(0, GFP_KERNEL);
if (!mtouch->irq) { if (!mtouch->irq) {
dbg("%s - usb_alloc_urb failed: mtouch->irq", __FUNCTION__); dbg("%s - usb_alloc_urb failed: mtouch->irq", __FUNCTION__);
mtouchusb_free_buffers(udev, mtouch); mtouchusb_free_buffers(udev, mtouch);
kfree(mtouch); kfree(mtouch);
return -ENOMEM; return -ENOMEM;
} }
dbg("%s - usb_fill_int_urb", __FUNCTION__); dbg("%s - usb_fill_int_urb", __FUNCTION__);
usb_fill_int_urb(mtouch->irq, usb_fill_int_urb(mtouch->irq, mtouch->udev,
mtouch->udev, usb_rcvintpipe(mtouch->udev, 0x81),
usb_rcvintpipe(mtouch->udev, 0x81), mtouch->data, MTOUCHUSB_REPORT_DATA_SIZE,
mtouch->data, mtouchusb_irq, mtouch, endpoint->bInterval);
MTOUCHUSB_REPORT_DATA_SIZE,
mtouchusb_irq,
mtouch,
endpoint->bInterval);
dbg("%s - input_register_device", __FUNCTION__); dbg("%s - input_register_device", __FUNCTION__);
input_register_device(&mtouch->input); input_register_device(&mtouch->input);
nRet = usb_control_msg(mtouch->udev, nRet = usb_control_msg(mtouch->udev, usb_rcvctrlpipe(udev, 0),
usb_rcvctrlpipe(udev, 0), MTOUCHUSB_ASYNC_REPORT,
MTOUCHUSB_ASYNC_REPORT, USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, 1, 1, NULL, 0, USB_CTRL_SET_TIMEOUT);
1, dbg("%s - usb_control_msg - MTOUCHUSB_ASYNC_REPORT - bytes|err: %d",
1, __FUNCTION__, nRet);
NULL,
0,
USB_CTRL_SET_TIMEOUT);
dbg("%s - usb_control_msg - MTOUCHUSB_ASYNC_REPORT - bytes|err: %d",
__FUNCTION__, nRet);
printk(KERN_INFO "input: %s on %s\n", mtouch->name, path); printk(KERN_INFO "input: %s on %s\n", mtouch->name, path);
usb_set_intfdata(intf, mtouch); usb_set_intfdata(intf, mtouch);
return 0; return 0;
} }
static void mtouchusb_disconnect(struct usb_interface *intf) static void mtouchusb_disconnect(struct usb_interface *intf)
{ {
struct mtouch_usb *mtouch = usb_get_intfdata (intf); struct mtouch_usb *mtouch = usb_get_intfdata(intf);
dbg("%s - called", __FUNCTION__); dbg("%s - called", __FUNCTION__);
usb_set_intfdata(intf, NULL); usb_set_intfdata(intf, NULL);
if (mtouch) { if (mtouch) {
dbg("%s - mtouch is initialized, cleaning up", __FUNCTION__); dbg("%s - mtouch is initialized, cleaning up", __FUNCTION__);
usb_kill_urb(mtouch->irq); usb_kill_urb(mtouch->irq);
input_unregister_device(&mtouch->input); input_unregister_device(&mtouch->input);
usb_free_urb(mtouch->irq); usb_free_urb(mtouch->irq);
mtouchusb_free_buffers(interface_to_usbdev(intf), mtouch); mtouchusb_free_buffers(interface_to_usbdev(intf), mtouch);
kfree(mtouch); kfree(mtouch);
} }
} }
MODULE_DEVICE_TABLE (usb, mtouchusb_devices); MODULE_DEVICE_TABLE(usb, mtouchusb_devices);
static struct usb_driver mtouchusb_driver = { static struct usb_driver mtouchusb_driver = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.name = "mtouchusb", .name = "mtouchusb",
.probe = mtouchusb_probe, .probe = mtouchusb_probe,
.disconnect = mtouchusb_disconnect, .disconnect = mtouchusb_disconnect,
.id_table = mtouchusb_devices, .id_table = mtouchusb_devices,
}; };
static int __init mtouchusb_init(void) { static int __init mtouchusb_init(void)
dbg("%s - called", __FUNCTION__); {
return usb_register(&mtouchusb_driver); dbg("%s - called", __FUNCTION__);
return usb_register(&mtouchusb_driver);
} }
static void __exit mtouchusb_cleanup(void) { static void __exit mtouchusb_cleanup(void)
dbg("%s - called", __FUNCTION__); {
usb_deregister(&mtouchusb_driver); dbg("%s - called", __FUNCTION__);
usb_deregister(&mtouchusb_driver);
} }
module_init(mtouchusb_init); module_init(mtouchusb_init);
module_exit(mtouchusb_cleanup); module_exit(mtouchusb_cleanup);
MODULE_AUTHOR( DRIVER_AUTHOR ); MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION( DRIVER_DESC ); MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");

View file

@ -10,7 +10,7 @@
* back to the host when polled by the USB controller. * back to the host when polled by the USB controller.
* *
* Testing with the knob I have has shown that it measures approximately 94 "clicks" * Testing with the knob I have has shown that it measures approximately 94 "clicks"
* for one full rotation. Testing with my High Speed Rotation Actuator (ok, it was * for one full rotation. Testing with my High Speed Rotation Actuator (ok, it was
* a variable speed cordless electric drill) has shown that the device can measure * a variable speed cordless electric drill) has shown that the device can measure
* speeds of up to 7 clicks either clockwise or anticlockwise between pollings from * speeds of up to 7 clicks either clockwise or anticlockwise between pollings from
* the host. If it counts more than 7 clicks before it is polled, it will wrap back * the host. If it counts more than 7 clicks before it is polled, it will wrap back
@ -120,9 +120,9 @@ exit:
/* Decide if we need to issue a control message and do so. Must be called with pm->lock taken */ /* Decide if we need to issue a control message and do so. Must be called with pm->lock taken */
static void powermate_sync_state(struct powermate_device *pm) static void powermate_sync_state(struct powermate_device *pm)
{ {
if (pm->requires_update == 0) if (pm->requires_update == 0)
return; /* no updates are required */ return; /* no updates are required */
if (pm->config->status == -EINPROGRESS) if (pm->config->status == -EINPROGRESS)
return; /* an update is already in progress; it'll issue this update when it completes */ return; /* an update is already in progress; it'll issue this update when it completes */
if (pm->requires_update & UPDATE_PULSE_ASLEEP){ if (pm->requires_update & UPDATE_PULSE_ASLEEP){
@ -142,7 +142,7 @@ static void powermate_sync_state(struct powermate_device *pm)
2: multiply the speed 2: multiply the speed
the argument only has an effect for operations 0 and 2, and ranges between the argument only has an effect for operations 0 and 2, and ranges between
1 (least effect) to 255 (maximum effect). 1 (least effect) to 255 (maximum effect).
thus, several states are equivalent and are coalesced into one state. thus, several states are equivalent and are coalesced into one state.
we map this onto a range from 0 to 510, with: we map this onto a range from 0 to 510, with:
@ -151,7 +151,7 @@ static void powermate_sync_state(struct powermate_device *pm)
256 -- 510 -- use multiple (510 = fastest). 256 -- 510 -- use multiple (510 = fastest).
Only values of 'arg' quite close to 255 are particularly useful/spectacular. Only values of 'arg' quite close to 255 are particularly useful/spectacular.
*/ */
if (pm->pulse_speed < 255){ if (pm->pulse_speed < 255){
op = 0; // divide op = 0; // divide
arg = 255 - pm->pulse_speed; arg = 255 - pm->pulse_speed;
@ -199,14 +199,14 @@ static void powermate_config_complete(struct urb *urb, struct pt_regs *regs)
if (urb->status) if (urb->status)
printk(KERN_ERR "powermate: config urb returned %d\n", urb->status); printk(KERN_ERR "powermate: config urb returned %d\n", urb->status);
spin_lock_irqsave(&pm->lock, flags); spin_lock_irqsave(&pm->lock, flags);
powermate_sync_state(pm); powermate_sync_state(pm);
spin_unlock_irqrestore(&pm->lock, flags); spin_unlock_irqrestore(&pm->lock, flags);
} }
/* Set the LED up as described and begin the sync with the hardware if required */ /* Set the LED up as described and begin the sync with the hardware if required */
static void powermate_pulse_led(struct powermate_device *pm, int static_brightness, int pulse_speed, static void powermate_pulse_led(struct powermate_device *pm, int static_brightness, int pulse_speed,
int pulse_table, int pulse_asleep, int pulse_awake) int pulse_table, int pulse_asleep, int pulse_awake)
{ {
unsigned long flags; unsigned long flags;
@ -229,7 +229,7 @@ static void powermate_pulse_led(struct powermate_device *pm, int static_brightne
/* mark state updates which are required */ /* mark state updates which are required */
if (static_brightness != pm->static_brightness){ if (static_brightness != pm->static_brightness){
pm->static_brightness = static_brightness; pm->static_brightness = static_brightness;
pm->requires_update |= UPDATE_STATIC_BRIGHTNESS; pm->requires_update |= UPDATE_STATIC_BRIGHTNESS;
} }
if (pulse_asleep != pm->pulse_asleep){ if (pulse_asleep != pm->pulse_asleep){
pm->pulse_asleep = pulse_asleep; pm->pulse_asleep = pulse_asleep;
@ -246,7 +246,7 @@ static void powermate_pulse_led(struct powermate_device *pm, int static_brightne
} }
powermate_sync_state(pm); powermate_sync_state(pm);
spin_unlock_irqrestore(&pm->lock, flags); spin_unlock_irqrestore(&pm->lock, flags);
} }
@ -257,19 +257,19 @@ static int powermate_input_event(struct input_dev *dev, unsigned int type, unsig
struct powermate_device *pm = dev->private; struct powermate_device *pm = dev->private;
if (type == EV_MSC && code == MSC_PULSELED){ if (type == EV_MSC && code == MSC_PULSELED){
/* /*
bits 0- 7: 8 bits: LED brightness bits 0- 7: 8 bits: LED brightness
bits 8-16: 9 bits: pulsing speed modifier (0 ... 510); 0-254 = slower, 255 = standard, 256-510 = faster. bits 8-16: 9 bits: pulsing speed modifier (0 ... 510); 0-254 = slower, 255 = standard, 256-510 = faster.
bits 17-18: 2 bits: pulse table (0, 1, 2 valid) bits 17-18: 2 bits: pulse table (0, 1, 2 valid)
bit 19: 1 bit : pulse whilst asleep? bit 19: 1 bit : pulse whilst asleep?
bit 20: 1 bit : pulse constantly? bit 20: 1 bit : pulse constantly?
*/ */
int static_brightness = command & 0xFF; // bits 0-7 int static_brightness = command & 0xFF; // bits 0-7
int pulse_speed = (command >> 8) & 0x1FF; // bits 8-16 int pulse_speed = (command >> 8) & 0x1FF; // bits 8-16
int pulse_table = (command >> 17) & 0x3; // bits 17-18 int pulse_table = (command >> 17) & 0x3; // bits 17-18
int pulse_asleep = (command >> 19) & 0x1; // bit 19 int pulse_asleep = (command >> 19) & 0x1; // bit 19
int pulse_awake = (command >> 20) & 0x1; // bit 20 int pulse_awake = (command >> 20) & 0x1; // bit 20
powermate_pulse_led(pm, static_brightness, pulse_speed, pulse_table, pulse_asleep, pulse_awake); powermate_pulse_led(pm, static_brightness, pulse_speed, pulse_table, pulse_asleep, pulse_awake);
} }
@ -378,7 +378,7 @@ static int powermate_probe(struct usb_interface *intf, const struct usb_device_i
switch (le16_to_cpu(udev->descriptor.idProduct)) { switch (le16_to_cpu(udev->descriptor.idProduct)) {
case POWERMATE_PRODUCT_NEW: pm->input.name = pm_name_powermate; break; case POWERMATE_PRODUCT_NEW: pm->input.name = pm_name_powermate; break;
case POWERMATE_PRODUCT_OLD: pm->input.name = pm_name_soundknob; break; case POWERMATE_PRODUCT_OLD: pm->input.name = pm_name_soundknob; break;
default: default:
pm->input.name = pm_name_soundknob; pm->input.name = pm_name_soundknob;
printk(KERN_WARNING "powermate: unknown product id %04x\n", printk(KERN_WARNING "powermate: unknown product id %04x\n",
le16_to_cpu(udev->descriptor.idProduct)); le16_to_cpu(udev->descriptor.idProduct));
@ -402,11 +402,11 @@ static int powermate_probe(struct usb_interface *intf, const struct usb_device_i
usb_make_path(udev, path, 64); usb_make_path(udev, path, 64);
snprintf(pm->phys, 64, "%s/input0", path); snprintf(pm->phys, 64, "%s/input0", path);
printk(KERN_INFO "input: %s on %s\n", pm->input.name, pm->input.phys); printk(KERN_INFO "input: %s on %s\n", pm->input.name, pm->input.phys);
/* force an update of everything */ /* force an update of everything */
pm->requires_update = UPDATE_PULSE_ASLEEP | UPDATE_PULSE_AWAKE | UPDATE_PULSE_MODE | UPDATE_STATIC_BRIGHTNESS; pm->requires_update = UPDATE_PULSE_ASLEEP | UPDATE_PULSE_AWAKE | UPDATE_PULSE_MODE | UPDATE_STATIC_BRIGHTNESS;
powermate_pulse_led(pm, 0x80, 255, 0, 1, 0); // set default pulse parameters powermate_pulse_led(pm, 0x80, 255, 0, 1, 0); // set default pulse parameters
usb_set_intfdata(intf, pm); usb_set_intfdata(intf, pm);
return 0; return 0;
} }

View file

@ -69,7 +69,6 @@ struct touchkit_usb {
struct urb *irq; struct urb *irq;
struct usb_device *udev; struct usb_device *udev;
struct input_dev input; struct input_dev input;
int open;
char name[128]; char name[128];
char phys[64]; char phys[64];
}; };
@ -134,15 +133,10 @@ static int touchkit_open(struct input_dev *input)
{ {
struct touchkit_usb *touchkit = input->private; struct touchkit_usb *touchkit = input->private;
if (touchkit->open++)
return 0;
touchkit->irq->dev = touchkit->udev; touchkit->irq->dev = touchkit->udev;
if (usb_submit_urb(touchkit->irq, GFP_ATOMIC)) { if (usb_submit_urb(touchkit->irq, GFP_ATOMIC))
touchkit->open--;
return -EIO; return -EIO;
}
return 0; return 0;
} }
@ -151,8 +145,7 @@ static void touchkit_close(struct input_dev *input)
{ {
struct touchkit_usb *touchkit = input->private; struct touchkit_usb *touchkit = input->private;
if (!--touchkit->open) usb_kill_urb(touchkit->irq);
usb_kill_urb(touchkit->irq);
} }
static int touchkit_alloc_buffers(struct usb_device *udev, static int touchkit_alloc_buffers(struct usb_device *udev,

View file

@ -9,18 +9,18 @@
/* /*
* This program is free software; you can redistribute it and/or modify * 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 * 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. * (at your option) any later version.
* *
* This program is distributed in the hope that it will be useful, * This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * GNU General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * 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 * 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: * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
@ -72,7 +72,6 @@ struct usb_kbd {
unsigned char newleds; unsigned char newleds;
char name[128]; char name[128];
char phys[64]; char phys[64];
int open;
unsigned char *new; unsigned char *new;
struct usb_ctrlrequest *cr; struct usb_ctrlrequest *cr;
@ -166,7 +165,7 @@ static void usb_kbd_led(struct urb *urb, struct pt_regs *regs)
if (urb->status) if (urb->status)
warn("led urb status %d received", urb->status); warn("led urb status %d received", urb->status);
if (*(kbd->leds) == kbd->newleds) if (*(kbd->leds) == kbd->newleds)
return; return;
@ -180,14 +179,9 @@ static int usb_kbd_open(struct input_dev *dev)
{ {
struct usb_kbd *kbd = dev->private; struct usb_kbd *kbd = dev->private;
if (kbd->open++)
return 0;
kbd->irq->dev = kbd->usbdev; kbd->irq->dev = kbd->usbdev;
if (usb_submit_urb(kbd->irq, GFP_KERNEL)) { if (usb_submit_urb(kbd->irq, GFP_KERNEL))
kbd->open--;
return -EIO; return -EIO;
}
return 0; return 0;
} }
@ -196,8 +190,7 @@ static void usb_kbd_close(struct input_dev *dev)
{ {
struct usb_kbd *kbd = dev->private; struct usb_kbd *kbd = dev->private;
if (!--kbd->open) usb_kill_urb(kbd->irq);
usb_kill_urb(kbd->irq);
} }
static int usb_kbd_alloc_mem(struct usb_device *dev, struct usb_kbd *kbd) static int usb_kbd_alloc_mem(struct usb_device *dev, struct usb_kbd *kbd)
@ -230,7 +223,7 @@ static void usb_kbd_free_mem(struct usb_device *dev, struct usb_kbd *kbd)
usb_buffer_free(dev, 1, kbd->leds, kbd->leds_dma); usb_buffer_free(dev, 1, kbd->leds, kbd->leds_dma);
} }
static int usb_kbd_probe(struct usb_interface *iface, static int usb_kbd_probe(struct usb_interface *iface,
const struct usb_device_id *id) const struct usb_device_id *id)
{ {
struct usb_device * dev = interface_to_usbdev(iface); struct usb_device * dev = interface_to_usbdev(iface);
@ -272,7 +265,7 @@ static int usb_kbd_probe(struct usb_interface *iface,
for (i = 0; i < 255; i++) for (i = 0; i < 255; i++)
set_bit(usb_kbd_keycode[i], kbd->dev.keybit); set_bit(usb_kbd_keycode[i], kbd->dev.keybit);
clear_bit(0, kbd->dev.keybit); clear_bit(0, kbd->dev.keybit);
kbd->dev.private = kbd; kbd->dev.private = kbd;
kbd->dev.event = usb_kbd_event; kbd->dev.event = usb_kbd_event;
kbd->dev.open = usb_kbd_open; kbd->dev.open = usb_kbd_open;
@ -294,7 +287,7 @@ static int usb_kbd_probe(struct usb_interface *iface,
sprintf(kbd->phys, "%s/input0", path); sprintf(kbd->phys, "%s/input0", path);
kbd->dev.name = kbd->name; kbd->dev.name = kbd->name;
kbd->dev.phys = kbd->phys; kbd->dev.phys = kbd->phys;
kbd->dev.id.bustype = BUS_USB; kbd->dev.id.bustype = BUS_USB;
kbd->dev.id.vendor = le16_to_cpu(dev->descriptor.idVendor); kbd->dev.id.vendor = le16_to_cpu(dev->descriptor.idVendor);
kbd->dev.id.product = le16_to_cpu(dev->descriptor.idProduct); kbd->dev.id.product = le16_to_cpu(dev->descriptor.idProduct);
@ -329,7 +322,7 @@ static int usb_kbd_probe(struct usb_interface *iface,
static void usb_kbd_disconnect(struct usb_interface *intf) static void usb_kbd_disconnect(struct usb_interface *intf)
{ {
struct usb_kbd *kbd = usb_get_intfdata (intf); struct usb_kbd *kbd = usb_get_intfdata (intf);
usb_set_intfdata(intf, NULL); usb_set_intfdata(intf, NULL);
if (kbd) { if (kbd) {
usb_kill_urb(kbd->irq); usb_kill_urb(kbd->irq);

View file

@ -9,18 +9,18 @@
/* /*
* This program is free software; you can redistribute it and/or modify * 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 * 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. * (at your option) any later version.
* *
* This program is distributed in the hope that it will be useful, * This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * GNU General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * 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 * 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: * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
@ -51,7 +51,6 @@ struct usb_mouse {
struct usb_device *usbdev; struct usb_device *usbdev;
struct input_dev dev; struct input_dev dev;
struct urb *irq; struct urb *irq;
int open;
signed char *data; signed char *data;
dma_addr_t data_dma; dma_addr_t data_dma;
@ -101,14 +100,9 @@ static int usb_mouse_open(struct input_dev *dev)
{ {
struct usb_mouse *mouse = dev->private; struct usb_mouse *mouse = dev->private;
if (mouse->open++)
return 0;
mouse->irq->dev = mouse->usbdev; mouse->irq->dev = mouse->usbdev;
if (usb_submit_urb(mouse->irq, GFP_KERNEL)) { if (usb_submit_urb(mouse->irq, GFP_KERNEL))
mouse->open--;
return -EIO; return -EIO;
}
return 0; return 0;
} }
@ -117,8 +111,7 @@ static void usb_mouse_close(struct input_dev *dev)
{ {
struct usb_mouse *mouse = dev->private; struct usb_mouse *mouse = dev->private;
if (!--mouse->open) usb_kill_urb(mouse->irq);
usb_kill_urb(mouse->irq);
} }
static int usb_mouse_probe(struct usb_interface * intf, const struct usb_device_id * id) static int usb_mouse_probe(struct usb_interface * intf, const struct usb_device_id * id)
@ -132,19 +125,19 @@ static int usb_mouse_probe(struct usb_interface * intf, const struct usb_device_
interface = intf->cur_altsetting; interface = intf->cur_altsetting;
if (interface->desc.bNumEndpoints != 1) if (interface->desc.bNumEndpoints != 1)
return -ENODEV; return -ENODEV;
endpoint = &interface->endpoint[0].desc; endpoint = &interface->endpoint[0].desc;
if (!(endpoint->bEndpointAddress & 0x80)) if (!(endpoint->bEndpointAddress & 0x80))
return -ENODEV; return -ENODEV;
if ((endpoint->bmAttributes & 3) != 3) if ((endpoint->bmAttributes & 3) != 3)
return -ENODEV; return -ENODEV;
pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress); pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);
maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe)); maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe));
if (!(mouse = kmalloc(sizeof(struct usb_mouse), GFP_KERNEL))) if (!(mouse = kmalloc(sizeof(struct usb_mouse), GFP_KERNEL)))
return -ENOMEM; return -ENOMEM;
memset(mouse, 0, sizeof(struct usb_mouse)); memset(mouse, 0, sizeof(struct usb_mouse));
@ -209,7 +202,7 @@ static int usb_mouse_probe(struct usb_interface * intf, const struct usb_device_
static void usb_mouse_disconnect(struct usb_interface *intf) static void usb_mouse_disconnect(struct usb_interface *intf)
{ {
struct usb_mouse *mouse = usb_get_intfdata (intf); struct usb_mouse *mouse = usb_get_intfdata (intf);
usb_set_intfdata(intf, NULL); usb_set_intfdata(intf, NULL);
if (mouse) { if (mouse) {
usb_kill_urb(mouse->irq); usb_kill_urb(mouse->irq);
@ -238,7 +231,7 @@ static struct usb_driver usb_mouse_driver = {
static int __init usb_mouse_init(void) static int __init usb_mouse_init(void)
{ {
int retval = usb_register(&usb_mouse_driver); int retval = usb_register(&usb_mouse_driver);
if (retval == 0) if (retval == 0)
info(DRIVER_VERSION ":" DRIVER_DESC); info(DRIVER_VERSION ":" DRIVER_DESC);
return retval; return retval;
} }

View file

@ -9,7 +9,7 @@
* Copyright (c) 2000 Daniel Egger <egger@suse.de> * Copyright (c) 2000 Daniel Egger <egger@suse.de>
* Copyright (c) 2001 Frederic Lepied <flepied@mandrakesoft.com> * Copyright (c) 2001 Frederic Lepied <flepied@mandrakesoft.com>
* Copyright (c) 2004 Panagiotis Issaris <panagiotis.issaris@mech.kuleuven.ac.be> * Copyright (c) 2004 Panagiotis Issaris <panagiotis.issaris@mech.kuleuven.ac.be>
* Copyright (c) 2002-2004 Ping Cheng <pingc@wacom.com> * Copyright (c) 2002-2005 Ping Cheng <pingc@wacom.com>
* *
* ChangeLog: * ChangeLog:
* v0.1 (vp) - Initial release * v0.1 (vp) - Initial release
@ -18,7 +18,7 @@
* v0.4 (sm) - Support for more Intuos models, menustrip * v0.4 (sm) - Support for more Intuos models, menustrip
* relative mode, proximity. * relative mode, proximity.
* v0.5 (vp) - Big cleanup, nifty features removed, * v0.5 (vp) - Big cleanup, nifty features removed,
* they belong in userspace * they belong in userspace
* v1.8 (vp) - Submit URB only when operating, moved to CVS, * v1.8 (vp) - Submit URB only when operating, moved to CVS,
* use input_report_key instead of report_btn and * use input_report_key instead of report_btn and
* other cleanups * other cleanups
@ -51,6 +51,9 @@
* - Cleanups here and there * - Cleanups here and there
* v1.30.1 (pi) - Added Graphire3 support * v1.30.1 (pi) - Added Graphire3 support
* v1.40 (pc) - Add support for several new devices, fix eraser reporting, ... * v1.40 (pc) - Add support for several new devices, fix eraser reporting, ...
* v1.43 (pc) - Added support for Cintiq 21UX
- Fixed a Graphire bug
- Merged wacom_intuos3_irq into wacom_intuos_irq
*/ */
/* /*
@ -72,7 +75,7 @@
/* /*
* Version Information * Version Information
*/ */
#define DRIVER_VERSION "v1.40" #define DRIVER_VERSION "v1.43"
#define DRIVER_AUTHOR "Vojtech Pavlik <vojtech@ucw.cz>" #define DRIVER_AUTHOR "Vojtech Pavlik <vojtech@ucw.cz>"
#define DRIVER_DESC "USB Wacom Graphire and Wacom Intuos tablet driver" #define DRIVER_DESC "USB Wacom Graphire and Wacom Intuos tablet driver"
#define DRIVER_LICENSE "GPL" #define DRIVER_LICENSE "GPL"
@ -83,6 +86,16 @@ MODULE_LICENSE(DRIVER_LICENSE);
#define USB_VENDOR_ID_WACOM 0x056a #define USB_VENDOR_ID_WACOM 0x056a
enum {
PENPARTNER = 0,
GRAPHIRE,
PL,
INTUOS,
INTUOS3,
CINTIQ,
MAX_TYPE
};
struct wacom_features { struct wacom_features {
char *name; char *name;
int pktlen; int pktlen;
@ -102,7 +115,6 @@ struct wacom {
struct urb *irq; struct urb *irq;
struct wacom_features *features; struct wacom_features *features;
int tool[2]; int tool[2];
int open;
__u32 serial[2]; __u32 serial[2];
char phys[32]; char phys[32];
}; };
@ -149,7 +161,7 @@ static void wacom_pl_irq(struct urb *urb, struct pt_regs *regs)
prox = data[1] & 0x40; prox = data[1] & 0x40;
input_regs(dev, regs); input_regs(dev, regs);
if (prox) { if (prox) {
pressure = (signed char)((data[7] << 1) | ((data[4] >> 2) & 1)); pressure = (signed char)((data[7] << 1) | ((data[4] >> 2) & 1));
@ -166,8 +178,7 @@ static void wacom_pl_irq(struct urb *urb, struct pt_regs *regs)
if (!wacom->tool[0]) { if (!wacom->tool[0]) {
/* Going into proximity select tool */ /* Going into proximity select tool */
wacom->tool[1] = (data[4] & 0x20)? BTN_TOOL_RUBBER : BTN_TOOL_PEN; wacom->tool[1] = (data[4] & 0x20)? BTN_TOOL_RUBBER : BTN_TOOL_PEN;
} } else {
else {
/* was entered with stylus2 pressed */ /* was entered with stylus2 pressed */
if (wacom->tool[1] == BTN_TOOL_RUBBER && !(data[4] & 0x20) ) { if (wacom->tool[1] == BTN_TOOL_RUBBER && !(data[4] & 0x20) ) {
/* report out proximity for previous tool */ /* report out proximity for previous tool */
@ -182,16 +193,15 @@ static void wacom_pl_irq(struct urb *urb, struct pt_regs *regs)
wacom->tool[1] = BTN_TOOL_PEN; wacom->tool[1] = BTN_TOOL_PEN;
} }
input_report_key(dev, wacom->tool[1], prox); /* report in proximity for tool */ input_report_key(dev, wacom->tool[1], prox); /* report in proximity for tool */
input_report_abs(dev, ABS_X, data[3] | ((__u32)data[2] << 7) | ((__u32)(data[1] & 0x03) << 14)); input_report_abs(dev, ABS_X, data[3] | (data[2] << 7) | ((data[1] & 0x03) << 14));
input_report_abs(dev, ABS_Y, data[6] | ((__u32)data[5] << 7) | ((__u32)(data[4] & 0x03) << 14)); input_report_abs(dev, ABS_Y, data[6] | (data[5] << 7) | ((data[4] & 0x03) << 14));
input_report_abs(dev, ABS_PRESSURE, pressure); input_report_abs(dev, ABS_PRESSURE, pressure);
input_report_key(dev, BTN_TOUCH, data[4] & 0x08); input_report_key(dev, BTN_TOUCH, data[4] & 0x08);
input_report_key(dev, BTN_STYLUS, data[4] & 0x10); input_report_key(dev, BTN_STYLUS, data[4] & 0x10);
/* Only allow the stylus2 button to be reported for the pen tool. */ /* Only allow the stylus2 button to be reported for the pen tool. */
input_report_key(dev, BTN_STYLUS2, (wacom->tool[1] == BTN_TOOL_PEN) && (data[4] & 0x20)); input_report_key(dev, BTN_STYLUS2, (wacom->tool[1] == BTN_TOOL_PEN) && (data[4] & 0x20));
} } else {
else {
/* report proximity-out of a (valid) tool */ /* report proximity-out of a (valid) tool */
if (wacom->tool[1] != BTN_TOOL_RUBBER) { if (wacom->tool[1] != BTN_TOOL_RUBBER) {
/* Unknown tool selected default to pen tool */ /* Unknown tool selected default to pen tool */
@ -203,7 +213,7 @@ static void wacom_pl_irq(struct urb *urb, struct pt_regs *regs)
wacom->tool[0] = prox; /* Save proximity state */ wacom->tool[0] = prox; /* Save proximity state */
input_sync(dev); input_sync(dev);
exit: exit:
retval = usb_submit_urb (urb, GFP_ATOMIC); retval = usb_submit_urb (urb, GFP_ATOMIC);
if (retval) if (retval)
err ("%s - usb_submit_urb failed with result %d", err ("%s - usb_submit_urb failed with result %d",
@ -232,20 +242,16 @@ static void wacom_ptu_irq(struct urb *urb, struct pt_regs *regs)
goto exit; goto exit;
} }
if (data[0] != 2) if (data[0] != 2) {
{
printk(KERN_INFO "wacom_ptu_irq: received unknown report #%d\n", data[0]); printk(KERN_INFO "wacom_ptu_irq: received unknown report #%d\n", data[0]);
goto exit; goto exit;
} }
input_regs(dev, regs); input_regs(dev, regs);
if (data[1] & 0x04) if (data[1] & 0x04) {
{
input_report_key(dev, BTN_TOOL_RUBBER, data[1] & 0x20); input_report_key(dev, BTN_TOOL_RUBBER, data[1] & 0x20);
input_report_key(dev, BTN_TOUCH, data[1] & 0x08); input_report_key(dev, BTN_TOUCH, data[1] & 0x08);
} } else {
else
{
input_report_key(dev, BTN_TOOL_PEN, data[1] & 0x20); input_report_key(dev, BTN_TOOL_PEN, data[1] & 0x20);
input_report_key(dev, BTN_TOUCH, data[1] & 0x01); input_report_key(dev, BTN_TOUCH, data[1] & 0x01);
} }
@ -257,7 +263,7 @@ static void wacom_ptu_irq(struct urb *urb, struct pt_regs *regs)
input_sync(dev); input_sync(dev);
exit: exit:
retval = usb_submit_urb (urb, GFP_ATOMIC); retval = usb_submit_urb (urb, GFP_ATOMIC);
if (retval) if (retval)
err ("%s - usb_submit_urb failed with result %d", err ("%s - usb_submit_urb failed with result %d",
@ -300,7 +306,7 @@ static void wacom_penpartner_irq(struct urb *urb, struct pt_regs *regs)
input_report_key(dev, BTN_STYLUS, (data[5] & 0x40)); input_report_key(dev, BTN_STYLUS, (data[5] & 0x40));
input_sync(dev); input_sync(dev);
exit: exit:
retval = usb_submit_urb (urb, GFP_ATOMIC); retval = usb_submit_urb (urb, GFP_ATOMIC);
if (retval) if (retval)
err ("%s - usb_submit_urb failed with result %d", err ("%s - usb_submit_urb failed with result %d",
@ -340,47 +346,47 @@ static void wacom_graphire_irq(struct urb *urb, struct pt_regs *regs)
input_regs(dev, regs); input_regs(dev, regs);
switch ((data[1] >> 5) & 3) { if (data[1] & 0x10) { /* in prox */
case 0: /* Pen */ switch ((data[1] >> 5) & 3) {
input_report_key(dev, BTN_TOOL_PEN, data[1] & 0x80);
break;
case 1: /* Rubber */ case 0: /* Pen */
input_report_key(dev, BTN_TOOL_RUBBER, data[1] & 0x80); wacom->tool[0] = BTN_TOOL_PEN;
break; break;
case 2: /* Mouse with wheel */ case 1: /* Rubber */
input_report_key(dev, BTN_MIDDLE, data[1] & 0x04); wacom->tool[0] = BTN_TOOL_RUBBER;
input_report_rel(dev, REL_WHEEL, (signed char) data[6]); break;
/* fall through */
case 3: /* Mouse without wheel */ case 2: /* Mouse with wheel */
input_report_key(dev, BTN_TOOL_MOUSE, data[7] > 24); input_report_key(dev, BTN_MIDDLE, data[1] & 0x04);
input_report_key(dev, BTN_LEFT, data[1] & 0x01); input_report_rel(dev, REL_WHEEL, (signed char) data[6]);
input_report_key(dev, BTN_RIGHT, data[1] & 0x02); /* fall through */
input_report_abs(dev, ABS_DISTANCE, data[7]);
input_report_abs(dev, ABS_X, x); case 3: /* Mouse without wheel */
input_report_abs(dev, ABS_Y, y); wacom->tool[0] = BTN_TOOL_MOUSE;
input_report_key(dev, BTN_LEFT, data[1] & 0x01);
input_sync(dev); input_report_key(dev, BTN_RIGHT, data[1] & 0x02);
goto exit; input_report_abs(dev, ABS_DISTANCE, data[7]);
break;
}
} }
if (data[1] & 0x80) { if (data[1] & 0x80) {
input_report_abs(dev, ABS_X, x); input_report_abs(dev, ABS_X, x);
input_report_abs(dev, ABS_Y, y); input_report_abs(dev, ABS_Y, y);
} }
if (wacom->tool[0] != BTN_TOOL_MOUSE) {
input_report_abs(dev, ABS_PRESSURE, le16_to_cpu(*(__le16 *) &data[6]));
input_report_key(dev, BTN_TOUCH, data[1] & 0x01);
input_report_key(dev, BTN_STYLUS, data[1] & 0x02);
input_report_key(dev, BTN_STYLUS2, data[1] & 0x04);
}
input_report_abs(dev, ABS_PRESSURE, le16_to_cpu(*(__le16 *) &data[6])); input_report_key(dev, wacom->tool[0], data[1] & 0x10);
input_report_key(dev, BTN_TOUCH, data[1] & 0x01);
input_report_key(dev, BTN_STYLUS, data[1] & 0x02);
input_report_key(dev, BTN_STYLUS2, data[1] & 0x04);
input_sync(dev); input_sync(dev);
exit: exit:
retval = usb_submit_urb (urb, GFP_ATOMIC); retval = usb_submit_urb (urb, GFP_ATOMIC);
if (retval) if (retval)
err ("%s - usb_submit_urb failed with result %d", err ("%s - usb_submit_urb failed with result %d",
@ -398,14 +404,13 @@ static int wacom_intuos_inout(struct urb *urb)
idx = data[1] & 0x01; idx = data[1] & 0x01;
/* Enter report */ /* Enter report */
if ((data[1] & 0xfc) == 0xc0) if ((data[1] & 0xfc) == 0xc0) {
{
/* serial number of the tool */ /* serial number of the tool */
wacom->serial[idx] = ((__u32)(data[3] & 0x0f) << 28) + wacom->serial[idx] = ((data[3] & 0x0f) << 28) +
((__u32)data[4] << 20) + ((__u32)data[5] << 12) + (data[4] << 20) + (data[5] << 12) +
((__u32)data[6] << 4) + (data[7] >> 4); (data[6] << 4) + (data[7] >> 4);
switch (((__u32)data[2] << 4) | (data[3] >> 4)) { switch ((data[2] << 4) | (data[3] >> 4)) {
case 0x812: /* Inking pen */ case 0x812: /* Inking pen */
case 0x801: /* Intuos3 Inking pen */ case 0x801: /* Intuos3 Inking pen */
case 0x012: case 0x012:
@ -449,7 +454,7 @@ static int wacom_intuos_inout(struct urb *urb)
case 0x112: case 0x112:
case 0x913: /* Intuos3 Airbrush */ case 0x913: /* Intuos3 Airbrush */
wacom->tool[idx] = BTN_TOOL_AIRBRUSH; wacom->tool[idx] = BTN_TOOL_AIRBRUSH;
break; /* Airbrush */ break;
default: /* Unknown tool */ default: /* Unknown tool */
wacom->tool[idx] = BTN_TOOL_PEN; wacom->tool[idx] = BTN_TOOL_PEN;
} }
@ -478,9 +483,8 @@ static void wacom_intuos_general(struct urb *urb)
unsigned int t; unsigned int t;
/* general pen packet */ /* general pen packet */
if ((data[1] & 0xb8) == 0xa0) if ((data[1] & 0xb8) == 0xa0) {
{ t = (data[6] << 2) | ((data[7] >> 6) & 3);
t = ((__u32)data[6] << 2) | ((data[7] >> 6) & 3);
input_report_abs(dev, ABS_PRESSURE, t); input_report_abs(dev, ABS_PRESSURE, t);
input_report_abs(dev, ABS_TILT_X, input_report_abs(dev, ABS_TILT_X,
((data[7] << 1) & 0x7e) | (data[8] >> 7)); ((data[7] << 1) & 0x7e) | (data[8] >> 7));
@ -491,10 +495,9 @@ static void wacom_intuos_general(struct urb *urb)
} }
/* airbrush second packet */ /* airbrush second packet */
if ((data[1] & 0xbc) == 0xb4) if ((data[1] & 0xbc) == 0xb4) {
{
input_report_abs(dev, ABS_WHEEL, input_report_abs(dev, ABS_WHEEL,
((__u32)data[6] << 2) | ((data[7] >> 6) & 3)); (data[6] << 2) | ((data[7] >> 6) & 3));
input_report_abs(dev, ABS_TILT_X, input_report_abs(dev, ABS_TILT_X,
((data[7] << 1) & 0x7e) | (data[8] >> 7)); ((data[7] << 1) & 0x7e) | (data[8] >> 7));
input_report_abs(dev, ABS_TILT_Y, data[8] & 0x7f); input_report_abs(dev, ABS_TILT_Y, data[8] & 0x7f);
@ -526,7 +529,7 @@ static void wacom_intuos_irq(struct urb *urb, struct pt_regs *regs)
goto exit; goto exit;
} }
if (data[0] != 2 && data[0] != 5 && data[0] != 6) { if (data[0] != 2 && data[0] != 5 && data[0] != 6 && data[0] != 12) {
dbg("wacom_intuos_irq: received unknown report #%d", data[0]); dbg("wacom_intuos_irq: received unknown report #%d", data[0]);
goto exit; goto exit;
} }
@ -536,107 +539,10 @@ static void wacom_intuos_irq(struct urb *urb, struct pt_regs *regs)
/* tool number */ /* tool number */
idx = data[1] & 0x01; idx = data[1] & 0x01;
/* process in/out prox events */
if (wacom_intuos_inout(urb)) goto exit;
input_report_abs(dev, ABS_X, be16_to_cpu(*(__be16 *) &data[2]));
input_report_abs(dev, ABS_Y, be16_to_cpu(*(__be16 *) &data[4]));
input_report_abs(dev, ABS_DISTANCE, data[9]);
/* process general packets */
wacom_intuos_general(urb);
if ((data[1] & 0xbc) == 0xa8 || (data[1] & 0xbe) == 0xb0) { /* 4D mouse or Lens cursor packets */
if (data[1] & 0x02) { /* Rotation packet */
t = ((__u32)data[6] << 3) | ((data[7] >> 5) & 7);
input_report_abs(dev, ABS_RZ, (data[7] & 0x20) ? ((t - 1) / 2) : -t / 2);
} else {
if ((data[1] & 0x10) == 0) { /* 4D mouse packets */
input_report_key(dev, BTN_LEFT, data[8] & 0x01);
input_report_key(dev, BTN_MIDDLE, data[8] & 0x02);
input_report_key(dev, BTN_RIGHT, data[8] & 0x04);
input_report_key(dev, BTN_SIDE, data[8] & 0x20);
input_report_key(dev, BTN_EXTRA, data[8] & 0x10);
t = ((__u32)data[6] << 2) | ((data[7] >> 6) & 3);
input_report_abs(dev, ABS_THROTTLE, (data[8] & 0x08) ? -t : t);
} else {
if (wacom->tool[idx] == BTN_TOOL_MOUSE) { /* 2D mouse packets */
input_report_key(dev, BTN_LEFT, data[8] & 0x04);
input_report_key(dev, BTN_MIDDLE, data[8] & 0x08);
input_report_key(dev, BTN_RIGHT, data[8] & 0x10);
input_report_rel(dev, REL_WHEEL,
(-(__u32)(data[8] & 0x01) + (__u32)((data[8] & 0x02) >> 1)));
}
else { /* Lens cursor packets */
input_report_key(dev, BTN_LEFT, data[8] & 0x01);
input_report_key(dev, BTN_MIDDLE, data[8] & 0x02);
input_report_key(dev, BTN_RIGHT, data[8] & 0x04);
input_report_key(dev, BTN_SIDE, data[8] & 0x10);
input_report_key(dev, BTN_EXTRA, data[8] & 0x08);
}
}
}
}
input_report_key(dev, wacom->tool[idx], 1);
input_event(dev, EV_MSC, MSC_SERIAL, wacom->serial[idx]);
input_sync(dev);
exit:
retval = usb_submit_urb (urb, GFP_ATOMIC);
if (retval)
err ("%s - usb_submit_urb failed with result %d",
__FUNCTION__, retval);
}
static void wacom_intuos3_irq(struct urb *urb, struct pt_regs *regs)
{
struct wacom *wacom = urb->context;
unsigned char *data = wacom->data;
struct input_dev *dev = &wacom->dev;
unsigned int t;
int idx, retval;
switch (urb->status) {
case 0:
/* success */
break;
case -ECONNRESET:
case -ENOENT:
case -ESHUTDOWN:
/* this urb is terminated, clean up */
dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status);
return;
default:
dbg("%s - nonzero urb status received: %d", __FUNCTION__, urb->status);
goto exit;
}
/* check for valid report */
if (data[0] != 2 && data[0] != 5 && data[0] != 12)
{
printk(KERN_INFO "wacom_intuos3_irq: received unknown report #%d\n", data[0]);
goto exit;
}
input_regs(dev, regs);
/* tool index is always 0 here since there is no dual input tool */
idx = data[1] & 0x01;
/* pad packets. Works as a second tool and is always in prox */ /* pad packets. Works as a second tool and is always in prox */
if (data[0] == 12) if (data[0] == 12) {
{
/* initiate the pad as a device */ /* initiate the pad as a device */
if (wacom->tool[1] != BTN_TOOL_FINGER) if (wacom->tool[1] != BTN_TOOL_FINGER) {
{
wacom->tool[1] = BTN_TOOL_FINGER; wacom->tool[1] = BTN_TOOL_FINGER;
input_report_key(dev, wacom->tool[1], 1); input_report_key(dev, wacom->tool[1], 1);
} }
@ -656,37 +562,78 @@ static void wacom_intuos3_irq(struct urb *urb, struct pt_regs *regs)
} }
/* process in/out prox events */ /* process in/out prox events */
if (wacom_intuos_inout(urb)) goto exit; if (wacom_intuos_inout(urb))
goto exit;
input_report_abs(dev, ABS_X, ((__u32)data[2] << 9) | ((__u32)data[3] << 1) | ((data[9] >> 1) & 1)); /* Cintiq doesn't send data when RDY bit isn't set */
input_report_abs(dev, ABS_Y, ((__u32)data[4] << 9) | ((__u32)data[5] << 1) | (data[9] & 1)); if ((wacom->features->type == CINTIQ) && !(data[1] & 0x40))
input_report_abs(dev, ABS_DISTANCE, ((data[9] >> 2) & 0x3f)); return;
if (wacom->features->type >= INTUOS3) {
input_report_abs(dev, ABS_X, (data[2] << 9) | (data[3] << 1) | ((data[9] >> 1) & 1));
input_report_abs(dev, ABS_Y, (data[4] << 9) | (data[5] << 1) | (data[9] & 1));
input_report_abs(dev, ABS_DISTANCE, ((data[9] >> 2) & 0x3f));
} else {
input_report_abs(dev, ABS_X, be16_to_cpu(*(__be16 *) &data[2]));
input_report_abs(dev, ABS_Y, be16_to_cpu(*(__be16 *) &data[4]));
input_report_abs(dev, ABS_DISTANCE, ((data[9] >> 3) & 0x1f));
}
/* process general packets */ /* process general packets */
wacom_intuos_general(urb); wacom_intuos_general(urb);
if ((data[1] & 0xbc) == 0xa8 || (data[1] & 0xbe) == 0xb0) /* 4D mouse, 2D mouse, marker pen rotation, or Lens cursor packets */
{ if ((data[1] & 0xbc) == 0xa8 || (data[1] & 0xbe) == 0xb0) {
/* Marker pen rotation packet. Reported as wheel due to valuator limitation */
if (data[1] & 0x02)
{
t = ((__u32)data[6] << 3) | ((data[7] >> 5) & 7);
t = (data[7] & 0x20) ? ((t > 900) ? ((t-1) / 2 - 1350) :
((t-1) / 2 + 450)) : (450 - t / 2) ;
input_report_abs(dev, ABS_WHEEL, t);
}
/* 2D mouse packets */ if (data[1] & 0x02) {
if (wacom->tool[idx] == BTN_TOOL_MOUSE) /* Rotation packet */
{ if (wacom->features->type >= INTUOS3) {
/* I3 marker pen rotation reported as wheel
* due to valuator limitation
*/
t = (data[6] << 3) | ((data[7] >> 5) & 7);
t = (data[7] & 0x20) ? ((t > 900) ? ((t-1) / 2 - 1350) :
((t-1) / 2 + 450)) : (450 - t / 2) ;
input_report_abs(dev, ABS_WHEEL, t);
} else {
/* 4D mouse rotation packet */
t = (data[6] << 3) | ((data[7] >> 5) & 7);
input_report_abs(dev, ABS_RZ, (data[7] & 0x20) ?
((t - 1) / 2) : -t / 2);
}
} else if (!(data[1] & 0x10) && wacom->features->type < INTUOS3) {
/* 4D mouse packet */
input_report_key(dev, BTN_LEFT, data[8] & 0x01);
input_report_key(dev, BTN_MIDDLE, data[8] & 0x02);
input_report_key(dev, BTN_RIGHT, data[8] & 0x04);
input_report_key(dev, BTN_SIDE, data[8] & 0x20);
input_report_key(dev, BTN_EXTRA, data[8] & 0x10);
t = (data[6] << 2) | ((data[7] >> 6) & 3);
input_report_abs(dev, ABS_THROTTLE, (data[8] & 0x08) ? -t : t);
} else if (wacom->tool[idx] == BTN_TOOL_MOUSE) {
/* 2D mouse packet */
input_report_key(dev, BTN_LEFT, data[8] & 0x04); input_report_key(dev, BTN_LEFT, data[8] & 0x04);
input_report_key(dev, BTN_MIDDLE, data[8] & 0x08); input_report_key(dev, BTN_MIDDLE, data[8] & 0x08);
input_report_key(dev, BTN_RIGHT, data[8] & 0x10); input_report_key(dev, BTN_RIGHT, data[8] & 0x10);
input_report_key(dev, BTN_SIDE, data[8] & 0x40); input_report_rel(dev, REL_WHEEL, ((data[8] & 0x02) >> 1)
input_report_key(dev, BTN_EXTRA, data[8] & 0x20); - (data[8] & 0x01));
/* mouse wheel is positive when rolled backwards */
input_report_rel(dev, REL_WHEEL, ((__u32)((data[8] & 0x02) >> 1) /* I3 2D mouse side buttons */
- (__u32)(data[8] & 0x01))); if (wacom->features->type == INTUOS3) {
input_report_key(dev, BTN_SIDE, data[8] & 0x40);
input_report_key(dev, BTN_EXTRA, data[8] & 0x20);
}
} else if (wacom->features->type < INTUOS3) {
/* Lens cursor packets */
input_report_key(dev, BTN_LEFT, data[8] & 0x01);
input_report_key(dev, BTN_MIDDLE, data[8] & 0x02);
input_report_key(dev, BTN_RIGHT, data[8] & 0x04);
input_report_key(dev, BTN_SIDE, data[8] & 0x10);
input_report_key(dev, BTN_EXTRA, data[8] & 0x08);
} }
} }
@ -702,35 +649,36 @@ exit:
} }
static struct wacom_features wacom_features[] = { static struct wacom_features wacom_features[] = {
{ "Wacom Penpartner", 7, 5040, 3780, 255, 32, 0, wacom_penpartner_irq }, { "Wacom Penpartner", 7, 5040, 3780, 255, 32, PENPARTNER, wacom_penpartner_irq },
{ "Wacom Graphire", 8, 10206, 7422, 511, 32, 1, wacom_graphire_irq }, { "Wacom Graphire", 8, 10206, 7422, 511, 32, GRAPHIRE, wacom_graphire_irq },
{ "Wacom Graphire2 4x5", 8, 10206, 7422, 511, 32, 1, wacom_graphire_irq }, { "Wacom Graphire2 4x5", 8, 10206, 7422, 511, 32, GRAPHIRE, wacom_graphire_irq },
{ "Wacom Graphire2 5x7", 8, 13918, 10206, 511, 32, 1, wacom_graphire_irq }, { "Wacom Graphire2 5x7", 8, 13918, 10206, 511, 32, GRAPHIRE, wacom_graphire_irq },
{ "Wacom Graphire3", 8, 10208, 7424, 511, 32, 1, wacom_graphire_irq }, { "Wacom Graphire3", 8, 10208, 7424, 511, 32, GRAPHIRE, wacom_graphire_irq },
{ "Wacom Graphire3 6x8", 8, 16704, 12064, 511, 32, 1, wacom_graphire_irq }, { "Wacom Graphire3 6x8", 8, 16704, 12064, 511, 32, GRAPHIRE, wacom_graphire_irq },
{ "Wacom Intuos 4x5", 10, 12700, 10600, 1023, 15, 2, wacom_intuos_irq }, { "Wacom Intuos 4x5", 10, 12700, 10600, 1023, 15, INTUOS, wacom_intuos_irq },
{ "Wacom Intuos 6x8", 10, 20320, 16240, 1023, 15, 2, wacom_intuos_irq }, { "Wacom Intuos 6x8", 10, 20320, 16240, 1023, 15, INTUOS, wacom_intuos_irq },
{ "Wacom Intuos 9x12", 10, 30480, 24060, 1023, 15, 2, wacom_intuos_irq }, { "Wacom Intuos 9x12", 10, 30480, 24060, 1023, 15, INTUOS, wacom_intuos_irq },
{ "Wacom Intuos 12x12", 10, 30480, 31680, 1023, 15, 2, wacom_intuos_irq }, { "Wacom Intuos 12x12", 10, 30480, 31680, 1023, 15, INTUOS, wacom_intuos_irq },
{ "Wacom Intuos 12x18", 10, 45720, 31680, 1023, 15, 2, wacom_intuos_irq }, { "Wacom Intuos 12x18", 10, 45720, 31680, 1023, 15, INTUOS, wacom_intuos_irq },
{ "Wacom PL400", 8, 5408, 4056, 255, 32, 3, wacom_pl_irq }, { "Wacom PL400", 8, 5408, 4056, 255, 32, PL, wacom_pl_irq },
{ "Wacom PL500", 8, 6144, 4608, 255, 32, 3, wacom_pl_irq }, { "Wacom PL500", 8, 6144, 4608, 255, 32, PL, wacom_pl_irq },
{ "Wacom PL600", 8, 6126, 4604, 255, 32, 3, wacom_pl_irq }, { "Wacom PL600", 8, 6126, 4604, 255, 32, PL, wacom_pl_irq },
{ "Wacom PL600SX", 8, 6260, 5016, 255, 32, 3, wacom_pl_irq }, { "Wacom PL600SX", 8, 6260, 5016, 255, 32, PL, wacom_pl_irq },
{ "Wacom PL550", 8, 6144, 4608, 511, 32, 3, wacom_pl_irq }, { "Wacom PL550", 8, 6144, 4608, 511, 32, PL, wacom_pl_irq },
{ "Wacom PL800", 8, 7220, 5780, 511, 32, 3, wacom_pl_irq }, { "Wacom PL800", 8, 7220, 5780, 511, 32, PL, wacom_pl_irq },
{ "Wacom Intuos2 4x5", 10, 12700, 10600, 1023, 15, 2, wacom_intuos_irq }, { "Wacom Intuos2 4x5", 10, 12700, 10600, 1023, 15, INTUOS, wacom_intuos_irq },
{ "Wacom Intuos2 6x8", 10, 20320, 16240, 1023, 15, 2, wacom_intuos_irq }, { "Wacom Intuos2 6x8", 10, 20320, 16240, 1023, 15, INTUOS, wacom_intuos_irq },
{ "Wacom Intuos2 9x12", 10, 30480, 24060, 1023, 15, 2, wacom_intuos_irq }, { "Wacom Intuos2 9x12", 10, 30480, 24060, 1023, 15, INTUOS, wacom_intuos_irq },
{ "Wacom Intuos2 12x12", 10, 30480, 31680, 1023, 15, 2, wacom_intuos_irq }, { "Wacom Intuos2 12x12", 10, 30480, 31680, 1023, 15, INTUOS, wacom_intuos_irq },
{ "Wacom Intuos2 12x18", 10, 45720, 31680, 1023, 15, 2, wacom_intuos_irq }, { "Wacom Intuos2 12x18", 10, 45720, 31680, 1023, 15, INTUOS, wacom_intuos_irq },
{ "Wacom Volito", 8, 5104, 3712, 511, 32, 1, wacom_graphire_irq }, { "Wacom Volito", 8, 5104, 3712, 511, 32, GRAPHIRE, wacom_graphire_irq },
{ "Wacom Cintiq Partner",8, 20480, 15360, 511, 32, 3, wacom_ptu_irq }, { "Wacom Cintiq Partner",8, 20480, 15360, 511, 32, PL, wacom_ptu_irq },
{ "Wacom Intuos3 4x5", 10, 25400, 20320, 1023, 15, 4, wacom_intuos3_irq }, { "Wacom Intuos3 4x5", 10, 25400, 20320, 1023, 15, INTUOS3, wacom_intuos_irq },
{ "Wacom Intuos3 6x8", 10, 40640, 30480, 1023, 15, 4, wacom_intuos3_irq }, { "Wacom Intuos3 6x8", 10, 40640, 30480, 1023, 15, INTUOS3, wacom_intuos_irq },
{ "Wacom Intuos3 9x12", 10, 60960, 45720, 1023, 15, 4, wacom_intuos3_irq }, { "Wacom Intuos3 9x12", 10, 60960, 45720, 1023, 15, INTUOS3, wacom_intuos_irq },
{ "Wacom Intuos2 6x8", 10, 20320, 16240, 1023, 15, 2, wacom_intuos_irq }, { "Wacom Cintiq 21UX", 10, 87200, 65600, 1023, 15, CINTIQ, wacom_intuos_irq },
{ } { "Wacom Intuos2 6x8", 10, 20320, 16240, 1023, 15, INTUOS, wacom_intuos_irq },
{ }
}; };
static struct usb_device_id wacom_ids[] = { static struct usb_device_id wacom_ids[] = {
@ -761,6 +709,7 @@ static struct usb_device_id wacom_ids[] = {
{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB0) }, { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB0) },
{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB1) }, { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB1) },
{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB2) }, { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB2) },
{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0x3F) },
{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0x47) }, { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x47) },
{ } { }
}; };
@ -771,14 +720,9 @@ static int wacom_open(struct input_dev *dev)
{ {
struct wacom *wacom = dev->private; struct wacom *wacom = dev->private;
if (wacom->open++)
return 0;
wacom->irq->dev = wacom->usbdev; wacom->irq->dev = wacom->usbdev;
if (usb_submit_urb(wacom->irq, GFP_KERNEL)) { if (usb_submit_urb(wacom->irq, GFP_KERNEL))
wacom->open--;
return -EIO; return -EIO;
}
return 0; return 0;
} }
@ -787,8 +731,7 @@ static void wacom_close(struct input_dev *dev)
{ {
struct wacom *wacom = dev->private; struct wacom *wacom = dev->private;
if (!--wacom->open) usb_kill_urb(wacom->irq);
usb_kill_urb(wacom->irq);
} }
static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *id) static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *id)
@ -823,32 +766,33 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i
wacom->dev.keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_PEN) | BIT(BTN_TOUCH) | BIT(BTN_STYLUS); wacom->dev.keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_PEN) | BIT(BTN_TOUCH) | BIT(BTN_STYLUS);
switch (wacom->features->type) { switch (wacom->features->type) {
case 1: case GRAPHIRE:
wacom->dev.evbit[0] |= BIT(EV_REL); wacom->dev.evbit[0] |= BIT(EV_REL);
wacom->dev.relbit[0] |= BIT(REL_WHEEL); wacom->dev.relbit[0] |= BIT(REL_WHEEL);
wacom->dev.absbit[0] |= BIT(ABS_DISTANCE); wacom->dev.absbit[0] |= BIT(ABS_DISTANCE);
wacom->dev.keybit[LONG(BTN_LEFT)] |= BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE); wacom->dev.keybit[LONG(BTN_LEFT)] |= BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE);
wacom->dev.keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_RUBBER) | BIT(BTN_TOOL_MOUSE) | BIT(BTN_STYLUS2); wacom->dev.keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_RUBBER) | BIT(BTN_TOOL_MOUSE) | BIT(BTN_STYLUS2);
break; break;
case 4: /* new functions for Intuos3 */ case INTUOS3:
case CINTIQ:
wacom->dev.keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_FINGER); wacom->dev.keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_FINGER);
wacom->dev.keybit[LONG(BTN_LEFT)] |= BIT(BTN_0) | BIT(BTN_1) | BIT(BTN_2) | BIT(BTN_3) | BIT(BTN_4) | BIT(BTN_5) | BIT(BTN_6) | BIT(BTN_7); wacom->dev.keybit[LONG(BTN_LEFT)] |= BIT(BTN_0) | BIT(BTN_1) | BIT(BTN_2) | BIT(BTN_3) | BIT(BTN_4) | BIT(BTN_5) | BIT(BTN_6) | BIT(BTN_7);
wacom->dev.absbit[0] |= BIT(ABS_RX) | BIT(ABS_RY); wacom->dev.absbit[0] |= BIT(ABS_RX) | BIT(ABS_RY);
/* fall through */ /* fall through */
case 2: case INTUOS:
wacom->dev.evbit[0] |= BIT(EV_MSC) | BIT(EV_REL); wacom->dev.evbit[0] |= BIT(EV_MSC) | BIT(EV_REL);
wacom->dev.mscbit[0] |= BIT(MSC_SERIAL); wacom->dev.mscbit[0] |= BIT(MSC_SERIAL);
wacom->dev.relbit[0] |= BIT(REL_WHEEL); wacom->dev.relbit[0] |= BIT(REL_WHEEL);
wacom->dev.keybit[LONG(BTN_LEFT)] |= BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE) | BIT(BTN_SIDE) | BIT(BTN_EXTRA); wacom->dev.keybit[LONG(BTN_LEFT)] |= BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE) | BIT(BTN_SIDE) | BIT(BTN_EXTRA);
wacom->dev.keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_RUBBER) | BIT(BTN_TOOL_MOUSE) | BIT(BTN_TOOL_BRUSH) wacom->dev.keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_RUBBER) | BIT(BTN_TOOL_MOUSE) | BIT(BTN_TOOL_BRUSH)
| BIT(BTN_TOOL_PENCIL) | BIT(BTN_TOOL_AIRBRUSH) | BIT(BTN_TOOL_LENS) | BIT(BTN_STYLUS2); | BIT(BTN_TOOL_PENCIL) | BIT(BTN_TOOL_AIRBRUSH) | BIT(BTN_TOOL_LENS) | BIT(BTN_STYLUS2);
wacom->dev.absbit[0] |= BIT(ABS_DISTANCE) | BIT(ABS_WHEEL) | BIT(ABS_TILT_X) | BIT(ABS_TILT_Y) | BIT(ABS_RZ) | BIT(ABS_THROTTLE); wacom->dev.absbit[0] |= BIT(ABS_DISTANCE) | BIT(ABS_WHEEL) | BIT(ABS_TILT_X) | BIT(ABS_TILT_Y) | BIT(ABS_RZ) | BIT(ABS_THROTTLE);
break; break;
case 3: case PL:
wacom->dev.keybit[LONG(BTN_DIGI)] |= BIT(BTN_STYLUS2) | BIT(BTN_TOOL_RUBBER); wacom->dev.keybit[LONG(BTN_DIGI)] |= BIT(BTN_STYLUS2) | BIT(BTN_TOOL_RUBBER);
break; break;
} }

View file

@ -104,13 +104,12 @@ MODULE_DEVICE_TABLE (usb, xpad_table);
struct usb_xpad { struct usb_xpad {
struct input_dev dev; /* input device interface */ struct input_dev dev; /* input device interface */
struct usb_device *udev; /* usb device */ struct usb_device *udev; /* usb device */
struct urb *irq_in; /* urb for interrupt in report */ struct urb *irq_in; /* urb for interrupt in report */
unsigned char *idata; /* input data */ unsigned char *idata; /* input data */
dma_addr_t idata_dma; dma_addr_t idata_dma;
char phys[65]; /* physical device path */ char phys[65]; /* physical device path */
int open_count; /* reference count */
}; };
/* /*
@ -128,35 +127,35 @@ static void xpad_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char *d
struct input_dev *dev = &xpad->dev; struct input_dev *dev = &xpad->dev;
input_regs(dev, regs); input_regs(dev, regs);
/* left stick */ /* left stick */
input_report_abs(dev, ABS_X, (__s16) (((__s16)data[13] << 8) | data[12])); input_report_abs(dev, ABS_X, (__s16) (((__s16)data[13] << 8) | data[12]));
input_report_abs(dev, ABS_Y, (__s16) (((__s16)data[15] << 8) | data[14])); input_report_abs(dev, ABS_Y, (__s16) (((__s16)data[15] << 8) | data[14]));
/* right stick */ /* right stick */
input_report_abs(dev, ABS_RX, (__s16) (((__s16)data[17] << 8) | data[16])); input_report_abs(dev, ABS_RX, (__s16) (((__s16)data[17] << 8) | data[16]));
input_report_abs(dev, ABS_RY, (__s16) (((__s16)data[19] << 8) | data[18])); input_report_abs(dev, ABS_RY, (__s16) (((__s16)data[19] << 8) | data[18]));
/* triggers left/right */ /* triggers left/right */
input_report_abs(dev, ABS_Z, data[10]); input_report_abs(dev, ABS_Z, data[10]);
input_report_abs(dev, ABS_RZ, data[11]); input_report_abs(dev, ABS_RZ, data[11]);
/* digital pad */ /* digital pad */
input_report_abs(dev, ABS_HAT0X, !!(data[2] & 0x08) - !!(data[2] & 0x04)); input_report_abs(dev, ABS_HAT0X, !!(data[2] & 0x08) - !!(data[2] & 0x04));
input_report_abs(dev, ABS_HAT0Y, !!(data[2] & 0x02) - !!(data[2] & 0x01)); input_report_abs(dev, ABS_HAT0Y, !!(data[2] & 0x02) - !!(data[2] & 0x01));
/* start/back buttons and stick press left/right */ /* start/back buttons and stick press left/right */
input_report_key(dev, BTN_START, (data[2] & 0x10) >> 4); input_report_key(dev, BTN_START, (data[2] & 0x10) >> 4);
input_report_key(dev, BTN_BACK, (data[2] & 0x20) >> 5); input_report_key(dev, BTN_BACK, (data[2] & 0x20) >> 5);
input_report_key(dev, BTN_THUMBL, (data[2] & 0x40) >> 6); input_report_key(dev, BTN_THUMBL, (data[2] & 0x40) >> 6);
input_report_key(dev, BTN_THUMBR, data[2] >> 7); input_report_key(dev, BTN_THUMBR, data[2] >> 7);
/* "analog" buttons A, B, X, Y */ /* "analog" buttons A, B, X, Y */
input_report_key(dev, BTN_A, data[4]); input_report_key(dev, BTN_A, data[4]);
input_report_key(dev, BTN_B, data[5]); input_report_key(dev, BTN_B, data[5]);
input_report_key(dev, BTN_X, data[6]); input_report_key(dev, BTN_X, data[6]);
input_report_key(dev, BTN_Y, data[7]); input_report_key(dev, BTN_Y, data[7]);
/* "analog" buttons black, white */ /* "analog" buttons black, white */
input_report_key(dev, BTN_C, data[8]); input_report_key(dev, BTN_C, data[8]);
input_report_key(dev, BTN_Z, data[9]); input_report_key(dev, BTN_Z, data[9]);
@ -168,7 +167,7 @@ static void xpad_irq_in(struct urb *urb, struct pt_regs *regs)
{ {
struct usb_xpad *xpad = urb->context; struct usb_xpad *xpad = urb->context;
int retval; int retval;
switch (urb->status) { switch (urb->status) {
case 0: case 0:
/* success */ /* success */
@ -183,7 +182,7 @@ static void xpad_irq_in(struct urb *urb, struct pt_regs *regs)
dbg("%s - nonzero urb status received: %d", __FUNCTION__, urb->status); dbg("%s - nonzero urb status received: %d", __FUNCTION__, urb->status);
goto exit; goto exit;
} }
xpad_process_packet(xpad, 0, xpad->idata, regs); xpad_process_packet(xpad, 0, xpad->idata, regs);
exit: exit:
@ -196,25 +195,19 @@ exit:
static int xpad_open (struct input_dev *dev) static int xpad_open (struct input_dev *dev)
{ {
struct usb_xpad *xpad = dev->private; struct usb_xpad *xpad = dev->private;
if (xpad->open_count++)
return 0;
xpad->irq_in->dev = xpad->udev; xpad->irq_in->dev = xpad->udev;
if (usb_submit_urb(xpad->irq_in, GFP_KERNEL)) { if (usb_submit_urb(xpad->irq_in, GFP_KERNEL))
xpad->open_count--;
return -EIO; return -EIO;
}
return 0; return 0;
} }
static void xpad_close (struct input_dev *dev) static void xpad_close (struct input_dev *dev)
{ {
struct usb_xpad *xpad = dev->private; struct usb_xpad *xpad = dev->private;
if (!--xpad->open_count) usb_kill_urb(xpad->irq_in);
usb_kill_urb(xpad->irq_in);
} }
static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id) static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id)
@ -224,19 +217,19 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
struct usb_endpoint_descriptor *ep_irq_in; struct usb_endpoint_descriptor *ep_irq_in;
char path[64]; char path[64];
int i; int i;
for (i = 0; xpad_device[i].idVendor; i++) { for (i = 0; xpad_device[i].idVendor; i++) {
if ((le16_to_cpu(udev->descriptor.idVendor) == xpad_device[i].idVendor) && if ((le16_to_cpu(udev->descriptor.idVendor) == xpad_device[i].idVendor) &&
(le16_to_cpu(udev->descriptor.idProduct) == xpad_device[i].idProduct)) (le16_to_cpu(udev->descriptor.idProduct) == xpad_device[i].idProduct))
break; break;
} }
if ((xpad = kmalloc (sizeof(struct usb_xpad), GFP_KERNEL)) == NULL) { if ((xpad = kmalloc (sizeof(struct usb_xpad), GFP_KERNEL)) == NULL) {
err("cannot allocate memory for new pad"); err("cannot allocate memory for new pad");
return -ENOMEM; return -ENOMEM;
} }
memset(xpad, 0, sizeof(struct usb_xpad)); memset(xpad, 0, sizeof(struct usb_xpad));
xpad->idata = usb_buffer_alloc(udev, XPAD_PKT_LEN, xpad->idata = usb_buffer_alloc(udev, XPAD_PKT_LEN,
SLAB_ATOMIC, &xpad->idata_dma); SLAB_ATOMIC, &xpad->idata_dma);
if (!xpad->idata) { if (!xpad->idata) {
@ -251,18 +244,18 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
kfree(xpad); kfree(xpad);
return -ENOMEM; return -ENOMEM;
} }
ep_irq_in = &intf->cur_altsetting->endpoint[0].desc; ep_irq_in = &intf->cur_altsetting->endpoint[0].desc;
usb_fill_int_urb(xpad->irq_in, udev, usb_fill_int_urb(xpad->irq_in, udev,
usb_rcvintpipe(udev, ep_irq_in->bEndpointAddress), usb_rcvintpipe(udev, ep_irq_in->bEndpointAddress),
xpad->idata, XPAD_PKT_LEN, xpad_irq_in, xpad->idata, XPAD_PKT_LEN, xpad_irq_in,
xpad, ep_irq_in->bInterval); xpad, ep_irq_in->bInterval);
xpad->irq_in->transfer_dma = xpad->idata_dma; xpad->irq_in->transfer_dma = xpad->idata_dma;
xpad->irq_in->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; xpad->irq_in->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
xpad->udev = udev; xpad->udev = udev;
xpad->dev.id.bustype = BUS_USB; xpad->dev.id.bustype = BUS_USB;
xpad->dev.id.vendor = le16_to_cpu(udev->descriptor.idVendor); xpad->dev.id.vendor = le16_to_cpu(udev->descriptor.idVendor);
xpad->dev.id.product = le16_to_cpu(udev->descriptor.idProduct); xpad->dev.id.product = le16_to_cpu(udev->descriptor.idProduct);
@ -273,21 +266,21 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
xpad->dev.phys = xpad->phys; xpad->dev.phys = xpad->phys;
xpad->dev.open = xpad_open; xpad->dev.open = xpad_open;
xpad->dev.close = xpad_close; xpad->dev.close = xpad_close;
usb_make_path(udev, path, 64); usb_make_path(udev, path, 64);
snprintf(xpad->phys, 64, "%s/input0", path); snprintf(xpad->phys, 64, "%s/input0", path);
xpad->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); xpad->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
for (i = 0; xpad_btn[i] >= 0; i++) for (i = 0; xpad_btn[i] >= 0; i++)
set_bit(xpad_btn[i], xpad->dev.keybit); set_bit(xpad_btn[i], xpad->dev.keybit);
for (i = 0; xpad_abs[i] >= 0; i++) { for (i = 0; xpad_abs[i] >= 0; i++) {
signed short t = xpad_abs[i]; signed short t = xpad_abs[i];
set_bit(t, xpad->dev.absbit); set_bit(t, xpad->dev.absbit);
switch (t) { switch (t) {
case ABS_X: case ABS_X:
case ABS_Y: case ABS_Y:
@ -310,11 +303,11 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
break; break;
} }
} }
input_register_device(&xpad->dev); input_register_device(&xpad->dev);
printk(KERN_INFO "input: %s on %s", xpad->dev.name, path); printk(KERN_INFO "input: %s on %s", xpad->dev.name, path);
usb_set_intfdata(intf, xpad); usb_set_intfdata(intf, xpad);
return 0; return 0;
} }
@ -322,7 +315,7 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
static void xpad_disconnect(struct usb_interface *intf) static void xpad_disconnect(struct usb_interface *intf)
{ {
struct usb_xpad *xpad = usb_get_intfdata (intf); struct usb_xpad *xpad = usb_get_intfdata (intf);
usb_set_intfdata(intf, NULL); usb_set_intfdata(intf, NULL);
if (xpad) { if (xpad) {
usb_kill_urb(xpad->irq_in); usb_kill_urb(xpad->irq_in);

View file

@ -859,6 +859,10 @@ struct input_dev {
int (*erase_effect)(struct input_dev *dev, int effect_id); int (*erase_effect)(struct input_dev *dev, int effect_id);
struct input_handle *grab; struct input_handle *grab;
struct semaphore sem; /* serializes open and close operations */
unsigned int users;
struct device *dev; struct device *dev;
struct list_head h_list; struct list_head h_list;

View file

@ -111,18 +111,35 @@ struct js_corr {
#define JS_SET_ALL 8 #define JS_SET_ALL 8
struct JS_DATA_TYPE { struct JS_DATA_TYPE {
int buttons; __s32 buttons;
int x; __s32 x;
int y; __s32 y;
}; };
struct JS_DATA_SAVE_TYPE { struct JS_DATA_SAVE_TYPE_32 {
int JS_TIMEOUT; __s32 JS_TIMEOUT;
int BUSY; __s32 BUSY;
long JS_EXPIRETIME; __s32 JS_EXPIRETIME;
long JS_TIMELIMIT; __s32 JS_TIMELIMIT;
struct JS_DATA_TYPE JS_SAVE; struct JS_DATA_TYPE JS_SAVE;
struct JS_DATA_TYPE JS_CORR; struct JS_DATA_TYPE JS_CORR;
}; };
struct JS_DATA_SAVE_TYPE_64 {
__s32 JS_TIMEOUT;
__s32 BUSY;
__s64 JS_EXPIRETIME;
__s64 JS_TIMELIMIT;
struct JS_DATA_TYPE JS_SAVE;
struct JS_DATA_TYPE JS_CORR;
};
#if BITS_PER_LONG == 64
#define JS_DATA_SAVE_TYPE JS_DATA_SAVE_TYPE_64
#elif BITS_PER_LONG == 32
#define JS_DATA_SAVE_TYPE JS_DATA_SAVE_TYPE_32
#else
#error Unexpected BITS_PER_LONG
#endif
#endif /* _LINUX_JOYSTICK_H */ #endif /* _LINUX_JOYSTICK_H */

View file

@ -41,6 +41,7 @@ struct ps2dev {
void ps2_init(struct ps2dev *ps2dev, struct serio *serio); void ps2_init(struct ps2dev *ps2dev, struct serio *serio);
int ps2_sendbyte(struct ps2dev *ps2dev, unsigned char byte, int timeout); int ps2_sendbyte(struct ps2dev *ps2dev, unsigned char byte, int timeout);
void ps2_drain(struct ps2dev *ps2dev, int maxbytes, int timeout);
int ps2_command(struct ps2dev *ps2dev, unsigned char *param, int command); int ps2_command(struct ps2dev *ps2dev, unsigned char *param, int command);
int ps2_schedule_command(struct ps2dev *ps2dev, unsigned char *param, int command); int ps2_schedule_command(struct ps2dev *ps2dev, unsigned char *param, int command);
int ps2_handle_ack(struct ps2dev *ps2dev, unsigned char data); int ps2_handle_ack(struct ps2dev *ps2dev, unsigned char data);

View file

@ -83,6 +83,7 @@ static inline void serio_register_port(struct serio *serio)
} }
void serio_unregister_port(struct serio *serio); void serio_unregister_port(struct serio *serio);
void serio_unregister_child_port(struct serio *serio);
void __serio_unregister_port_delayed(struct serio *serio, struct module *owner); void __serio_unregister_port_delayed(struct serio *serio, struct module *owner);
static inline void serio_unregister_port_delayed(struct serio *serio) static inline void serio_unregister_port_delayed(struct serio *serio)
{ {
@ -153,6 +154,11 @@ static inline int serio_pin_driver(struct serio *serio)
return down_interruptible(&serio->drv_sem); return down_interruptible(&serio->drv_sem);
} }
static inline void serio_pin_driver_uninterruptible(struct serio *serio)
{
down(&serio->drv_sem);
}
static inline void serio_unpin_driver(struct serio *serio) static inline void serio_unpin_driver(struct serio *serio)
{ {
up(&serio->drv_sem); up(&serio->drv_sem);

View file

@ -52,7 +52,7 @@ config SOUND_CMPCI_MIDI
config SOUND_CMPCI_JOYSTICK config SOUND_CMPCI_JOYSTICK
bool "Enable joystick" bool "Enable joystick"
depends on SOUND_CMPCI && X86 depends on SOUND_CMPCI && X86 && (GAMEPORT=y || SOUND_CMPCI=GAMEPORT)
help help
Say Y here in order to enable the joystick port on a sound card using Say Y here in order to enable the joystick port on a sound card using
the CMI8338 or the CMI8738 chipset. You need to config the the CMI8338 or the CMI8738 chipset. You need to config the

View file

@ -162,6 +162,10 @@
#include <asm/page.h> #include <asm/page.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE))
#define SUPPORT_JOYSTICK
#endif
/* --------------------------------------------------------------------- */ /* --------------------------------------------------------------------- */
#undef OSS_DOCUMENTED_MIXER_SEMANTICS #undef OSS_DOCUMENTED_MIXER_SEMANTICS
@ -385,7 +389,10 @@ struct es1370_state {
unsigned char obuf[MIDIOUTBUF]; unsigned char obuf[MIDIOUTBUF];
} midi; } midi;
#ifdef SUPPORT_JOYSTICK
struct gameport *gameport; struct gameport *gameport;
#endif
struct semaphore sem; struct semaphore sem;
}; };
@ -2554,10 +2561,55 @@ static struct initvol {
{ SOUND_MIXER_WRITE_OGAIN, 0x4040 } { SOUND_MIXER_WRITE_OGAIN, 0x4040 }
}; };
#ifdef SUPPORT_JOYSTICK
static int __devinit es1370_register_gameport(struct es1370_state *s)
{
struct gameport *gp;
if (!request_region(0x200, JOY_EXTENT, "es1370")) {
printk(KERN_ERR "es1370: joystick io port 0x200 in use\n");
return -EBUSY;
}
s->gameport = gp = gameport_allocate_port();
if (!gp) {
printk(KERN_ERR "es1370: can not allocate memory for gameport\n");
release_region(0x200, JOY_EXTENT);
return -ENOMEM;
}
gameport_set_name(gp, "ESS1370");
gameport_set_phys(gp, "pci%s/gameport0", pci_name(s->dev));
gp->dev.parent = &s->dev->dev;
gp->io = 0x200;
s->ctrl |= CTRL_JYSTK_EN;
outl(s->ctrl, s->io + ES1370_REG_CONTROL);
gameport_register_port(gp);
return 0;
}
static inline void es1370_unregister_gameport(struct es1370_state *s)
{
if (s->gameport) {
int gpio = s->gameport->io;
gameport_unregister_port(s->gameport);
release_region(gpio, JOY_EXTENT);
}
}
#else
static inline int es1370_register_gameport(struct es1370_state *s) { return -ENOSYS; }
static inline void es1370_unregister_gameport(struct es1370_state *s) { }
#endif /* SUPPORT_JOYSTICK */
static int __devinit es1370_probe(struct pci_dev *pcidev, const struct pci_device_id *pciid) static int __devinit es1370_probe(struct pci_dev *pcidev, const struct pci_device_id *pciid)
{ {
struct es1370_state *s; struct es1370_state *s;
struct gameport *gp = NULL;
mm_segment_t fs; mm_segment_t fs;
int i, val, ret; int i, val, ret;
@ -2606,28 +2658,14 @@ static int __devinit es1370_probe(struct pci_dev *pcidev, const struct pci_devic
/* note: setting CTRL_SERR_DIS is reported to break /* note: setting CTRL_SERR_DIS is reported to break
* mic bias setting (by Kim.Berts@fisub.mail.abb.com) */ * mic bias setting (by Kim.Berts@fisub.mail.abb.com) */
s->ctrl = CTRL_CDC_EN | (DAC2_SRTODIV(8000) << CTRL_SH_PCLKDIV) | (1 << CTRL_SH_WTSRSEL); s->ctrl = CTRL_CDC_EN | (DAC2_SRTODIV(8000) << CTRL_SH_PCLKDIV) | (1 << CTRL_SH_WTSRSEL);
if (!request_region(0x200, JOY_EXTENT, "es1370")) {
printk(KERN_ERR "es1370: joystick io port 0x200 in use\n");
} else if (!(s->gameport = gp = gameport_allocate_port())) {
printk(KERN_ERR "es1370: can not allocate memory for gameport\n");
release_region(0x200, JOY_EXTENT);
} else {
gameport_set_name(gp, "ESS1370");
gameport_set_phys(gp, "pci%s/gameport0", pci_name(s->dev));
gp->dev.parent = &s->dev->dev;
gp->io = 0x200;
s->ctrl |= CTRL_JYSTK_EN;
}
if (lineout[devindex]) if (lineout[devindex])
s->ctrl |= CTRL_XCTL0; s->ctrl |= CTRL_XCTL0;
if (micbias[devindex]) if (micbias[devindex])
s->ctrl |= CTRL_XCTL1; s->ctrl |= CTRL_XCTL1;
s->sctrl = 0; s->sctrl = 0;
printk(KERN_INFO "es1370: found adapter at io %#lx irq %u\n" printk(KERN_INFO "es1370: adapter at io %#lx irq %u, line %s, mic impedance %s\n",
KERN_INFO "es1370: features: joystick %s, line %s, mic impedance %s\n", s->io, s->irq, (s->ctrl & CTRL_XCTL0) ? "out" : "in",
s->io, s->irq, (s->ctrl & CTRL_JYSTK_EN) ? "on" : "off", (s->ctrl & CTRL_XCTL1) ? "1" : "0");
(s->ctrl & CTRL_XCTL0) ? "out" : "in",
(s->ctrl & CTRL_XCTL1) ? "1" : "0");
/* register devices */ /* register devices */
if ((s->dev_audio = register_sound_dsp(&es1370_audio_fops, -1)) < 0) { if ((s->dev_audio = register_sound_dsp(&es1370_audio_fops, -1)) < 0) {
ret = s->dev_audio; ret = s->dev_audio;
@ -2673,9 +2711,7 @@ static int __devinit es1370_probe(struct pci_dev *pcidev, const struct pci_devic
} }
set_fs(fs); set_fs(fs);
/* register gameport */ es1370_register_gameport(s);
if (gp)
gameport_register_port(gp);
/* store it in the driver field */ /* store it in the driver field */
pci_set_drvdata(pcidev, s); pci_set_drvdata(pcidev, s);
@ -2697,10 +2733,6 @@ static int __devinit es1370_probe(struct pci_dev *pcidev, const struct pci_devic
err_dev1: err_dev1:
printk(KERN_ERR "es1370: cannot register misc device\n"); printk(KERN_ERR "es1370: cannot register misc device\n");
free_irq(s->irq, s); free_irq(s->irq, s);
if (s->gameport) {
release_region(s->gameport->io, JOY_EXTENT);
gameport_free_port(s->gameport);
}
err_irq: err_irq:
release_region(s->io, ES1370_EXTENT); release_region(s->io, ES1370_EXTENT);
err_region: err_region:
@ -2719,11 +2751,7 @@ static void __devexit es1370_remove(struct pci_dev *dev)
outl(0, s->io+ES1370_REG_SERIAL_CONTROL); /* clear serial interrupts */ outl(0, s->io+ES1370_REG_SERIAL_CONTROL); /* clear serial interrupts */
synchronize_irq(s->irq); synchronize_irq(s->irq);
free_irq(s->irq, s); free_irq(s->irq, s);
if (s->gameport) { es1370_unregister_gameport(s);
int gpio = s->gameport->io;
gameport_unregister_port(s->gameport);
release_region(gpio, JOY_EXTENT);
}
release_region(s->io, ES1370_EXTENT); release_region(s->io, ES1370_EXTENT);
unregister_sound_dsp(s->dev_audio); unregister_sound_dsp(s->dev_audio);
unregister_sound_mixer(s->dev_mixer); unregister_sound_mixer(s->dev_mixer);

View file

@ -134,6 +134,10 @@
#include <asm/page.h> #include <asm/page.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE))
#define SUPPORT_JOYSTICK
#endif
/* --------------------------------------------------------------------- */ /* --------------------------------------------------------------------- */
#undef OSS_DOCUMENTED_MIXER_SEMANTICS #undef OSS_DOCUMENTED_MIXER_SEMANTICS
@ -454,7 +458,10 @@ struct es1371_state {
unsigned char obuf[MIDIOUTBUF]; unsigned char obuf[MIDIOUTBUF];
} midi; } midi;
#ifdef SUPPORT_JOYSTICK
struct gameport *gameport; struct gameport *gameport;
#endif
struct semaphore sem; struct semaphore sem;
}; };
@ -2787,12 +2794,63 @@ static struct
{ PCI_ANY_ID, PCI_ANY_ID } { PCI_ANY_ID, PCI_ANY_ID }
}; };
#ifdef SUPPORT_JOYSTICK
static int __devinit es1371_register_gameport(struct es1371_state *s)
{
struct gameport *gp;
int gpio;
for (gpio = 0x218; gpio >= 0x200; gpio -= 0x08)
if (request_region(gpio, JOY_EXTENT, "es1371"))
break;
if (gpio < 0x200) {
printk(KERN_ERR PFX "no free joystick address found\n");
return -EBUSY;
}
s->gameport = gp = gameport_allocate_port();
if (!gp) {
printk(KERN_ERR PFX "can not allocate memory for gameport\n");
release_region(gpio, JOY_EXTENT);
return -ENOMEM;
}
gameport_set_name(gp, "ESS1371 Gameport");
gameport_set_phys(gp, "isa%04x/gameport0", gpio);
gp->dev.parent = &s->dev->dev;
gp->io = gpio;
s->ctrl |= CTRL_JYSTK_EN | (((gpio >> 3) & CTRL_JOY_MASK) << CTRL_JOY_SHIFT);
outl(s->ctrl, s->io + ES1371_REG_CONTROL);
gameport_register_port(gp);
return 0;
}
static inline void es1371_unregister_gameport(struct es1371_state *s)
{
if (s->gameport) {
int gpio = s->gameport->io;
gameport_unregister_port(s->gameport);
release_region(gpio, JOY_EXTENT);
}
}
#else
static inline int es1371_register_gameport(struct es1371_state *s) { return -ENOSYS; }
static inline void es1371_unregister_gameport(struct es1371_state *s) { }
#endif /* SUPPORT_JOYSTICK */
static int __devinit es1371_probe(struct pci_dev *pcidev, const struct pci_device_id *pciid) static int __devinit es1371_probe(struct pci_dev *pcidev, const struct pci_device_id *pciid)
{ {
struct es1371_state *s; struct es1371_state *s;
struct gameport *gp;
mm_segment_t fs; mm_segment_t fs;
int i, gpio, val, res = -1; int i, val, res = -1;
int idx; int idx;
unsigned long tmo; unsigned long tmo;
signed long tmo2; signed long tmo2;
@ -2883,23 +2941,6 @@ static int __devinit es1371_probe(struct pci_dev *pcidev, const struct pci_devic
} }
} }
for (gpio = 0x218; gpio >= 0x200; gpio -= 0x08)
if (request_region(gpio, JOY_EXTENT, "es1371"))
break;
if (gpio < 0x200) {
printk(KERN_ERR PFX "no free joystick address found\n");
} else if (!(s->gameport = gp = gameport_allocate_port())) {
printk(KERN_ERR PFX "can not allocate memory for gameport\n");
release_region(gpio, JOY_EXTENT);
} else {
gameport_set_name(gp, "ESS1371 Gameport");
gameport_set_phys(gp, "isa%04x/gameport0", gpio);
gp->dev.parent = &s->dev->dev;
gp->io = gpio;
s->ctrl |= CTRL_JYSTK_EN | (((gpio >> 3) & CTRL_JOY_MASK) << CTRL_JOY_SHIFT);
}
s->sctrl = 0; s->sctrl = 0;
cssr = 0; cssr = 0;
s->spdif_volume = -1; s->spdif_volume = -1;
@ -2969,9 +3010,7 @@ static int __devinit es1371_probe(struct pci_dev *pcidev, const struct pci_devic
/* turn on S/PDIF output driver if requested */ /* turn on S/PDIF output driver if requested */
outl(cssr, s->io+ES1371_REG_STATUS); outl(cssr, s->io+ES1371_REG_STATUS);
/* register gameport */ es1371_register_gameport(s);
if (s->gameport)
gameport_register_port(s->gameport);
/* store it in the driver field */ /* store it in the driver field */
pci_set_drvdata(pcidev, s); pci_set_drvdata(pcidev, s);
@ -2980,13 +3019,9 @@ static int __devinit es1371_probe(struct pci_dev *pcidev, const struct pci_devic
/* increment devindex */ /* increment devindex */
if (devindex < NR_DEVICE-1) if (devindex < NR_DEVICE-1)
devindex++; devindex++;
return 0; return 0;
err_gp: err_gp:
if (s->gameport) {
release_region(s->gameport->io, JOY_EXTENT);
gameport_free_port(s->gameport);
}
#ifdef ES1371_DEBUG #ifdef ES1371_DEBUG
if (s->ps) if (s->ps)
remove_proc_entry("es1371", NULL); remove_proc_entry("es1371", NULL);
@ -3025,11 +3060,7 @@ static void __devexit es1371_remove(struct pci_dev *dev)
outl(0, s->io+ES1371_REG_SERIAL_CONTROL); /* clear serial interrupts */ outl(0, s->io+ES1371_REG_SERIAL_CONTROL); /* clear serial interrupts */
synchronize_irq(s->irq); synchronize_irq(s->irq);
free_irq(s->irq, s); free_irq(s->irq, s);
if (s->gameport) { es1371_unregister_gameport(s);
int gpio = s->gameport->io;
gameport_unregister_port(s->gameport);
release_region(gpio, JOY_EXTENT);
}
release_region(s->io, ES1371_EXTENT); release_region(s->io, ES1371_EXTENT);
unregister_sound_dsp(s->dev_audio); unregister_sound_dsp(s->dev_audio);
unregister_sound_mixer(s->codec->dev_mixer); unregister_sound_mixer(s->codec->dev_mixer);

View file

@ -150,6 +150,10 @@
#define FMODE_DMFM 0x10 #define FMODE_DMFM 0x10
#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE))
#define SUPPORT_JOYSTICK 1
#endif
static struct pci_driver solo1_driver; static struct pci_driver solo1_driver;
/* --------------------------------------------------------------------- */ /* --------------------------------------------------------------------- */
@ -227,7 +231,9 @@ struct solo1_state {
unsigned char obuf[MIDIOUTBUF]; unsigned char obuf[MIDIOUTBUF];
} midi; } midi;
#if SUPPORT_JOYSTICK
struct gameport *gameport; struct gameport *gameport;
#endif
}; };
/* --------------------------------------------------------------------- */ /* --------------------------------------------------------------------- */
@ -2281,6 +2287,7 @@ solo1_resume(struct pci_dev *pci_dev) {
return 0; return 0;
} }
#ifdef SUPPORT_JOYSTICK
static int __devinit solo1_register_gameport(struct solo1_state *s, int io_port) static int __devinit solo1_register_gameport(struct solo1_state *s, int io_port)
{ {
struct gameport *gp; struct gameport *gp;
@ -2307,6 +2314,19 @@ static int __devinit solo1_register_gameport(struct solo1_state *s, int io_port)
return 0; return 0;
} }
static inline void solo1_unregister_gameport(struct solo1_state *s)
{
if (s->gameport) {
int gpio = s->gameport->io;
gameport_unregister_port(s->gameport);
release_region(gpio, GAMEPORT_EXTENT);
}
}
#else
static inline int solo1_register_gameport(struct solo1_state *s, int io_port) { return -ENOSYS; }
static inline void solo1_unregister_gameport(struct solo1_state *s) { }
#endif /* SUPPORT_JOYSTICK */
static int __devinit solo1_probe(struct pci_dev *pcidev, const struct pci_device_id *pciid) static int __devinit solo1_probe(struct pci_dev *pcidev, const struct pci_device_id *pciid)
{ {
struct solo1_state *s; struct solo1_state *s;
@ -2438,11 +2458,7 @@ static void __devexit solo1_remove(struct pci_dev *dev)
synchronize_irq(s->irq); synchronize_irq(s->irq);
pci_write_config_word(s->dev, 0x60, 0); /* turn off DDMA controller address space */ pci_write_config_word(s->dev, 0x60, 0); /* turn off DDMA controller address space */
free_irq(s->irq, s); free_irq(s->irq, s);
if (s->gameport) { solo1_unregister_gameport(s);
int gpio = s->gameport->io;
gameport_unregister_port(s->gameport);
release_region(gpio, GAMEPORT_EXTENT);
}
release_region(s->iobase, IOBASE_EXTENT); release_region(s->iobase, IOBASE_EXTENT);
release_region(s->sbbase+FMSYNTH_EXTENT, SBBASE_EXTENT-FMSYNTH_EXTENT); release_region(s->sbbase+FMSYNTH_EXTENT, SBBASE_EXTENT-FMSYNTH_EXTENT);
release_region(s->ddmabase, DDMABASE_EXTENT); release_region(s->ddmabase, DDMABASE_EXTENT);

View file

@ -50,9 +50,12 @@
#include "sb.h" #include "sb.h"
#include "mpu401.h" #include "mpu401.h"
#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE))
#define SUPPORT_JOYSTICK 1
#endif
static int mad16_conf; static int mad16_conf;
static int mad16_cdsel; static int mad16_cdsel;
static struct gameport *gameport;
static DEFINE_SPINLOCK(lock); static DEFINE_SPINLOCK(lock);
#define C928 1 #define C928 1
@ -902,6 +905,10 @@ static int __initdata irq_map[16] =
-1, -1, -1, -1 -1, -1, -1, -1
}; };
#ifdef SUPPORT_JOYSTICK
static struct gameport *gameport;
static int __devinit mad16_register_gameport(int io_port) static int __devinit mad16_register_gameport(int io_port)
{ {
if (!request_region(io_port, 1, "mad16 gameport")) { if (!request_region(io_port, 1, "mad16 gameport")) {
@ -925,6 +932,20 @@ static int __devinit mad16_register_gameport(int io_port)
return 0; return 0;
} }
static inline void mad16_unregister_gameport(void)
{
if (gameport) {
/* the gameport was initialized so we must free it up */
gameport_unregister_port(gameport);
gameport = NULL;
release_region(0x201, 1);
}
}
#else
static inline int mad16_register_gameport(int io_port) { return -ENOSYS; }
static inline void mad16_unregister_gameport(void) { }
#endif
static int __devinit init_mad16(void) static int __devinit init_mad16(void)
{ {
int dmatype = 0; int dmatype = 0;
@ -1060,12 +1081,7 @@ static void __exit cleanup_mad16(void)
{ {
if (found_mpu) if (found_mpu)
unload_mad16_mpu(&cfg_mpu); unload_mad16_mpu(&cfg_mpu);
if (gameport) { mad16_unregister_gameport();
/* the gameport was initialized so we must free it up */
gameport_unregister_port(gameport);
gameport = NULL;
release_region(0x201, 1);
}
unload_mad16(&cfg); unload_mad16(&cfg);
release_region(MC0_PORT, 12); release_region(MC0_PORT, 12);
} }

View file

@ -122,6 +122,9 @@
#include "dm.h" #include "dm.h"
#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE))
#define SUPPORT_JOYSTICK 1
#endif
/* --------------------------------------------------------------------- */ /* --------------------------------------------------------------------- */
@ -365,7 +368,9 @@ struct sv_state {
unsigned char obuf[MIDIOUTBUF]; unsigned char obuf[MIDIOUTBUF];
} midi; } midi;
#if SUPPORT_JOYSTICK
struct gameport *gameport; struct gameport *gameport;
#endif
}; };
/* --------------------------------------------------------------------- */ /* --------------------------------------------------------------------- */
@ -2485,6 +2490,7 @@ static struct initvol {
#define RSRCISIOREGION(dev,num) (pci_resource_start((dev), (num)) != 0 && \ #define RSRCISIOREGION(dev,num) (pci_resource_start((dev), (num)) != 0 && \
(pci_resource_flags((dev), (num)) & IORESOURCE_IO)) (pci_resource_flags((dev), (num)) & IORESOURCE_IO))
#ifdef SUPPORT_JOYSTICK
static int __devinit sv_register_gameport(struct sv_state *s, int io_port) static int __devinit sv_register_gameport(struct sv_state *s, int io_port)
{ {
struct gameport *gp; struct gameport *gp;
@ -2511,6 +2517,19 @@ static int __devinit sv_register_gameport(struct sv_state *s, int io_port)
return 0; return 0;
} }
static inline void sv_unregister_gameport(struct sv_state *s)
{
if (s->gameport) {
int gpio = s->gameport->io;
gameport_unregister_port(s->gameport);
release_region(gpio, SV_EXTENT_GAME);
}
}
#else
static inline int sv_register_gameport(struct sv_state *s, int io_port) { return -ENOSYS; }
static inline void sv_unregister_gameport(struct sv_state *s) { }
#endif /* SUPPORT_JOYSTICK */
static int __devinit sv_probe(struct pci_dev *pcidev, const struct pci_device_id *pciid) static int __devinit sv_probe(struct pci_dev *pcidev, const struct pci_device_id *pciid)
{ {
static char __devinitdata sv_ddma_name[] = "S3 Inc. SonicVibes DDMA Controller"; static char __devinitdata sv_ddma_name[] = "S3 Inc. SonicVibes DDMA Controller";
@ -2711,11 +2730,7 @@ static void __devexit sv_remove(struct pci_dev *dev)
/*outb(0, s->iodmaa + SV_DMA_RESET);*/ /*outb(0, s->iodmaa + SV_DMA_RESET);*/
/*outb(0, s->iodmac + SV_DMA_RESET);*/ /*outb(0, s->iodmac + SV_DMA_RESET);*/
free_irq(s->irq, s); free_irq(s->irq, s);
if (s->gameport) { sv_unregister_gameport(s);
int gpio = s->gameport->io;
gameport_unregister_port(s->gameport);
release_region(gpio, SV_EXTENT_GAME);
}
release_region(s->iodmac, SV_EXTENT_DMA); release_region(s->iodmac, SV_EXTENT_DMA);
release_region(s->iodmaa, SV_EXTENT_DMA); release_region(s->iodmaa, SV_EXTENT_DMA);
release_region(s->ioenh, SV_EXTENT_ENH); release_region(s->ioenh, SV_EXTENT_ENH);

View file

@ -228,6 +228,10 @@
#define DRIVER_VERSION "0.14.10j-2.6" #define DRIVER_VERSION "0.14.10j-2.6"
#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE))
#define SUPPORT_JOYSTICK 1
#endif
/* magic numbers to protect our data structures */ /* magic numbers to protect our data structures */
#define TRIDENT_CARD_MAGIC 0x5072696E /* "Prin" */ #define TRIDENT_CARD_MAGIC 0x5072696E /* "Prin" */
#define TRIDENT_STATE_MAGIC 0x63657373 /* "cess" */ #define TRIDENT_STATE_MAGIC 0x63657373 /* "cess" */
@ -4252,24 +4256,25 @@ trident_ac97_init(struct trident_card *card)
return num_ac97 + 1; return num_ac97 + 1;
} }
#ifdef SUPPORT_JOYSTICK
/* Gameport functions for the cards ADC gameport */ /* Gameport functions for the cards ADC gameport */
static unsigned char static unsigned char trident_game_read(struct gameport *gameport)
trident_game_read(struct gameport *gameport)
{ {
struct trident_card *card = gameport->port_data; struct trident_card *card = gameport->port_data;
return inb(TRID_REG(card, T4D_GAME_LEG)); return inb(TRID_REG(card, T4D_GAME_LEG));
} }
static void static void trident_game_trigger(struct gameport *gameport)
trident_game_trigger(struct gameport *gameport)
{ {
struct trident_card *card = gameport->port_data; struct trident_card *card = gameport->port_data;
outb(0xff, TRID_REG(card, T4D_GAME_LEG)); outb(0xff, TRID_REG(card, T4D_GAME_LEG));
} }
static int static int trident_game_cooked_read(struct gameport *gameport,
trident_game_cooked_read(struct gameport *gameport, int *axes, int *buttons) int *axes, int *buttons)
{ {
struct trident_card *card = gameport->port_data; struct trident_card *card = gameport->port_data;
int i; int i;
@ -4285,8 +4290,7 @@ trident_game_cooked_read(struct gameport *gameport, int *axes, int *buttons)
return 0; return 0;
} }
static int static int trident_game_open(struct gameport *gameport, int mode)
trident_game_open(struct gameport *gameport, int mode)
{ {
struct trident_card *card = gameport->port_data; struct trident_card *card = gameport->port_data;
@ -4305,8 +4309,7 @@ trident_game_open(struct gameport *gameport, int mode)
return 0; return 0;
} }
static int __devinit static int __devinit trident_register_gameport(struct trident_card *card)
trident_register_gameport(struct trident_card *card)
{ {
struct gameport *gp; struct gameport *gp;
@ -4330,6 +4333,17 @@ trident_register_gameport(struct trident_card *card)
return 0; return 0;
} }
static inline void trident_unregister_gameport(struct trident_card *card)
{
if (card->gameport)
gameport_unregister_port(card->gameport);
}
#else
static inline int trident_register_gameport(struct trident_card *card) { return -ENOSYS; }
static inline void trident_unregister_gameport(struct trident_card *card) { }
#endif /* SUPPORT_JOYSTICK */
/* install the driver, we do not allocate hardware channel nor DMA buffer */ /* install the driver, we do not allocate hardware channel nor DMA buffer */
/* now, they are defered until "ACCESS" time (in prog_dmabuf called by */ /* now, they are defered until "ACCESS" time (in prog_dmabuf called by */
/* open/read/write/ioctl/mmap) */ /* open/read/write/ioctl/mmap) */
@ -4569,8 +4583,7 @@ trident_remove(struct pci_dev *pci_dev)
} }
/* Unregister gameport */ /* Unregister gameport */
if (card->gameport) trident_unregister_gameport(card);
gameport_unregister_port(card->gameport);
/* Kill interrupts, and SP/DIF */ /* Kill interrupts, and SP/DIF */
trident_disable_loop_interrupts(card); trident_disable_loop_interrupts(card);

View file

@ -1338,11 +1338,6 @@ static inline int snd_cs4281_create_gameport(cs4281_t *chip) { return -ENOSYS; }
static inline void snd_cs4281_free_gameport(cs4281_t *chip) { } static inline void snd_cs4281_free_gameport(cs4281_t *chip) { }
#endif /* CONFIG_GAMEPORT || (MODULE && CONFIG_GAMEPORT_MODULE) */ #endif /* CONFIG_GAMEPORT || (MODULE && CONFIG_GAMEPORT_MODULE) */
/*
*/
static int snd_cs4281_free(cs4281_t *chip) static int snd_cs4281_free(cs4281_t *chip)
{ {
snd_cs4281_free_gameport(chip); snd_cs4281_free_gameport(chip);