Commit b9abaa3f authored by Linus Torvalds's avatar Linus Torvalds
parents 8995b161 736ce432
......@@ -3,7 +3,7 @@ Apple Touchpad Driver (appletouch)
Copyright (C) 2005 Stelian Pop <stelian@popies.net>
appletouch is a Linux kernel driver for the USB touchpad found on post
February 2005 Apple Alu Powerbooks.
February 2005 and October 2005 Apple Aluminium Powerbooks.
This driver is derived from Johannes Berg's appletrackpad driver[1], but it has
been improved in some areas:
......@@ -13,7 +13,8 @@ been improved in some areas:
Credits go to Johannes Berg for reverse-engineering the touchpad protocol,
Frank Arnold for further improvements, and Alex Harper for some additional
information about the inner workings of the touchpad sensors.
information about the inner workings of the touchpad sensors. Michael
Hanselmann added support for the October 2005 models.
Usage:
------
......
......@@ -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
......
......@@ -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
......@@ -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;
......
......@@ -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);
......
......@@ -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);
......@@ -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);
......
......@@ -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();
}
......
......@@ -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 */
......
......@@ -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"),
},
},
{ }
};
......
......@@ -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 },
......
......@@ -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;
......@@ -539,12 +543,6 @@ static int psmouse_extensions(struct psmouse *psmouse,
if (max_proto >= PSMOUSE_IMPS && intellimouse_detect(psmouse, set_properties) == 0)
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;
......
......@@ -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;
......
......@@ -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);
......
......@@ -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"),
},
},
{ }
};
......
......@@ -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);
......
......@@ -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);
......
......@@ -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);
......
......@@ -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;
};
......
......@@ -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);
}
......@@ -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);
}
......
......@@ -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] = {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment