]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/commitdiff
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input
authorLinus Torvalds <torvalds@linux-foundation.org>
Wed, 7 Jan 2009 01:14:01 +0000 (17:14 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Wed, 7 Jan 2009 01:14:01 +0000 (17:14 -0800)
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input: (29 commits)
  Input: i8042 - add Dell Vostro 1510 to nomux list
  Input: gtco - use USB endpoint API
  Input: add support for Maple controller as a joystick
  Input: atkbd - broaden the Dell DMI signatures
  Input: HIL drivers - add MODULE_ALIAS()
  Input: map_to_7segment.h - convert to __inline__ for userspace
  Input: add support for enhanced rotary controller on pxa930 and pxa935
  Input: add support for trackball on pxa930 and pxa935
  Input: add da9034 touchscreen support
  Input: ads7846 - strict_strtoul takes unsigned long
  Input: make some variables and functions static
  Input: add tsc2007 based touchscreen driver
  Input: psmouse - add module parameters to control OLPC touchpad delays
  Input: i8042 - add Gigabyte M912 netbook to noloop exception table
  Input: atkbd - Samsung NC10 key repeat fix
  Input: atkbd - add keyboard quirk for HP Pavilion ZV6100 laptop
  Input: libps2 - handle 0xfc responses from devices
  Input: add support for Wacom W8001 penabled serial touchscreen
  Input: synaptics - report multi-taps only if supported by the device
  Input: add joystick driver for Walkera WK-0701 RC transmitter
  ...

54 files changed:
Documentation/input/walkera0701.txt [new file with mode: 0644]
arch/arm/mach-pxa/include/mach/pxa930_rotary.h [new file with mode: 0644]
arch/arm/mach-pxa/include/mach/pxa930_trkball.h [new file with mode: 0644]
drivers/input/Makefile
drivers/input/evbug.c
drivers/input/evdev.c
drivers/input/gameport/gameport.c
drivers/input/gameport/ns558.c
drivers/input/input-compat.c [new file with mode: 0644]
drivers/input/input-compat.h [new file with mode: 0644]
drivers/input/input.c
drivers/input/joydev.c
drivers/input/joystick/Kconfig
drivers/input/joystick/Makefile
drivers/input/joystick/maplecontrol.c [new file with mode: 0644]
drivers/input/joystick/walkera0701.c [new file with mode: 0644]
drivers/input/keyboard/Kconfig
drivers/input/keyboard/Makefile
drivers/input/keyboard/atkbd.c
drivers/input/keyboard/gpio_keys.c
drivers/input/keyboard/hil_kbd.c
drivers/input/keyboard/omap-keypad.c
drivers/input/keyboard/pxa930_rotary.c [new file with mode: 0644]
drivers/input/misc/pcspkr.c
drivers/input/misc/uinput.c
drivers/input/mouse/Kconfig
drivers/input/mouse/Makefile
drivers/input/mouse/appletouch.c
drivers/input/mouse/gpio_mouse.c
drivers/input/mouse/hgpk.c
drivers/input/mouse/hil_ptr.c
drivers/input/mouse/pxa930_trkball.c [new file with mode: 0644]
drivers/input/mouse/synaptics.c
drivers/input/mousedev.c
drivers/input/serio/hil_mlc.c
drivers/input/serio/i8042-x86ia64io.h
drivers/input/serio/libps2.c
drivers/input/serio/pcips2.c
drivers/input/serio/serio.c
drivers/input/serio/xilinx_ps2.c
drivers/input/tablet/gtco.c
drivers/input/tablet/wacom_wac.c
drivers/input/touchscreen/Kconfig
drivers/input/touchscreen/Makefile
drivers/input/touchscreen/ads7846.c
drivers/input/touchscreen/da9034-ts.c [new file with mode: 0644]
drivers/input/touchscreen/tsc2007.c [new file with mode: 0644]
drivers/input/touchscreen/usbtouchscreen.c
drivers/input/touchscreen/wacom_w8001.c [new file with mode: 0644]
include/linux/gpio_keys.h
include/linux/i2c/tsc2007.h [new file with mode: 0644]
include/linux/libps2.h
include/linux/map_to_7segment.h
include/linux/serio.h

diff --git a/Documentation/input/walkera0701.txt b/Documentation/input/walkera0701.txt
new file mode 100644 (file)
index 0000000..8f4289e
--- /dev/null
@@ -0,0 +1,109 @@
+
+Walkera WK-0701 transmitter is supplied with a ready to fly Walkera
+helicopters such as HM36, HM37, HM60. The walkera0701 module enables to use
+this transmitter as joystick
+
+Devel homepage and download:
+http://zub.fei.tuke.sk/walkera-wk0701/
+
+or use cogito:
+cg-clone http://zub.fei.tuke.sk/GIT/walkera0701-joystick
+
+
+Connecting to PC:
+
+At back side of transmitter S-video connector can be found. Modulation
+pulses from processor to HF part can be found at pin 2 of this connector,
+pin 3 is GND. Between pin 3 and CPU 5k6 resistor can be found. To get
+modulation pulses to PC, signal pulses must be amplified.
+
+Cable: (walkera TX to parport)
+
+Walkera WK-0701 TX S-VIDEO connector:
+ (back side of TX)
+     __   __              S-video:                                  canon25
+    /  |_|  \             pin 2 (signal)              NPN           parport
+   / O 4 3 O \            pin 3 (GND)        LED        ________________  10 ACK
+  ( O 2   1 O )                                         | C
+   \   ___   /      2 ________________________|\|_____|/
+    | [___] |                                 |/|   B |\
+     -------        3 __________________________________|________________ 25 GND
+                                                          E
+
+
+I use green LED and BC109 NPN transistor.
+
+Software:
+
+Build kernel with walkera0701 module. Module walkera0701 need exclusive
+access to parport, modules like lp must be unloaded before loading
+walkera0701 module, check dmesg for error messages. Connect TX to PC by
+cable and run jstest /dev/input/js0 to see values from TX. If no value can
+be changed by TX "joystick", check output from /proc/interrupts. Value for
+(usually irq7) parport must increase if TX is on.
+
+
+
+Technical details:
+
+Driver use interrupt from parport ACK input bit to measure pulse length
+using hrtimers.
+
+Frame format:
+Based on walkera WK-0701 PCM Format description by Shaul Eizikovich.
+(downloaded from http://www.smartpropoplus.com/Docs/Walkera_Wk-0701_PCM.pdf)
+
+Signal pulses:
+                   (ANALOG)
+    SYNC      BIN   OCT
+  +---------+      +------+
+  |         |      |      |
+--+         +------+      +---
+
+Frame:
+ SYNC , BIN1, OCT1, BIN2, OCT2 ... BIN24, OCT24, BIN25, next frame SYNC ..
+
+pulse length:
+   Binary values:              Analog octal values:
+
+   288 uS Binary 0             318 uS       000
+   438 uS Binary 1             398 uS       001
+                               478 uS       010
+                               558 uS       011
+                               638 uS       100
+  1306 uS SYNC                 718 uS       101
+                               798 uS       110
+                               878 uS       111
+
+24 bin+oct values + 1 bin value = 24*4+1 bits  = 97 bits
+
+(Warning, pulses on ACK ar inverted by transistor, irq is rised up on sync
+to bin change or octal value to bin change).
+
+Binary data representations:
+
+One binary and octal value can be grouped to nibble. 24 nibbles + one binary
+values can be sampled between sync pulses.
+
+Values for first four channels (analog joystick values) can be found in
+first 10 nibbles. Analog value is represented by one sign bit and 9 bit
+absolute binary value. (10 bits per channel). Next nibble is checksum for
+first ten nibbles.
+
+Next nibbles 12 .. 21 represents four channels (not all channels can be
+directly controlled from TX). Binary representations ar the same as in first
+four channels. In nibbles 22 and 23 is a special magic number. Nibble 24 is
+checksum for nibbles 12..23.
+
+After last octal value for nibble 24 and next sync pulse one additional
+binary value can be sampled. This bit and magic number is not used in
+software driver. Some details about this magic numbers can be found in
+Walkera_Wk-0701_PCM.pdf.
+
+Checksum calculation:
+
+Summary of octal values in nibbles must be same as octal value in checksum
+nibble (only first 3 bits are used). Binary value for checksum nibble is
+calculated by sum of binary values in checked nibbles + sum of octal values
+in checked nibbles divided by 8. Only bit 0 of this sum is used.
+
diff --git a/arch/arm/mach-pxa/include/mach/pxa930_rotary.h b/arch/arm/mach-pxa/include/mach/pxa930_rotary.h
new file mode 100644 (file)
index 0000000..053587c
--- /dev/null
@@ -0,0 +1,20 @@
+#ifndef __ASM_ARCH_PXA930_ROTARY_H
+#define __ASM_ARCH_PXA930_ROTARY_H
+
+/* NOTE:
+ *
+ * rotary can be either interpreted as a ralative input event (e.g.
+ * REL_WHEEL or REL_HWHEEL) or a specific key event (e.g. UP/DOWN
+ * or LEFT/RIGHT), depending on if up_key & down_key are assigned
+ * or rel_code is assigned a non-zero value. When all are non-zero,
+ * up_key and down_key will be preferred.
+ */
+struct pxa930_rotary_platform_data {
+       int     up_key;
+       int     down_key;
+       int     rel_code;
+};
+
+void __init pxa930_set_rotarykey_info(struct pxa930_rotary_platform_data *info);
+
+#endif /* __ASM_ARCH_PXA930_ROTARY_H */
diff --git a/arch/arm/mach-pxa/include/mach/pxa930_trkball.h b/arch/arm/mach-pxa/include/mach/pxa930_trkball.h
new file mode 100644 (file)
index 0000000..5e0789b
--- /dev/null
@@ -0,0 +1,10 @@
+#ifndef __ASM_ARCH_PXA930_TRKBALL_H
+#define __ASM_ARCH_PXA930_TRKBALL_H
+
+struct pxa930_trkball_platform_data {
+       int x_filter;
+       int y_filter;
+};
+
+#endif /* __ASM_ARCH_PXA930_TRKBALL_H */
+
index 98c4f9a778768d40af7a4942624caf8f46f13260..4c9c745a7020eefecf5984d1388e2b57ac37c814 100644 (file)
@@ -5,7 +5,7 @@
 # Each configuration option enables a list of files.
 
 obj-$(CONFIG_INPUT)            += input-core.o
-input-core-objs := input.o ff-core.o
+input-core-objs := input.o input-compat.o ff-core.o
 
 obj-$(CONFIG_INPUT_FF_MEMLESS) += ff-memless.o
 obj-$(CONFIG_INPUT_POLLDEV)    += input-polldev.o
index 0353601ac3b575e9a7e968387ec22d10fb88c04e..f7c5c14ec12ad933d5613fc4ea8c7a93cfa796e7 100644 (file)
@@ -39,7 +39,7 @@ MODULE_LICENSE("GPL");
 static void evbug_event(struct input_handle *handle, unsigned int type, unsigned int code, int value)
 {
        printk(KERN_DEBUG "evbug.c: Event. Dev: %s, Type: %d, Code: %d, Value: %d\n",
-               handle->dev->dev.bus_id, type, code, value);
+               dev_name(&handle->dev->dev), type, code, value);
 }
 
 static int evbug_connect(struct input_handler *handler, struct input_dev *dev,
@@ -65,7 +65,7 @@ static int evbug_connect(struct input_handler *handler, struct input_dev *dev,
                goto err_unregister_handle;
 
        printk(KERN_DEBUG "evbug.c: Connected device: %s (%s at %s)\n",
-               dev->dev.bus_id,
+               dev_name(&dev->dev),
                dev->name ?: "unknown",
                dev->phys ?: "unknown");
 
@@ -81,7 +81,7 @@ static int evbug_connect(struct input_handler *handler, struct input_dev *dev,
 static void evbug_disconnect(struct input_handle *handle)
 {
        printk(KERN_DEBUG "evbug.c: Disconnected device: %s\n",
-               handle->dev->dev.bus_id);
+               dev_name(&handle->dev->dev));
 
        input_close_device(handle);
        input_unregister_handle(handle);
index 1070db330d3563010668c2608c00db1c85369a1f..ed8baa0aec3cce31023a2e97557db22ab5a7f7c6 100644 (file)
@@ -19,7 +19,7 @@
 #include <linux/input.h>
 #include <linux/major.h>
 #include <linux/device.h>
-#include <linux/compat.h>
+#include "input-compat.h"
 
 struct evdev {
        int exist;
@@ -290,187 +290,6 @@ static int evdev_open(struct inode *inode, struct file *file)
        return error;
 }
 
-#ifdef CONFIG_COMPAT
-
-struct input_event_compat {
-       struct compat_timeval time;
-       __u16 type;
-       __u16 code;
-       __s32 value;
-};
-
-struct ff_periodic_effect_compat {
-       __u16 waveform;
-       __u16 period;
-       __s16 magnitude;
-       __s16 offset;
-       __u16 phase;
-
-       struct ff_envelope envelope;
-
-       __u32 custom_len;
-       compat_uptr_t custom_data;
-};
-
-struct ff_effect_compat {
-       __u16 type;
-       __s16 id;
-       __u16 direction;
-       struct ff_trigger trigger;
-       struct ff_replay replay;
-
-       union {
-               struct ff_constant_effect constant;
-               struct ff_ramp_effect ramp;
-               struct ff_periodic_effect_compat periodic;
-               struct ff_condition_effect condition[2]; /* One for each axis */
-               struct ff_rumble_effect rumble;
-       } u;
-};
-
-/* Note to the author of this code: did it ever occur to
-   you why the ifdefs are needed? Think about it again. -AK */
-#ifdef CONFIG_X86_64
-#  define COMPAT_TEST is_compat_task()
-#elif defined(CONFIG_IA64)
-#  define COMPAT_TEST IS_IA32_PROCESS(task_pt_regs(current))
-#elif defined(CONFIG_S390)
-#  define COMPAT_TEST test_thread_flag(TIF_31BIT)
-#elif defined(CONFIG_MIPS)
-#  define COMPAT_TEST test_thread_flag(TIF_32BIT_ADDR)
-#else
-#  define COMPAT_TEST test_thread_flag(TIF_32BIT)
-#endif
-
-static inline size_t evdev_event_size(void)
-{
-       return COMPAT_TEST ?
-               sizeof(struct input_event_compat) : sizeof(struct input_event);
-}
-
-static int evdev_event_from_user(const char __user *buffer,
-                                struct input_event *event)
-{
-       if (COMPAT_TEST) {
-               struct input_event_compat compat_event;
-
-               if (copy_from_user(&compat_event, buffer,
-                                  sizeof(struct input_event_compat)))
-                       return -EFAULT;
-
-               event->time.tv_sec = compat_event.time.tv_sec;
-               event->time.tv_usec = compat_event.time.tv_usec;
-               event->type = compat_event.type;
-               event->code = compat_event.code;
-               event->value = compat_event.value;
-
-       } else {
-               if (copy_from_user(event, buffer, sizeof(struct input_event)))
-                       return -EFAULT;
-       }
-
-       return 0;
-}
-
-static int evdev_event_to_user(char __user *buffer,
-                               const struct input_event *event)
-{
-       if (COMPAT_TEST) {
-               struct input_event_compat compat_event;
-
-               compat_event.time.tv_sec = event->time.tv_sec;
-               compat_event.time.tv_usec = event->time.tv_usec;
-               compat_event.type = event->type;
-               compat_event.code = event->code;
-               compat_event.value = event->value;
-
-               if (copy_to_user(buffer, &compat_event,
-                                sizeof(struct input_event_compat)))
-                       return -EFAULT;
-
-       } else {
-               if (copy_to_user(buffer, event, sizeof(struct input_event)))
-                       return -EFAULT;
-       }
-
-       return 0;
-}
-
-static int evdev_ff_effect_from_user(const char __user *buffer, size_t size,
-                                    struct ff_effect *effect)
-{
-       if (COMPAT_TEST) {
-               struct ff_effect_compat *compat_effect;
-
-               if (size != sizeof(struct ff_effect_compat))
-                       return -EINVAL;
-
-               /*
-                * It so happens that the pointer which needs to be changed
-                * is the last field in the structure, so we can copy the
-                * whole thing and replace just the pointer.
-                */
-
-               compat_effect = (struct ff_effect_compat *)effect;
-
-               if (copy_from_user(compat_effect, buffer,
-                                  sizeof(struct ff_effect_compat)))
-                       return -EFAULT;
-
-               if (compat_effect->type == FF_PERIODIC &&
-                   compat_effect->u.periodic.waveform == FF_CUSTOM)
-                       effect->u.periodic.custom_data =
-                               compat_ptr(compat_effect->u.periodic.custom_data);
-       } else {
-               if (size != sizeof(struct ff_effect))
-                       return -EINVAL;
-
-               if (copy_from_user(effect, buffer, sizeof(struct ff_effect)))
-                       return -EFAULT;
-       }
-
-       return 0;
-}
-
-#else
-
-static inline size_t evdev_event_size(void)
-{
-       return sizeof(struct input_event);
-}
-
-static int evdev_event_from_user(const char __user *buffer,
-                                struct input_event *event)
-{
-       if (copy_from_user(event, buffer, sizeof(struct input_event)))
-               return -EFAULT;
-
-       return 0;
-}
-
-static int evdev_event_to_user(char __user *buffer,
-                               const struct input_event *event)
-{
-       if (copy_to_user(buffer, event, sizeof(struct input_event)))
-               return -EFAULT;
-
-       return 0;
-}
-
-static int evdev_ff_effect_from_user(const char __user *buffer, size_t size,
-                                    struct ff_effect *effect)
-{
-       if (size != sizeof(struct ff_effect))
-               return -EINVAL;
-
-       if (copy_from_user(effect, buffer, sizeof(struct ff_effect)))
-               return -EFAULT;
-
-       return 0;
-}
-
-#endif /* CONFIG_COMPAT */
-
 static ssize_t evdev_write(struct file *file, const char __user *buffer,
                           size_t count, loff_t *ppos)
 {
@@ -490,14 +309,14 @@ static ssize_t evdev_write(struct file *file, const char __user *buffer,
 
        while (retval < count) {
 
-               if (evdev_event_from_user(buffer + retval, &event)) {
+               if (input_event_from_user(buffer + retval, &event)) {
                        retval = -EFAULT;
                        goto out;
                }
 
                input_inject_event(&evdev->handle,
                                   event.type, event.code, event.value);
-               retval += evdev_event_size();
+               retval += input_event_size();
        }
 
  out:
@@ -531,7 +350,7 @@ static ssize_t evdev_read(struct file *file, char __user *buffer,
        struct input_event event;
        int retval;
 
-       if (count < evdev_event_size())
+       if (count < input_event_size())
                return -EINVAL;
 
        if (client->head == client->tail && evdev->exist &&
@@ -546,13 +365,13 @@ static ssize_t evdev_read(struct file *file, char __user *buffer,
        if (!evdev->exist)
                return -ENODEV;
 
-       while (retval + evdev_event_size() <= count &&
+       while (retval + input_event_size() <= count &&
               evdev_fetch_next_event(client, &event)) {
 
-               if (evdev_event_to_user(buffer + retval, &event))
+               if (input_event_to_user(buffer + retval, &event))
                        return -EFAULT;
 
-               retval += evdev_event_size();
+               retval += input_event_size();
        }
 
        return retval;
@@ -823,7 +642,7 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd,
 
                        if (_IOC_NR(cmd) == _IOC_NR(EVIOCSFF)) {
 
-                               if (evdev_ff_effect_from_user(p, _IOC_SIZE(cmd), &effect))
+                               if (input_ff_effect_from_user(p, _IOC_SIZE(cmd), &effect))
                                        return -EFAULT;
 
                                error = input_ff_upload(dev, &effect, file);
@@ -1000,7 +819,7 @@ static int evdev_connect(struct input_handler *handler, struct input_dev *dev,
        evdev->handle.handler = handler;
        evdev->handle.private = evdev;
 
-       strlcpy(evdev->dev.bus_id, evdev->name, sizeof(evdev->dev.bus_id));
+       dev_set_name(&evdev->dev, evdev->name);
        evdev->dev.devt = MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + minor);
        evdev->dev.class = &input_class;
        evdev->dev.parent = &dev->dev;
index 2880eaae157a90896ce7785cea9b4e2c3c32dd4f..ebf4be5b7c4e7d56b39618aed449e2834d262576 100644 (file)
@@ -530,8 +530,7 @@ static void gameport_init_port(struct gameport *gameport)
 
        mutex_init(&gameport->drv_mutex);
        device_initialize(&gameport->dev);
-       snprintf(gameport->dev.bus_id, sizeof(gameport->dev.bus_id),
-                "gameport%lu", (unsigned long)atomic_inc_return(&gameport_no) - 1);
+       dev_set_name(&gameport->dev, "gameport%lu", (unsigned long)atomic_inc_return(&gameport_no) - 1);
        gameport->dev.bus = &gameport_bus;
        gameport->dev.release = gameport_release_port;
        if (gameport->parent)
index 2b282cde4b89bca7af7010f4127f6cfc93d81a8e..db556b71dddadc609568fbb772f0f6379a20b381 100644 (file)
@@ -226,7 +226,7 @@ static int ns558_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *did)
        ns558->gameport = port;
 
        gameport_set_name(port, "NS558 PnP Gameport");
-       gameport_set_phys(port, "pnp%s/gameport0", dev->dev.bus_id);
+       gameport_set_phys(port, "pnp%s/gameport0", dev_name(&dev->dev));
        port->dev.parent = &dev->dev;
        port->io = ioport;
 
diff --git a/drivers/input/input-compat.c b/drivers/input/input-compat.c
new file mode 100644 (file)
index 0000000..1accb89
--- /dev/null
@@ -0,0 +1,135 @@
+/*
+ * 32bit compatibility wrappers for the input subsystem.
+ *
+ * Very heavily based on evdev.c - Copyright (c) 1999-2002 Vojtech Pavlik
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ */
+
+#include <asm/uaccess.h>
+#include "input-compat.h"
+
+#ifdef CONFIG_COMPAT
+
+int input_event_from_user(const char __user *buffer,
+                         struct input_event *event)
+{
+       if (INPUT_COMPAT_TEST) {
+               struct input_event_compat compat_event;
+
+               if (copy_from_user(&compat_event, buffer,
+                                  sizeof(struct input_event_compat)))
+                       return -EFAULT;
+
+               event->time.tv_sec = compat_event.time.tv_sec;
+               event->time.tv_usec = compat_event.time.tv_usec;
+               event->type = compat_event.type;
+               event->code = compat_event.code;
+               event->value = compat_event.value;
+
+       } else {
+               if (copy_from_user(event, buffer, sizeof(struct input_event)))
+                       return -EFAULT;
+       }
+
+       return 0;
+}
+
+int input_event_to_user(char __user *buffer,
+                       const struct input_event *event)
+{
+       if (INPUT_COMPAT_TEST) {
+               struct input_event_compat compat_event;
+
+               compat_event.time.tv_sec = event->time.tv_sec;
+               compat_event.time.tv_usec = event->time.tv_usec;
+               compat_event.type = event->type;
+               compat_event.code = event->code;
+               compat_event.value = event->value;
+
+               if (copy_to_user(buffer, &compat_event,
+                                sizeof(struct input_event_compat)))
+                       return -EFAULT;
+
+       } else {
+               if (copy_to_user(buffer, event, sizeof(struct input_event)))
+                       return -EFAULT;
+       }
+
+       return 0;
+}
+
+int input_ff_effect_from_user(const char __user *buffer, size_t size,
+                             struct ff_effect *effect)
+{
+       if (INPUT_COMPAT_TEST) {
+               struct ff_effect_compat *compat_effect;
+
+               if (size != sizeof(struct ff_effect_compat))
+                       return -EINVAL;
+
+               /*
+                * It so happens that the pointer which needs to be changed
+                * is the last field in the structure, so we can retrieve the
+                * whole thing and replace just the pointer.
+                */
+               compat_effect = (struct ff_effect_compat *)effect;
+
+               if (copy_from_user(compat_effect, buffer,
+                                  sizeof(struct ff_effect_compat)))
+                       return -EFAULT;
+
+               if (compat_effect->type == FF_PERIODIC &&
+                   compat_effect->u.periodic.waveform == FF_CUSTOM)
+                       effect->u.periodic.custom_data =
+                               compat_ptr(compat_effect->u.periodic.custom_data);
+       } else {
+               if (size != sizeof(struct ff_effect))
+                       return -EINVAL;
+
+               if (copy_from_user(effect, buffer, sizeof(struct ff_effect)))
+                       return -EFAULT;
+       }
+
+       return 0;
+}
+
+#else
+
+int input_event_from_user(const char __user *buffer,
+                        struct input_event *event)
+{
+       if (copy_from_user(event, buffer, sizeof(struct input_event)))
+               return -EFAULT;
+
+       return 0;
+}
+
+int input_event_to_user(char __user *buffer,
+                       const struct input_event *event)
+{
+       if (copy_to_user(buffer, event, sizeof(struct input_event)))
+               return -EFAULT;
+
+       return 0;
+}
+
+int input_ff_effect_from_user(const char __user *buffer, size_t size,
+                             struct ff_effect *effect)
+{
+       if (size != sizeof(struct ff_effect))
+               return -EINVAL;
+
+       if (copy_from_user(effect, buffer, sizeof(struct ff_effect)))
+               return -EFAULT;
+
+       return 0;
+}
+
+#endif /* CONFIG_COMPAT */
+
+EXPORT_SYMBOL_GPL(input_event_from_user);
+EXPORT_SYMBOL_GPL(input_event_to_user);
+EXPORT_SYMBOL_GPL(input_ff_effect_from_user);
diff --git a/drivers/input/input-compat.h b/drivers/input/input-compat.h
new file mode 100644 (file)
index 0000000..47cd9ea
--- /dev/null
@@ -0,0 +1,94 @@
+#ifndef _INPUT_COMPAT_H
+#define _INPUT_COMPAT_H
+
+/*
+ * 32bit compatibility wrappers for the input subsystem.
+ *
+ * Very heavily based on evdev.c - Copyright (c) 1999-2002 Vojtech Pavlik
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ */
+
+#include <linux/compiler.h>
+#include <linux/compat.h>
+#include <linux/input.h>
+
+#ifdef CONFIG_COMPAT
+
+/* Note to the author of this code: did it ever occur to
+   you why the ifdefs are needed? Think about it again. -AK */
+#ifdef CONFIG_X86_64
+#  define INPUT_COMPAT_TEST is_compat_task()
+#elif defined(CONFIG_IA64)
+#  define INPUT_COMPAT_TEST IS_IA32_PROCESS(task_pt_regs(current))
+#elif defined(CONFIG_S390)
+#  define INPUT_COMPAT_TEST test_thread_flag(TIF_31BIT)
+#elif defined(CONFIG_MIPS)
+#  define INPUT_COMPAT_TEST test_thread_flag(TIF_32BIT_ADDR)
+#else
+#  define INPUT_COMPAT_TEST test_thread_flag(TIF_32BIT)
+#endif
+
+struct input_event_compat {
+       struct compat_timeval time;
+       __u16 type;
+       __u16 code;
+       __s32 value;
+};
+
+struct ff_periodic_effect_compat {
+       __u16 waveform;
+       __u16 period;
+       __s16 magnitude;
+       __s16 offset;
+       __u16 phase;
+
+       struct ff_envelope envelope;
+
+       __u32 custom_len;
+       compat_uptr_t custom_data;
+};
+
+struct ff_effect_compat {
+       __u16 type;
+       __s16 id;
+       __u16 direction;
+       struct ff_trigger trigger;
+       struct ff_replay replay;
+
+       union {
+               struct ff_constant_effect constant;
+               struct ff_ramp_effect ramp;
+               struct ff_periodic_effect_compat periodic;
+               struct ff_condition_effect condition[2]; /* One for each axis */
+               struct ff_rumble_effect rumble;
+       } u;
+};
+
+static inline size_t input_event_size(void)
+{
+       return INPUT_COMPAT_TEST ?
+               sizeof(struct input_event_compat) : sizeof(struct input_event);
+}
+
+#else
+
+static inline size_t input_event_size(void)
+{
+       return sizeof(struct input_event);
+}
+
+#endif /* CONFIG_COMPAT */
+
+int input_event_from_user(const char __user *buffer,
+                        struct input_event *event);
+
+int input_event_to_user(char __user *buffer,
+                       const struct input_event *event);
+
+int input_ff_effect_from_user(const char __user *buffer, size_t size,
+                             struct ff_effect *effect);
+
+#endif /* _INPUT_COMPAT_H */
index c13ced3e0d3dfe7d0db777776c1b51a2cf4f59e5..1730d7331a5dff13a6841fd0009066f49cde6666 100644 (file)
@@ -1389,8 +1389,8 @@ int input_register_device(struct input_dev *dev)
        if (!dev->setkeycode)
                dev->setkeycode = input_default_setkeycode;
 
-       snprintf(dev->dev.bus_id, sizeof(dev->dev.bus_id),
-                "input%ld", (unsigned long) atomic_inc_return(&input_no) - 1);
+       dev_set_name(&dev->dev, "input%ld",
+                    (unsigned long) atomic_inc_return(&input_no) - 1);
 
        error = device_add(&dev->dev);
        if (error)
index a85b1485e77499cd6afb15f46590b82951e1aa9e..6f2366220a50bd9c415f0b6986ded77bd309ffe0 100644 (file)
@@ -800,7 +800,7 @@ static int joydev_connect(struct input_handler *handler, struct input_dev *dev,
                }
        }
 
-       strlcpy(joydev->dev.bus_id, joydev->name, sizeof(joydev->dev.bus_id));
+       dev_set_name(&joydev->dev, joydev->name);
        joydev->dev.devt = MKDEV(INPUT_MAJOR, JOYDEV_MINOR_BASE + minor);
        joydev->dev.class = &input_class;
        joydev->dev.parent = &dev->dev;
index be5c14a5a0a4f8afcff50c18ee6ecd4343d44411..b11419590cfe21e61da8324f233d86fcf7a12209 100644 (file)
@@ -294,4 +294,28 @@ config JOYSTICK_XPAD_LEDS
          This option enables support for the LED which surrounds the Big X on
          XBox 360 controller.
 
+config JOYSTICK_WALKERA0701
+       tristate "Walkera WK-0701 RC transmitter"
+       depends on HIGH_RES_TIMERS && PARPORT
+       help
+         Say Y or M here if you have a Walkera WK-0701 transmitter which is
+         supplied with a ready to fly Walkera helicopters such as HM36,
+         HM37, HM60 and want to use it via parport as a joystick. More
+         information is available: <file:Documentation/input/walkera0701.txt>
+
+         To compile this driver as a module, choose M here: the
+         module will be called walkera0701.
+
+config JOYSTICK_MAPLE
+       tristate "Dreamcast control pad"
+       depends on MAPLE
+       help
+         Say Y here if you have a SEGA Dreamcast and want to use your
+         controller as a joystick.
+
+         Most Dreamcast users will say Y.
+
+         To compile this as a module choose M here: the module will be called
+         maplecontrol.
+
 endif
index fdbf8c4c2876083686f8fc868427776792f80997..f3a8cbe2abb69fc69089fb479cfd40b325a441f9 100644 (file)
@@ -19,6 +19,7 @@ obj-$(CONFIG_JOYSTICK_IFORCE)         += iforce/
 obj-$(CONFIG_JOYSTICK_INTERACT)                += interact.o
 obj-$(CONFIG_JOYSTICK_JOYDUMP)         += joydump.o
 obj-$(CONFIG_JOYSTICK_MAGELLAN)                += magellan.o
+obj-$(CONFIG_JOYSTICK_MAPLE)           += maplecontrol.o
 obj-$(CONFIG_JOYSTICK_SIDEWINDER)      += sidewinder.o
 obj-$(CONFIG_JOYSTICK_SPACEBALL)       += spaceball.o
 obj-$(CONFIG_JOYSTICK_SPACEORB)                += spaceorb.o
@@ -29,4 +30,5 @@ obj-$(CONFIG_JOYSTICK_TWIDJOY)                += twidjoy.o
 obj-$(CONFIG_JOYSTICK_WARRIOR)         += warrior.o
 obj-$(CONFIG_JOYSTICK_XPAD)            += xpad.o
 obj-$(CONFIG_JOYSTICK_ZHENHUA)         += zhenhua.o
+obj-$(CONFIG_JOYSTICK_WALKERA0701)     += walkera0701.o
 
diff --git a/drivers/input/joystick/maplecontrol.c b/drivers/input/joystick/maplecontrol.c
new file mode 100644 (file)
index 0000000..e50047b
--- /dev/null
@@ -0,0 +1,193 @@
+/*
+ *     SEGA Dreamcast controller driver
+ *     Based on drivers/usb/iforce.c
+ *
+ *     Copyright Yaegashi Takeshi, 2001
+ *     Adrian McMenamin, 2008
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/input.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/timer.h>
+#include <linux/maple.h>
+
+MODULE_AUTHOR("Adrian McMenamin <adrian@mcmen.demon.co.uk>");
+MODULE_DESCRIPTION("SEGA Dreamcast controller driver");
+MODULE_LICENSE("GPL");
+
+struct dc_pad {
+       struct input_dev *dev;
+       struct maple_device *mdev;
+};
+
+static void dc_pad_callback(struct mapleq *mq)
+{
+       unsigned short buttons;
+       struct maple_device *mapledev = mq->dev;
+       struct dc_pad *pad = maple_get_drvdata(mapledev);
+       struct input_dev *dev = pad->dev;
+       unsigned char *res = mq->recvbuf;
+
+       buttons = ~le16_to_cpup((__le16 *)(res + 8));
+
+       input_report_abs(dev, ABS_HAT0Y,
+               (buttons & 0x0010 ? -1 : 0) + (buttons & 0x0020 ? 1 : 0));
+       input_report_abs(dev, ABS_HAT0X,
+               (buttons & 0x0040 ? -1 : 0) + (buttons & 0x0080 ? 1 : 0));
+       input_report_abs(dev, ABS_HAT1Y,
+               (buttons & 0x1000 ? -1 : 0) + (buttons & 0x2000 ? 1 : 0));
+       input_report_abs(dev, ABS_HAT1X,
+               (buttons & 0x4000 ? -1 : 0) + (buttons & 0x8000 ? 1 : 0));
+
+       input_report_key(dev, BTN_C,      buttons & 0x0001);
+       input_report_key(dev, BTN_B,      buttons & 0x0002);
+       input_report_key(dev, BTN_A,      buttons & 0x0004);
+       input_report_key(dev, BTN_START,  buttons & 0x0008);
+       input_report_key(dev, BTN_Z,      buttons & 0x0100);
+       input_report_key(dev, BTN_Y,      buttons & 0x0200);
+       input_report_key(dev, BTN_X,      buttons & 0x0400);
+       input_report_key(dev, BTN_SELECT, buttons & 0x0800);
+
+       input_report_abs(dev, ABS_GAS,    res[10]);
+       input_report_abs(dev, ABS_BRAKE,  res[11]);
+       input_report_abs(dev, ABS_X,      res[12]);
+       input_report_abs(dev, ABS_Y,      res[13]);
+       input_report_abs(dev, ABS_RX,     res[14]);
+       input_report_abs(dev, ABS_RY,     res[15]);
+}
+
+static int dc_pad_open(struct input_dev *dev)
+{
+       struct dc_pad *pad = dev->dev.platform_data;
+
+       maple_getcond_callback(pad->mdev, dc_pad_callback, HZ/20,
+               MAPLE_FUNC_CONTROLLER);
+
+       return 0;
+}
+
+static void dc_pad_close(struct input_dev *dev)
+{
+       struct dc_pad *pad = dev->dev.platform_data;
+
+       maple_getcond_callback(pad->mdev, dc_pad_callback, 0,
+               MAPLE_FUNC_CONTROLLER);
+}
+
+/* allow the controller to be used */
+static int __devinit probe_maple_controller(struct device *dev)
+{
+       static const short btn_bit[32] = {
+               BTN_C, BTN_B, BTN_A, BTN_START, -1, -1, -1, -1,
+               BTN_Z, BTN_Y, BTN_X, BTN_SELECT, -1, -1, -1, -1,
+               -1, -1, -1, -1, -1, -1, -1, -1,
+               -1, -1, -1, -1, -1, -1, -1, -1,
+       };
+
+       static const short abs_bit[32] = {
+               -1, -1, -1, -1, ABS_HAT0Y, ABS_HAT0Y, ABS_HAT0X, ABS_HAT0X,
+               -1, -1, -1, -1, ABS_HAT1Y, ABS_HAT1Y, ABS_HAT1X, ABS_HAT1X,
+               ABS_GAS, ABS_BRAKE, ABS_X, ABS_Y, ABS_RX, ABS_RY, -1, -1,
+               -1, -1, -1, -1, -1, -1, -1, -1,
+       };
+
+       struct maple_device *mdev = to_maple_dev(dev);
+       struct maple_driver *mdrv = to_maple_driver(dev->driver);
+       int i, error;
+       struct dc_pad *pad;
+       struct input_dev *idev;
+       unsigned long data = be32_to_cpu(mdev->devinfo.function_data[0]);
+
+       pad = kzalloc(sizeof(struct dc_pad), GFP_KERNEL);
+       idev = input_allocate_device();
+       if (!pad || !idev) {
+               error = -ENOMEM;
+               goto fail;
+       }
+
+       pad->dev = idev;
+       pad->mdev = mdev;
+
+       idev->open = dc_pad_open;
+       idev->close = dc_pad_close;
+
+       for (i = 0; i < 32; i++) {
+               if (data & (1 << i)) {
+                       if (btn_bit[i] >= 0)
+                               __set_bit(btn_bit[i], idev->keybit);
+                       else if (abs_bit[i] >= 0)
+                               __set_bit(abs_bit[i], idev->absbit);
+               }
+       }
+
+       if (idev->keybit[BIT_WORD(BTN_JOYSTICK)])
+               idev->evbit[0] |= BIT_MASK(EV_KEY);
+
+       if (idev->absbit[0])
+               idev->evbit[0] |= BIT_MASK(EV_ABS);
+
+       for (i = ABS_X; i <= ABS_BRAKE; i++)
+               input_set_abs_params(idev, i, 0, 255, 0, 0);
+
+       for (i = ABS_HAT0X; i <= ABS_HAT3Y; i++)
+               input_set_abs_params(idev, i, 1, -1, 0, 0);
+
+       idev->dev.platform_data = pad;
+       idev->dev.parent = &mdev->dev;
+       idev->name = mdev->product_name;
+       idev->id.bustype = BUS_HOST;
+       input_set_drvdata(idev, pad);
+
+       error = input_register_device(idev);
+       if (error)
+               goto fail;
+
+       mdev->driver = mdrv;
+       maple_set_drvdata(mdev, pad);
+
+       return 0;
+
+fail:
+       input_free_device(idev);
+       kfree(pad);
+       maple_set_drvdata(mdev, NULL);
+       return error;
+}
+
+static int __devexit remove_maple_controller(struct device *dev)
+{
+       struct maple_device *mdev = to_maple_dev(dev);
+       struct dc_pad *pad = maple_get_drvdata(mdev);
+
+       mdev->callback = NULL;
+       input_unregister_device(pad->dev);
+       maple_set_drvdata(mdev, NULL);
+       kfree(pad);
+
+       return 0;
+}
+
+static struct maple_driver dc_pad_driver = {
+       .function =     MAPLE_FUNC_CONTROLLER,
+       .drv = {
+               .name   = "Dreamcast_controller",
+               .probe  = probe_maple_controller,
+               .remove = __devexit_p(remove_maple_controller),
+       },
+};
+
+static int __init dc_pad_init(void)
+{
+       return maple_driver_register(&dc_pad_driver);
+}
+
+static void __exit dc_pad_exit(void)
+{
+       maple_driver_unregister(&dc_pad_driver);
+}
+
+module_init(dc_pad_init);
+module_exit(dc_pad_exit);
diff --git a/drivers/input/joystick/walkera0701.c b/drivers/input/joystick/walkera0701.c
new file mode 100644 (file)
index 0000000..4dfa1ee
--- /dev/null
@@ -0,0 +1,292 @@
+/*
+ *  Parallel port to Walkera WK-0701 TX joystick
+ *
+ *  Copyright (c) 2008 Peter Popovec
+ *
+ *  More about driver:  <file:Documentation/input/walkera0701.txt>
+ */
+
+/*
+ * 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.
+*/
+
+/* #define WK0701_DEBUG */
+
+#define RESERVE 20000
+#define SYNC_PULSE 1306000
+#define BIN0_PULSE 288000
+#define BIN1_PULSE 438000
+
+#define ANALOG_MIN_PULSE 318000
+#define ANALOG_MAX_PULSE 878000
+#define ANALOG_DELTA 80000
+
+#define BIN_SAMPLE ((BIN0_PULSE + BIN1_PULSE) / 2)
+
+#define NO_SYNC 25
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/parport.h>
+#include <linux/input.h>
+#include <linux/hrtimer.h>
+
+MODULE_AUTHOR("Peter Popovec <popovec@fei.tuke.sk>");
+MODULE_DESCRIPTION("Walkera WK-0701 TX as joystick");
+MODULE_LICENSE("GPL");
+
+static unsigned int walkera0701_pp_no;
+module_param_named(port, walkera0701_pp_no, int, 0);
+MODULE_PARM_DESC(port,
+                "Parallel port adapter for Walkera WK-0701 TX (default is 0)");
+
+/*
+ * For now, only one device is supported, if somebody need more devices, code
+ * can be expanded, one struct walkera_dev per device must be allocated and
+ * set up by walkera0701_connect (release of device by walkera0701_disconnect)
+ */
+
+struct walkera_dev {
+       unsigned char buf[25];
+       u64 irq_time, irq_lasttime;
+       int counter;
+       int ack;
+
+       struct input_dev *input_dev;
+       struct hrtimer timer;
+
+       struct parport *parport;
+       struct pardevice *pardevice;
+};
+
+static struct walkera_dev w_dev;
+
+static inline void walkera0701_parse_frame(struct walkera_dev *w)
+{
+       int i;
+       int val1, val2, val3, val4, val5, val6, val7, val8;
+       int crc1, crc2;
+
+       for (crc1 = crc2 = i = 0; i < 10; i++) {
+               crc1 += w->buf[i] & 7;
+               crc2 += (w->buf[i] & 8) >> 3;
+       }
+       if ((w->buf[10] & 7) != (crc1 & 7))
+               return;
+       if (((w->buf[10] & 8) >> 3) != (((crc1 >> 3) + crc2) & 1))
+               return;
+       for (crc1 = crc2 = 0, i = 11; i < 23; i++) {
+               crc1 += w->buf[i] & 7;
+               crc2 += (w->buf[i] & 8) >> 3;
+       }
+       if ((w->buf[23] & 7) != (crc1 & 7))
+               return;
+       if (((w->buf[23] & 8) >> 3) != (((crc1 >> 3) + crc2) & 1))
+               return;
+       val1 = ((w->buf[0] & 7) * 256 + w->buf[1] * 16 + w->buf[2]) >> 2;
+       val1 *= ((w->buf[0] >> 2) & 2) - 1;     /* sign */
+       val2 = (w->buf[2] & 1) << 8 | (w->buf[3] << 4) | w->buf[4];
+       val2 *= (w->buf[2] & 2) - 1;    /* sign */
+       val3 = ((w->buf[5] & 7) * 256 + w->buf[6] * 16 + w->buf[7]) >> 2;
+       val3 *= ((w->buf[5] >> 2) & 2) - 1;     /* sign */
+       val4 = (w->buf[7] & 1) << 8 | (w->buf[8] << 4) | w->buf[9];
+       val4 *= (w->buf[7] & 2) - 1;    /* sign */
+       val5 = ((w->buf[11] & 7) * 256 + w->buf[12] * 16 + w->buf[13]) >> 2;
+       val5 *= ((w->buf[11] >> 2) & 2) - 1;    /* sign */
+       val6 = (w->buf[13] & 1) << 8 | (w->buf[14] << 4) | w->buf[15];
+       val6 *= (w->buf[13] & 2) - 1;   /* sign */
+       val7 = ((w->buf[16] & 7) * 256 + w->buf[17] * 16 + w->buf[18]) >> 2;
+       val7 *= ((w->buf[16] >> 2) & 2) - 1;    /*sign */
+       val8 = (w->buf[18] & 1) << 8 | (w->buf[19] << 4) | w->buf[20];
+       val8 *= (w->buf[18] & 2) - 1;   /*sign */
+
+#ifdef WK0701_DEBUG
+       {
+               int magic, magic_bit;
+               magic = (w->buf[21] << 4) | w->buf[22];
+               magic_bit = (w->buf[24] & 8) >> 3;
+               printk(KERN_DEBUG
+                      "walkera0701: %4d %4d %4d %4d  %4d %4d %4d %4d (magic %2x %d)\n",
+                      val1, val2, val3, val4, val5, val6, val7, val8, magic,
+                      magic_bit);
+       }
+#endif
+       input_report_abs(w->input_dev, ABS_X, val2);
+       input_report_abs(w->input_dev, ABS_Y, val1);
+       input_report_abs(w->input_dev, ABS_Z, val6);
+       input_report_abs(w->input_dev, ABS_THROTTLE, val3);
+       input_report_abs(w->input_dev, ABS_RUDDER, val4);
+       input_report_abs(w->input_dev, ABS_MISC, val7);
+       input_report_key(w->input_dev, BTN_GEAR_DOWN, val5 > 0);
+}
+
+static inline int read_ack(struct pardevice *p)
+{
+       return parport_read_status(p->port) & 0x40;
+}
+
+/* falling edge, prepare to BIN value calculation */
+static void walkera0701_irq_handler(void *handler_data)
+{
+       u64 pulse_time;
+       struct walkera_dev *w = handler_data;
+
+       w->irq_time = ktime_to_ns(ktime_get());
+       pulse_time = w->irq_time - w->irq_lasttime;
+       w->irq_lasttime = w->irq_time;
+
+       /* cancel timer, if in handler or active do resync */
+       if (unlikely(0 != hrtimer_try_to_cancel(&w->timer))) {
+               w->counter = NO_SYNC;
+               return;
+       }
+
+       if (w->counter < NO_SYNC) {
+               if (w->ack) {
+                       pulse_time -= BIN1_PULSE;
+                       w->buf[w->counter] = 8;
+               } else {
+                       pulse_time -= BIN0_PULSE;
+                       w->buf[w->counter] = 0;
+               }
+               if (w->counter == 24) { /* full frame */
+                       walkera0701_parse_frame(w);
+                       w->counter = NO_SYNC;
+                       if (abs(pulse_time - SYNC_PULSE) < RESERVE)     /* new frame sync */
+                               w->counter = 0;
+               } else {
+                       if ((pulse_time > (ANALOG_MIN_PULSE - RESERVE)
+                            && (pulse_time < (ANALOG_MAX_PULSE + RESERVE)))) {
+                               pulse_time -= (ANALOG_MIN_PULSE - RESERVE);
+                               pulse_time = (u32) pulse_time / ANALOG_DELTA;   /* overtiping is safe, pulsetime < s32.. */
+                               w->buf[w->counter++] |= (pulse_time & 7);
+                       } else
+                               w->counter = NO_SYNC;
+               }
+       } else if (abs(pulse_time - SYNC_PULSE - BIN0_PULSE) <
+                               RESERVE + BIN1_PULSE - BIN0_PULSE)      /* frame sync .. */
+               w->counter = 0;
+
+       hrtimer_start(&w->timer, ktime_set(0, BIN_SAMPLE), HRTIMER_MODE_REL);
+}
+
+static enum hrtimer_restart timer_handler(struct hrtimer
+                                         *handle)
+{
+       struct walkera_dev *w;
+
+       w = container_of(handle, struct walkera_dev, timer);
+       w->ack = read_ack(w->pardevice);
+
+       return HRTIMER_NORESTART;
+}
+
+static int walkera0701_open(struct input_dev *dev)
+{
+       struct walkera_dev *w = input_get_drvdata(dev);
+
+       parport_enable_irq(w->parport);
+       return 0;
+}
+
+static void walkera0701_close(struct input_dev *dev)
+{
+       struct walkera_dev *w = input_get_drvdata(dev);
+
+       parport_disable_irq(w->parport);
+}
+
+static int walkera0701_connect(struct walkera_dev *w, int parport)
+{
+       int err = -ENODEV;
+
+       w->parport = parport_find_number(parport);
+       if (w->parport == NULL)
+               return -ENODEV;
+
+       if (w->parport->irq == -1) {
+               printk(KERN_ERR "walkera0701: parport without interrupt\n");
+               goto init_err;
+       }
+
+       err = -EBUSY;
+       w->pardevice = parport_register_device(w->parport, "walkera0701",
+                                   NULL, NULL, walkera0701_irq_handler,
+                                   PARPORT_DEV_EXCL, w);
+       if (!w->pardevice)
+               goto init_err;
+
+       if (parport_negotiate(w->pardevice->port, IEEE1284_MODE_COMPAT))
+               goto init_err1;
+
+       if (parport_claim(w->pardevice))
+               goto init_err1;
+
+       w->input_dev = input_allocate_device();
+       if (!w->input_dev)
+               goto init_err2;
+
+       input_set_drvdata(w->input_dev, w);
+       w->input_dev->name = "Walkera WK-0701 TX";
+       w->input_dev->phys = w->parport->name;
+       w->input_dev->id.bustype = BUS_PARPORT;
+
+       /* TODO what id vendor/product/version ? */
+       w->input_dev->id.vendor = 0x0001;
+       w->input_dev->id.product = 0x0001;
+       w->input_dev->id.version = 0x0100;
+       w->input_dev->open = walkera0701_open;
+       w->input_dev->close = walkera0701_close;
+
+       w->input_dev->evbit[0] = BIT(EV_ABS) | BIT_MASK(EV_KEY);
+       w->input_dev->keybit[BIT_WORD(BTN_GEAR_DOWN)] = BIT_MASK(BTN_GEAR_DOWN);
+
+       input_set_abs_params(w->input_dev, ABS_X, -512, 512, 0, 0);
+       input_set_abs_params(w->input_dev, ABS_Y, -512, 512, 0, 0);
+       input_set_abs_params(w->input_dev, ABS_Z, -512, 512, 0, 0);
+       input_set_abs_params(w->input_dev, ABS_THROTTLE, -512, 512, 0, 0);
+       input_set_abs_params(w->input_dev, ABS_RUDDER, -512, 512, 0, 0);
+       input_set_abs_params(w->input_dev, ABS_MISC, -512, 512, 0, 0);
+
+       err = input_register_device(w->input_dev);
+       if (err)
+               goto init_err3;
+
+       hrtimer_init(&w->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+       w->timer.function = timer_handler;
+       return 0;
+
+ init_err3:
+       input_free_device(w->input_dev);
+ init_err2:
+       parport_release(w->pardevice);
+ init_err1:
+       parport_unregister_device(w->pardevice);
+ init_err:
+       parport_put_port(w->parport);
+       return err;
+}
+
+static void walkera0701_disconnect(struct walkera_dev *w)
+{
+       hrtimer_cancel(&w->timer);
+       input_unregister_device(w->input_dev);
+       parport_release(w->pardevice);
+       parport_unregister_device(w->pardevice);
+       parport_put_port(w->parport);
+}
+
+static int __init walkera0701_init(void)
+{
+       return walkera0701_connect(&w_dev, walkera0701_pp_no);
+}
+
+static void __exit walkera0701_exit(void)
+{
+       walkera0701_disconnect(&w_dev);
+}
+
+module_init(walkera0701_init);
+module_exit(walkera0701_exit);
index efd70a9745910bfacd97e39b4fdebe451fa14ca4..35561689ff38717f60ddc588493d7d02206f2008 100644 (file)
@@ -268,6 +268,15 @@ config KEYBOARD_PXA27x
          To compile this driver as a module, choose M here: the
          module will be called pxa27x_keypad.
 
+config KEYBOARD_PXA930_ROTARY
+       tristate "PXA930/PXA935 Enhanced Rotary Controller Support"
+       depends on CPU_PXA930 || CPU_PXA935
+       help
+         Enable support for PXA930/PXA935 Enhanced Rotary Controller.
+
+         To compile this driver as a module, choose M here: the
+         module will be called pxa930_rotary.
+
 config KEYBOARD_AAED2000
        tristate "AAED-2000 keyboard"
        depends on MACH_AAED2000
index 0edc8f285d1cf57f21a93eb4da8e6fa279920a7a..36351e1190f9e2db8d49da0ac1b6a941c8b547d1 100644 (file)
@@ -20,6 +20,7 @@ obj-$(CONFIG_KEYBOARD_HIL)            += hil_kbd.o
 obj-$(CONFIG_KEYBOARD_HIL_OLD)         += hilkbd.o
 obj-$(CONFIG_KEYBOARD_OMAP)            += omap-keypad.o
 obj-$(CONFIG_KEYBOARD_PXA27x)          += pxa27x_keypad.o
+obj-$(CONFIG_KEYBOARD_PXA930_ROTARY)   += pxa930_rotary.o
 obj-$(CONFIG_KEYBOARD_AAED2000)                += aaed2000_kbd.o
 obj-$(CONFIG_KEYBOARD_GPIO)            += gpio_keys.o
 obj-$(CONFIG_KEYBOARD_HP6XX)           += jornada680_kbd.o
index 379b7ff354ec7ba0036d3e1d1072b51eac61f1c3..f6e9f39a527b63d8d80b3b0448850090285b05ed 100644 (file)
@@ -883,6 +883,39 @@ static void atkbd_inventec_keymap_fixup(struct atkbd *atkbd)
                                  atkbd->force_release_mask);
 }
 
+/*
+ * Perform fixup for HP Pavilion ZV6100 laptop that doesn't generate release
+ * for its volume buttons
+ */
+static void atkbd_hp_zv6100_keymap_fixup(struct atkbd *atkbd)
+{
+       const unsigned int forced_release_keys[] = {
+               0xae, 0xb0,
+       };
+       int i;
+
+       if (atkbd->set == 2)
+               for (i = 0; i < ARRAY_SIZE(forced_release_keys); i++)
+                       __set_bit(forced_release_keys[i],
+                                       atkbd->force_release_mask);
+}
+
+/*
+ * Samsung NC10 with Fn+F? key release not working
+ */
+static void atkbd_samsung_keymap_fixup(struct atkbd *atkbd)
+{
+       const unsigned int forced_release_keys[] = {
+               0x82, 0x83, 0x84, 0x86, 0x88, 0x89, 0xb3, 0xf7, 0xf9,
+       };
+       int i;
+
+       if (atkbd->set == 2)
+               for (i = 0; i < ARRAY_SIZE(forced_release_keys); i++)
+                       __set_bit(forced_release_keys[i],
+                                 atkbd->force_release_mask);
+}
+
 /*
  * atkbd_set_keycode_table() initializes keyboard's keycode table
  * according to the selected scancode set
@@ -1475,6 +1508,15 @@ static struct dmi_system_id atkbd_dmi_quirk_table[] __initdata = {
                .callback = atkbd_setup_fixup,
                .driver_data = atkbd_dell_laptop_keymap_fixup,
        },
+       {
+               .ident = "Dell Laptop",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"),
+                       DMI_MATCH(DMI_CHASSIS_TYPE, "8"), /* Portable */
+               },
+               .callback = atkbd_setup_fixup,
+               .driver_data = atkbd_dell_laptop_keymap_fixup,
+       },
        {
                .ident = "HP 2133",
                .matches = {
@@ -1484,6 +1526,15 @@ static struct dmi_system_id atkbd_dmi_quirk_table[] __initdata = {
                .callback = atkbd_setup_fixup,
                .driver_data = atkbd_hp_keymap_fixup,
        },
+       {
+               .ident = "HP Pavilion ZV6100",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "Pavilion ZV6100"),
+               },
+               .callback = atkbd_setup_fixup,
+               .driver_data = atkbd_hp_zv6100_keymap_fixup,
+       },
        {
                .ident = "Inventec Symphony",
                .matches = {
@@ -1493,6 +1544,15 @@ static struct dmi_system_id atkbd_dmi_quirk_table[] __initdata = {
                .callback = atkbd_setup_fixup,
                .driver_data = atkbd_inventec_keymap_fixup,
        },
+       {
+               .ident = "Samsung NC10",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "NC10"),
+               },
+               .callback = atkbd_setup_fixup,
+               .driver_data = atkbd_samsung_keymap_fixup,
+       },
        { }
 };
 
index 05f3f43582c2c1e40658e2d8e6e77f8717210f38..ad67d763fdbda4137b46d166666e7fc53b36455b 100644 (file)
@@ -98,6 +98,10 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev)
        input->id.product = 0x0001;
        input->id.version = 0x0100;
 
+       /* Enable auto repeat feature of Linux input subsystem */
+       if (pdata->rep)
+               __set_bit(EV_REP, input->evbit);
+
        ddata->input = input;
 
        for (i = 0; i < pdata->nbuttons; i++) {
index 71c1971abf80873ba4a2a46590483b72428c4098..6f356705ee3bb9025937742cc558627ea0e60f03 100644 (file)
@@ -47,6 +47,7 @@
 MODULE_AUTHOR("Brian S. Julin <bri@calyx.com>");
 MODULE_DESCRIPTION(HIL_GENERIC_NAME " driver");
 MODULE_LICENSE("Dual BSD/GPL");
+MODULE_ALIAS("serio:ty03pr25id00ex*");
 
 #define HIL_KBD_MAX_LENGTH 16
 
index db22fd9b4cf2ca29243035e48ae1312d1dd341ed..3f3d1198cdb10dd76fb4973766ab9d6e1908d246 100644 (file)
@@ -122,14 +122,10 @@ static void omap_kp_scan_keypad(struct omap_kp *omap_kp, unsigned char *state)
 
        /* read the keypad status */
        if (cpu_is_omap24xx()) {
-               int i;
-               for (i = 0; i < omap_kp->rows; i++)
-                       disable_irq(OMAP_GPIO_IRQ(row_gpios[i]));
-
                /* read the keypad status */
                for (col = 0; col < omap_kp->cols; col++) {
                        set_col_gpio_val(omap_kp, ~(1 << col));
-                       state[col] = ~(get_row_gpio_val(omap_kp)) & 0x3f;
+                       state[col] = ~(get_row_gpio_val(omap_kp)) & 0xff;
                }
                set_col_gpio_val(omap_kp, 0);
 
diff --git a/drivers/input/keyboard/pxa930_rotary.c b/drivers/input/keyboard/pxa930_rotary.c
new file mode 100644 (file)
index 0000000..95fbba4
--- /dev/null
@@ -0,0 +1,212 @@
+/*
+ * Driver for the enhanced rotary controller on pxa930 and pxa935
+ *
+ * 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/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/input.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+
+#include <mach/pxa930_rotary.h>
+
+#define SBCR   (0x04)
+#define ERCR   (0x0c)
+
+#define SBCR_ERSB      (1 << 5)
+
+struct pxa930_rotary {
+       struct input_dev        *input_dev;
+       void __iomem            *mmio_base;
+       int                     last_ercr;
+
+       struct pxa930_rotary_platform_data *pdata;
+};
+
+static void clear_sbcr(struct pxa930_rotary *r)
+{
+       uint32_t sbcr = __raw_readl(r->mmio_base + SBCR);
+
+       __raw_writel(sbcr | SBCR_ERSB, r->mmio_base + SBCR);
+       __raw_writel(sbcr & ~SBCR_ERSB, r->mmio_base + SBCR);
+}
+
+static irqreturn_t rotary_irq(int irq, void *dev_id)
+{
+       struct pxa930_rotary *r = dev_id;
+       struct pxa930_rotary_platform_data *pdata = r->pdata;
+       int ercr, delta, key;
+
+       ercr = __raw_readl(r->mmio_base + ERCR) & 0xf;
+       clear_sbcr(r);
+
+       delta = ercr - r->last_ercr;
+       if (delta == 0)
+               return IRQ_HANDLED;
+
+       r->last_ercr = ercr;
+
+       if (pdata->up_key && pdata->down_key) {
+               key = (delta > 0) ? pdata->up_key : pdata->down_key;
+               input_report_key(r->input_dev, key, 1);
+               input_sync(r->input_dev);
+               input_report_key(r->input_dev, key, 0);
+       } else
+               input_report_rel(r->input_dev, pdata->rel_code, delta);
+
+       input_sync(r->input_dev);
+
+       return IRQ_HANDLED;
+}
+
+static int pxa930_rotary_open(struct input_dev *dev)
+{
+       struct pxa930_rotary *r = input_get_drvdata(dev);
+
+       clear_sbcr(r);
+
+       return 0;
+}
+
+static void pxa930_rotary_close(struct input_dev *dev)
+{
+       struct pxa930_rotary *r = input_get_drvdata(dev);
+
+       clear_sbcr(r);
+}
+
+static int __devinit pxa930_rotary_probe(struct platform_device *pdev)
+{
+       struct pxa930_rotary_platform_data *pdata = pdev->dev.platform_data;
+       struct pxa930_rotary *r;
+       struct input_dev *input_dev;
+       struct resource *res;
+       int irq;
+       int err;
+
+       irq = platform_get_irq(pdev, 0);
+       if (irq < 0) {
+               dev_err(&pdev->dev, "no irq for rotary controller\n");
+               return -ENXIO;
+       }
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res) {
+               dev_err(&pdev->dev, "no I/O memory defined\n");
+               return -ENXIO;
+       }
+
+       if (!pdata) {
+               dev_err(&pdev->dev, "no platform data defined\n");
+               return -EINVAL;
+       }
+
+       r = kzalloc(sizeof(struct pxa930_rotary), GFP_KERNEL);
+       if (!r)
+               return -ENOMEM;
+
+       r->mmio_base = ioremap_nocache(res->start, resource_size(res));
+       if (r->mmio_base == NULL) {
+               dev_err(&pdev->dev, "failed to remap IO memory\n");
+               err = -ENXIO;
+               goto failed_free;
+       }
+
+       r->pdata = pdata;
+       platform_set_drvdata(pdev, r);
+
+       /* allocate and register the input device */
+       input_dev = input_allocate_device();
+       if (!input_dev) {
+               dev_err(&pdev->dev, "failed to allocate input device\n");
+               err = -ENOMEM;
+               goto failed_free_io;
+       }
+
+       input_dev->name = pdev->name;
+       input_dev->id.bustype = BUS_HOST;
+       input_dev->open = pxa930_rotary_open;
+       input_dev->close = pxa930_rotary_close;
+       input_dev->dev.parent = &pdev->dev;
+
+       if (pdata->up_key && pdata->down_key) {
+               __set_bit(pdata->up_key, input_dev->keybit);
+               __set_bit(pdata->down_key, input_dev->keybit);
+               __set_bit(EV_KEY, input_dev->evbit);
+       } else {
+               __set_bit(pdata->rel_code, input_dev->relbit);
+               __set_bit(EV_REL, input_dev->evbit);
+       }
+
+       r->input_dev = input_dev;
+       input_set_drvdata(input_dev, r);
+
+       err = request_irq(irq, rotary_irq, IRQF_DISABLED,
+                       "enhanced rotary", r);
+       if (err) {
+               dev_err(&pdev->dev, "failed to request IRQ\n");
+               goto failed_free_input;
+       }
+
+       err = input_register_device(input_dev);
+       if (err) {
+               dev_err(&pdev->dev, "failed to register input device\n");
+               goto failed_free_irq;
+       }
+
+       return 0;
+
+failed_free_irq:
+       free_irq(irq, r);
+failed_free_input:
+       input_free_device(input_dev);
+failed_free_io:
+       iounmap(r->mmio_base);
+failed_free:
+       kfree(r);
+       return err;
+}
+
+static int __devexit pxa930_rotary_remove(struct platform_device *pdev)
+{
+       struct pxa930_rotary *r = platform_get_drvdata(pdev);
+
+       free_irq(platform_get_irq(pdev, 0), r);
+       input_unregister_device(r->input_dev);
+       iounmap(r->mmio_base);
+       platform_set_drvdata(pdev, NULL);
+       kfree(r);
+
+       return 0;
+}
+
+static struct platform_driver pxa930_rotary_driver = {
+       .driver         = {
+               .name   = "pxa930-rotary",
+               .owner  = THIS_MODULE,
+       },
+       .probe          = pxa930_rotary_probe,
+       .remove         = __devexit_p(pxa930_rotary_remove),
+};
+
+static int __init pxa930_rotary_init(void)
+{
+       return platform_driver_register(&pxa930_rotary_driver);
+}
+module_init(pxa930_rotary_init);
+
+static void __exit pxa930_rotary_exit(void)
+{
+       platform_driver_unregister(&pxa930_rotary_driver);
+}
+module_exit(pxa930_rotary_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Driver for PXA93x Enhanced Rotary Controller");
+MODULE_AUTHOR("Yao Yong <yaoyong@marvell.com>");
index 43aaa5cebd1224f8a39dcac296546c49f73597f2..d6a30cee7bc79b63f5ed124d48dc36ac55bd9e05 100644 (file)
@@ -52,13 +52,13 @@ static int pcspkr_event(struct input_dev *dev, unsigned int type, unsigned int c
        spin_lock_irqsave(&i8253_lock, flags);
 
        if (count) {
-               /* enable counter 2 */
-               outb_p(inb_p(0x61) | 3, 0x61);
                /* set command for counter 2, 2 byte write */
                outb_p(0xB6, 0x43);
                /* select desired HZ */
                outb_p(count & 0xff, 0x42);
                outb((count >> 8) & 0xff, 0x42);
+               /* enable counter 2 */
+               outb_p(inb_p(0x61) | 3, 0x61);
        } else {
                /* disable counter 2 */
                outb(inb_p(0x61) & 0xFC, 0x61);
index 223d56d5555b345e9068e9d7957e8843f980c032..46b7caeb2817f3363eda4570d52e8bc1bdeedc00 100644 (file)
@@ -37,6 +37,7 @@
 #include <linux/fs.h>
 #include <linux/miscdevice.h>
 #include <linux/uinput.h>
+#include "../input-compat.h"
 
 static int uinput_dev_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
 {
@@ -78,6 +79,7 @@ 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;
+
        return udev->requests[id];
 }
 
@@ -127,6 +129,17 @@ static int uinput_dev_upload_effect(struct input_dev *dev, struct ff_effect *eff
        struct uinput_request request;
        int retval;
 
+       /*
+        * uinput driver does not currently support periodic effects with
+        * custom waveform since it does not have a way to pass buffer of
+        * samples (custom_data) to userspace. If ever there is a device
+        * supporting custom waveforms we would need to define an additional
+        * ioctl (UI_UPLOAD_SAMPLES) but for now we just bail out.
+        */
+       if (effect->type == FF_PERIODIC &&
+                       effect->u.periodic.waveform == FF_CUSTOM)
+               return -EINVAL;
+
        request.id = -1;
        init_completion(&request.done);
        request.code = UI_FF_UPLOAD;
@@ -353,15 +366,15 @@ static inline ssize_t uinput_inject_event(struct uinput_device *udev, const char
 {
        struct input_event ev;
 
-       if (count != sizeof(struct input_event))
+       if (count < input_event_size())
                return -EINVAL;
 
-       if (copy_from_user(&ev, buffer, sizeof(struct input_event)))
+       if (input_event_from_user(buffer, &ev))
                return -EFAULT;
 
        input_event(udev->dev, ev.type, ev.code, ev.value);
 
-       return sizeof(struct input_event);
+       return input_event_size();
 }
 
 static ssize_t uinput_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
@@ -407,13 +420,13 @@ static ssize_t uinput_read(struct file *file, char __user *buffer, size_t count,
                goto out;
        }
 
-       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))) {
+       while (udev->head != udev->tail && retval + input_event_size() <= count) {
+               if (input_event_to_user(buffer + retval, &udev->buff[udev->tail])) {
                        retval = -EFAULT;
                        goto out;
                }
                udev->tail = (udev->tail + 1) % UINPUT_BUFFER_SIZE;
-               retval += sizeof(struct input_event);
+               retval += input_event_size();
        }
 
  out:
@@ -444,6 +457,93 @@ static int uinput_release(struct inode *inode, struct file *file)
        return 0;
 }
 
+#ifdef CONFIG_COMPAT
+struct uinput_ff_upload_compat {
+       int                     request_id;
+       int                     retval;
+       struct ff_effect_compat effect;
+       struct ff_effect_compat old;
+};
+
+static int uinput_ff_upload_to_user(char __user *buffer,
+                                   const struct uinput_ff_upload *ff_up)
+{
+       if (INPUT_COMPAT_TEST) {
+               struct uinput_ff_upload_compat ff_up_compat;
+
+               ff_up_compat.request_id = ff_up->request_id;
+               ff_up_compat.retval = ff_up->retval;
+               /*
+                * It so happens that the pointer that gives us the trouble
+                * is the last field in the structure. Since we don't support
+                * custom waveforms in uinput anyway we can just copy the whole
+                * thing (to the compat size) and ignore the pointer.
+                */
+               memcpy(&ff_up_compat.effect, &ff_up->effect,
+                       sizeof(struct ff_effect_compat));
+               memcpy(&ff_up_compat.old, &ff_up->old,
+                       sizeof(struct ff_effect_compat));
+
+               if (copy_to_user(buffer, &ff_up_compat,
+                                sizeof(struct uinput_ff_upload_compat)))
+                       return -EFAULT;
+       } else {
+               if (copy_to_user(buffer, ff_up,
+                                sizeof(struct uinput_ff_upload)))
+                       return -EFAULT;
+       }
+
+       return 0;
+}
+
+static int uinput_ff_upload_from_user(const char __user *buffer,
+                                     struct uinput_ff_upload *ff_up)
+{
+       if (INPUT_COMPAT_TEST) {
+               struct uinput_ff_upload_compat ff_up_compat;
+
+               if (copy_from_user(&ff_up_compat, buffer,
+                                  sizeof(struct uinput_ff_upload_compat)))
+                       return -EFAULT;
+
+               ff_up->request_id = ff_up_compat.request_id;
+               ff_up->retval = ff_up_compat.retval;
+               memcpy(&ff_up->effect, &ff_up_compat.effect,
+                       sizeof(struct ff_effect_compat));
+               memcpy(&ff_up->old, &ff_up_compat.old,
+                       sizeof(struct ff_effect_compat));
+
+       } else {
+               if (copy_from_user(ff_up, buffer,
+                                  sizeof(struct uinput_ff_upload)))
+                       return -EFAULT;
+       }
+
+       return 0;
+}
+
+#else
+
+static int uinput_ff_upload_to_user(char __user *buffer,
+                                   const struct uinput_ff_upload *ff_up)
+{
+       if (copy_to_user(buffer, ff_up, sizeof(struct uinput_ff_upload)))
+               return -EFAULT;
+
+       return 0;
+}
+
+static int uinput_ff_upload_from_user(const char __user *buffer,
+                                     struct uinput_ff_upload *ff_up)
+{
+       if (copy_from_user(ff_up, buffer, sizeof(struct uinput_ff_upload)))
+               return -EFAULT;
+
+       return 0;
+}
+
+#endif
+
 #define uinput_set_bit(_arg, _bit, _max)               \
 ({                                                     \
        int __ret = 0;                                  \
@@ -455,19 +555,17 @@ static int uinput_release(struct inode *inode, struct file *file)
        __ret;                                          \
 })
 
-static long uinput_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+static long uinput_ioctl_handler(struct file *file, unsigned int cmd,
+                                unsigned long arg, void __user *p)
 {
        int                     retval;
-       struct uinput_device    *udev;
-       void __user             *p = (void __user *)arg;
+       struct uinput_device    *udev = file->private_data;
        struct uinput_ff_upload ff_up;
        struct uinput_ff_erase  ff_erase;
        struct uinput_request   *req;
        int                     length;
        char                    *phys;
 
-       udev = file->private_data;
-
        retval = mutex_lock_interruptible(&udev->mutex);
        if (retval)
                return retval;
@@ -549,26 +647,24 @@ static long uinput_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
                        break;
 
                case UI_BEGIN_FF_UPLOAD:
-                       if (copy_from_user(&ff_up, p, sizeof(ff_up))) {
-                               retval = -EFAULT;
+                       retval = uinput_ff_upload_from_user(p, &ff_up);
+                       if (retval)
                                break;
-                       }
+
                        req = uinput_request_find(udev, ff_up.request_id);
-                       if (!(req && req->code == UI_FF_UPLOAD && req->u.upload.effect)) {
+                       if (!req || req->code != UI_FF_UPLOAD || !req->u.upload.effect) {
                                retval = -EINVAL;
                                break;
                        }
+
                        ff_up.retval = 0;
-                       memcpy(&ff_up.effect, req->u.upload.effect, sizeof(struct ff_effect));
+                       ff_up.effect = *req->u.upload.effect;
                        if (req->u.upload.old)
-                               memcpy(&ff_up.old, req->u.upload.old, sizeof(struct ff_effect));
+                               ff_up.old = *req->u.upload.old;
                        else
                                memset(&ff_up.old, 0, sizeof(struct ff_effect));
 
-                       if (copy_to_user(p, &ff_up, sizeof(ff_up))) {
-                               retval = -EFAULT;
-                               break;
-                       }
+                       retval = uinput_ff_upload_to_user(p, &ff_up);
                        break;
 
                case UI_BEGIN_FF_ERASE:
@@ -576,29 +672,34 @@ static long uinput_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
                                retval = -EFAULT;
                                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;
                        }
+
                        ff_erase.retval = 0;
                        ff_erase.effect_id = req->u.effect_id;
                        if (copy_to_user(p, &ff_erase, sizeof(ff_erase))) {
                                retval = -EFAULT;
                                break;
                        }
+
                        break;
 
                case UI_END_FF_UPLOAD:
-                       if (copy_from_user(&ff_up, p, sizeof(ff_up))) {
-                               retval = -EFAULT;
+                       retval = uinput_ff_upload_from_user(p, &ff_up);
+                       if (retval)
                                break;
-                       }
+
                        req = uinput_request_find(udev, ff_up.request_id);
-                       if (!(req && req->code == UI_FF_UPLOAD && req->u.upload.effect)) {
+                       if (!req || req->code != UI_FF_UPLOAD ||
+                           !req->u.upload.effect) {
                                retval = -EINVAL;
                                break;
                        }
+
                        req->retval = ff_up.retval;
                        uinput_request_done(udev, req);
                        break;
@@ -608,11 +709,13 @@ static long uinput_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
                                retval = -EFAULT;
                                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;
                        uinput_request_done(udev, req);
                        break;
@@ -626,6 +729,18 @@ static long uinput_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
        return retval;
 }
 
+static long uinput_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+       return uinput_ioctl_handler(file, cmd, arg, (void __user *)arg);
+}
+
+#ifdef CONFIG_COMPAT
+static long uinput_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+       return uinput_ioctl_handler(file, cmd, arg, compat_ptr(arg));
+}
+#endif
+
 static const struct file_operations uinput_fops = {
        .owner          = THIS_MODULE,
        .open           = uinput_open,
@@ -634,6 +749,9 @@ static const struct file_operations uinput_fops = {
        .write          = uinput_write,
        .poll           = uinput_poll,
        .unlocked_ioctl = uinput_ioctl,
+#ifdef CONFIG_COMPAT
+       .compat_ioctl   = uinput_compat_ioctl,
+#endif
 };
 
 static struct miscdevice uinput_misc = {
index 4e993425977558b4a79d408f023149d6b492339c..093c8c1bca746b651a4c18ab260931a02dac5dae 100644 (file)
@@ -286,4 +286,10 @@ config MOUSE_GPIO
          To compile this driver as a module, choose M here: the
          module will be called gpio_mouse.
 
+config MOUSE_PXA930_TRKBALL
+       tristate "PXA930 Trackball mouse"
+       depends on CPU_PXA930 || CPU_PXA935
+       help
+         Say Y here to support PXA930 Trackball mouse.
+
 endif
index 96f1dd8037f8dfa19562e8d7a200321b6e3c02d5..8c8a1f236e28cded7f6ade983da64c90445aa999 100644 (file)
@@ -4,19 +4,20 @@
 
 # Each configuration option enables a list of files.
 
-obj-$(CONFIG_MOUSE_AMIGA)      += amimouse.o
-obj-$(CONFIG_MOUSE_APPLETOUCH) += appletouch.o
-obj-$(CONFIG_MOUSE_BCM5974)    += bcm5974.o
-obj-$(CONFIG_MOUSE_ATARI)      += atarimouse.o
-obj-$(CONFIG_MOUSE_RISCPC)     += rpcmouse.o
-obj-$(CONFIG_MOUSE_INPORT)     += inport.o
-obj-$(CONFIG_MOUSE_LOGIBM)     += logibm.o
-obj-$(CONFIG_MOUSE_PC110PAD)   += pc110pad.o
-obj-$(CONFIG_MOUSE_PS2)                += psmouse.o
-obj-$(CONFIG_MOUSE_SERIAL)     += sermouse.o
-obj-$(CONFIG_MOUSE_HIL)                += hil_ptr.o
-obj-$(CONFIG_MOUSE_VSXXXAA)    += vsxxxaa.o
-obj-$(CONFIG_MOUSE_GPIO)       += gpio_mouse.o
+obj-$(CONFIG_MOUSE_AMIGA)              += amimouse.o
+obj-$(CONFIG_MOUSE_APPLETOUCH)         += appletouch.o
+obj-$(CONFIG_MOUSE_BCM5974)            += bcm5974.o
+obj-$(CONFIG_MOUSE_ATARI)              += atarimouse.o
+obj-$(CONFIG_MOUSE_RISCPC)             += rpcmouse.o
+obj-$(CONFIG_MOUSE_INPORT)             += inport.o
+obj-$(CONFIG_MOUSE_LOGIBM)             += logibm.o
+obj-$(CONFIG_MOUSE_PC110PAD)           += pc110pad.o
+obj-$(CONFIG_MOUSE_PS2)                        += psmouse.o
+obj-$(CONFIG_MOUSE_PXA930_TRKBALL)     += pxa930_trkball.o
+obj-$(CONFIG_MOUSE_SERIAL)             += sermouse.o
+obj-$(CONFIG_MOUSE_HIL)                        += hil_ptr.o
+obj-$(CONFIG_MOUSE_VSXXXAA)            += vsxxxaa.o
+obj-$(CONFIG_MOUSE_GPIO)               += gpio_mouse.o
 
 psmouse-objs := psmouse-base.o synaptics.o
 
index 079816e6b23b042bff9a883aa984ffea757ee5a6..454b96112f03187b5e5c9ea042af86c166902332 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (C) 2001-2004 Greg Kroah-Hartman (greg@kroah.com)
  * Copyright (C) 2005-2008 Johannes Berg (johannes@sipsolutions.net)
- * Copyright (C) 2005      Stelian Pop (stelian@popies.net)
+ * Copyright (C) 2005-2008 Stelian Pop (stelian@popies.net)
  * Copyright (C) 2005      Frank Arnold (frank@scirocco-5v-turbo.de)
  * Copyright (C) 2005      Peter Osterlund (petero2@telia.com)
  * Copyright (C) 2005      Michael Hanselmann (linux-kernel@hansmi.ch)
 #include <linux/module.h>
 #include <linux/usb/input.h>
 
-/* Type of touchpad */
-enum atp_touchpad_type {
-       ATP_FOUNTAIN,
-       ATP_GEYSER1,
-       ATP_GEYSER2,
-       ATP_GEYSER3,
-       ATP_GEYSER4
+/*
+ * Note: We try to keep the touchpad aspect ratio while still doing only
+ * simple arithmetics:
+ *     0 <= x <= (xsensors - 1) * xfact
+ *     0 <= y <= (ysensors - 1) * yfact
+ */
+struct atp_info {
+       int xsensors;                           /* number of X sensors */
+       int xsensors_17;                        /* 17" models have more sensors */
+       int ysensors;                           /* number of Y sensors */
+       int xfact;                              /* X multiplication factor */
+       int yfact;                              /* Y multiplication factor */
+       int datalen;                            /* size of USB transfers */
+       void (*callback)(struct urb *);         /* callback function */
+};
+
+static void atp_complete_geyser_1_2(struct urb *urb);
+static void atp_complete_geyser_3_4(struct urb *urb);
+
+static const struct atp_info fountain_info = {
+       .xsensors       = 16,
+       .xsensors_17    = 26,
+       .ysensors       = 16,
+       .xfact          = 64,
+       .yfact          = 43,
+       .datalen        = 81,
+       .callback       = atp_complete_geyser_1_2,
+};
+
+static const struct atp_info geyser1_info = {
+       .xsensors       = 16,
+       .xsensors_17    = 26,
+       .ysensors       = 16,
+       .xfact          = 64,
+       .yfact          = 43,
+       .datalen        = 81,
+       .callback       = atp_complete_geyser_1_2,
+};
+
+static const struct atp_info geyser2_info = {
+       .xsensors       = 15,
+       .xsensors_17    = 20,
+       .ysensors       = 9,
+       .xfact          = 64,
+       .yfact          = 43,
+       .datalen        = 64,
+       .callback       = atp_complete_geyser_1_2,
+};
+
+static const struct atp_info geyser3_info = {
+       .xsensors       = 20,
+       .ysensors       = 10,
+       .xfact          = 64,
+       .yfact          = 64,
+       .datalen        = 64,
+       .callback       = atp_complete_geyser_3_4,
 };
 
-#define ATP_DEVICE(prod, type)                                 \
+static const struct atp_info geyser4_info = {
+       .xsensors       = 20,
+       .ysensors       = 10,
+       .xfact          = 64,
+       .yfact          = 64,
+       .datalen        = 64,
+       .callback       = atp_complete_geyser_3_4,
+};
+
+#define ATP_DEVICE(prod, info)                                 \
 {                                                              \
        .match_flags = USB_DEVICE_ID_MATCH_DEVICE |             \
                       USB_DEVICE_ID_MATCH_INT_CLASS |          \
@@ -53,7 +111,7 @@ enum atp_touchpad_type {
        .idProduct = (prod),                                    \
        .bInterfaceClass = 0x03,                                \
        .bInterfaceProtocol = 0x02,                             \
-       .driver_info = ATP_ ## type,                            \
+       .driver_info = (unsigned long) &info,                   \
 }
 
 /*
@@ -62,43 +120,39 @@ enum atp_touchpad_type {
  *  According to Info.plist Geyser IV is the same as Geyser III.)
  */
 
-static struct usb_device_id atp_table [] = {
+static struct usb_device_id atp_table[] = {
        /* PowerBooks Feb 2005, iBooks G4 */
-       ATP_DEVICE(0x020e, FOUNTAIN),   /* FOUNTAIN ANSI */
-       ATP_DEVICE(0x020f, FOUNTAIN),   /* FOUNTAIN ISO */
-       ATP_DEVICE(0x030a, FOUNTAIN),   /* FOUNTAIN TP ONLY */
-       ATP_DEVICE(0x030b, GEYSER1),    /* GEYSER 1 TP ONLY */
+       ATP_DEVICE(0x020e, fountain_info),      /* FOUNTAIN ANSI */
+       ATP_DEVICE(0x020f, fountain_info),      /* FOUNTAIN ISO */
+       ATP_DEVICE(0x030a, fountain_info),      /* FOUNTAIN TP ONLY */
+       ATP_DEVICE(0x030b, geyser1_info),       /* GEYSER 1 TP ONLY */
 
        /* PowerBooks Oct 2005 */
-       ATP_DEVICE(0x0214, GEYSER2),    /* GEYSER 2 ANSI */
-       ATP_DEVICE(0x0215, GEYSER2),    /* GEYSER 2 ISO */
-       ATP_DEVICE(0x0216, GEYSER2),    /* GEYSER 2 JIS */
+       ATP_DEVICE(0x0214, geyser2_info),       /* GEYSER 2 ANSI */
+       ATP_DEVICE(0x0215, geyser2_info),       /* GEYSER 2 ISO */
+       ATP_DEVICE(0x0216, geyser2_info),       /* GEYSER 2 JIS */
 
        /* Core Duo MacBook & MacBook Pro */
-       ATP_DEVICE(0x0217, GEYSER3),    /* GEYSER 3 ANSI */
-       ATP_DEVICE(0x0218, GEYSER3),    /* GEYSER 3 ISO */
-       ATP_DEVICE(0x0219, GEYSER3),    /* GEYSER 3 JIS */
+       ATP_DEVICE(0x0217, geyser3_info),       /* GEYSER 3 ANSI */
+       ATP_DEVICE(0x0218, geyser3_info),       /* GEYSER 3 ISO */
+       ATP_DEVICE(0x0219, geyser3_info),       /* GEYSER 3 JIS */
 
        /* Core2 Duo MacBook & MacBook Pro */
-       ATP_DEVICE(0x021a, GEYSER4),    /* GEYSER 4 ANSI */
-       ATP_DEVICE(0x021b, GEYSER4),    /* GEYSER 4 ISO */
-       ATP_DEVICE(0x021c, GEYSER4),    /* GEYSER 4 JIS */
+       ATP_DEVICE(0x021a, geyser4_info),       /* GEYSER 4 ANSI */
+       ATP_DEVICE(0x021b, geyser4_info),       /* GEYSER 4 ISO */
+       ATP_DEVICE(0x021c, geyser4_info),       /* GEYSER 4 JIS */
 
        /* Core2 Duo MacBook3,1 */
-       ATP_DEVICE(0x0229, GEYSER4),    /* GEYSER 4 HF ANSI */
-       ATP_DEVICE(0x022a, GEYSER4),    /* GEYSER 4 HF ISO */
-       ATP_DEVICE(0x022b, GEYSER4),    /* GEYSER 4 HF JIS */
+       ATP_DEVICE(0x0229, geyser4_info),       /* GEYSER 4 HF ANSI */
+       ATP_DEVICE(0x022a, geyser4_info),       /* GEYSER 4 HF ISO */
+       ATP_DEVICE(0x022b, geyser4_info),       /* GEYSER 4 HF JIS */
 
        /* Terminating entry */
        { }
 };
 MODULE_DEVICE_TABLE(usb, atp_table);
 
-/*
- * number of sensors. Note that only 16 instead of 26 X (horizontal)
- * sensors exist on 12" and 15" PowerBooks. All models have 16 Y
- * (vertical) sensors.
- */
+/* maximum number of sensors */
 #define ATP_XSENSORS   26
 #define ATP_YSENSORS   16
 
@@ -107,21 +161,6 @@ MODULE_DEVICE_TABLE(usb, atp_table);
 
 /* maximum pressure this driver will report */
 #define ATP_PRESSURE   300
-/*
- * multiplication factor for the X and Y coordinates.
- * We try to keep the touchpad aspect ratio while still doing only simple
- * arithmetics.
- * The factors below give coordinates like:
- *
- *      0 <= x <  960 on 12" and 15" Powerbooks
- *      0 <= x < 1600 on 17" Powerbooks and 17" MacBook Pro
- *      0 <= x < 1216 on MacBooks and 15" MacBook Pro
- *
- *      0 <= y <  646 on all Powerbooks
- *      0 <= y <  774 on all MacBooks
- */
-#define ATP_XFACT      64
-#define ATP_YFACT      43
 
 /*
  * Threshold for the touchpad sensors. Any change less than ATP_THRESHOLD is
@@ -159,7 +198,7 @@ struct atp {
        struct urb              *urb;           /* usb request block */
        u8                      *data;          /* transferred data */
        struct input_dev        *input;         /* input dev */
-       enum atp_touchpad_type  type;           /* type of touchpad */
+       const struct atp_info   *info;          /* touchpad model */
        bool                    open;
        bool                    valid;          /* are the samples valid? */
        bool                    size_detect_done;
@@ -169,7 +208,6 @@ struct atp {
        signed char             xy_cur[ATP_XSENSORS + ATP_YSENSORS];
        signed char             xy_old[ATP_XSENSORS + ATP_YSENSORS];
        int                     xy_acc[ATP_XSENSORS + ATP_YSENSORS];
-       int                     datalen;        /* size of USB transfer */
        int                     idlecount;      /* number of empty packets */
        struct work_struct      work;
 };
@@ -359,7 +397,7 @@ static int atp_status_check(struct urb *urb)
                if (!dev->overflow_warned) {
                        printk(KERN_WARNING "appletouch: OVERFLOW with data "
                                "length %d, actual length is %d\n",
-                               dev->datalen, dev->urb->actual_length);
+                               dev->info->datalen, dev->urb->actual_length);
                        dev->overflow_warned = true;
                }
        case -ECONNRESET:
@@ -377,7 +415,7 @@ static int atp_status_check(struct urb *urb)
        }
 
        /* drop incomplete datasets */
-       if (dev->urb->actual_length != dev->datalen) {
+       if (dev->urb->actual_length != dev->info->datalen) {
                dprintk("appletouch: incomplete data package"
                        " (first byte: %d, length: %d).\n",
                        dev->data[0], dev->urb->actual_length);
@@ -387,6 +425,25 @@ static int atp_status_check(struct urb *urb)
        return ATP_URB_STATUS_SUCCESS;
 }
 
+static void atp_detect_size(struct atp *dev)
+{
+       int i;
+
+       /* 17" Powerbooks have extra X sensors */
+       for (i = dev->info->xsensors; i < ATP_XSENSORS; i++) {
+               if (dev->xy_cur[i]) {
+
+                       printk(KERN_INFO "appletouch: 17\" model detected.\n");
+
+                       input_set_abs_params(dev->input, ABS_X, 0,
+                                            (dev->info->xsensors_17 - 1) *
+                                                       dev->info->xfact - 1,
+                                            ATP_FUZZ, 0);
+                       break;
+               }
+       }
+}
+
 /*
  * USB interrupt callback functions
  */
@@ -407,7 +464,7 @@ static void atp_complete_geyser_1_2(struct urb *urb)
                goto exit;
 
        /* reorder the sensors values */
-       if (dev->type == ATP_GEYSER2) {
+       if (dev->info == &geyser2_info) {
                memset(dev->xy_cur, 0, sizeof(dev->xy_cur));
 
                /*
@@ -437,8 +494,8 @@ static void atp_complete_geyser_1_2(struct urb *urb)
                                dev->xy_cur[i + 24] = dev->data[5 * i + 44];
 
                        /* Y values */
-                       dev->xy_cur[i + 26] = dev->data[5 * i +  1];
-                       dev->xy_cur[i + 34] = dev->data[5 * i +  3];
+                       dev->xy_cur[ATP_XSENSORS + i] = dev->data[5 * i +  1];
+                       dev->xy_cur[ATP_XSENSORS + i + 8] = dev->data[5 * i + 3];
                }
        }
 
@@ -453,32 +510,8 @@ static void atp_complete_geyser_1_2(struct urb *urb)
                memcpy(dev->xy_old, dev->xy_cur, sizeof(dev->xy_old));
 
                /* Perform size detection, if not done already */
-               if (!dev->size_detect_done) {
-
-                       /* 17" Powerbooks have extra X sensors */
-                       for (i = (dev->type == ATP_GEYSER2 ? 15 : 16);
-                            i < ATP_XSENSORS; i++) {
-                               if (!dev->xy_cur[i])
-                                       continue;
-
-                               printk(KERN_INFO
-                                       "appletouch: 17\" model detected.\n");
-
-                               if (dev->type == ATP_GEYSER2)
-                                       input_set_abs_params(dev->input, ABS_X,
-                                                            0,
-                                                            (20 - 1) *
-                                                            ATP_XFACT - 1,
-                                                            ATP_FUZZ, 0);
-                               else
-                                       input_set_abs_params(dev->input, ABS_X,
-                                                            0,
-                                                            (26 - 1) *
-                                                            ATP_XFACT - 1,
-                                                            ATP_FUZZ, 0);
-                               break;
-                       }
-
+               if (unlikely(!dev->size_detect_done)) {
+                       atp_detect_size(dev);
                        dev->size_detect_done = 1;
                        goto exit;
                }
@@ -499,10 +532,10 @@ static void atp_complete_geyser_1_2(struct urb *urb)
        dbg_dump("accumulator", dev->xy_acc);
 
        x = atp_calculate_abs(dev->xy_acc, ATP_XSENSORS,
-                             ATP_XFACT, &x_z, &x_f);
+                             dev->info->xfact, &x_z, &x_f);
        y = atp_calculate_abs(dev->xy_acc + ATP_XSENSORS, ATP_YSENSORS,
-                             ATP_YFACT, &y_z, &y_f);
-       key = dev->data[dev->datalen - 1] & ATP_STATUS_BUTTON;
+                             dev->info->yfact, &y_z, &y_f);
+       key = dev->data[dev->info->datalen - 1] & ATP_STATUS_BUTTON;
 
        if (x && y) {
                if (dev->x_old != -1) {
@@ -583,7 +616,7 @@ static void atp_complete_geyser_3_4(struct urb *urb)
        dbg_dump("sample", dev->xy_cur);
 
        /* Just update the base values (i.e. touchpad in untouched state) */
-       if (dev->data[dev->datalen - 1] & ATP_STATUS_BASE_UPDATE) {
+       if (dev->data[dev->info->datalen - 1] & ATP_STATUS_BASE_UPDATE) {
 
                dprintk(KERN_DEBUG "appletouch: updated base values\n");
 
@@ -610,10 +643,10 @@ static void atp_complete_geyser_3_4(struct urb *urb)
        dbg_dump("accumulator", dev->xy_acc);
 
        x = atp_calculate_abs(dev->xy_acc, ATP_XSENSORS,
-                             ATP_XFACT, &x_z, &x_f);
+                             dev->info->xfact, &x_z, &x_f);
        y = atp_calculate_abs(dev->xy_acc + ATP_XSENSORS, ATP_YSENSORS,
-                             ATP_YFACT, &y_z, &y_f);
-       key = dev->data[dev->datalen - 1] & ATP_STATUS_BUTTON;
+                             dev->info->yfact, &y_z, &y_f);
+       key = dev->data[dev->info->datalen - 1] & ATP_STATUS_BUTTON;
 
        if (x && y) {
                if (dev->x_old != -1) {
@@ -705,7 +738,7 @@ static int atp_handle_geyser(struct atp *dev)
 {
        struct usb_device *udev = dev->udev;
 
-       if (dev->type != ATP_FOUNTAIN) {
+       if (dev->info != &fountain_info) {
                /* switch to raw sensor mode */
                if (atp_geyser_init(udev))
                        return -EIO;
@@ -726,6 +759,7 @@ static int atp_probe(struct usb_interface *iface,
        struct usb_endpoint_descriptor *endpoint;
        int int_in_endpointAddr = 0;
        int i, error = -ENOMEM;
+       const struct atp_info *info = (const struct atp_info *)id->driver_info;
 
        /* set up the endpoint information */
        /* use only the first interrupt-in endpoint */
@@ -753,35 +787,22 @@ static int atp_probe(struct usb_interface *iface,
 
        dev->udev = udev;
        dev->input = input_dev;
-       dev->type = id->driver_info;
+       dev->info = info;
        dev->overflow_warned = false;
-       if (dev->type == ATP_FOUNTAIN || dev->type == ATP_GEYSER1)
-               dev->datalen = 81;
-       else
-               dev->datalen = 64;
 
        dev->urb = usb_alloc_urb(0, GFP_KERNEL);
        if (!dev->urb)
                goto err_free_devs;
 
-       dev->data = usb_buffer_alloc(dev->udev, dev->datalen, GFP_KERNEL,
+       dev->data = usb_buffer_alloc(dev->udev, dev->info->datalen, GFP_KERNEL,
                                     &dev->urb->transfer_dma);
        if (!dev->data)
                goto err_free_urb;
 
-       /* Select the USB complete (callback) function */
-       if (dev->type == ATP_FOUNTAIN ||
-           dev->type == ATP_GEYSER1 ||
-           dev->type == ATP_GEYSER2)
-               usb_fill_int_urb(dev->urb, udev,
-                                usb_rcvintpipe(udev, int_in_endpointAddr),
-                                dev->data, dev->datalen,
-                                atp_complete_geyser_1_2, dev, 1);
-       else
-               usb_fill_int_urb(dev->urb, udev,
-                                usb_rcvintpipe(udev, int_in_endpointAddr),
-                                dev->data, dev->datalen,
-                                atp_complete_geyser_3_4, dev, 1);
+       usb_fill_int_urb(dev->urb, udev,
+                        usb_rcvintpipe(udev, int_in_endpointAddr),
+                        dev->data, dev->info->datalen,
+                        dev->info->callback, dev, 1);
 
        error = atp_handle_geyser(dev);
        if (error)
@@ -802,35 +823,12 @@ static int atp_probe(struct usb_interface *iface,
 
        set_bit(EV_ABS, input_dev->evbit);
 
-       if (dev->type == ATP_GEYSER3 || dev->type == ATP_GEYSER4) {
-               /*
-                * MacBook have 20 X sensors, 10 Y sensors
-                */
-               input_set_abs_params(input_dev, ABS_X, 0,
-                                    ((20 - 1) * ATP_XFACT) - 1, ATP_FUZZ, 0);
-               input_set_abs_params(input_dev, ABS_Y, 0,
-                                    ((10 - 1) * ATP_YFACT) - 1, ATP_FUZZ, 0);
-       } else if (dev->type == ATP_GEYSER2) {
-               /*
-                * Oct 2005 15" PowerBooks have 15 X sensors, 17" are detected
-                * later.
-                */
-               input_set_abs_params(input_dev, ABS_X, 0,
-                                    ((15 - 1) * ATP_XFACT) - 1, ATP_FUZZ, 0);
-               input_set_abs_params(input_dev, ABS_Y, 0,
-                                    ((9 - 1) * ATP_YFACT) - 1, ATP_FUZZ, 0);
-       } else {
-               /*
-                * 12" and 15" Powerbooks only have 16 x sensors,
-                * 17" models are detected later.
-                */
-               input_set_abs_params(input_dev, ABS_X, 0,
-                                    (16 - 1) * ATP_XFACT - 1,
-                                    ATP_FUZZ, 0);
-               input_set_abs_params(input_dev, ABS_Y, 0,
-                                    (ATP_YSENSORS - 1) * ATP_YFACT - 1,
-                                    ATP_FUZZ, 0);
-       }
+       input_set_abs_params(input_dev, ABS_X, 0,
+                            (dev->info->xsensors - 1) * dev->info->xfact - 1,
+                            ATP_FUZZ, 0);
+       input_set_abs_params(input_dev, ABS_Y, 0,
+                            (dev->info->ysensors - 1) * dev->info->yfact - 1,
+                            ATP_FUZZ, 0);
        input_set_abs_params(input_dev, ABS_PRESSURE, 0, ATP_PRESSURE, 0, 0);
 
        set_bit(EV_KEY, input_dev->evbit);
@@ -852,7 +850,7 @@ static int atp_probe(struct usb_interface *iface,
        return 0;
 
  err_free_buffer:
-       usb_buffer_free(dev->udev, dev->datalen,
+       usb_buffer_free(dev->udev, dev->info->datalen,
                        dev->data, dev->urb->transfer_dma);
  err_free_urb:
        usb_free_urb(dev->urb);
@@ -871,7 +869,7 @@ static void atp_disconnect(struct usb_interface *iface)
        if (dev) {
                usb_kill_urb(dev->urb);
                input_unregister_device(dev->input);
-               usb_buffer_free(dev->udev, dev->datalen,
+               usb_buffer_free(dev->udev, dev->info->datalen,
                                dev->data, dev->urb->transfer_dma);
                usb_free_urb(dev->urb);
                kfree(dev);
index 72cf5e33790ea6e0541b7e351e53e2cf03803bd4..0db8d16c5eddafd297edcf25b3387968d976d135 100644 (file)
@@ -173,7 +173,7 @@ static int __devexit gpio_mouse_remove(struct platform_device *pdev)
 /* work with hotplug and coldplug */
 MODULE_ALIAS("platform:gpio_mouse");
 
-struct platform_driver gpio_mouse_device_driver = {
+static struct platform_driver gpio_mouse_device_driver = {
        .remove         = __devexit_p(gpio_mouse_remove),
        .driver         = {
                .name   = "gpio_mouse",
index 88f04bf2ad6cfe677d13e9f3d73da6d5379d2186..81e6ebf323e9b9a8bdfc780afc487e690caf5c2c 100644 (file)
@@ -48,6 +48,30 @@ module_param(recalib_delta, int, 0644);
 MODULE_PARM_DESC(recalib_delta,
        "packets containing a delta this large will cause a recalibration.");
 
+static int jumpy_delay = 1000;
+module_param(jumpy_delay, int, 0644);
+MODULE_PARM_DESC(jumpy_delay,
+       "delay (ms) before recal after jumpiness detected");
+
+static int spew_delay = 1000;
+module_param(spew_delay, int, 0644);
+MODULE_PARM_DESC(spew_delay,
+       "delay (ms) before recal after packet spew detected");
+
+static int recal_guard_time = 2000;
+module_param(recal_guard_time, int, 0644);
+MODULE_PARM_DESC(recal_guard_time,
+       "interval (ms) during which recal will be restarted if packet received");
+
+static int post_interrupt_delay = 1000;
+module_param(post_interrupt_delay, int, 0644);
+MODULE_PARM_DESC(post_interrupt_delay,
+       "delay (ms) before recal after recal interrupt detected");
+
+static int autorecal = 1;
+module_param(autorecal, int, 0644);
+MODULE_PARM_DESC(autorecal, "enable recalibration in the driver");
+
 /*
  * When the touchpad gets ultra-sensitive, one can keep their finger 1/2"
  * above the pad and still have it send packets.  This causes a jump cursor
@@ -66,7 +90,7 @@ static void hgpk_jumpy_hack(struct psmouse *psmouse, int x, int y)
                /* My car gets forty rods to the hogshead and that's the
                 * way I likes it! */
                psmouse_queue_work(psmouse, &priv->recalib_wq,
-                               msecs_to_jiffies(1000));
+                               msecs_to_jiffies(jumpy_delay));
        }
 }
 
@@ -103,7 +127,7 @@ static void hgpk_spewing_hack(struct psmouse *psmouse,
                        hgpk_dbg(psmouse, "packet spew detected (%d,%d)\n",
                                 priv->x_tally, priv->y_tally);
                        psmouse_queue_work(psmouse, &priv->recalib_wq,
-                                          msecs_to_jiffies(1000));
+                                          msecs_to_jiffies(spew_delay));
                }
                /* reset every 100 packets */
                priv->count = 0;
@@ -181,7 +205,7 @@ static psmouse_ret_t hgpk_process_byte(struct psmouse *psmouse)
                                 "packet inside calibration window, "
                                 "queueing another recalibration\n");
                        psmouse_queue_work(psmouse, &priv->recalib_wq,
-                                       msecs_to_jiffies(1000));
+                                       msecs_to_jiffies(post_interrupt_delay));
                }
                priv->recalib_window = 0;
        }
@@ -231,7 +255,7 @@ static int hgpk_force_recalibrate(struct psmouse *psmouse)
         * If someone's finger *was* on the touchpad, it's probably
         * miscalibrated.  So, we should schedule another recalibration
         */
-       priv->recalib_window = jiffies +  msecs_to_jiffies(2000);
+       priv->recalib_window = jiffies +  msecs_to_jiffies(recal_guard_time);
 
        return 0;
 }
index e532c48410ea63013b5d558ae3d150fd5e77fb44..3263ce083bf0c17c61f542d868d4ff87c6d51bd7 100644 (file)
@@ -46,7 +46,7 @@
 MODULE_AUTHOR("Brian S. Julin <bri@calyx.com>");
 MODULE_DESCRIPTION(HIL_GENERIC_NAME " driver");
 MODULE_LICENSE("Dual BSD/GPL");
-
+MODULE_ALIAS("serio:ty03pr25id0Fex*");
 
 #define TABLET_SIMULATES_MOUSE /* allow tablet to be used as mouse */
 #undef  TABLET_AUTOADJUST      /* auto-adjust valid tablet ranges */
diff --git a/drivers/input/mouse/pxa930_trkball.c b/drivers/input/mouse/pxa930_trkball.c
new file mode 100644 (file)
index 0000000..a0f45c4
--- /dev/null
@@ -0,0 +1,269 @@
+/*
+ * PXA930 track ball mouse driver
+ *
+ * Copyright (C) 2007 Marvell International Ltd.
+ * 2008-02-28: Yong Yao <yaoyong@marvell.com>
+ *             initial version
+ *
+ *  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/init.h>
+#include <linux/input.h>
+#include <linux/version.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+
+#include <mach/hardware.h>
+#include <mach/pxa930_trkball.h>
+
+/* Trackball Controller Register Definitions */
+#define TBCR           (0x000C)
+#define TBCNTR         (0x0010)
+#define TBSBC          (0x0014)
+
+#define TBCR_TBRST     (1 << 1)
+#define TBCR_TBSB      (1 << 10)
+
+#define TBCR_Y_FLT(n)  (((n) & 0xf) << 6)
+#define TBCR_X_FLT(n)  (((n) & 0xf) << 2)
+
+#define TBCNTR_YM(n)   (((n) >> 24) & 0xff)
+#define TBCNTR_YP(n)   (((n) >> 16) & 0xff)
+#define TBCNTR_XM(n)   (((n) >> 8) & 0xff)
+#define TBCNTR_XP(n)   ((n) & 0xff)
+
+#define TBSBC_TBSBC    (0x1)
+
+struct pxa930_trkball {
+       struct pxa930_trkball_platform_data *pdata;
+
+       /* Memory Mapped Register */
+       struct resource *mem;
+       void __iomem *mmio_base;
+
+       struct input_dev *input;
+};
+
+static irqreturn_t pxa930_trkball_interrupt(int irq, void *dev_id)
+{
+       struct pxa930_trkball *trkball = dev_id;
+       struct input_dev *input = trkball->input;
+       int tbcntr, x, y;
+
+       /* According to the spec software must read TBCNTR twice:
+        * if the read value is the same, the reading is valid
+        */
+       tbcntr = __raw_readl(trkball->mmio_base + TBCNTR);
+
+       if (tbcntr == __raw_readl(trkball->mmio_base + TBCNTR)) {
+               x = (TBCNTR_XP(tbcntr) - TBCNTR_XM(tbcntr)) / 2;
+               y = (TBCNTR_YP(tbcntr) - TBCNTR_YM(tbcntr)) / 2;
+
+               input_report_rel(input, REL_X, x);
+               input_report_rel(input, REL_Y, y);
+               input_sync(input);
+       }
+
+       __raw_writel(TBSBC_TBSBC, trkball->mmio_base + TBSBC);
+       __raw_writel(0, trkball->mmio_base + TBSBC);
+
+       return IRQ_HANDLED;
+}
+
+/* For TBCR, we need to wait for a while to make sure it has been modified. */
+static int write_tbcr(struct pxa930_trkball *trkball, int v)
+{
+       int i = 100;
+
+       __raw_writel(v, trkball->mmio_base + TBCR);
+
+       while (i--) {
+               if (__raw_readl(trkball->mmio_base + TBCR) == v)
+                       break;
+               msleep(1);
+       }
+
+       if (i == 0) {
+               pr_err("%s: timed out writing TBCR(%x)!\n", __func__, v);
+               return -ETIMEDOUT;
+       }
+
+       return 0;
+}
+
+static void pxa930_trkball_config(struct pxa930_trkball *trkball)
+{
+       uint32_t tbcr;
+
+       /* According to spec, need to write the filters of x,y to 0xf first! */
+       tbcr = __raw_readl(trkball->mmio_base + TBCR);
+       write_tbcr(trkball, tbcr | TBCR_X_FLT(0xf) | TBCR_Y_FLT(0xf));
+       write_tbcr(trkball, TBCR_X_FLT(trkball->pdata->x_filter) |
+                           TBCR_Y_FLT(trkball->pdata->y_filter));
+
+       /* According to spec, set TBCR_TBRST first, before clearing it! */
+       tbcr = __raw_readl(trkball->mmio_base + TBCR);
+       write_tbcr(trkball, tbcr | TBCR_TBRST);
+       write_tbcr(trkball, tbcr & ~TBCR_TBRST);
+
+       __raw_writel(TBSBC_TBSBC, trkball->mmio_base + TBSBC);
+       __raw_writel(0, trkball->mmio_base + TBSBC);
+
+       pr_debug("%s: final TBCR=%x!\n", __func__,
+                __raw_readl(trkball->mmio_base + TBCR));
+}
+
+static int pxa930_trkball_open(struct input_dev *dev)
+{
+       struct pxa930_trkball *trkball = input_get_drvdata(dev);
+
+       pxa930_trkball_config(trkball);
+
+       return 0;
+}
+
+static void pxa930_trkball_disable(struct pxa930_trkball *trkball)
+{
+       uint32_t tbcr = __raw_readl(trkball->mmio_base + TBCR);
+
+       /* Held in reset, gate the 32-KHz input clock off */
+       write_tbcr(trkball, tbcr | TBCR_TBRST);
+}
+
+static void pxa930_trkball_close(struct input_dev *dev)
+{
+       struct pxa930_trkball *trkball = input_get_drvdata(dev);
+
+       pxa930_trkball_disable(trkball);
+}
+
+static int __devinit pxa930_trkball_probe(struct platform_device *pdev)
+{
+       struct pxa930_trkball *trkball;
+       struct input_dev *input;
+       struct resource *res;
+       int irq, error;
+
+       irq = platform_get_irq(pdev, 0);
+       if (irq < 0) {
+               dev_err(&pdev->dev, "failed to get trkball irq\n");
+               return -ENXIO;
+       }
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res) {
+               dev_err(&pdev->dev, "failed to get register memory\n");
+               return -ENXIO;
+       }
+
+       trkball = kzalloc(sizeof(struct pxa930_trkball), GFP_KERNEL);
+       if (!trkball)
+               return -ENOMEM;
+
+       trkball->pdata = pdev->dev.platform_data;
+       if (!trkball->pdata) {
+               dev_err(&pdev->dev, "no platform data defined\n");
+               error = -EINVAL;
+               goto failed;
+       }
+
+       trkball->mmio_base = ioremap_nocache(res->start, resource_size(res));
+       if (!trkball->mmio_base) {
+               dev_err(&pdev->dev, "failed to ioremap registers\n");
+               error = -ENXIO;
+               goto failed;
+       }
+
+       /* held the module in reset, will be enabled in open() */
+       pxa930_trkball_disable(trkball);
+
+       error = request_irq(irq, pxa930_trkball_interrupt, IRQF_DISABLED,
+                           pdev->name, trkball);
+       if (error) {
+               dev_err(&pdev->dev, "failed to request irq: %d\n", ret);
+               goto failed_free_io;
+       }
+
+       platform_set_drvdata(pdev, trkball);
+
+       input = input_allocate_device();
+       if (!input) {
+               dev_err(&pdev->dev, "failed to allocate input device\n");
+               error = -ENOMEM;
+               goto failed_free_irq;
+       }
+
+       input->name = pdev->name;
+       input->id.bustype = BUS_HOST;
+       input->open = pxa930_trkball_open;
+       input->close = pxa930_trkball_close;
+       input->dev.parent = &pdev->dev;
+       input_set_drvdata(input, trkball);
+
+       trkball->input = input;
+
+       input_set_capability(input, EV_REL, REL_X);
+       input_set_capability(input, EV_REL, REL_Y);
+
+       error = input_register_device(input);
+       if (error) {
+               dev_err(&pdev->dev, "unable to register input device\n");
+               goto failed_free_input;
+       }
+
+       return 0;
+
+failed_free_input:
+       input_free_device(input);
+failed_free_irq:
+       free_irq(irq, trkball);
+failed_free_io:
+       iounmap(trkball->mmio_base);
+failed:
+       kfree(trkball);
+       return ret;
+}
+
+static int __devexit pxa930_trkball_remove(struct platform_device *pdev)
+{
+       struct pxa930_trkball *trkball = platform_get_drvdata(pdev);
+       int irq = platform_get_irq(pdev, 0);
+
+       input_unregister_device(trkball->input);
+       free_irq(irq, trkball);
+       iounmap(trkball->mmio_base);
+       kfree(trkball);
+
+       return 0;
+}
+
+static struct platform_driver pxa930_trkball_driver = {
+       .driver         = {
+               .name   = "pxa930-trkball",
+       },
+       .probe          = pxa930_trkball_probe,
+       .remove         = __devexit_p(pxa930_trkball_remove),
+};
+
+static int __init pxa930_trkball_init(void)
+{
+       return platform_driver_register(&pxa930_trkball_driver);
+}
+
+static void __exit pxa930_trkball_exit(void)
+{
+       platform_driver_unregister(&pxa930_trkball_driver);
+}
+
+module_init(pxa930_trkball_init);
+module_exit(pxa930_trkball_exit);
+
+MODULE_AUTHOR("Yong Yao <yaoyong@marvell.com>");
+MODULE_DESCRIPTION("PXA930 Trackball Mouse Driver");
+MODULE_LICENSE("GPL");
index d349c4a5e3e84488a4e812e33e6e547aac4d97e7..865fc69e9bc39e8ef81b213722e572c95917fb0e 100644 (file)
@@ -445,12 +445,14 @@ static void synaptics_process_packet(struct psmouse *psmouse)
 
        input_report_abs(dev, ABS_TOOL_WIDTH, finger_width);
        input_report_key(dev, BTN_TOOL_FINGER, num_fingers == 1);
-       input_report_key(dev, BTN_TOOL_DOUBLETAP, num_fingers == 2);
-       input_report_key(dev, BTN_TOOL_TRIPLETAP, num_fingers == 3);
-
        input_report_key(dev, BTN_LEFT, hw.left);
        input_report_key(dev, BTN_RIGHT, hw.right);
 
+       if (SYN_CAP_MULTIFINGER(priv->capabilities)) {
+               input_report_key(dev, BTN_TOOL_DOUBLETAP, num_fingers == 2);
+               input_report_key(dev, BTN_TOOL_TRIPLETAP, num_fingers == 3);
+       }
+
        if (SYN_CAP_MIDDLE_BUTTON(priv->capabilities))
                input_report_key(dev, BTN_MIDDLE, hw.middle);
 
@@ -543,12 +545,14 @@ static void set_input_params(struct input_dev *dev, struct synaptics_data *priv)
        set_bit(EV_KEY, dev->evbit);
        set_bit(BTN_TOUCH, dev->keybit);
        set_bit(BTN_TOOL_FINGER, dev->keybit);
-       set_bit(BTN_TOOL_DOUBLETAP, dev->keybit);
-       set_bit(BTN_TOOL_TRIPLETAP, dev->keybit);
-
        set_bit(BTN_LEFT, dev->keybit);
        set_bit(BTN_RIGHT, dev->keybit);
 
+       if (SYN_CAP_MULTIFINGER(priv->capabilities)) {
+               set_bit(BTN_TOOL_DOUBLETAP, dev->keybit);
+               set_bit(BTN_TOOL_TRIPLETAP, dev->keybit);
+       }
+
        if (SYN_CAP_MIDDLE_BUTTON(priv->capabilities))
                set_bit(BTN_MIDDLE, dev->keybit);
 
index d8c056fe7e982c2ee1f1dc39298e0e4721a06921..ef99a7e6d40cb8741a18a796048ea78a32d2cc3b 100644 (file)
@@ -878,8 +878,7 @@ static struct mousedev *mousedev_create(struct input_dev *dev,
        mousedev->handle.handler = handler;
        mousedev->handle.private = mousedev;
 
-       strlcpy(mousedev->dev.bus_id, mousedev->name,
-               sizeof(mousedev->dev.bus_id));
+       dev_set_name(&mousedev->dev, mousedev->name);
        mousedev->dev.class = &input_class;
        if (dev)
                mousedev->dev.parent = &dev->dev;
index 37586a68d3459935e8f034588aefb1a75718fa77..7ba9f2b2c0414c1e7389fef80045e7c61a9a6d01 100644 (file)
@@ -934,6 +934,7 @@ int hil_mlc_register(hil_mlc *mlc)
                snprintf(mlc_serio->name, sizeof(mlc_serio->name)-1, "HIL_SERIO%d", i);
                snprintf(mlc_serio->phys, sizeof(mlc_serio->phys)-1, "HIL%d", i);
                mlc_serio->id                   = hil_mlc_serio_id;
+               mlc_serio->id.id                = i; /* HIL port no. */
                mlc_serio->write                = hil_mlc_serio_write;
                mlc_serio->open                 = hil_mlc_serio_open;
                mlc_serio->close                = hil_mlc_serio_close;
index 29e686388a2c9a85732a028ede45d16e188087c8..6fa2deff744663574fcd31f3f28a0950f083a1b6 100644 (file)
@@ -143,6 +143,14 @@ static struct dmi_system_id __initdata i8042_dmi_noloop_table[] = {
                        DMI_MATCH(DMI_PRODUCT_VERSION, "M606"),
                },
        },
+       {
+               .ident = "Gigabyte M912",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "GIGABYTE"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "M912"),
+                       DMI_MATCH(DMI_PRODUCT_VERSION, "01"),
+               },
+       },
        { }
 };
 
@@ -351,6 +359,13 @@ static struct dmi_system_id __initdata i8042_dmi_nomux_table[] = {
                        DMI_MATCH(DMI_PRODUCT_NAME, "HEL80I"),
                },
        },
+       {
+               .ident = "Dell Vostro 1510",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "Vostro1510"),
+               },
+       },
        { }
 };
 
index 2b304c22c2008c41d6262acb3514b750fb862dcb..67248c31e19a06ab17ba7980bfd3c04fb54d7a52 100644 (file)
@@ -262,9 +262,17 @@ int ps2_handle_ack(struct ps2dev *ps2dev, unsigned char data)
                        break;
 
                case PS2_RET_NAK:
-                       ps2dev->nak = 1;
+                       ps2dev->flags |= PS2_FLAG_NAK;
+                       ps2dev->nak = PS2_RET_NAK;
                        break;
 
+               case PS2_RET_ERR:
+                       if (ps2dev->flags & PS2_FLAG_NAK) {
+                               ps2dev->flags &= ~PS2_FLAG_NAK;
+                               ps2dev->nak = PS2_RET_ERR;
+                               break;
+                       }
+
                /*
                 * Workaround for mice which don't ACK the Get ID command.
                 * These are valid mouse IDs that we recognize.
@@ -282,8 +290,11 @@ int ps2_handle_ack(struct ps2dev *ps2dev, unsigned char data)
        }
 
 
-       if (!ps2dev->nak && ps2dev->cmdcnt)
-               ps2dev->flags |= PS2_FLAG_CMD | PS2_FLAG_CMD1;
+       if (!ps2dev->nak) {
+               ps2dev->flags &= ~PS2_FLAG_NAK;
+               if (ps2dev->cmdcnt)
+                       ps2dev->flags |= PS2_FLAG_CMD | PS2_FLAG_CMD1;
+       }
 
        ps2dev->flags &= ~PS2_FLAG_ACK;
        wake_up(&ps2dev->wait);
@@ -329,6 +340,7 @@ void ps2_cmd_aborted(struct ps2dev *ps2dev)
        if (ps2dev->flags & (PS2_FLAG_ACK | PS2_FLAG_CMD))
                wake_up(&ps2dev->wait);
 
-       ps2dev->flags = 0;
+       /* reset all flags except last nack */
+       ps2dev->flags &= PS2_FLAG_NAK;
 }
 EXPORT_SYMBOL(ps2_cmd_aborted);
index 1b404f9e3bff03b6ef34f50d5359f578700b0859..1dacbe0d934832e54cae29353fd258e9a24bb339 100644 (file)
@@ -153,7 +153,7 @@ static int __devinit pcips2_probe(struct pci_dev *dev, const struct pci_device_i
        serio->open             = pcips2_open;
        serio->close            = pcips2_close;
        strlcpy(serio->name, pci_name(dev), sizeof(serio->name));
-       strlcpy(serio->phys, dev->dev.bus_id, sizeof(serio->phys));
+       strlcpy(serio->phys, dev_name(&dev->dev), sizeof(serio->phys));
        serio->port_data        = ps2if;
        serio->dev.parent       = &dev->dev;
        ps2if->io               = serio;
index 2f12d60eee3b4e61f4b93363f5458189d471b0c1..bc033250dfcd10d62657744d778b25034a2ac831 100644 (file)
@@ -546,8 +546,8 @@ static void serio_init_port(struct serio *serio)
        spin_lock_init(&serio->lock);
        mutex_init(&serio->drv_mutex);
        device_initialize(&serio->dev);
-       snprintf(serio->dev.bus_id, sizeof(serio->dev.bus_id),
-                "serio%ld", (long)atomic_inc_return(&serio_no) - 1);
+       dev_set_name(&serio->dev, "serio%ld",
+                       (long)atomic_inc_return(&serio_no) - 1);
        serio->dev.bus = &serio_bus;
        serio->dev.release = serio_release_port;
        if (serio->parent) {
index 765007899d9a87b759defaee46f49dc5647d5867..ebb22f88c8426bdd3cebff9e2f822d0b7412ade7 100644 (file)
 
 /* Mask for all the Receive Interrupts */
 #define XPS2_IPIXR_RX_ALL      (XPS2_IPIXR_RX_OVF | XPS2_IPIXR_RX_ERR |  \
-                                       XPS2_IPIXR_RX_FULL)
+                                XPS2_IPIXR_RX_FULL)
 
 /* Mask for all the Interrupts */
 #define XPS2_IPIXR_ALL         (XPS2_IPIXR_TX_ALL | XPS2_IPIXR_RX_ALL |  \
-                                       XPS2_IPIXR_WDT_TOUT)
+                                XPS2_IPIXR_WDT_TOUT)
 
 /* Global Interrupt Enable mask */
 #define XPS2_GIER_GIE_MASK     0x80000000
 
 struct xps2data {
        int irq;
-       u32 phys_addr;
-       u32 remap_size;
        spinlock_t lock;
-       u8 rxb;                         /* Rx buffer */
        void __iomem *base_address;     /* virt. address of control registers */
-       unsigned int dfl;
+       unsigned int flags;
        struct serio serio;             /* serio */
 };
 
@@ -82,8 +79,13 @@ struct xps2data {
 /* XPS PS/2 data transmission calls */
 /************************************/
 
-/*
- * xps2_recv() will attempt to receive a byte of data from the PS/2 port.
+/**
+ * xps2_recv() - attempts to receive a byte from the PS/2 port.
+ * @drvdata:   pointer to ps2 device private data structure
+ * @byte:      address where the read data will be copied
+ *
+ * If there is any data available in the PS/2 receiver, this functions reads
+ * the data, otherwise it returns error.
  */
 static int xps2_recv(struct xps2data *drvdata, u8 *byte)
 {
@@ -116,33 +118,27 @@ static irqreturn_t xps2_interrupt(int irq, void *dev_id)
 
        /* Check which interrupt is active */
        if (intr_sr & XPS2_IPIXR_RX_OVF)
-               printk(KERN_WARNING "%s: receive overrun error\n",
-                       drvdata->serio.name);
+               dev_warn(drvdata->serio.dev.parent, "receive overrun error\n");
 
        if (intr_sr & XPS2_IPIXR_RX_ERR)
-               drvdata->dfl |= SERIO_PARITY;
+               drvdata->flags |= SERIO_PARITY;
 
        if (intr_sr & (XPS2_IPIXR_TX_NOACK | XPS2_IPIXR_WDT_TOUT))
-               drvdata->dfl |= SERIO_TIMEOUT;
+               drvdata->flags |= SERIO_TIMEOUT;
 
        if (intr_sr & XPS2_IPIXR_RX_FULL) {
-               status = xps2_recv(drvdata, &drvdata->rxb);
+               status = xps2_recv(drvdata, &c);
 
                /* Error, if a byte is not received */
                if (status) {
-                       printk(KERN_ERR
-                               "%s: wrong rcvd byte count (%d)\n",
-                               drvdata->serio.name, status);
+                       dev_err(drvdata->serio.dev.parent,
+                               "wrong rcvd byte count (%d)\n", status);
                } else {
-                       c = drvdata->rxb;
-                       serio_interrupt(&drvdata->serio, c, drvdata->dfl);
-                       drvdata->dfl = 0;
+                       serio_interrupt(&drvdata->serio, c, drvdata->flags);
+                       drvdata->flags = 0;
                }
        }
 
-       if (intr_sr & XPS2_IPIXR_TX_ACK)
-               drvdata->dfl = 0;
-
        return IRQ_HANDLED;
 }
 
@@ -150,8 +146,15 @@ static irqreturn_t xps2_interrupt(int irq, void *dev_id)
 /* serio callbacks */
 /*******************/
 
-/*
- * sxps2_write() sends a byte out through the PS/2 interface.
+/**
+ * sxps2_write() - sends a byte out through the PS/2 port.
+ * @pserio:    pointer to the serio structure of the PS/2 port
+ * @c:         data that needs to be written to the PS/2 port
+ *
+ * This function checks if the PS/2 transmitter is empty and sends a byte.
+ * Otherwise it returns error. Transmission fails only when nothing is connected
+ * to the PS/2 port. Thats why, we do not try to resend the data in case of a
+ * failure.
  */
 static int sxps2_write(struct serio *pserio, unsigned char c)
 {
@@ -174,33 +177,39 @@ static int sxps2_write(struct serio *pserio, unsigned char c)
        return status;
 }
 
-/*
- * sxps2_open() is called when a port is open by the higher layer.
+/**
+ * sxps2_open() - called when a port is opened by the higher layer.
+ * @pserio:    pointer to the serio structure of the PS/2 device
+ *
+ * This function requests irq and enables interrupts for the PS/2 device.
  */
 static int sxps2_open(struct serio *pserio)
 {
        struct xps2data *drvdata = pserio->port_data;
-       int retval;
+       int error;
+       u8 c;
 
-       retval = request_irq(drvdata->irq, &xps2_interrupt, 0,
+       error = request_irq(drvdata->irq, &xps2_interrupt, 0,
                                DRIVER_NAME, drvdata);
-       if (retval) {
-               printk(KERN_ERR
-                       "%s: Couldn't allocate interrupt %d\n",
-                       drvdata->serio.name, drvdata->irq);
-               return retval;
+       if (error) {
+               dev_err(drvdata->serio.dev.parent,
+                       "Couldn't allocate interrupt %d\n", drvdata->irq);
+               return error;
        }
 
        /* start reception by enabling the interrupts */
        out_be32(drvdata->base_address + XPS2_GIER_OFFSET, XPS2_GIER_GIE_MASK);
        out_be32(drvdata->base_address + XPS2_IPIER_OFFSET, XPS2_IPIXR_RX_ALL);
-       (void)xps2_recv(drvdata, &drvdata->rxb);
+       (void)xps2_recv(drvdata, &c);
 
        return 0;               /* success */
 }
 
-/*
- * sxps2_close() frees the interrupt.
+/**
+ * sxps2_close() - frees the interrupt.
+ * @pserio:    pointer to the serio structure of the PS/2 device
+ *
+ * This function frees the irq and disables interrupts for the PS/2 device.
  */
 static void sxps2_close(struct serio *pserio)
 {
@@ -212,24 +221,41 @@ static void sxps2_close(struct serio *pserio)
        free_irq(drvdata->irq, drvdata);
 }
 
-/*********************/
-/* Device setup code */
-/*********************/
-
-static int xps2_setup(struct device *dev, struct resource *regs_res,
-                     struct resource *irq_res)
+/**
+ * xps2_of_probe - probe method for the PS/2 device.
+ * @of_dev:    pointer to OF device structure
+ * @match:     pointer to the stucture used for matching a device
+ *
+ * This function probes the PS/2 device in the device tree.
+ * It initializes the driver data structure and the hardware.
+ * It returns 0, if the driver is bound to the PS/2 device, or a negative
+ * value if there is an error.
+ */
+static int __devinit xps2_of_probe(struct of_device *ofdev,
+                                  const struct of_device_id *match)
 {
+       struct resource r_irq; /* Interrupt resources */
+       struct resource r_mem; /* IO mem resources */
        struct xps2data *drvdata;
        struct serio *serio;
-       unsigned long remap_size;
-       int retval;
+       struct device *dev = &ofdev->dev;
+       resource_size_t remap_size, phys_addr;
+       int error;
+
+       dev_info(dev, "Device Tree Probing \'%s\'\n",
+                       ofdev->node->name);
 
-       if (!dev)
-               return -EINVAL;
+       /* Get iospace for the device */
+       error = of_address_to_resource(ofdev->node, 0, &r_mem);
+       if (error) {
+               dev_err(dev, "invalid address\n");
+               return error;
+       }
 
-       if (!regs_res || !irq_res) {
-               dev_err(dev, "IO resource(s) not found\n");
-               return -EINVAL;
+       /* Get IRQ for the device */
+       if (of_irq_to_resource(ofdev->node, 0, &r_irq) == NO_IRQ) {
+               dev_err(dev, "no IRQ found\n");
+               return -ENODEV;
        }
 
        drvdata = kzalloc(sizeof(struct xps2data), GFP_KERNEL);
@@ -241,24 +267,23 @@ static int xps2_setup(struct device *dev, struct resource *regs_res,
        dev_set_drvdata(dev, drvdata);
 
        spin_lock_init(&drvdata->lock);
-       drvdata->irq = irq_res->start;
-
-       remap_size = regs_res->end - regs_res->start + 1;
-       if (!request_mem_region(regs_res->start, remap_size, DRIVER_NAME)) {
-               dev_err(dev, "Couldn't lock memory region at 0x%08X\n",
-                       (unsigned int)regs_res->start);
-               retval = -EBUSY;
+       drvdata->irq = r_irq.start;
+
+       phys_addr = r_mem.start;
+       remap_size = r_mem.end - r_mem.start + 1;
+       if (!request_mem_region(phys_addr, remap_size, DRIVER_NAME)) {
+               dev_err(dev, "Couldn't lock memory region at 0x%08llX\n",
+                       (unsigned long long)phys_addr);
+               error = -EBUSY;
                goto failed1;
        }
 
        /* Fill in configuration data and add them to the list */
-       drvdata->phys_addr = regs_res->start;
-       drvdata->remap_size = remap_size;
-       drvdata->base_address = ioremap(regs_res->start, remap_size);
+       drvdata->base_address = ioremap(phys_addr, remap_size);
        if (drvdata->base_address == NULL) {
-               dev_err(dev, "Couldn't ioremap memory at 0x%08X\n",
-                       (unsigned int)regs_res->start);
-               retval = -EFAULT;
+               dev_err(dev, "Couldn't ioremap memory at 0x%08llX\n",
+                       (unsigned long long)phys_addr);
+               error = -EFAULT;
                goto failed2;
        }
 
@@ -269,8 +294,9 @@ static int xps2_setup(struct device *dev, struct resource *regs_res,
         * we have the PS2 in a good state */
        out_be32(drvdata->base_address + XPS2_SRST_OFFSET, XPS2_SRST_RESET);
 
-       dev_info(dev, "Xilinx PS2 at 0x%08X mapped to 0x%p, irq=%d\n",
-               drvdata->phys_addr, drvdata->base_address, drvdata->irq);
+       dev_info(dev, "Xilinx PS2 at 0x%08llX mapped to 0x%p, irq=%d\n",
+                (unsigned long long)phys_addr, drvdata->base_address,
+                drvdata->irq);
 
        serio = &drvdata->serio;
        serio->id.type = SERIO_8042;
@@ -280,71 +306,51 @@ static int xps2_setup(struct device *dev, struct resource *regs_res,
        serio->port_data = drvdata;
        serio->dev.parent = dev;
        snprintf(serio->name, sizeof(serio->name),
-                "Xilinx XPS PS/2 at %08X", drvdata->phys_addr);
+                "Xilinx XPS PS/2 at %08llX", (unsigned long long)phys_addr);
        snprintf(serio->phys, sizeof(serio->phys),
-                "xilinxps2/serio at %08X", drvdata->phys_addr);
+                "xilinxps2/serio at %08llX", (unsigned long long)phys_addr);
+
        serio_register_port(serio);
 
        return 0;               /* success */
 
 failed2:
-       release_mem_region(regs_res->start, remap_size);
+       release_mem_region(phys_addr, remap_size);
 failed1:
        kfree(drvdata);
        dev_set_drvdata(dev, NULL);
 
-       return retval;
-}
-
-/***************************/
-/* OF Platform Bus Support */
-/***************************/
-
-static int __devinit xps2_of_probe(struct of_device *ofdev, const struct
-                                  of_device_id * match)
-{
-       struct resource r_irq; /* Interrupt resources */
-       struct resource r_mem; /* IO mem resources */
-       int rc = 0;
-
-       printk(KERN_INFO "Device Tree Probing \'%s\'\n",
-                       ofdev->node->name);
-
-       /* Get iospace for the device */
-       rc = of_address_to_resource(ofdev->node, 0, &r_mem);
-       if (rc) {
-               dev_err(&ofdev->dev, "invalid address\n");
-               return rc;
-       }
-
-       /* Get IRQ for the device */
-       rc = of_irq_to_resource(ofdev->node, 0, &r_irq);
-       if (rc == NO_IRQ) {
-               dev_err(&ofdev->dev, "no IRQ found\n");
-               return rc;
-       }
-
-       return xps2_setup(&ofdev->dev, &r_mem, &r_irq);
+       return error;
 }
 
+/**
+ * xps2_of_remove - unbinds the driver from the PS/2 device.
+ * @of_dev:    pointer to OF device structure
+ *
+ * This function is called if a device is physically removed from the system or
+ * if the driver module is being unloaded. It frees any resources allocated to
+ * the device.
+ */
 static int __devexit xps2_of_remove(struct of_device *of_dev)
 {
        struct device *dev = &of_dev->dev;
-       struct xps2data *drvdata;
-
-       if (!dev)
-               return -EINVAL;
-
-       drvdata = dev_get_drvdata(dev);
+       struct xps2data *drvdata = dev_get_drvdata(dev);
+       struct resource r_mem; /* IO mem resources */
 
        serio_unregister_port(&drvdata->serio);
        iounmap(drvdata->base_address);
-       release_mem_region(drvdata->phys_addr, drvdata->remap_size);
+
+       /* Get iospace of the device */
+       if (of_address_to_resource(of_dev->node, 0, &r_mem))
+               dev_err(dev, "invalid address\n");
+       else
+               release_mem_region(r_mem.start, r_mem.end - r_mem.start + 1);
+
        kfree(drvdata);
 
        dev_set_drvdata(dev, NULL);
 
-       return 0;               /* success */
+       return 0;
 }
 
 /* Match table for of_platform binding */
index 5524e01dbb1a2fabd64ae1bc86b9b05dbfe12dc0..2e18a1c0c3519d21b149eaeff11d3f028d72bc3d 100644 (file)
@@ -877,7 +877,7 @@ static int gtco_probe(struct usb_interface *usbinterface,
        dbg("num endpoints:     %d", usbinterface->cur_altsetting->desc.bNumEndpoints);
        dbg("interface class:   %d", usbinterface->cur_altsetting->desc.bInterfaceClass);
        dbg("endpoint: attribute:0x%x type:0x%x", endpoint->bmAttributes, endpoint->bDescriptorType);
-       if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT)
+       if (usb_endpoint_xfer_int(endpoint))
                dbg("endpoint: we have interrupt endpoint\n");
 
        dbg("endpoint extra len:%d ", usbinterface->altsetting[0].extralen);
index 8dc8d1e59beaeeb1a1f154ba122e929d7f45e492..2638811c61ace2eff774a5bf212f1043036e978a 100644 (file)
@@ -535,7 +535,7 @@ static int wacom_intuos_irq(struct wacom_wac *wacom, void *wcombo)
        return 1;
 }
 
-int wacom_tpc_irq(struct wacom_wac *wacom, void *wcombo)
+static int wacom_tpc_irq(struct wacom_wac *wacom, void *wcombo)
 {
        char *data = wacom->data;
        int prox = 0, pressure;
index 3d1ab8fa9accb88e341f4d66748c7cf0b09db3f0..bb6486a8c070f599430020681c395e9e59300eb9 100644 (file)
@@ -58,6 +58,14 @@ config TOUCHSCREEN_CORGI
          NOTE: this driver is deprecated, try enable SPI and generic
          ADS7846-based touchscreen driver.
 
+config TOUCHSCREEN_DA9034
+       tristate "Touchscreen support for Dialog Semiconductor DA9034"
+       depends on PMIC_DA903X
+       default y
+       help
+         Say Y here to enable the support for the touchscreen found
+         on Dialog Semiconductor DA9034 PMIC.
+
 config TOUCHSCREEN_FUJITSU
        tristate "Fujitsu serial touchscreen"
        select SERIO
@@ -95,6 +103,19 @@ config TOUCHSCREEN_ELO
          To compile this driver as a module, choose M here: the
          module will be called elo.
 
+config TOUCHSCREEN_WACOM_W8001
+       tristate "Wacom W8001 penabled serial touchscreen"
+       select SERIO
+       help
+         Say Y here if you have an Wacom W8001 penabled serial touchscreen
+         connected to your system.
+
+         If unsure, say N.
+
+         To compile this driver as a module, choose M here: the
+         module will be called wacom_w8001.
+
+
 config TOUCHSCREEN_MTOUCH
        tristate "MicroTouch serial touchscreens"
        select SERIO
@@ -376,4 +397,15 @@ config TOUCHSCREEN_TOUCHIT213
          To compile this driver as a module, choose M here: the
          module will be called touchit213.
 
+config TOUCHSCREEN_TSC2007
+       tristate "TSC2007 based touchscreens"
+       depends on I2C
+       help
+         Say Y here if you have a TSC2007 based touchscreen.
+
+         If unsure, say N.
+
+         To compile this driver as a module, choose M here: the
+         module will be called tsc2007.
+
 endif
index 15cf2907948952df00b961ad2f0d97407b4a2faa..d3375aff46fe14303ed44f44e686213485aafb20 100644 (file)
@@ -25,8 +25,11 @@ obj-$(CONFIG_TOUCHSCREEN_PENMOUNT)   += penmount.o
 obj-$(CONFIG_TOUCHSCREEN_TOUCHIT213)   += touchit213.o
 obj-$(CONFIG_TOUCHSCREEN_TOUCHRIGHT)   += touchright.o
 obj-$(CONFIG_TOUCHSCREEN_TOUCHWIN)     += touchwin.o
+obj-$(CONFIG_TOUCHSCREEN_TSC2007)      += tsc2007.o
 obj-$(CONFIG_TOUCHSCREEN_UCB1400)      += ucb1400_ts.o
+obj-$(CONFIG_TOUCHSCREEN_WACOM_W8001)  += wacom_w8001.o
 obj-$(CONFIG_TOUCHSCREEN_WM97XX)       += wm97xx-ts.o
+obj-$(CONFIG_TOUCHSCREEN_DA9034)       += da9034-ts.o
 wm97xx-ts-$(CONFIG_TOUCHSCREEN_WM9705) += wm9705.o
 wm97xx-ts-$(CONFIG_TOUCHSCREEN_WM9712) += wm9712.o
 wm97xx-ts-$(CONFIG_TOUCHSCREEN_WM9713) += wm9713.o
index e1ece89fe9222b5ef810516ca0ea7384fd98eb2e..7c27c8b9b6d0e1b8d23199f584332119b541ba06 100644 (file)
@@ -472,7 +472,7 @@ static ssize_t ads7846_disable_store(struct device *dev,
                                     const char *buf, size_t count)
 {
        struct ads7846 *ts = dev_get_drvdata(dev);
-       long i;
+       unsigned long i;
 
        if (strict_strtoul(buf, 10, &i))
                return -EINVAL;
@@ -559,7 +559,7 @@ static void ads7846_rx(void *ads)
        if (packet->tc.ignore || Rt > ts->pressure_max) {
 #ifdef VERBOSE
                pr_debug("%s: ignored %d pressure %d\n",
-                       ts->spi->dev.bus_id, packet->tc.ignore, Rt);
+                       dev_name(&ts->spi->dev), packet->tc.ignore, Rt);
 #endif
                hrtimer_start(&ts->timer, ktime_set(0, TS_POLL_PERIOD),
                              HRTIMER_MODE_REL);
@@ -947,7 +947,7 @@ static int __devinit ads7846_probe(struct spi_device *spi)
                ts->penirq_recheck_delay_usecs =
                                pdata->penirq_recheck_delay_usecs;
 
-       snprintf(ts->phys, sizeof(ts->phys), "%s/input0", spi->dev.bus_id);
+       snprintf(ts->phys, sizeof(ts->phys), "%s/input0", dev_name(&spi->dev));
 
        input_dev->name = "ADS784x Touchscreen";
        input_dev->phys = ts->phys;
diff --git a/drivers/input/touchscreen/da9034-ts.c b/drivers/input/touchscreen/da9034-ts.c
new file mode 100644 (file)
index 0000000..4342e77
--- /dev/null
@@ -0,0 +1,389 @@
+/*
+ * Touchscreen driver for Dialog Semiconductor DA9034
+ *
+ * Copyright (C) 2006-2008 Marvell International Ltd.
+ *     Fengwei Yin <fengwei.yin@marvell.com>
+ *     Eric Miao <eric.miao@marvell.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.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/input.h>
+#include <linux/mfd/da903x.h>
+
+#define DA9034_MANUAL_CTRL     0x50
+#define DA9034_LDO_ADC_EN      (1 << 4)
+
+#define DA9034_AUTO_CTRL1      0x51
+
+#define DA9034_AUTO_CTRL2      0x52
+#define DA9034_AUTO_TSI_EN     (1 << 3)
+#define DA9034_PEN_DETECT      (1 << 4)
+
+#define DA9034_TSI_CTRL1       0x53
+#define DA9034_TSI_CTRL2       0x54
+#define DA9034_TSI_X_MSB       0x6c
+#define DA9034_TSI_Y_MSB       0x6d
+#define DA9034_TSI_XY_LSB      0x6e
+
+enum {
+       STATE_IDLE,     /* wait for pendown */
+       STATE_BUSY,     /* TSI busy sampling */
+       STATE_STOP,     /* sample available */
+       STATE_WAIT,     /* Wait to start next sample */
+};
+
+enum {
+       EVENT_PEN_DOWN,
+       EVENT_PEN_UP,
+       EVENT_TSI_READY,
+       EVENT_TIMEDOUT,
+};
+
+struct da9034_touch {
+       struct device           *da9034_dev;
+       struct input_dev        *input_dev;
+
+       struct delayed_work     tsi_work;
+       struct notifier_block   notifier;
+
+       int     state;
+
+       int     interval_ms;
+       int     x_inverted;
+       int     y_inverted;
+
+       int     last_x;
+       int     last_y;
+};
+
+static inline int is_pen_down(struct da9034_touch *touch)
+{
+       return da903x_query_status(touch->da9034_dev, DA9034_STATUS_PEN_DOWN);
+}
+
+static inline int detect_pen_down(struct da9034_touch *touch, int on)
+{
+       if (on)
+               return da903x_set_bits(touch->da9034_dev,
+                               DA9034_AUTO_CTRL2, DA9034_PEN_DETECT);
+       else
+               return da903x_clr_bits(touch->da9034_dev,
+                               DA9034_AUTO_CTRL2, DA9034_PEN_DETECT);
+}
+
+static int read_tsi(struct da9034_touch *touch)
+{
+       uint8_t _x, _y, _v;
+       int ret;
+
+       ret = da903x_read(touch->da9034_dev, DA9034_TSI_X_MSB, &_x);
+       if (ret)
+               return ret;
+
+       ret = da903x_read(touch->da9034_dev, DA9034_TSI_Y_MSB, &_y);
+       if (ret)
+               return ret;
+
+       ret = da903x_read(touch->da9034_dev, DA9034_TSI_XY_LSB, &_v);
+       if (ret)
+               return ret;
+
+       touch->last_x = ((_x << 2) & 0x3fc) | (_v & 0x3);
+       touch->last_y = ((_y << 2) & 0x3fc) | ((_v & 0xc) >> 2);
+
+       return 0;
+}
+
+static inline int start_tsi(struct da9034_touch *touch)
+{
+       return da903x_set_bits(touch->da9034_dev,
+                       DA9034_AUTO_CTRL2, DA9034_AUTO_TSI_EN);
+}
+
+static inline int stop_tsi(struct da9034_touch *touch)
+{
+       return da903x_clr_bits(touch->da9034_dev,
+                       DA9034_AUTO_CTRL2, DA9034_AUTO_TSI_EN);
+}
+
+static inline void report_pen_down(struct da9034_touch *touch)
+{
+       int x = touch->last_x;
+       int y = touch->last_y;
+
+       x &= 0xfff;
+       if (touch->x_inverted)
+               x = 1024 - x;
+       y &= 0xfff;
+       if (touch->y_inverted)
+               y = 1024 - y;
+
+       input_report_abs(touch->input_dev, ABS_X, x);
+       input_report_abs(touch->input_dev, ABS_Y, y);
+       input_report_key(touch->input_dev, BTN_TOUCH, 1);
+
+       input_sync(touch->input_dev);
+}
+
+static inline void report_pen_up(struct da9034_touch *touch)
+{
+       input_report_key(touch->input_dev, BTN_TOUCH, 0);
+       input_sync(touch->input_dev);
+}
+
+static void da9034_event_handler(struct da9034_touch *touch, int event)
+{
+       int err;
+
+       switch (touch->state) {
+       case STATE_IDLE:
+               if (event != EVENT_PEN_DOWN)
+                       break;
+
+               /* Enable auto measurement of the TSI, this will
+                * automatically disable pen down detection
+                */
+               err = start_tsi(touch);
+               if (err)
+                       goto err_reset;
+
+               touch->state = STATE_BUSY;
+               break;
+
+       case STATE_BUSY:
+               if (event != EVENT_TSI_READY)
+                       break;
+
+               err = read_tsi(touch);
+               if (err)
+                       goto err_reset;
+
+               /* Disable auto measurement of the TSI, so that
+                * pen down status will be available
+                */
+               err = stop_tsi(touch);
+               if (err)
+                       goto err_reset;
+
+               touch->state = STATE_STOP;
+               break;
+
+       case STATE_STOP:
+               if (event == EVENT_PEN_DOWN) {
+                       report_pen_down(touch);
+                       schedule_delayed_work(&touch->tsi_work,
+                               msecs_to_jiffies(touch->interval_ms));
+                       touch->state = STATE_WAIT;
+               }
+
+               if (event == EVENT_PEN_UP) {
+                       report_pen_up(touch);
+                       touch->state = STATE_IDLE;
+               }
+
+               input_sync(touch->input_dev);
+               break;
+
+       case STATE_WAIT:
+               if (event != EVENT_TIMEDOUT)
+                       break;
+
+               if (is_pen_down(touch)) {
+                       start_tsi(touch);
+                       touch->state = STATE_BUSY;
+               } else
+                       touch->state = STATE_IDLE;
+               break;
+       }
+       return;
+
+err_reset:
+       touch->state = STATE_IDLE;
+       stop_tsi(touch);
+       detect_pen_down(touch, 1);
+}
+
+static void da9034_tsi_work(struct work_struct *work)
+{
+       struct da9034_touch *touch =
+               container_of(work, struct da9034_touch, tsi_work.work);
+
+       da9034_event_handler(touch, EVENT_TIMEDOUT);
+}
+
+static int da9034_touch_notifier(struct notifier_block *nb,
+                                unsigned long event, void *data)
+{
+       struct da9034_touch *touch =
+               container_of(nb, struct da9034_touch, notifier);
+
+       if (event & DA9034_EVENT_PEN_DOWN) {
+               if (is_pen_down(touch))
+                       da9034_event_handler(touch, EVENT_PEN_DOWN);
+               else
+                       da9034_event_handler(touch, EVENT_PEN_UP);
+       }
+
+       if (event & DA9034_EVENT_TSI_READY)
+               da9034_event_handler(touch, EVENT_TSI_READY);
+
+       return 0;
+}
+
+static int da9034_touch_open(struct input_dev *dev)
+{
+       struct da9034_touch *touch = input_get_drvdata(dev);
+       int ret;
+
+       ret = da903x_register_notifier(touch->da9034_dev, &touch->notifier,
+                       DA9034_EVENT_PEN_DOWN | DA9034_EVENT_TSI_READY);
+       if (ret)
+               return -EBUSY;
+
+       /* Enable ADC LDO */
+       ret = da903x_set_bits(touch->da9034_dev,
+                       DA9034_MANUAL_CTRL, DA9034_LDO_ADC_EN);
+       if (ret)
+               return ret;
+
+       /* TSI_DELAY: 3 slots, TSI_SKIP: 3 slots */
+       ret = da903x_write(touch->da9034_dev, DA9034_TSI_CTRL1, 0x1b);
+       if (ret)
+               return ret;
+
+       ret = da903x_write(touch->da9034_dev, DA9034_TSI_CTRL2, 0x00);
+       if (ret)
+               return ret;
+
+       touch->state = STATE_IDLE;
+       detect_pen_down(touch, 1);
+
+       return 0;
+}
+
+static void da9034_touch_close(struct input_dev *dev)
+{
+       struct da9034_touch *touch = input_get_drvdata(dev);
+
+       da903x_unregister_notifier(touch->da9034_dev, &touch->notifier,
+                       DA9034_EVENT_PEN_DOWN | DA9034_EVENT_TSI_READY);
+
+       cancel_delayed_work_sync(&touch->tsi_work);
+
+       touch->state = STATE_IDLE;
+       stop_tsi(touch);
+       detect_pen_down(touch, 0);
+
+       /* Disable ADC LDO */
+       da903x_clr_bits(touch->da9034_dev,
+                       DA9034_MANUAL_CTRL, DA9034_LDO_ADC_EN);
+}
+
+
+static int __devinit da9034_touch_probe(struct platform_device *pdev)
+{
+       struct da9034_touch_pdata *pdata = pdev->dev.platform_data;
+       struct da9034_touch *touch;
+       struct input_dev *input_dev;
+       int ret;
+
+       touch = kzalloc(sizeof(struct da9034_touch), GFP_KERNEL);
+       if (touch == NULL) {
+               dev_err(&pdev->dev, "failed to allocate driver data\n");
+               return -ENOMEM;
+       }
+
+       touch->da9034_dev = pdev->dev.parent;
+
+       if (pdata) {
+               touch->interval_ms      = pdata->interval_ms;
+               touch->x_inverted       = pdata->x_inverted;
+               touch->y_inverted       = pdata->y_inverted;
+       } else
+               /* fallback into default */
+               touch->interval_ms      = 10;
+
+       INIT_DELAYED_WORK(&touch->tsi_work, da9034_tsi_work);
+       touch->notifier.notifier_call = da9034_touch_notifier;
+
+       input_dev = input_allocate_device();
+       if (!input_dev) {
+               dev_err(&pdev->dev, "failed to allocate input device\n");
+               ret = -ENOMEM;
+               goto err_free_touch;
+       }
+
+       input_dev->name         = pdev->name;
+       input_dev->open         = da9034_touch_open;
+       input_dev->close        = da9034_touch_close;
+       input_dev->dev.parent   = &pdev->dev;
+
+       __set_bit(EV_ABS, input_dev->evbit);
+       __set_bit(ABS_X, input_dev->absbit);
+       __set_bit(ABS_Y, input_dev->absbit);
+       input_set_abs_params(input_dev, ABS_X, 0, 1023, 0, 0);
+       input_set_abs_params(input_dev, ABS_Y, 0, 1023, 0, 0);
+
+       __set_bit(EV_KEY, input_dev->evbit);
+       __set_bit(BTN_TOUCH, input_dev->keybit);
+
+       touch->input_dev = input_dev;
+       input_set_drvdata(input_dev, touch);
+
+       ret = input_register_device(input_dev);
+       if (ret)
+               goto err_free_input;
+
+       platform_set_drvdata(pdev, touch);
+       return 0;
+
+err_free_input:
+       input_free_device(input_dev);
+err_free_touch:
+       kfree(touch);
+       return ret;
+}
+
+static int __devexit da9034_touch_remove(struct platform_device *pdev)
+{
+       struct da9034_touch *touch = platform_get_drvdata(pdev);
+
+       input_unregister_device(touch->input_dev);
+       kfree(touch);
+
+       return 0;
+}
+
+static struct platform_driver da9034_touch_driver = {
+       .driver = {
+               .name   = "da9034-touch",
+               .owner  = THIS_MODULE,
+       },
+       .probe          = da9034_touch_probe,
+       .remove         = __devexit_p(da9034_touch_remove),
+};
+
+static int __init da9034_touch_init(void)
+{
+       return platform_driver_register(&da9034_touch_driver);
+}
+module_init(da9034_touch_init);
+
+static void __exit da9034_touch_exit(void)
+{
+       platform_driver_unregister(&da9034_touch_driver);
+}
+module_exit(da9034_touch_exit);
+
+MODULE_DESCRIPTION("Touchscreen driver for Dialog Semiconductor DA9034");
+MODULE_AUTHOR("Eric Miao <eric.miao@marvell.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:da9034-touch");
diff --git a/drivers/input/touchscreen/tsc2007.c b/drivers/input/touchscreen/tsc2007.c
new file mode 100644 (file)
index 0000000..b75dc29
--- /dev/null
@@ -0,0 +1,381 @@
+/*
+ * drivers/input/touchscreen/tsc2007.c
+ *
+ * Copyright (c) 2008 MtekVision Co., Ltd.
+ *     Kwangwoo Lee <kwlee@mtekvision.com>
+ *
+ * Using code from:
+ *  - ads7846.c
+ *     Copyright (c) 2005 David Brownell
+ *     Copyright (c) 2006 Nokia Corporation
+ *  - corgi_ts.c
+ *     Copyright (C) 2004-2005 Richard Purdie
+ *  - omap_ts.[hc], ads7846.h, ts_osk.c
+ *     Copyright (C) 2002 MontaVista Software
+ *     Copyright (C) 2004 Texas Instruments
+ *     Copyright (C) 2005 Dirk Behme
+ *
+ *  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/module.h>
+#include <linux/hrtimer.h>
+#include <linux/slab.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/i2c.h>
+#include <linux/i2c/tsc2007.h>
+
+#define TS_POLL_DELAY  (10 * 1000)     /* ns delay before the first sample */
+#define TS_POLL_PERIOD (5 * 1000)      /* ns delay between samples */
+
+#define TSC2007_MEASURE_TEMP0          (0x0 << 4)
+#define TSC2007_MEASURE_AUX            (0x2 << 4)
+#define TSC2007_MEASURE_TEMP1          (0x4 << 4)
+#define TSC2007_ACTIVATE_XN            (0x8 << 4)
+#define TSC2007_ACTIVATE_YN            (0x9 << 4)
+#define TSC2007_ACTIVATE_YP_XN         (0xa << 4)
+#define TSC2007_SETUP                  (0xb << 4)
+#define TSC2007_MEASURE_X              (0xc << 4)
+#define TSC2007_MEASURE_Y              (0xd << 4)
+#define TSC2007_MEASURE_Z1             (0xe << 4)
+#define TSC2007_MEASURE_Z2             (0xf << 4)
+
+#define TSC2007_POWER_OFF_IRQ_EN       (0x0 << 2)
+#define TSC2007_ADC_ON_IRQ_DIS0                (0x1 << 2)
+#define TSC2007_ADC_OFF_IRQ_EN         (0x2 << 2)
+#define TSC2007_ADC_ON_IRQ_DIS1                (0x3 << 2)
+
+#define TSC2007_12BIT                  (0x0 << 1)
+#define TSC2007_8BIT                   (0x1 << 1)
+
+#define        MAX_12BIT                       ((1 << 12) - 1)
+
+#define ADC_ON_12BIT   (TSC2007_12BIT | TSC2007_ADC_ON_IRQ_DIS0)
+
+#define READ_Y         (ADC_ON_12BIT | TSC2007_MEASURE_Y)
+#define READ_Z1                (ADC_ON_12BIT | TSC2007_MEASURE_Z1)
+#define READ_Z2                (ADC_ON_12BIT | TSC2007_MEASURE_Z2)
+#define READ_X         (ADC_ON_12BIT | TSC2007_MEASURE_X)
+#define PWRDOWN                (TSC2007_12BIT | TSC2007_POWER_OFF_IRQ_EN)
+
+struct ts_event {
+       u16     x;
+       u16     y;
+       u16     z1, z2;
+};
+
+struct tsc2007 {
+       struct input_dev        *input;
+       char                    phys[32];
+       struct hrtimer          timer;
+       struct ts_event         tc;
+
+       struct i2c_client       *client;
+
+       spinlock_t              lock;
+
+       u16                     model;
+       u16                     x_plate_ohms;
+
+       unsigned                pendown;
+       int                     irq;
+
+       int                     (*get_pendown_state)(void);
+       void                    (*clear_penirq)(void);
+};
+
+static inline int tsc2007_xfer(struct tsc2007 *tsc, u8 cmd)
+{
+       s32 data;
+       u16 val;
+
+       data = i2c_smbus_read_word_data(tsc->client, cmd);
+       if (data < 0) {
+               dev_err(&tsc->client->dev, "i2c io error: %d\n", data);
+               return data;
+       }
+
+       /* The protocol and raw data format from i2c interface:
+        * S Addr Wr [A] Comm [A] S Addr Rd [A] [DataLow] A [DataHigh] NA P
+        * Where DataLow has [D11-D4], DataHigh has [D3-D0 << 4 | Dummy 4bit].
+        */
+       val = swab16(data) >> 4;
+
+       dev_dbg(&tsc->client->dev, "data: 0x%x, val: 0x%x\n", data, val);
+
+       return val;
+}
+
+static void tsc2007_send_event(void *tsc)
+{
+       struct tsc2007  *ts = tsc;
+       u32             rt;
+       u16             x, y, z1, z2;
+
+       x = ts->tc.x;
+       y = ts->tc.y;
+       z1 = ts->tc.z1;
+       z2 = ts->tc.z2;
+
+       /* range filtering */
+       if (x == MAX_12BIT)
+               x = 0;
+
+       if (likely(x && z1)) {
+               /* compute touch pressure resistance using equation #1 */
+               rt = z2;
+               rt -= z1;
+               rt *= x;
+               rt *= ts->x_plate_ohms;
+               rt /= z1;
+               rt = (rt + 2047) >> 12;
+       } else
+               rt = 0;
+
+       /* Sample found inconsistent by debouncing or pressure is beyond
+        * the maximum. Don't report it to user space, repeat at least
+        * once more the measurement
+        */
+       if (rt > MAX_12BIT) {
+               dev_dbg(&ts->client->dev, "ignored pressure %d\n", rt);
+
+               hrtimer_start(&ts->timer, ktime_set(0, TS_POLL_PERIOD),
+                             HRTIMER_MODE_REL);
+               return;
+       }
+
+       /* NOTE: We can't rely on the pressure to determine the pen down
+        * state, even this controller has a pressure sensor.  The pressure
+        * value can fluctuate for quite a while after lifting the pen and
+        * in some cases may not even settle at the expected value.
+        *
+        * The only safe way to check for the pen up condition is in the
+        * timer by reading the pen signal state (it's a GPIO _and_ IRQ).
+        */
+       if (rt) {
+               struct input_dev *input = ts->input;
+
+               if (!ts->pendown) {
+                       dev_dbg(&ts->client->dev, "DOWN\n");
+
+                       input_report_key(input, BTN_TOUCH, 1);
+                       ts->pendown = 1;
+               }
+
+               input_report_abs(input, ABS_X, x);
+               input_report_abs(input, ABS_Y, y);
+               input_report_abs(input, ABS_PRESSURE, rt);
+
+               input_sync(input);
+
+               dev_dbg(&ts->client->dev, "point(%4d,%4d), pressure (%4u)\n",
+                       x, y, rt);
+       }
+
+       hrtimer_start(&ts->timer, ktime_set(0, TS_POLL_PERIOD),
+                       HRTIMER_MODE_REL);
+}
+
+static int tsc2007_read_values(struct tsc2007 *tsc)
+{
+       /* y- still on; turn on only y+ (and ADC) */
+       tsc->tc.y = tsc2007_xfer(tsc, READ_Y);
+
+       /* turn y- off, x+ on, then leave in lowpower */
+       tsc->tc.x = tsc2007_xfer(tsc, READ_X);
+
+       /* turn y+ off, x- on; we'll use formula #1 */
+       tsc->tc.z1 = tsc2007_xfer(tsc, READ_Z1);
+       tsc->tc.z2 = tsc2007_xfer(tsc, READ_Z2);
+
+       /* power down */
+       tsc2007_xfer(tsc, PWRDOWN);
+
+       return 0;
+}
+
+static enum hrtimer_restart tsc2007_timer(struct hrtimer *handle)
+{
+       struct tsc2007 *ts = container_of(handle, struct tsc2007, timer);
+
+       spin_lock_irq(&ts->lock);
+
+       if (unlikely(!ts->get_pendown_state() && ts->pendown)) {
+               struct input_dev *input = ts->input;
+
+               dev_dbg(&ts->client->dev, "UP\n");
+
+               input_report_key(input, BTN_TOUCH, 0);
+               input_report_abs(input, ABS_PRESSURE, 0);
+               input_sync(input);
+
+               ts->pendown = 0;
+               enable_irq(ts->irq);
+       } else {
+               /* pen is still down, continue with the measurement */
+               dev_dbg(&ts->client->dev, "pen is still down\n");
+
+               tsc2007_read_values(ts);
+               tsc2007_send_event(ts);
+       }
+
+       spin_unlock_irq(&ts->lock);
+
+       return HRTIMER_NORESTART;
+}
+
+static irqreturn_t tsc2007_irq(int irq, void *handle)
+{
+       struct tsc2007 *ts = handle;
+       unsigned long flags;
+
+       spin_lock_irqsave(&ts->lock, flags);
+
+       if (likely(ts->get_pendown_state())) {
+               disable_irq(ts->irq);
+               hrtimer_start(&ts->timer, ktime_set(0, TS_POLL_DELAY),
+                                       HRTIMER_MODE_REL);
+       }
+
+       if (ts->clear_penirq)
+               ts->clear_penirq();
+
+       spin_unlock_irqrestore(&ts->lock, flags);
+
+       return IRQ_HANDLED;
+}
+
+static int tsc2007_probe(struct i2c_client *client,
+                       const struct i2c_device_id *id)
+{
+       struct tsc2007 *ts;
+       struct tsc2007_platform_data *pdata = pdata = client->dev.platform_data;
+       struct input_dev *input_dev;
+       int err;
+
+       if (!pdata) {
+               dev_err(&client->dev, "platform data is required!\n");
+               return -EINVAL;
+       }
+
+       if (!i2c_check_functionality(client->adapter,
+                                    I2C_FUNC_SMBUS_READ_WORD_DATA))
+               return -EIO;
+
+       ts = kzalloc(sizeof(struct tsc2007), GFP_KERNEL);
+       input_dev = input_allocate_device();
+       if (!ts || !input_dev) {
+               err = -ENOMEM;
+               goto err_free_mem;
+       }
+
+       ts->client = client;
+       i2c_set_clientdata(client, ts);
+
+       ts->input = input_dev;
+
+       hrtimer_init(&ts->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+       ts->timer.function = tsc2007_timer;
+
+       spin_lock_init(&ts->lock);
+
+       ts->model             = pdata->model;
+       ts->x_plate_ohms      = pdata->x_plate_ohms;
+       ts->get_pendown_state = pdata->get_pendown_state;
+       ts->clear_penirq      = pdata->clear_penirq;
+
+       pdata->init_platform_hw();
+
+       snprintf(ts->phys, sizeof(ts->phys), "%s/input0", client->dev.bus_id);
+
+       input_dev->name = "TSC2007 Touchscreen";
+       input_dev->phys = ts->phys;
+       input_dev->id.bustype = BUS_I2C;
+
+       input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
+       input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
+
+       input_set_abs_params(input_dev, ABS_X, 0, MAX_12BIT, 0, 0);
+       input_set_abs_params(input_dev, ABS_Y, 0, MAX_12BIT, 0, 0);
+       input_set_abs_params(input_dev, ABS_PRESSURE, 0, MAX_12BIT, 0, 0);
+
+       tsc2007_read_values(ts);
+
+       ts->irq = client->irq;
+
+       err = request_irq(ts->irq, tsc2007_irq, 0,
+                       client->dev.driver->name, ts);
+       if (err < 0) {
+               dev_err(&client->dev, "irq %d busy?\n", ts->irq);
+               goto err_free_mem;
+       }
+
+       err = input_register_device(input_dev);
+       if (err)
+               goto err_free_irq;
+
+       dev_info(&client->dev, "registered with irq (%d)\n", ts->irq);
+
+       return 0;
+
+ err_free_irq:
+       free_irq(ts->irq, ts);
+       hrtimer_cancel(&ts->timer);
+ err_free_mem:
+       input_free_device(input_dev);
+       kfree(ts);
+       return err;
+}
+
+static int tsc2007_remove(struct i2c_client *client)
+{
+       struct tsc2007  *ts = i2c_get_clientdata(client);
+       struct tsc2007_platform_data *pdata;
+
+       pdata = client->dev.platform_data;
+       pdata->exit_platform_hw();
+
+       free_irq(ts->irq, ts);
+       hrtimer_cancel(&ts->timer);
+       input_unregister_device(ts->input);
+       kfree(ts);
+
+       return 0;
+}
+
+static struct i2c_device_id tsc2007_idtable[] = {
+       { "tsc2007", 0 },
+       { }
+};
+
+MODULE_DEVICE_TABLE(i2c, tsc2007_idtable);
+
+static struct i2c_driver tsc2007_driver = {
+       .driver = {
+               .owner  = THIS_MODULE,
+               .name   = "tsc2007"
+       },
+       .id_table       = tsc2007_idtable,
+       .probe          = tsc2007_probe,
+       .remove         = tsc2007_remove,
+};
+
+static int __init tsc2007_init(void)
+{
+       return i2c_add_driver(&tsc2007_driver);
+}
+
+static void __exit tsc2007_exit(void)
+{
+       i2c_del_driver(&tsc2007_driver);
+}
+
+module_init(tsc2007_init);
+module_exit(tsc2007_exit);
+
+MODULE_AUTHOR("Kwangwoo Lee <kwlee@mtekvision.com>");
+MODULE_DESCRIPTION("TSC2007 TouchScreen Driver");
+MODULE_LICENSE("GPL");
index fdd645c214a2dce90dfd9fc89059b4a6d8ff4789..5080b26ba1608ba2c54e1abe4de83d72d2ed62cf 100644 (file)
@@ -424,7 +424,7 @@ static int dmc_tsc10_init(struct usbtouch_usb *usbtouch)
                              0, 0, buf, 2, USB_CTRL_SET_TIMEOUT);
        if (ret < 0)
                goto err_out;
-       if (buf[0] != 0x06 || buf[1] != 0x00) {
+       if (buf[0] != 0x06) {
                ret = -ENODEV;
                goto err_out;
        }
@@ -437,8 +437,7 @@ static int dmc_tsc10_init(struct usbtouch_usb *usbtouch)
                              TSC10_RATE_150, 0, buf, 2, USB_CTRL_SET_TIMEOUT);
        if (ret < 0)
                goto err_out;
-       if ((buf[0] != 0x06 || buf[1] != 0x00) &&
-           (buf[0] != 0x15 || buf[1] != 0x01)) {
+       if ((buf[0] != 0x06) && (buf[0] != 0x15 || buf[1] != 0x01)) {
                ret = -ENODEV;
                goto err_out;
        }
diff --git a/drivers/input/touchscreen/wacom_w8001.c b/drivers/input/touchscreen/wacom_w8001.c
new file mode 100644 (file)
index 0000000..2f33a01
--- /dev/null
@@ -0,0 +1,325 @@
+/*
+ * Wacom W8001 penabled serial touchscreen driver
+ *
+ * Copyright (c) 2008 Jaya Kumar
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file COPYING in the main directory of this archive for
+ * more details.
+ *
+ * Layout based on Elo serial touchscreen driver by Vojtech Pavlik
+ */
+
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/input.h>
+#include <linux/serio.h>
+#include <linux/init.h>
+#include <linux/ctype.h>
+
+#define DRIVER_DESC    "Wacom W8001 serial touchscreen driver"
+
+MODULE_AUTHOR("Jaya Kumar <jayakumar.lkml@gmail.com>");
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+
+/*
+ * Definitions & global arrays.
+ */
+
+#define W8001_MAX_LENGTH       11
+#define W8001_PACKET_LEN       11
+#define W8001_LEAD_MASK 0x80
+#define W8001_LEAD_BYTE 0x80
+#define W8001_TAB_MASK 0x40
+#define W8001_TAB_BYTE 0x40
+
+#define W8001_QUERY_PACKET 0x20
+
+struct w8001_coord {
+       u8 rdy;
+       u8 tsw;
+       u8 f1;
+       u8 f2;
+       u16 x;
+       u16 y;
+       u16 pen_pressure;
+       u8 tilt_x;
+       u8 tilt_y;
+};
+
+/*
+ * Per-touchscreen data.
+ */
+
+struct w8001 {
+       struct input_dev *dev;
+       struct serio *serio;
+       struct mutex cmd_mutex;
+       struct completion cmd_done;
+       int id;
+       int idx;
+       unsigned char expected_packet;
+       unsigned char data[W8001_MAX_LENGTH];
+       unsigned char response[W8001_PACKET_LEN];
+       char phys[32];
+};
+
+static int parse_data(u8 *data, struct w8001_coord *coord)
+{
+       coord->rdy = data[0] & 0x20;
+       coord->tsw = data[0] & 0x01;
+       coord->f1 = data[0] & 0x02;
+       coord->f2 = data[0] & 0x04;
+
+       coord->x = (data[1] & 0x7F) << 9;
+       coord->x |= (data[2] & 0x7F) << 2;
+       coord->x |= (data[6] & 0x60) >> 5;
+
+       coord->y = (data[3] & 0x7F) << 9;
+       coord->y |= (data[4] & 0x7F) << 2;
+       coord->y |= (data[6] & 0x18) >> 3;
+
+       coord->pen_pressure = data[5] & 0x7F;
+       coord->pen_pressure |= (data[6] & 0x07) << 7 ;
+
+       coord->tilt_x = data[7] & 0x7F;
+       coord->tilt_y = data[8] & 0x7F;
+
+       return 0;
+}
+
+static void w8001_process_data(struct w8001 *w8001, unsigned char data)
+{
+       struct input_dev *dev = w8001->dev;
+       u8 tmp;
+       struct w8001_coord coord;
+
+       w8001->data[w8001->idx] = data;
+       switch (w8001->idx++) {
+       case 0:
+               if ((data & W8001_LEAD_MASK) != W8001_LEAD_BYTE) {
+                       pr_debug("w8001: unsynchronized data: 0x%02x\n", data);
+                       w8001->idx = 0;
+               }
+               break;
+       case 8:
+               tmp = w8001->data[0] & W8001_TAB_MASK;
+               if (unlikely(tmp == W8001_TAB_BYTE))
+                       break;
+               w8001->idx = 0;
+               memset(&coord, 0, sizeof(coord));
+               parse_data(w8001->data, &coord);
+               input_report_abs(dev, ABS_X, coord.x);
+               input_report_abs(dev, ABS_Y, coord.y);
+               input_report_abs(dev, ABS_PRESSURE, coord.pen_pressure);
+               input_report_key(dev, BTN_TOUCH, coord.tsw);
+               input_sync(dev);
+               break;
+       case 10:
+               w8001->idx = 0;
+               memcpy(w8001->response, &w8001->data, W8001_PACKET_LEN);
+               w8001->expected_packet = W8001_QUERY_PACKET;
+               complete(&w8001->cmd_done);
+               break;
+       }
+}
+
+
+static irqreturn_t w8001_interrupt(struct serio *serio,
+               unsigned char data, unsigned int flags)
+{
+       struct w8001 *w8001 = serio_get_drvdata(serio);
+
+       w8001_process_data(w8001, data);
+
+       return IRQ_HANDLED;
+}
+
+static int w8001_async_command(struct w8001 *w8001, unsigned char *packet,
+                                       int len)
+{
+       int rc = -1;
+       int i;
+
+       mutex_lock(&w8001->cmd_mutex);
+
+       for (i = 0; i < len; i++) {
+               if (serio_write(w8001->serio, packet[i]))
+                       goto out;
+       }
+       rc = 0;
+
+out:
+       mutex_unlock(&w8001->cmd_mutex);
+       return rc;
+}
+
+static int w8001_command(struct w8001 *w8001, unsigned char *packet, int len)
+{
+       int rc = -1;
+       int i;
+
+       mutex_lock(&w8001->cmd_mutex);
+
+       serio_pause_rx(w8001->serio);
+       init_completion(&w8001->cmd_done);
+       serio_continue_rx(w8001->serio);
+
+       for (i = 0; i < len; i++) {
+               if (serio_write(w8001->serio, packet[i]))
+                       goto out;
+       }
+
+       wait_for_completion_timeout(&w8001->cmd_done, HZ);
+
+       if (w8001->expected_packet == W8001_QUERY_PACKET) {
+               /* We are back in reporting mode, the query was ACKed */
+               memcpy(packet, w8001->response, W8001_PACKET_LEN);
+               rc = 0;
+       }
+
+out:
+       mutex_unlock(&w8001->cmd_mutex);
+       return rc;
+}
+
+static int w8001_setup(struct w8001 *w8001)
+{
+       struct w8001_coord coord;
+       struct input_dev *dev = w8001->dev;
+       unsigned char start[1] = { '1' };
+       unsigned char query[11] = { '*' };
+
+       if (w8001_command(w8001, query, 1))
+               return -1;
+
+       memset(&coord, 0, sizeof(coord));
+       parse_data(query, &coord);
+
+       input_set_abs_params(dev, ABS_X, 0, coord.x, 0, 0);
+       input_set_abs_params(dev, ABS_Y, 0, coord.y, 0, 0);
+       input_set_abs_params(dev, ABS_PRESSURE, 0, coord.pen_pressure, 0, 0);
+       input_set_abs_params(dev, ABS_TILT_X, 0, coord.tilt_x, 0, 0);
+       input_set_abs_params(dev, ABS_TILT_Y, 0, coord.tilt_y, 0, 0);
+
+       if (w8001_async_command(w8001, start, 1))
+               return -1;
+
+       return 0;
+}
+
+/*
+ * w8001_disconnect() is the opposite of w8001_connect()
+ */
+
+static void w8001_disconnect(struct serio *serio)
+{
+       struct w8001 *w8001 = serio_get_drvdata(serio);
+
+       input_get_device(w8001->dev);
+       input_unregister_device(w8001->dev);
+       serio_close(serio);
+       serio_set_drvdata(serio, NULL);
+       input_put_device(w8001->dev);
+       kfree(w8001);
+}
+
+/*
+ * w8001_connect() is the routine that is called when someone adds a
+ * new serio device that supports the w8001 protocol and registers it as
+ * an input device.
+ */
+
+static int w8001_connect(struct serio *serio, struct serio_driver *drv)
+{
+       struct w8001 *w8001;
+       struct input_dev *input_dev;
+       int err;
+
+       w8001 = kzalloc(sizeof(struct w8001), GFP_KERNEL);
+       input_dev = input_allocate_device();
+       if (!w8001 || !input_dev) {
+               err = -ENOMEM;
+               goto fail1;
+       }
+
+       w8001->serio = serio;
+       w8001->id = serio->id.id;
+       w8001->dev = input_dev;
+       mutex_init(&w8001->cmd_mutex);
+       init_completion(&w8001->cmd_done);
+       snprintf(w8001->phys, sizeof(w8001->phys), "%s/input0", serio->phys);
+
+       input_dev->name = "Wacom W8001 Penabled Serial TouchScreen";
+       input_dev->phys = w8001->phys;
+       input_dev->id.bustype = BUS_RS232;
+       input_dev->id.vendor = SERIO_W8001;
+       input_dev->id.product = w8001->id;
+       input_dev->id.version = 0x0100;
+       input_dev->dev.parent = &serio->dev;
+
+       input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
+       input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
+
+       serio_set_drvdata(serio, w8001);
+       err = serio_open(serio, drv);
+       if (err)
+               goto fail2;
+
+       if (w8001_setup(w8001))
+               goto fail3;
+
+       err = input_register_device(w8001->dev);
+       if (err)
+               goto fail3;
+
+       return 0;
+
+fail3:
+       serio_close(serio);
+fail2:
+       serio_set_drvdata(serio, NULL);
+fail1:
+       input_free_device(input_dev);
+       kfree(w8001);
+       return err;
+}
+
+static struct serio_device_id w8001_serio_ids[] = {
+       {
+               .type   = SERIO_RS232,
+               .proto  = SERIO_W8001,
+               .id     = SERIO_ANY,
+               .extra  = SERIO_ANY,
+       },
+       { 0 }
+};
+
+MODULE_DEVICE_TABLE(serio, w8001_serio_ids);
+
+static struct serio_driver w8001_drv = {
+       .driver         = {
+               .name   = "w8001",
+       },
+       .description    = DRIVER_DESC,
+       .id_table       = w8001_serio_ids,
+       .interrupt      = w8001_interrupt,
+       .connect        = w8001_connect,
+       .disconnect     = w8001_disconnect,
+};
+
+static int __init w8001_init(void)
+{
+       return serio_register_driver(&w8001_drv);
+}
+
+static void __exit w8001_exit(void)
+{
+       serio_unregister_driver(&w8001_drv);
+}
+
+module_init(w8001_init);
+module_exit(w8001_exit);
index ec6ecd74781dca68bdf49c3ea1b80cc00b9d4966..1289fa7623ca22d7d79188bc39cf5b5b35c180b1 100644 (file)
@@ -15,6 +15,7 @@ struct gpio_keys_button {
 struct gpio_keys_platform_data {
        struct gpio_keys_button *buttons;
        int nbuttons;
+       unsigned int rep:1;             /* enable input subsystem auto repeat */
 };
 
 #endif
diff --git a/include/linux/i2c/tsc2007.h b/include/linux/i2c/tsc2007.h
new file mode 100644 (file)
index 0000000..c6361fb
--- /dev/null
@@ -0,0 +1,17 @@
+#ifndef __LINUX_I2C_TSC2007_H
+#define __LINUX_I2C_TSC2007_H
+
+/* linux/i2c/tsc2007.h */
+
+struct tsc2007_platform_data {
+       u16     model;                          /* 2007. */
+       u16     x_plate_ohms;
+
+       int     (*get_pendown_state)(void);
+       void    (*clear_penirq)(void);          /* If needed, clear 2nd level
+                                                  interrupt source */
+       int     (*init_platform_hw)(void);
+       void    (*exit_platform_hw)(void);
+};
+
+#endif
index afc413369101998ce5010ad56b23c752c68b4870..b94534b7e26658b805978e153339378c847575e8 100644 (file)
 #define PS2_RET_ID             0x00
 #define PS2_RET_ACK            0xfa
 #define PS2_RET_NAK            0xfe
+#define PS2_RET_ERR            0xfc
 
 #define PS2_FLAG_ACK           1       /* Waiting for ACK/NAK */
 #define PS2_FLAG_CMD           2       /* Waiting for command to finish */
 #define PS2_FLAG_CMD1          4       /* Waiting for the first byte of command response */
 #define PS2_FLAG_WAITID                8       /* Command execiting is GET ID */
+#define PS2_FLAG_NAK           16      /* Last transmission was NAKed */
 
 struct ps2dev {
        struct serio *serio;
index 7df8432c4402b576b9f1d5b116aea47a6182daef..12d62a54d47029383b79bdc3ed9b529fe21f6b90 100644 (file)
@@ -75,7 +75,7 @@ struct seg7_conversion_map {
        unsigned char   table[128];
 };
 
-static inline int map_to_seg7(struct seg7_conversion_map *map, int c)
+static __inline__ int map_to_seg7(struct seg7_conversion_map *map, int c)
 {
        return c >= 0 && c < sizeof(map->table) ? map->table[c] : -EINVAL;
 }
index 25641d9e0ea85c9901d42045a551580e6ccdecfd..1bcb357a01a1d00781b97fcad67eaa45dd82fba7 100644 (file)
@@ -213,5 +213,6 @@ static inline void serio_unpin_driver(struct serio *serio)
 #define SERIO_ZHENHUA  0x36
 #define SERIO_INEXIO   0x37
 #define SERIO_TOUCHIT213       0x37
+#define SERIO_W8001    0x39
 
 #endif