diff options
Diffstat (limited to 'drivers/input')
50 files changed, 1819 insertions, 704 deletions
diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c index 374f404e81da..3738d173f9a6 100644 --- a/drivers/input/evdev.c +++ b/drivers/input/evdev.c @@ -160,6 +160,8 @@ struct input_event_compat { # define COMPAT_TEST IS_IA32_PROCESS(ia64_task_regs(current)) #elif defined(CONFIG_ARCH_S390) # define COMPAT_TEST test_thread_flag(TIF_31BIT) +#elif defined(CONFIG_MIPS) +# define COMPAT_TEST (current->thread.mflags & MF_32BIT_ADDR) #else # define COMPAT_TEST test_thread_flag(TIF_32BIT) #endif @@ -320,6 +322,7 @@ static long evdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) 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); @@ -390,6 +393,7 @@ static long evdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) case EV_LED: bits = dev->ledbit; len = LED_MAX; break; case EV_SND: bits = dev->sndbit; len = SND_MAX; break; case EV_FF: bits = dev->ffbit; len = FF_MAX; break; + case EV_SW: bits = dev->swbit; len = SW_MAX; break; default: return -EINVAL; } len = NBITS(len) * sizeof(long); @@ -418,6 +422,13 @@ static long evdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) return copy_to_user(p, dev->snd, len) ? -EFAULT : len; } + 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(EVIOCGNAME(0))) { int len; if (!dev->name) return -ENOENT; @@ -498,7 +509,7 @@ do { \ int len = NBITS_COMPAT((max)) * sizeof(compat_long_t); \ if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd); \ for (i = 0; i < len / sizeof(compat_long_t); i++) \ - if (copy_to_user((compat_long_t*) p + i, \ + 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; \ diff --git a/drivers/input/gameport/emu10k1-gp.c b/drivers/input/gameport/emu10k1-gp.c index a0118038330a..462f8d300aae 100644 --- a/drivers/input/gameport/emu10k1-gp.c +++ b/drivers/input/gameport/emu10k1-gp.c @@ -75,7 +75,7 @@ static int __devinit emu_probe(struct pci_dev *pdev, const struct pci_device_id if (!request_region(ioport, iolen, "emu10k1-gp")) return -EBUSY; - emu = kcalloc(1, sizeof(struct emu), GFP_KERNEL); + emu = kzalloc(sizeof(struct emu), GFP_KERNEL); port = gameport_allocate_port(); if (!emu || !port) { printk(KERN_ERR "emu10k1-gp: Memory allocation failed\n"); diff --git a/drivers/input/gameport/fm801-gp.c b/drivers/input/gameport/fm801-gp.c index 57615bc63906..47e93daa0fa7 100644 --- a/drivers/input/gameport/fm801-gp.c +++ b/drivers/input/gameport/fm801-gp.c @@ -83,7 +83,7 @@ static int __devinit fm801_gp_probe(struct pci_dev *pci, const struct pci_device struct fm801_gp *gp; struct gameport *port; - gp = kcalloc(1, sizeof(struct fm801_gp), GFP_KERNEL); + gp = kzalloc(sizeof(struct fm801_gp), GFP_KERNEL); port = gameport_allocate_port(); if (!gp || !port) { printk(KERN_ERR "fm801-gp: Memory allocation failed\n"); diff --git a/drivers/input/gameport/ns558.c b/drivers/input/gameport/ns558.c index 1ab5f2dc8a2a..d2e55dc956ba 100644 --- a/drivers/input/gameport/ns558.c +++ b/drivers/input/gameport/ns558.c @@ -142,7 +142,7 @@ static int ns558_isa_probe(int io) return -EBUSY; } - ns558 = kcalloc(1, sizeof(struct ns558), GFP_KERNEL); + ns558 = kzalloc(sizeof(struct ns558), GFP_KERNEL); port = gameport_allocate_port(); if (!ns558 || !port) { printk(KERN_ERR "ns558: Memory allocation failed.\n"); @@ -215,7 +215,7 @@ static int ns558_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *did) if (!request_region(ioport, iolen, "ns558-pnp")) return -EBUSY; - ns558 = kcalloc(1, sizeof(struct ns558), GFP_KERNEL); + ns558 = kzalloc(sizeof(struct ns558), GFP_KERNEL); port = gameport_allocate_port(); if (!ns558 || !port) { printk(KERN_ERR "ns558: Memory allocation failed\n"); @@ -275,9 +275,9 @@ static int __init ns558_init(void) static void __exit ns558_exit(void) { - struct ns558 *ns558; + struct ns558 *ns558, *safe; - list_for_each_entry(ns558, &ns558_list, node) { + list_for_each_entry_safe(ns558, safe, &ns558_list, node) { gameport_unregister_port(ns558->gameport); release_region(ns558->io & ~(ns558->size - 1), ns558->size); kfree(ns558); diff --git a/drivers/input/input.c b/drivers/input/input.c index 7c4b4d37b3e6..88636a204525 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c @@ -48,12 +48,6 @@ static LIST_HEAD(input_handler_list); static struct input_handler *input_table[8]; -#ifdef CONFIG_PROC_FS -static struct proc_dir_entry *proc_bus_input_dir; -static DECLARE_WAIT_QUEUE_HEAD(input_devices_poll_wait); -static int input_devices_state; -#endif - void input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) { struct input_handle *handle; @@ -95,6 +89,15 @@ void input_event(struct input_dev *dev, unsigned int type, unsigned int code, in break; + case EV_SW: + + if (code > SW_MAX || !test_bit(code, dev->swbit) || !!test_bit(code, dev->sw) == value) + return; + + change_bit(code, dev->sw); + + break; + case EV_ABS: if (code > ABS_MAX || !test_bit(code, dev->absbit)) @@ -312,6 +315,7 @@ static struct input_device_id *input_match_device(struct input_device_id *id, st return NULL; } + /* * Input hotplugging interface - loading event handlers based on * device bitfields. @@ -407,6 +411,7 @@ static void input_call_hotplug(char *verb, struct input_dev *dev) SPRINTF_BIT_A2(ledbit, "LED=", LED_MAX, EV_LED); SPRINTF_BIT_A2(sndbit, "SND=", SND_MAX, EV_SND); SPRINTF_BIT_A2(ffbit, "FF=", FF_MAX, EV_FF); + SPRINTF_BIT_A2(swbit, "SW=", SW_MAX, EV_SW); envp[i++] = NULL; @@ -428,6 +433,178 @@ static void input_call_hotplug(char *verb, struct input_dev *dev) #endif +#ifdef CONFIG_PROC_FS + +static struct proc_dir_entry *proc_bus_input_dir; +static DECLARE_WAIT_QUEUE_HEAD(input_devices_poll_wait); +static int input_devices_state; + +static inline void input_wakeup_procfs_readers(void) +{ + input_devices_state++; + wake_up(&input_devices_poll_wait); +} + +static unsigned int input_devices_poll(struct file *file, poll_table *wait) +{ + int state = input_devices_state; + poll_wait(file, &input_devices_poll_wait, wait); + if (state != input_devices_state) + return POLLIN | POLLRDNORM; + return 0; +} + +#define SPRINTF_BIT_B(bit, name, max) \ + do { \ + len += sprintf(buf + len, "B: %s", name); \ + for (i = NBITS(max) - 1; i >= 0; i--) \ + if (dev->bit[i]) break; \ + for (; i >= 0; i--) \ + len += sprintf(buf + len, "%lx ", dev->bit[i]); \ + len += sprintf(buf + len, "\n"); \ + } while (0) + +#define SPRINTF_BIT_B2(bit, name, max, ev) \ + do { \ + if (test_bit(ev, dev->evbit)) \ + SPRINTF_BIT_B(bit, name, max); \ + } while (0) + +static int input_devices_read(char *buf, char **start, off_t pos, int count, int *eof, void *data) +{ + struct input_dev *dev; + struct input_handle *handle; + + off_t at = 0; + int i, len, cnt = 0; + + list_for_each_entry(dev, &input_dev_list, node) { + + len = sprintf(buf, "I: Bus=%04x Vendor=%04x Product=%04x Version=%04x\n", + dev->id.bustype, dev->id.vendor, dev->id.product, dev->id.version); + + len += sprintf(buf + len, "N: Name=\"%s\"\n", dev->name ? dev->name : ""); + len += sprintf(buf + len, "P: Phys=%s\n", dev->phys ? dev->phys : ""); + len += sprintf(buf + len, "H: Handlers="); + + list_for_each_entry(handle, &dev->h_list, d_node) + len += sprintf(buf + len, "%s ", handle->name); + + len += sprintf(buf + len, "\n"); + + SPRINTF_BIT_B(evbit, "EV=", EV_MAX); + SPRINTF_BIT_B2(keybit, "KEY=", KEY_MAX, EV_KEY); + SPRINTF_BIT_B2(relbit, "REL=", REL_MAX, EV_REL); + SPRINTF_BIT_B2(absbit, "ABS=", ABS_MAX, EV_ABS); + SPRINTF_BIT_B2(mscbit, "MSC=", MSC_MAX, EV_MSC); + SPRINTF_BIT_B2(ledbit, "LED=", LED_MAX, EV_LED); + SPRINTF_BIT_B2(sndbit, "SND=", SND_MAX, EV_SND); + SPRINTF_BIT_B2(ffbit, "FF=", FF_MAX, EV_FF); + SPRINTF_BIT_B2(swbit, "SW=", SW_MAX, EV_SW); + + len += sprintf(buf + len, "\n"); + + at += len; + + if (at >= pos) { + if (!*start) { + *start = buf + (pos - (at - len)); + cnt = at - pos; + } else cnt += len; + buf += len; + if (cnt >= count) + break; + } + } + + if (&dev->node == &input_dev_list) + *eof = 1; + + return (count > cnt) ? cnt : count; +} + +static int input_handlers_read(char *buf, char **start, off_t pos, int count, int *eof, void *data) +{ + struct input_handler *handler; + + off_t at = 0; + int len = 0, cnt = 0; + int i = 0; + + list_for_each_entry(handler, &input_handler_list, node) { + + if (handler->fops) + len = sprintf(buf, "N: Number=%d Name=%s Minor=%d\n", + i++, handler->name, handler->minor); + else + len = sprintf(buf, "N: Number=%d Name=%s\n", + i++, handler->name); + + at += len; + + if (at >= pos) { + if (!*start) { + *start = buf + (pos - (at - len)); + cnt = at - pos; + } else cnt += len; + buf += len; + if (cnt >= count) + break; + } + } + if (&handler->node == &input_handler_list) + *eof = 1; + + return (count > cnt) ? cnt : count; +} + +static struct file_operations input_fileops; + +static int __init input_proc_init(void) +{ + struct proc_dir_entry *entry; + + proc_bus_input_dir = proc_mkdir("input", proc_bus); + if (!proc_bus_input_dir) + return -ENOMEM; + + proc_bus_input_dir->owner = THIS_MODULE; + + entry = create_proc_read_entry("devices", 0, proc_bus_input_dir, input_devices_read, NULL); + if (!entry) + goto fail1; + + entry->owner = THIS_MODULE; + input_fileops = *entry->proc_fops; + entry->proc_fops = &input_fileops; + entry->proc_fops->poll = input_devices_poll; + + entry = create_proc_read_entry("handlers", 0, proc_bus_input_dir, input_handlers_read, NULL); + if (!entry) + goto fail2; + + entry->owner = THIS_MODULE; + + return 0; + + fail2: remove_proc_entry("devices", proc_bus_input_dir); + fail1: remove_proc_entry("input", proc_bus); + return -ENOMEM; +} + +static void input_proc_exit(void) +{ + remove_proc_entry("devices", proc_bus_input_dir); + remove_proc_entry("handlers", proc_bus_input_dir); + remove_proc_entry("input", proc_bus); +} + +#else /* !CONFIG_PROC_FS */ +static inline void input_wakeup_procfs_readers(void) { } +static inline int input_proc_init(void) { return 0; } +static inline void input_proc_exit(void) { } +#endif + void input_register_device(struct input_dev *dev) { struct input_handle *handle; @@ -464,10 +641,7 @@ void input_register_device(struct input_dev *dev) input_call_hotplug("add", dev); #endif -#ifdef CONFIG_PROC_FS - input_devices_state++; - wake_up(&input_devices_poll_wait); -#endif + input_wakeup_procfs_readers(); } void input_unregister_device(struct input_dev *dev) @@ -491,10 +665,7 @@ void input_unregister_device(struct input_dev *dev) list_del_init(&dev->node); -#ifdef CONFIG_PROC_FS - input_devices_state++; - wake_up(&input_devices_poll_wait); -#endif + input_wakeup_procfs_readers(); } void input_register_handler(struct input_handler *handler) @@ -518,10 +689,7 @@ void input_register_handler(struct input_handler *handler) if ((handle = handler->connect(handler, dev, id))) input_link_handle(handle); -#ifdef CONFIG_PROC_FS - input_devices_state++; - wake_up(&input_devices_poll_wait); -#endif + input_wakeup_procfs_readers(); } void input_unregister_handler(struct input_handler *handler) @@ -540,10 +708,7 @@ void input_unregister_handler(struct input_handler *handler) if (handler->fops != NULL) input_table[handler->minor >> 5] = NULL; -#ifdef CONFIG_PROC_FS - input_devices_state++; - wake_up(&input_devices_poll_wait); -#endif + input_wakeup_procfs_readers(); } static int input_open_file(struct inode *inode, struct file *file) @@ -582,190 +747,43 @@ static struct file_operations input_fops = { .open = input_open_file, }; -#ifdef CONFIG_PROC_FS - -#define SPRINTF_BIT_B(bit, name, max) \ - do { \ - len += sprintf(buf + len, "B: %s", name); \ - for (i = NBITS(max) - 1; i >= 0; i--) \ - if (dev->bit[i]) break; \ - for (; i >= 0; i--) \ - len += sprintf(buf + len, "%lx ", dev->bit[i]); \ - len += sprintf(buf + len, "\n"); \ - } while (0) - -#define SPRINTF_BIT_B2(bit, name, max, ev) \ - do { \ - if (test_bit(ev, dev->evbit)) \ - SPRINTF_BIT_B(bit, name, max); \ - } while (0) - - -static unsigned int input_devices_poll(struct file *file, poll_table *wait) -{ - int state = input_devices_state; - poll_wait(file, &input_devices_poll_wait, wait); - if (state != input_devices_state) - return POLLIN | POLLRDNORM; - return 0; -} +struct class *input_class; -static int input_devices_read(char *buf, char **start, off_t pos, int count, int *eof, void *data) +static int __init input_init(void) { - struct input_dev *dev; - struct input_handle *handle; - - off_t at = 0; - int i, len, cnt = 0; - - list_for_each_entry(dev, &input_dev_list, node) { - - len = sprintf(buf, "I: Bus=%04x Vendor=%04x Product=%04x Version=%04x\n", - dev->id.bustype, dev->id.vendor, dev->id.product, dev->id.version); - - len += sprintf(buf + len, "N: Name=\"%s\"\n", dev->name ? dev->name : ""); - len += sprintf(buf + len, "P: Phys=%s\n", dev->phys ? dev->phys : ""); - len += sprintf(buf + len, "H: Handlers="); - - list_for_each_entry(handle, &dev->h_list, d_node) - len += sprintf(buf + len, "%s ", handle->name); - - len += sprintf(buf + len, "\n"); - - SPRINTF_BIT_B(evbit, "EV=", EV_MAX); - SPRINTF_BIT_B2(keybit, "KEY=", KEY_MAX, EV_KEY); - SPRINTF_BIT_B2(relbit, "REL=", REL_MAX, EV_REL); - SPRINTF_BIT_B2(absbit, "ABS=", ABS_MAX, EV_ABS); - SPRINTF_BIT_B2(mscbit, "MSC=", MSC_MAX, EV_MSC); - SPRINTF_BIT_B2(ledbit, "LED=", LED_MAX, EV_LED); - SPRINTF_BIT_B2(sndbit, "SND=", SND_MAX, EV_SND); - SPRINTF_BIT_B2(ffbit, "FF=", FF_MAX, EV_FF); - - len += sprintf(buf + len, "\n"); - - at += len; + int err; - if (at >= pos) { - if (!*start) { - *start = buf + (pos - (at - len)); - cnt = at - pos; - } else cnt += len; - buf += len; - if (cnt >= count) - break; - } + input_class = class_create(THIS_MODULE, "input"); + if (IS_ERR(input_class)) { + printk(KERN_ERR "input: unable to register input class\n"); + return PTR_ERR(input_class); } - if (&dev->node == &input_dev_list) - *eof = 1; - - return (count > cnt) ? cnt : count; -} - -static int input_handlers_read(char *buf, char **start, off_t pos, int count, int *eof, void *data) -{ - struct input_handler *handler; - - off_t at = 0; - int len = 0, cnt = 0; - int i = 0; - - list_for_each_entry(handler, &input_handler_list, node) { - - if (handler->fops) - len = sprintf(buf, "N: Number=%d Name=%s Minor=%d\n", - i++, handler->name, handler->minor); - else - len = sprintf(buf, "N: Number=%d Name=%s\n", - i++, handler->name); - - at += len; + err = input_proc_init(); + if (err) + goto fail1; - if (at >= pos) { - if (!*start) { - *start = buf + (pos - (at - len)); - cnt = at - pos; - } else cnt += len; - buf += len; - if (cnt >= count) - break; - } + err = register_chrdev(INPUT_MAJOR, "input", &input_fops); + if (err) { + printk(KERN_ERR "input: unable to register char major %d", INPUT_MAJOR); + goto fail2; } - if (&handler->node == &input_handler_list) - *eof = 1; - return (count > cnt) ? cnt : count; -} - -static struct file_operations input_fileops; - -static int __init input_proc_init(void) -{ - struct proc_dir_entry *entry; + err = devfs_mk_dir("input"); + if (err) + goto fail3; - proc_bus_input_dir = proc_mkdir("input", proc_bus); - if (proc_bus_input_dir == NULL) - return -ENOMEM; - proc_bus_input_dir->owner = THIS_MODULE; - entry = create_proc_read_entry("devices", 0, proc_bus_input_dir, input_devices_read, NULL); - if (entry == NULL) { - remove_proc_entry("input", proc_bus); - return -ENOMEM; - } - entry->owner = THIS_MODULE; - input_fileops = *entry->proc_fops; - entry->proc_fops = &input_fileops; - entry->proc_fops->poll = input_devices_poll; - entry = create_proc_read_entry("handlers", 0, proc_bus_input_dir, input_handlers_read, NULL); - if (entry == NULL) { - remove_proc_entry("devices", proc_bus_input_dir); - remove_proc_entry("input", proc_bus); - return -ENOMEM; - } - entry->owner = THIS_MODULE; return 0; -} -#else /* !CONFIG_PROC_FS */ -static inline int input_proc_init(void) { return 0; } -#endif -struct class *input_class; - -static int __init input_init(void) -{ - int retval = -ENOMEM; - - input_class = class_create(THIS_MODULE, "input"); - if (IS_ERR(input_class)) - return PTR_ERR(input_class); - input_proc_init(); - retval = register_chrdev(INPUT_MAJOR, "input", &input_fops); - if (retval) { - printk(KERN_ERR "input: unable to register char major %d", INPUT_MAJOR); - remove_proc_entry("devices", proc_bus_input_dir); - remove_proc_entry("handlers", proc_bus_input_dir); - remove_proc_entry("input", proc_bus); - class_destroy(input_class); - return retval; - } - - retval = devfs_mk_dir("input"); - if (retval) { - remove_proc_entry("devices", proc_bus_input_dir); - remove_proc_entry("handlers", proc_bus_input_dir); - remove_proc_entry("input", proc_bus); - unregister_chrdev(INPUT_MAJOR, "input"); - class_destroy(input_class); - } - return retval; + fail3: unregister_chrdev(INPUT_MAJOR, "input"); + fail2: input_proc_exit(); + fail1: class_destroy(input_class); + return err; } static void __exit input_exit(void) { - remove_proc_entry("devices", proc_bus_input_dir); - remove_proc_entry("handlers", proc_bus_input_dir); - remove_proc_entry("input", proc_bus); - + input_proc_exit(); devfs_remove("input"); unregister_chrdev(INPUT_MAJOR, "input"); class_destroy(input_class); diff --git a/drivers/input/joydev.c b/drivers/input/joydev.c index ff8e1bbd0e13..e0938d1d3ad7 100644 --- a/drivers/input/joydev.c +++ b/drivers/input/joydev.c @@ -37,8 +37,6 @@ MODULE_LICENSE("GPL"); #define JOYDEV_MINORS 16 #define JOYDEV_BUFFER_SIZE 64 -#define MSECS(t) (1000 * ((t) / HZ) + 1000 * ((t) % HZ) / HZ) - struct joydev { int exist; int open; @@ -117,7 +115,7 @@ static void joydev_event(struct input_handle *handle, unsigned int type, unsigne return; } - event.time = MSECS(jiffies); + event.time = jiffies_to_msecs(jiffies); list_for_each_entry(list, &joydev->list, node) { @@ -245,7 +243,7 @@ static ssize_t joydev_read(struct file *file, char __user *buf, size_t count, lo struct js_event event; - event.time = MSECS(jiffies); + event.time = jiffies_to_msecs(jiffies); if (list->startup < joydev->nkey) { event.type = JS_EVENT_BUTTON | JS_EVENT_INIT; diff --git a/drivers/input/joystick/a3d.c b/drivers/input/joystick/a3d.c index bf34f75b9467..bf65430181fa 100644 --- a/drivers/input/joystick/a3d.c +++ b/drivers/input/joystick/a3d.c @@ -269,7 +269,7 @@ static int a3d_connect(struct gameport *gameport, struct gameport_driver *drv) int i; int err; - if (!(a3d = kcalloc(1, sizeof(struct a3d), GFP_KERNEL))) + if (!(a3d = kzalloc(sizeof(struct a3d), GFP_KERNEL))) return -ENOMEM; a3d->gameport = gameport; diff --git a/drivers/input/joystick/adi.c b/drivers/input/joystick/adi.c index 265962956c63..cf35ae638a0d 100644 --- a/drivers/input/joystick/adi.c +++ b/drivers/input/joystick/adi.c @@ -469,7 +469,7 @@ static int adi_connect(struct gameport *gameport, struct gameport_driver *drv) int i; int err; - if (!(port = kcalloc(1, sizeof(struct adi_port), GFP_KERNEL))) + if (!(port = kzalloc(sizeof(struct adi_port), GFP_KERNEL))) return -ENOMEM; port->gameport = gameport; diff --git a/drivers/input/joystick/amijoy.c b/drivers/input/joystick/amijoy.c index 033456bb9fe0..e996183c5b06 100644 --- a/drivers/input/joystick/amijoy.c +++ b/drivers/input/joystick/amijoy.c @@ -105,7 +105,7 @@ out: static void amijoy_close(struct input_dev *dev) { - down(&amijoysem); + down(&amijoy_sem); if (!--amijoy_used) free_irq(IRQ_AMIGA_VERTB, amijoy_interrupt); up(&amijoy_sem); diff --git a/drivers/input/joystick/analog.c b/drivers/input/joystick/analog.c index c3a5739030c3..64b1313a3c66 100644 --- a/drivers/input/joystick/analog.c +++ b/drivers/input/joystick/analog.c @@ -655,7 +655,7 @@ static int analog_connect(struct gameport *gameport, struct gameport_driver *drv int i; int err; - if (!(port = kcalloc(1, sizeof(struct analog_port), GFP_KERNEL))) + if (!(port = kzalloc(sizeof(struct analog_port), GFP_KERNEL))) return - ENOMEM; err = analog_init_port(gameport, drv, port); diff --git a/drivers/input/joystick/cobra.c b/drivers/input/joystick/cobra.c index a6002205328f..0b2e9fa26579 100644 --- a/drivers/input/joystick/cobra.c +++ b/drivers/input/joystick/cobra.c @@ -163,7 +163,7 @@ static int cobra_connect(struct gameport *gameport, struct gameport_driver *drv) int i, j; int err; - if (!(cobra = kcalloc(1, sizeof(struct cobra), GFP_KERNEL))) + if (!(cobra = kzalloc(sizeof(struct cobra), GFP_KERNEL))) return -ENOMEM; cobra->gameport = gameport; diff --git a/drivers/input/joystick/db9.c b/drivers/input/joystick/db9.c index fbd3eed07f90..2a3e4bb2da50 100644 --- a/drivers/input/joystick/db9.c +++ b/drivers/input/joystick/db9.c @@ -572,7 +572,7 @@ static struct db9 __init *db9_probe(int *config, int nargs) } } - if (!(db9 = kcalloc(1, sizeof(struct db9), GFP_KERNEL))) { + if (!(db9 = kzalloc(sizeof(struct db9), GFP_KERNEL))) { parport_put_port(pp); return NULL; } diff --git a/drivers/input/joystick/gamecon.c b/drivers/input/joystick/gamecon.c index 95bbdd302aad..5427bf9fc862 100644 --- a/drivers/input/joystick/gamecon.c +++ b/drivers/input/joystick/gamecon.c @@ -554,7 +554,7 @@ static struct gc __init *gc_probe(int *config, int nargs) return NULL; } - if (!(gc = kcalloc(1, sizeof(struct gc), GFP_KERNEL))) { + if (!(gc = kzalloc(sizeof(struct gc), GFP_KERNEL))) { parport_put_port(pp); return NULL; } diff --git a/drivers/input/joystick/gf2k.c b/drivers/input/joystick/gf2k.c index 7d969420066c..8e4f92b115e6 100644 --- a/drivers/input/joystick/gf2k.c +++ b/drivers/input/joystick/gf2k.c @@ -242,7 +242,7 @@ static int gf2k_connect(struct gameport *gameport, struct gameport_driver *drv) unsigned char data[GF2K_LENGTH]; int i, err; - if (!(gf2k = kcalloc(1, sizeof(struct gf2k), GFP_KERNEL))) + if (!(gf2k = kzalloc(sizeof(struct gf2k), GFP_KERNEL))) return -ENOMEM; gf2k->gameport = gameport; diff --git a/drivers/input/joystick/grip.c b/drivers/input/joystick/grip.c index d1500d2562d6..9d3f910dd568 100644 --- a/drivers/input/joystick/grip.c +++ b/drivers/input/joystick/grip.c @@ -301,7 +301,7 @@ static int grip_connect(struct gameport *gameport, struct gameport_driver *drv) int i, j, t; int err; - if (!(grip = kcalloc(1, sizeof(struct grip), GFP_KERNEL))) + if (!(grip = kzalloc(sizeof(struct grip), GFP_KERNEL))) return -ENOMEM; grip->gameport = gameport; diff --git a/drivers/input/joystick/grip_mp.c b/drivers/input/joystick/grip_mp.c index 0da7bd133ccf..da17eee6f574 100644 --- a/drivers/input/joystick/grip_mp.c +++ b/drivers/input/joystick/grip_mp.c @@ -607,7 +607,7 @@ static int grip_connect(struct gameport *gameport, struct gameport_driver *drv) struct grip_mp *grip; int err; - if (!(grip = kcalloc(1, sizeof(struct grip_mp), GFP_KERNEL))) + if (!(grip = kzalloc(sizeof(struct grip_mp), GFP_KERNEL))) return -ENOMEM; grip->gameport = gameport; diff --git a/drivers/input/joystick/guillemot.c b/drivers/input/joystick/guillemot.c index f93da7bc082d..6a70ec429f06 100644 --- a/drivers/input/joystick/guillemot.c +++ b/drivers/input/joystick/guillemot.c @@ -183,7 +183,7 @@ static int guillemot_connect(struct gameport *gameport, struct gameport_driver * int i, t; int err; - if (!(guillemot = kcalloc(1, sizeof(struct guillemot), GFP_KERNEL))) + if (!(guillemot = kzalloc(sizeof(struct guillemot), GFP_KERNEL))) return -ENOMEM; guillemot->gameport = gameport; diff --git a/drivers/input/joystick/iforce/iforce-packets.c b/drivers/input/joystick/iforce/iforce-packets.c index 58728ebaaf80..e5a31e55d3e2 100644 --- a/drivers/input/joystick/iforce/iforce-packets.c +++ b/drivers/input/joystick/iforce/iforce-packets.c @@ -249,9 +249,6 @@ void iforce_process_packet(struct iforce *iforce, u16 cmd, unsigned char *data, int iforce_get_id_packet(struct iforce *iforce, char *packet) { - DECLARE_WAITQUEUE(wait, current); - int timeout = HZ; /* 1 second */ - switch (iforce->bus) { case IFORCE_USB: @@ -260,22 +257,13 @@ int iforce_get_id_packet(struct iforce *iforce, char *packet) iforce->cr.bRequest = packet[0]; iforce->ctrl->dev = iforce->usbdev; - set_current_state(TASK_INTERRUPTIBLE); - add_wait_queue(&iforce->wait, &wait); - - if (usb_submit_urb(iforce->ctrl, GFP_ATOMIC)) { - set_current_state(TASK_RUNNING); - remove_wait_queue(&iforce->wait, &wait); + if (usb_submit_urb(iforce->ctrl, GFP_ATOMIC)) return -1; - } - while (timeout && iforce->ctrl->status == -EINPROGRESS) - timeout = schedule_timeout(timeout); + wait_event_interruptible_timeout(iforce->wait, + iforce->ctrl->status != -EINPROGRESS, HZ); - set_current_state(TASK_RUNNING); - remove_wait_queue(&iforce->wait, &wait); - - if (!timeout) { + if (iforce->ctrl->status != -EINPROGRESS) { usb_unlink_urb(iforce->ctrl); return -1; } @@ -290,16 +278,10 @@ int iforce_get_id_packet(struct iforce *iforce, char *packet) iforce->expect_packet = FF_CMD_QUERY; iforce_send_packet(iforce, FF_CMD_QUERY, packet); - set_current_state(TASK_INTERRUPTIBLE); - add_wait_queue(&iforce->wait, &wait); - - while (timeout && iforce->expect_packet) - timeout = schedule_timeout(timeout); - - set_current_state(TASK_RUNNING); - remove_wait_queue(&iforce->wait, &wait); + wait_event_interruptible_timeout(iforce->wait, + !iforce->expect_packet, HZ); - if (!timeout) { + if (iforce->expect_packet) { iforce->expect_packet = 0; return -1; } diff --git a/drivers/input/joystick/iforce/iforce-usb.c b/drivers/input/joystick/iforce/iforce-usb.c index 6369a24684fe..58600f91eff5 100644 --- a/drivers/input/joystick/iforce/iforce-usb.c +++ b/drivers/input/joystick/iforce/iforce-usb.c @@ -95,6 +95,7 @@ static void iforce_usb_irq(struct urb *urb, struct pt_regs *regs) goto exit; } + wake_up(&iforce->wait); iforce_process_packet(iforce, (iforce->data[0] << 8) | (urb->actual_length - 1), iforce->data + 1, regs); diff --git a/drivers/input/joystick/interact.c b/drivers/input/joystick/interact.c index 9d3f8c38cb09..d7b3472bd686 100644 --- a/drivers/input/joystick/interact.c +++ b/drivers/input/joystick/interact.c @@ -212,7 +212,7 @@ static int interact_connect(struct gameport *gameport, struct gameport_driver *d int i, t; int err; - if (!(interact = kcalloc(1, sizeof(struct interact), GFP_KERNEL))) + if (!(interact = kzalloc(sizeof(struct interact), GFP_KERNEL))) return -ENOMEM; interact->gameport = gameport; diff --git a/drivers/input/joystick/sidewinder.c b/drivers/input/joystick/sidewinder.c index 47144a7ed9e7..9e0353721a35 100644 --- a/drivers/input/joystick/sidewinder.c +++ b/drivers/input/joystick/sidewinder.c @@ -590,7 +590,7 @@ static int sw_connect(struct gameport *gameport, struct gameport_driver *drv) comment[0] = 0; - sw = kcalloc(1, sizeof(struct sw), GFP_KERNEL); + sw = kzalloc(sizeof(struct sw), GFP_KERNEL); buf = kmalloc(SW_LENGTH, GFP_KERNEL); idbuf = kmalloc(SW_LENGTH, GFP_KERNEL); if (!sw || !buf || !idbuf) { diff --git a/drivers/input/joystick/tmdc.c b/drivers/input/joystick/tmdc.c index 9eb9954cac6e..7431efc4330e 100644 --- a/drivers/input/joystick/tmdc.c +++ b/drivers/input/joystick/tmdc.c @@ -262,7 +262,7 @@ static int tmdc_connect(struct gameport *gameport, struct gameport_driver *drv) int i, j, k, l, m; int err; - if (!(tmdc = kcalloc(1, sizeof(struct tmdc), GFP_KERNEL))) + if (!(tmdc = kzalloc(sizeof(struct tmdc), GFP_KERNEL))) return -ENOMEM; tmdc->gameport = gameport; diff --git a/drivers/input/joystick/turbografx.c b/drivers/input/joystick/turbografx.c index 28100d461cb7..0c5b9c8297cd 100644 --- a/drivers/input/joystick/turbografx.c +++ b/drivers/input/joystick/turbografx.c @@ -178,7 +178,7 @@ static struct tgfx __init *tgfx_probe(int *config, int nargs) return NULL; } - if (!(tgfx = kcalloc(1, sizeof(struct tgfx), GFP_KERNEL))) { + if (!(tgfx = kzalloc(sizeof(struct tgfx), GFP_KERNEL))) { parport_put_port(pp); return NULL; } diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig index e55dee390775..444f7756fee6 100644 --- a/drivers/input/keyboard/Kconfig +++ b/drivers/input/keyboard/Kconfig @@ -132,6 +132,17 @@ config KEYBOARD_CORGI To compile this driver as a module, choose M here: the module will be called corgikbd. +config KEYBOARD_SPITZ + tristate "Spitz keyboard" + depends on PXA_SHARPSL + default y + help + Say Y here to enable the keyboard on the Sharp Zaurus SL-C1000, + SL-C3000 and Sl-C3100 series of PDAs. + + To compile this driver as a module, choose M here: the + module will be called spitzkbd. + config KEYBOARD_MAPLE tristate "Maple bus keyboard" depends on SH_DREAMCAST && MAPLE diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile index b02eeceea3c3..9ce0b87f2fac 100644 --- a/drivers/input/keyboard/Makefile +++ b/drivers/input/keyboard/Makefile @@ -14,6 +14,7 @@ obj-$(CONFIG_KEYBOARD_LOCOMO) += locomokbd.o obj-$(CONFIG_KEYBOARD_NEWTON) += newtonkbd.o obj-$(CONFIG_KEYBOARD_98KBD) += 98kbd.o obj-$(CONFIG_KEYBOARD_CORGI) += corgikbd.o +obj-$(CONFIG_KEYBOARD_SPITZ) += spitzkbd.o obj-$(CONFIG_KEYBOARD_HIL) += hil_kbd.o obj-$(CONFIG_KEYBOARD_HIL_OLD) += hilkbd.o diff --git a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c index 4d4985b59abf..1ad8c2ee7dbf 100644 --- a/drivers/input/keyboard/atkbd.c +++ b/drivers/input/keyboard/atkbd.c @@ -208,6 +208,7 @@ struct atkbd { unsigned char resend; unsigned char release; unsigned char bat_xl; + unsigned char err_xl; unsigned int last; unsigned long time; }; @@ -296,15 +297,18 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data, if (atkbd->emul || !(code == ATKBD_RET_EMUL0 || code == ATKBD_RET_EMUL1 || code == ATKBD_RET_HANGUEL || code == ATKBD_RET_HANJA || - code == ATKBD_RET_ERR || + (code == ATKBD_RET_ERR && !atkbd->err_xl) || (code == ATKBD_RET_BAT && !atkbd->bat_xl))) { atkbd->release = code >> 7; code &= 0x7f; } - if (!atkbd->emul && - (code & 0x7f) == (ATKBD_RET_BAT & 0x7f)) + if (!atkbd->emul) { + if ((code & 0x7f) == (ATKBD_RET_BAT & 0x7f)) atkbd->bat_xl = !atkbd->release; + if ((code & 0x7f) == (ATKBD_RET_ERR & 0x7f)) + atkbd->err_xl = !atkbd->release; + } } switch (code) { diff --git a/drivers/input/keyboard/corgikbd.c b/drivers/input/keyboard/corgikbd.c index a8551711e8d6..cd4b6e795013 100644 --- a/drivers/input/keyboard/corgikbd.c +++ b/drivers/input/keyboard/corgikbd.c @@ -16,6 +16,7 @@ #include <linux/init.h> #include <linux/input.h> #include <linux/interrupt.h> +#include <linux/jiffies.h> #include <linux/module.h> #include <linux/slab.h> #include <asm/irq.h> @@ -32,7 +33,6 @@ /* zero code, 124 scancodes + 3 hinge combinations */ #define NR_SCANCODES ( SCANCODE(KB_ROWS-1,KB_COLS-1) +1 +1 +3 ) #define SCAN_INTERVAL (HZ/10) -#define CORGIKBD_PRESSED 1 #define HINGE_SCAN_INTERVAL (HZ/4) @@ -73,25 +73,13 @@ struct corgikbd { struct input_dev input; char phys[32]; - unsigned char state[ARRAY_SIZE(corgikbd_keycode)]; spinlock_t lock; - struct timer_list timer; struct timer_list htimer; -}; -static void handle_scancode(unsigned int pressed,unsigned int scancode, struct corgikbd *corgikbd_data) -{ - if (pressed && !(corgikbd_data->state[scancode] & CORGIKBD_PRESSED)) { - corgikbd_data->state[scancode] |= CORGIKBD_PRESSED; - input_report_key(&corgikbd_data->input, corgikbd_data->keycode[scancode], 1); - if (corgikbd_data->keycode[scancode] == CORGI_KEY_OFF) - input_event(&corgikbd_data->input, EV_PWR, CORGI_KEY_OFF, 1); - } else if (!pressed && corgikbd_data->state[scancode] & CORGIKBD_PRESSED) { - corgikbd_data->state[scancode] &= ~CORGIKBD_PRESSED; - input_report_key(&corgikbd_data->input, corgikbd_data->keycode[scancode], 0); - } -} + unsigned int suspended; + unsigned long suspend_jiffies; +}; #define KB_DISCHARGE_DELAY 10 #define KB_ACTIVATE_DELAY 10 @@ -105,36 +93,36 @@ static void handle_scancode(unsigned int pressed,unsigned int scancode, struct c */ static inline void corgikbd_discharge_all(void) { - // STROBE All HiZ + /* STROBE All HiZ */ GPCR2 = CORGI_GPIO_ALL_STROBE_BIT; GPDR2 &= ~CORGI_GPIO_ALL_STROBE_BIT; } static inline void corgikbd_activate_all(void) { - // STROBE ALL -> High + /* STROBE ALL -> High */ GPSR2 = CORGI_GPIO_ALL_STROBE_BIT; GPDR2 |= CORGI_GPIO_ALL_STROBE_BIT; udelay(KB_DISCHARGE_DELAY); - // Clear any interrupts we may have triggered when altering the GPIO lines + /* Clear any interrupts we may have triggered when altering the GPIO lines */ GEDR1 = CORGI_GPIO_HIGH_SENSE_BIT; GEDR2 = CORGI_GPIO_LOW_SENSE_BIT; } static inline void corgikbd_activate_col(int col) { - // STROBE col -> High, not col -> HiZ + /* STROBE col -> High, not col -> HiZ */ GPSR2 = CORGI_GPIO_STROBE_BIT(col); GPDR2 = (GPDR2 & ~CORGI_GPIO_ALL_STROBE_BIT) | CORGI_GPIO_STROBE_BIT(col); } static inline void corgikbd_reset_col(int col) { - // STROBE col -> Low + /* STROBE col -> Low */ GPCR2 = CORGI_GPIO_STROBE_BIT(col); - // STROBE col -> out, not col -> HiZ + /* STROBE col -> out, not col -> HiZ */ GPDR2 = (GPDR2 & ~CORGI_GPIO_ALL_STROBE_BIT) | CORGI_GPIO_STROBE_BIT(col); } @@ -149,10 +137,13 @@ static inline void corgikbd_reset_col(int col) /* Scan the hardware keyboard and push any changes up through the input layer */ static void corgikbd_scankeyboard(struct corgikbd *corgikbd_data, struct pt_regs *regs) { - unsigned int row, col, rowd, scancode; + unsigned int row, col, rowd; unsigned long flags; unsigned int num_pressed; + if (corgikbd_data->suspended) + return; + spin_lock_irqsave(&corgikbd_data->lock, flags); if (regs) @@ -173,10 +164,21 @@ static void corgikbd_scankeyboard(struct corgikbd *corgikbd_data, struct pt_regs rowd = GET_ROWS_STATUS(col); for (row = 0; row < KB_ROWS; row++) { + unsigned int scancode, pressed; + scancode = SCANCODE(row, col); - handle_scancode((rowd & KB_ROWMASK(row)), scancode, corgikbd_data); - if (rowd & KB_ROWMASK(row)) + pressed = rowd & KB_ROWMASK(row); + + input_report_key(&corgikbd_data->input, corgikbd_data->keycode[scancode], pressed); + + if (pressed) num_pressed++; + + if (pressed && (corgikbd_data->keycode[scancode] == CORGI_KEY_OFF) + && time_after(jiffies, corgikbd_data->suspend_jiffies + HZ)) { + input_event(&corgikbd_data->input, EV_PWR, CORGI_KEY_OFF, 1); + corgikbd_data->suspend_jiffies=jiffies; + } } corgikbd_reset_col(col); } @@ -221,8 +223,11 @@ static void corgikbd_timer_callback(unsigned long data) * The hinge switches generate no interrupt so they need to be * monitored by a timer. * - * When we detect changes, we debounce it and then pass the three - * positions the system can take as keypresses to the input system. + * We debounce the switches and pass them to the input system. + * + * gprr == 0x00 - Keyboard with Landscape Screen + * 0x08 - No Keyboard with Portrait Screen + * 0x0c - Keyboard and Screen Closed */ #define HINGE_STABLE_COUNT 2 @@ -235,7 +240,7 @@ static void corgikbd_hinge_timer(unsigned long data) unsigned long gprr; unsigned long flags; - gprr = read_scoop_reg(SCOOP_GPRR) & (CORGI_SCP_SWA | CORGI_SCP_SWB); + gprr = read_scoop_reg(&corgiscoop_device.dev, SCOOP_GPRR) & (CORGI_SCP_SWA | CORGI_SCP_SWB); if (gprr != sharpsl_hinge_state) { hinge_count = 0; sharpsl_hinge_state = gprr; @@ -244,9 +249,8 @@ static void corgikbd_hinge_timer(unsigned long data) if (hinge_count >= HINGE_STABLE_COUNT) { spin_lock_irqsave(&corgikbd_data->lock, flags); - handle_scancode((sharpsl_hinge_state == 0x00), 125, corgikbd_data); /* Keyboard with Landscape Screen */ - handle_scancode((sharpsl_hinge_state == 0x08), 126, corgikbd_data); /* No Keyboard with Portrait Screen */ - handle_scancode((sharpsl_hinge_state == 0x0c), 127, corgikbd_data); /* Keyboard and Screen Closed */ + input_report_switch(&corgikbd_data->input, SW_0, ((sharpsl_hinge_state & CORGI_SCP_SWA) != 0)); + input_report_switch(&corgikbd_data->input, SW_1, ((sharpsl_hinge_state & CORGI_SCP_SWB) != 0)); input_sync(&corgikbd_data->input); spin_unlock_irqrestore(&corgikbd_data->lock, flags); @@ -255,19 +259,45 @@ static void corgikbd_hinge_timer(unsigned long data) mod_timer(&corgikbd_data->htimer, jiffies + HINGE_SCAN_INTERVAL); } +#ifdef CONFIG_PM +static int corgikbd_suspend(struct device *dev, pm_message_t state, uint32_t level) +{ + if (level == SUSPEND_POWER_DOWN) { + struct corgikbd *corgikbd = dev_get_drvdata(dev); + corgikbd->suspended = 1; + } + return 0; +} + +static int corgikbd_resume(struct device *dev, uint32_t level) +{ + if (level == RESUME_POWER_ON) { + struct corgikbd *corgikbd = dev_get_drvdata(dev); + + /* Upon resume, ignore the suspend key for a short while */ + corgikbd->suspend_jiffies=jiffies; + corgikbd->suspended = 0; + } + return 0; +} +#else +#define corgikbd_suspend NULL +#define corgikbd_resume NULL +#endif + static int __init corgikbd_probe(struct device *dev) { int i; struct corgikbd *corgikbd; - corgikbd = kcalloc(1, sizeof(struct corgikbd), GFP_KERNEL); + corgikbd = kzalloc(sizeof(struct corgikbd), GFP_KERNEL); if (!corgikbd) return -ENOMEM; dev_set_drvdata(dev,corgikbd); strcpy(corgikbd->phys, "corgikbd/input0"); - spin_lock_init(corgikbd->lock); + spin_lock_init(&corgikbd->lock); /* Init Keyboard rescan timer */ init_timer(&corgikbd->timer); @@ -279,6 +309,8 @@ static int __init corgikbd_probe(struct device *dev) corgikbd->htimer.function = corgikbd_hinge_timer; corgikbd->htimer.data = (unsigned long) corgikbd; + corgikbd->suspend_jiffies=jiffies; + init_input_dev(&corgikbd->input); corgikbd->input.private = corgikbd; corgikbd->input.name = "Corgi Keyboard"; @@ -288,7 +320,7 @@ static int __init corgikbd_probe(struct device *dev) corgikbd->input.id.vendor = 0x0001; corgikbd->input.id.product = 0x0001; corgikbd->input.id.version = 0x0100; - corgikbd->input.evbit[0] = BIT(EV_KEY) | BIT(EV_REP) | BIT(EV_PWR); + corgikbd->input.evbit[0] = BIT(EV_KEY) | BIT(EV_REP) | BIT(EV_PWR) | BIT(EV_SW); corgikbd->input.keycode = corgikbd->keycode; corgikbd->input.keycodesize = sizeof(unsigned char); corgikbd->input.keycodemax = ARRAY_SIZE(corgikbd_keycode); @@ -297,6 +329,8 @@ static int __init corgikbd_probe(struct device *dev) for (i = 0; i < ARRAY_SIZE(corgikbd_keycode); i++) set_bit(corgikbd->keycode[i], corgikbd->input.keybit); clear_bit(0, corgikbd->input.keybit); + set_bit(SW_0, corgikbd->input.swbit); + set_bit(SW_1, corgikbd->input.swbit); input_register_device(&corgikbd->input); mod_timer(&corgikbd->htimer, jiffies + HINGE_SCAN_INTERVAL); @@ -343,6 +377,8 @@ static struct device_driver corgikbd_driver = { .bus = &platform_bus_type, .probe = corgikbd_probe, .remove = corgikbd_remove, + .suspend = corgikbd_suspend, + .resume = corgikbd_resume, }; static int __devinit corgikbd_init(void) diff --git a/drivers/input/keyboard/spitzkbd.c b/drivers/input/keyboard/spitzkbd.c new file mode 100644 index 000000000000..1714045a182b --- /dev/null +++ b/drivers/input/keyboard/spitzkbd.c @@ -0,0 +1,478 @@ +/* + * Keyboard driver for Sharp Spitz, Borzoi and Akita (SL-Cxx00 series) + * + * Copyright (c) 2005 Richard Purdie + * + * Based on corgikbd.c + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#include <linux/delay.h> +#include <linux/device.h> +#include <linux/init.h> +#include <linux/input.h> +#include <linux/interrupt.h> +#include <linux/jiffies.h> +#include <linux/module.h> +#include <linux/slab.h> +#include <asm/irq.h> + +#include <asm/arch/spitz.h> +#include <asm/arch/hardware.h> +#include <asm/arch/pxa-regs.h> + +#define KB_ROWS 7 +#define KB_COLS 11 +#define KB_ROWMASK(r) (1 << (r)) +#define SCANCODE(r,c) (((r)<<4) + (c) + 1) +#define NR_SCANCODES ((KB_ROWS<<4) + 1) + +#define HINGE_SCAN_INTERVAL (150) /* ms */ + +#define SPITZ_KEY_CALENDER KEY_F1 +#define SPITZ_KEY_ADDRESS KEY_F2 +#define SPITZ_KEY_FN KEY_F3 +#define SPITZ_KEY_CANCEL KEY_F4 +#define SPITZ_KEY_EXOK KEY_F5 +#define SPITZ_KEY_EXCANCEL KEY_F6 +#define SPITZ_KEY_EXJOGDOWN KEY_F7 +#define SPITZ_KEY_EXJOGUP KEY_F8 +#define SPITZ_KEY_JAP1 KEY_LEFTALT +#define SPITZ_KEY_JAP2 KEY_RIGHTCTRL +#define SPITZ_KEY_SYNC KEY_F9 +#define SPITZ_KEY_MAIL KEY_F10 +#define SPITZ_KEY_OK KEY_F11 +#define SPITZ_KEY_MENU KEY_F12 + +static unsigned char spitzkbd_keycode[NR_SCANCODES] = { + 0, /* 0 */ + KEY_LEFTCTRL, KEY_1, KEY_3, KEY_5, KEY_6, KEY_7, KEY_9, KEY_0, KEY_BACKSPACE, SPITZ_KEY_EXOK, SPITZ_KEY_EXCANCEL, 0, 0, 0, 0, 0, /* 1-16 */ + 0, KEY_2, KEY_4, KEY_R, KEY_Y, KEY_8, KEY_I, KEY_O, KEY_P, SPITZ_KEY_EXJOGDOWN, SPITZ_KEY_EXJOGUP, 0, 0, 0, 0, 0, /* 17-32 */ + KEY_TAB, KEY_Q, KEY_E, KEY_T, KEY_G, KEY_U, KEY_J, KEY_K, 0, 0, 0, 0, 0, 0, 0, 0, /* 33-48 */ + SPITZ_KEY_CALENDER, KEY_W, KEY_S, KEY_F, KEY_V, KEY_H, KEY_M, KEY_L, 0, 0, KEY_RIGHTSHIFT, 0, 0, 0, 0, 0, /* 49-64 */ + SPITZ_KEY_ADDRESS, KEY_A, KEY_D, KEY_C, KEY_B, KEY_N, KEY_DOT, 0, KEY_ENTER, KEY_LEFTSHIFT, 0, 0, 0, 0, 0, 0, /* 65-80 */ + SPITZ_KEY_MAIL, KEY_Z, KEY_X, KEY_MINUS, KEY_SPACE, KEY_COMMA, 0, KEY_UP, 0, 0, SPITZ_KEY_FN, 0, 0, 0, 0, 0, /* 81-96 */ + KEY_SYSRQ, SPITZ_KEY_JAP1, SPITZ_KEY_JAP2, SPITZ_KEY_CANCEL, SPITZ_KEY_OK, SPITZ_KEY_MENU, KEY_LEFT, KEY_DOWN, KEY_RIGHT, 0, 0, 0, 0, 0, 0, 0 /* 97-112 */ +}; + +static int spitz_strobes[] = { + SPITZ_GPIO_KEY_STROBE0, + SPITZ_GPIO_KEY_STROBE1, + SPITZ_GPIO_KEY_STROBE2, + SPITZ_GPIO_KEY_STROBE3, + SPITZ_GPIO_KEY_STROBE4, + SPITZ_GPIO_KEY_STROBE5, + SPITZ_GPIO_KEY_STROBE6, + SPITZ_GPIO_KEY_STROBE7, + SPITZ_GPIO_KEY_STROBE8, + SPITZ_GPIO_KEY_STROBE9, + SPITZ_GPIO_KEY_STROBE10, +}; + +static int spitz_senses[] = { + SPITZ_GPIO_KEY_SENSE0, + SPITZ_GPIO_KEY_SENSE1, + SPITZ_GPIO_KEY_SENSE2, + SPITZ_GPIO_KEY_SENSE3, + SPITZ_GPIO_KEY_SENSE4, + SPITZ_GPIO_KEY_SENSE5, + SPITZ_GPIO_KEY_SENSE6, +}; + +struct spitzkbd { + unsigned char keycode[ARRAY_SIZE(spitzkbd_keycode)]; + struct input_dev input; + char phys[32]; + + spinlock_t lock; + struct timer_list timer; + struct timer_list htimer; + + unsigned int suspended; + unsigned long suspend_jiffies; +}; + +#define KB_DISCHARGE_DELAY 10 +#define KB_ACTIVATE_DELAY 10 + +/* Helper functions for reading the keyboard matrix + * Note: We should really be using pxa_gpio_mode to alter GPDR but it + * requires a function call per GPIO bit which is excessive + * when we need to access 11 bits at once, multiple times. + * These functions must be called within local_irq_save()/local_irq_restore() + * or similar. + */ +static inline void spitzkbd_discharge_all(void) +{ + /* STROBE All HiZ */ + GPCR0 = SPITZ_GPIO_G0_STROBE_BIT; + GPDR0 &= ~SPITZ_GPIO_G0_STROBE_BIT; + GPCR1 = SPITZ_GPIO_G1_STROBE_BIT; + GPDR1 &= ~SPITZ_GPIO_G1_STROBE_BIT; + GPCR2 = SPITZ_GPIO_G2_STROBE_BIT; + GPDR2 &= ~SPITZ_GPIO_G2_STROBE_BIT; + GPCR3 = SPITZ_GPIO_G3_STROBE_BIT; + GPDR3 &= ~SPITZ_GPIO_G3_STROBE_BIT; +} + +static inline void spitzkbd_activate_all(void) +{ + /* STROBE ALL -> High */ + GPSR0 = SPITZ_GPIO_G0_STROBE_BIT; + GPDR0 |= SPITZ_GPIO_G0_STROBE_BIT; + GPSR1 = SPITZ_GPIO_G1_STROBE_BIT; + GPDR1 |= SPITZ_GPIO_G1_STROBE_BIT; + GPSR2 = SPITZ_GPIO_G2_STROBE_BIT; + GPDR2 |= SPITZ_GPIO_G2_STROBE_BIT; + GPSR3 = SPITZ_GPIO_G3_STROBE_BIT; + GPDR3 |= SPITZ_GPIO_G3_STROBE_BIT; + + udelay(KB_DISCHARGE_DELAY); + + /* Clear any interrupts we may have triggered when altering the GPIO lines */ + GEDR0 = SPITZ_GPIO_G0_SENSE_BIT; + GEDR1 = SPITZ_GPIO_G1_SENSE_BIT; + GEDR2 = SPITZ_GPIO_G2_SENSE_BIT; + GEDR3 = SPITZ_GPIO_G3_SENSE_BIT; +} + +static inline void spitzkbd_activate_col(int col) +{ + int gpio = spitz_strobes[col]; + GPDR0 &= ~SPITZ_GPIO_G0_STROBE_BIT; + GPDR1 &= ~SPITZ_GPIO_G1_STROBE_BIT; + GPDR2 &= ~SPITZ_GPIO_G2_STROBE_BIT; + GPDR3 &= ~SPITZ_GPIO_G3_STROBE_BIT; + GPSR(gpio) = GPIO_bit(gpio); + GPDR(gpio) |= GPIO_bit(gpio); +} + +static inline void spitzkbd_reset_col(int col) +{ + int gpio = spitz_strobes[col]; + GPDR0 &= ~SPITZ_GPIO_G0_STROBE_BIT; + GPDR1 &= ~SPITZ_GPIO_G1_STROBE_BIT; + GPDR2 &= ~SPITZ_GPIO_G2_STROBE_BIT; + GPDR3 &= ~SPITZ_GPIO_G3_STROBE_BIT; + GPCR(gpio) = GPIO_bit(gpio); + GPDR(gpio) |= GPIO_bit(gpio); +} + +static inline int spitzkbd_get_row_status(int col) +{ + return ((GPLR0 >> 12) & 0x01) | ((GPLR0 >> 16) & 0x02) + | ((GPLR2 >> 25) & 0x04) | ((GPLR1 << 1) & 0x08) + | ((GPLR1 >> 0) & 0x10) | ((GPLR1 >> 1) & 0x60); +} + +/* + * The spitz keyboard only generates interrupts when a key is pressed. + * When a key is pressed, we enable a timer which then scans the + * keyboard to detect when the key is released. + */ + +/* Scan the hardware keyboard and push any changes up through the input layer */ +static void spitzkbd_scankeyboard(struct spitzkbd *spitzkbd_data, struct pt_regs *regs) +{ + unsigned int row, col, rowd; + unsigned long flags; + unsigned int num_pressed, pwrkey = ((GPLR(SPITZ_GPIO_ON_KEY) & GPIO_bit(SPITZ_GPIO_ON_KEY)) != 0); + + if (spitzkbd_data->suspended) + return; + + spin_lock_irqsave(&spitzkbd_data->lock, flags); + + if (regs) + input_regs(&spitzkbd_data->input, regs); + + num_pressed = 0; + for (col = 0; col < KB_COLS; col++) { + /* + * Discharge the output driver capacitatance + * in the keyboard matrix. (Yes it is significant..) + */ + + spitzkbd_discharge_all(); + udelay(KB_DISCHARGE_DELAY); + + spitzkbd_activate_col(col); + udelay(KB_ACTIVATE_DELAY); + + rowd = spitzkbd_get_row_status(col); + for (row = 0; row < KB_ROWS; row++) { + unsigned int scancode, pressed; + + scancode = SCANCODE(row, col); + pressed = rowd & KB_ROWMASK(row); + + input_report_key(&spitzkbd_data->input, spitzkbd_data->keycode[scancode], pressed); + + if (pressed) + num_pressed++; + } + spitzkbd_reset_col(col); + } + + spitzkbd_activate_all(); + + input_report_key(&spitzkbd_data->input, SPITZ_KEY_SYNC, (GPLR(SPITZ_GPIO_SYNC) & GPIO_bit(SPITZ_GPIO_SYNC)) != 0 ); + input_report_key(&spitzkbd_data->input, KEY_SUSPEND, pwrkey); + + if (pwrkey && time_after(jiffies, spitzkbd_data->suspend_jiffies + msecs_to_jiffies(1000))) { + input_event(&spitzkbd_data->input, EV_PWR, KEY_SUSPEND, 1); + spitzkbd_data->suspend_jiffies = jiffies; + } + + input_sync(&spitzkbd_data->input); + + /* if any keys are pressed, enable the timer */ + if (num_pressed) + mod_timer(&spitzkbd_data->timer, jiffies + msecs_to_jiffies(100)); + + spin_unlock_irqrestore(&spitzkbd_data->lock, flags); +} + +/* + * spitz keyboard interrupt handler. + */ +static irqreturn_t spitzkbd_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct spitzkbd *spitzkbd_data = dev_id; + + if (!timer_pending(&spitzkbd_data->timer)) { + /** wait chattering delay **/ + udelay(20); + spitzkbd_scankeyboard(spitzkbd_data, regs); + } + + return IRQ_HANDLED; +} + +/* + * spitz timer checking for released keys + */ +static void spitzkbd_timer_callback(unsigned long data) +{ + struct spitzkbd *spitzkbd_data = (struct spitzkbd *) data; + spitzkbd_scankeyboard(spitzkbd_data, NULL); +} + +/* + * The hinge switches generate an interrupt. + * We debounce the switches and pass them to the input system. + */ + +static irqreturn_t spitzkbd_hinge_isr(int irq, void *dev_id, struct pt_regs *regs) +{ + struct spitzkbd *spitzkbd_data = dev_id; + + if (!timer_pending(&spitzkbd_data->htimer)) + mod_timer(&spitzkbd_data->htimer, jiffies + msecs_to_jiffies(HINGE_SCAN_INTERVAL)); + + return IRQ_HANDLED; +} + +#define HINGE_STABLE_COUNT 2 +static int sharpsl_hinge_state; +static int hinge_count; + +static void spitzkbd_hinge_timer(unsigned long data) +{ + struct spitzkbd *spitzkbd_data = (struct spitzkbd *) data; + unsigned long state; + unsigned long flags; + + state = GPLR(SPITZ_GPIO_SWA) & (GPIO_bit(SPITZ_GPIO_SWA)|GPIO_bit(SPITZ_GPIO_SWB)); + if (state != sharpsl_hinge_state) { + hinge_count = 0; + sharpsl_hinge_state = state; + } else if (hinge_count < HINGE_STABLE_COUNT) { + hinge_count++; + } + + if (hinge_count >= HINGE_STABLE_COUNT) { + spin_lock_irqsave(&spitzkbd_data->lock, flags); + + input_report_switch(&spitzkbd_data->input, SW_0, ((GPLR(SPITZ_GPIO_SWA) & GPIO_bit(SPITZ_GPIO_SWA)) != 0)); + input_report_switch(&spitzkbd_data->input, SW_1, ((GPLR(SPITZ_GPIO_SWB) & GPIO_bit(SPITZ_GPIO_SWB)) != 0)); + input_sync(&spitzkbd_data->input); + + spin_unlock_irqrestore(&spitzkbd_data->lock, flags); + } else { + mod_timer(&spitzkbd_data->htimer, jiffies + msecs_to_jiffies(HINGE_SCAN_INTERVAL)); + } +} + +#ifdef CONFIG_PM +static int spitzkbd_suspend(struct device *dev, pm_message_t state, uint32_t level) +{ + if (level == SUSPEND_POWER_DOWN) { + int i; + struct spitzkbd *spitzkbd = dev_get_drvdata(dev); + spitzkbd->suspended = 1; + + /* Set Strobe lines as inputs - *except* strobe line 0 leave this + enabled so we can detect a power button press for resume */ + for (i = 1; i < SPITZ_KEY_STROBE_NUM; i++) + pxa_gpio_mode(spitz_strobes[i] | GPIO_IN); + } + return 0; +} + +static int spitzkbd_resume(struct device *dev, uint32_t level) +{ + if (level == RESUME_POWER_ON) { + int i; + struct spitzkbd *spitzkbd = dev_get_drvdata(dev); + + for (i = 0; i < SPITZ_KEY_STROBE_NUM; i++) + pxa_gpio_mode(spitz_strobes[i] | GPIO_OUT | GPIO_DFLT_HIGH); + + /* Upon resume, ignore the suspend key for a short while */ + spitzkbd->suspend_jiffies = jiffies; + spitzkbd->suspended = 0; + } + return 0; +} +#else +#define spitzkbd_suspend NULL +#define spitzkbd_resume NULL +#endif + +static int __init spitzkbd_probe(struct device *dev) +{ + int i; + struct spitzkbd *spitzkbd; + + spitzkbd = kzalloc(sizeof(struct spitzkbd), GFP_KERNEL); + if (!spitzkbd) + return -ENOMEM; + + dev_set_drvdata(dev,spitzkbd); + strcpy(spitzkbd->phys, "spitzkbd/input0"); + + spin_lock_init(&spitzkbd->lock); + + /* Init Keyboard rescan timer */ + init_timer(&spitzkbd->timer); + spitzkbd->timer.function = spitzkbd_timer_callback; + spitzkbd->timer.data = (unsigned long) spitzkbd; + + /* Init Hinge Timer */ + init_timer(&spitzkbd->htimer); + spitzkbd->htimer.function = spitzkbd_hinge_timer; + spitzkbd->htimer.data = (unsigned long) spitzkbd; + + spitzkbd->suspend_jiffies=jiffies; + + init_input_dev(&spitzkbd->input); + spitzkbd->input.private = spitzkbd; + spitzkbd->input.name = "Spitz Keyboard"; + spitzkbd->input.dev = dev; + spitzkbd->input.phys = spitzkbd->phys; + spitzkbd->input.id.bustype = BUS_HOST; + spitzkbd->input.id.vendor = 0x0001; + spitzkbd->input.id.product = 0x0001; + spitzkbd->input.id.version = 0x0100; + spitzkbd->input.evbit[0] = BIT(EV_KEY) | BIT(EV_REP) | BIT(EV_PWR) | BIT(EV_SW); + spitzkbd->input.keycode = spitzkbd->keycode; + spitzkbd->input.keycodesize = sizeof(unsigned char); + spitzkbd->input.keycodemax = ARRAY_SIZE(spitzkbd_keycode); + + memcpy(spitzkbd->keycode, spitzkbd_keycode, sizeof(spitzkbd->keycode)); + for (i = 0; i < ARRAY_SIZE(spitzkbd_keycode); i++) + set_bit(spitzkbd->keycode[i], spitzkbd->input.keybit); + clear_bit(0, spitzkbd->input.keybit); + set_bit(SW_0, spitzkbd->input.swbit); + set_bit(SW_1, spitzkbd->input.swbit); + + input_register_device(&spitzkbd->input); + mod_timer(&spitzkbd->htimer, jiffies + msecs_to_jiffies(HINGE_SCAN_INTERVAL)); + + /* Setup sense interrupts - RisingEdge Detect, sense lines as inputs */ + for (i = 0; i < SPITZ_KEY_SENSE_NUM; i++) { + pxa_gpio_mode(spitz_senses[i] | GPIO_IN); + if (request_irq(IRQ_GPIO(spitz_senses[i]), spitzkbd_interrupt, + SA_INTERRUPT, "Spitzkbd Sense", spitzkbd)) + printk(KERN_WARNING "spitzkbd: Can't get Sense IRQ: %d!\n", i); + else + set_irq_type(IRQ_GPIO(spitz_senses[i]),IRQT_RISING); + } + + /* Set Strobe lines as outputs - set high */ + for (i = 0; i < SPITZ_KEY_STROBE_NUM; i++) + pxa_gpio_mode(spitz_strobes[i] | GPIO_OUT | GPIO_DFLT_HIGH); + + pxa_gpio_mode(SPITZ_GPIO_SYNC | GPIO_IN); + pxa_gpio_mode(SPITZ_GPIO_ON_KEY | GPIO_IN); + pxa_gpio_mode(SPITZ_GPIO_SWA | GPIO_IN); + pxa_gpio_mode(SPITZ_GPIO_SWB | GPIO_IN); + + request_irq(SPITZ_IRQ_GPIO_SYNC, spitzkbd_interrupt, SA_INTERRUPT, "Spitzkbd Sync", spitzkbd); + request_irq(SPITZ_IRQ_GPIO_ON_KEY, spitzkbd_interrupt, SA_INTERRUPT, "Spitzkbd PwrOn", spitzkbd); + request_irq(SPITZ_IRQ_GPIO_SWA, spitzkbd_hinge_isr, SA_INTERRUPT, "Spitzkbd SWA", spitzkbd); + request_irq(SPITZ_IRQ_GPIO_SWB, spitzkbd_hinge_isr, SA_INTERRUPT, "Spitzkbd SWB", spitzkbd); + + set_irq_type(SPITZ_IRQ_GPIO_SYNC, IRQT_BOTHEDGE); + set_irq_type(SPITZ_IRQ_GPIO_ON_KEY, IRQT_BOTHEDGE); + set_irq_type(SPITZ_IRQ_GPIO_SWA, IRQT_BOTHEDGE); + set_irq_type(SPITZ_IRQ_GPIO_SWB, IRQT_BOTHEDGE); + + printk(KERN_INFO "input: Spitz Keyboard Registered\n"); + + return 0; +} + +static int spitzkbd_remove(struct device *dev) +{ + int i; + struct spitzkbd *spitzkbd = dev_get_drvdata(dev); + + for (i = 0; i < SPITZ_KEY_SENSE_NUM; i++) + free_irq(IRQ_GPIO(spitz_senses[i]), spitzkbd); + + free_irq(SPITZ_IRQ_GPIO_SYNC, spitzkbd); + free_irq(SPITZ_IRQ_GPIO_ON_KEY, spitzkbd); + free_irq(SPITZ_IRQ_GPIO_SWA, spitzkbd); + free_irq(SPITZ_IRQ_GPIO_SWB, spitzkbd); + + del_timer_sync(&spitzkbd->htimer); + del_timer_sync(&spitzkbd->timer); + + input_unregister_device(&spitzkbd->input); + + kfree(spitzkbd); + + return 0; +} + +static struct device_driver spitzkbd_driver = { + .name = "spitz-keyboard", + .bus = &platform_bus_type, + .probe = spitzkbd_probe, + .remove = spitzkbd_remove, + .suspend = spitzkbd_suspend, + .resume = spitzkbd_resume, +}; + +static int __devinit spitzkbd_init(void) +{ + return driver_register(&spitzkbd_driver); +} + +static void __exit spitzkbd_exit(void) +{ + driver_unregister(&spitzkbd_driver); +} + +module_init(spitzkbd_init); +module_exit(spitzkbd_exit); + +MODULE_AUTHOR("Richard Purdie <rpurdie@rpsys.net>"); +MODULE_DESCRIPTION("Spitz Keyboard Driver"); +MODULE_LICENSE("GPLv2"); diff --git a/drivers/input/keyboard/sunkbd.c b/drivers/input/keyboard/sunkbd.c index 596964ceb96d..4bae5d89348d 100644 --- a/drivers/input/keyboard/sunkbd.c +++ b/drivers/input/keyboard/sunkbd.c @@ -44,7 +44,7 @@ MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); static unsigned char sunkbd_keycode[128] = { - 0,128,114,129,115, 59, 60, 68, 61, 87, 62, 88, 63,100, 64, 0, + 0,128,114,129,115, 59, 60, 68, 61, 87, 62, 88, 63,100, 64,112, 65, 66, 67, 56,103,119, 99, 70,105,130,131,108,106, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 41, 14,110,113, 98, 55, 116,132, 83,133,102, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, diff --git a/drivers/input/misc/uinput.c b/drivers/input/misc/uinput.c index 98710997aaaa..d5c5b32045af 100644 --- a/drivers/input/misc/uinput.c +++ b/drivers/input/misc/uinput.c @@ -36,16 +36,6 @@ #include <linux/miscdevice.h> #include <linux/uinput.h> -static int uinput_dev_open(struct input_dev *dev) -{ - return 0; -} - -static void uinput_dev_close(struct input_dev *dev) -{ - -} - static int uinput_dev_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) { struct uinput_device *udev; @@ -63,22 +53,24 @@ static int uinput_dev_event(struct input_dev *dev, unsigned int type, unsigned i return 0; } -static int uinput_request_alloc_id(struct input_dev *dev, struct uinput_request *request) +static int uinput_request_alloc_id(struct uinput_device *udev, struct uinput_request *request) { /* Atomically allocate an ID for the given request. Returns 0 on success. */ - struct uinput_device *udev = dev->private; int id; + int err = -1; + + spin_lock(&udev->requests_lock); - down(&udev->requests_sem); - for (id=0; id<UINPUT_NUM_REQUESTS; id++) + for (id = 0; id < UINPUT_NUM_REQUESTS; id++) if (!udev->requests[id]) { - udev->requests[id] = request; request->id = id; - up(&udev->requests_sem); - return 0; + udev->requests[id] = request; + err = 0; + break; } - up(&udev->requests_sem); - return -1; + + spin_unlock(&udev->requests_lock); + return err; } static struct uinput_request* uinput_request_find(struct uinput_device *udev, int id) @@ -86,70 +78,78 @@ static struct uinput_request* uinput_request_find(struct uinput_device *udev, in /* Find an input request, by ID. Returns NULL if the ID isn't valid. */ if (id >= UINPUT_NUM_REQUESTS || id < 0) return NULL; - if (udev->requests[id]->completed) - return NULL; return udev->requests[id]; } -static void uinput_request_init(struct input_dev *dev, struct uinput_request *request, int code) +static inline int uinput_request_reserve_slot(struct uinput_device *udev, struct uinput_request *request) { - struct uinput_device *udev = dev->private; + /* Allocate slot. If none are available right away, wait. */ + return wait_event_interruptible(udev->requests_waitq, + !uinput_request_alloc_id(udev, request)); +} - memset(request, 0, sizeof(struct uinput_request)); - request->code = code; - init_waitqueue_head(&request->waitq); +static void uinput_request_done(struct uinput_device *udev, struct uinput_request *request) +{ + complete(&request->done); - /* Allocate an ID. If none are available right away, wait. */ - request->retval = wait_event_interruptible(udev->requests_waitq, - !uinput_request_alloc_id(dev, request)); + /* Mark slot as available */ + udev->requests[request->id] = NULL; + wake_up_interruptible(&udev->requests_waitq); } -static void uinput_request_submit(struct input_dev *dev, struct uinput_request *request) +static int uinput_request_submit(struct input_dev *dev, struct uinput_request *request) { - struct uinput_device *udev = dev->private; int retval; /* Tell our userspace app about this new request by queueing an input event */ uinput_dev_event(dev, EV_UINPUT, request->code, request->id); /* Wait for the request to complete */ - retval = wait_event_interruptible(request->waitq, request->completed); - if (retval) - request->retval = retval; + retval = wait_for_completion_interruptible(&request->done); + if (!retval) + retval = request->retval; - /* Release this request's ID, let others know it's available */ - udev->requests[request->id] = NULL; - wake_up_interruptible(&udev->requests_waitq); + return retval; } static int uinput_dev_upload_effect(struct input_dev *dev, struct ff_effect *effect) { struct uinput_request request; + int retval; if (!test_bit(EV_FF, dev->evbit)) return -ENOSYS; - uinput_request_init(dev, &request, UI_FF_UPLOAD); - if (request.retval) - return request.retval; + request.id = -1; + init_completion(&request.done); + request.code = UI_FF_UPLOAD; request.u.effect = effect; - uinput_request_submit(dev, &request); - return request.retval; + + retval = uinput_request_reserve_slot(dev->private, &request); + if (!retval) + retval = uinput_request_submit(dev, &request); + + return retval; } static int uinput_dev_erase_effect(struct input_dev *dev, int effect_id) { struct uinput_request request; + int retval; if (!test_bit(EV_FF, dev->evbit)) return -ENOSYS; - uinput_request_init(dev, &request, UI_FF_ERASE); - if (request.retval) - return request.retval; + request.id = -1; + init_completion(&request.done); + request.code = UI_FF_ERASE; request.u.effect_id = effect_id; - uinput_request_submit(dev, &request); - return request.retval; + + retval = uinput_request_reserve_slot(dev->private, &request); + if (!retval) + retval = uinput_request_submit(dev, &request); + + return retval; } static int uinput_create_device(struct uinput_device *udev) @@ -159,32 +159,30 @@ static int uinput_create_device(struct uinput_device *udev) return -EINVAL; } - udev->dev->open = uinput_dev_open; - udev->dev->close = uinput_dev_close; udev->dev->event = uinput_dev_event; udev->dev->upload_effect = uinput_dev_upload_effect; udev->dev->erase_effect = uinput_dev_erase_effect; udev->dev->private = udev; - init_waitqueue_head(&(udev->waitq)); + init_waitqueue_head(&udev->waitq); input_register_device(udev->dev); - set_bit(UIST_CREATED, &(udev->state)); + set_bit(UIST_CREATED, &udev->state); return 0; } static int uinput_destroy_device(struct uinput_device *udev) { - if (!test_bit(UIST_CREATED, &(udev->state))) { + if (!test_bit(UIST_CREATED, &udev->state)) { printk(KERN_WARNING "%s: create the device first\n", UINPUT_NAME); return -EINVAL; } input_unregister_device(udev->dev); - clear_bit(UIST_CREATED, &(udev->state)); + clear_bit(UIST_CREATED, &udev->state); return 0; } @@ -198,7 +196,7 @@ static int uinput_open(struct inode *inode, struct file *file) if (!newdev) goto error; memset(newdev, 0, sizeof(struct uinput_device)); - init_MUTEX(&newdev->requests_sem); + spin_lock_init(&newdev->requests_lock); init_waitqueue_head(&newdev->requests_waitq); newinput = kmalloc(sizeof(struct input_dev), GFP_KERNEL); @@ -253,15 +251,16 @@ static int uinput_alloc_device(struct file *file, const char __user *buffer, siz struct uinput_user_dev *user_dev; struct input_dev *dev; struct uinput_device *udev; - int size, - retval; + char *name; + int size; + int retval; retval = count; udev = file->private_data; dev = udev->dev; - user_dev = kmalloc(sizeof(*user_dev), GFP_KERNEL); + user_dev = kmalloc(sizeof(struct uinput_user_dev), GFP_KERNEL); if (!user_dev) { retval = -ENOMEM; goto exit; @@ -272,17 +271,17 @@ static int uinput_alloc_device(struct file *file, const char __user *buffer, siz goto exit; } - if (NULL != dev->name) + if (dev->name) kfree(dev->name); size = strnlen(user_dev->name, UINPUT_MAX_NAME_SIZE) + 1; - dev->name = kmalloc(size, GFP_KERNEL); - if (!dev->name) { + dev->name = name = kmalloc(size, GFP_KERNEL); + if (!name) { retval = -ENOMEM; goto exit; } + strlcpy(name, user_dev->name, size); - strlcpy(dev->name, user_dev->name, size); dev->id.bustype = user_dev->id.bustype; dev->id.vendor = user_dev->id.vendor; dev->id.product = user_dev->id.product; @@ -314,14 +313,13 @@ static ssize_t uinput_write(struct file *file, const char __user *buffer, size_t { struct uinput_device *udev = file->private_data; - if (test_bit(UIST_CREATED, &(udev->state))) { + if (test_bit(UIST_CREATED, &udev->state)) { struct input_event ev; if (copy_from_user(&ev, buffer, sizeof(struct input_event))) return -EFAULT; input_event(udev->dev, ev.type, ev.code, ev.value); - } - else + } else count = uinput_alloc_device(file, buffer, count); return count; @@ -332,26 +330,24 @@ static ssize_t uinput_read(struct file *file, char __user *buffer, size_t count, struct uinput_device *udev = file->private_data; int retval = 0; - if (!test_bit(UIST_CREATED, &(udev->state))) + if (!test_bit(UIST_CREATED, &udev->state)) return -ENODEV; - if ((udev->head == udev->tail) && (file->f_flags & O_NONBLOCK)) + if (udev->head == udev->tail && (file->f_flags & O_NONBLOCK)) return -EAGAIN; retval = wait_event_interruptible(udev->waitq, - (udev->head != udev->tail) || - !test_bit(UIST_CREATED, &(udev->state))); - + udev->head != udev->tail || !test_bit(UIST_CREATED, &udev->state)); if (retval) return retval; - if (!test_bit(UIST_CREATED, &(udev->state))) + if (!test_bit(UIST_CREATED, &udev->state)) return -ENODEV; while ((udev->head != udev->tail) && (retval + sizeof(struct input_event) <= count)) { - if (copy_to_user(buffer + retval, &(udev->buff[udev->tail]), - sizeof(struct input_event))) return -EFAULT; + if (copy_to_user(buffer + retval, &udev->buff[udev->tail], sizeof(struct input_event))) + return -EFAULT; udev->tail = (udev->tail + 1) % UINPUT_BUFFER_SIZE; retval += sizeof(struct input_event); } @@ -373,12 +369,12 @@ static unsigned int uinput_poll(struct file *file, poll_table *wait) static int uinput_burn_device(struct uinput_device *udev) { - if (test_bit(UIST_CREATED, &(udev->state))) + if (test_bit(UIST_CREATED, &udev->state)) uinput_destroy_device(udev); - if (NULL != udev->dev->name) + if (udev->dev->name) kfree(udev->dev->name); - if (NULL != udev->dev->phys) + if (udev->dev->phys) kfree(udev->dev->phys); kfree(udev->dev); @@ -389,7 +385,8 @@ static int uinput_burn_device(struct uinput_device *udev) static int uinput_close(struct inode *inode, struct file *file) { - return uinput_burn_device(file->private_data); + uinput_burn_device(file->private_data); + return 0; } static int uinput_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) @@ -401,6 +398,7 @@ static int uinput_ioctl(struct inode *inode, struct file *file, unsigned int cmd struct uinput_ff_erase ff_erase; struct uinput_request *req; int length; + char *phys; udev = file->private_data; @@ -415,7 +413,7 @@ static int uinput_ioctl(struct inode *inode, struct file *file, unsigned int cmd case UI_SET_SNDBIT: case UI_SET_FFBIT: case UI_SET_PHYS: - if (test_bit(UIST_CREATED, &(udev->state))) + if (test_bit(UIST_CREATED, &udev->state)) return -EINVAL; } @@ -498,20 +496,19 @@ static int uinput_ioctl(struct inode *inode, struct file *file, unsigned int cmd retval = -EFAULT; break; } - if (NULL != udev->dev->phys) - kfree(udev->dev->phys); - udev->dev->phys = kmalloc(length, GFP_KERNEL); - if (!udev->dev->phys) { + kfree(udev->dev->phys); + udev->dev->phys = phys = kmalloc(length, GFP_KERNEL); + if (!phys) { retval = -ENOMEM; break; } - if (copy_from_user(udev->dev->phys, p, length)) { - retval = -EFAULT; - kfree(udev->dev->phys); + if (copy_from_user(phys, p, length)) { udev->dev->phys = NULL; + kfree(phys); + retval = -EFAULT; break; } - udev->dev->phys[length-1] = '\0'; + phys[length - 1] = '\0'; break; case UI_BEGIN_FF_UPLOAD: @@ -520,7 +517,7 @@ static int uinput_ioctl(struct inode *inode, struct file *file, unsigned int cmd break; } req = uinput_request_find(udev, ff_up.request_id); - if (!(req && req->code==UI_FF_UPLOAD && req->u.effect)) { + if (!(req && req->code == UI_FF_UPLOAD && req->u.effect)) { retval = -EINVAL; break; } @@ -538,7 +535,7 @@ static int uinput_ioctl(struct inode *inode, struct file *file, unsigned int cmd break; } req = uinput_request_find(udev, ff_erase.request_id); - if (!(req && req->code==UI_FF_ERASE)) { + if (!(req && req->code == UI_FF_ERASE)) { retval = -EINVAL; break; } @@ -556,14 +553,13 @@ static int uinput_ioctl(struct inode *inode, struct file *file, unsigned int cmd break; } req = uinput_request_find(udev, ff_up.request_id); - if (!(req && req->code==UI_FF_UPLOAD && req->u.effect)) { + if (!(req && req->code == UI_FF_UPLOAD && req->u.effect)) { retval = -EINVAL; break; } req->retval = ff_up.retval; memcpy(req->u.effect, &ff_up.effect, sizeof(struct ff_effect)); - req->completed = 1; - wake_up_interruptible(&req->waitq); + uinput_request_done(udev, req); break; case UI_END_FF_ERASE: @@ -572,13 +568,12 @@ static int uinput_ioctl(struct inode *inode, struct file *file, unsigned int cmd break; } req = uinput_request_find(udev, ff_erase.request_id); - if (!(req && req->code==UI_FF_ERASE)) { + if (!(req && req->code == UI_FF_ERASE)) { retval = -EINVAL; break; } req->retval = ff_erase.retval; - req->completed = 1; - wake_up_interruptible(&req->waitq); + uinput_request_done(udev, req); break; default: diff --git a/drivers/input/mouse/Makefile b/drivers/input/mouse/Makefile index c4909b49337d..82b330bbf068 100644 --- a/drivers/input/mouse/Makefile +++ b/drivers/input/mouse/Makefile @@ -15,4 +15,4 @@ obj-$(CONFIG_MOUSE_SERIAL) += sermouse.o obj-$(CONFIG_MOUSE_HIL) += hil_ptr.o obj-$(CONFIG_MOUSE_VSXXXAA) += vsxxxaa.o -psmouse-objs := psmouse-base.o alps.o logips2pp.o synaptics.o lifebook.o +psmouse-objs := psmouse-base.o alps.o logips2pp.o synaptics.o lifebook.o trackpoint.o diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c index a12e98158a75..b20783f9748a 100644 --- a/drivers/input/mouse/alps.c +++ b/drivers/input/mouse/alps.c @@ -2,7 +2,7 @@ * ALPS touchpad PS/2 mouse driver * * Copyright (c) 2003 Neil Brown <neilb@cse.unsw.edu.au> - * Copyright (c) 2003 Peter Osterlund <petero2@telia.com> + * Copyright (c) 2003-2005 Peter Osterlund <petero2@telia.com> * Copyright (c) 2004 Dmitry Torokhov <dtor@mail.ru> * Copyright (c) 2005 Vojtech Pavlik <vojtech@suse.cz> * @@ -170,7 +170,7 @@ static void alps_process_packet(struct psmouse *psmouse, struct pt_regs *regs) input_report_key(dev, BTN_TOOL_FINGER, z > 0); if (priv->i->flags & ALPS_WHEEL) - input_report_rel(dev, REL_WHEEL, ((packet[0] >> 4) & 0x07) | ((packet[2] >> 2) & 0x08)); + input_report_rel(dev, REL_WHEEL, ((packet[2] << 1) & 0x08) - ((packet[0] >> 4) & 0x07)); if (priv->i->flags & (ALPS_FW_BK_1 | ALPS_FW_BK_2)) { input_report_key(dev, BTN_FORWARD, forward); @@ -350,7 +350,6 @@ static int alps_tap_mode(struct psmouse *psmouse, int enable) static int alps_reconnect(struct psmouse *psmouse) { struct alps_data *priv = psmouse->private; - unsigned char param[4]; int version; psmouse_reset(psmouse); @@ -358,21 +357,20 @@ static int alps_reconnect(struct psmouse *psmouse) if (!(priv->i = alps_get_model(psmouse, &version))) return -1; - if (priv->i->flags & ALPS_PASS && alps_passthrough_mode(psmouse, 1)) + if ((priv->i->flags & ALPS_PASS) && alps_passthrough_mode(psmouse, 1)) return -1; - if (alps_get_status(psmouse, param)) + if (alps_tap_mode(psmouse, 1)) { + printk(KERN_WARNING "alps.c: Failed to reenable hardware tapping\n"); return -1; - - if (!(param[0] & 0x04)) - alps_tap_mode(psmouse, 1); + } if (alps_absolute_mode(psmouse)) { - printk(KERN_ERR "alps.c: Failed to enable absolute mode\n"); + printk(KERN_ERR "alps.c: Failed to reenable absolute mode\n"); return -1; } - if (priv->i->flags == ALPS_PASS && alps_passthrough_mode(psmouse, 0)) + if ((priv->i->flags & ALPS_PASS) && alps_passthrough_mode(psmouse, 0)) return -1; return 0; @@ -389,7 +387,6 @@ static void alps_disconnect(struct psmouse *psmouse) int alps_init(struct psmouse *psmouse) { struct alps_data *priv; - unsigned char param[4]; int version; psmouse->private = priv = kmalloc(sizeof(struct alps_data), GFP_KERNEL); @@ -403,16 +400,8 @@ int alps_init(struct psmouse *psmouse) if ((priv->i->flags & ALPS_PASS) && alps_passthrough_mode(psmouse, 1)) goto init_fail; - if (alps_get_status(psmouse, param)) { - printk(KERN_ERR "alps.c: touchpad status report request failed\n"); - goto init_fail; - } - - if (param[0] & 0x04) { - printk(KERN_INFO "alps.c: Enabling hardware tapping\n"); - if (alps_tap_mode(psmouse, 1)) - printk(KERN_WARNING "alps.c: Failed to enable hardware tapping\n"); - } + if (alps_tap_mode(psmouse, 1)) + printk(KERN_WARNING "alps.c: Failed to enable hardware tapping\n"); if (alps_absolute_mode(psmouse)) { printk(KERN_ERR "alps.c: Failed to enable absolute mode\n"); diff --git a/drivers/input/mouse/logips2pp.c b/drivers/input/mouse/logips2pp.c index 5ab1bd7d529d..7df96525222e 100644 --- a/drivers/input/mouse/logips2pp.c +++ b/drivers/input/mouse/logips2pp.c @@ -150,12 +150,12 @@ static void ps2pp_set_smartscroll(struct psmouse *psmouse, unsigned int smartscr ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES); } -static ssize_t psmouse_attr_show_smartscroll(struct psmouse *psmouse, char *buf) +static ssize_t ps2pp_attr_show_smartscroll(struct psmouse *psmouse, void *data, char *buf) { return sprintf(buf, "%d\n", psmouse->smartscroll ? 1 : 0); } -static ssize_t psmouse_attr_set_smartscroll(struct psmouse *psmouse, const char *buf, size_t count) +static ssize_t ps2pp_attr_set_smartscroll(struct psmouse *psmouse, void *data, const char *buf, size_t count) { unsigned long value; char *rest; @@ -169,7 +169,8 @@ static ssize_t psmouse_attr_set_smartscroll(struct psmouse *psmouse, const char return count; } -PSMOUSE_DEFINE_ATTR(smartscroll); +PSMOUSE_DEFINE_ATTR(smartscroll, S_IWUSR | S_IRUGO, NULL, + ps2pp_attr_show_smartscroll, ps2pp_attr_set_smartscroll); /* * Support 800 dpi resolution _only_ if the user wants it (there are good @@ -194,7 +195,7 @@ static void ps2pp_set_resolution(struct psmouse *psmouse, unsigned int resolutio static void ps2pp_disconnect(struct psmouse *psmouse) { - device_remove_file(&psmouse->ps2dev.serio->dev, &psmouse_attr_smartscroll); + device_remove_file(&psmouse->ps2dev.serio->dev, &psmouse_attr_smartscroll.dattr); } static struct ps2pp_info *get_model_info(unsigned char model) @@ -222,6 +223,7 @@ 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 }, + { 86, PS2PP_KIND_WHEEL, PS2PP_WHEEL }, { 88, PS2PP_KIND_WHEEL, PS2PP_WHEEL }, { 96, 0, 0 }, { 97, PS2PP_KIND_TP3, PS2PP_WHEEL | PS2PP_HWHEEL }, @@ -379,14 +381,13 @@ int ps2pp_init(struct psmouse *psmouse, int set_properties) psmouse->set_resolution = ps2pp_set_resolution; psmouse->disconnect = ps2pp_disconnect; - device_create_file(&psmouse->ps2dev.serio->dev, &psmouse_attr_smartscroll); + device_create_file(&psmouse->ps2dev.serio->dev, + &psmouse_attr_smartscroll.dattr); } } if (buttons < 3) clear_bit(BTN_MIDDLE, psmouse->dev.keybit); - if (buttons < 2) - clear_bit(BTN_RIGHT, psmouse->dev.keybit); if (model_info) ps2pp_set_model_properties(psmouse, model_info, use_ps2pp); diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c index 19785a6c5abd..af24313ff5bb 100644 --- a/drivers/input/mouse/psmouse-base.c +++ b/drivers/input/mouse/psmouse-base.c @@ -25,6 +25,7 @@ #include "logips2pp.h" #include "alps.h" #include "lifebook.h" +#include "trackpoint.h" #define DRIVER_DESC "PS/2 mouse driver" @@ -57,10 +58,30 @@ static unsigned int psmouse_resetafter; module_param_named(resetafter, psmouse_resetafter, uint, 0644); MODULE_PARM_DESC(resetafter, "Reset device after so many bad packets (0 = never)."); -PSMOUSE_DEFINE_ATTR(protocol); -PSMOUSE_DEFINE_ATTR(rate); -PSMOUSE_DEFINE_ATTR(resolution); -PSMOUSE_DEFINE_ATTR(resetafter); +PSMOUSE_DEFINE_ATTR(protocol, S_IWUSR | S_IRUGO, + NULL, + psmouse_attr_show_protocol, psmouse_attr_set_protocol); +PSMOUSE_DEFINE_ATTR(rate, S_IWUSR | S_IRUGO, + (void *) offsetof(struct psmouse, rate), + psmouse_show_int_attr, psmouse_attr_set_rate); +PSMOUSE_DEFINE_ATTR(resolution, S_IWUSR | S_IRUGO, + (void *) offsetof(struct psmouse, resolution), + psmouse_show_int_attr, psmouse_attr_set_resolution); +PSMOUSE_DEFINE_ATTR(resetafter, S_IWUSR | S_IRUGO, + (void *) offsetof(struct psmouse, resetafter), + psmouse_show_int_attr, psmouse_set_int_attr); + +static struct attribute *psmouse_attributes[] = { + &psmouse_attr_protocol.dattr.attr, + &psmouse_attr_rate.dattr.attr, + &psmouse_attr_resolution.dattr.attr, + &psmouse_attr_resetafter.dattr.attr, + NULL +}; + +static struct attribute_group psmouse_attribute_group = { + .attrs = psmouse_attributes, +}; __obsolete_setup("psmouse_noext"); __obsolete_setup("psmouse_resolution="); @@ -344,6 +365,7 @@ static int intellimouse_detect(struct psmouse *psmouse, int set_properties) return -1; if (set_properties) { + set_bit(BTN_MIDDLE, psmouse->dev.keybit); set_bit(REL_WHEEL, psmouse->dev.relbit); if (!psmouse->vendor) psmouse->vendor = "Generic"; @@ -376,6 +398,7 @@ static int im_explorer_detect(struct psmouse *psmouse, int set_properties) return -1; if (set_properties) { + set_bit(BTN_MIDDLE, psmouse->dev.keybit); set_bit(REL_WHEEL, psmouse->dev.relbit); set_bit(BTN_SIDE, psmouse->dev.keybit); set_bit(BTN_EXTRA, psmouse->dev.keybit); @@ -518,6 +541,12 @@ 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. */ @@ -598,6 +627,12 @@ static struct psmouse_protocol psmouse_protocols[] = { .init = lifebook_init, }, { + .type = PSMOUSE_TRACKPOINT, + .name = "TPPS/2", + .alias = "trackpoint", + .detect = trackpoint_detect, + }, + { .type = PSMOUSE_AUTO, .name = "auto", .alias = "any", @@ -785,10 +820,7 @@ static void psmouse_disconnect(struct serio *serio) psmouse = serio_get_drvdata(serio); - device_remove_file(&serio->dev, &psmouse_attr_protocol); - device_remove_file(&serio->dev, &psmouse_attr_rate); - device_remove_file(&serio->dev, &psmouse_attr_resolution); - device_remove_file(&serio->dev, &psmouse_attr_resetafter); + sysfs_remove_group(&serio->dev.kobj, &psmouse_attribute_group); down(&psmouse_sem); @@ -881,7 +913,7 @@ static int psmouse_connect(struct serio *serio, struct serio_driver *drv) psmouse_deactivate(parent); } - if (!(psmouse = kcalloc(1, sizeof(struct psmouse), GFP_KERNEL))) { + if (!(psmouse = kzalloc(sizeof(struct psmouse), GFP_KERNEL))) { retval = -ENOMEM; goto out; } @@ -925,10 +957,7 @@ static int psmouse_connect(struct serio *serio, struct serio_driver *drv) if (parent && parent->pt_activate) parent->pt_activate(parent); - device_create_file(&serio->dev, &psmouse_attr_protocol); - device_create_file(&serio->dev, &psmouse_attr_rate); - device_create_file(&serio->dev, &psmouse_attr_resolution); - device_create_file(&serio->dev, &psmouse_attr_resetafter); + sysfs_create_group(&serio->dev.kobj, &psmouse_attribute_group); psmouse_activate(psmouse); @@ -1025,10 +1054,12 @@ static struct serio_driver psmouse_drv = { .cleanup = psmouse_cleanup, }; -ssize_t psmouse_attr_show_helper(struct device *dev, char *buf, - ssize_t (*handler)(struct psmouse *, char *)) +ssize_t psmouse_attr_show_helper(struct device *dev, struct device_attribute *devattr, + char *buf) { struct serio *serio = to_serio_port(dev); + struct psmouse_attribute *attr = to_psmouse_attr(devattr); + struct psmouse *psmouse; int retval; retval = serio_pin_driver(serio); @@ -1040,19 +1071,21 @@ ssize_t psmouse_attr_show_helper(struct device *dev, char *buf, goto out; } - retval = handler(serio_get_drvdata(serio), buf); + psmouse = serio_get_drvdata(serio); + + retval = attr->show(psmouse, attr->data, buf); out: serio_unpin_driver(serio); return retval; } -ssize_t psmouse_attr_set_helper(struct device *dev, const char *buf, size_t count, - ssize_t (*handler)(struct psmouse *, const char *, size_t)) +ssize_t psmouse_attr_set_helper(struct device *dev, struct device_attribute *devattr, + const char *buf, size_t count) { struct serio *serio = to_serio_port(dev); - struct psmouse *psmouse = serio_get_drvdata(serio); - struct psmouse *parent = NULL; + struct psmouse_attribute *attr = to_psmouse_attr(devattr); + struct psmouse *psmouse, *parent = NULL; int retval; retval = serio_pin_driver(serio); @@ -1068,6 +1101,8 @@ ssize_t psmouse_attr_set_helper(struct device *dev, const char *buf, size_t coun if (retval) goto out_unpin; + psmouse = serio_get_drvdata(serio); + if (psmouse->state == PSMOUSE_IGNORE) { retval = -ENODEV; goto out_up; @@ -1080,7 +1115,7 @@ ssize_t psmouse_attr_set_helper(struct device *dev, const char *buf, size_t coun psmouse_deactivate(psmouse); - retval = handler(psmouse, buf, count); + retval = attr->set(psmouse, attr->data, buf, count); if (retval != -ENODEV) psmouse_activate(psmouse); @@ -1095,12 +1130,34 @@ ssize_t psmouse_attr_set_helper(struct device *dev, const char *buf, size_t coun return retval; } -static ssize_t psmouse_attr_show_protocol(struct psmouse *psmouse, char *buf) +static ssize_t psmouse_show_int_attr(struct psmouse *psmouse, void *offset, char *buf) +{ + unsigned long *field = (unsigned long *)((char *)psmouse + (size_t)offset); + + return sprintf(buf, "%lu\n", *field); +} + +static ssize_t psmouse_set_int_attr(struct psmouse *psmouse, void *offset, const char *buf, size_t count) +{ + unsigned long *field = (unsigned long *)((char *)psmouse + (size_t)offset); + unsigned long value; + char *rest; + + value = simple_strtoul(buf, &rest, 10); + if (*rest) + return -EINVAL; + + *field = value; + + return count; +} + +static ssize_t psmouse_attr_show_protocol(struct psmouse *psmouse, void *data, char *buf) { return sprintf(buf, "%s\n", psmouse_protocol_by_type(psmouse->type)->name); } -static ssize_t psmouse_attr_set_protocol(struct psmouse *psmouse, const char *buf, size_t count) +static ssize_t psmouse_attr_set_protocol(struct psmouse *psmouse, void *data, const char *buf, size_t count) { struct serio *serio = psmouse->ps2dev.serio; struct psmouse *parent = NULL; @@ -1164,12 +1221,7 @@ static ssize_t psmouse_attr_set_protocol(struct psmouse *psmouse, const char *bu return count; } -static ssize_t psmouse_attr_show_rate(struct psmouse *psmouse, char *buf) -{ - return sprintf(buf, "%d\n", psmouse->rate); -} - -static ssize_t psmouse_attr_set_rate(struct psmouse *psmouse, const char *buf, size_t count) +static ssize_t psmouse_attr_set_rate(struct psmouse *psmouse, void *data, const char *buf, size_t count) { unsigned long value; char *rest; @@ -1182,12 +1234,7 @@ static ssize_t psmouse_attr_set_rate(struct psmouse *psmouse, const char *buf, s return count; } -static ssize_t psmouse_attr_show_resolution(struct psmouse *psmouse, char *buf) -{ - return sprintf(buf, "%d\n", psmouse->resolution); -} - -static ssize_t psmouse_attr_set_resolution(struct psmouse *psmouse, const char *buf, size_t count) +static ssize_t psmouse_attr_set_resolution(struct psmouse *psmouse, void *data, const char *buf, size_t count) { unsigned long value; char *rest; @@ -1200,23 +1247,6 @@ static ssize_t psmouse_attr_set_resolution(struct psmouse *psmouse, const char * return count; } -static ssize_t psmouse_attr_show_resetafter(struct psmouse *psmouse, char *buf) -{ - return sprintf(buf, "%d\n", psmouse->resetafter); -} - -static ssize_t psmouse_attr_set_resetafter(struct psmouse *psmouse, const char *buf, size_t count) -{ - unsigned long value; - char *rest; - - value = simple_strtoul(buf, &rest, 10); - if (*rest) - return -EINVAL; - - psmouse->resetafter = value; - return count; -} static int psmouse_set_maxproto(const char *val, struct kernel_param *kp) { @@ -1232,7 +1262,7 @@ static int psmouse_set_maxproto(const char *val, struct kernel_param *kp) *((unsigned int *)kp->arg) = proto->type; - return 0; \ + return 0; } static int psmouse_get_maxproto(char *buffer, struct kernel_param *kp) diff --git a/drivers/input/mouse/psmouse.h b/drivers/input/mouse/psmouse.h index 86691cf43433..45d2bd774f00 100644 --- a/drivers/input/mouse/psmouse.h +++ b/drivers/input/mouse/psmouse.h @@ -78,6 +78,7 @@ enum psmouse_type { PSMOUSE_SYNAPTICS, PSMOUSE_ALPS, PSMOUSE_LIFEBOOK, + PSMOUSE_TRACKPOINT, PSMOUSE_AUTO /* This one should always be last */ }; @@ -85,24 +86,37 @@ int psmouse_sliced_command(struct psmouse *psmouse, unsigned char command); int psmouse_reset(struct psmouse *psmouse); void psmouse_set_resolution(struct psmouse *psmouse, unsigned int resolution); -ssize_t psmouse_attr_show_helper(struct device *dev, char *buf, - ssize_t (*handler)(struct psmouse *, char *)); -ssize_t psmouse_attr_set_helper(struct device *dev, const char *buf, size_t count, - ssize_t (*handler)(struct psmouse *, const char *, size_t)); - -#define PSMOUSE_DEFINE_ATTR(_name) \ -static ssize_t psmouse_attr_show_##_name(struct psmouse *, char *); \ -static ssize_t psmouse_attr_set_##_name(struct psmouse *, const char *, size_t);\ -static ssize_t psmouse_do_show_##_name(struct device *d, struct device_attribute *attr, char *b) \ -{ \ - return psmouse_attr_show_helper(d, b, psmouse_attr_show_##_name); \ -} \ -static ssize_t psmouse_do_set_##_name(struct device *d, struct device_attribute *attr, const char *b, size_t s)\ -{ \ - return psmouse_attr_set_helper(d, b, s, psmouse_attr_set_##_name); \ -} \ -static struct device_attribute psmouse_attr_##_name = \ - __ATTR(_name, S_IWUSR | S_IRUGO, \ - psmouse_do_show_##_name, psmouse_do_set_##_name); + +struct psmouse_attribute { + struct device_attribute dattr; + void *data; + ssize_t (*show)(struct psmouse *psmouse, void *data, char *buf); + ssize_t (*set)(struct psmouse *psmouse, void *data, + const char *buf, size_t count); +}; +#define to_psmouse_attr(a) container_of((a), struct psmouse_attribute, dattr) + +ssize_t psmouse_attr_show_helper(struct device *dev, struct device_attribute *attr, + char *buf); +ssize_t psmouse_attr_set_helper(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count); + +#define PSMOUSE_DEFINE_ATTR(_name, _mode, _data, _show, _set) \ +static ssize_t _show(struct psmouse *, void *data, char *); \ +static ssize_t _set(struct psmouse *, void *data, const char *, size_t); \ +static struct psmouse_attribute psmouse_attr_##_name = { \ + .dattr = { \ + .attr = { \ + .name = __stringify(_name), \ + .mode = _mode, \ + .owner = THIS_MODULE, \ + }, \ + .show = psmouse_attr_show_helper, \ + .store = psmouse_attr_set_helper, \ + }, \ + .data = _data, \ + .show = _show, \ + .set = _set, \ +} #endif /* _PSMOUSE_H */ diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c index 36c721227b68..029309422409 100644 --- a/drivers/input/mouse/synaptics.c +++ b/drivers/input/mouse/synaptics.c @@ -219,7 +219,7 @@ static void synaptics_pass_pt_packet(struct serio *ptport, unsigned char *packet serio_interrupt(ptport, packet[1], 0, NULL); serio_interrupt(ptport, packet[4], 0, NULL); serio_interrupt(ptport, packet[5], 0, NULL); - if (child->type >= PSMOUSE_GENPS) + if (child->pktsize == 4) serio_interrupt(ptport, packet[2], 0, NULL); } else serio_interrupt(ptport, packet[1], 0, NULL); @@ -233,7 +233,7 @@ static void synaptics_pt_activate(struct psmouse *psmouse) /* adjust the touchpad to child's choice of protocol */ if (child) { - if (child->type >= PSMOUSE_GENPS) + if (child->pktsize == 4) priv->mode |= SYN_BIT_FOUR_BYTE_CLIENT; else priv->mode &= ~SYN_BIT_FOUR_BYTE_CLIENT; @@ -608,6 +608,13 @@ static struct dmi_system_id toshiba_dmi_table[] = { DMI_MATCH(DMI_PRODUCT_NAME , "Satellite"), }, }, + { + .ident = "Toshiba Dynabook", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), + DMI_MATCH(DMI_PRODUCT_NAME , "dynabook"), + }, + }, { } }; #endif @@ -656,7 +663,8 @@ int synaptics_init(struct psmouse *psmouse) * thye same as rate of standard PS/2 mouse. */ if (psmouse->rate >= 80 && dmi_check_system(toshiba_dmi_table)) { - printk(KERN_INFO "synaptics: Toshiba Satellite detected, limiting rate to 40pps.\n"); + printk(KERN_INFO "synaptics: Toshiba %s detected, limiting rate to 40pps.\n", + dmi_get_system_info(DMI_PRODUCT_NAME)); psmouse->rate = 40; } #endif diff --git a/drivers/input/mouse/trackpoint.c b/drivers/input/mouse/trackpoint.c new file mode 100644 index 000000000000..b4898d8a68e2 --- /dev/null +++ b/drivers/input/mouse/trackpoint.c @@ -0,0 +1,304 @@ +/* + * Stephen Evanchik <evanchsa@gmail.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * Trademarks are the property of their respective owners. + */ + +#include <linux/delay.h> +#include <linux/serio.h> +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/input.h> +#include <linux/libps2.h> +#include <linux/proc_fs.h> +#include <asm/uaccess.h> +#include "psmouse.h" +#include "trackpoint.h" + +/* + * Device IO: read, write and toggle bit + */ +static int trackpoint_read(struct ps2dev *ps2dev, unsigned char loc, unsigned char *results) +{ + if (ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, TP_COMMAND)) || + ps2_command(ps2dev, results, MAKE_PS2_CMD(0, 1, loc))) { + return -1; + } + + return 0; +} + +static int trackpoint_write(struct ps2dev *ps2dev, unsigned char loc, unsigned char val) +{ + if (ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, TP_COMMAND)) || + ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, TP_WRITE_MEM)) || + ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, loc)) || + ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, val))) { + return -1; + } + + return 0; +} + +static int trackpoint_toggle_bit(struct ps2dev *ps2dev, unsigned char loc, unsigned char mask) +{ + /* Bad things will happen if the loc param isn't in this range */ + if (loc < 0x20 || loc >= 0x2F) + return -1; + + if (ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, TP_COMMAND)) || + ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, TP_TOGGLE)) || + ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, loc)) || + ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, mask))) { + return -1; + } + + return 0; +} + + +/* + * Trackpoint-specific attributes + */ +struct trackpoint_attr_data { + size_t field_offset; + unsigned char command; + unsigned char mask; +}; + +static ssize_t trackpoint_show_int_attr(struct psmouse *psmouse, void *data, char *buf) +{ + struct trackpoint_data *tp = psmouse->private; + struct trackpoint_attr_data *attr = data; + unsigned char *field = (unsigned char *)((char *)tp + attr->field_offset); + + return sprintf(buf, "%u\n", *field); +} + +static ssize_t trackpoint_set_int_attr(struct psmouse *psmouse, void *data, + const char *buf, size_t count) +{ + struct trackpoint_data *tp = psmouse->private; + struct trackpoint_attr_data *attr = data; + unsigned char *field = (unsigned char *)((char *)tp + attr->field_offset); + unsigned long value; + char *rest; + + value = simple_strtoul(buf, &rest, 10); + if (*rest || value > 255) + return -EINVAL; + + *field = value; + trackpoint_write(&psmouse->ps2dev, attr->command, value); + + return count; +} + +#define TRACKPOINT_INT_ATTR(_name, _command) \ + static struct trackpoint_attr_data trackpoint_attr_##_name = { \ + .field_offset = offsetof(struct trackpoint_data, _name), \ + .command = _command, \ + }; \ + PSMOUSE_DEFINE_ATTR(_name, S_IWUSR | S_IRUGO, \ + &trackpoint_attr_##_name, \ + trackpoint_show_int_attr, trackpoint_set_int_attr) + +static ssize_t trackpoint_set_bit_attr(struct psmouse *psmouse, void *data, + const char *buf, size_t count) +{ + struct trackpoint_data *tp = psmouse->private; + struct trackpoint_attr_data *attr = data; + unsigned char *field = (unsigned char *)((char *)tp + attr->field_offset); + unsigned long value; + char *rest; + + value = simple_strtoul(buf, &rest, 10); + if (*rest || value > 1) + return -EINVAL; + + if (*field != value) { + *field = value; + trackpoint_toggle_bit(&psmouse->ps2dev, attr->command, attr->mask); + } + + return count; +} + + +#define TRACKPOINT_BIT_ATTR(_name, _command, _mask) \ + static struct trackpoint_attr_data trackpoint_attr_##_name = { \ + .field_offset = offsetof(struct trackpoint_data, _name), \ + .command = _command, \ + .mask = _mask, \ + }; \ + PSMOUSE_DEFINE_ATTR(_name, S_IWUSR | S_IRUGO, \ + &trackpoint_attr_##_name, \ + trackpoint_show_int_attr, trackpoint_set_bit_attr) + +TRACKPOINT_INT_ATTR(sensitivity, TP_SENS); +TRACKPOINT_INT_ATTR(speed, TP_SPEED); +TRACKPOINT_INT_ATTR(inertia, TP_INERTIA); +TRACKPOINT_INT_ATTR(reach, TP_REACH); +TRACKPOINT_INT_ATTR(draghys, TP_DRAGHYS); +TRACKPOINT_INT_ATTR(mindrag, TP_MINDRAG); +TRACKPOINT_INT_ATTR(thresh, TP_THRESH); +TRACKPOINT_INT_ATTR(upthresh, TP_UP_THRESH); +TRACKPOINT_INT_ATTR(ztime, TP_Z_TIME); +TRACKPOINT_INT_ATTR(jenks, TP_JENKS_CURV); + +TRACKPOINT_BIT_ATTR(press_to_select, TP_TOGGLE_PTSON, TP_MASK_PTSON); +TRACKPOINT_BIT_ATTR(skipback, TP_TOGGLE_SKIPBACK, TP_MASK_SKIPBACK); +TRACKPOINT_BIT_ATTR(ext_dev, TP_TOGGLE_EXT_DEV, TP_MASK_EXT_DEV); + +static struct attribute *trackpoint_attrs[] = { + &psmouse_attr_sensitivity.dattr.attr, + &psmouse_attr_speed.dattr.attr, + &psmouse_attr_inertia.dattr.attr, + &psmouse_attr_reach.dattr.attr, + &psmouse_attr_draghys.dattr.attr, + &psmouse_attr_mindrag.dattr.attr, + &psmouse_attr_thresh.dattr.attr, + &psmouse_attr_upthresh.dattr.attr, + &psmouse_attr_ztime.dattr.attr, + &psmouse_attr_jenks.dattr.attr, + &psmouse_attr_press_to_select.dattr.attr, + &psmouse_attr_skipback.dattr.attr, + &psmouse_attr_ext_dev.dattr.attr, + NULL +}; + +static struct attribute_group trackpoint_attr_group = { + .attrs = trackpoint_attrs, +}; + +static void trackpoint_disconnect(struct psmouse *psmouse) +{ + sysfs_remove_group(&psmouse->ps2dev.serio->dev.kobj, &trackpoint_attr_group); + + kfree(psmouse->private); + psmouse->private = NULL; +} + +static int trackpoint_sync(struct psmouse *psmouse) +{ + unsigned char toggle; + struct trackpoint_data *tp = psmouse->private; + + if (!tp) + return -1; + + /* Disable features that may make device unusable with this driver */ + trackpoint_read(&psmouse->ps2dev, TP_TOGGLE_TWOHAND, &toggle); + if (toggle & TP_MASK_TWOHAND) + trackpoint_toggle_bit(&psmouse->ps2dev, TP_TOGGLE_TWOHAND, TP_MASK_TWOHAND); + + trackpoint_read(&psmouse->ps2dev, TP_TOGGLE_SOURCE_TAG, &toggle); + if (toggle & TP_MASK_SOURCE_TAG) + trackpoint_toggle_bit(&psmouse->ps2dev, TP_TOGGLE_SOURCE_TAG, TP_MASK_SOURCE_TAG); + + trackpoint_read(&psmouse->ps2dev, TP_TOGGLE_MB, &toggle); + if (toggle & TP_MASK_MB) + trackpoint_toggle_bit(&psmouse->ps2dev, TP_TOGGLE_MB, TP_MASK_MB); + + /* Push the config to the device */ + trackpoint_write(&psmouse->ps2dev, TP_SENS, tp->sensitivity); + trackpoint_write(&psmouse->ps2dev, TP_INERTIA, tp->inertia); + trackpoint_write(&psmouse->ps2dev, TP_SPEED, tp->speed); + + trackpoint_write(&psmouse->ps2dev, TP_REACH, tp->reach); + trackpoint_write(&psmouse->ps2dev, TP_DRAGHYS, tp->draghys); + trackpoint_write(&psmouse->ps2dev, TP_MINDRAG, tp->mindrag); + + trackpoint_write(&psmouse->ps2dev, TP_THRESH, tp->thresh); + trackpoint_write(&psmouse->ps2dev, TP_UP_THRESH, tp->upthresh); + + trackpoint_write(&psmouse->ps2dev, TP_Z_TIME, tp->ztime); + trackpoint_write(&psmouse->ps2dev, TP_JENKS_CURV, tp->jenks); + + trackpoint_read(&psmouse->ps2dev, TP_TOGGLE_PTSON, &toggle); + if (((toggle & TP_MASK_PTSON) == TP_MASK_PTSON) != tp->press_to_select) + trackpoint_toggle_bit(&psmouse->ps2dev, TP_TOGGLE_PTSON, TP_MASK_PTSON); + + trackpoint_read(&psmouse->ps2dev, TP_TOGGLE_SKIPBACK, &toggle); + if (((toggle & TP_MASK_SKIPBACK) == TP_MASK_SKIPBACK) != tp->skipback) + trackpoint_toggle_bit(&psmouse->ps2dev, TP_TOGGLE_SKIPBACK, TP_MASK_SKIPBACK); + + trackpoint_read(&psmouse->ps2dev, TP_TOGGLE_EXT_DEV, &toggle); + if (((toggle & TP_MASK_EXT_DEV) == TP_MASK_EXT_DEV) != tp->ext_dev) + trackpoint_toggle_bit(&psmouse->ps2dev, TP_TOGGLE_EXT_DEV, TP_MASK_EXT_DEV); + + return 0; +} + +static void trackpoint_defaults(struct trackpoint_data *tp) +{ + tp->press_to_select = TP_DEF_PTSON; + tp->sensitivity = TP_DEF_SENS; + tp->speed = TP_DEF_SPEED; + tp->reach = TP_DEF_REACH; + + tp->draghys = TP_DEF_DRAGHYS; + tp->mindrag = TP_DEF_MINDRAG; + + tp->thresh = TP_DEF_THRESH; + tp->upthresh = TP_DEF_UP_THRESH; + + tp->ztime = TP_DEF_Z_TIME; + tp->jenks = TP_DEF_JENKS_CURV; + + tp->inertia = TP_DEF_INERTIA; + tp->skipback = TP_DEF_SKIPBACK; + tp->ext_dev = TP_DEF_EXT_DEV; +} + +int trackpoint_detect(struct psmouse *psmouse, int set_properties) +{ + struct trackpoint_data *priv; + struct ps2dev *ps2dev = &psmouse->ps2dev; + unsigned char firmware_id; + unsigned char button_info; + unsigned char param[2]; + + param[0] = param[1] = 0; + + if (ps2_command(ps2dev, param, MAKE_PS2_CMD(0, 2, TP_READ_ID))) + return -1; + + if (param[0] != TP_MAGIC_IDENT) + return -1; + + if (!set_properties) + return 0; + + firmware_id = param[1]; + + if (trackpoint_read(&psmouse->ps2dev, TP_EXT_BTN, &button_info)) { + printk(KERN_WARNING "trackpoint.c: failed to get extended button data\n"); + button_info = 0; + } + + psmouse->private = priv = kcalloc(1, sizeof(struct trackpoint_data), GFP_KERNEL); + if (!priv) + return -1; + + psmouse->vendor = "IBM"; + psmouse->name = "TrackPoint"; + + psmouse->reconnect = trackpoint_sync; + psmouse->disconnect = trackpoint_disconnect; + + trackpoint_defaults(priv); + trackpoint_sync(psmouse); + + sysfs_create_group(&ps2dev->serio->dev.kobj, &trackpoint_attr_group); + + printk(KERN_INFO "IBM TrackPoint firmware: 0x%02x, buttons: %d/%d\n", + firmware_id, (button_info & 0xf0) >> 4, button_info & 0x0f); + + return 0; +} + diff --git a/drivers/input/mouse/trackpoint.h b/drivers/input/mouse/trackpoint.h new file mode 100644 index 000000000000..9857d8b6ad66 --- /dev/null +++ b/drivers/input/mouse/trackpoint.h @@ -0,0 +1,147 @@ +/* + * IBM TrackPoint PS/2 mouse driver + * + * Stephen Evanchik <evanchsa@gmail.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + */ + +#ifndef _TRACKPOINT_H +#define _TRACKPOINT_H + +/* + * These constants are from the TrackPoint System + * Engineering documentation Version 4 from IBM Watson + * research: + * http://wwwcssrv.almaden.ibm.com/trackpoint/download.html + */ + +#define TP_COMMAND 0xE2 /* Commands start with this */ + +#define TP_READ_ID 0xE1 /* Sent for device identification */ +#define TP_MAGIC_IDENT 0x01 /* Sent after a TP_READ_ID followed */ + /* by the firmware ID */ + + +/* + * Commands + */ +#define TP_RECALIB 0x51 /* Recalibrate */ +#define TP_POWER_DOWN 0x44 /* Can only be undone through HW reset */ +#define TP_EXT_DEV 0x21 /* Determines if external device is connected (RO) */ +#define TP_EXT_BTN 0x4B /* Read extended button status */ +#define TP_POR 0x7F /* Execute Power on Reset */ +#define TP_POR_RESULTS 0x25 /* Read Power on Self test results */ +#define TP_DISABLE_EXT 0x40 /* Disable external pointing device */ +#define TP_ENABLE_EXT 0x41 /* Enable external pointing device */ + +/* + * Mode manipulation + */ +#define TP_SET_SOFT_TRANS 0x4E /* Set mode */ +#define TP_CANCEL_SOFT_TRANS 0xB9 /* Cancel mode */ +#define TP_SET_HARD_TRANS 0x45 /* Mode can only be set */ + + +/* + * Register oriented commands/properties + */ +#define TP_WRITE_MEM 0x81 +#define TP_READ_MEM 0x80 /* Not used in this implementation */ + +/* +* RAM Locations for properties + */ +#define TP_SENS 0x4A /* Sensitivity */ +#define TP_MB 0x4C /* Read Middle Button Status (RO) */ +#define TP_INERTIA 0x4D /* Negative Inertia */ +#define TP_SPEED 0x60 /* Speed of TP Cursor */ +#define TP_REACH 0x57 /* Backup for Z-axis press */ +#define TP_DRAGHYS 0x58 /* Drag Hysteresis */ + /* (how hard it is to drag */ + /* with Z-axis pressed) */ + +#define TP_MINDRAG 0x59 /* Minimum amount of force needed */ + /* to trigger dragging */ + +#define TP_THRESH 0x5C /* Minimum value for a Z-axis press */ +#define TP_UP_THRESH 0x5A /* Used to generate a 'click' on Z-axis */ +#define TP_Z_TIME 0x5E /* How sharp of a press */ +#define TP_JENKS_CURV 0x5D /* Minimum curvature for double click */ + +/* + * Toggling Flag bits + */ +#define TP_TOGGLE 0x47 /* Toggle command */ + +#define TP_TOGGLE_MB 0x23 /* Disable/Enable Middle Button */ +#define TP_MASK_MB 0x01 +#define TP_TOGGLE_EXT_DEV 0x23 /* Toggle external device */ +#define TP_MASK_EXT_DEV 0x02 +#define TP_TOGGLE_DRIFT 0x23 /* Drift Correction */ +#define TP_MASK_DRIFT 0x80 +#define TP_TOGGLE_BURST 0x28 /* Burst Mode */ +#define TP_MASK_BURST 0x80 +#define TP_TOGGLE_PTSON 0x2C /* Press to Select */ +#define TP_MASK_PTSON 0x01 +#define TP_TOGGLE_HARD_TRANS 0x2C /* Alternate method to set Hard Transparency */ +#define TP_MASK_HARD_TRANS 0x80 +#define TP_TOGGLE_TWOHAND 0x2D /* Two handed */ +#define TP_MASK_TWOHAND 0x01 +#define TP_TOGGLE_STICKY_TWO 0x2D /* Sticky two handed */ +#define TP_MASK_STICKY_TWO 0x04 +#define TP_TOGGLE_SKIPBACK 0x2D /* Suppress movement after drag release */ +#define TP_MASK_SKIPBACK 0x08 +#define TP_TOGGLE_SOURCE_TAG 0x20 /* Bit 3 of the first packet will be set to + to the origin of the packet (external or TP) */ +#define TP_MASK_SOURCE_TAG 0x80 +#define TP_TOGGLE_EXT_TAG 0x22 /* Bit 3 of the first packet coming from the + external device will be forced to 1 */ +#define TP_MASK_EXT_TAG 0x04 + + +/* Power on Self Test Results */ +#define TP_POR_SUCCESS 0x3B + +/* + * Default power on values + */ +#define TP_DEF_SENS 0x80 +#define TP_DEF_INERTIA 0x06 +#define TP_DEF_SPEED 0x61 +#define TP_DEF_REACH 0x0A + +#define TP_DEF_DRAGHYS 0xFF +#define TP_DEF_MINDRAG 0x14 + +#define TP_DEF_THRESH 0x08 +#define TP_DEF_UP_THRESH 0xFF +#define TP_DEF_Z_TIME 0x26 +#define TP_DEF_JENKS_CURV 0x87 + +/* Toggles */ +#define TP_DEF_MB 0x00 +#define TP_DEF_PTSON 0x00 +#define TP_DEF_SKIPBACK 0x00 +#define TP_DEF_EXT_DEV 0x01 + +#define MAKE_PS2_CMD(params, results, cmd) ((params<<12) | (results<<8) | (cmd)) + +struct trackpoint_data +{ + unsigned char sensitivity, speed, inertia, reach; + unsigned char draghys, mindrag; + unsigned char thresh, upthresh; + unsigned char ztime, jenks; + + unsigned char press_to_select; + unsigned char skipback; + + unsigned char ext_dev; +}; + +extern int trackpoint_detect(struct psmouse *psmouse, int set_properties); + +#endif /* _TRACKPOINT_H */ diff --git a/drivers/input/serio/Kconfig b/drivers/input/serio/Kconfig index b3710733b36b..98acf170252c 100644 --- a/drivers/input/serio/Kconfig +++ b/drivers/input/serio/Kconfig @@ -175,7 +175,7 @@ config SERIO_RAW allocating minor 1 (that historically corresponds to /dev/psaux) first. To bind this driver to a serio port use sysfs interface: - echo -n "serio_raw" > /sys/bus/serio/devices/serioX/driver + echo -n "serio_raw" > /sys/bus/serio/devices/serioX/drvctl To compile this driver as a module, choose M here: the module will be called serio_raw. diff --git a/drivers/input/serio/i8042-io.h b/drivers/input/serio/i8042-io.h index c9e633d21d90..9a9221644250 100644 --- a/drivers/input/serio/i8042-io.h +++ b/drivers/input/serio/i8042-io.h @@ -69,16 +69,16 @@ static inline int i8042_platform_init(void) */ #if !defined(__sh__) && !defined(__alpha__) && !defined(__mips__) && !defined(CONFIG_PPC64) if (!request_region(I8042_DATA_REG, 16, "i8042")) - return -1; + return -EBUSY; #endif i8042_reset = 1; #if defined(CONFIG_PPC64) if (check_legacy_ioport(I8042_DATA_REG)) - return -1; + return -EBUSY; if (!request_region(I8042_DATA_REG, 16, "i8042")) - return -1; + return -EBUSY; #endif return 0; } diff --git a/drivers/input/serio/i8042-ip22io.h b/drivers/input/serio/i8042-ip22io.h index 863b9c95fbb8..ee1ad27d6ed0 100644 --- a/drivers/input/serio/i8042-ip22io.h +++ b/drivers/input/serio/i8042-ip22io.h @@ -58,7 +58,7 @@ static inline int i8042_platform_init(void) #if 0 /* XXX sgi_kh is a virtual address */ if (!request_mem_region(sgi_kh, sizeof(struct hpc_keyb), "i8042")) - return 1; + return -EBUSY; #endif i8042_reset = 1; diff --git a/drivers/input/serio/i8042-jazzio.h b/drivers/input/serio/i8042-jazzio.h index 5c20ab131488..13fd7108eb28 100644 --- a/drivers/input/serio/i8042-jazzio.h +++ b/drivers/input/serio/i8042-jazzio.h @@ -53,7 +53,7 @@ static inline int i8042_platform_init(void) #if 0 /* XXX JAZZ_KEYBOARD_ADDRESS is a virtual address */ if (!request_mem_region(JAZZ_KEYBOARD_ADDRESS, 2, "i8042")) - return 1; + return -EBUSY; #endif return 0; diff --git a/drivers/input/serio/i8042-sparcio.h b/drivers/input/serio/i8042-sparcio.h index da2a19812485..ed9446f6d7e3 100644 --- a/drivers/input/serio/i8042-sparcio.h +++ b/drivers/input/serio/i8042-sparcio.h @@ -48,10 +48,10 @@ static inline void i8042_write_command(int val) #define OBP_PS2MS_NAME1 "kdmouse" #define OBP_PS2MS_NAME2 "mouse" -static int i8042_platform_init(void) +static int __init i8042_platform_init(void) { #ifndef CONFIG_PCI - return -1; + return -ENODEV; #else char prop[128]; int len; @@ -59,14 +59,14 @@ static int i8042_platform_init(void) len = prom_getproperty(prom_root_node, "name", prop, sizeof(prop)); if (len < 0) { printk("i8042: Cannot get name property of root OBP node.\n"); - return -1; + return -ENODEV; } if (strncmp(prop, "SUNW,JavaStation-1", len) == 0) { /* Hardcoded values for MrCoffee. */ i8042_kbd_irq = i8042_aux_irq = 13 | 0x20; kbd_iobase = ioremap(0x71300060, 8); if (!kbd_iobase) - return -1; + return -ENODEV; } else { struct linux_ebus *ebus; struct linux_ebus_device *edev; @@ -78,7 +78,7 @@ static int i8042_platform_init(void) goto edev_found; } } - return -1; + return -ENODEV; edev_found: for_each_edevchild(edev, child) { @@ -96,7 +96,7 @@ static int i8042_platform_init(void) i8042_aux_irq == -1) { printk("i8042: Error, 8042 device lacks both kbd and " "mouse nodes.\n"); - return -1; + return -ENODEV; } } diff --git a/drivers/input/serio/i8042-x86ia64io.h b/drivers/input/serio/i8042-x86ia64io.h index 0487ecbb8a49..273bb3b08cfa 100644 --- a/drivers/input/serio/i8042-x86ia64io.h +++ b/drivers/input/serio/i8042-x86ia64io.h @@ -131,12 +131,33 @@ static struct dmi_system_id __initdata i8042_dmi_nomux_table[] = { }, }, { + .ident = "Fujitsu-Siemens Lifebook T3010", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), + DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK T3010"), + }, + }, + { + .ident = "Fujitsu-Siemens Lifebook E4010", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), + DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK E4010"), + }, + }, + { .ident = "Toshiba P10", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), DMI_MATCH(DMI_PRODUCT_NAME, "Satellite P10"), }, }, + { + .ident = "Alienware Sentia", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ALIENWARE"), + DMI_MATCH(DMI_PRODUCT_NAME, "Sentia"), + }, + }, { } }; @@ -242,9 +263,10 @@ static void i8042_pnp_exit(void) } } -static int i8042_pnp_init(void) +static int __init i8042_pnp_init(void) { - int result_kbd, result_aux; + int result_kbd = 0, result_aux = 0; + char kbd_irq_str[4] = { 0 }, aux_irq_str[4] = { 0 }; if (i8042_nopnp) { printk(KERN_INFO "i8042: PNP detection disabled\n"); @@ -253,6 +275,7 @@ static int i8042_pnp_init(void) if ((result_kbd = pnp_register_driver(&i8042_pnp_kbd_driver)) >= 0) i8042_pnp_kbd_registered = 1; + if ((result_aux = pnp_register_driver(&i8042_pnp_aux_driver)) >= 0) i8042_pnp_aux_registered = 1; @@ -266,6 +289,27 @@ static int i8042_pnp_init(void) #endif } + if (result_kbd > 0) + snprintf(kbd_irq_str, sizeof(kbd_irq_str), + "%d", i8042_pnp_kbd_irq); + if (result_aux > 0) + snprintf(aux_irq_str, sizeof(aux_irq_str), + "%d", i8042_pnp_aux_irq); + + printk(KERN_INFO "PNP: PS/2 Controller [%s%s%s] at %#x,%#x irq %s%s%s\n", + i8042_pnp_kbd_name, (result_kbd > 0 && result_aux > 0) ? "," : "", + i8042_pnp_aux_name, + i8042_pnp_data_reg, i8042_pnp_command_reg, + kbd_irq_str, (result_kbd > 0 && result_aux > 0) ? "," : "", + aux_irq_str); + +#if defined(__ia64__) + if (result_kbd <= 0) + i8042_nokbd = 1; + if (result_aux <= 0) + i8042_noaux = 1; +#endif + if (((i8042_pnp_data_reg & ~0xf) == (i8042_data_reg & ~0xf) && i8042_pnp_data_reg != i8042_data_reg) || !i8042_pnp_data_reg) { printk(KERN_WARNING "PNP: PS/2 controller has invalid data port %#x; using default %#x\n", @@ -280,53 +324,47 @@ static int i8042_pnp_init(void) i8042_pnp_command_reg = i8042_command_reg; } - if (!i8042_pnp_kbd_irq) { - printk(KERN_WARNING "PNP: PS/2 controller doesn't have KBD irq; using default %#x\n", i8042_kbd_irq); + if (!i8042_nokbd && !i8042_pnp_kbd_irq) { + printk(KERN_WARNING "PNP: PS/2 controller doesn't have KBD irq; using default %d\n", i8042_kbd_irq); i8042_pnp_kbd_irq = i8042_kbd_irq; } - if (!i8042_pnp_aux_irq) { - printk(KERN_WARNING "PNP: PS/2 controller doesn't have AUX irq; using default %#x\n", i8042_aux_irq); + if (!i8042_noaux && !i8042_pnp_aux_irq) { + printk(KERN_WARNING "PNP: PS/2 controller doesn't have AUX irq; using default %d\n", i8042_aux_irq); i8042_pnp_aux_irq = i8042_aux_irq; } -#if defined(__ia64__) - if (result_aux <= 0) - i8042_noaux = 1; -#endif - i8042_data_reg = i8042_pnp_data_reg; i8042_command_reg = i8042_pnp_command_reg; i8042_kbd_irq = i8042_pnp_kbd_irq; i8042_aux_irq = i8042_pnp_aux_irq; - printk(KERN_INFO "PNP: PS/2 Controller [%s%s%s] at %#x,%#x irq %d%s%d\n", - i8042_pnp_kbd_name, (result_kbd > 0 && result_aux > 0) ? "," : "", i8042_pnp_aux_name, - i8042_data_reg, i8042_command_reg, i8042_kbd_irq, - (result_aux > 0) ? "," : "", i8042_aux_irq); - return 0; } +#else +static inline int i8042_pnp_init(void) { return 0; } +static inline void i8042_pnp_exit(void) { } #endif -static inline int i8042_platform_init(void) +static int __init i8042_platform_init(void) { + int retval; + /* * On ix86 platforms touching the i8042 data register region can do really * bad things. Because of this the region is always reserved on ix86 boxes. * * if (!request_region(I8042_DATA_REG, 16, "i8042")) - * return -1; + * return -EBUSY; */ i8042_kbd_irq = I8042_MAP_IRQ(1); i8042_aux_irq = I8042_MAP_IRQ(12); -#ifdef CONFIG_PNP - if (i8042_pnp_init()) - return -1; -#endif + retval = i8042_pnp_init(); + if (retval) + return retval; #if defined(__ia64__) i8042_reset = 1; @@ -340,14 +378,12 @@ static inline int i8042_platform_init(void) i8042_nomux = 1; #endif - return 0; + return retval; } static inline void i8042_platform_exit(void) { -#ifdef CONFIG_PNP i8042_pnp_exit(); -#endif } #endif /* _I8042_X86IA64IO_H */ diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c index a9bf549c8dc5..40d451ce07ff 100644 --- a/drivers/input/serio/i8042.c +++ b/drivers/input/serio/i8042.c @@ -27,6 +27,10 @@ MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>"); MODULE_DESCRIPTION("i8042 keyboard and mouse controller driver"); MODULE_LICENSE("GPL"); +static unsigned int i8042_nokbd; +module_param_named(nokbd, i8042_nokbd, bool, 0); +MODULE_PARM_DESC(nokbd, "Do not probe or use KBD port."); + static unsigned int i8042_noaux; module_param_named(noaux, i8042_noaux, bool, 0); MODULE_PARM_DESC(noaux, "Do not probe or use AUX (mouse) port."); @@ -100,7 +104,7 @@ struct i8042_port { static struct i8042_port i8042_ports[I8042_NUM_PORTS] = { { .disable = I8042_CTR_KBDDIS, - .irqen = I8042_CTR_KBDINT, + .irqen = I8042_CTR_KBDINT, .mux = -1, .name = "KBD", }, @@ -191,41 +195,45 @@ static int i8042_flush(void) static int i8042_command(unsigned char *param, int command) { unsigned long flags; - int retval = 0, i = 0; + int i, retval, auxerr = 0; if (i8042_noloop && command == I8042_CMD_AUX_LOOP) return -1; spin_lock_irqsave(&i8042_lock, flags); - retval = i8042_wait_write(); - if (!retval) { - dbg("%02x -> i8042 (command)", command & 0xff); - i8042_write_command(command & 0xff); + if ((retval = i8042_wait_write())) + goto out; + + dbg("%02x -> i8042 (command)", command & 0xff); + i8042_write_command(command & 0xff); + + for (i = 0; i < ((command >> 12) & 0xf); i++) { + if ((retval = i8042_wait_write())) + goto out; + dbg("%02x -> i8042 (parameter)", param[i]); + i8042_write_data(param[i]); } - if (!retval) - for (i = 0; i < ((command >> 12) & 0xf); i++) { - if ((retval = i8042_wait_write())) break; - dbg("%02x -> i8042 (parameter)", param[i]); - i8042_write_data(param[i]); - } + for (i = 0; i < ((command >> 8) & 0xf); i++) { + if ((retval = i8042_wait_read())) + goto out; - if (!retval) - for (i = 0; i < ((command >> 8) & 0xf); i++) { - if ((retval = i8042_wait_read())) break; - if (i8042_read_status() & I8042_STR_AUXDATA) - param[i] = ~i8042_read_data(); - else - param[i] = i8042_read_data(); - dbg("%02x <- i8042 (return)", param[i]); + if (command == I8042_CMD_AUX_LOOP && + !(i8042_read_status() & I8042_STR_AUXDATA)) { + retval = auxerr = -1; + goto out; } - spin_unlock_irqrestore(&i8042_lock, flags); + param[i] = i8042_read_data(); + dbg("%02x <- i8042 (return)", param[i]); + } if (retval) - dbg(" -- i8042 (timeout)"); + dbg(" -- i8042 (%s)", auxerr ? "auxerr" : "timeout"); + out: + spin_unlock_irqrestore(&i8042_lock, flags); return retval; } @@ -334,10 +342,10 @@ static int i8042_open(struct serio *serio) return 0; -activate_fail: + activate_fail: free_irq(port->irq, i8042_request_irq_cookie); -irq_fail: + irq_fail: serio_unregister_port_delayed(serio); return -1; @@ -481,7 +489,7 @@ static irqreturn_t i8042_interrupt(int irq, void *dev_id, struct pt_regs *regs) serio_interrupt(port->serio, data, dfl, regs); ret = 1; -out: + out: return IRQ_RETVAL(ret); } @@ -507,17 +515,17 @@ static int i8042_set_mux_mode(unsigned int mode, unsigned char *mux_version) */ param = 0xf0; - if (i8042_command(¶m, I8042_CMD_AUX_LOOP) || param != 0x0f) + if (i8042_command(¶m, I8042_CMD_AUX_LOOP) || param != 0xf0) return -1; param = mode ? 0x56 : 0xf6; - if (i8042_command(¶m, I8042_CMD_AUX_LOOP) || param != (mode ? 0xa9 : 0x09)) + if (i8042_command(¶m, I8042_CMD_AUX_LOOP) || param != (mode ? 0x56 : 0xf6)) return -1; param = mode ? 0xa4 : 0xa5; - if (i8042_command(¶m, I8042_CMD_AUX_LOOP) || param == (mode ? 0x5b : 0x5a)) + if (i8042_command(¶m, I8042_CMD_AUX_LOOP) || param == (mode ? 0xa4 : 0xa5)) return -1; if (mux_version) - *mux_version = ~param; + *mux_version = param; return 0; } @@ -548,7 +556,7 @@ static int i8042_enable_mux_ports(void) * Enable all muxed ports. */ - for (i = 0; i < 4; i++) { + for (i = 0; i < I8042_NUM_MUX_PORTS; i++) { i8042_command(¶m, I8042_CMD_MUX_PFX + i); i8042_command(¶m, I8042_CMD_AUX_ENABLE); } @@ -619,7 +627,7 @@ static int __init i8042_check_aux(void) */ param = 0x5a; - if (i8042_command(¶m, I8042_CMD_AUX_LOOP) || param != 0xa5) { + if (i8042_command(¶m, I8042_CMD_AUX_LOOP) || param != 0x5a) { /* * External connection test - filters out AT-soldered PS/2 i8042's @@ -630,7 +638,7 @@ static int __init i8042_check_aux(void) */ if (i8042_command(¶m, I8042_CMD_AUX_TEST) - || (param && param != 0xfa && param != 0xff)) + || (param && param != 0xfa && param != 0xff)) return -1; } @@ -678,7 +686,7 @@ static int __init i8042_port_register(struct i8042_port *port) kfree(port->serio); port->serio = NULL; i8042_ctr |= port->disable; - return -1; + return -EIO; } printk(KERN_INFO "serio: i8042 %s port at %#lx,%#lx irq %d\n", @@ -973,85 +981,88 @@ static struct device_driver i8042_driver = { .shutdown = i8042_shutdown, }; -static void __init i8042_create_kbd_port(void) +static int __init i8042_create_kbd_port(void) { struct serio *serio; struct i8042_port *port = &i8042_ports[I8042_KBD_PORT_NO]; - serio = kmalloc(sizeof(struct serio), GFP_KERNEL); - if (serio) { - memset(serio, 0, sizeof(struct serio)); - serio->id.type = i8042_direct ? SERIO_8042 : SERIO_8042_XL; - serio->write = i8042_dumbkbd ? NULL : i8042_kbd_write; - serio->open = i8042_open; - serio->close = i8042_close; - serio->start = i8042_start; - serio->stop = i8042_stop; - serio->port_data = port; - serio->dev.parent = &i8042_platform_device->dev; - strlcpy(serio->name, "i8042 Kbd Port", sizeof(serio->name)); - strlcpy(serio->phys, I8042_KBD_PHYS_DESC, sizeof(serio->phys)); - - port->serio = serio; - i8042_port_register(port); - } + serio = kzalloc(sizeof(struct serio), GFP_KERNEL); + if (!serio) + return -ENOMEM; + + serio->id.type = i8042_direct ? SERIO_8042 : SERIO_8042_XL; + serio->write = i8042_dumbkbd ? NULL : i8042_kbd_write; + serio->open = i8042_open; + serio->close = i8042_close; + serio->start = i8042_start; + serio->stop = i8042_stop; + serio->port_data = port; + serio->dev.parent = &i8042_platform_device->dev; + strlcpy(serio->name, "i8042 Kbd Port", sizeof(serio->name)); + strlcpy(serio->phys, I8042_KBD_PHYS_DESC, sizeof(serio->phys)); + + port->serio = serio; + + return i8042_port_register(port); } -static void __init i8042_create_aux_port(void) +static int __init i8042_create_aux_port(void) { struct serio *serio; struct i8042_port *port = &i8042_ports[I8042_AUX_PORT_NO]; - serio = kmalloc(sizeof(struct serio), GFP_KERNEL); - if (serio) { - memset(serio, 0, sizeof(struct serio)); - serio->id.type = SERIO_8042; - serio->write = i8042_aux_write; - serio->open = i8042_open; - serio->close = i8042_close; - serio->start = i8042_start; - serio->stop = i8042_stop; - serio->port_data = port; - serio->dev.parent = &i8042_platform_device->dev; - strlcpy(serio->name, "i8042 Aux Port", sizeof(serio->name)); - strlcpy(serio->phys, I8042_AUX_PHYS_DESC, sizeof(serio->phys)); - - port->serio = serio; - i8042_port_register(port); - } + serio = kzalloc(sizeof(struct serio), GFP_KERNEL); + if (!serio) + return -ENOMEM; + + serio->id.type = SERIO_8042; + serio->write = i8042_aux_write; + serio->open = i8042_open; + serio->close = i8042_close; + serio->start = i8042_start; + serio->stop = i8042_stop; + serio->port_data = port; + serio->dev.parent = &i8042_platform_device->dev; + strlcpy(serio->name, "i8042 Aux Port", sizeof(serio->name)); + strlcpy(serio->phys, I8042_AUX_PHYS_DESC, sizeof(serio->phys)); + + port->serio = serio; + + return i8042_port_register(port); } -static void __init i8042_create_mux_port(int index) +static int __init i8042_create_mux_port(int index) { struct serio *serio; struct i8042_port *port = &i8042_ports[I8042_MUX_PORT_NO + index]; - serio = kmalloc(sizeof(struct serio), GFP_KERNEL); - if (serio) { - memset(serio, 0, sizeof(struct serio)); - serio->id.type = SERIO_8042; - serio->write = i8042_aux_write; - serio->open = i8042_open; - serio->close = i8042_close; - serio->start = i8042_start; - serio->stop = i8042_stop; - serio->port_data = port; - serio->dev.parent = &i8042_platform_device->dev; - snprintf(serio->name, sizeof(serio->name), "i8042 Aux-%d Port", index); - snprintf(serio->phys, sizeof(serio->phys), I8042_MUX_PHYS_DESC, index + 1); - - *port = i8042_ports[I8042_AUX_PORT_NO]; - port->exists = 0; - snprintf(port->name, sizeof(port->name), "AUX%d", index); - port->mux = index; - port->serio = serio; - i8042_port_register(port); - } + serio = kzalloc(sizeof(struct serio), GFP_KERNEL); + if (!serio) + return -ENOMEM; + + serio->id.type = SERIO_8042; + serio->write = i8042_aux_write; + serio->open = i8042_open; + serio->close = i8042_close; + serio->start = i8042_start; + serio->stop = i8042_stop; + serio->port_data = port; + serio->dev.parent = &i8042_platform_device->dev; + snprintf(serio->name, sizeof(serio->name), "i8042 Aux-%d Port", index); + snprintf(serio->phys, sizeof(serio->phys), I8042_MUX_PHYS_DESC, index + 1); + + *port = i8042_ports[I8042_AUX_PORT_NO]; + port->exists = 0; + snprintf(port->name, sizeof(port->name), "AUX%d", index); + port->mux = index; + port->serio = serio; + + return i8042_port_register(port); } static int __init i8042_init(void) { - int i; + int i, have_ports = 0; int err; dbg_init(); @@ -1059,43 +1070,73 @@ static int __init i8042_init(void) init_timer(&i8042_timer); i8042_timer.function = i8042_timer_func; - if (i8042_platform_init()) - return -EBUSY; + 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()) { - i8042_platform_exit(); - return -ENODEV; + err = -ENODEV; + goto err_platform_exit; } err = driver_register(&i8042_driver); - if (err) { - i8042_platform_exit(); - return err; - } + if (err) + goto err_controller_cleanup; i8042_platform_device = platform_device_register_simple("i8042", -1, NULL, 0); if (IS_ERR(i8042_platform_device)) { - driver_unregister(&i8042_driver); - i8042_platform_exit(); - return PTR_ERR(i8042_platform_device); + err = PTR_ERR(i8042_platform_device); + goto err_unregister_driver; } if (!i8042_noaux && !i8042_check_aux()) { - if (!i8042_nomux && !i8042_check_mux()) - for (i = 0; i < I8042_NUM_MUX_PORTS; i++) - i8042_create_mux_port(i); - else - i8042_create_aux_port(); + if (!i8042_nomux && !i8042_check_mux()) { + for (i = 0; i < I8042_NUM_MUX_PORTS; i++) { + err = i8042_create_mux_port(i); + if (err) + goto err_unregister_ports; + } + } else { + err = i8042_create_aux_port(); + if (err) + goto err_unregister_ports; + } + have_ports = 1; + } + + if (!i8042_nokbd) { + err = i8042_create_kbd_port(); + if (err) + goto err_unregister_ports; + have_ports = 1; } - i8042_create_kbd_port(); + if (!have_ports) { + err = -ENODEV; + goto err_unregister_device; + } 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: + driver_unregister(&i8042_driver); + err_controller_cleanup: + i8042_controller_cleanup(); + err_platform_exit: + i8042_platform_exit(); + + return err; } static void __exit i8042_exit(void) diff --git a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c index f367695e69b5..edd15db17715 100644 --- a/drivers/input/serio/serio.c +++ b/drivers/input/serio/serio.c @@ -389,6 +389,14 @@ static ssize_t serio_show_description(struct device *dev, struct device_attribut return sprintf(buf, "%s\n", serio->name); } +static ssize_t serio_show_modalias(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct serio *serio = to_serio_port(dev); + + return sprintf(buf, "serio:ty%02Xpr%02Xid%02Xex%02X\n", + serio->id.type, serio->id.proto, serio->id.id, serio->id.extra); +} + static ssize_t serio_show_id_type(struct device *dev, struct device_attribute *attr, char *buf) { struct serio *serio = to_serio_port(dev); @@ -487,6 +495,7 @@ static ssize_t serio_set_bind_mode(struct device *dev, struct device_attribute * static struct device_attribute serio_device_attrs[] = { __ATTR(description, S_IRUGO, serio_show_description, NULL), + __ATTR(modalias, S_IRUGO, serio_show_modalias, NULL), __ATTR(drvctl, S_IWUSR, NULL, serio_rebind_driver), __ATTR(bind_mode, S_IWUSR | S_IRUGO, serio_show_bind_mode, serio_set_bind_mode), __ATTR_NULL @@ -785,36 +794,37 @@ static int serio_bus_match(struct device *dev, struct device_driver *drv) #ifdef CONFIG_HOTPLUG -#define PUT_ENVP(fmt, val) \ -do { \ - envp[i++] = buffer; \ - length += snprintf(buffer, buffer_size - length, fmt, val); \ - if (buffer_size - length <= 0 || i >= num_envp) \ - return -ENOMEM; \ - length++; \ - buffer += length; \ -} while (0) +#define SERIO_ADD_HOTPLUG_VAR(fmt, val...) \ + do { \ + int err = add_hotplug_env_var(envp, num_envp, &i, \ + buffer, buffer_size, &len, \ + fmt, val); \ + if (err) \ + return err; \ + } while (0) + static int serio_hotplug(struct device *dev, char **envp, int num_envp, char *buffer, int buffer_size) { struct serio *serio; int i = 0; - int length = 0; + int len = 0; if (!dev) return -ENODEV; serio = to_serio_port(dev); - PUT_ENVP("SERIO_TYPE=%02x", serio->id.type); - PUT_ENVP("SERIO_PROTO=%02x", serio->id.proto); - PUT_ENVP("SERIO_ID=%02x", serio->id.id); - PUT_ENVP("SERIO_EXTRA=%02x", serio->id.extra); - + SERIO_ADD_HOTPLUG_VAR("SERIO_TYPE=%02x", serio->id.type); + SERIO_ADD_HOTPLUG_VAR("SERIO_PROTO=%02x", serio->id.proto); + SERIO_ADD_HOTPLUG_VAR("SERIO_ID=%02x", serio->id.id); + SERIO_ADD_HOTPLUG_VAR("SERIO_EXTRA=%02x", serio->id.extra); + SERIO_ADD_HOTPLUG_VAR("MODALIAS=serio:ty%02Xpr%02Xid%02Xex%02X", + serio->id.type, serio->id.proto, serio->id.id, serio->id.extra); envp[i] = NULL; return 0; } -#undef PUT_ENVP +#undef SERIO_ADD_HOTPLUG_VAR #else diff --git a/drivers/input/serio/serio_raw.c b/drivers/input/serio/serio_raw.c index d914e7e93db4..47e08de18d07 100644 --- a/drivers/input/serio/serio_raw.c +++ b/drivers/input/serio/serio_raw.c @@ -299,6 +299,7 @@ static int serio_raw_connect(struct serio *serio, struct serio_driver *drv) serio_raw->dev.minor = PSMOUSE_MINOR; serio_raw->dev.name = serio_raw->name; + serio_raw->dev.dev = &serio->dev; serio_raw->dev.fops = &serio_raw_fops; err = misc_register(&serio_raw->dev); diff --git a/drivers/input/serio/serport.c b/drivers/input/serio/serport.c index 79ca38469159..1bd88fca0542 100644 --- a/drivers/input/serio/serport.c +++ b/drivers/input/serio/serport.c @@ -87,7 +87,7 @@ static int serport_ldisc_open(struct tty_struct *tty) if (!capable(CAP_SYS_ADMIN)) return -EPERM; - serport = kcalloc(1, sizeof(struct serport), GFP_KERNEL); + serport = kzalloc(sizeof(struct serport), GFP_KERNEL); if (!serport) return -ENOMEM; @@ -165,7 +165,7 @@ static ssize_t serport_ldisc_read(struct tty_struct * tty, struct file * file, u if (test_and_set_bit(SERPORT_BUSY, &serport->flags)) return -EBUSY; - serport->serio = serio = kcalloc(1, sizeof(struct serio), GFP_KERNEL); + serport->serio = serio = kzalloc(sizeof(struct serio), GFP_KERNEL); if (!serio) return -ENOMEM; diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index 7e991274ea40..21d55ed4b88a 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -24,17 +24,17 @@ config TOUCHSCREEN_BITSY module will be called h3600_ts_input. config TOUCHSCREEN_CORGI - tristate "Corgi touchscreen (for Sharp SL-C7xx)" + tristate "SharpSL (Corgi and Spitz series) touchscreen driver" depends on PXA_SHARPSL default y help Say Y here to enable the driver for the touchscreen on the - Sharp SL-C7xx series of PDAs. + Sharp SL-C7xx and SL-Cxx00 series of PDAs. If unsure, say N. To compile this driver as a module, choose M here: the - module will be called ads7846_ts. + module will be called corgi_ts. config TOUCHSCREEN_GUNZE tristate "Gunze AHL-51S touchscreen" @@ -58,7 +58,7 @@ config TOUCHSCREEN_ELO If unsure, say N. To compile this driver as a module, choose M here: the - module will be called gunze. + module will be called elo. config TOUCHSCREEN_MTOUCH tristate "MicroTouch serial touchscreens" diff --git a/drivers/input/touchscreen/corgi_ts.c b/drivers/input/touchscreen/corgi_ts.c index 3f8b61cfbc37..4c7fbe550365 100644 --- a/drivers/input/touchscreen/corgi_ts.c +++ b/drivers/input/touchscreen/corgi_ts.c @@ -1,5 +1,5 @@ /* - * Touchscreen driver for Sharp Corgi models (SL-C7xx) + * Touchscreen driver for Sharp SL-C7xx and SL-Cxx00 models * * Copyright (c) 2004-2005 Richard Purdie * @@ -19,7 +19,7 @@ #include <linux/slab.h> #include <asm/irq.h> -#include <asm/arch/corgi.h> +#include <asm/arch/sharpsl.h> #include <asm/arch/hardware.h> #include <asm/arch/pxa-regs.h> @@ -47,18 +47,20 @@ struct corgi_ts { struct ts_event tc; int pendown; int power_mode; + int irq_gpio; + struct corgits_machinfo *machinfo; }; -#define STATUS_HSYNC (GPLR(CORGI_GPIO_HSYNC) & GPIO_bit(CORGI_GPIO_HSYNC)) - -#define SyncHS() while((STATUS_HSYNC) == 0); while((STATUS_HSYNC) != 0); +#ifdef CONFIG_PXA25x #define CCNT(a) asm volatile ("mrc p14, 0, %0, C1, C0, 0" : "=r"(a)) -#define CCNT_ON() {int pmnc = 1; asm volatile ("mcr p14, 0, %0, C0, C0, 0" : : "r"(pmnc));} -#define CCNT_OFF() {int pmnc = 0; asm volatile ("mcr p14, 0, %0, C0, C0, 0" : : "r"(pmnc));} - -#define WAIT_HS_400_VGA 7013U // 17.615us -#define WAIT_HS_400_QVGA 16622U // 41.750us - +#define PMNC_GET(x) asm volatile ("mrc p14, 0, %0, C0, C0, 0" : "=r"(x)) +#define PMNC_SET(x) asm volatile ("mcr p14, 0, %0, C0, C0, 0" : : "r"(x)) +#endif +#ifdef CONFIG_PXA27x +#define CCNT(a) asm volatile ("mrc p14, 0, %0, C1, C1, 0" : "=r"(a)) +#define PMNC_GET(x) asm volatile ("mrc p14, 0, %0, C0, C1, 0" : "=r"(x)) +#define PMNC_SET(x) asm volatile ("mcr p14, 0, %0, C0, C1, 0" : : "r"(x)) +#endif /* ADS7846 Touch Screen Controller bit definitions */ #define ADSCTRL_PD0 (1u << 0) /* PD0 */ @@ -69,43 +71,31 @@ struct corgi_ts { #define ADSCTRL_STS (1u << 7) /* Start Bit */ /* External Functions */ -extern int w100fb_get_xres(void); -extern int w100fb_get_blanking(void); -extern int w100fb_get_fastsysclk(void); extern unsigned int get_clk_frequency_khz(int info); -static unsigned long calc_waittime(void) +static unsigned long calc_waittime(struct corgi_ts *corgi_ts) { - int w100fb_xres = w100fb_get_xres(); - unsigned int waittime = 0; - - if (w100fb_xres == 480 || w100fb_xres == 640) { - waittime = WAIT_HS_400_VGA * get_clk_frequency_khz(0) / 398131U; - - if (w100fb_get_fastsysclk() == 100) - waittime = waittime * 75 / 100; - - if (w100fb_xres == 640) - waittime *= 3; + unsigned long hsync_len = corgi_ts->machinfo->get_hsync_len(); - return waittime; - } - - return WAIT_HS_400_QVGA * get_clk_frequency_khz(0) / 398131U; + if (hsync_len) + return get_clk_frequency_khz(0)*1000/hsync_len; + else + return 0; } -static int sync_receive_data_send_cmd(int doRecive, int doSend, unsigned int address, unsigned long wait_time) +static int sync_receive_data_send_cmd(struct corgi_ts *corgi_ts, int doRecive, int doSend, + unsigned int address, unsigned long wait_time) { + unsigned long timer1 = 0, timer2, pmnc = 0; int pos = 0; - unsigned long timer1 = 0, timer2; - int dosleep; - dosleep = !w100fb_get_blanking(); + if (wait_time && doSend) { + PMNC_GET(pmnc); + if (!(pmnc & 0x01)) + PMNC_SET(0x01); - if (dosleep && doSend) { - CCNT_ON(); /* polling HSync */ - SyncHS(); + corgi_ts->machinfo->wait_hsync(); /* get CCNT */ CCNT(timer1); } @@ -119,12 +109,12 @@ static int sync_receive_data_send_cmd(int doRecive, int doSend, unsigned int add corgi_ssp_ads7846_put(cmd); corgi_ssp_ads7846_get(); - if (dosleep) { + if (wait_time) { /* Wait after HSync */ CCNT(timer2); if (timer2-timer1 > wait_time) { - /* timeout */ - SyncHS(); + /* too slow - timeout, try again */ + corgi_ts->machinfo->wait_hsync(); /* get OSCR */ CCNT(timer1); /* Wait after HSync */ @@ -134,8 +124,8 @@ static int sync_receive_data_send_cmd(int doRecive, int doSend, unsigned int add CCNT(timer2); } corgi_ssp_ads7846_put(cmd); - if (dosleep) - CCNT_OFF(); + if (wait_time && !(pmnc & 0x01)) + PMNC_SET(pmnc); } return pos; } @@ -148,23 +138,23 @@ static int read_xydata(struct corgi_ts *corgi_ts) /* critical section */ local_irq_save(flags); corgi_ssp_ads7846_lock(); - wait_time=calc_waittime(); + wait_time = calc_waittime(corgi_ts); /* Y-axis */ - sync_receive_data_send_cmd(0, 1, 1u, wait_time); + sync_receive_data_send_cmd(corgi_ts, 0, 1, 1u, wait_time); /* Y-axis */ - sync_receive_data_send_cmd(1, 1, 1u, wait_time); + sync_receive_data_send_cmd(corgi_ts, 1, 1, 1u, wait_time); /* X-axis */ - y = sync_receive_data_send_cmd(1, 1, 5u, wait_time); + y = sync_receive_data_send_cmd(corgi_ts, 1, 1, 5u, wait_time); /* Z1 */ - x = sync_receive_data_send_cmd(1, 1, 3u, wait_time); + x = sync_receive_data_send_cmd(corgi_ts, 1, 1, 3u, wait_time); /* Z2 */ - z1 = sync_receive_data_send_cmd(1, 1, 4u, wait_time); - z2 = sync_receive_data_send_cmd(1, 0, 4u, wait_time); + z1 = sync_receive_data_send_cmd(corgi_ts, 1, 1, 4u, wait_time); + z2 = sync_receive_data_send_cmd(corgi_ts, 1, 0, 4u, wait_time); /* Power-Down Enable */ corgi_ssp_ads7846_put((1u << ADSCTRL_ADR_SH) | ADSCTRL_STS); @@ -204,9 +194,9 @@ static void new_data(struct corgi_ts *corgi_ts, struct pt_regs *regs) static void ts_interrupt_main(struct corgi_ts *corgi_ts, int isTimer, struct pt_regs *regs) { - if ((GPLR(CORGI_GPIO_TP_INT) & GPIO_bit(CORGI_GPIO_TP_INT)) == 0) { + if ((GPLR(IRQ_TO_GPIO(corgi_ts->irq_gpio)) & GPIO_bit(IRQ_TO_GPIO(corgi_ts->irq_gpio))) == 0) { /* Disable Interrupt */ - set_irq_type(CORGI_IRQ_GPIO_TP_INT, IRQT_NOEDGE); + set_irq_type(corgi_ts->irq_gpio, IRQT_NOEDGE); if (read_xydata(corgi_ts)) { corgi_ts->pendown = 1; new_data(corgi_ts, regs); @@ -225,7 +215,7 @@ static void ts_interrupt_main(struct corgi_ts *corgi_ts, int isTimer, struct pt_ } /* Enable Falling Edge */ - set_irq_type(CORGI_IRQ_GPIO_TP_INT, IRQT_FALLING); + set_irq_type(corgi_ts->irq_gpio, IRQT_FALLING); corgi_ts->pendown = 0; } } @@ -244,7 +234,7 @@ static irqreturn_t ts_interrupt(int irq, void *dev_id, struct pt_regs *regs) } #ifdef CONFIG_PM -static int corgits_suspend(struct device *dev, uint32_t state, uint32_t level) +static int corgits_suspend(struct device *dev, pm_message_t state, uint32_t level) { if (level == SUSPEND_POWER_DOWN) { struct corgi_ts *corgi_ts = dev_get_drvdata(dev); @@ -269,7 +259,7 @@ static int corgits_resume(struct device *dev, uint32_t level) corgi_ssp_ads7846_putget((4u << ADSCTRL_ADR_SH) | ADSCTRL_STS); /* Enable Falling Edge */ - set_irq_type(CORGI_IRQ_GPIO_TP_INT, IRQT_FALLING); + set_irq_type(corgi_ts->irq_gpio, IRQT_FALLING); corgi_ts->power_mode = PWR_MODE_ACTIVE; } return 0; @@ -282,6 +272,7 @@ static int corgits_resume(struct device *dev, uint32_t level) static int __init corgits_probe(struct device *dev) { struct corgi_ts *corgi_ts; + struct platform_device *pdev = to_platform_device(dev); if (!(corgi_ts = kmalloc(sizeof(struct corgi_ts), GFP_KERNEL))) return -ENOMEM; @@ -290,6 +281,14 @@ static int __init corgits_probe(struct device *dev) memset(corgi_ts, 0, sizeof(struct corgi_ts)); + corgi_ts->machinfo = dev->platform_data; + corgi_ts->irq_gpio = platform_get_irq(pdev, 0); + + if (corgi_ts->irq_gpio < 0) { + kfree(corgi_ts); + return -ENODEV; + } + init_input_dev(&corgi_ts->input); corgi_ts->input.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); corgi_ts->input.keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH); @@ -308,8 +307,7 @@ static int __init corgits_probe(struct device *dev) corgi_ts->input.id.product = 0x0002; corgi_ts->input.id.version = 0x0100; - pxa_gpio_mode(CORGI_GPIO_TP_INT | GPIO_IN); - pxa_gpio_mode(CORGI_GPIO_HSYNC | GPIO_IN); + pxa_gpio_mode(IRQ_TO_GPIO(corgi_ts->irq_gpio) | GPIO_IN); /* Initiaize ADS7846 Difference Reference mode */ corgi_ssp_ads7846_putget((1u << ADSCTRL_ADR_SH) | ADSCTRL_STS); @@ -328,14 +326,14 @@ static int __init corgits_probe(struct device *dev) input_register_device(&corgi_ts->input); corgi_ts->power_mode = PWR_MODE_ACTIVE; - if (request_irq(CORGI_IRQ_GPIO_TP_INT, ts_interrupt, SA_INTERRUPT, "ts", corgi_ts)) { + if (request_irq(corgi_ts->irq_gpio, ts_interrupt, SA_INTERRUPT, "ts", corgi_ts)) { input_unregister_device(&corgi_ts->input); kfree(corgi_ts); return -EBUSY; } /* Enable Falling Edge */ - set_irq_type(CORGI_IRQ_GPIO_TP_INT, IRQT_FALLING); + set_irq_type(corgi_ts->irq_gpio, IRQT_FALLING); printk(KERN_INFO "input: Corgi Touchscreen Registered\n"); @@ -346,8 +344,9 @@ static int corgits_remove(struct device *dev) { struct corgi_ts *corgi_ts = dev_get_drvdata(dev); - free_irq(CORGI_IRQ_GPIO_TP_INT, NULL); + free_irq(corgi_ts->irq_gpio, NULL); del_timer_sync(&corgi_ts->timer); + corgi_ts->machinfo->put_hsync(); input_unregister_device(&corgi_ts->input); kfree(corgi_ts); return 0; |
