You've already forked linux-apfs
mirror of
https://github.com/linux-apfs/linux-apfs.git
synced 2026-05-01 15:00:59 -07:00
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:
@@ -1115,7 +1115,7 @@ running once the system is up.
|
||||
See Documentation/ramdisk.txt.
|
||||
|
||||
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
|
||||
per second.
|
||||
psmouse.resetafter=
|
||||
|
||||
+337
-90
@@ -21,6 +21,7 @@
|
||||
#include <linux/smp_lock.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/devfs_fs_kernel.h>
|
||||
#include <linux/compat.h>
|
||||
|
||||
struct evdev {
|
||||
int exist;
|
||||
@@ -145,6 +146,41 @@ static int evdev_open(struct inode * inode, struct file * file)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_COMPAT
|
||||
struct input_event_compat {
|
||||
struct compat_timeval time;
|
||||
__u16 type;
|
||||
__u16 code;
|
||||
__s32 value;
|
||||
};
|
||||
|
||||
#ifdef CONFIG_X86_64
|
||||
# define COMPAT_TEST test_thread_flag(TIF_IA32)
|
||||
#elif defined(CONFIG_IA64)
|
||||
# define COMPAT_TEST IS_IA32_PROCESS(ia64_task_regs(current))
|
||||
#elif defined(CONFIG_ARCH_S390)
|
||||
# define COMPAT_TEST test_thread_flag(TIF_31BIT)
|
||||
#else
|
||||
# define COMPAT_TEST test_thread_flag(TIF_32BIT)
|
||||
#endif
|
||||
|
||||
static ssize_t evdev_write_compat(struct file * file, const char __user * buffer, size_t count, loff_t *ppos)
|
||||
{
|
||||
struct evdev_list *list = file->private_data;
|
||||
struct input_event_compat event;
|
||||
int retval = 0;
|
||||
|
||||
while (retval < count) {
|
||||
if (copy_from_user(&event, buffer + retval, sizeof(struct input_event_compat)))
|
||||
return -EFAULT;
|
||||
input_event(list->evdev->handle.dev, event.type, event.code, event.value);
|
||||
retval += sizeof(struct input_event_compat);
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
#endif
|
||||
|
||||
static ssize_t evdev_write(struct file * file, const char __user * buffer, size_t count, loff_t *ppos)
|
||||
{
|
||||
struct evdev_list *list = file->private_data;
|
||||
@@ -153,6 +189,11 @@ static ssize_t evdev_write(struct file * file, const char __user * buffer, size_
|
||||
|
||||
if (!list->evdev->exist) return -ENODEV;
|
||||
|
||||
#ifdef CONFIG_COMPAT
|
||||
if (COMPAT_TEST)
|
||||
return evdev_write_compat(file, buffer, count, ppos);
|
||||
#endif
|
||||
|
||||
while (retval < count) {
|
||||
|
||||
if (copy_from_user(&event, buffer + retval, sizeof(struct input_event)))
|
||||
@@ -164,11 +205,56 @@ static ssize_t evdev_write(struct file * file, const char __user * buffer, size_
|
||||
return retval;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_COMPAT
|
||||
static ssize_t evdev_read_compat(struct file * file, char __user * buffer, size_t count, loff_t *ppos)
|
||||
{
|
||||
struct evdev_list *list = file->private_data;
|
||||
int retval;
|
||||
|
||||
if (count < sizeof(struct input_event_compat))
|
||||
return -EINVAL;
|
||||
|
||||
if (list->head == list->tail && list->evdev->exist && (file->f_flags & O_NONBLOCK))
|
||||
return -EAGAIN;
|
||||
|
||||
retval = wait_event_interruptible(list->evdev->wait,
|
||||
list->head != list->tail || (!list->evdev->exist));
|
||||
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
if (!list->evdev->exist)
|
||||
return -ENODEV;
|
||||
|
||||
while (list->head != list->tail && retval + sizeof(struct input_event_compat) <= count) {
|
||||
struct input_event *event = (struct input_event *) list->buffer + list->tail;
|
||||
struct input_event_compat event_compat;
|
||||
event_compat.time.tv_sec = event->time.tv_sec;
|
||||
event_compat.time.tv_usec = event->time.tv_usec;
|
||||
event_compat.type = event->type;
|
||||
event_compat.code = event->code;
|
||||
event_compat.value = event->value;
|
||||
|
||||
if (copy_to_user(buffer + retval, &event_compat,
|
||||
sizeof(struct input_event_compat))) return -EFAULT;
|
||||
list->tail = (list->tail + 1) & (EVDEV_BUFFER_SIZE - 1);
|
||||
retval += sizeof(struct input_event_compat);
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
#endif
|
||||
|
||||
static ssize_t evdev_read(struct file * file, char __user * buffer, size_t count, loff_t *ppos)
|
||||
{
|
||||
struct evdev_list *list = file->private_data;
|
||||
int retval;
|
||||
|
||||
#ifdef CONFIG_COMPAT
|
||||
if (COMPAT_TEST)
|
||||
return evdev_read_compat(file, buffer, count, ppos);
|
||||
#endif
|
||||
|
||||
if (count < sizeof(struct input_event))
|
||||
return -EINVAL;
|
||||
|
||||
@@ -186,7 +272,7 @@ static ssize_t evdev_read(struct file * file, char __user * buffer, size_t count
|
||||
|
||||
while (list->head != list->tail && retval + sizeof(struct input_event) <= count) {
|
||||
if (copy_to_user(buffer + retval, list->buffer + list->tail,
|
||||
sizeof(struct input_event))) return -EFAULT;
|
||||
sizeof(struct input_event))) return -EFAULT;
|
||||
list->tail = (list->tail + 1) & (EVDEV_BUFFER_SIZE - 1);
|
||||
retval += sizeof(struct input_event);
|
||||
}
|
||||
@@ -203,7 +289,7 @@ static unsigned int evdev_poll(struct file *file, poll_table *wait)
|
||||
(list->evdev->exist ? 0 : (POLLHUP | POLLERR));
|
||||
}
|
||||
|
||||
static int evdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
|
||||
static long evdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
struct evdev_list *list = file->private_data;
|
||||
struct evdev *evdev = list->evdev;
|
||||
@@ -285,110 +371,268 @@ static int evdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
|
||||
|
||||
default:
|
||||
|
||||
if (_IOC_TYPE(cmd) != 'E' || _IOC_DIR(cmd) != _IOC_READ)
|
||||
if (_IOC_TYPE(cmd) != 'E')
|
||||
return -EINVAL;
|
||||
|
||||
if ((_IOC_NR(cmd) & ~EV_MAX) == _IOC_NR(EVIOCGBIT(0,0))) {
|
||||
if (_IOC_DIR(cmd) == _IOC_READ) {
|
||||
|
||||
long *bits;
|
||||
int len;
|
||||
if ((_IOC_NR(cmd) & ~EV_MAX) == _IOC_NR(EVIOCGBIT(0,0))) {
|
||||
|
||||
switch (_IOC_NR(cmd) & EV_MAX) {
|
||||
case 0: bits = dev->evbit; len = EV_MAX; break;
|
||||
case EV_KEY: bits = dev->keybit; len = KEY_MAX; break;
|
||||
case EV_REL: bits = dev->relbit; len = REL_MAX; break;
|
||||
case EV_ABS: bits = dev->absbit; len = ABS_MAX; break;
|
||||
case EV_MSC: bits = dev->mscbit; len = MSC_MAX; break;
|
||||
case EV_LED: bits = dev->ledbit; len = LED_MAX; break;
|
||||
case EV_SND: bits = dev->sndbit; len = SND_MAX; break;
|
||||
case EV_FF: bits = dev->ffbit; len = FF_MAX; break;
|
||||
default: return -EINVAL;
|
||||
long *bits;
|
||||
int len;
|
||||
|
||||
switch (_IOC_NR(cmd) & EV_MAX) {
|
||||
case 0: bits = dev->evbit; len = EV_MAX; break;
|
||||
case EV_KEY: bits = dev->keybit; len = KEY_MAX; break;
|
||||
case EV_REL: bits = dev->relbit; len = REL_MAX; break;
|
||||
case EV_ABS: bits = dev->absbit; len = ABS_MAX; break;
|
||||
case EV_MSC: bits = dev->mscbit; len = MSC_MAX; break;
|
||||
case EV_LED: bits = dev->ledbit; len = LED_MAX; break;
|
||||
case EV_SND: bits = dev->sndbit; len = SND_MAX; break;
|
||||
case EV_FF: bits = dev->ffbit; len = FF_MAX; break;
|
||||
default: return -EINVAL;
|
||||
}
|
||||
len = NBITS(len) * sizeof(long);
|
||||
if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
|
||||
return copy_to_user(p, bits, len) ? -EFAULT : len;
|
||||
}
|
||||
len = NBITS(len) * sizeof(long);
|
||||
if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
|
||||
return copy_to_user(p, bits, len) ? -EFAULT : len;
|
||||
|
||||
if (_IOC_NR(cmd) == _IOC_NR(EVIOCGKEY(0))) {
|
||||
int len;
|
||||
len = NBITS(KEY_MAX) * sizeof(long);
|
||||
if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
|
||||
return copy_to_user(p, dev->key, len) ? -EFAULT : len;
|
||||
}
|
||||
|
||||
if (_IOC_NR(cmd) == _IOC_NR(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))) {
|
||||
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_DIR(cmd) == _IOC_WRITE) {
|
||||
|
||||
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) & ~ABS_MAX) == _IOC_NR(EVIOCSABS(0))) {
|
||||
|
||||
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;
|
||||
}
|
||||
int t = _IOC_NR(cmd) & ABS_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 (copy_from_user(&abs, p, sizeof(struct input_absinfo)))
|
||||
return -EFAULT;
|
||||
|
||||
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;
|
||||
}
|
||||
dev->abs[t] = abs.value;
|
||||
dev->absmin[t] = abs.minimum;
|
||||
dev->absmax[t] = abs.maximum;
|
||||
dev->absfuzz[t] = abs.fuzz;
|
||||
dev->absflat[t] = abs.flat;
|
||||
|
||||
if (_IOC_NR(cmd) == _IOC_NR(EVIOCGUNIQ(0))) {
|
||||
int len;
|
||||
if (!dev->uniq) return -ENOENT;
|
||||
len = strlen(dev->uniq) + 1;
|
||||
if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
|
||||
return copy_to_user(p, dev->uniq, len) ? -EFAULT : len;
|
||||
}
|
||||
|
||||
if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCGABS(0))) {
|
||||
|
||||
int t = _IOC_NR(cmd) & ABS_MAX;
|
||||
|
||||
abs.value = dev->abs[t];
|
||||
abs.minimum = dev->absmin[t];
|
||||
abs.maximum = dev->absmax[t];
|
||||
abs.fuzz = dev->absfuzz[t];
|
||||
abs.flat = dev->absflat[t];
|
||||
|
||||
if (copy_to_user(p, &abs, sizeof(struct input_absinfo)))
|
||||
return -EFAULT;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCSABS(0))) {
|
||||
|
||||
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 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
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 = {
|
||||
.owner = THIS_MODULE,
|
||||
.read = evdev_read,
|
||||
@@ -396,7 +640,10 @@ static struct file_operations evdev_fops = {
|
||||
.poll = evdev_poll,
|
||||
.open = evdev_open,
|
||||
.release = evdev_release,
|
||||
.ioctl = evdev_ioctl,
|
||||
.unlocked_ioctl = evdev_ioctl,
|
||||
#ifdef CONFIG_COMPAT
|
||||
.compat_ioctl = evdev_ioctl_compat,
|
||||
#endif
|
||||
.fasync = evdev_fasync,
|
||||
.flush = evdev_flush
|
||||
};
|
||||
|
||||
@@ -49,22 +49,8 @@ config GAMEPORT_EMU10K1
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called emu10k1-gp.
|
||||
|
||||
config GAMEPORT_VORTEX
|
||||
tristate "Aureal Vortex, Vortex 2 gameport support"
|
||||
depends on PCI
|
||||
help
|
||||
Say Y here if you have an Aureal Vortex 1 or 2 card and want
|
||||
to use its gameport.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called vortex.
|
||||
|
||||
config GAMEPORT_FM801
|
||||
tristate "ForteMedia FM801 gameport support"
|
||||
depends on PCI
|
||||
|
||||
config GAMEPORT_CS461X
|
||||
tristate "Crystal SoundFusion gameport support"
|
||||
depends on PCI
|
||||
|
||||
endif
|
||||
|
||||
@@ -5,9 +5,7 @@
|
||||
# Each configuration option enables a list of files.
|
||||
|
||||
obj-$(CONFIG_GAMEPORT) += gameport.o
|
||||
obj-$(CONFIG_GAMEPORT_CS461X) += cs461x.o
|
||||
obj-$(CONFIG_GAMEPORT_EMU10K1) += emu10k1-gp.o
|
||||
obj-$(CONFIG_GAMEPORT_FM801) += fm801-gp.o
|
||||
obj-$(CONFIG_GAMEPORT_L4) += lightning.o
|
||||
obj-$(CONFIG_GAMEPORT_NS558) += ns558.o
|
||||
obj-$(CONFIG_GAMEPORT_VORTEX) += vortex.o
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -258,18 +258,18 @@ static int __init ns558_init(void)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
if (pnp_register_driver(&ns558_pnp_driver) >= 0)
|
||||
pnp_registered = 1;
|
||||
|
||||
/*
|
||||
* Probe ISA ports first so that PnP gets to choose free port addresses
|
||||
* not occupied by the ISA ports.
|
||||
* Probe ISA ports after PnP, so that PnP ports that are already
|
||||
* enabled get detected as PnP. This may be suboptimal in multi-device
|
||||
* configurations, but saves hassle with simple setups.
|
||||
*/
|
||||
|
||||
while (ns558_isa_portlist[i])
|
||||
ns558_isa_probe(ns558_isa_portlist[i++]);
|
||||
|
||||
if (pnp_register_driver(&ns558_pnp_driver) >= 0)
|
||||
pnp_registered = 1;
|
||||
|
||||
|
||||
return (list_empty(&ns558_list) && !pnp_registered) ? -ENODEV : 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
+32
-5
@@ -219,10 +219,24 @@ void input_release_device(struct input_handle *handle)
|
||||
|
||||
int input_open_device(struct input_handle *handle)
|
||||
{
|
||||
struct input_dev *dev = handle->dev;
|
||||
int err;
|
||||
|
||||
err = down_interruptible(&dev->sem);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
handle->open++;
|
||||
if (handle->dev->open)
|
||||
return handle->dev->open(handle->dev);
|
||||
return 0;
|
||||
|
||||
if (!dev->users++ && dev->open)
|
||||
err = dev->open(dev);
|
||||
|
||||
if (err)
|
||||
handle->open--;
|
||||
|
||||
up(&dev->sem);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int input_flush_device(struct input_handle* handle, struct file* file)
|
||||
@@ -235,10 +249,17 @@ int input_flush_device(struct input_handle* handle, struct file* file)
|
||||
|
||||
void input_close_device(struct input_handle *handle)
|
||||
{
|
||||
struct input_dev *dev = handle->dev;
|
||||
|
||||
input_release_device(handle);
|
||||
if (handle->dev->close)
|
||||
handle->dev->close(handle->dev);
|
||||
|
||||
down(&dev->sem);
|
||||
|
||||
if (!--dev->users && dev->close)
|
||||
dev->close(dev);
|
||||
handle->open--;
|
||||
|
||||
up(&dev->sem);
|
||||
}
|
||||
|
||||
static void input_link_handle(struct input_handle *handle)
|
||||
@@ -415,6 +436,8 @@ void input_register_device(struct input_dev *dev)
|
||||
|
||||
set_bit(EV_SYN, dev->evbit);
|
||||
|
||||
init_MUTEX(&dev->sem);
|
||||
|
||||
/*
|
||||
* If delay and period are pre-set by the driver, then autorepeating
|
||||
* is handled by the driver itself and we don't do it in input.c.
|
||||
@@ -674,6 +697,8 @@ static int input_handlers_read(char *buf, char **start, off_t pos, int count, in
|
||||
return (count > cnt) ? cnt : count;
|
||||
}
|
||||
|
||||
static struct file_operations input_fileops;
|
||||
|
||||
static int __init input_proc_init(void)
|
||||
{
|
||||
struct proc_dir_entry *entry;
|
||||
@@ -688,6 +713,8 @@ static int __init input_proc_init(void)
|
||||
return -ENOMEM;
|
||||
}
|
||||
entry->owner = THIS_MODULE;
|
||||
input_fileops = *entry->proc_fops;
|
||||
entry->proc_fops = &input_fileops;
|
||||
entry->proc_fops->poll = input_devices_poll;
|
||||
entry = create_proc_read_entry("handlers", 0, proc_bus_input_dir, input_handlers_read, NULL);
|
||||
if (entry == NULL) {
|
||||
|
||||
+91
-25
@@ -285,48 +285,33 @@ static unsigned int joydev_poll(struct file *file, poll_table *wait)
|
||||
(POLLIN | POLLRDNORM) : 0) | (list->joydev->exist ? 0 : (POLLHUP | POLLERR));
|
||||
}
|
||||
|
||||
static int joydev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
|
||||
static int joydev_ioctl_common(struct joydev *joydev, unsigned int cmd, void __user *argp)
|
||||
{
|
||||
struct joydev_list *list = file->private_data;
|
||||
struct joydev *joydev = list->joydev;
|
||||
struct input_dev *dev = joydev->handle.dev;
|
||||
void __user *argp = (void __user *)arg;
|
||||
int i, j;
|
||||
|
||||
if (!joydev->exist) return -ENODEV;
|
||||
|
||||
switch (cmd) {
|
||||
|
||||
case JS_SET_CAL:
|
||||
return copy_from_user(&joydev->glue.JS_CORR, argp,
|
||||
sizeof(struct JS_DATA_TYPE)) ? -EFAULT : 0;
|
||||
sizeof(joydev->glue.JS_CORR)) ? -EFAULT : 0;
|
||||
case JS_GET_CAL:
|
||||
return copy_to_user(argp, &joydev->glue.JS_CORR,
|
||||
sizeof(struct JS_DATA_TYPE)) ? -EFAULT : 0;
|
||||
sizeof(joydev->glue.JS_CORR)) ? -EFAULT : 0;
|
||||
case JS_SET_TIMEOUT:
|
||||
return get_user(joydev->glue.JS_TIMEOUT, (int __user *) arg);
|
||||
return get_user(joydev->glue.JS_TIMEOUT, (s32 __user *) argp);
|
||||
case JS_GET_TIMEOUT:
|
||||
return put_user(joydev->glue.JS_TIMEOUT, (int __user *) arg);
|
||||
case JS_SET_TIMELIMIT:
|
||||
return get_user(joydev->glue.JS_TIMELIMIT, (long __user *) arg);
|
||||
case JS_GET_TIMELIMIT:
|
||||
return put_user(joydev->glue.JS_TIMELIMIT, (long __user *) arg);
|
||||
case JS_SET_ALL:
|
||||
return copy_from_user(&joydev->glue, argp,
|
||||
sizeof(struct JS_DATA_SAVE_TYPE)) ? -EFAULT : 0;
|
||||
case JS_GET_ALL:
|
||||
return copy_to_user(argp, &joydev->glue,
|
||||
sizeof(struct JS_DATA_SAVE_TYPE)) ? -EFAULT : 0;
|
||||
return put_user(joydev->glue.JS_TIMEOUT, (s32 __user *) argp);
|
||||
|
||||
case JSIOCGVERSION:
|
||||
return put_user(JS_VERSION, (__u32 __user *) arg);
|
||||
return put_user(JS_VERSION, (__u32 __user *) argp);
|
||||
case JSIOCGAXES:
|
||||
return put_user(joydev->nabs, (__u8 __user *) arg);
|
||||
return put_user(joydev->nabs, (__u8 __user *) argp);
|
||||
case JSIOCGBUTTONS:
|
||||
return put_user(joydev->nkey, (__u8 __user *) arg);
|
||||
return put_user(joydev->nkey, (__u8 __user *) argp);
|
||||
case JSIOCSCORR:
|
||||
if (copy_from_user(joydev->corr, argp,
|
||||
sizeof(struct js_corr) * joydev->nabs))
|
||||
sizeof(joydev->corr[0]) * joydev->nabs))
|
||||
return -EFAULT;
|
||||
for (i = 0; i < joydev->nabs; i++) {
|
||||
j = joydev->abspam[i];
|
||||
@@ -335,7 +320,7 @@ static int joydev_ioctl(struct inode *inode, struct file *file, unsigned int cmd
|
||||
return 0;
|
||||
case JSIOCGCORR:
|
||||
return copy_to_user(argp, joydev->corr,
|
||||
sizeof(struct js_corr) * joydev->nabs) ? -EFAULT : 0;
|
||||
sizeof(joydev->corr[0]) * joydev->nabs) ? -EFAULT : 0;
|
||||
case JSIOCSAXMAP:
|
||||
if (copy_from_user(joydev->abspam, argp, sizeof(__u8) * (ABS_MAX + 1)))
|
||||
return -EFAULT;
|
||||
@@ -371,6 +356,84 @@ static int joydev_ioctl(struct inode *inode, struct file *file, unsigned int cmd
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_COMPAT
|
||||
static long joydev_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
struct joydev_list *list = file->private_data;
|
||||
struct joydev *joydev = list->joydev;
|
||||
void __user *argp = (void __user *)arg;
|
||||
s32 tmp32;
|
||||
struct JS_DATA_SAVE_TYPE_32 ds32;
|
||||
int err;
|
||||
|
||||
if (!joydev->exist) return -ENODEV;
|
||||
switch(cmd) {
|
||||
case JS_SET_TIMELIMIT:
|
||||
err = get_user(tmp32, (s32 __user *) arg);
|
||||
if (err == 0)
|
||||
joydev->glue.JS_TIMELIMIT = tmp32;
|
||||
break;
|
||||
case JS_GET_TIMELIMIT:
|
||||
tmp32 = joydev->glue.JS_TIMELIMIT;
|
||||
err = put_user(tmp32, (s32 __user *) arg);
|
||||
break;
|
||||
|
||||
case JS_SET_ALL:
|
||||
err = copy_from_user(&ds32, argp,
|
||||
sizeof(ds32)) ? -EFAULT : 0;
|
||||
if (err == 0) {
|
||||
joydev->glue.JS_TIMEOUT = ds32.JS_TIMEOUT;
|
||||
joydev->glue.BUSY = ds32.BUSY;
|
||||
joydev->glue.JS_EXPIRETIME = ds32.JS_EXPIRETIME;
|
||||
joydev->glue.JS_TIMELIMIT = ds32.JS_TIMELIMIT;
|
||||
joydev->glue.JS_SAVE = ds32.JS_SAVE;
|
||||
joydev->glue.JS_CORR = ds32.JS_CORR;
|
||||
}
|
||||
break;
|
||||
|
||||
case JS_GET_ALL:
|
||||
ds32.JS_TIMEOUT = joydev->glue.JS_TIMEOUT;
|
||||
ds32.BUSY = joydev->glue.BUSY;
|
||||
ds32.JS_EXPIRETIME = joydev->glue.JS_EXPIRETIME;
|
||||
ds32.JS_TIMELIMIT = joydev->glue.JS_TIMELIMIT;
|
||||
ds32.JS_SAVE = joydev->glue.JS_SAVE;
|
||||
ds32.JS_CORR = joydev->glue.JS_CORR;
|
||||
|
||||
err = copy_to_user(argp, &ds32,
|
||||
sizeof(ds32)) ? -EFAULT : 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
err = joydev_ioctl_common(joydev, cmd, argp);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
#endif /* CONFIG_COMPAT */
|
||||
|
||||
static int joydev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
struct joydev_list *list = file->private_data;
|
||||
struct joydev *joydev = list->joydev;
|
||||
void __user *argp = (void __user *)arg;
|
||||
|
||||
if (!joydev->exist) return -ENODEV;
|
||||
|
||||
switch(cmd) {
|
||||
case JS_SET_TIMELIMIT:
|
||||
return get_user(joydev->glue.JS_TIMELIMIT, (long __user *) arg);
|
||||
case JS_GET_TIMELIMIT:
|
||||
return put_user(joydev->glue.JS_TIMELIMIT, (long __user *) arg);
|
||||
case JS_SET_ALL:
|
||||
return copy_from_user(&joydev->glue, argp,
|
||||
sizeof(joydev->glue)) ? -EFAULT : 0;
|
||||
case JS_GET_ALL:
|
||||
return copy_to_user(argp, &joydev->glue,
|
||||
sizeof(joydev->glue)) ? -EFAULT : 0;
|
||||
default:
|
||||
return joydev_ioctl_common(joydev, cmd, argp);
|
||||
}
|
||||
}
|
||||
|
||||
static struct file_operations joydev_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.read = joydev_read,
|
||||
@@ -379,6 +442,9 @@ static struct file_operations joydev_fops = {
|
||||
.open = joydev_open,
|
||||
.release = joydev_release,
|
||||
.ioctl = joydev_ioctl,
|
||||
#ifdef CONFIG_COMPAT
|
||||
.compat_ioctl = joydev_compat_ioctl,
|
||||
#endif
|
||||
.fasync = joydev_fasync,
|
||||
};
|
||||
|
||||
|
||||
@@ -185,7 +185,7 @@ static void a3d_poll(struct gameport *gameport)
|
||||
a3d->reads++;
|
||||
if (a3d_read_packet(a3d->gameport, a3d->length, data) != a3d->length ||
|
||||
data[0] != a3d->mode || a3d_csum(data, a3d->length))
|
||||
a3d->bads++;
|
||||
a3d->bads++;
|
||||
else
|
||||
a3d_read(a3d, data);
|
||||
}
|
||||
|
||||
@@ -82,7 +82,7 @@ static char adi_cm2_abs[] = { ABS_X, ABS_Y, ABS_Z, ABS_RX, ABS_RY, ABS_RZ };
|
||||
static char adi_wmf_abs[] = { ABS_WHEEL, ABS_GAS, ABS_BRAKE, ABS_HAT0X, ABS_HAT0Y, ABS_HAT1X, ABS_HAT1Y, ABS_HAT2X, ABS_HAT2Y };
|
||||
|
||||
static short adi_wmgpe_key[] = { BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_TL, BTN_TR, BTN_START, BTN_MODE, BTN_SELECT };
|
||||
static short adi_wmi_key[] = { BTN_TRIGGER, BTN_TOP, BTN_THUMB, BTN_TOP2, BTN_BASE, BTN_BASE2, BTN_BASE3, BTN_BASE4, BTN_EXTRA };
|
||||
static short adi_wmi_key[] = { BTN_TRIGGER, BTN_TOP, BTN_THUMB, BTN_TOP2, BTN_BASE, BTN_BASE2, BTN_BASE3, BTN_BASE4, BTN_EXTRA };
|
||||
static short adi_wmed3d_key[] = { BTN_TRIGGER, BTN_THUMB, BTN_THUMB2, BTN_TOP, BTN_TOP2, BTN_BASE, BTN_BASE2 };
|
||||
static short adi_cm2_key[] = { BTN_1, BTN_2, BTN_3, BTN_4, BTN_5, BTN_6, BTN_7, BTN_8 };
|
||||
|
||||
@@ -183,7 +183,7 @@ static void adi_move_bits(struct adi_port *port, int length)
|
||||
int i;
|
||||
struct adi *adi = port->adi;
|
||||
|
||||
adi[0].idx = adi[1].idx = 0;
|
||||
adi[0].idx = adi[1].idx = 0;
|
||||
|
||||
if (adi[0].ret <= 0 || adi[1].ret <= 0) return;
|
||||
if (adi[0].data[0] & 0x20 || ~adi[1].data[0] & 0x20) return;
|
||||
|
||||
@@ -51,7 +51,8 @@ MODULE_PARM_DESC(map, "Map of attached joysticks in form of <a>,<b> (default is
|
||||
|
||||
__obsolete_setup("amijoy=");
|
||||
|
||||
static int amijoy_used[2] = { 0, 0 };
|
||||
static int amijoy_used;
|
||||
static DECLARE_MUTEX(amijoy_sem);
|
||||
static struct input_dev amijoy_dev[2];
|
||||
static char *amijoy_phys[2] = { "amijoy/input0", "amijoy/input1" };
|
||||
|
||||
@@ -84,26 +85,30 @@ static irqreturn_t amijoy_interrupt(int irq, void *dummy, struct pt_regs *fp)
|
||||
|
||||
static int amijoy_open(struct input_dev *dev)
|
||||
{
|
||||
int *used = dev->private;
|
||||
int err;
|
||||
|
||||
if ((*used)++)
|
||||
return 0;
|
||||
err = down_interruptible(&amijoy_sem);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (request_irq(IRQ_AMIGA_VERTB, amijoy_interrupt, 0, "amijoy", amijoy_interrupt)) {
|
||||
(*used)--;
|
||||
if (!amijoy_used && request_irq(IRQ_AMIGA_VERTB, amijoy_interrupt, 0, "amijoy", amijoy_interrupt)) {
|
||||
printk(KERN_ERR "amijoy.c: Can't allocate irq %d\n", IRQ_AMIGA_VERTB);
|
||||
return -EBUSY;
|
||||
err = -EBUSY;
|
||||
goto out;
|
||||
}
|
||||
|
||||
return 0;
|
||||
amijoy_used++;
|
||||
out:
|
||||
up(&amijoy_sem);
|
||||
return err;
|
||||
}
|
||||
|
||||
static void amijoy_close(struct input_dev *dev)
|
||||
{
|
||||
int *used = dev->private;
|
||||
|
||||
if (!--(*used))
|
||||
down(&amijoysem);
|
||||
if (!--amijoy_used)
|
||||
free_irq(IRQ_AMIGA_VERTB, amijoy_interrupt);
|
||||
up(&amijoy_sem);
|
||||
}
|
||||
|
||||
static int __init amijoy_init(void)
|
||||
@@ -138,8 +143,6 @@ static int __init amijoy_init(void)
|
||||
amijoy_dev[i].id.product = 0x0003;
|
||||
amijoy_dev[i].id.version = 0x0100;
|
||||
|
||||
amijoy_dev[i].private = amijoy_used + i;
|
||||
|
||||
input_register_device(amijoy_dev + i);
|
||||
printk(KERN_INFO "input: %s at joy%ddat\n", amijoy_name, i);
|
||||
}
|
||||
|
||||
@@ -87,7 +87,7 @@ __obsolete_setup("db9_3=");
|
||||
#define DB9_NORMAL 0x0a
|
||||
#define DB9_NOSELECT 0x08
|
||||
|
||||
#define DB9_MAX_DEVICES 2
|
||||
#define DB9_MAX_DEVICES 2
|
||||
|
||||
#define DB9_GENESIS6_DELAY 14
|
||||
#define DB9_REFRESH_TIME HZ/100
|
||||
@@ -98,6 +98,7 @@ struct db9 {
|
||||
struct pardevice *pd;
|
||||
int mode;
|
||||
int used;
|
||||
struct semaphore sem;
|
||||
char phys[2][32];
|
||||
};
|
||||
|
||||
@@ -503,6 +504,11 @@ static int db9_open(struct input_dev *dev)
|
||||
{
|
||||
struct db9 *db9 = dev->private;
|
||||
struct parport *port = db9->pd->port;
|
||||
int err;
|
||||
|
||||
err = down_interruptible(&db9->sem);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (!db9->used++) {
|
||||
parport_claim(db9->pd);
|
||||
@@ -514,6 +520,7 @@ static int db9_open(struct input_dev *dev)
|
||||
mod_timer(&db9->timer, jiffies + DB9_REFRESH_TIME);
|
||||
}
|
||||
|
||||
up(&db9->sem);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -522,12 +529,14 @@ static void db9_close(struct input_dev *dev)
|
||||
struct db9 *db9 = dev->private;
|
||||
struct parport *port = db9->pd->port;
|
||||
|
||||
down(&db9->sem);
|
||||
if (!--db9->used) {
|
||||
del_timer(&db9->timer);
|
||||
del_timer_sync(&db9->timer);
|
||||
parport_write_control(port, 0x00);
|
||||
parport_data_forward(port);
|
||||
parport_release(db9->pd);
|
||||
}
|
||||
up(&db9->sem);
|
||||
}
|
||||
|
||||
static struct db9 __init *db9_probe(int *config, int nargs)
|
||||
@@ -563,12 +572,12 @@ static struct db9 __init *db9_probe(int *config, int nargs)
|
||||
}
|
||||
}
|
||||
|
||||
if (!(db9 = kmalloc(sizeof(struct db9), GFP_KERNEL))) {
|
||||
if (!(db9 = kcalloc(1, sizeof(struct db9), GFP_KERNEL))) {
|
||||
parport_put_port(pp);
|
||||
return NULL;
|
||||
}
|
||||
memset(db9, 0, sizeof(struct db9));
|
||||
|
||||
init_MUTEX(&db9->sem);
|
||||
db9->mode = config[1];
|
||||
init_timer(&db9->timer);
|
||||
db9->timer.data = (long) db9;
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
/*
|
||||
* NES, SNES, N64, MultiSystem, PSX gamepad driver for Linux
|
||||
*
|
||||
* Copyright (c) 1999-2004 Vojtech Pavlik <vojtech@suse.cz>
|
||||
* Copyright (c) 2004 Peter Nelson <rufus-kernel@hackish.org>
|
||||
* Copyright (c) 1999-2004 Vojtech Pavlik <vojtech@suse.cz>
|
||||
* Copyright (c) 2004 Peter Nelson <rufus-kernel@hackish.org>
|
||||
*
|
||||
* Based on the work of:
|
||||
* Andree Borrmann John Dahlstrom
|
||||
* David Kuder Nathan Hand
|
||||
* Andree Borrmann John Dahlstrom
|
||||
* David Kuder Nathan Hand
|
||||
*/
|
||||
|
||||
/*
|
||||
@@ -81,6 +81,7 @@ struct gc {
|
||||
struct timer_list timer;
|
||||
unsigned char pads[GC_MAX + 1];
|
||||
int used;
|
||||
struct semaphore sem;
|
||||
char phys[5][32];
|
||||
};
|
||||
|
||||
@@ -433,7 +434,7 @@ static void gc_timer(unsigned long private)
|
||||
gc_psx_read_packet(gc, data_psx, data);
|
||||
|
||||
for (i = 0; i < 5; i++) {
|
||||
switch (data[i]) {
|
||||
switch (data[i]) {
|
||||
|
||||
case GC_PSX_RUMBLE:
|
||||
|
||||
@@ -503,22 +504,33 @@ static void gc_timer(unsigned long private)
|
||||
static int gc_open(struct input_dev *dev)
|
||||
{
|
||||
struct gc *gc = dev->private;
|
||||
int err;
|
||||
|
||||
err = down_interruptible(&gc->sem);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (!gc->used++) {
|
||||
parport_claim(gc->pd);
|
||||
parport_write_control(gc->pd->port, 0x04);
|
||||
mod_timer(&gc->timer, jiffies + GC_REFRESH_TIME);
|
||||
}
|
||||
|
||||
up(&gc->sem);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void gc_close(struct input_dev *dev)
|
||||
{
|
||||
struct gc *gc = dev->private;
|
||||
|
||||
down(&gc->sem);
|
||||
if (!--gc->used) {
|
||||
del_timer(&gc->timer);
|
||||
del_timer_sync(&gc->timer);
|
||||
parport_write_control(gc->pd->port, 0x00);
|
||||
parport_release(gc->pd);
|
||||
}
|
||||
up(&gc->sem);
|
||||
}
|
||||
|
||||
static struct gc __init *gc_probe(int *config, int nargs)
|
||||
@@ -542,11 +554,12 @@ static struct gc __init *gc_probe(int *config, int nargs)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!(gc = kmalloc(sizeof(struct gc), GFP_KERNEL))) {
|
||||
if (!(gc = kcalloc(1, sizeof(struct gc), GFP_KERNEL))) {
|
||||
parport_put_port(pp);
|
||||
return NULL;
|
||||
}
|
||||
memset(gc, 0, sizeof(struct gc));
|
||||
|
||||
init_MUTEX(&gc->sem);
|
||||
|
||||
gc->pd = parport_register_device(pp, "gamecon", NULL, NULL, NULL, PARPORT_DEV_EXCL, NULL);
|
||||
|
||||
|
||||
@@ -329,7 +329,7 @@ static int gf2k_connect(struct gameport *gameport, struct gameport_driver *drv)
|
||||
|
||||
for (i = 0; i < gf2k_axes[gf2k->id]; i++) {
|
||||
gf2k->dev.absmax[gf2k_abs[i]] = (i < 2) ? gf2k->dev.abs[gf2k_abs[i]] * 2 - 32 :
|
||||
gf2k->dev.abs[gf2k_abs[0]] + gf2k->dev.abs[gf2k_abs[1]] - 32;
|
||||
gf2k->dev.abs[gf2k_abs[0]] + gf2k->dev.abs[gf2k_abs[1]] - 32;
|
||||
gf2k->dev.absmin[gf2k_abs[i]] = 32;
|
||||
gf2k->dev.absfuzz[gf2k_abs[i]] = 8;
|
||||
gf2k->dev.absflat[gf2k_abs[i]] = (i < 2) ? 24 : 0;
|
||||
|
||||
@@ -171,7 +171,7 @@ static int mp_io(struct gameport* gameport, int sendflags, int sendcode, u32 *pa
|
||||
*packet = 0;
|
||||
raw_data = gameport_read(gameport);
|
||||
if (raw_data & 1)
|
||||
return IO_RETRY;
|
||||
return IO_RETRY;
|
||||
|
||||
for (i = 0; i < 64; i++) {
|
||||
raw_data = gameport_read(gameport);
|
||||
|
||||
@@ -78,6 +78,7 @@ static struct iforce_device iforce_device[] = {
|
||||
{ 0x061c, 0xc0a4, "ACT LABS Force RS", btn_wheel, abs_wheel, ff_iforce }, //?
|
||||
{ 0x06f8, 0x0001, "Guillemot Race Leader Force Feedback", btn_wheel, abs_wheel, ff_iforce }, //?
|
||||
{ 0x06f8, 0x0004, "Guillemot Force Feedback Racing Wheel", btn_wheel, abs_wheel, ff_iforce }, //?
|
||||
{ 0x06f8, 0x0004, "Gullemot Jet Leader 3D", btn_joystick, abs_joystick, ff_iforce }, //?
|
||||
{ 0x0000, 0x0000, "Unknown I-Force Device [%04x:%04x]", btn_joystick, abs_joystick, ff_iforce }
|
||||
};
|
||||
|
||||
|
||||
@@ -229,6 +229,7 @@ static struct usb_device_id iforce_usb_ids [] = {
|
||||
{ USB_DEVICE(0x061c, 0xc0a4) }, /* ACT LABS Force RS */
|
||||
{ USB_DEVICE(0x06f8, 0x0001) }, /* Guillemot Race Leader Force Feedback */
|
||||
{ USB_DEVICE(0x06f8, 0x0004) }, /* Guillemot Force Feedback Racing Wheel */
|
||||
{ USB_DEVICE(0x06f8, 0xa302) }, /* Guillemot Jet Leader 3D */
|
||||
{ } /* Terminating entry */
|
||||
};
|
||||
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
* Copyright (c) 1999-2001 Vojtech Pavlik
|
||||
*
|
||||
* Based on the work of:
|
||||
* David Thompson
|
||||
* Joseph Krahn
|
||||
* David Thompson
|
||||
* Joseph Krahn
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* Copyright (c) 1999-2001 Vojtech Pavlik
|
||||
*
|
||||
* Based on the work of:
|
||||
* David Thompson
|
||||
* David Thompson
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user