summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@g5.osdl.org>2006-01-07 11:29:51 -0800
committerLinus Torvalds <torvalds@g5.osdl.org>2006-01-07 11:29:51 -0800
commitb9abaa3fb7328851bdeaad19e694048f0ff71d9a (patch)
treede56cda929b837c6b2e421b57c723939ec7df5da /drivers
parent8995b161eb142b843094dd614b80e4cce1d66352 (diff)
parent736ce43295682d060f2b93624b4a339f9af6aab1 (diff)
Merge git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input
Diffstat (limited to 'drivers')
-rw-r--r--drivers/input/evdev.c493
-rw-r--r--drivers/input/gameport/Kconfig7
-rw-r--r--drivers/input/keyboard/atkbd.c2
-rw-r--r--drivers/input/misc/m68kspkr.c102
-rw-r--r--drivers/input/misc/pcspkr.c86
-rw-r--r--drivers/input/misc/sparcspkr.c162
-rw-r--r--drivers/input/misc/wistron_btns.c133
-rw-r--r--drivers/input/mouse/alps.c1
-rw-r--r--drivers/input/mouse/lifebook.c7
-rw-r--r--drivers/input/mouse/logips2pp.c2
-rw-r--r--drivers/input/mouse/psmouse-base.c15
-rw-r--r--drivers/input/mousedev.c10
-rw-r--r--drivers/input/serio/ct82c710.c89
-rw-r--r--drivers/input/serio/i8042-x86ia64io.h15
-rw-r--r--drivers/input/serio/i8042.c116
-rw-r--r--drivers/input/serio/maceps2.c68
-rw-r--r--drivers/input/serio/q40kbd.c89
-rw-r--r--drivers/misc/ibmasm/ibmasm.h6
-rw-r--r--drivers/misc/ibmasm/remote.c76
-rw-r--r--drivers/usb/input/appletouch.c145
-rw-r--r--drivers/usb/input/hid-debug.h15
21 files changed, 1025 insertions, 614 deletions
diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c
index a1e660e3531..f7490a015d1 100644
--- a/drivers/input/evdev.c
+++ b/drivers/input/evdev.c
@@ -146,6 +146,7 @@ static int evdev_open(struct inode * inode, struct file * file)
}
#ifdef CONFIG_COMPAT
+
struct input_event_compat {
struct compat_timeval time;
__u16 type;
@@ -165,98 +166,107 @@ struct input_event_compat {
# 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)
+static inline size_t evdev_event_size(void)
{
- struct evdev_list *list = file->private_data;
- struct input_event_compat event;
- int retval = 0;
+ return COMPAT_TEST ?
+ sizeof(struct input_event_compat) : sizeof(struct input_event);
+}
- while (retval < count) {
- if (copy_from_user(&event, buffer + retval, sizeof(struct input_event_compat)))
+static int evdev_event_from_user(const char __user *buffer, struct input_event *event)
+{
+ if (COMPAT_TEST) {
+ struct input_event_compat compat_event;
+
+ if (copy_from_user(&compat_event, buffer, sizeof(struct input_event_compat)))
+ return -EFAULT;
+
+ event->time.tv_sec = compat_event.time.tv_sec;
+ event->time.tv_usec = compat_event.time.tv_usec;
+ event->type = compat_event.type;
+ event->code = compat_event.code;
+ event->value = compat_event.value;
+
+ } else {
+ if (copy_from_user(event, buffer, sizeof(struct input_event)))
return -EFAULT;
- input_event(list->evdev->handle.dev, event.type, event.code, event.value);
- retval += sizeof(struct input_event_compat);
}
- return retval;
+ return 0;
}
-#endif
-static ssize_t evdev_write(struct file * file, const char __user * buffer, size_t count, loff_t *ppos)
+static int evdev_event_to_user(char __user *buffer, const struct input_event *event)
{
- struct evdev_list *list = file->private_data;
- struct input_event event;
- int retval = 0;
-
- if (!list->evdev->exist) return -ENODEV;
+ if (COMPAT_TEST) {
+ struct input_event_compat compat_event;
-#ifdef CONFIG_COMPAT
- if (COMPAT_TEST)
- return evdev_write_compat(file, buffer, count, ppos);
-#endif
+ compat_event.time.tv_sec = event->time.tv_sec;
+ compat_event.time.tv_usec = event->time.tv_usec;
+ compat_event.type = event->type;
+ compat_event.code = event->code;
+ compat_event.value = event->value;
- while (retval < count) {
+ if (copy_to_user(buffer, &compat_event, sizeof(struct input_event_compat)))
+ return -EFAULT;
- if (copy_from_user(&event, buffer + retval, sizeof(struct input_event)))
+ } else {
+ if (copy_to_user(buffer, event, sizeof(struct input_event)))
return -EFAULT;
- input_event(list->evdev->handle.dev, event.type, event.code, event.value);
- retval += sizeof(struct input_event);
}
- return retval;
+ return 0;
}
-#ifdef CONFIG_COMPAT
-static ssize_t evdev_read_compat(struct file * file, char __user * buffer, size_t count, loff_t *ppos)
+#else
+
+static inline size_t evdev_event_size(void)
{
- struct evdev_list *list = file->private_data;
- int retval;
+ return sizeof(struct input_event);
+}
- if (count < sizeof(struct input_event_compat))
- return -EINVAL;
+static int evdev_event_from_user(const char __user *buffer, struct input_event *event)
+{
+ if (copy_from_user(event, buffer, sizeof(struct input_event)))
+ return -EFAULT;
- if (list->head == list->tail && list->evdev->exist && (file->f_flags & O_NONBLOCK))
- return -EAGAIN;
+ return 0;
+}
- retval = wait_event_interruptible(list->evdev->wait,
- list->head != list->tail || (!list->evdev->exist));
+static int evdev_event_to_user(char __user *buffer, const struct input_event *event)
+{
+ if (copy_to_user(buffer, event, sizeof(struct input_event)))
+ return -EFAULT;
- if (retval)
- return retval;
+ return 0;
+}
+
+#endif /* CONFIG_COMPAT */
+
+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 input_event event;
+ int retval = 0;
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);
+ while (retval < count) {
+
+ if (evdev_event_from_user(buffer + retval, &event))
+ return -EFAULT;
+ input_event(list->evdev->handle.dev, event.type, event.code, event.value);
+ retval += evdev_event_size();
}
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))
+ if (count < evdev_event_size())
return -EINVAL;
if (list->head == list->tail && list->evdev->exist && (file->f_flags & O_NONBLOCK))
@@ -271,11 +281,15 @@ static ssize_t evdev_read(struct file * file, char __user * buffer, size_t count
if (!list->evdev->exist)
return -ENODEV;
- 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;
+ while (list->head != list->tail && retval + evdev_event_size() <= count) {
+
+ struct input_event *event = (struct input_event *) list->buffer + list->tail;
+
+ if (evdev_event_to_user(buffer + retval, event))
+ return -EFAULT;
+
list->tail = (list->tail + 1) & (EVDEV_BUFFER_SIZE - 1);
- retval += sizeof(struct input_event);
+ retval += evdev_event_size();
}
return retval;
@@ -290,17 +304,95 @@ static unsigned int evdev_poll(struct file *file, poll_table *wait)
(list->evdev->exist ? 0 : (POLLHUP | POLLERR));
}
-static long evdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+#ifdef CONFIG_COMPAT
+
+#define BITS_PER_LONG_COMPAT (sizeof(compat_long_t) * 8)
+#define NBITS_COMPAT(x) ((((x) - 1) / BITS_PER_LONG_COMPAT) + 1)
+
+#ifdef __BIG_ENDIAN
+static int bits_to_user(unsigned long *bits, unsigned int maxbit,
+ unsigned int maxlen, void __user *p, int compat)
+{
+ int len, i;
+
+ if (compat) {
+ len = NBITS_COMPAT(maxbit) * sizeof(compat_long_t);
+ if (len < maxlen)
+ len = maxlen;
+
+ for (i = 0; i < len / sizeof(compat_long_t); i++)
+ if (copy_to_user((compat_long_t __user *) p + i,
+ (compat_long_t *) bits +
+ i + 1 - ((i % 2) << 1),
+ sizeof(compat_long_t)))
+ return -EFAULT;
+ } else {
+ len = NBITS(maxbit) * sizeof(long);
+ if (len > maxlen)
+ len = maxlen;
+
+ if (copy_to_user(p, bits, len))
+ return -EFAULT;
+ }
+
+ return len;
+}
+#else
+static int bits_to_user(unsigned long *bits, unsigned int maxbit,
+ unsigned int maxlen, void __user *p, int compat)
+{
+ int len = compat ?
+ NBITS_COMPAT(maxbit) * sizeof(compat_long_t) :
+ NBITS(maxbit) * sizeof(long);
+
+ if (len > maxlen)
+ len = maxlen;
+
+ return copy_to_user(p, bits, len) ? -EFAULT : len;
+}
+#endif /* __BIG_ENDIAN */
+
+#else
+
+static int bits_to_user(unsigned long *bits, unsigned int maxbit,
+ unsigned int maxlen, void __user *p, int compat)
+{
+ int len = NBITS(maxbit) * sizeof(long);
+
+ if (len > maxlen)
+ len = maxlen;
+
+ return copy_to_user(p, bits, len) ? -EFAULT : len;
+}
+
+#endif /* CONFIG_COMPAT */
+
+static int str_to_user(const char *str, unsigned int maxlen, void __user *p)
+{
+ int len;
+
+ if (!str)
+ return -ENOENT;
+
+ len = strlen(str) + 1;
+ if (len > maxlen)
+ len = maxlen;
+
+ return copy_to_user(p, str, len) ? -EFAULT : len;
+}
+
+static long evdev_ioctl_handler(struct file *file, unsigned int cmd,
+ void __user *p, int compat_mode)
{
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 = (void __user *)arg;
- int __user *ip = (int __user *)arg;
+ int __user *ip = (int __user *)p;
int i, t, u, v;
- if (!evdev->exist) return -ENODEV;
+ if (!evdev->exist)
+ return -ENODEV;
switch (cmd) {
@@ -308,26 +400,39 @@ static long evdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
return put_user(EV_VERSION, ip);
case EVIOCGID:
- return copy_to_user(p, &dev->id, sizeof(struct input_id)) ? -EFAULT : 0;
+ if (copy_to_user(p, &dev->id, sizeof(struct input_id)))
+ return -EFAULT;
+
+ return 0;
case EVIOCGKEYCODE:
- if (get_user(t, ip)) return -EFAULT;
- if (t < 0 || t >= dev->keycodemax || !dev->keycodesize) return -EINVAL;
- if (put_user(INPUT_KEYCODE(dev, t), ip + 1)) return -EFAULT;
+ if (get_user(t, ip))
+ return -EFAULT;
+ if (t < 0 || t >= dev->keycodemax || !dev->keycodesize)
+ return -EINVAL;
+ if (put_user(INPUT_KEYCODE(dev, t), ip + 1))
+ return -EFAULT;
return 0;
case EVIOCSKEYCODE:
- if (get_user(t, ip)) return -EFAULT;
- if (t < 0 || t >= dev->keycodemax || !dev->keycodesize) return -EINVAL;
- if (get_user(v, ip + 1)) return -EFAULT;
- if (v < 0 || v > KEY_MAX) return -EINVAL;
- if (dev->keycodesize < sizeof(v) && (v >> (dev->keycodesize * 8))) return -EINVAL;
+ if (get_user(t, ip))
+ return -EFAULT;
+ if (t < 0 || t >= dev->keycodemax || !dev->keycodesize)
+ return -EINVAL;
+ if (get_user(v, ip + 1))
+ return -EFAULT;
+ if (v < 0 || v > KEY_MAX)
+ return -EINVAL;
+ if (dev->keycodesize < sizeof(v) && (v >> (dev->keycodesize * 8)))
+ return -EINVAL;
+
u = SET_INPUT_KEYCODE(dev, t, v);
clear_bit(u, dev->keybit);
set_bit(v, dev->keybit);
for (i = 0; i < dev->keycodemax; i++)
- if (INPUT_KEYCODE(dev,i) == u)
+ if (INPUT_KEYCODE(dev, i) == u)
set_bit(u, dev->keybit);
+
return 0;
case EVIOCSFF:
@@ -338,17 +443,17 @@ static long evdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
if (copy_from_user(&effect, p, sizeof(effect)))
return -EFAULT;
err = dev->upload_effect(dev, &effect);
- if (put_user(effect.id, &(((struct ff_effect __user *)arg)->id)))
+ if (put_user(effect.id, &(((struct ff_effect __user *)p)->id)))
return -EFAULT;
return err;
- }
- else return -ENOSYS;
+ } else
+ return -ENOSYS;
case EVIOCRMFF:
- if (dev->erase_effect) {
- return dev->erase_effect(dev, (int)arg);
- }
- else return -ENOSYS;
+ if (!dev->erase_effect)
+ return -ENOSYS;
+
+ return dev->erase_effect(dev, (int)(unsigned long) p);
case EVIOCGEFFECTS:
if (put_user(dev->ff_effects_max, ip))
@@ -356,7 +461,7 @@ static long evdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
return 0;
case EVIOCGRAB:
- if (arg) {
+ if (p) {
if (evdev->grab)
return -EBUSY;
if (input_grab_device(&evdev->handle))
@@ -395,62 +500,33 @@ static long evdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
case EV_SW: bits = dev->swbit; len = SW_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;
+ return bits_to_user(bits, len, _IOC_SIZE(cmd), p, compat_mode);
}
- if (_IOC_NR(cmd) == _IOC_NR(EVIOCGKEY(0))) {
- int len;
- len = NBITS(KEY_MAX) * sizeof(long);
- if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
- return copy_to_user(p, dev->key, len) ? -EFAULT : len;
- }
+ if (_IOC_NR(cmd) == _IOC_NR(EVIOCGKEY(0)))
+ return bits_to_user(dev->key, KEY_MAX, _IOC_SIZE(cmd),
+ p, compat_mode);
- if (_IOC_NR(cmd) == _IOC_NR(EVIOCGLED(0))) {
- int len;
- len = NBITS(LED_MAX) * sizeof(long);
- if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
- return copy_to_user(p, dev->led, len) ? -EFAULT : len;
- }
+ if (_IOC_NR(cmd) == _IOC_NR(EVIOCGLED(0)))
+ return bits_to_user(dev->led, LED_MAX, _IOC_SIZE(cmd),
+ p, compat_mode);
- if (_IOC_NR(cmd) == _IOC_NR(EVIOCGSND(0))) {
- int len;
- len = NBITS(SND_MAX) * sizeof(long);
- if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
- return copy_to_user(p, dev->snd, len) ? -EFAULT : len;
- }
+ if (_IOC_NR(cmd) == _IOC_NR(EVIOCGSND(0)))
+ return bits_to_user(dev->snd, SND_MAX, _IOC_SIZE(cmd),
+ p, compat_mode);
- if (_IOC_NR(cmd) == _IOC_NR(EVIOCGSW(0))) {
- int len;
- len = NBITS(SW_MAX) * sizeof(long);
- if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
- return copy_to_user(p, dev->sw, len) ? -EFAULT : len;
- }
+ if (_IOC_NR(cmd) == _IOC_NR(EVIOCGSW(0)))
+ return bits_to_user(dev->sw, SW_MAX, _IOC_SIZE(cmd),
+ p, compat_mode);
- if (_IOC_NR(cmd) == _IOC_NR(EVIOCGNAME(0))) {
- int len;
- if (!dev->name) return -ENOENT;
- len = strlen(dev->name) + 1;
- if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
- return copy_to_user(p, dev->name, len) ? -EFAULT : len;
- }
+ if (_IOC_NR(cmd) == _IOC_NR(EVIOCGNAME(0)))
+ return str_to_user(dev->name, _IOC_SIZE(cmd), p);
- 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(EVIOCGPHYS(0)))
+ return str_to_user(dev->phys, _IOC_SIZE(cmd), p);
- 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) == _IOC_NR(EVIOCGUNIQ(0)))
+ return str_to_user(dev->uniq, _IOC_SIZE(cmd), p);
if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCGABS(0))) {
@@ -492,158 +568,15 @@ static long evdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
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 __user *) 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(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ return evdev_ioctl_handler(file, cmd, (void __user *)arg, 0);
+}
+#ifdef CONFIG_COMPAT
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;
- case EV_SW: bits = dev->swbit; max = SW_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(EVIOCGSW(0)))
- bit_to_user(dev->sw, SW_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;
+ return evdev_ioctl_handler(file, cmd, compat_ptr(arg), 1);
}
#endif
diff --git a/drivers/input/gameport/Kconfig b/drivers/input/gameport/Kconfig
index 7524bd7d8b8..d279454a5c9 100644
--- a/drivers/input/gameport/Kconfig
+++ b/drivers/input/gameport/Kconfig
@@ -52,5 +52,12 @@ config GAMEPORT_EMU10K1
config GAMEPORT_FM801
tristate "ForteMedia FM801 gameport support"
depends on PCI
+ help
+ Say Y here if you have ForteMedia FM801 PCI audio controller
+ (Abit AU10, Genius Sound Maker, HP Workstation zx2000,
+ and others), and want to use its gameport.
+
+ To compile this driver as a module, choose M here: the
+ module will be called fm801-gp.
endif
diff --git a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c
index a0256f8de8e..ffacf6eca5f 100644
--- a/drivers/input/keyboard/atkbd.c
+++ b/drivers/input/keyboard/atkbd.c
@@ -321,7 +321,7 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data,
switch (code) {
case ATKBD_RET_BAT:
atkbd->enabled = 0;
- serio_rescan(atkbd->ps2dev.serio);
+ serio_reconnect(atkbd->ps2dev.serio);
goto out;
case ATKBD_RET_EMUL0:
atkbd->emul = 1;
diff --git a/drivers/input/misc/m68kspkr.c b/drivers/input/misc/m68kspkr.c
index 04489ad7702..8d6c3837bad 100644
--- a/drivers/input/misc/m68kspkr.c
+++ b/drivers/input/misc/m68kspkr.c
@@ -17,6 +17,7 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/input.h>
+#include <linux/platform_device.h>
#include <asm/machdep.h>
#include <asm/io.h>
@@ -24,7 +25,7 @@ MODULE_AUTHOR("Richard Zidlicky <rz@linux-m68k.org>");
MODULE_DESCRIPTION("m68k beeper driver");
MODULE_LICENSE("GPL");
-static struct input_dev *m68kspkr_dev;
+static struct platform_device *m68kspkr_platform_device;
static int m68kspkr_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
{
@@ -47,36 +48,103 @@ static int m68kspkr_event(struct input_dev *dev, unsigned int type, unsigned int
return 0;
}
+static int __devinit m68kspkr_probe(struct platform_device *dev)
+{
+ struct input_dev *input_dev;
+ int err;
+
+ input_dev = input_allocate_device();
+ if (!input_dev)
+ return -ENOMEM;
+
+ input_dev->name = "m68k beeper";
+ input_dev->phys = "m68k/generic";
+ input_dev->id.bustype = BUS_HOST;
+ input_dev->id.vendor = 0x001f;
+ input_dev->id.product = 0x0001;
+ input_dev->id.version = 0x0100;
+ input_dev->cdev.dev = &dev->dev;
+
+ input_dev->evbit[0] = BIT(EV_SND);
+ input_dev->sndbit[0] = BIT(SND_BELL) | BIT(SND_TONE);
+ input_dev->event = m68kspkr_event;
+
+ err = input_register_device(input_dev);
+ if (err) {
+ input_free_device(input_dev);
+ return err;
+ }
+
+ platform_set_drvdata(dev, input_dev);
+
+ return 0;
+}
+
+static int __devexit m68kspkr_remove(struct platform_device *dev)
+{
+ struct input_dev *input_dev = platform_get_drvdata(dev);
+
+ input_unregister_device(input_dev);
+ platform_set_drvdata(dev, NULL);
+ /* turn off the speaker */
+ m68kspkr_event(NULL, EV_SND, SND_BELL, 0);
+
+ return 0;
+}
+
+static void m68kspkr_shutdown(struct platform_device *dev)
+{
+ /* turn off the speaker */
+ m68kspkr_event(NULL, EV_SND, SND_BELL, 0);
+}
+
+static struct platform_driver m68kspkr_platform_driver = {
+ .driver = {
+ .name = "m68kspkr",
+ .owner = THIS_MODULE,
+ },
+ .probe = m68kspkr_probe,
+ .remove = __devexit_p(m68kspkr_remove),
+ .shutdown = m68kspkr_shutdown,
+};
+
static int __init m68kspkr_init(void)
{
- if (!mach_beep) {
+ int err;
+
+ if (!mach_beep) {
printk(KERN_INFO "m68kspkr: no lowlevel beep support\n");
return -ENODEV;
}
- m68kspkr_dev = input_allocate_device();
- if (!m68kspkr_dev)
- return -ENOMEM;
-
- m68kspkr_dev->name = "m68k beeper";
- m68kspkr_dev->phys = "m68k/generic";
- m68kspkr_dev->id.bustype = BUS_HOST;
- m68kspkr_dev->id.vendor = 0x001f;
- m68kspkr_dev->id.product = 0x0001;
- m68kspkr_dev->id.version = 0x0100;
+ err = platform_driver_register(&m68kspkr_platform_driver);
+ if (err)
+ return err;
- m68kspkr_dev->evbit[0] = BIT(EV_SND);
- m68kspkr_dev->sndbit[0] = BIT(SND_BELL) | BIT(SND_TONE);
- m68kspkr_dev->event = m68kspkr_event;
+ m68kspkr_platform_device = platform_device_alloc("m68kspkr", -1);
+ if (!m68kspkr_platform_device) {
+ err = -ENOMEM;
+ goto err_unregister_driver;
+ }
- input_register_device(m68kspkr_dev);
+ err = platform_device_add(m68kspkr_platform_device);
+ if (err)
+ goto err_free_device;
return 0;
+
+ err_free_device:
+ platform_device_put(m68kspkr_platform_device);
+ err_unregister_driver:
+ platform_driver_unregister(&m68kspkr_platform_driver);
+
+ return err;
}
static void __exit m68kspkr_exit(void)
{
- input_unregister_device(m68kspkr_dev);
+ platform_device_unregister(m68kspkr_platform_device);
+ platform_driver_unregister(&m68kspkr_platform_driver);
}
module_init(m68kspkr_init);
diff --git a/drivers/input/misc/pcspkr.c b/drivers/input/misc/pcspkr.c
index 68ac97f101b..1ef477f4469 100644
--- a/drivers/input/misc/pcspkr.c
+++ b/drivers/input/misc/pcspkr.c
@@ -16,6 +16,7 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/input.h>
+#include <linux/platform_device.h>
#include <asm/8253pit.h>
#include <asm/io.h>
@@ -23,8 +24,7 @@ MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
MODULE_DESCRIPTION("PC Speaker beeper driver");
MODULE_LICENSE("GPL");
-static struct input_dev *pcspkr_dev;
-
+static struct platform_device *pcspkr_platform_device;
static DEFINE_SPINLOCK(i8253_beep_lock);
static int pcspkr_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
@@ -64,8 +64,11 @@ static int pcspkr_event(struct input_dev *dev, unsigned int type, unsigned int c
return 0;
}
-static int __init pcspkr_init(void)
+static int __devinit pcspkr_probe(struct platform_device *dev)
{
+ struct input_dev *pcspkr_dev;
+ int err;
+
pcspkr_dev = input_allocate_device();
if (!pcspkr_dev)
return -ENOMEM;
@@ -76,22 +79,93 @@ static int __init pcspkr_init(void)
pcspkr_dev->id.vendor = 0x001f;
pcspkr_dev->id.product = 0x0001;
pcspkr_dev->id.version = 0x0100;
+ pcspkr_dev->cdev.dev = &dev->dev;
pcspkr_dev->evbit[0] = BIT(EV_SND);
pcspkr_dev->sndbit[0] = BIT(SND_BELL) | BIT(SND_TONE);
pcspkr_dev->event = pcspkr_event;
- input_register_device(pcspkr_dev);
+ err = input_register_device(pcspkr_dev);
+ if (err) {
+ input_free_device(pcspkr_dev);
+ return err;
+ }
+
+ platform_set_drvdata(dev, pcspkr_dev);
return 0;
}
-static void __exit pcspkr_exit(void)
+static int __devexit pcspkr_remove(struct platform_device *dev)
+{
+ struct input_dev *pcspkr_dev = platform_get_drvdata(dev);
+
+ input_unregister_device(pcspkr_dev);
+ platform_set_drvdata(dev, NULL);
+ /* turn off the speaker */
+ pcspkr_event(NULL, EV_SND, SND_BELL, 0);
+
+ return 0;
+}
+
+static int pcspkr_suspend(struct platform_device *dev, pm_message_t state)
+{
+ pcspkr_event(NULL, EV_SND, SND_BELL, 0);
+
+ return 0;
+}
+
+static void pcspkr_shutdown(struct platform_device *dev)
{
- input_unregister_device(pcspkr_dev);
/* turn off the speaker */
pcspkr_event(NULL, EV_SND, SND_BELL, 0);
}
+static struct platform_driver pcspkr_platform_driver = {
+ .driver = {
+ .name = "pcspkr",
+ .owner = THIS_MODULE,
+ },
+ .probe = pcspkr_probe,
+ .remove = __devexit_p(pcspkr_remove),
+ .suspend = pcspkr_suspend,
+ .shutdown = pcspkr_shutdown,
+};
+
+
+static int __init pcspkr_init(void)
+{
+ int err;
+
+ err = platform_driver_register(&pcspkr_platform_driver);
+ if (err)
+ return err;
+
+ pcspkr_platform_device = platform_device_alloc("pcspkr", -1);
+ if (!pcspkr_platform_device) {
+ err = -ENOMEM;
+ goto err_unregister_driver;
+ }
+
+ err = platform_device_add(pcspkr_platform_device);
+ if (err)
+ goto err_free_device;
+
+ return 0;
+
+ err_free_device:
+ platform_device_put(pcspkr_platform_device);
+ err_unregister_driver:
+ platform_driver_unregister(&pcspkr_platform_driver);
+
+ return err;
+}
+
+static void __exit pcspkr_exit(void)
+{
+ platform_device_unregister(pcspkr_platform_device);
+ platform_driver_unregister(&pcspkr_platform_driver);
+}
+
module_init(pcspkr_init);
module_exit(pcspkr_exit);
diff --git a/drivers/input/misc/sparcspkr.c b/drivers/input/misc/sparcspkr.c
index 29d97b12be7..f0fd2c4740f 100644
--- a/drivers/input/misc/sparcspkr.c
+++ b/drivers/input/misc/sparcspkr.c
@@ -9,6 +9,7 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/input.h>
+#include <linux/platform_device.h>
#include <asm/io.h>
#include <asm/ebus.h>
@@ -20,22 +21,10 @@ MODULE_AUTHOR("David S. Miller <davem@redhat.com>");
MODULE_DESCRIPTION("Sparc Speaker beeper driver");
MODULE_LICENSE("GPL");
+const char *beep_name;
static unsigned long beep_iobase;
-static struct input_dev *sparcspkr_dev;
-
-DEFINE_SPINLOCK(beep_lock);
-
-static void __init init_sparcspkr_struct(void)
-{
- sparcspkr_dev->evbit[0] = BIT(EV_SND);
- sparcspkr_dev->sndbit[0] = BIT(SND_BELL) | BIT(SND_TONE);
-
- sparcspkr_dev->phys = "sparc/input0";
- sparcspkr_dev->id.bustype = BUS_ISA;
- sparcspkr_dev->id.vendor = 0x001f;
- sparcspkr_dev->id.product = 0x0001;
- sparcspkr_dev->id.version = 0x0100;
-}
+static int (*beep_event)(struct input_dev *dev, unsigned int type, unsigned int code, int value);
+static DEFINE_SPINLOCK(beep_lock);
static int ebus_spkr_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
{
@@ -59,39 +48,16 @@ static int ebus_spkr_event(struct input_dev *dev, unsigned int type, unsigned in
/* EBUS speaker only has on/off state, the frequency does not
* appear to be programmable.
*/
- if (count) {
- if (beep_iobase & 0x2UL)
- outb(1, beep_iobase);
- else
- outl(1, beep_iobase);
- } else {
- if (beep_iobase & 0x2UL)
- outb(0, beep_iobase);
- else
- outl(0, beep_iobase);
- }
+ if (beep_iobase & 0x2UL)
+ outb(!!count, beep_iobase);
+ else
+ outl(!!count, beep_iobase);
spin_unlock_irqrestore(&beep_lock, flags);
return 0;
}
-static int __init init_ebus_beep(struct linux_ebus_device *edev)
-{
- beep_iobase = edev->resource[0].start;
-
- sparcspkr_dev = input_allocate_device();
- if (!sparcspkr_dev)
- return -ENOMEM;
-
- sparcspkr_dev->name = "Sparc EBUS Speaker";
- sparcspkr_dev->event = ebus_spkr_event;
-
- input_register_device(sparcspkr_dev);
-
- return 0;
-}
-
#ifdef CONFIG_SPARC64
static int isa_spkr_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
{
@@ -129,30 +95,103 @@ static int isa_spkr_event(struct input_dev *dev, unsigned int type, unsigned int
return 0;
}
+#endif
-static int __init init_isa_beep(struct sparc_isa_device *isa_dev)
+static int __devinit sparcspkr_probe(struct platform_device *dev)
{
- beep_iobase = isa_dev->resource.start;
+ struct input_dev *input_dev;
+ int error;
- sparcspkr_dev = input_allocate_device();
- if (!sparcspkr_dev)
+ input_dev = input_allocate_device();
+ if (!input_dev)
return -ENOMEM;
- init_sparcspkr_struct();
+ input_dev->name = beep_name;
+ input_dev->phys = "sparc/input0";
+ input_dev->id.bustype = BUS_ISA;
+ input_dev->id.vendor = 0x001f;
+ input_dev->id.product = 0x0001;
+ input_dev->id.version = 0x0100;
+ input_dev->cdev.dev = &dev->dev;
- sparcspkr_dev->name = "Sparc ISA Speaker";
- sparcspkr_dev->event = isa_spkr_event;
+ input_dev->evbit[0] = BIT(EV_SND);
+ input_dev->sndbit[0] = BIT(SND_BELL) | BIT(SND_TONE);
- input_register_device(sparcspkr_dev);
+ input_dev->event = beep_event;
+
+ error = input_register_device(input_dev);
+ if (error) {
+ input_free_device(input_dev);
+ return error;
+ }
+
+ platform_set_drvdata(dev, input_dev);
return 0;
}
-#endif
+
+static int __devexit sparcspkr_remove(struct platform_device *dev)
+{
+ struct input_dev *input_dev = platform_get_drvdata(dev);
+
+ input_unregister_device(input_dev);
+ platform_set_drvdata(dev, NULL);
+ /* turn off the speaker */
+ beep_event(NULL, EV_SND, SND_BELL, 0);
+
+ return 0;
+}
+
+static void sparcspkr_shutdown(struct platform_device *dev)
+{
+ /* turn off the speaker */
+ beep_event(NULL, EV_SND, SND_BELL, 0);
+}
+
+static struct platform_driver sparcspkr_platform_driver = {
+ .driver = {
+ .name = "sparcspkr",
+ .owner = THIS_MODULE,
+ },
+ .probe = sparcspkr_probe,
+ .remove = __devexit_p(sparcspkr_remove),
+ .shutdown = sparcspkr_shutdown,
+};
+
+static struct platform_device *sparcspkr_platform_device;
+
+static int __init sparcspkr_drv_init(void)
+{
+ int error;
+
+ error = platform_driver_register(&sparcspkr_platform_driver);
+ if (error)
+ return error;
+
+ sparcspkr_platform_device = platform_device_alloc("sparcspkr", -1);
+ if (!sparcspkr_platform_device) {
+ error = -ENOMEM;
+ goto err_unregister_driver;
+ }
+
+ error = platform_device_add(sparcspkr_platform_device);
+ if (error)
+ goto err_free_device;
+
+ return 0;
+
+ err_free_device:
+ platform_device_put(sparcspkr_platform_device);
+ err_unregister_driver:
+ platform_driver_unregister(&sparcspkr_platform_driver);
+
+ return error;
+}
static int __init sparcspkr_init(void)
{
struct linux_ebus *ebus;
- struct linux_ebus_device *edev = NULL;
+ struct linux_ebus_device *edev;
#ifdef CONFIG_SPARC64
struct sparc_isa_bridge *isa_br;
struct sparc_isa_device *isa_dev;
@@ -160,8 +199,12 @@ static int __init sparcspkr_init(void)
for_each_ebus(ebus) {
for_each_ebusdev(edev, ebus) {
- if (!strcmp(edev->prom_name, "beep"))
- return init_ebus_beep(edev);
+ if (!strcmp(edev->prom_name, "beep")) {
+ beep_name = "Sparc EBUS Speaker";
+ beep_event = ebus_spkr_event;
+ beep_iobase = edev->resource[0].start;
+ return sparcspkr_drv_init();
+ }
}
}
#ifdef CONFIG_SPARC64
@@ -170,8 +213,12 @@ static int __init sparcspkr_init(void)
/* A hack, the beep device's base lives in
* the DMA isa node.
*/
- if (!strcmp(isa_dev->prom_name, "dma"))
- return init_isa_beep(isa_dev);
+ if (!strcmp(isa_dev->prom_name, "dma")) {
+ beep_name = "Sparc ISA Speaker";
+ beep_event = isa_spkr_event,
+ beep_iobase = isa_dev->resource.start;
+ return sparcspkr_drv_init();
+ }
}
}
#endif
@@ -181,7 +228,8 @@ static int __init sparcspkr_init(void)
static void __exit sparcspkr_exit(void)
{
- input_unregister_device(sparcspkr_dev);
+ platform_device_unregister(sparcspkr_platform_device);
+ platform_driver_unregister(&sparcspkr_platform_driver);
}
module_init(sparcspkr_init);
diff --git a/drivers/input/misc/wistron_btns.c b/drivers/input/misc/wistron_btns.c
index bac3085185f..a05b8557842 100644
--- a/drivers/input/misc/wistron_btns.c
+++ b/drivers/input/misc/wistron_btns.c
@@ -174,7 +174,7 @@ static u16 bios_pop_queue(void)
return regs.eax;
}
-static void __init bios_attach(void)
+static void __devinit bios_attach(void)
{
struct regs regs;
@@ -194,7 +194,7 @@ static void bios_detach(void)
call_bios(&regs);
}
-static u8 __init bios_get_cmos_address(void)
+static u8 __devinit bios_get_cmos_address(void)
{
struct regs regs;
@@ -206,7 +206,7 @@ static u8 __init bios_get_cmos_address(void)
return regs.ecx;
}
-static u16 __init bios_get_default_setting(u8 subsys)
+static u16 __devinit bios_get_default_setting(u8 subsys)
{
struct regs regs;
@@ -296,6 +296,16 @@ static struct key_entry keymap_acer_aspire_1500[] = {
{ KE_END, 0 }
};
+static struct key_entry keymap_acer_travelmate_240[] = {
+ { KE_KEY, 0x31, KEY_MAIL },
+ { KE_KEY, 0x36, KEY_WWW },
+ { KE_KEY, 0x11, KEY_PROG1 },
+ { KE_KEY, 0x12, KEY_PROG2 },
+ { KE_BLUETOOTH, 0x44, 0 },
+ { KE_WIFI, 0x30, 0 },
+ { KE_END, 0 }
+};
+
/*
* If your machine is not here (which is currently rather likely), please send
* a list of buttons and their key codes (reported when loading this module
@@ -320,6 +330,15 @@ static struct dmi_system_id dmi_ids[] = {
},
.driver_data = keymap_acer_aspire_1500
},
+ {
+ .callback = dmi_matched,
+ .ident = "Acer TravelMate 240",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 240"),
+ },
+ .driver_data = keymap_acer_travelmate_240
+ },
{ NULL, }
};
@@ -348,7 +367,7 @@ static int __init select_keymap(void)
static struct input_dev *input_dev;
-static int __init setup_input_dev(void)
+static int __devinit setup_input_dev(void)
{
const struct key_entry *key;
int error;
@@ -447,6 +466,52 @@ static void poll_bios(unsigned long discard)
mod_timer(&poll_timer, jiffies + HZ / POLL_FREQUENCY);
}
+static int __devinit wistron_probe(struct platform_device *dev)
+{
+ int err = setup_input_dev();
+ if (err)
+ return err;
+
+ bios_attach();
+ cmos_address = bios_get_cmos_address();
+
+ if (have_wifi) {
+ u16 wifi = bios_get_default_setting(WIFI);
+ if (wifi & 1)
+ wifi_enabled = (wifi & 2) ? 1 : 0;
+ else
+ have_wifi = 0;
+
+ if (have_wifi)
+ bios_set_state(WIFI, wifi_enabled);
+ }
+
+ if (have_bluetooth) {
+ u16 bt = bios_get_default_setting(BLUETOOTH);
+ if (bt & 1)
+ bluetooth_enabled = (bt & 2) ? 1 : 0;
+ else
+ have_bluetooth = 0;
+
+ if (have_bluetooth)
+ bios_set_state(BLUETOOTH, bluetooth_enabled);
+ }
+
+ poll_bios(1); /* Flush stale event queue and arm timer */
+
+ return 0;
+}
+
+static int __devexit wistron_remove(struct platform_device *dev)
+{
+ del_timer_sync(&poll_timer);
+ input_unregister_device(input_dev);
+ bios_detach();
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
static int wistron_suspend(struct platform_device *dev, pm_message_t state)
{
del_timer_sync(&poll_timer);
@@ -472,13 +537,20 @@ static int wistron_resume(struct platform_device *dev)
return 0;
}
+#else
+#define wistron_suspend NULL
+#define wistron_resume NULL
+#endif
static struct platform_driver wistron_driver = {
- .suspend = wistron_suspend,
- .resume = wistron_resume,
.driver = {
.name = "wistron-bios",
+ .owner = THIS_MODULE,
},
+ .probe = wistron_probe,
+ .remove = __devexit_p(wistron_remove),
+ .suspend = wistron_suspend,
+ .resume = wistron_resume,
};
static int __init wb_module_init(void)
@@ -493,55 +565,27 @@ static int __init wb_module_init(void)
if (err)
return err;
- bios_attach();
- cmos_address = bios_get_cmos_address();
-
err = platform_driver_register(&wistron_driver);
if (err)
- goto err_detach_bios;
+ goto err_unmap_bios;
- wistron_device = platform_device_register_simple("wistron-bios", -1, NULL, 0);
- if (IS_ERR(wistron_device)) {
- err = PTR_ERR(wistron_device);
+ wistron_device = platform_device_alloc("wistron-bios", -1);
+ if (!wistron_device) {
+ err = -ENOMEM;
goto err_unregister_driver;
}
- if (have_wifi) {
- u16 wifi = bios_get_default_setting(WIFI);
- if (wifi & 1)
- wifi_enabled = (wifi & 2) ? 1 : 0;
- else
- have_wifi = 0;
-
- if (have_wifi)
- bios_set_state(WIFI, wifi_enabled);
- }
-
- if (have_bluetooth) {
- u16 bt = bios_get_default_setting(BLUETOOTH);
- if (bt & 1)
- bluetooth_enabled = (bt & 2) ? 1 : 0;
- else
- have_bluetooth = 0;
-
- if (have_bluetooth)
- bios_set_state(BLUETOOTH, bluetooth_enabled);
- }
-
- err = setup_input_dev();
+ err = platform_device_add(wistron_device);
if (err)
- goto err_unregister_device;
-
- poll_bios(1); /* Flush stale event queue and arm timer */
+ goto err_free_device;
return 0;
- err_unregister_device:
- platform_device_unregister(wistron_device);
+ err_free_device:
+ platform_device_put(wistron_device);
err_unregister_driver:
platform_driver_unregister(&wistron_driver);
- err_detach_bios:
- bios_detach();
+ err_unmap_bios:
unmap_bios();
return err;
@@ -549,11 +593,8 @@ static int __init wb_module_init(void)
static void __exit wb_module_exit(void)
{
- del_timer_sync(&poll_timer);
- input_unregister_device(input_dev);
platform_device_unregister(wistron_device);
platform_driver_unregister(&wistron_driver);
- bios_detach();
unmap_bios();
}
diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c
index 4f41ec3e433..24474335dfd 100644
--- a/drivers/input/mouse/alps.c
+++ b/drivers/input/mouse/alps.c
@@ -40,6 +40,7 @@ static struct alps_model_info alps_model_data[] = {
{ { 0x33, 0x02, 0x0a }, 0x88, 0xf8, ALPS_OLDPROTO }, /* UMAX-530T */
{ { 0x53, 0x02, 0x0a }, 0xf8, 0xf8, 0 },
{ { 0x53, 0x02, 0x14 }, 0xf8, 0xf8, 0 },
+ { { 0x60, 0x03, 0xc8 }, 0xf8, 0xf8, 0 }, /* HP ze1115 */
{ { 0x63, 0x02, 0x0a }, 0xf8, 0xf8, 0 },
{ { 0x63, 0x02, 0x14 }, 0xf8, 0xf8, 0 },
{ { 0x63, 0x02, 0x28 }, 0xf8, 0xf8, ALPS_FW_BK_2 }, /* Fujitsu Siemens S6010 */
diff --git a/drivers/input/mouse/lifebook.c b/drivers/input/mouse/lifebook.c
index 55991424ac9..5ccc3ef3b89 100644
--- a/drivers/input/mouse/lifebook.c
+++ b/drivers/input/mouse/lifebook.c
@@ -27,6 +27,13 @@ static struct dmi_system_id lifebook_dmi_table[] = {
DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK B Series"),
},
},
+ {
+ .ident = "Lifebook B142",
+ .matches = {
+ DMI_MATCH(DMI_PRODUCT_NAME, "LifeBook B142"),
+ },
+
+ },
{ }
};
diff --git a/drivers/input/mouse/logips2pp.c b/drivers/input/mouse/logips2pp.c
index 31a59f7abfa..025a71de540 100644
--- a/drivers/input/mouse/logips2pp.c
+++ b/drivers/input/mouse/logips2pp.c
@@ -226,7 +226,9 @@ static struct ps2pp_info *get_model_info(unsigned char model)
{ 80, PS2PP_KIND_WHEEL, PS2PP_SIDE_BTN | PS2PP_WHEEL },
{ 81, PS2PP_KIND_WHEEL, PS2PP_WHEEL },
{ 83, PS2PP_KIND_WHEEL, PS2PP_WHEEL },
+ { 85, PS2PP_KIND_WHEEL, PS2PP_WHEEL },
{ 86, PS2PP_KIND_WHEEL, PS2PP_WHEEL },
+ { 87, PS2PP_KIND_WHEEL, PS2PP_WHEEL },
{ 88, PS2PP_KIND_WHEEL, PS2PP_WHEEL },
{ 96, 0, 0 },
{ 97, PS2PP_KIND_TP3, PS2PP_WHEEL | PS2PP_HWHEEL },
diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c
index 6ee9999a2ea..4d5ecc04c5b 100644
--- a/drivers/input/mouse/psmouse-base.c
+++ b/drivers/input/mouse/psmouse-base.c
@@ -527,11 +527,15 @@ static int psmouse_extensions(struct psmouse *psmouse,
if (max_proto > PSMOUSE_IMEX && ps2pp_init(psmouse, set_properties) == 0)
return PSMOUSE_PS2PP;
+ if (max_proto > PSMOUSE_IMEX && trackpoint_detect(psmouse, set_properties) == 0)
+ return PSMOUSE_TRACKPOINT;
+
/*
* Reset to defaults in case the device got confused by extended
- * protocol probes.
+ * protocol probes. Note that we do full reset becuase some mice
+ * put themselves to sleep when see PSMOUSE_RESET_DIS.
*/
- ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_RESET_DIS);
+ psmouse_reset(psmouse);
if (max_proto >= PSMOUSE_IMEX && im_explorer_detect(psmouse, set_properties) == 0)
return PSMOUSE_IMEX;
@@ -540,12 +544,6 @@ static int psmouse_extensions(struct psmouse *psmouse,
return PSMOUSE_IMPS;
/*
- * Try to initialize the IBM TrackPoint
- */
- if (max_proto > PSMOUSE_IMEX && trackpoint_detect(psmouse, set_properties) == 0)
- return PSMOUSE_TRACKPOINT;
-
-/*
* Okay, all failed, we have a standard mouse here. The number of the buttons
* is still a question, though. We assume 3.
*/
@@ -559,7 +557,6 @@ static int psmouse_extensions(struct psmouse *psmouse,
* extensions.
*/
psmouse_reset(psmouse);
- ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_RESET_DIS);
}
return PSMOUSE_PS2;
diff --git a/drivers/input/mousedev.c b/drivers/input/mousedev.c
index 2d0af44ac4b..81fd7a97a93 100644
--- a/drivers/input/mousedev.c
+++ b/drivers/input/mousedev.c
@@ -40,15 +40,15 @@ MODULE_LICENSE("GPL");
#endif
static int xres = CONFIG_INPUT_MOUSEDEV_SCREEN_X;
-module_param(xres, uint, 0);
+module_param(xres, uint, 0644);
MODULE_PARM_DESC(xres, "Horizontal screen resolution");
static int yres = CONFIG_INPUT_MOUSEDEV_SCREEN_Y;
-module_param(yres, uint, 0);
+module_param(yres, uint, 0644);
MODULE_PARM_DESC(yres, "Vertical screen resolution");
static unsigned tap_time = 200;
-module_param(tap_time, uint, 0);
+module_param(tap_time, uint, 0644);
MODULE_PARM_DESC(tap_time, "Tap time for touchpads in absolute mode (msecs)");
struct mousedev_hw_data {
@@ -155,7 +155,7 @@ static void mousedev_abs_event(struct input_dev *dev, struct mousedev *mousedev,
switch (code) {
case ABS_X:
size = dev->absmax[ABS_X] - dev->absmin[ABS_X];
- if (size == 0) size = xres;
+ if (size == 0) size = xres ? : 1;
if (value > dev->absmax[ABS_X]) value = dev->absmax[ABS_X];
if (value < dev->absmin[ABS_X]) value = dev->absmin[ABS_X];
mousedev->packet.x = ((value - dev->absmin[ABS_X]) * xres) / size;
@@ -164,7 +164,7 @@ static void mousedev_abs_event(struct input_dev *dev, struct mousedev *mousedev,
case ABS_Y:
size = dev->absmax[ABS_Y] - dev->absmin[ABS_Y];
- if (size == 0) size = yres;
+ if (size == 0) size = yres ? : 1;
if (value > dev->absmax[ABS_Y]) value = dev->absmax[ABS_Y];
if (value < dev->absmin[ABS_Y]) value = dev->absmin[ABS_Y];
mousedev->packet.y = yres - ((value - dev->absmin[ABS_Y]) * yres) / size;
diff --git a/drivers/input/serio/ct82c710.c b/drivers/input/serio/ct82c710.c
index 4da6c86b5d7..096b6a0b5cc 100644
--- a/drivers/input/serio/ct82c710.c
+++ b/drivers/input/serio/ct82c710.c
@@ -154,7 +154,7 @@ static int ct82c710_write(struct serio *port, unsigned char c)
* See if we can find a 82C710 device. Read mouse address.
*/
-static int __init ct82c710_probe(void)
+static int __init ct82c710_detect(void)
{
outb_p(0x55, 0x2fa); /* Any value except 9, ff or 36 */
outb_p(0xaa, 0x3fa); /* Inverse of 55 */
@@ -163,7 +163,7 @@ static int __init ct82c710_probe(void)
outb_p(0x1b, 0x2fa); /* Inverse of e4 */
outb_p(0x0f, 0x390); /* Write index */
if (inb_p(0x391) != 0xe4) /* Config address found? */
- return -1; /* No: no 82C710 here */
+ return -ENODEV; /* No: no 82C710 here */
outb_p(0x0d, 0x390); /* Write index */
ct82c710_iores.start = inb_p(0x391) << 2; /* Get mouse I/O address */
@@ -175,51 +175,88 @@ static int __init ct82c710_probe(void)
return 0;
}
-static struct serio * __init ct82c710_allocate_port(void)
+static int __devinit ct82c710_probe(struct platform_device *dev)
{
- struct serio *serio;
-
- serio = kmalloc(sizeof(struct serio), GFP_KERNEL);
- if (serio) {
- memset(serio, 0, sizeof(struct serio));
- serio->id.type = SERIO_8042;
- serio->open = ct82c710_open;
- serio->close = ct82c710_close;
- serio->write = ct82c710_write;
- serio->dev.parent = &ct82c710_device->dev;
- strlcpy(serio->name, "C&T 82c710 mouse port", sizeof(serio->name));
- snprintf(serio->phys, sizeof(serio->phys), "isa%04lx/serio0", CT82C710_DATA);
- }
+ ct82c710_port = kzalloc(sizeof(struct serio), GFP_KERNEL);
+ if (!ct82c710_port)
+ return -ENOMEM;
+
+ ct82c710_port->id.type = SERIO_8042;
+ ct82c710_port->dev.parent = &dev->dev;
+ ct82c710_port->open = ct82c710_open;
+ ct82c710_port->close = ct82c710_close;
+ ct82c710_port->write = ct82c710_write;
+ strlcpy(ct82c710_port->name, "C&T 82c710 mouse port",
+ sizeof(ct82c710_port->name));
+ snprintf(ct82c710_port->phys, sizeof(ct82c710_port->phys),
+ "isa%04lx/serio0", CT82C710_DATA);
+
+ serio_register_port(ct82c710_port);
+
+ return 0;
+}
+
+static int __devexit ct82c710_remove(struct platform_device *dev)
+{
+ serio_unregister_port(ct82c710_port);
- return serio;
+ return 0;
}
+static struct platform_driver ct82c710_driver = {
+ .driver = {
+ .name = "ct82c710",
+ .owner = THIS_MODULE,
+ },
+ .probe = ct82c710_probe,
+ .remove = __devexit_p(ct82c710_remove),
+};
+
+
static int __init ct82c710_init(void)
{
- if (ct82c710_probe())
- return -ENODEV;
+ int error;
- ct82c710_device = platform_device_register_simple("ct82c710", -1, &ct82c710_iores, 1);
- if (IS_ERR(ct82c710_device))
- return PTR_ERR(ct82c710_device);
+ error = ct82c710_detect();
+ if (error)
+ return error;
- if (!(ct82c710_port = ct82c710_allocate_port())) {
- platform_device_unregister(ct82c710_device);
- return -ENOMEM;
+ error = platform_driver_register(&ct82c710_driver);
+ if (error)
+ return error;
+
+ ct82c710_device = platform_device_alloc("ct82c710", -1);
+ if (!ct82c710_device) {
+ error = -ENOMEM;
+ goto err_unregister_driver;
}
+ error = platform_device_add_resources(ct82c710_device, &ct82c710_iores, 1);
+ if (error)
+ goto err_free_device;
+
+ error = platform_device_add(ct82c710_device);
+ if (error)
+ goto err_free_device;
+
serio_register_port(ct82c710_port);
printk(KERN_INFO "serio: C&T 82c710 mouse port at %#lx irq %d\n",
CT82C710_DATA, CT82C710_IRQ);
return 0;
+
+ err_free_device:
+ platform_device_put(ct82c710_device);
+ err_unregister_driver:
+ platform_driver_unregister(&ct82c710_driver);
+ return error;
}
static void __exit ct82c710_exit(void)
{
- serio_unregister_port(ct82c710_port);
platform_device_unregister(ct82c710_device);
+ platform_driver_unregister(&ct82c710_driver);
}
module_init(ct82c710_init);
diff --git a/drivers/input/serio/i8042-x86ia64io.h b/drivers/input/serio/i8042-x86ia64io.h
index 273bb3b08cf..2d2f9fb3ade 100644
--- a/drivers/input/serio/i8042-x86ia64io.h
+++ b/drivers/input/serio/i8042-x86ia64io.h
@@ -84,6 +84,14 @@ static struct dmi_system_id __initdata i8042_dmi_noloop_table[] = {
DMI_MATCH(DMI_PRODUCT_VERSION, "DL760"),
},
},
+ {
+ .ident = "OQO Model 01",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "OQO"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "ZEPTO"),
+ DMI_MATCH(DMI_PRODUCT_VERSION, "00"),
+ },
+ },
{ }
};
@@ -158,6 +166,13 @@ static struct dmi_system_id __initdata i8042_dmi_nomux_table[] = {
DMI_MATCH(DMI_PRODUCT_NAME, "Sentia"),
},
},
+ {
+ .ident = "Sharp Actius MM20",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "SHARP"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "PC-MM20 Series"),
+ },
+ },
{ }
};
diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c
index ac86c1d1d83..a7d91d5356a 100644
--- a/drivers/input/serio/i8042.c
+++ b/drivers/input/serio/i8042.c
@@ -572,7 +572,7 @@ static int i8042_enable_mux_ports(void)
* LCS/Telegraphics.
*/
-static int __init i8042_check_mux(void)
+static int __devinit i8042_check_mux(void)
{
unsigned char mux_version;
@@ -600,7 +600,7 @@ static int __init i8042_check_mux(void)
* the presence of an AUX interface.
*/
-static int __init i8042_check_aux(void)
+static int __devinit i8042_check_aux(void)
{
unsigned char param;
static int i8042_check_aux_cookie;
@@ -678,7 +678,7 @@ static int __init i8042_check_aux(void)
* registers it, and reports to the user.
*/
-static int __init i8042_port_register(struct i8042_port *port)
+static int __devinit i8042_port_register(struct i8042_port *port)
{
i8042_ctr &= ~port->disable;
@@ -956,7 +956,6 @@ static int i8042_resume(struct platform_device *dev)
panic_blink = i8042_panic_blink;
return 0;
-
}
/*
@@ -969,16 +968,7 @@ static void i8042_shutdown(struct platform_device *dev)
i8042_controller_cleanup();
}
-static struct platform_driver i8042_driver = {
- .suspend = i8042_suspend,
- .resume = i8042_resume,
- .shutdown = i8042_shutdown,
- .driver = {
- .name = "i8042",
- },
-};
-
-static int __init i8042_create_kbd_port(void)
+static int __devinit i8042_create_kbd_port(void)
{
struct serio *serio;
struct i8042_port *port = &i8042_ports[I8042_KBD_PORT_NO];
@@ -1003,7 +993,7 @@ static int __init i8042_create_kbd_port(void)
return i8042_port_register(port);
}
-static int __init i8042_create_aux_port(void)
+static int __devinit i8042_create_aux_port(void)
{
struct serio *serio;
struct i8042_port *port = &i8042_ports[I8042_AUX_PORT_NO];
@@ -1028,7 +1018,7 @@ static int __init i8042_create_aux_port(void)
return i8042_port_register(port);
}
-static int __init i8042_create_mux_port(int index)
+static int __devinit i8042_create_mux_port(int index)
{
struct serio *serio;
struct i8042_port *port = &i8042_ports[I8042_MUX_PORT_NO + index];
@@ -1057,37 +1047,16 @@ static int __init i8042_create_mux_port(int index)
return i8042_port_register(port);
}
-static int __init i8042_init(void)
+static int __devinit i8042_probe(struct platform_device *dev)
{
int i, have_ports = 0;
int err;
- dbg_init();
-
init_timer(&i8042_timer);
i8042_timer.function = i8042_timer_func;
- err = i8042_platform_init();
- if (err)
- return err;
-
- i8042_ports[I8042_AUX_PORT_NO].irq = I8042_AUX_IRQ;
- i8042_ports[I8042_KBD_PORT_NO].irq = I8042_KBD_IRQ;
-
- if (i8042_controller_init()) {
- err = -ENODEV;
- goto err_platform_exit;
- }
-
- err = platform_driver_register(&i8042_driver);
- if (err)
- goto err_controller_cleanup;
-
- i8042_platform_device = platform_device_register_simple("i8042", -1, NULL, 0);
- if (IS_ERR(i8042_platform_device)) {
- err = PTR_ERR(i8042_platform_device);
- goto err_unregister_driver;
- }
+ if (i8042_controller_init())
+ return -ENODEV;
if (!i8042_noaux && !i8042_check_aux()) {
if (!i8042_nomux && !i8042_check_mux()) {
@@ -1113,30 +1082,23 @@ static int __init i8042_init(void)
if (!have_ports) {
err = -ENODEV;
- goto err_unregister_device;
+ goto err_controller_cleanup;
}
mod_timer(&i8042_timer, jiffies + I8042_POLL_PERIOD);
-
return 0;
err_unregister_ports:
for (i = 0; i < I8042_NUM_PORTS; i++)
if (i8042_ports[i].serio)
serio_unregister_port(i8042_ports[i].serio);
- err_unregister_device:
- platform_device_unregister(i8042_platform_device);
- err_unregister_driver:
- platform_driver_unregister(&i8042_driver);
err_controller_cleanup:
i8042_controller_cleanup();
- err_platform_exit:
- i8042_platform_exit();
return err;
}
-static void __exit i8042_exit(void)
+static int __devexit i8042_remove(struct platform_device *dev)
{
int i;
@@ -1148,6 +1110,62 @@ static void __exit i8042_exit(void)
del_timer_sync(&i8042_timer);
+ return 0;
+}
+
+static struct platform_driver i8042_driver = {
+ .driver = {
+ .name = "i8042",
+ .owner = THIS_MODULE,
+ },
+ .probe = i8042_probe,
+ .remove = __devexit_p(i8042_remove),
+ .suspend = i8042_suspend,
+ .resume = i8042_resume,
+ .shutdown = i8042_shutdown,
+};
+
+static int __init i8042_init(void)
+{
+ int err;
+
+ dbg_init();
+
+ err = i8042_platform_init();
+ if (err)
+ return err;
+
+ i8042_ports[I8042_AUX_PORT_NO].irq = I8042_AUX_IRQ;
+ i8042_ports[I8042_KBD_PORT_NO].irq = I8042_KBD_IRQ;
+
+ err = platform_driver_register(&i8042_driver);
+ if (err)
+ goto err_platform_exit;
+
+ i8042_platform_device = platform_device_alloc("i8042", -1);
+ if (!i8042_platform_device) {
+ err = -ENOMEM;
+ goto err_unregister_driver;
+ }
+
+ err = platform_device_add(i8042_platform_device);
+ if (err)
+ goto err_free_device;
+
+ return 0;
+
+ err_free_device:
+ platform_device_put(i8042_platform_device);
+ err_unregister_driver:
+ platform_driver_unregister(&i8042_driver);
+ err_platform_exit:
+ i8042_platform_exit();
+
+ return err;
+}
+
+static void __exit i8042_exit(void)
+{
platform_device_unregister(i8042_platform_device);
platform_driver_unregister(&i8042_driver);
diff --git a/drivers/input/serio/maceps2.c b/drivers/input/serio/maceps2.c
index d857f7081ad..f08a5d0cd5f 100644
--- a/drivers/input/serio/maceps2.c
+++ b/drivers/input/serio/maceps2.c
@@ -118,13 +118,12 @@ static void maceps2_close(struct serio *dev)
}
-static struct serio * __init maceps2_allocate_port(int idx)
+static struct serio * __devinit maceps2_allocate_port(int idx)
{
struct serio *serio;
- serio = kmalloc(sizeof(struct serio), GFP_KERNEL);
+ serio = kzalloc(sizeof(struct serio), GFP_KERNEL);
if (serio) {
- memset(serio, 0, sizeof(struct serio));
serio->id.type = SERIO_8042;
serio->write = maceps2_write;
serio->open = maceps2_open;
@@ -138,24 +137,13 @@ static struct serio * __init maceps2_allocate_port(int idx)
return serio;
}
-
-static int __init maceps2_init(void)
+static int __devinit maceps2_probe(struct platform_device *dev)
{
- maceps2_device = platform_device_register_simple("maceps2", -1, NULL, 0);
- if (IS_ERR(maceps2_device))
- return PTR_ERR(maceps2_device);
-
- port_data[0].port = &mace->perif.ps2.keyb;
- port_data[0].irq = MACEISA_KEYB_IRQ;
- port_data[1].port = &mace->perif.ps2.mouse;
- port_data[1].irq = MACEISA_MOUSE_IRQ;
-
maceps2_port[0] = maceps2_allocate_port(0);
maceps2_port[1] = maceps2_allocate_port(1);
if (!maceps2_port[0] || !maceps2_port[1]) {
kfree(maceps2_port[0]);
kfree(maceps2_port[1]);
- platform_device_unregister(maceps2_device);
return -ENOMEM;
}
@@ -165,11 +153,59 @@ static int __init maceps2_init(void)
return 0;
}
-static void __exit maceps2_exit(void)
+static int __devexit maceps2_remove(struct platform_device *dev)
{
serio_unregister_port(maceps2_port[0]);
serio_unregister_port(maceps2_port[1]);
+
+ return 0;
+}
+
+static struct platform_driver maceps2_driver = {
+ .driver = {
+ .name = "maceps2",
+ .owner = THIS_MODULE,
+ },
+ .probe = maceps2_probe,
+ .remove = __devexit_p(maceps2_remove),
+};
+
+static int __init maceps2_init(void)
+{
+ int error;
+
+ error = platform_driver_register(&maceps2_driver);
+ if (error)
+ return error;
+
+ maceps2_device = platform_device_alloc("maceps2", -1);
+ if (!maceps2_device) {
+ error = -ENOMEM;
+ goto err_unregister_driver;
+ }
+
+ port_data[0].port = &mace->perif.ps2.keyb;
+ port_data[0].irq = MACEISA_KEYB_IRQ;
+ port_data[1].port = &mace->perif.ps2.mouse;
+ port_data[1].irq = MACEISA_MOUSE_IRQ;
+
+ error = platform_device_add(maceps2_device);
+ if (error)
+ goto err_free_device;
+
+ return 0;
+
+ err_free_device:
+ platform_device_put(maceps2_device);
+ err_unregister_driver:
+ platform_driver_unregister(&maceps2_driver);
+ return error;
+}
+
+static void __exit maceps2_exit(void)
+{
platform_device_unregister(maceps2_device);
+ platform_driver_unregister(&maceps2_driver);
}
module_init(maceps2_init);
diff --git a/drivers/input/serio/q40kbd.c b/drivers/input/serio/q40kbd.c
index b44d255596c..d3827c5fe11 100644
--- a/drivers/input/serio/q40kbd.c
+++ b/drivers/input/serio/q40kbd.c
@@ -75,13 +75,13 @@ static irqreturn_t q40kbd_interrupt(int irq, void *dev_id, struct pt_regs *regs)
static void q40kbd_flush(void)
{
- int maxread = 100;
+ int maxread = 100;
unsigned long flags;
spin_lock_irqsave(&q40kbd_lock, flags);
- while (maxread-- && (Q40_IRQ_KEYB_MASK & master_inb(INTERRUPT_REG)))
- master_inb(KEYCODE_REG);
+ while (maxread-- && (Q40_IRQ_KEYB_MASK & master_inb(INTERRUPT_REG)))
+ master_inb(KEYCODE_REG);
spin_unlock_irqrestore(&q40kbd_lock, flags);
}
@@ -97,14 +97,14 @@ static int q40kbd_open(struct serio *port)
if (request_irq(Q40_IRQ_KEYBOARD, q40kbd_interrupt, 0, "q40kbd", NULL)) {
printk(KERN_ERR "q40kbd.c: Can't get irq %d.\n", Q40_IRQ_KEYBOARD);
- return -1;
+ return -EBUSY;
}
- /* off we go */
- master_outb(-1, KEYBOARD_UNLOCK_REG);
- master_outb(1, KEY_IRQ_ENABLE_REG);
+ /* off we go */
+ master_outb(-1, KEYBOARD_UNLOCK_REG);
+ master_outb(1, KEY_IRQ_ENABLE_REG);
- return 0;
+ return 0;
}
static void q40kbd_close(struct serio *port)
@@ -116,48 +116,73 @@ static void q40kbd_close(struct serio *port)
q40kbd_flush();
}
-static struct serio * __init q40kbd_allocate_port(void)
+static int __devinit q40kbd_probe(struct platform_device *dev)
{
- struct serio *serio;
-
- serio = kmalloc(sizeof(struct serio), GFP_KERNEL);
- if (serio) {
- memset(serio, 0, sizeof(struct serio));
- serio->id.type = SERIO_8042;
- serio->open = q40kbd_open;
- serio->close = q40kbd_close;
- serio->dev.parent = &q40kbd_device->dev;
- strlcpy(serio->name, "Q40 Kbd Port", sizeof(serio->name));
- strlcpy(serio->phys, "Q40", sizeof(serio->phys));
- }
+ q40kbd_port = kzalloc(sizeof(struct serio), GFP_KERNEL);
+ if (!q40kbd_port)
+ return -ENOMEM;
+
+ q40kbd_port->id.type = SERIO_8042;
+ q40kbd_port->open = q40kbd_open;
+ q40kbd_port->close = q40kbd_close;
+ q40kbd_port->dev.parent = &dev->dev;
+ strlcpy(q40kbd_port->name, "Q40 Kbd Port", sizeof(q40kbd_port->name));
+ strlcpy(q40kbd_port->phys, "Q40", sizeof(q40kbd_port->phys));
+
+ serio_register_port(q40kbd_port);
+ printk(KERN_INFO "serio: Q40 kbd registered\n");
- return serio;
+ return 0;
}
+static int __devexit q40kbd_remove(struct platform_device *dev)
+{
+ serio_unregister_port(q40kbd_port);
+
+ return 0;
+}
+
+static struct platform_driver q40kbd_driver = {
+ .driver = {
+ .name = "q40kbd",
+ .owner = THIS_MODULE,
+ },
+ .probe = q40kbd_probe,
+ .remove = __devexit_p(q40kbd_remove),
+};
+
static int __init q40kbd_init(void)
{
+ int error;
+
if (!MACH_IS_Q40)
return -EIO;
- q40kbd_device = platform_device_register_simple("q40kbd", -1, NULL, 0);
- if (IS_ERR(q40kbd_device))
- return PTR_ERR(q40kbd_device);
+ error = platform_driver_register(&q40kbd_driver);
+ if (error)
+ return error;
- if (!(q40kbd_port = q40kbd_allocate_port())) {
- platform_device_unregister(q40kbd_device);
- return -ENOMEM;
- }
+ q40kbd_device = platform_device_alloc("q40kbd", -1);
+ if (!q40kbd_device)
+ goto err_unregister_driver;
- serio_register_port(q40kbd_port);
- printk(KERN_INFO "serio: Q40 kbd registered\n");
+ error = platform_device_add(q40kbd_device);
+ if (error)
+ goto err_free_device;
return 0;
+
+ err_free_device:
+ platform_device_put(q40kbd_device);
+ err_unregister_driver:
+ platform_driver_unregister(&q40kbd_driver);
+ return error;
}
static void __exit q40kbd_exit(void)
{
- serio_unregister_port(q40kbd_port);
platform_device_unregister(q40kbd_device);
+ platform_driver_unregister(&q40kbd_driver);
}
module_init(q40kbd_init);
diff --git a/drivers/misc/ibmasm/ibmasm.h b/drivers/misc/ibmasm/ibmasm.h
index d7e20a34f88..1cef2387fa6 100644
--- a/drivers/misc/ibmasm/ibmasm.h
+++ b/drivers/misc/ibmasm/ibmasm.h
@@ -141,8 +141,8 @@ struct reverse_heartbeat {
};
struct ibmasm_remote {
- struct input_dev keybd_dev;
- struct input_dev mouse_dev;
+ struct input_dev *keybd_dev;
+ struct input_dev *mouse_dev;
};
struct service_processor {
@@ -157,7 +157,7 @@ struct service_processor {
char dirname[IBMASM_NAME_SIZE];
char devname[IBMASM_NAME_SIZE];
unsigned int number;
- struct ibmasm_remote *remote;
+ struct ibmasm_remote remote;
int serial_line;
struct device *dev;
};
diff --git a/drivers/misc/ibmasm/remote.c b/drivers/misc/ibmasm/remote.c
index d3c48d23ee5..1abd0c58ae2 100644
--- a/drivers/misc/ibmasm/remote.c
+++ b/drivers/misc/ibmasm/remote.c
@@ -203,9 +203,9 @@ void ibmasm_handle_mouse_interrupt(struct service_processor *sp,
print_input(&input);
if (input.type == INPUT_TYPE_MOUSE) {
- send_mouse_event(&sp->remote->mouse_dev, regs, &input);
+ send_mouse_event(sp->remote.mouse_dev, regs, &input);
} else if (input.type == INPUT_TYPE_KEYBOARD) {
- send_keyboard_event(&sp->remote->keybd_dev, regs, &input);
+ send_keyboard_event(sp->remote.keybd_dev, regs, &input);
} else
break;
@@ -217,56 +217,70 @@ void ibmasm_handle_mouse_interrupt(struct service_processor *sp,
int ibmasm_init_remote_input_dev(struct service_processor *sp)
{
/* set up the mouse input device */
- struct ibmasm_remote *remote;
+ struct input_dev *mouse_dev, *keybd_dev;
struct pci_dev *pdev = to_pci_dev(sp->dev);
+ int error = -ENOMEM;
int i;
- sp->remote = remote = kmalloc(sizeof(*remote), GFP_KERNEL);
- if (!remote)
- return -ENOMEM;
+ sp->remote.mouse_dev = mouse_dev = input_allocate_device();
+ sp->remote.keybd_dev = keybd_dev = input_allocate_device();
- memset(remote, 0, sizeof(*remote));
+ if (!mouse_dev || !keybd_dev)
+ goto err_free_devices;
- remote->mouse_dev.private = remote;
- init_input_dev(&remote->mouse_dev);
- remote->mouse_dev.id.vendor = pdev->vendor;
- remote->mouse_dev.id.product = pdev->device;
- remote->mouse_dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
- remote->mouse_dev.keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) |
+ mouse_dev->id.bustype = BUS_PCI;
+ mouse_dev->id.vendor = pdev->vendor;
+ mouse_dev->id.product = pdev->device;
+ mouse_dev->id.version = 1;
+ mouse_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
+ mouse_dev->keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) |
BIT(BTN_RIGHT) | BIT(BTN_MIDDLE);
- set_bit(BTN_TOUCH, remote->mouse_dev.keybit);
- remote->mouse_dev.name = remote_mouse_name;
- input_set_abs_params(&remote->mouse_dev, ABS_X, 0, xmax, 0, 0);
- input_set_abs_params(&remote->mouse_dev, ABS_Y, 0, ymax, 0, 0);
+ set_bit(BTN_TOUCH, mouse_dev->keybit);
+ mouse_dev->name = remote_mouse_name;
+ input_set_abs_params(mouse_dev, ABS_X, 0, xmax, 0, 0);
+ input_set_abs_params(mouse_dev, ABS_Y, 0, ymax, 0, 0);
- remote->keybd_dev.private = remote;
- init_input_dev(&remote->keybd_dev);
- remote->keybd_dev.id.vendor = pdev->vendor;
- remote->keybd_dev.id.product = pdev->device;
- remote->keybd_dev.evbit[0] = BIT(EV_KEY);
- remote->keybd_dev.name = remote_keybd_name;
+ mouse_dev->id.bustype = BUS_PCI;
+ keybd_dev->id.vendor = pdev->vendor;
+ keybd_dev->id.product = pdev->device;
+ mouse_dev->id.version = 2;
+ keybd_dev->evbit[0] = BIT(EV_KEY);
+ keybd_dev->name = remote_keybd_name;
- for (i=0; i<XLATE_SIZE; i++) {
+ for (i = 0; i < XLATE_SIZE; i++) {
if (xlate_high[i])
- set_bit(xlate_high[i], remote->keybd_dev.keybit);
+ set_bit(xlate_high[i], keybd_dev->keybit);
if (xlate[i])
- set_bit(xlate[i], remote->keybd_dev.keybit);
+ set_bit(xlate[i], keybd_dev->keybit);
}
- input_register_device(&remote->mouse_dev);
- input_register_device(&remote->keybd_dev);
+ error = input_register_device(mouse_dev);
+ if (error)
+ goto err_free_devices;
+
+ error = input_register_device(keybd_dev);
+ if (error)
+ goto err_unregister_mouse_dev;
+
enable_mouse_interrupts(sp);
printk(KERN_INFO "ibmasm remote responding to events on RSA card %d\n", sp->number);
return 0;
+
+ err_unregister_mouse_dev:
+ input_unregister_device(mouse_dev);
+ err_free_devices:
+ input_free_device(mouse_dev);
+ input_free_device(keybd_dev);
+
+ return error;
}
void ibmasm_free_remote_input_dev(struct service_processor *sp)
{
disable_mouse_interrupts(sp);
- input_unregister_device(&sp->remote->keybd_dev);
- input_unregister_device(&sp->remote->mouse_dev);
- kfree(sp->remote);
+ input_unregister_device(sp->remote.mouse_dev);
+ input_unregister_device(sp->remote.keybd_dev);
}
diff --git a/drivers/usb/input/appletouch.c b/drivers/usb/input/appletouch.c
index 1949b54f41f..c222ed13dea 100644
--- a/drivers/usb/input/appletouch.c
+++ b/drivers/usb/input/appletouch.c
@@ -6,6 +6,7 @@
* Copyright (C) 2005 Stelian Pop (stelian@popies.net)
* Copyright (C) 2005 Frank Arnold (frank@scirocco-5v-turbo.de)
* Copyright (C) 2005 Peter Osterlund (petero2@telia.com)
+ * Copyright (C) 2005 Michael Hanselmann (linux-kernel@hansmi.ch)
*
* Thanks to Alex Harper <basilisk@foobox.net> for his inputs.
*
@@ -38,6 +39,11 @@
/* Apple has powerbooks which have the keyboard with different Product IDs */
#define APPLE_VENDOR_ID 0x05AC
+/* These names come from Info.plist in AppleUSBTrackpad.kext */
+#define GEYSER_ANSI_PRODUCT_ID 0x0214
+#define GEYSER_ISO_PRODUCT_ID 0x0215
+#define GEYSER_JIS_PRODUCT_ID 0x0216
+
#define ATP_DEVICE(prod) \
.match_flags = USB_DEVICE_ID_MATCH_DEVICE | \
USB_DEVICE_ID_MATCH_INT_CLASS | \
@@ -53,13 +59,17 @@ static struct usb_device_id atp_table [] = {
{ ATP_DEVICE(0x020F) },
{ ATP_DEVICE(0x030A) },
{ ATP_DEVICE(0x030B) },
- { } /* Terminating entry */
+
+ /* PowerBooks Oct 2005 */
+ { ATP_DEVICE(GEYSER_ANSI_PRODUCT_ID) },
+ { ATP_DEVICE(GEYSER_ISO_PRODUCT_ID) },
+ { ATP_DEVICE(GEYSER_JIS_PRODUCT_ID) },
+
+ /* Terminating entry */
+ { }
};
MODULE_DEVICE_TABLE (usb, atp_table);
-/* size of a USB urb transfer */
-#define ATP_DATASIZE 81
-
/*
* number of sensors. Note that only 16 instead of 26 X (horizontal)
* sensors exist on 12" and 15" PowerBooks. All models have 16 Y
@@ -108,6 +118,8 @@ struct atp {
signed char xy_old[ATP_XSENSORS + ATP_YSENSORS];
/* accumulated sensors */
int xy_acc[ATP_XSENSORS + ATP_YSENSORS];
+ int overflowwarn; /* overflow warning printed? */
+ int datalen; /* size of an USB urb transfer */
};
#define dbg_dump(msg, tab) \
@@ -124,7 +136,7 @@ struct atp {
if (debug) printk(format, ##a); \
} while (0)
-MODULE_AUTHOR("Johannes Berg, Stelian Pop, Frank Arnold");
+MODULE_AUTHOR("Johannes Berg, Stelian Pop, Frank Arnold, Michael Hanselmann");
MODULE_DESCRIPTION("Apple PowerBooks USB touchpad driver");
MODULE_LICENSE("GPL");
@@ -132,6 +144,16 @@ static int debug = 1;
module_param(debug, int, 0644);
MODULE_PARM_DESC(debug, "Activate debugging output");
+/* Checks if the device a Geyser 2 (ANSI, ISO, JIS) */
+static inline int atp_is_geyser_2(struct atp *dev)
+{
+ int16_t productId = le16_to_cpu(dev->udev->descriptor.idProduct);
+
+ return (productId == GEYSER_ANSI_PRODUCT_ID) ||
+ (productId == GEYSER_ISO_PRODUCT_ID) ||
+ (productId == GEYSER_JIS_PRODUCT_ID);
+}
+
static int atp_calculate_abs(int *xy_sensors, int nb_sensors, int fact,
int *z, int *fingers)
{
@@ -168,13 +190,20 @@ static inline void atp_report_fingers(struct input_dev *input, int fingers)
static void atp_complete(struct urb* urb, struct pt_regs* regs)
{
int x, y, x_z, y_z, x_f, y_f;
- int retval, i;
+ int retval, i, j;
struct atp *dev = urb->context;
switch (urb->status) {
case 0:
/* success */
break;
+ case -EOVERFLOW:
+ if(!dev->overflowwarn) {
+ printk("appletouch: OVERFLOW with data "
+ "length %d, actual length is %d\n",
+ dev->datalen, dev->urb->actual_length);
+ dev->overflowwarn = 1;
+ }
case -ECONNRESET:
case -ENOENT:
case -ESHUTDOWN:
@@ -189,23 +218,45 @@ static void atp_complete(struct urb* urb, struct pt_regs* regs)
}
/* drop incomplete datasets */
- if (dev->urb->actual_length != ATP_DATASIZE) {
+ if (dev->urb->actual_length != dev->datalen) {
dprintk("appletouch: incomplete data package.\n");
goto exit;
}
/* reorder the sensors values */
- for (i = 0; i < 8; i++) {
- /* X values */
- dev->xy_cur[i ] = dev->data[5 * i + 2];
- dev->xy_cur[i + 8] = dev->data[5 * i + 4];
- dev->xy_cur[i + 16] = dev->data[5 * i + 42];
- if (i < 2)
- dev->xy_cur[i + 24] = dev->data[5 * i + 44];
-
- /* Y values */
- dev->xy_cur[i + 26] = dev->data[5 * i + 1];
- dev->xy_cur[i + 34] = dev->data[5 * i + 3];
+ if (atp_is_geyser_2(dev)) {
+ memset(dev->xy_cur, 0, sizeof(dev->xy_cur));
+
+ /*
+ * The values are laid out like this:
+ * Y1, Y2, -, Y3, Y4, -, ..., X1, X2, -, X3, X4, -, ...
+ * '-' is an unused value.
+ */
+
+ /* read X values */
+ for (i = 0, j = 19; i < 20; i += 2, j += 3) {
+ dev->xy_cur[i] = dev->data[j];
+ dev->xy_cur[i + 1] = dev->data[j + 1];
+ }
+
+ /* read Y values */
+ for (i = 0, j = 1; i < 9; i += 2, j += 3) {
+ dev->xy_cur[ATP_XSENSORS + i] = dev->data[j];
+ dev->xy_cur[ATP_XSENSORS + i + 1] = dev->data[j + 1];
+ }
+ } else {
+ for (i = 0; i < 8; i++) {
+ /* X values */
+ dev->xy_cur[i ] = dev->data[5 * i + 2];
+ dev->xy_cur[i + 8] = dev->data[5 * i + 4];
+ dev->xy_cur[i + 16] = dev->data[5 * i + 42];
+ if (i < 2)
+ dev->xy_cur[i + 24] = dev->data[5 * i + 44];
+
+ /* Y values */
+ dev->xy_cur[i + 26] = dev->data[5 * i + 1];
+ dev->xy_cur[i + 34] = dev->data[5 * i + 3];
+ }
}
dbg_dump("sample", dev->xy_cur);
@@ -216,16 +267,24 @@ static void atp_complete(struct urb* urb, struct pt_regs* regs)
dev->x_old = dev->y_old = -1;
memcpy(dev->xy_old, dev->xy_cur, sizeof(dev->xy_old));
- /* 17" Powerbooks have 10 extra X sensors */
- for (i = 16; i < ATP_XSENSORS; i++)
- if (dev->xy_cur[i]) {
- printk("appletouch: 17\" model detected.\n");
+ /* 17" Powerbooks have extra X sensors */
+ for (i = (atp_is_geyser_2(dev)?15:16); i < ATP_XSENSORS; i++) {
+ if (!dev->xy_cur[i]) continue;
+
+ printk("appletouch: 17\" model detected.\n");
+ if(atp_is_geyser_2(dev))
+ input_set_abs_params(dev->input, ABS_X, 0,
+ (20 - 1) *
+ ATP_XFACT - 1,
+ ATP_FUZZ, 0);
+ else
input_set_abs_params(dev->input, ABS_X, 0,
(ATP_XSENSORS - 1) *
ATP_XFACT - 1,
ATP_FUZZ, 0);
- break;
- }
+
+ break;
+ }
goto exit;
}
@@ -282,7 +341,8 @@ static void atp_complete(struct urb* urb, struct pt_regs* regs)
memset(dev->xy_acc, 0, sizeof(dev->xy_acc));
}
- input_report_key(dev->input, BTN_LEFT, !!dev->data[80]);
+ input_report_key(dev->input, BTN_LEFT,
+ !!dev->data[dev->datalen - 1]);
input_sync(dev->input);
@@ -353,6 +413,8 @@ static int atp_probe(struct usb_interface *iface, const struct usb_device_id *id
dev->udev = udev;
dev->input = input_dev;
+ dev->overflowwarn = 0;
+ dev->datalen = (atp_is_geyser_2(dev)?64:81);
dev->urb = usb_alloc_urb(0, GFP_KERNEL);
if (!dev->urb) {
@@ -360,7 +422,7 @@ static int atp_probe(struct usb_interface *iface, const struct usb_device_id *id
goto err_free_devs;
}
- dev->data = usb_buffer_alloc(dev->udev, ATP_DATASIZE, GFP_KERNEL,
+ dev->data = usb_buffer_alloc(dev->udev, dev->datalen, GFP_KERNEL,
&dev->urb->transfer_dma);
if (!dev->data) {
retval = -ENOMEM;
@@ -369,7 +431,7 @@ static int atp_probe(struct usb_interface *iface, const struct usb_device_id *id
usb_fill_int_urb(dev->urb, udev,
usb_rcvintpipe(udev, int_in_endpointAddr),
- dev->data, ATP_DATASIZE, atp_complete, dev, 1);
+ dev->data, dev->datalen, atp_complete, dev, 1);
usb_make_path(udev, dev->phys, sizeof(dev->phys));
strlcat(dev->phys, "/input0", sizeof(dev->phys));
@@ -385,14 +447,25 @@ static int atp_probe(struct usb_interface *iface, const struct usb_device_id *id
set_bit(EV_ABS, input_dev->evbit);
- /*
- * 12" and 15" Powerbooks only have 16 x sensors,
- * 17" models are detected later.
- */
- input_set_abs_params(input_dev, ABS_X, 0,
- (16 - 1) * ATP_XFACT - 1, ATP_FUZZ, 0);
- input_set_abs_params(input_dev, ABS_Y, 0,
- (ATP_YSENSORS - 1) * ATP_YFACT - 1, ATP_FUZZ, 0);
+ if (atp_is_geyser_2(dev)) {
+ /*
+ * Oct 2005 15" PowerBooks have 15 X sensors, 17" are detected
+ * later.
+ */
+ input_set_abs_params(input_dev, ABS_X, 0,
+ ((15 - 1) * ATP_XFACT) - 1, ATP_FUZZ, 0);
+ input_set_abs_params(input_dev, ABS_Y, 0,
+ ((9 - 1) * ATP_YFACT) - 1, ATP_FUZZ, 0);
+ } else {
+ /*
+ * 12" and 15" Powerbooks only have 16 x sensors,
+ * 17" models are detected later.
+ */
+ input_set_abs_params(input_dev, ABS_X, 0,
+ (16 - 1) * ATP_XFACT - 1, ATP_FUZZ, 0);
+ input_set_abs_params(input_dev, ABS_Y, 0,
+ (ATP_YSENSORS - 1) * ATP_YFACT - 1, ATP_FUZZ, 0);
+ }
input_set_abs_params(input_dev, ABS_PRESSURE, 0, ATP_PRESSURE, 0, 0);
set_bit(EV_KEY, input_dev->evbit);
@@ -427,7 +500,7 @@ static void atp_disconnect(struct usb_interface *iface)
usb_kill_urb(dev->urb);
input_unregister_device(dev->input);
usb_free_urb(dev->urb);
- usb_buffer_free(dev->udev, ATP_DATASIZE,
+ usb_buffer_free(dev->udev, dev->datalen,
dev->data, dev->urb->transfer_dma);
kfree(dev);
}
diff --git a/drivers/usb/input/hid-debug.h b/drivers/usb/input/hid-debug.h
index ceebab99eff..702c48c2f81 100644
--- a/drivers/usb/input/hid-debug.h
+++ b/drivers/usb/input/hid-debug.h
@@ -681,6 +681,21 @@ static char *keys[KEY_MAX + 1] = {
[KEY_SEND] = "Send", [KEY_REPLY] = "Reply",
[KEY_FORWARDMAIL] = "ForwardMail", [KEY_SAVE] = "Save",
[KEY_DOCUMENTS] = "Documents",
+ [KEY_FN] = "Fn", [KEY_FN_ESC] = "Fn+ESC",
+ [KEY_FN_1] = "Fn+1", [KEY_FN_2] = "Fn+2",
+ [KEY_FN_B] = "Fn+B", [KEY_FN_D] = "Fn+D",
+ [KEY_FN_E] = "Fn+E", [KEY_FN_F] = "Fn+F",
+ [KEY_FN_S] = "Fn+S",
+ [KEY_FN_F1] = "Fn+F1", [KEY_FN_F2] = "Fn+F2",
+ [KEY_FN_F3] = "Fn+F3", [KEY_FN_F4] = "Fn+F4",
+ [KEY_FN_F5] = "Fn+F5", [KEY_FN_F6] = "Fn+F6",
+ [KEY_FN_F7] = "Fn+F7", [KEY_FN_F8] = "Fn+F8",
+ [KEY_FN_F9] = "Fn+F9", [KEY_FN_F10] = "Fn+F10",
+ [KEY_FN_F11] = "Fn+F11", [KEY_FN_F12] = "Fn+F12",
+ [KEY_KBDILLUMTOGGLE] = "KbdIlluminationToggle",
+ [KEY_KBDILLUMDOWN] = "KbdIlluminationDown",
+ [KEY_KBDILLUMUP] = "KbdIlluminationUp",
+ [KEY_SWITCHVIDEOMODE] = "SwitchVideoMode",
};
static char *relatives[REL_MAX + 1] = {