Merge branch 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/rydberg/input...
authorDmitry Torokhov <dmitry.torokhov@gmail.com>
Tue, 28 Dec 2010 01:33:20 +0000 (17:33 -0800)
committerDmitry Torokhov <dmitry.torokhov@gmail.com>
Tue, 28 Dec 2010 01:33:20 +0000 (17:33 -0800)
52 files changed:
Documentation/input/cma3000_d0x.txt [new file with mode: 0644]
arch/arm/plat-spear/include/plat/keyboard.h [new file with mode: 0644]
drivers/input/Makefile
drivers/input/apm-power.c
drivers/input/evbug.c
drivers/input/evdev.c
drivers/input/ff-core.c
drivers/input/ff-memless.c
drivers/input/gameport/gameport.c
drivers/input/input-polldev.c
drivers/input/input.c
drivers/input/joydev.c
drivers/input/joystick/iforce/Makefile
drivers/input/joystick/xpad.c
drivers/input/keyboard/Kconfig
drivers/input/keyboard/Makefile
drivers/input/keyboard/adp5588-keys.c
drivers/input/keyboard/atkbd.c
drivers/input/keyboard/spear-keyboard.c [new file with mode: 0644]
drivers/input/keyboard/tca6416-keypad.c
drivers/input/misc/Kconfig
drivers/input/misc/Makefile
drivers/input/misc/cma3000_d0x.c [new file with mode: 0644]
drivers/input/misc/cma3000_d0x.h [new file with mode: 0644]
drivers/input/misc/cma3000_d0x_i2c.c [new file with mode: 0644]
drivers/input/misc/pcf8574_keypad.c
drivers/input/mouse/hgpk.c
drivers/input/mouse/hgpk.h
drivers/input/mouse/psmouse-base.c
drivers/input/mouse/synaptics.c
drivers/input/mousedev.c
drivers/input/serio/ams_delta_serio.c
drivers/input/serio/ct82c710.c
drivers/input/serio/hil_mlc.c
drivers/input/serio/hp_sdc_mlc.c
drivers/input/serio/i8042-x86ia64io.h
drivers/input/serio/i8042.c
drivers/input/serio/i8042.h
drivers/input/serio/ps2mult.c
drivers/input/serio/serio.c
drivers/input/tablet/acecad.c
drivers/input/touchscreen/Kconfig
drivers/input/touchscreen/Makefile
drivers/input/touchscreen/bu21013_ts.c
drivers/input/touchscreen/qt602240_ts.c
drivers/input/touchscreen/st1232.c [new file with mode: 0644]
drivers/input/xen-kbdfront.c
drivers/macintosh/mac_hid.c
drivers/serial/kgdboc.c
include/linux/i2c/adp5588.h
include/linux/input.h
include/linux/input/cma3000.h [new file with mode: 0644]

diff --git a/Documentation/input/cma3000_d0x.txt b/Documentation/input/cma3000_d0x.txt
new file mode 100644 (file)
index 0000000..29d088d
--- /dev/null
@@ -0,0 +1,115 @@
+Kernel driver for CMA3000-D0x
+============================
+
+Supported chips:
+* VTI CMA3000-D0x
+Datasheet:
+  CMA3000-D0X Product Family Specification 8281000A.02.pdf
+  <http://www.vti.fi/en/>
+
+Author: Hemanth V <hemanthv@ti.com>
+
+
+Description
+-----------
+CMA3000 Tri-axis accelerometer supports Motion detect, Measurement and
+Free fall modes.
+
+Motion Detect Mode: Its the low power mode where interrupts are generated only
+when motion exceeds the defined thresholds.
+
+Measurement Mode: This mode is used to read the acceleration data on X,Y,Z
+axis and supports 400, 100, 40 Hz sample frequency.
+
+Free fall Mode: This mode is intended to save system resources.
+
+Threshold values: Chip supports defining threshold values for above modes
+which includes time and g value. Refer product specifications for more details.
+
+CMA3000 chip supports mutually exclusive I2C and SPI interfaces for
+communication, currently the driver supports I2C based communication only.
+Initial configuration for bus mode is set in non volatile memory and can later
+be modified through bus interface command.
+
+Driver reports acceleration data through input subsystem. It generates ABS_MISC
+event with value 1 when free fall is detected.
+
+Platform data need to be configured for initial default values.
+
+Platform Data
+-------------
+fuzz_x: Noise on X Axis
+
+fuzz_y: Noise on Y Axis
+
+fuzz_z: Noise on Z Axis
+
+g_range: G range in milli g i.e 2000 or 8000
+
+mode: Default Operating mode
+
+mdthr: Motion detect g range threshold value
+
+mdfftmr: Motion detect and free fall time threshold value
+
+ffthr: Free fall g range threshold value
+
+Input Interface
+--------------
+Input driver version is 1.0.0
+Input device ID: bus 0x18 vendor 0x0 product 0x0 version 0x0
+Input device name: "cma3000-accelerometer"
+Supported events:
+  Event type 0 (Sync)
+  Event type 3 (Absolute)
+    Event code 0 (X)
+      Value     47
+      Min    -8000
+      Max     8000
+      Fuzz     200
+    Event code 1 (Y)
+      Value    -28
+      Min    -8000
+      Max     8000
+      Fuzz     200
+    Event code 2 (Z)
+      Value    905
+      Min    -8000
+      Max     8000
+      Fuzz     200
+    Event code 40 (Misc)
+      Value      0
+      Min        0
+      Max        1
+  Event type 4 (Misc)
+
+
+Register/Platform parameters Description
+----------------------------------------
+
+mode:
+       0: power down mode
+       1: 100 Hz Measurement mode
+       2: 400 Hz Measurement mode
+       3: 40 Hz Measurement mode
+       4: Motion Detect mode (default)
+       5: 100 Hz Free fall mode
+       6: 40 Hz Free fall mode
+       7: Power off mode
+
+grange:
+       2000: 2000 mg or 2G Range
+       8000: 8000 mg or 8G Range
+
+mdthr:
+       X: X * 71mg (8G Range)
+       X: X * 18mg (2G Range)
+
+mdfftmr:
+       X: (X & 0x70) * 100 ms (MDTMR)
+          (X & 0x0F) * 2.5 ms (FFTMR 400 Hz)
+          (X & 0x0F) * 10 ms  (FFTMR 100 Hz)
+
+ffthr:
+       X: (X >> 2) * 18mg (2G Range)
+       X: (X & 0x0F) * 71 mg (8G Range)
diff --git a/arch/arm/plat-spear/include/plat/keyboard.h b/arch/arm/plat-spear/include/plat/keyboard.h
new file mode 100644 (file)
index 0000000..68b5394
--- /dev/null
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2010 ST Microelectronics
+ * Rajeev Kumar<rajeev-dlh.kumar@st.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#ifndef __PLAT_KEYBOARD_H
+#define __PLAT_KEYBOARD_H
+
+#include <linux/bitops.h>
+#include <linux/input.h>
+#include <linux/input/matrix_keypad.h>
+#include <linux/types.h>
+
+#define DECLARE_KEYMAP(_name) \
+int _name[] = { \
+       KEY(0, 0, KEY_ESC), \
+       KEY(0, 1, KEY_1), \
+       KEY(0, 2, KEY_2), \
+       KEY(0, 3, KEY_3), \
+       KEY(0, 4, KEY_4), \
+       KEY(0, 5, KEY_5), \
+       KEY(0, 6, KEY_6), \
+       KEY(0, 7, KEY_7), \
+       KEY(0, 8, KEY_8), \
+       KEY(1, 0, KEY_9), \
+       KEY(1, 1, KEY_MINUS), \
+       KEY(1, 2, KEY_EQUAL), \
+       KEY(1, 3, KEY_BACKSPACE), \
+       KEY(1, 4, KEY_TAB), \
+       KEY(1, 5, KEY_Q), \
+       KEY(1, 6, KEY_W), \
+       KEY(1, 7, KEY_E), \
+       KEY(1, 8, KEY_R), \
+       KEY(2, 0, KEY_T), \
+       KEY(2, 1, KEY_Y), \
+       KEY(2, 2, KEY_U), \
+       KEY(2, 3, KEY_I), \
+       KEY(2, 4, KEY_O), \
+       KEY(2, 5, KEY_P), \
+       KEY(2, 6, KEY_LEFTBRACE), \
+       KEY(2, 7, KEY_RIGHTBRACE), \
+       KEY(2, 8, KEY_ENTER), \
+       KEY(3, 0, KEY_LEFTCTRL), \
+       KEY(3, 1, KEY_A), \
+       KEY(3, 2, KEY_S), \
+       KEY(3, 3, KEY_D), \
+       KEY(3, 4, KEY_F), \
+       KEY(3, 5, KEY_G), \
+       KEY(3, 6, KEY_H), \
+       KEY(3, 7, KEY_J), \
+       KEY(3, 8, KEY_K), \
+       KEY(4, 0, KEY_L), \
+       KEY(4, 1, KEY_SEMICOLON), \
+       KEY(4, 2, KEY_APOSTROPHE), \
+       KEY(4, 3, KEY_GRAVE), \
+       KEY(4, 4, KEY_LEFTSHIFT), \
+       KEY(4, 5, KEY_BACKSLASH), \
+       KEY(4, 6, KEY_Z), \
+       KEY(4, 7, KEY_X), \
+       KEY(4, 8, KEY_C), \
+       KEY(4, 0, KEY_L), \
+       KEY(4, 1, KEY_SEMICOLON), \
+       KEY(4, 2, KEY_APOSTROPHE), \
+       KEY(4, 3, KEY_GRAVE), \
+       KEY(4, 4, KEY_LEFTSHIFT), \
+       KEY(4, 5, KEY_BACKSLASH), \
+       KEY(4, 6, KEY_Z), \
+       KEY(4, 7, KEY_X), \
+       KEY(4, 8, KEY_C), \
+       KEY(4, 0, KEY_L), \
+       KEY(4, 1, KEY_SEMICOLON), \
+       KEY(4, 2, KEY_APOSTROPHE), \
+       KEY(4, 3, KEY_GRAVE), \
+       KEY(4, 4, KEY_LEFTSHIFT), \
+       KEY(4, 5, KEY_BACKSLASH), \
+       KEY(4, 6, KEY_Z), \
+       KEY(4, 7, KEY_X), \
+       KEY(4, 8, KEY_C), \
+       KEY(5, 0, KEY_V), \
+       KEY(5, 1, KEY_B), \
+       KEY(5, 2, KEY_N), \
+       KEY(5, 3, KEY_M), \
+       KEY(5, 4, KEY_COMMA), \
+       KEY(5, 5, KEY_DOT), \
+       KEY(5, 6, KEY_SLASH), \
+       KEY(5, 7, KEY_RIGHTSHIFT), \
+       KEY(5, 8, KEY_KPASTERISK), \
+       KEY(6, 0, KEY_LEFTALT), \
+       KEY(6, 1, KEY_SPACE), \
+       KEY(6, 2, KEY_CAPSLOCK), \
+       KEY(6, 3, KEY_F1), \
+       KEY(6, 4, KEY_F2), \
+       KEY(6, 5, KEY_F3), \
+       KEY(6, 6, KEY_F4), \
+       KEY(6, 7, KEY_F5), \
+       KEY(6, 8, KEY_F6), \
+       KEY(7, 0, KEY_F7), \
+       KEY(7, 1, KEY_F8), \
+       KEY(7, 2, KEY_F9), \
+       KEY(7, 3, KEY_F10), \
+       KEY(7, 4, KEY_NUMLOCK), \
+       KEY(7, 5, KEY_SCROLLLOCK), \
+       KEY(7, 6, KEY_KP7), \
+       KEY(7, 7, KEY_KP8), \
+       KEY(7, 8, KEY_KP9), \
+       KEY(8, 0, KEY_KPMINUS), \
+       KEY(8, 1, KEY_KP4), \
+       KEY(8, 2, KEY_KP5), \
+       KEY(8, 3, KEY_KP6), \
+       KEY(8, 4, KEY_KPPLUS), \
+       KEY(8, 5, KEY_KP1), \
+       KEY(8, 6, KEY_KP2), \
+       KEY(8, 7, KEY_KP3), \
+       KEY(8, 8, KEY_KP0), \
+}
+
+/**
+ * struct kbd_platform_data - spear keyboard platform data
+ * keymap: pointer to keymap data (table and size)
+ * rep: enables key autorepeat
+ *
+ * This structure is supposed to be used by platform code to supply
+ * keymaps to drivers that implement keyboards.
+ */
+struct kbd_platform_data {
+       const struct matrix_keymap_data *keymap;
+       bool rep;
+};
+
+/* This function is used to set platform data field of pdev->dev */
+static inline void
+kbd_set_plat_data(struct platform_device *pdev, struct kbd_platform_data *data)
+{
+       pdev->dev.platform_data = data;
+}
+
+#endif /* __PLAT_KEYBOARD_H */
index 569938b..09614ce 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 input-compat.o ff-core.o input-mt.o
+input-core-y := input.o input-compat.o input-mt.o ff-core.o
 
 obj-$(CONFIG_INPUT_FF_MEMLESS) += ff-memless.o
 obj-$(CONFIG_INPUT_POLLDEV)    += input-polldev.o
index 7d61a96..e90ee3d 100644 (file)
@@ -9,6 +9,8 @@
  *
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/input.h>
 #include <linux/slab.h>
@@ -23,8 +25,7 @@ static void system_power_event(unsigned int keycode)
        switch (keycode) {
        case KEY_SUSPEND:
                apm_queue_event(APM_USER_SUSPEND);
-
-               printk(KERN_INFO "apm-power: Requesting system suspend...\n");
+               pr_info("Requesting system suspend...\n");
                break;
        default:
                break;
@@ -65,18 +66,15 @@ static int apmpower_connect(struct input_handler *handler,
 
        error = input_register_handle(handle);
        if (error) {
-               printk(KERN_ERR
-                       "apm-power: Failed to register input power handler, "
-                       "error %d\n", error);
+               pr_err("Failed to register input power handler, error %d\n",
+                      error);
                kfree(handle);
                return error;
        }
 
        error = input_open_device(handle);
        if (error) {
-               printk(KERN_ERR
-                       "apm-power: Failed to open input power device, "
-                       "error %d\n", error);
+               pr_err("Failed to open input power device, error %d\n", error);
                input_unregister_handle(handle);
                kfree(handle);
                return error;
index f7c5c14..cd4e667 100644 (file)
@@ -26,6 +26,8 @@
  * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/slab.h>
 #include <linux/module.h>
 #include <linux/input.h>
@@ -38,8 +40,8 @@ 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",
-               dev_name(&handle->dev->dev), type, code, value);
+       printk(KERN_DEBUG pr_fmt("Event. Dev: %s, Type: %d, Code: %d, Value: %d\n"),
+              dev_name(&handle->dev->dev), type, code, value);
 }
 
 static int evbug_connect(struct input_handler *handler, struct input_dev *dev,
@@ -64,10 +66,10 @@ static int evbug_connect(struct input_handler *handler, struct input_dev *dev,
        if (error)
                goto err_unregister_handle;
 
-       printk(KERN_DEBUG "evbug.c: Connected device: %s (%s at %s)\n",
-               dev_name(&dev->dev),
-               dev->name ?: "unknown",
-               dev->phys ?: "unknown");
+       printk(KERN_DEBUG pr_fmt("Connected device: %s (%s at %s)\n"),
+              dev_name(&dev->dev),
+              dev->name ?: "unknown",
+              dev->phys ?: "unknown");
 
        return 0;
 
@@ -80,8 +82,8 @@ 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",
-               dev_name(&handle->dev->dev));
+       printk(KERN_DEBUG pr_fmt("Disconnected device: %s\n"),
+              dev_name(&handle->dev->dev));
 
        input_close_device(handle);
        input_unregister_handle(handle);
index 0cd97e8..f8635b7 100644 (file)
@@ -8,6 +8,8 @@
  * the Free Software Foundation.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #define EVDEV_MINOR_BASE       64
 #define EVDEV_MINORS           32
 #define EVDEV_MIN_BUFFER_SIZE  64U
@@ -522,12 +524,11 @@ static int handle_eviocgbit(struct input_dev *dev,
        if (type == EV_KEY && size == OLD_KEY_MAX) {
                len = OLD_KEY_MAX;
                if (printk_timed_ratelimit(&keymax_warn_time, 10 * 1000))
-                       printk(KERN_WARNING
-                               "evdev.c(EVIOCGBIT): Suspicious buffer size %u, "
-                               "limiting output to %zu bytes. See "
-                               "http://userweb.kernel.org/~dtor/eviocgbit-bug.html\n",
-                               OLD_KEY_MAX,
-                               BITS_TO_LONGS(OLD_KEY_MAX) * sizeof(long));
+                       pr_warning("(EVIOCGBIT): Suspicious buffer size %u, "
+                                  "limiting output to %zu bytes. See "
+                                  "http://userweb.kernel.org/~dtor/eviocgbit-bug.html\n",
+                                  OLD_KEY_MAX,
+                                  BITS_TO_LONGS(OLD_KEY_MAX) * sizeof(long));
        }
 
        return bits_to_user(bits, len, size, p, compat_mode);
@@ -898,7 +899,7 @@ static int evdev_connect(struct input_handler *handler, struct input_dev *dev,
                        break;
 
        if (minor == EVDEV_MINORS) {
-               printk(KERN_ERR "evdev: no more free evdev devices\n");
+               pr_err("no more free evdev devices\n");
                return -ENFILE;
        }
 
index 03078c0..3367f76 100644 (file)
@@ -23,7 +23,7 @@
 
 /* #define DEBUG */
 
-#define debug(format, arg...) pr_debug("ff-core: " format "\n", ## arg)
+#define pr_fmt(fmt) KBUILD_BASENAME ": " fmt
 
 #include <linux/input.h>
 #include <linux/module.h>
@@ -116,7 +116,7 @@ int input_ff_upload(struct input_dev *dev, struct ff_effect *effect,
 
        if (effect->type < FF_EFFECT_MIN || effect->type > FF_EFFECT_MAX ||
            !test_bit(effect->type, dev->ffbit)) {
-               debug("invalid or not supported effect type in upload");
+               pr_debug("invalid or not supported effect type in upload\n");
                return -EINVAL;
        }
 
@@ -124,7 +124,7 @@ int input_ff_upload(struct input_dev *dev, struct ff_effect *effect,
            (effect->u.periodic.waveform < FF_WAVEFORM_MIN ||
             effect->u.periodic.waveform > FF_WAVEFORM_MAX ||
             !test_bit(effect->u.periodic.waveform, dev->ffbit))) {
-               debug("invalid or not supported wave form in upload");
+               pr_debug("invalid or not supported wave form in upload\n");
                return -EINVAL;
        }
 
@@ -246,7 +246,7 @@ static int flush_effects(struct input_dev *dev, struct file *file)
        struct ff_device *ff = dev->ff;
        int i;
 
-       debug("flushing now");
+       pr_debug("flushing now\n");
 
        mutex_lock(&ff->mutex);
 
@@ -315,8 +315,7 @@ int input_ff_create(struct input_dev *dev, int max_effects)
        int i;
 
        if (!max_effects) {
-               printk(KERN_ERR
-                      "ff-core: cannot allocate device without any effects\n");
+               pr_err("cannot allocate device without any effects\n");
                return -EINVAL;
        }
 
index 1d881c9..117a59a 100644 (file)
@@ -23,7 +23,7 @@
 
 /* #define DEBUG */
 
-#define debug(format, arg...) pr_debug("ff-memless: " format "\n", ## arg)
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
 #include <linux/slab.h>
 #include <linux/input.h>
@@ -129,7 +129,7 @@ static void ml_schedule_timer(struct ml_device *ml)
        int events = 0;
        int i;
 
-       debug("calculating next timer");
+       pr_debug("calculating next timer\n");
 
        for (i = 0; i < FF_MEMLESS_EFFECTS; i++) {
 
@@ -149,10 +149,10 @@ static void ml_schedule_timer(struct ml_device *ml)
        }
 
        if (!events) {
-               debug("no actions");
+               pr_debug("no actions\n");
                del_timer(&ml->timer);
        } else {
-               debug("timer set");
+               pr_debug("timer set\n");
                mod_timer(&ml->timer, earliest);
        }
 }
@@ -173,8 +173,8 @@ static int apply_envelope(struct ml_effect_state *state, int value,
        if (envelope->attack_length &&
            time_before(now,
                        state->play_at + msecs_to_jiffies(envelope->attack_length))) {
-               debug("value = 0x%x, attack_level = 0x%x", value,
-                     envelope->attack_level);
+               pr_debug("value = 0x%x, attack_level = 0x%x\n",
+                        value, envelope->attack_level);
                time_from_level = jiffies_to_msecs(now - state->play_at);
                time_of_envelope = envelope->attack_length;
                envelope_level = min_t(__s16, envelope->attack_level, 0x7fff);
@@ -191,13 +191,13 @@ static int apply_envelope(struct ml_effect_state *state, int value,
 
        difference = abs(value) - envelope_level;
 
-       debug("difference = %d", difference);
-       debug("time_from_level = 0x%x", time_from_level);
-       debug("time_of_envelope = 0x%x", time_of_envelope);
+       pr_debug("difference = %d\n", difference);
+       pr_debug("time_from_level = 0x%x\n", time_from_level);
+       pr_debug("time_of_envelope = 0x%x\n", time_of_envelope);
 
        difference = difference * time_from_level / time_of_envelope;
 
-       debug("difference = %d", difference);
+       pr_debug("difference = %d\n", difference);
 
        return value < 0 ?
                -(difference + envelope_level) : (difference + envelope_level);
@@ -215,8 +215,7 @@ static int get_compatible_type(struct ff_device *ff, int effect_type)
        if (effect_type == FF_PERIODIC && test_bit(FF_RUMBLE, ff->ffbit))
                return FF_RUMBLE;
 
-       printk(KERN_ERR
-              "ff-memless: invalid type in get_compatible_type()\n");
+       pr_err("invalid type in get_compatible_type()\n");
 
        return 0;
 }
@@ -312,7 +311,7 @@ static void ml_combine_effects(struct ff_effect *effect,
                break;
 
        default:
-               printk(KERN_ERR "ff-memless: invalid type in ml_combine_effects()\n");
+               pr_err("invalid type in ml_combine_effects()\n");
                break;
        }
 
@@ -406,7 +405,7 @@ static void ml_effect_timer(unsigned long timer_data)
        struct ml_device *ml = dev->ff->private;
        unsigned long flags;
 
-       debug("timer: updating effects");
+       pr_debug("timer: updating effects\n");
 
        spin_lock_irqsave(&dev->event_lock, flags);
        ml_play_effects(ml);
@@ -438,7 +437,7 @@ static int ml_ff_playback(struct input_dev *dev, int effect_id, int value)
        struct ml_effect_state *state = &ml->states[effect_id];
 
        if (value > 0) {
-               debug("initiated play");
+               pr_debug("initiated play\n");
 
                __set_bit(FF_EFFECT_STARTED, &state->flags);
                state->count = value;
@@ -449,7 +448,7 @@ static int ml_ff_playback(struct input_dev *dev, int effect_id, int value)
                state->adj_at = state->play_at;
 
        } else {
-               debug("initiated stop");
+               pr_debug("initiated stop\n");
 
                if (test_bit(FF_EFFECT_PLAYING, &state->flags))
                        __set_bit(FF_EFFECT_ABORTING, &state->flags);
index 46239e4..dbf741c 100644 (file)
 #include <linux/ioport.h>
 #include <linux/init.h>
 #include <linux/gameport.h>
-#include <linux/wait.h>
 #include <linux/slab.h>
 #include <linux/delay.h>
-#include <linux/kthread.h>
+#include <linux/workqueue.h>
 #include <linux/sched.h>       /* HZ */
 #include <linux/mutex.h>
-#include <linux/freezer.h>
 
 /*#include <asm/io.h>*/
 
@@ -234,58 +232,22 @@ struct gameport_event {
 
 static DEFINE_SPINLOCK(gameport_event_lock);   /* protects gameport_event_list */
 static LIST_HEAD(gameport_event_list);
-static DECLARE_WAIT_QUEUE_HEAD(gameport_wait);
-static struct task_struct *gameport_task;
 
-static int gameport_queue_event(void *object, struct module *owner,
-                               enum gameport_event_type event_type)
+static struct gameport_event *gameport_get_event(void)
 {
+       struct gameport_event *event = NULL;
        unsigned long flags;
-       struct gameport_event *event;
-       int retval = 0;
 
        spin_lock_irqsave(&gameport_event_lock, flags);
 
-       /*
-        * Scan event list for the other events for the same gameport port,
-        * starting with the most recent one. If event is the same we
-        * do not need add new one. If event is of different type we
-        * need to add this event and should not look further because
-        * we need to preseve sequence of distinct events.
-        */
-       list_for_each_entry_reverse(event, &gameport_event_list, node) {
-               if (event->object == object) {
-                       if (event->type == event_type)
-                               goto out;
-                       break;
-               }
-       }
-
-       event = kmalloc(sizeof(struct gameport_event), GFP_ATOMIC);
-       if (!event) {
-               pr_err("Not enough memory to queue event %d\n", event_type);
-               retval = -ENOMEM;
-               goto out;
-       }
-
-       if (!try_module_get(owner)) {
-               pr_warning("Can't get module reference, dropping event %d\n",
-                          event_type);
-               kfree(event);
-               retval = -EINVAL;
-               goto out;
+       if (!list_empty(&gameport_event_list)) {
+               event = list_first_entry(&gameport_event_list,
+                                        struct gameport_event, node);
+               list_del_init(&event->node);
        }
 
-       event->type = event_type;
-       event->object = object;
-       event->owner = owner;
-
-       list_add_tail(&event->node, &gameport_event_list);
-       wake_up(&gameport_wait);
-
-out:
        spin_unlock_irqrestore(&gameport_event_lock, flags);
-       return retval;
+       return event;
 }
 
 static void gameport_free_event(struct gameport_event *event)
@@ -319,24 +281,8 @@ static void gameport_remove_duplicate_events(struct gameport_event *event)
        spin_unlock_irqrestore(&gameport_event_lock, flags);
 }
 
-static struct gameport_event *gameport_get_event(void)
-{
-       struct gameport_event *event = NULL;
-       unsigned long flags;
-
-       spin_lock_irqsave(&gameport_event_lock, flags);
-
-       if (!list_empty(&gameport_event_list)) {
-               event = list_first_entry(&gameport_event_list,
-                                        struct gameport_event, node);
-               list_del_init(&event->node);
-       }
-
-       spin_unlock_irqrestore(&gameport_event_lock, flags);
-       return event;
-}
 
-static void gameport_handle_event(void)
+static void gameport_handle_events(struct work_struct *work)
 {
        struct gameport_event *event;
 
@@ -368,6 +314,59 @@ static void gameport_handle_event(void)
        mutex_unlock(&gameport_mutex);
 }
 
+static DECLARE_WORK(gameport_event_work, gameport_handle_events);
+
+static int gameport_queue_event(void *object, struct module *owner,
+                               enum gameport_event_type event_type)
+{
+       unsigned long flags;
+       struct gameport_event *event;
+       int retval = 0;
+
+       spin_lock_irqsave(&gameport_event_lock, flags);
+
+       /*
+        * Scan event list for the other events for the same gameport port,
+        * starting with the most recent one. If event is the same we
+        * do not need add new one. If event is of different type we
+        * need to add this event and should not look further because
+        * we need to preserve sequence of distinct events.
+        */
+       list_for_each_entry_reverse(event, &gameport_event_list, node) {
+               if (event->object == object) {
+                       if (event->type == event_type)
+                               goto out;
+                       break;
+               }
+       }
+
+       event = kmalloc(sizeof(struct gameport_event), GFP_ATOMIC);
+       if (!event) {
+               pr_err("Not enough memory to queue event %d\n", event_type);
+               retval = -ENOMEM;
+               goto out;
+       }
+
+       if (!try_module_get(owner)) {
+               pr_warning("Can't get module reference, dropping event %d\n",
+                          event_type);
+               kfree(event);
+               retval = -EINVAL;
+               goto out;
+       }
+
+       event->type = event_type;
+       event->object = object;
+       event->owner = owner;
+
+       list_add_tail(&event->node, &gameport_event_list);
+       schedule_work(&gameport_event_work);
+
+out:
+       spin_unlock_irqrestore(&gameport_event_lock, flags);
+       return retval;
+}
+
 /*
  * Remove all events that have been submitted for a given object,
  * be it a gameport port or a driver.
@@ -419,19 +418,6 @@ static struct gameport *gameport_get_pending_child(struct gameport *parent)
        return child;
 }
 
-static int gameport_thread(void *nothing)
-{
-       set_freezable();
-       do {
-               gameport_handle_event();
-               wait_event_freezable(gameport_wait,
-                       kthread_should_stop() || !list_empty(&gameport_event_list));
-       } while (!kthread_should_stop());
-
-       return 0;
-}
-
-
 /*
  * Gameport port operations
  */
@@ -814,13 +800,6 @@ static int __init gameport_init(void)
                return error;
        }
 
-       gameport_task = kthread_run(gameport_thread, NULL, "kgameportd");
-       if (IS_ERR(gameport_task)) {
-               bus_unregister(&gameport_bus);
-               error = PTR_ERR(gameport_task);
-               pr_err("Failed to start kgameportd, error: %d\n", error);
-               return error;
-       }
 
        return 0;
 }
@@ -828,7 +807,12 @@ static int __init gameport_init(void)
 static void __exit gameport_exit(void)
 {
        bus_unregister(&gameport_bus);
-       kthread_stop(gameport_task);
+
+       /*
+        * There should not be any outstanding events but work may
+        * still be scheduled so simply cancel it.
+        */
+       cancel_work_sync(&gameport_event_work);
 }
 
 subsys_initcall(gameport_init);
index 10c9b0a..0559e30 100644 (file)
@@ -8,6 +8,8 @@
  * the Free Software Foundation.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/jiffies.h>
 #include <linux/slab.h>
 #include <linux/mutex.h>
@@ -33,8 +35,7 @@ static int input_polldev_start_workqueue(void)
        if (!polldev_users) {
                polldev_wq = create_singlethread_workqueue("ipolldevd");
                if (!polldev_wq) {
-                       printk(KERN_ERR "input-polldev: failed to create "
-                               "ipolldevd workqueue\n");
+                       pr_err("failed to create ipolldevd workqueue\n");
                        retval = -ENOMEM;
                        goto out;
                }
index 3bb6907..9408dba 100644 (file)
@@ -10,6 +10,8 @@
  * the Free Software Foundation.
  */
 
+#define pr_fmt(fmt) KBUILD_BASENAME ": " fmt
+
 #include <linux/init.h>
 #include <linux/types.h>
 #include <linux/input/mt.h>
@@ -74,6 +76,7 @@ static int input_defuzz_abs_event(int value, int old_val, int fuzz)
  * dev->event_lock held and interrupts disabled.
  */
 static void input_pass_event(struct input_dev *dev,
+                            struct input_handler *src_handler,
                             unsigned int type, unsigned int code, int value)
 {
        struct input_handler *handler;
@@ -92,6 +95,15 @@ static void input_pass_event(struct input_dev *dev,
                                continue;
 
                        handler = handle->handler;
+
+                       /*
+                        * If this is the handler that injected this
+                        * particular event we want to skip it to avoid
+                        * filters firing again and again.
+                        */
+                       if (handler == src_handler)
+                               continue;
+
                        if (!handler->filter) {
                                if (filtered)
                                        break;
@@ -121,7 +133,7 @@ static void input_repeat_key(unsigned long data)
        if (test_bit(dev->repeat_key, dev->key) &&
            is_event_supported(dev->repeat_key, dev->keybit, KEY_MAX)) {
 
-               input_pass_event(dev, EV_KEY, dev->repeat_key, 2);
+               input_pass_event(dev, NULL, EV_KEY, dev->repeat_key, 2);
 
                if (dev->sync) {
                        /*
@@ -130,7 +142,7 @@ static void input_repeat_key(unsigned long data)
                         * Otherwise assume that the driver will send
                         * SYN_REPORT once it's done.
                         */
-                       input_pass_event(dev, EV_SYN, SYN_REPORT, 1);
+                       input_pass_event(dev, NULL, EV_SYN, SYN_REPORT, 1);
                }
 
                if (dev->rep[REP_PERIOD])
@@ -163,6 +175,7 @@ static void input_stop_autorepeat(struct input_dev *dev)
 #define INPUT_PASS_TO_ALL      (INPUT_PASS_TO_HANDLERS | INPUT_PASS_TO_DEVICE)
 
 static int input_handle_abs_event(struct input_dev *dev,
+                                 struct input_handler *src_handler,
                                  unsigned int code, int *pval)
 {
        bool is_mt_event;
@@ -206,13 +219,15 @@ static int input_handle_abs_event(struct input_dev *dev,
        /* Flush pending "slot" event */
        if (is_mt_event && dev->slot != input_abs_get_val(dev, ABS_MT_SLOT)) {
                input_abs_set_val(dev, ABS_MT_SLOT, dev->slot);
-               input_pass_event(dev, EV_ABS, ABS_MT_SLOT, dev->slot);
+               input_pass_event(dev, src_handler,
+                                EV_ABS, ABS_MT_SLOT, dev->slot);
        }
 
        return INPUT_PASS_TO_HANDLERS;
 }
 
 static void input_handle_event(struct input_dev *dev,
+                              struct input_handler *src_handler,
                               unsigned int type, unsigned int code, int value)
 {
        int disposition = INPUT_IGNORE_EVENT;
@@ -265,7 +280,8 @@ static void input_handle_event(struct input_dev *dev,
 
        case EV_ABS:
                if (is_event_supported(code, dev->absbit, ABS_MAX))
-                       disposition = input_handle_abs_event(dev, code, &value);
+                       disposition = input_handle_abs_event(dev, src_handler,
+                                                            code, &value);
 
                break;
 
@@ -323,7 +339,7 @@ static void input_handle_event(struct input_dev *dev,
                dev->event(dev, type, code, value);
 
        if (disposition & INPUT_PASS_TO_HANDLERS)
-               input_pass_event(dev, type, code, value);
+               input_pass_event(dev, src_handler, type, code, value);
 }
 
 /**
@@ -352,7 +368,7 @@ void input_event(struct input_dev *dev,
 
                spin_lock_irqsave(&dev->event_lock, flags);
                add_input_randomness(type, code, value);
-               input_handle_event(dev, type, code, value);
+               input_handle_event(dev, NULL, type, code, value);
                spin_unlock_irqrestore(&dev->event_lock, flags);
        }
 }
@@ -382,7 +398,8 @@ void input_inject_event(struct input_handle *handle,
                rcu_read_lock();
                grab = rcu_dereference(dev->grab);
                if (!grab || grab == handle)
-                       input_handle_event(dev, type, code, value);
+                       input_handle_event(dev, handle->handler,
+                                          type, code, value);
                rcu_read_unlock();
 
                spin_unlock_irqrestore(&dev->event_lock, flags);
@@ -595,10 +612,10 @@ static void input_dev_release_keys(struct input_dev *dev)
                for (code = 0; code <= KEY_MAX; code++) {
                        if (is_event_supported(code, dev->keybit, KEY_MAX) &&
                            __test_and_clear_bit(code, dev->key)) {
-                               input_pass_event(dev, EV_KEY, code, 0);
+                               input_pass_event(dev, NULL, EV_KEY, code, 0);
                        }
                }
-               input_pass_event(dev, EV_SYN, SYN_REPORT, 1);
+               input_pass_event(dev, NULL, EV_SYN, SYN_REPORT, 1);
        }
 }
 
@@ -873,9 +890,9 @@ int input_set_keycode(struct input_dev *dev,
            !is_event_supported(old_keycode, dev->keybit, KEY_MAX) &&
            __test_and_clear_bit(old_keycode, dev->key)) {
 
-               input_pass_event(dev, EV_KEY, old_keycode, 0);
+               input_pass_event(dev, NULL, EV_KEY, old_keycode, 0);
                if (dev->sync)
-                       input_pass_event(dev, EV_SYN, SYN_REPORT, 1);
+                       input_pass_event(dev, NULL, EV_SYN, SYN_REPORT, 1);
        }
 
  out:
@@ -944,10 +961,8 @@ static int input_attach_handler(struct input_dev *dev, struct input_handler *han
 
        error = handler->connect(handler, dev, id);
        if (error && error != -ENODEV)
-               printk(KERN_ERR
-                       "input: failed to attach handler %s to device %s, "
-                       "error: %d\n",
-                       handler->name, kobject_name(&dev->dev.kobj), error);
+               pr_err("failed to attach handler %s to device %s, error: %d\n",
+                      handler->name, kobject_name(&dev->dev.kobj), error);
 
        return error;
 }
@@ -1584,8 +1599,7 @@ static int input_dev_uevent(struct device *device, struct kobj_uevent_env *env)
                }                                                       \
        } while (0)
 
-#ifdef CONFIG_PM
-static void input_dev_reset(struct input_dev *dev, bool activate)
+static void input_dev_toggle(struct input_dev *dev, bool activate)
 {
        if (!dev->event)
                return;
@@ -1599,12 +1613,44 @@ static void input_dev_reset(struct input_dev *dev, bool activate)
        }
 }
 
+/**
+ * input_reset_device() - reset/restore the state of input device
+ * @dev: input device whose state needs to be reset
+ *
+ * This function tries to reset the state of an opened input device and
+ * bring internal state and state if the hardware in sync with each other.
+ * We mark all keys as released, restore LED state, repeat rate, etc.
+ */
+void input_reset_device(struct input_dev *dev)
+{
+       mutex_lock(&dev->mutex);
+
+       if (dev->users) {
+               input_dev_toggle(dev, true);
+
+               /*
+                * Keys that have been pressed at suspend time are unlikely
+                * to be still pressed when we resume.
+                */
+               spin_lock_irq(&dev->event_lock);
+               input_dev_release_keys(dev);
+               spin_unlock_irq(&dev->event_lock);
+       }
+
+       mutex_unlock(&dev->mutex);
+}
+EXPORT_SYMBOL(input_reset_device);
+
+#ifdef CONFIG_PM
 static int input_dev_suspend(struct device *dev)
 {
        struct input_dev *input_dev = to_input_dev(dev);
 
        mutex_lock(&input_dev->mutex);
-       input_dev_reset(input_dev, false);
+
+       if (input_dev->users)
+               input_dev_toggle(input_dev, false);
+
        mutex_unlock(&input_dev->mutex);
 
        return 0;
@@ -1614,18 +1660,7 @@ static int input_dev_resume(struct device *dev)
 {
        struct input_dev *input_dev = to_input_dev(dev);
 
-       mutex_lock(&input_dev->mutex);
-       input_dev_reset(input_dev, true);
-
-       /*
-        * Keys that have been pressed at suspend time are unlikely
-        * to be still pressed when we resume.
-        */
-       spin_lock_irq(&input_dev->event_lock);
-       input_dev_release_keys(input_dev);
-       spin_unlock_irq(&input_dev->event_lock);
-
-       mutex_unlock(&input_dev->mutex);
+       input_reset_device(input_dev);
 
        return 0;
 }
@@ -1758,9 +1793,8 @@ void input_set_capability(struct input_dev *dev, unsigned int type, unsigned int
                break;
 
        default:
-               printk(KERN_ERR
-                       "input_set_capability: unknown type %u (code %u)\n",
-                       type, code);
+               pr_err("input_set_capability: unknown type %u (code %u)\n",
+                      type, code);
                dump_stack();
                return;
        }
@@ -1842,8 +1876,9 @@ int input_register_device(struct input_dev *dev)
                return error;
 
        path = kobject_get_path(&dev->dev.kobj, GFP_KERNEL);
-       printk(KERN_INFO "input: %s as %s\n",
-               dev->name ? dev->name : "Unspecified device", path ? path : "N/A");
+       pr_info("%s as %s\n",
+               dev->name ? dev->name : "Unspecified device",
+               path ? path : "N/A");
        kfree(path);
 
        error = mutex_lock_interruptible(&input_mutex);
@@ -2125,7 +2160,7 @@ static int __init input_init(void)
 
        err = class_register(&input_class);
        if (err) {
-               printk(KERN_ERR "input: unable to register input_dev class\n");
+               pr_err("unable to register input_dev class\n");
                return err;
        }
 
@@ -2135,7 +2170,7 @@ static int __init input_init(void)
 
        err = register_chrdev(INPUT_MAJOR, "input", &input_fops);
        if (err) {
-               printk(KERN_ERR "input: unable to register char major %d", INPUT_MAJOR);
+               pr_err("unable to register char major %d", INPUT_MAJOR);
                goto fail2;
        }
 
index 9d424ce..3182c9c 100644 (file)
@@ -10,6 +10,8 @@
  * (at your option) any later version.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <asm/io.h>
 #include <asm/system.h>
 #include <linux/delay.h>
@@ -806,7 +808,7 @@ static int joydev_connect(struct input_handler *handler, struct input_dev *dev,
                        break;
 
        if (minor == JOYDEV_MINORS) {
-               printk(KERN_ERR "joydev: no more free joydev devices\n");
+               pr_err("no more free joydev devices\n");
                return -ENFILE;
        }
 
index 74daff4..bc5bda2 100644 (file)
@@ -4,17 +4,8 @@
 # By Johann Deneux <johann.deneux@gmail.com>
 #
 
-# Goal definition
-iforce-objs    := iforce-ff.o iforce-main.o iforce-packets.o
-
 obj-$(CONFIG_JOYSTICK_IFORCE)  += iforce.o
 
-ifeq ($(CONFIG_JOYSTICK_IFORCE_232),y)
-       iforce-objs += iforce-serio.o
-endif
-
-ifeq ($(CONFIG_JOYSTICK_IFORCE_USB),y)
-       iforce-objs += iforce-usb.o
-endif
-
-EXTRA_CFLAGS = -Werror-implicit-function-declaration
+iforce-y := iforce-ff.o iforce-main.o iforce-packets.o
+iforce-$(CONFIG_JOYSTICK_IFORCE_232)   += iforce-serio.o
+iforce-$(CONFIG_JOYSTICK_IFORCE_USB)   += iforce-usb.o
index f9fb7fa..56abf3d 100644 (file)
@@ -543,21 +543,25 @@ exit:
 static int xpad_init_output(struct usb_interface *intf, struct usb_xpad *xpad)
 {
        struct usb_endpoint_descriptor *ep_irq_out;
-       int error = -ENOMEM;
+       int error;
 
        if (xpad->xtype != XTYPE_XBOX360 && xpad->xtype != XTYPE_XBOX)
                return 0;
 
        xpad->odata = usb_alloc_coherent(xpad->udev, XPAD_PKT_LEN,
                                         GFP_KERNEL, &xpad->odata_dma);
-       if (!xpad->odata)
+       if (!xpad->odata) {
+               error = -ENOMEM;
                goto fail1;
+       }
 
        mutex_init(&xpad->odata_mutex);
 
        xpad->irq_out = usb_alloc_urb(0, GFP_KERNEL);
-       if (!xpad->irq_out)
+       if (!xpad->irq_out) {
+               error = -ENOMEM;
                goto fail2;
+       }
 
        ep_irq_out = &intf->cur_altsetting->endpoint[1].desc;
        usb_fill_int_urb(xpad->irq_out, xpad->udev,
@@ -728,7 +732,7 @@ static void xpad_led_disconnect(struct usb_xpad *xpad)
 
        if (xpad_led) {
                led_classdev_unregister(&xpad_led->led_cdev);
-               kfree(xpad_led->name);
+               kfree(xpad_led);
        }
 }
 #else
@@ -756,8 +760,9 @@ static void xpad_close(struct input_dev *dev)
 {
        struct usb_xpad *xpad = input_get_drvdata(dev);
 
-       if(xpad->xtype != XTYPE_XBOX360W)
+       if (xpad->xtype != XTYPE_XBOX360W)
                usb_kill_urb(xpad->irq_in);
+
        xpad_stop_output(xpad);
 }
 
@@ -789,8 +794,7 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
        struct usb_xpad *xpad;
        struct input_dev *input_dev;
        struct usb_endpoint_descriptor *ep_irq_in;
-       int i;
-       int error = -ENOMEM;
+       int i, error;
 
        for (i = 0; xpad_device[i].idVendor; i++) {
                if ((le16_to_cpu(udev->descriptor.idVendor) == xpad_device[i].idVendor) &&
@@ -800,17 +804,23 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
 
        xpad = kzalloc(sizeof(struct usb_xpad), GFP_KERNEL);
        input_dev = input_allocate_device();
-       if (!xpad || !input_dev)
+       if (!xpad || !input_dev) {
+               error = -ENOMEM;
                goto fail1;
+       }
 
        xpad->idata = usb_alloc_coherent(udev, XPAD_PKT_LEN,
                                         GFP_KERNEL, &xpad->idata_dma);
-       if (!xpad->idata)
+       if (!xpad->idata) {
+               error = -ENOMEM;
                goto fail1;
+       }
 
        xpad->irq_in = usb_alloc_urb(0, GFP_KERNEL);
-       if (!xpad->irq_in)
+       if (!xpad->irq_in) {
+               error = -ENOMEM;
                goto fail2;
+       }
 
        xpad->udev = udev;
        xpad->mapping = xpad_device[i].mapping;
@@ -887,15 +897,15 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
 
        error = xpad_init_output(intf, xpad);
        if (error)
-               goto fail2;
+               goto fail3;
 
        error = xpad_init_ff(xpad);
        if (error)
-               goto fail3;
+               goto fail4;
 
        error = xpad_led_probe(xpad);
        if (error)
-               goto fail3;
+               goto fail5;
 
        ep_irq_in = &intf->cur_altsetting->endpoint[0].desc;
        usb_fill_int_urb(xpad->irq_in, udev,
@@ -907,34 +917,26 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
 
        error = input_register_device(xpad->dev);
        if (error)
-               goto fail4;
+               goto fail6;
 
        usb_set_intfdata(intf, xpad);
 
-       /*
-        * Submit the int URB immediatly rather than waiting for open
-        * because we get status messages from the device whether
-        * or not any controllers are attached.  In fact, it's
-        * exactly the message that a controller has arrived that
-        * we're waiting for.
-        */
        if (xpad->xtype == XTYPE_XBOX360W) {
-               xpad->irq_in->dev = xpad->udev;
-               error = usb_submit_urb(xpad->irq_in, GFP_KERNEL);
-               if (error)
-                       goto fail4;
-
                /*
                 * Setup the message to set the LEDs on the
                 * controller when it shows up
                 */
                xpad->bulk_out = usb_alloc_urb(0, GFP_KERNEL);
-               if(!xpad->bulk_out)
-                       goto fail5;
+               if (!xpad->bulk_out) {
+                       error = -ENOMEM;
+                       goto fail7;
+               }
 
                xpad->bdata = kzalloc(XPAD_PKT_LEN, GFP_KERNEL);
-               if(!xpad->bdata)
-                       goto fail6;
+               if (!xpad->bdata) {
+                       error = -ENOMEM;
+                       goto fail8;
+               }
 
                xpad->bdata[2] = 0x08;
                switch (intf->cur_altsetting->desc.bInterfaceNumber) {
@@ -955,14 +957,31 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
                usb_fill_bulk_urb(xpad->bulk_out, udev,
                                usb_sndbulkpipe(udev, ep_irq_in->bEndpointAddress),
                                xpad->bdata, XPAD_PKT_LEN, xpad_bulk_out, xpad);
+
+               /*
+                * Submit the int URB immediately rather than waiting for open
+                * because we get status messages from the device whether
+                * or not any controllers are attached.  In fact, it's
+                * exactly the message that a controller has arrived that
+                * we're waiting for.
+                */
+               xpad->irq_in->dev = xpad->udev;
+               error = usb_submit_urb(xpad->irq_in, GFP_KERNEL);
+               if (error)
+                       goto fail9;
        }
 
        return 0;
 
- fail6:        usb_free_urb(xpad->bulk_out);
- fail5:        usb_kill_urb(xpad->irq_in);
- fail4:        usb_free_urb(xpad->irq_in);
- fail3:        xpad_deinit_output(xpad);
+ fail9:        kfree(xpad->bdata);
+ fail8:        usb_free_urb(xpad->bulk_out);
+ fail7:        input_unregister_device(input_dev);
+       input_dev = NULL;
+ fail6:        xpad_led_disconnect(xpad);
+ fail5:        if (input_dev)
+               input_ff_destroy(input_dev);
+ fail4:        xpad_deinit_output(xpad);
+ fail3:        usb_free_urb(xpad->irq_in);
  fail2:        usb_free_coherent(udev, XPAD_PKT_LEN, xpad->idata, xpad->idata_dma);
  fail1:        input_free_device(input_dev);
        kfree(xpad);
@@ -974,21 +993,24 @@ static void xpad_disconnect(struct usb_interface *intf)
 {
        struct usb_xpad *xpad = usb_get_intfdata (intf);
 
-       usb_set_intfdata(intf, NULL);
-       if (xpad) {
-               xpad_led_disconnect(xpad);
-               input_unregister_device(xpad->dev);
-               xpad_deinit_output(xpad);
-               if (xpad->xtype == XTYPE_XBOX360W) {
-                       usb_kill_urb(xpad->bulk_out);
-                       usb_free_urb(xpad->bulk_out);
-                       usb_kill_urb(xpad->irq_in);
-               }
-               usb_free_urb(xpad->irq_in);
-               usb_free_coherent(xpad->udev, XPAD_PKT_LEN,
-                               xpad->idata, xpad->idata_dma);
-               kfree(xpad);
+       xpad_led_disconnect(xpad);
+       input_unregister_device(xpad->dev);
+       xpad_deinit_output(xpad);
+
+       if (xpad->xtype == XTYPE_XBOX360W) {
+               usb_kill_urb(xpad->bulk_out);
+               usb_free_urb(xpad->bulk_out);
+               usb_kill_urb(xpad->irq_in);
        }
+
+       usb_free_urb(xpad->irq_in);
+       usb_free_coherent(xpad->udev, XPAD_PKT_LEN,
+                       xpad->idata, xpad->idata_dma);
+
+       kfree(xpad->bdata);
+       kfree(xpad);
+
+       usb_set_intfdata(intf, NULL);
 }
 
 static struct usb_driver xpad_driver = {
@@ -1000,10 +1022,7 @@ static struct usb_driver xpad_driver = {
 
 static int __init usb_xpad_init(void)
 {
-       int result = usb_register(&xpad_driver);
-       if (result == 0)
-               printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_DESC "\n");
-       return result;
+       return usb_register(&xpad_driver);
 }
 
 static void __exit usb_xpad_exit(void)
index b8c51b9..a378e95 100644 (file)
@@ -180,20 +180,22 @@ config KEYBOARD_GPIO
          module will be called gpio_keys.
 
 config KEYBOARD_TCA6416
-       tristate "TCA6416 Keypad Support"
+       tristate "TCA6416/TCA6408A Keypad Support"
        depends on I2C
        help
          This driver implements basic keypad functionality
-         for keys connected through TCA6416 IO expander
+         for keys connected through TCA6416/TCA6408A IO expanders.
 
          Say Y here if your device has keys connected to
-         TCA6416 IO expander. Your board-specific setup logic
+         TCA6416/TCA6408A IO expander. Your board-specific setup logic
          must also provide pin-mask details(of which TCA6416 pins
          are used for keypad).
 
-         If enabled the complete TCA6416 device will be managed through
+         If enabled the entire TCA6416 device will be managed through
          this driver.
 
+         To compile this driver as a module, choose M here: the
+         module will be called tca6416_keypad.
 
 config KEYBOARD_MATRIX
        tristate "GPIO driven matrix keypad support"
@@ -443,6 +445,15 @@ config KEYBOARD_OMAP4
          To compile this driver as a module, choose M here: the
          module will be called omap4-keypad.
 
+config KEYBOARD_SPEAR
+       tristate "ST SPEAR keyboard support"
+       depends on PLAT_SPEAR
+       help
+         Say Y here if you want to use the SPEAR keyboard.
+
+         To compile this driver as a module, choose M here: the
+         module will be called spear-keboard.
+
 config KEYBOARD_TNETV107X
        tristate "TI TNETV107X keypad support"
        depends on ARCH_DAVINCI_TNETV107X
index a34452e..8449c73 100644 (file)
@@ -37,6 +37,7 @@ obj-$(CONFIG_KEYBOARD_PXA930_ROTARY)  += pxa930_rotary.o
 obj-$(CONFIG_KEYBOARD_QT2160)          += qt2160.o
 obj-$(CONFIG_KEYBOARD_SAMSUNG)         += samsung-keypad.o
 obj-$(CONFIG_KEYBOARD_SH_KEYSC)                += sh_keysc.o
+obj-$(CONFIG_KEYBOARD_SPEAR)           += spear-keyboard.o
 obj-$(CONFIG_KEYBOARD_STMPE)           += stmpe-keypad.o
 obj-$(CONFIG_KEYBOARD_STOWAWAY)                += stowaway.o
 obj-$(CONFIG_KEYBOARD_SUNKBD)          += sunkbd.o
index b92d1cd..af45d27 100644 (file)
@@ -4,7 +4,7 @@
  *              I2C QWERTY Keypad and IO Expander
  * Bugs: Enter bugs at http://blackfin.uclinux.org/
  *
- * Copyright (C) 2008-2009 Analog Devices Inc.
+ * Copyright (C) 2008-2010 Analog Devices Inc.
  * Licensed under the GPL-2 or later.
  */
 
 
 #include <linux/i2c/adp5588.h>
 
- /* Configuration Register1 */
-#define AUTO_INC       (1 << 7)
-#define GPIEM_CFG      (1 << 6)
-#define OVR_FLOW_M     (1 << 5)
-#define INT_CFG                (1 << 4)
-#define OVR_FLOW_IEN   (1 << 3)
-#define K_LCK_IM       (1 << 2)
-#define GPI_IEN                (1 << 1)
-#define KE_IEN         (1 << 0)
-
-/* Interrupt Status Register */
-#define CMP2_INT       (1 << 5)
-#define CMP1_INT       (1 << 4)
-#define OVR_FLOW_INT   (1 << 3)
-#define K_LCK_INT      (1 << 2)
-#define GPI_INT                (1 << 1)
-#define KE_INT         (1 << 0)
-
-/* Key Lock and Event Counter Register */
-#define K_LCK_EN       (1 << 6)
-#define LCK21          0x30
-#define KEC            0xF
-
 /* Key Event Register xy */
 #define KEY_EV_PRESSED         (1 << 7)
 #define KEY_EV_MASK            (0x7F)
 
 #define KEYP_MAX_EVENT         10
 
-#define MAXGPIO                        18
-#define ADP_BANK(offs)         ((offs) >> 3)
-#define ADP_BIT(offs)          (1u << ((offs) & 0x7))
-
 /*
  * Early pre 4.0 Silicon required to delay readout by at least 25ms,
  * since the Event Counter Register updated 25ms after the interrupt
@@ -75,7 +48,7 @@ struct adp5588_kpad {
        const struct adp5588_gpi_map *gpimap;
        unsigned short gpimapsize;
 #ifdef CONFIG_GPIOLIB
-       unsigned char gpiomap[MAXGPIO];
+       unsigned char gpiomap[ADP5588_MAXGPIO];
        bool export_gpio;
        struct gpio_chip gc;
        struct mutex gpio_lock; /* Protect cached dir, dat_out */
@@ -103,8 +76,8 @@ static int adp5588_write(struct i2c_client *client, u8 reg, u8 val)
 static int adp5588_gpio_get_value(struct gpio_chip *chip, unsigned off)
 {
        struct adp5588_kpad *kpad = container_of(chip, struct adp5588_kpad, gc);
-       unsigned int bank = ADP_BANK(kpad->gpiomap[off]);
-       unsigned int bit = ADP_BIT(kpad->gpiomap[off]);
+       unsigned int bank = ADP5588_BANK(kpad->gpiomap[off]);
+       unsigned int bit = ADP5588_BIT(kpad->gpiomap[off]);
 
        return !!(adp5588_read(kpad->client, GPIO_DAT_STAT1 + bank) & bit);
 }
@@ -113,8 +86,8 @@ static void adp5588_gpio_set_value(struct gpio_chip *chip,
                                   unsigned off, int val)
 {
        struct adp5588_kpad *kpad = container_of(chip, struct adp5588_kpad, gc);
-       unsigned int bank = ADP_BANK(kpad->gpiomap[off]);
-       unsigned int bit = ADP_BIT(kpad->gpiomap[off]);
+       unsigned int bank = ADP5588_BANK(kpad->gpiomap[off]);
+       unsigned int bit = ADP5588_BIT(kpad->gpiomap[off]);
 
        mutex_lock(&kpad->gpio_lock);
 
@@ -132,8 +105,8 @@ static void adp5588_gpio_set_value(struct gpio_chip *chip,
 static int adp5588_gpio_direction_input(struct gpio_chip *chip, unsigned off)
 {
        struct adp5588_kpad *kpad = container_of(chip, struct adp5588_kpad, gc);
-       unsigned int bank = ADP_BANK(kpad->gpiomap[off]);
-       unsigned int bit = ADP_BIT(kpad->gpiomap[off]);
+       unsigned int bank = ADP5588_BANK(kpad->gpiomap[off]);
+       unsigned int bit = ADP5588_BIT(kpad->gpiomap[off]);
        int ret;
 
        mutex_lock(&kpad->gpio_lock);
@@ -150,8 +123,8 @@ static int adp5588_gpio_direction_output(struct gpio_chip *chip,
                                         unsigned off, int val)
 {
        struct adp5588_kpad *kpad = container_of(chip, struct adp5588_kpad, gc);
-       unsigned int bank = ADP_BANK(kpad->gpiomap[off]);
-       unsigned int bit = ADP_BIT(kpad->gpiomap[off]);
+       unsigned int bank = ADP5588_BANK(kpad->gpiomap[off]);
+       unsigned int bit = ADP5588_BIT(kpad->gpiomap[off]);
        int ret;
 
        mutex_lock(&kpad->gpio_lock);
@@ -176,7 +149,7 @@ static int adp5588_gpio_direction_output(struct gpio_chip *chip,
 static int __devinit adp5588_build_gpiomap(struct adp5588_kpad *kpad,
                                const struct adp5588_kpad_platform_data *pdata)
 {
-       bool pin_used[MAXGPIO];
+       bool pin_used[ADP5588_MAXGPIO];
        int n_unused = 0;
        int i;
 
@@ -191,7 +164,7 @@ static int __devinit adp5588_build_gpiomap(struct adp5588_kpad *kpad,
        for (i = 0; i < kpad->gpimapsize; i++)
                pin_used[kpad->gpimap[i].pin - GPI_PIN_BASE] = true;
 
-       for (i = 0; i < MAXGPIO; i++)
+       for (i = 0; i < ADP5588_MAXGPIO; i++)
                if (!pin_used[i])
                        kpad->gpiomap[n_unused++] = i;
 
@@ -234,7 +207,7 @@ static int __devinit adp5588_gpio_add(struct adp5588_kpad *kpad)
                return error;
        }
 
-       for (i = 0; i <= ADP_BANK(MAXGPIO); i++) {
+       for (i = 0; i <= ADP5588_BANK(ADP5588_MAXGPIO); i++) {
                kpad->dat_out[i] = adp5588_read(kpad->client,
                                                GPIO_DAT_OUT1 + i);
                kpad->dir[i] = adp5588_read(kpad->client, GPIO_DIR1 + i);
@@ -318,11 +291,11 @@ static void adp5588_work(struct work_struct *work)
 
        status = adp5588_read(client, INT_STAT);
 
-       if (status & OVR_FLOW_INT)      /* Unlikely and should never happen */
+       if (status & ADP5588_OVR_FLOW_INT)      /* Unlikely and should never happen */
                dev_err(&client->dev, "Event Overflow Error\n");
 
-       if (status & KE_INT) {
-               ev_cnt = adp5588_read(client, KEY_LCK_EC_STAT) & KEC;
+       if (status & ADP5588_KE_INT) {
+               ev_cnt = adp5588_read(client, KEY_LCK_EC_STAT) & ADP5588_KEC;
                if (ev_cnt) {
                        adp5588_report_events(kpad, ev_cnt);
                        input_sync(kpad->input);
@@ -360,7 +333,7 @@ static int __devinit adp5588_setup(struct i2c_client *client)
        if (pdata->en_keylock) {
                ret |= adp5588_write(client, UNLOCK1, pdata->unlock_key1);
                ret |= adp5588_write(client, UNLOCK2, pdata->unlock_key2);
-               ret |= adp5588_write(client, KEY_LCK_EC_STAT, K_LCK_EN);
+               ret |= adp5588_write(client, KEY_LCK_EC_STAT, ADP5588_K_LCK_EN);
        }
 
        for (i = 0; i < KEYP_MAX_EVENT; i++)
@@ -384,7 +357,7 @@ static int __devinit adp5588_setup(struct i2c_client *client)
        }
 
        if (gpio_data) {
-               for (i = 0; i <= ADP_BANK(MAXGPIO); i++) {
+               for (i = 0; i <= ADP5588_BANK(ADP5588_MAXGPIO); i++) {
                        int pull_mask = gpio_data->pullup_dis_mask;
 
                        ret |= adp5588_write(client, GPIO_PULL1 + i,
@@ -392,11 +365,14 @@ static int __devinit adp5588_setup(struct i2c_client *client)
                }
        }
 
-       ret |= adp5588_write(client, INT_STAT, CMP2_INT | CMP1_INT |
-                                       OVR_FLOW_INT | K_LCK_INT |
-                                       GPI_INT | KE_INT); /* Status is W1C */
+       ret |= adp5588_write(client, INT_STAT,
+                               ADP5588_CMP2_INT | ADP5588_CMP1_INT |
+                               ADP5588_OVR_FLOW_INT | ADP5588_K_LCK_INT |
+                               ADP5588_GPI_INT | ADP5588_KE_INT); /* Status is W1C */
 
-       ret |= adp5588_write(client, CFG, INT_CFG | OVR_FLOW_IEN | KE_IEN);
+       ret |= adp5588_write(client, CFG, ADP5588_INT_CFG |
+                                         ADP5588_OVR_FLOW_IEN |
+                                         ADP5588_KE_IEN);
 
        if (ret < 0) {
                dev_err(&client->dev, "Write Error\n");
index d358ef8..11478eb 100644 (file)
@@ -63,6 +63,10 @@ static bool atkbd_extra;
 module_param_named(extra, atkbd_extra, bool, 0);
 MODULE_PARM_DESC(extra, "Enable extra LEDs and keys on IBM RapidAcces, EzKey and similar keyboards");
 
+static bool atkbd_terminal;
+module_param_named(terminal, atkbd_terminal, bool, 0);
+MODULE_PARM_DESC(terminal, "Enable break codes on an IBM Terminal keyboard connected via AT/PS2");
+
 /*
  * Scancode to keycode tables. These are just the default setting, and
  * are loadable via a userland utility.
@@ -136,7 +140,8 @@ static const unsigned short atkbd_unxlate_table[128] = {
 #define ATKBD_CMD_ENABLE       0x00f4
 #define ATKBD_CMD_RESET_DIS    0x00f5  /* Reset to defaults and disable */
 #define ATKBD_CMD_RESET_DEF    0x00f6  /* Reset to defaults */
-#define ATKBD_CMD_SETALL_MBR   0x00fa
+#define ATKBD_CMD_SETALL_MB    0x00f8  /* Set all keys to give break codes */
+#define ATKBD_CMD_SETALL_MBR   0x00fa  /* ... and repeat */
 #define ATKBD_CMD_RESET_BAT    0x02ff
 #define ATKBD_CMD_RESEND       0x00fe
 #define ATKBD_CMD_EX_ENABLE    0x10ea
@@ -764,6 +769,11 @@ static int atkbd_select_set(struct atkbd *atkbd, int target_set, int allow_extra
                }
        }
 
+       if (atkbd_terminal) {
+               ps2_command(ps2dev, param, ATKBD_CMD_SETALL_MB);
+               return 3;
+       }
+
        if (target_set != 3)
                return 2;
 
diff --git a/drivers/input/keyboard/spear-keyboard.c b/drivers/input/keyboard/spear-keyboard.c
new file mode 100644 (file)
index 0000000..bee03d6
--- /dev/null
@@ -0,0 +1,344 @@
+/*
+ * SPEAr Keyboard Driver
+ * Based on omap-keypad driver
+ *
+ * Copyright (C) 2010 ST Microelectronics
+ * Rajeev Kumar<rajeev-dlh.kumar@st.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/clk.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/input.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/pm_wakeup.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <plat/keyboard.h>
+
+/* Keyboard Registers */
+#define MODE_REG       0x00    /* 16 bit reg */
+#define STATUS_REG     0x0C    /* 2 bit reg */
+#define DATA_REG       0x10    /* 8 bit reg */
+#define INTR_MASK      0x54
+
+/* Register Values */
+/*
+ * pclk freq mask = (APB FEQ -1)= 82 MHZ.Programme bit 15-9 in mode
+ * control register as 1010010(82MHZ)
+ */
+#define PCLK_FREQ_MSK  0xA400  /* 82 MHz */
+#define START_SCAN     0x0100
+#define SCAN_RATE_10   0x0000
+#define SCAN_RATE_20   0x0004
+#define SCAN_RATE_40   0x0008
+#define SCAN_RATE_80   0x000C
+#define MODE_KEYBOARD  0x0002
+#define DATA_AVAIL     0x2
+
+#define KEY_MASK       0xFF000000
+#define KEY_VALUE      0x00FFFFFF
+#define ROW_MASK       0xF0
+#define COLUMN_MASK    0x0F
+#define ROW_SHIFT      4
+
+struct spear_kbd {
+       struct input_dev *input;
+       struct resource *res;
+       void __iomem *io_base;
+       struct clk *clk;
+       unsigned int irq;
+       unsigned short last_key;
+       unsigned short keycodes[256];
+};
+
+static irqreturn_t spear_kbd_interrupt(int irq, void *dev_id)
+{
+       struct spear_kbd *kbd = dev_id;
+       struct input_dev *input = kbd->input;
+       unsigned int key;
+       u8 sts, val;
+
+       sts = readb(kbd->io_base + STATUS_REG);
+       if (sts & DATA_AVAIL)
+               return IRQ_NONE;
+
+       if (kbd->last_key != KEY_RESERVED) {
+               input_report_key(input, kbd->last_key, 0);
+               kbd->last_key = KEY_RESERVED;
+       }
+
+       /* following reads active (row, col) pair */
+       val = readb(kbd->io_base + DATA_REG);
+       key = kbd->keycodes[val];
+
+       input_event(input, EV_MSC, MSC_SCAN, val);
+       input_report_key(input, key, 1);
+       input_sync(input);
+
+       kbd->last_key = key;
+
+       /* clear interrupt */
+       writeb(0, kbd->io_base + STATUS_REG);
+
+       return IRQ_HANDLED;
+}
+
+static int spear_kbd_open(struct input_dev *dev)
+{
+       struct spear_kbd *kbd = input_get_drvdata(dev);
+       int error;
+       u16 val;
+
+       kbd->last_key = KEY_RESERVED;
+
+       error = clk_enable(kbd->clk);
+       if (error)
+               return error;
+
+       /* program keyboard */
+       val = SCAN_RATE_80 | MODE_KEYBOARD | PCLK_FREQ_MSK;
+       writew(val, kbd->io_base + MODE_REG);
+       writeb(1, kbd->io_base + STATUS_REG);
+
+       /* start key scan */
+       val = readw(kbd->io_base + MODE_REG);
+       val |= START_SCAN;
+       writew(val, kbd->io_base + MODE_REG);
+
+       return 0;
+}
+
+static void spear_kbd_close(struct input_dev *dev)
+{
+       struct spear_kbd *kbd = input_get_drvdata(dev);
+       u16 val;
+
+       /* stop key scan */
+       val = readw(kbd->io_base + MODE_REG);
+       val &= ~START_SCAN;
+       writew(val, kbd->io_base + MODE_REG);
+
+       clk_disable(kbd->clk);
+
+       kbd->last_key = KEY_RESERVED;
+}
+
+static int __devinit spear_kbd_probe(struct platform_device *pdev)
+{
+       const struct kbd_platform_data *pdata = pdev->dev.platform_data;
+       const struct matrix_keymap_data *keymap;
+       struct spear_kbd *kbd;
+       struct input_dev *input_dev;
+       struct resource *res;
+       int irq;
+       int error;
+
+       if (!pdata) {
+               dev_err(&pdev->dev, "Invalid platform data\n");
+               return -EINVAL;
+       }
+
+       keymap = pdata->keymap;
+       if (!keymap) {
+               dev_err(&pdev->dev, "no keymap defined\n");
+               return -EINVAL;
+       }
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res) {
+               dev_err(&pdev->dev, "no keyboard resource defined\n");
+               return -EBUSY;
+       }
+
+       irq = platform_get_irq(pdev, 0);
+       if (irq < 0) {
+               dev_err(&pdev->dev, "not able to get irq for the device\n");
+               return irq;
+       }
+
+       kbd = kzalloc(sizeof(*kbd), GFP_KERNEL);
+       input_dev = input_allocate_device();
+       if (!kbd || !input_dev) {
+               dev_err(&pdev->dev, "out of memory\n");
+               error = -ENOMEM;
+               goto err_free_mem;
+       }
+
+       kbd->input = input_dev;
+       kbd->irq = irq;
+       kbd->res = request_mem_region(res->start, resource_size(res),
+                                     pdev->name);
+       if (!kbd->res) {
+               dev_err(&pdev->dev, "keyboard region already claimed\n");
+               error = -EBUSY;
+               goto err_free_mem;
+       }
+
+       kbd->io_base = ioremap(res->start, resource_size(res));
+       if (!kbd->io_base) {
+               dev_err(&pdev->dev, "ioremap failed for kbd_region\n");
+               error = -ENOMEM;
+               goto err_release_mem_region;
+       }
+
+       kbd->clk = clk_get(&pdev->dev, NULL);
+       if (IS_ERR(kbd->clk)) {
+               error = PTR_ERR(kbd->clk);
+               goto err_iounmap;
+       }
+
+       input_dev->name = "Spear Keyboard";
+       input_dev->phys = "keyboard/input0";
+       input_dev->dev.parent = &pdev->dev;
+       input_dev->id.bustype = BUS_HOST;
+       input_dev->id.vendor = 0x0001;
+       input_dev->id.product = 0x0001;
+       input_dev->id.version = 0x0100;
+       input_dev->open = spear_kbd_open;
+       input_dev->close = spear_kbd_close;
+
+       __set_bit(EV_KEY, input_dev->evbit);
+       if (pdata->rep)
+               __set_bit(EV_REP, input_dev->evbit);
+       input_set_capability(input_dev, EV_MSC, MSC_SCAN);
+
+       input_dev->keycode = kbd->keycodes;
+       input_dev->keycodesize = sizeof(kbd->keycodes[0]);
+       input_dev->keycodemax = ARRAY_SIZE(kbd->keycodes);
+
+       matrix_keypad_build_keymap(keymap, ROW_SHIFT,
+                       input_dev->keycode, input_dev->keybit);
+
+       input_set_drvdata(input_dev, kbd);
+
+       error = request_irq(irq, spear_kbd_interrupt, 0, "keyboard", kbd);
+       if (error) {
+               dev_err(&pdev->dev, "request_irq fail\n");
+               goto err_put_clk;
+       }
+
+       error = input_register_device(input_dev);
+       if (error) {
+               dev_err(&pdev->dev, "Unable to register keyboard device\n");
+               goto err_free_irq;
+       }
+
+       device_init_wakeup(&pdev->dev, 1);
+       platform_set_drvdata(pdev, kbd);
+
+       return 0;
+
+err_free_irq:
+       free_irq(kbd->irq, kbd);
+err_put_clk:
+       clk_put(kbd->clk);
+err_iounmap:
+       iounmap(kbd->io_base);
+err_release_mem_region:
+       release_mem_region(res->start, resource_size(res));
+err_free_mem:
+       input_free_device(input_dev);
+       kfree(kbd);
+
+       return error;
+}
+
+static int __devexit spear_kbd_remove(struct platform_device *pdev)
+{
+       struct spear_kbd *kbd = platform_get_drvdata(pdev);
+
+       free_irq(kbd->irq, kbd);
+       input_unregister_device(kbd->input);
+       clk_put(kbd->clk);
+       iounmap(kbd->io_base);
+       release_mem_region(kbd->res->start, resource_size(kbd->res));
+       kfree(kbd);
+
+       device_init_wakeup(&pdev->dev, 1);
+       platform_set_drvdata(pdev, NULL);
+
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int spear_kbd_suspend(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct spear_kbd *kbd = platform_get_drvdata(pdev);
+       struct input_dev *input_dev = kbd->input;
+
+       mutex_lock(&input_dev->mutex);
+
+       if (input_dev->users)
+               clk_enable(kbd->clk);
+
+       if (device_may_wakeup(&pdev->dev))
+               enable_irq_wake(kbd->irq);
+
+       mutex_unlock(&input_dev->mutex);
+
+       return 0;
+}
+
+static int spear_kbd_resume(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct spear_kbd *kbd = platform_get_drvdata(pdev);
+       struct input_dev *input_dev = kbd->input;
+
+       mutex_lock(&input_dev->mutex);
+
+       if (device_may_wakeup(&pdev->dev))
+               disable_irq_wake(kbd->irq);
+
+       if (input_dev->users)
+               clk_enable(kbd->clk);
+
+       mutex_unlock(&input_dev->mutex);
+
+       return 0;
+}
+
+static const struct dev_pm_ops spear_kbd_pm_ops = {
+       .suspend        = spear_kbd_suspend,
+       .resume         = spear_kbd_resume,
+};
+#endif
+
+static struct platform_driver spear_kbd_driver = {
+       .probe          = spear_kbd_probe,
+       .remove         = __devexit_p(spear_kbd_remove),
+       .driver         = {
+               .name   = "keyboard",
+               .owner  = THIS_MODULE,
+#ifdef CONFIG_PM
+               .pm     = &spear_kbd_pm_ops,
+#endif
+       },
+};
+
+static int __init spear_kbd_init(void)
+{
+       return platform_driver_register(&spear_kbd_driver);
+}
+module_init(spear_kbd_init);
+
+static void __exit spear_kbd_exit(void)
+{
+       platform_driver_unregister(&spear_kbd_driver);
+}
+module_exit(spear_kbd_exit);
+
+MODULE_AUTHOR("Rajeev Kumar");
+MODULE_DESCRIPTION("SPEAr Keyboard Driver");
+MODULE_LICENSE("GPL");
index 00137be..800fbcc 100644 (file)
@@ -29,6 +29,7 @@
 
 static const struct i2c_device_id tca6416_id[] = {
        { "tca6416-keys", 16, },
+       { "tca6408-keys", 8, },
        { }
 };
 MODULE_DEVICE_TABLE(i2c, tca6416_id);
@@ -46,8 +47,9 @@ struct tca6416_keypad_chip {
        struct i2c_client *client;
        struct input_dev *input;
        struct delayed_work dwork;
-       u16 pinmask;
+       int io_size;
        int irqnum;
+       u16 pinmask;
        bool use_polling;
        struct tca6416_button buttons[0];
 };
@@ -56,7 +58,9 @@ static int tca6416_write_reg(struct tca6416_keypad_chip *chip, int reg, u16 val)
 {
        int error;
 
-       error = i2c_smbus_write_word_data(chip->client, reg << 1, val);
+       error = chip->io_size > 8 ?
+               i2c_smbus_write_word_data(chip->client, reg << 1, val) :
+               i2c_smbus_write_byte_data(chip->client, reg, val);
        if (error < 0) {
                dev_err(&chip->client->dev,
                        "%s failed, reg: %d, val: %d, error: %d\n",
@@ -71,7 +75,9 @@ static int tca6416_read_reg(struct tca6416_keypad_chip *chip, int reg, u16 *val)
 {
        int retval;
 
-       retval = i2c_smbus_read_word_data(chip->client, reg << 1);
+       retval = chip->io_size > 8 ?
+                i2c_smbus_read_word_data(chip->client, reg << 1) :
+                i2c_smbus_read_byte_data(chip->client, reg);
        if (retval < 0) {
                dev_err(&chip->client->dev, "%s failed, reg: %d, error: %d\n",
                        __func__, reg, retval);
@@ -224,6 +230,7 @@ static int __devinit tca6416_keypad_probe(struct i2c_client *client,
 
        chip->client = client;
        chip->input = input;
+       chip->io_size = id->driver_data;
        chip->pinmask = pdata->pinmask;
        chip->use_polling = pdata->use_polling;
 
index b99b8cb..f0d9017 100644 (file)
@@ -448,4 +448,28 @@ config INPUT_ADXL34X_SPI
          To compile this driver as a module, choose M here: the
          module will be called adxl34x-spi.
 
+config INPUT_CMA3000
+       tristate "VTI CMA3000 Tri-axis accelerometer"
+       help
+         Say Y here if you want to use VTI CMA3000_D0x Accelerometer
+         driver
+
+         This driver currently only supports I2C interface to the
+         controller. Also select the I2C method.
+
+         If unsure, say N
+
+         To compile this driver as a module, choose M here: the
+         module will be called cma3000_d0x.
+
+config INPUT_CMA3000_I2C
+       tristate "Support I2C bus connection"
+       depends on INPUT_CMA3000 && I2C
+       help
+         Say Y here if you want to use VTI CMA3000_D0x Accelerometer
+         through I2C interface.
+
+         To compile this driver as a module, choose M here: the
+         module will be called cma3000_d0x_i2c.
+
 endif
index 1fe1f6c..35bcfe4 100644 (file)
@@ -18,6 +18,8 @@ obj-$(CONFIG_INPUT_ATI_REMOTE2)               += ati_remote2.o
 obj-$(CONFIG_INPUT_ATLAS_BTNS)         += atlas_btns.o
 obj-$(CONFIG_INPUT_BFIN_ROTARY)                += bfin_rotary.o
 obj-$(CONFIG_INPUT_CM109)              += cm109.o
+obj-$(CONFIG_INPUT_CMA3000)            += cma3000_d0x.o
+obj-$(CONFIG_INPUT_CMA3000_I2C)                += cma3000_d0x_i2c.o
 obj-$(CONFIG_INPUT_COBALT_BTNS)                += cobalt_btns.o
 obj-$(CONFIG_INPUT_DM355EVM)           += dm355evm_keys.o
 obj-$(CONFIG_HP_SDC_RTC)               += hp_sdc_rtc.o
diff --git a/drivers/input/misc/cma3000_d0x.c b/drivers/input/misc/cma3000_d0x.c
new file mode 100644 (file)
index 0000000..1633b63
--- /dev/null
@@ -0,0 +1,398 @@
+/*
+ * VTI CMA3000_D0x Accelerometer driver
+ *
+ * Copyright (C) 2010 Texas Instruments
+ * Author: Hemanth V <hemanthv@ti.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.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/input.h>
+#include <linux/input/cma3000.h>
+
+#include "cma3000_d0x.h"
+
+#define CMA3000_WHOAMI      0x00
+#define CMA3000_REVID       0x01
+#define CMA3000_CTRL        0x02
+#define CMA3000_STATUS      0x03
+#define CMA3000_RSTR        0x04
+#define CMA3000_INTSTATUS   0x05
+#define CMA3000_DOUTX       0x06
+#define CMA3000_DOUTY       0x07
+#define CMA3000_DOUTZ       0x08
+#define CMA3000_MDTHR       0x09
+#define CMA3000_MDFFTMR     0x0A
+#define CMA3000_FFTHR       0x0B
+
+#define CMA3000_RANGE2G    (1 << 7)
+#define CMA3000_RANGE8G    (0 << 7)
+#define CMA3000_BUSI2C     (0 << 4)
+#define CMA3000_MODEMASK   (7 << 1)
+#define CMA3000_GRANGEMASK (1 << 7)
+
+#define CMA3000_STATUS_PERR    1
+#define CMA3000_INTSTATUS_FFDET (1 << 2)
+
+/* Settling time delay in ms */
+#define CMA3000_SETDELAY    30
+
+/* Delay for clearing interrupt in us */
+#define CMA3000_INTDELAY    44
+
+
+/*
+ * Bit weights in mg for bit 0, other bits need
+ * multipy factor 2^n. Eight bit is the sign bit.
+ */
+#define BIT_TO_2G  18
+#define BIT_TO_8G  71
+
+struct cma3000_accl_data {
+       const struct cma3000_bus_ops *bus_ops;
+       const struct cma3000_platform_data *pdata;
+
+       struct device *dev;
+       struct input_dev *input_dev;
+
+       int bit_to_mg;
+       int irq;
+
+       int g_range;
+       u8 mode;
+
+       struct mutex mutex;
+       bool opened;
+       bool suspended;
+};
+
+#define CMA3000_READ(data, reg, msg) \
+       (data->bus_ops->read(data->dev, reg, msg))
+#define CMA3000_SET(data, reg, val, msg) \
+       ((data)->bus_ops->write(data->dev, reg, val, msg))
+
+/*
+ * Conversion for each of the eight modes to g, depending
+ * on G range i.e 2G or 8G. Some modes always operate in
+ * 8G.
+ */
+
+static int mode_to_mg[8][2] = {
+       { 0, 0 },
+       { BIT_TO_8G, BIT_TO_2G },
+       { BIT_TO_8G, BIT_TO_2G },
+       { BIT_TO_8G, BIT_TO_8G },
+       { BIT_TO_8G, BIT_TO_8G },
+       { BIT_TO_8G, BIT_TO_2G },
+       { BIT_TO_8G, BIT_TO_2G },
+       { 0, 0},
+};
+
+static void decode_mg(struct cma3000_accl_data *data, int *datax,
+                               int *datay, int *dataz)
+{
+       /* Data in 2's complement, convert to mg */
+       *datax = ((s8)*datax) * data->bit_to_mg;
+       *datay = ((s8)*datay) * data->bit_to_mg;
+       *dataz = ((s8)*dataz) * data->bit_to_mg;
+}
+
+static irqreturn_t cma3000_thread_irq(int irq, void *dev_id)
+{
+       struct cma3000_accl_data *data = dev_id;
+       int datax, datay, dataz;
+       u8 ctrl, mode, range, intr_status;
+
+       intr_status = CMA3000_READ(data, CMA3000_INTSTATUS, "interrupt status");
+       if (intr_status < 0)
+               return IRQ_NONE;
+
+       /* Check if free fall is detected, report immediately */
+       if (intr_status & CMA3000_INTSTATUS_FFDET) {
+               input_report_abs(data->input_dev, ABS_MISC, 1);
+               input_sync(data->input_dev);
+       } else {
+               input_report_abs(data->input_dev, ABS_MISC, 0);
+       }
+
+       datax = CMA3000_READ(data, CMA3000_DOUTX, "X");
+       datay = CMA3000_READ(data, CMA3000_DOUTY, "Y");
+       dataz = CMA3000_READ(data, CMA3000_DOUTZ, "Z");
+
+       ctrl = CMA3000_READ(data, CMA3000_CTRL, "ctrl");
+       mode = (ctrl & CMA3000_MODEMASK) >> 1;
+       range = (ctrl & CMA3000_GRANGEMASK) >> 7;
+
+       data->bit_to_mg = mode_to_mg[mode][range];
+
+       /* Interrupt not for this device */
+       if (data->bit_to_mg == 0)
+               return IRQ_NONE;
+
+       /* Decode register values to milli g */
+       decode_mg(data, &datax, &datay, &dataz);
+
+       input_report_abs(data->input_dev, ABS_X, datax);
+       input_report_abs(data->input_dev, ABS_Y, datay);
+       input_report_abs(data->input_dev, ABS_Z, dataz);
+       input_sync(data->input_dev);
+
+       return IRQ_HANDLED;
+}
+
+static int cma3000_reset(struct cma3000_accl_data *data)
+{
+       int val;
+
+       /* Reset sequence */
+       CMA3000_SET(data, CMA3000_RSTR, 0x02, "Reset");
+       CMA3000_SET(data, CMA3000_RSTR, 0x0A, "Reset");
+       CMA3000_SET(data, CMA3000_RSTR, 0x04, "Reset");
+
+       /* Settling time delay */
+       mdelay(10);
+
+       val = CMA3000_READ(data, CMA3000_STATUS, "Status");
+       if (val < 0) {
+               dev_err(data->dev, "Reset failed\n");
+               return val;
+       }
+
+       if (val & CMA3000_STATUS_PERR) {
+               dev_err(data->dev, "Parity Error\n");
+               return -EIO;
+       }
+
+       return 0;
+}
+
+static int cma3000_poweron(struct cma3000_accl_data *data)
+{
+       const struct cma3000_platform_data *pdata = data->pdata;
+       u8 ctrl = 0;
+       int ret;
+
+       if (data->g_range == CMARANGE_2G) {
+               ctrl = (data->mode << 1) | CMA3000_RANGE2G;
+       } else if (data->g_range == CMARANGE_8G) {
+               ctrl = (data->mode << 1) | CMA3000_RANGE8G;
+       } else {
+               dev_info(data->dev,
+                        "Invalid G range specified, assuming 8G\n");
+               ctrl = (data->mode << 1) | CMA3000_RANGE8G;
+       }
+
+       ctrl |= data->bus_ops->ctrl_mod;
+
+       CMA3000_SET(data, CMA3000_MDTHR, pdata->mdthr,
+                   "Motion Detect Threshold");
+       CMA3000_SET(data, CMA3000_MDFFTMR, pdata->mdfftmr,
+                   "Time register");
+       CMA3000_SET(data, CMA3000_FFTHR, pdata->ffthr,
+                   "Free fall threshold");
+       ret = CMA3000_SET(data, CMA3000_CTRL, ctrl, "Mode setting");
+       if (ret < 0)
+               return -EIO;
+
+       msleep(CMA3000_SETDELAY);
+
+       return 0;
+}
+
+static int cma3000_poweroff(struct cma3000_accl_data *data)
+{
+       int ret;
+
+       ret = CMA3000_SET(data, CMA3000_CTRL, CMAMODE_POFF, "Mode setting");
+       msleep(CMA3000_SETDELAY);
+
+       return ret;
+}
+
+static int cma3000_open(struct input_dev *input_dev)
+{
+       struct cma3000_accl_data *data = input_get_drvdata(input_dev);
+
+       mutex_lock(&data->mutex);
+
+       if (!data->suspended)
+               cma3000_poweron(data);
+
+       data->opened = true;
+
+       mutex_unlock(&data->mutex);
+
+       return 0;
+}
+
+static void cma3000_close(struct input_dev *input_dev)
+{
+       struct cma3000_accl_data *data = input_get_drvdata(input_dev);
+
+       mutex_lock(&data->mutex);
+
+       if (!data->suspended)
+               cma3000_poweroff(data);
+
+       data->opened = false;
+
+       mutex_unlock(&data->mutex);
+}
+
+void cma3000_suspend(struct cma3000_accl_data *data)
+{
+       mutex_lock(&data->mutex);
+
+       if (!data->suspended && data->opened)
+               cma3000_poweroff(data);
+
+       data->suspended = true;
+
+       mutex_unlock(&data->mutex);
+}
+EXPORT_SYMBOL(cma3000_suspend);
+
+
+void cma3000_resume(struct cma3000_accl_data *data)
+{
+       mutex_lock(&data->mutex);
+
+       if (data->suspended && data->opened)
+               cma3000_poweron(data);
+
+       data->suspended = false;
+
+       mutex_unlock(&data->mutex);
+}
+EXPORT_SYMBOL(cma3000_resume);
+
+struct cma3000_accl_data *cma3000_init(struct device *dev, int irq,
+                                      const struct cma3000_bus_ops *bops)
+{
+       const struct cma3000_platform_data *pdata = dev->platform_data;
+       struct cma3000_accl_data *data;
+       struct input_dev *input_dev;
+       int rev;
+       int error;
+
+       if (!pdata) {
+               dev_err(dev, "platform data not found\n");
+               error = -EINVAL;
+               goto err_out;
+       }
+
+
+       /* if no IRQ return error */
+       if (irq == 0) {
+               error = -EINVAL;
+               goto err_out;
+       }
+
+       data = kzalloc(sizeof(struct cma3000_accl_data), GFP_KERNEL);
+       input_dev = input_allocate_device();
+       if (!data || !input_dev) {
+               error = -ENOMEM;
+               goto err_free_mem;
+       }
+
+       data->dev = dev;
+       data->input_dev = input_dev;
+       data->bus_ops = bops;
+       data->pdata = pdata;
+       data->irq = irq;
+       mutex_init(&data->mutex);
+
+       data->mode = pdata->mode;
+       if (data->mode < CMAMODE_DEFAULT || data->mode > CMAMODE_POFF) {
+               data->mode = CMAMODE_MOTDET;
+               dev_warn(dev,
+                        "Invalid mode specified, assuming Motion Detect\n");
+       }
+
+       data->g_range = pdata->g_range;
+       if (data->g_range != CMARANGE_2G && data->g_range != CMARANGE_8G) {
+               dev_info(dev,
+                        "Invalid G range specified, assuming 8G\n");
+               data->g_range = CMARANGE_8G;
+       }
+
+       input_dev->name = "cma3000-accelerometer";
+       input_dev->id.bustype = bops->bustype;
+       input_dev->open = cma3000_open;
+       input_dev->close = cma3000_close;
+
+        __set_bit(EV_ABS, input_dev->evbit);
+
+       input_set_abs_params(input_dev, ABS_X,
+                       -data->g_range, data->g_range, pdata->fuzz_x, 0);
+       input_set_abs_params(input_dev, ABS_Y,
+                       -data->g_range, data->g_range, pdata->fuzz_y, 0);
+       input_set_abs_params(input_dev, ABS_Z,
+                       -data->g_range, data->g_range, pdata->fuzz_z, 0);
+       input_set_abs_params(input_dev, ABS_MISC, 0, 1, 0, 0);
+
+       input_set_drvdata(input_dev, data);
+
+       error = cma3000_reset(data);
+       if (error)
+               goto err_free_mem;
+
+       rev = CMA3000_READ(data, CMA3000_REVID, "Revid");
+       if (rev < 0) {
+               error = rev;
+               goto err_free_mem;
+       }
+
+       pr_info("CMA3000 Accelerometer: Revision %x\n", rev);
+
+       error = request_threaded_irq(irq, NULL, cma3000_thread_irq,
+                                    pdata->irqflags | IRQF_ONESHOT,
+                                    "cma3000_d0x", data);
+       if (error) {
+               dev_err(dev, "request_threaded_irq failed\n");
+               goto err_free_mem;
+       }
+
+       error = input_register_device(data->input_dev);
+       if (error) {
+               dev_err(dev, "Unable to register input device\n");
+               goto err_free_irq;
+       }
+
+       return data;
+
+err_free_irq:
+       free_irq(irq, data);
+err_free_mem:
+       input_free_device(input_dev);
+       kfree(data);
+err_out:
+       return ERR_PTR(error);
+}
+EXPORT_SYMBOL(cma3000_init);
+
+void cma3000_exit(struct cma3000_accl_data *data)
+{
+       free_irq(data->irq, data);
+       input_unregister_device(data->input_dev);
+       kfree(data);
+}
+EXPORT_SYMBOL(cma3000_exit);
+
+MODULE_DESCRIPTION("CMA3000-D0x Accelerometer Driver");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Hemanth V <hemanthv@ti.com>");
diff --git a/drivers/input/misc/cma3000_d0x.h b/drivers/input/misc/cma3000_d0x.h
new file mode 100644 (file)
index 0000000..2304ce3
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * VTI CMA3000_D0x Accelerometer driver
+ *
+ * Copyright (C) 2010 Texas Instruments
+ * Author: Hemanth V <hemanthv@ti.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.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _INPUT_CMA3000_H
+#define _INPUT_CMA3000_H
+
+#include <linux/types.h>
+#include <linux/input.h>
+
+struct device;
+struct cma3000_accl_data;
+
+struct cma3000_bus_ops {
+       u16 bustype;
+       u8 ctrl_mod;
+       int (*read)(struct device *, u8, char *);
+       int (*write)(struct device *, u8, u8, char *);
+};
+
+struct cma3000_accl_data *cma3000_init(struct device *dev, int irq,
+                                       const struct cma3000_bus_ops *bops);
+void cma3000_exit(struct cma3000_accl_data *);
+void cma3000_suspend(struct cma3000_accl_data *);
+void cma3000_resume(struct cma3000_accl_data *);
+
+#endif
diff --git a/drivers/input/misc/cma3000_d0x_i2c.c b/drivers/input/misc/cma3000_d0x_i2c.c
new file mode 100644 (file)
index 0000000..d100cc5
--- /dev/null
@@ -0,0 +1,143 @@
+/*
+ * Implements I2C interface for VTI CMA300_D0x Accelerometer driver
+ *
+ * Copyright (C) 2010 Texas Instruments
+ * Author: Hemanth V <hemanthv@ti.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.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/input/cma3000.h>
+#include "cma3000_d0x.h"
+
+static int cma3000_i2c_set(struct device *dev,
+                          u8 reg, u8 val, char *msg)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       int ret;
+
+       ret = i2c_smbus_write_byte_data(client, reg, val);
+       if (ret < 0)
+               dev_err(&client->dev,
+                       "%s failed (%s, %d)\n", __func__, msg, ret);
+       return ret;
+}
+
+static int cma3000_i2c_read(struct device *dev, u8 reg, char *msg)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       int ret;
+
+       ret = i2c_smbus_read_byte_data(client, reg);
+       if (ret < 0)
+               dev_err(&client->dev,
+                       "%s failed (%s, %d)\n", __func__, msg, ret);
+       return ret;
+}
+
+static const struct cma3000_bus_ops cma3000_i2c_bops = {
+       .bustype        = BUS_I2C,
+#define CMA3000_BUSI2C     (0 << 4)
+       .ctrl_mod       = CMA3000_BUSI2C,
+       .read           = cma3000_i2c_read,
+       .write          = cma3000_i2c_set,
+};
+
+static int __devinit cma3000_i2c_probe(struct i2c_client *client,
+                                       const struct i2c_device_id *id)
+{
+       struct cma3000_accl_data *data;
+
+       data = cma3000_init(&client->dev, client->irq, &cma3000_i2c_bops);
+       if (IS_ERR(data))
+               return PTR_ERR(data);
+
+       i2c_set_clientdata(client, data);
+
+       return 0;
+}
+
+static int __devexit cma3000_i2c_remove(struct i2c_client *client)
+{
+       struct cma3000_accl_data *data = i2c_get_clientdata(client);
+
+       cma3000_exit(data);
+
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int cma3000_i2c_suspend(struct device *dev)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct cma3000_accl_data *data = i2c_get_clientdata(client);
+
+       cma3000_suspend(data);
+
+       return 0;
+}
+
+static int cma3000_i2c_resume(struct device *dev)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct cma3000_accl_data *data = i2c_get_clientdata(client);
+
+       cma3000_resume(data);
+
+       return 0;
+}
+
+static const struct dev_pm_ops cma3000_i2c_pm_ops = {
+       .suspend        = cma3000_i2c_suspend,
+       .resume         = cma3000_i2c_resume,
+};
+#endif
+
+static const struct i2c_device_id cma3000_i2c_id[] = {
+       { "cma3000_d01", 0 },
+       { },
+};
+
+MODULE_DEVICE_TABLE(i2c, cma3000_i2c_id);
+
+static struct i2c_driver cma3000_i2c_driver = {
+       .probe          = cma3000_i2c_probe,
+       .remove         = __devexit_p(cma3000_i2c_remove),
+       .id_table       = cma3000_i2c_id,
+       .driver = {
+               .name   = "cma3000_i2c_accl",
+               .owner  = THIS_MODULE,
+#ifdef CONFIG_PM
+               .pm     = &cma3000_i2c_pm_ops,
+#endif
+       },
+};
+
+static int __init cma3000_i2c_init(void)
+{
+       return i2c_add_driver(&cma3000_i2c_driver);
+}
+
+static void __exit cma3000_i2c_exit(void)
+{
+       i2c_del_driver(&cma3000_i2c_driver);
+}
+
+module_init(cma3000_i2c_init);
+module_exit(cma3000_i2c_exit);
+
+MODULE_DESCRIPTION("CMA3000-D0x Accelerometer I2C Driver");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Hemanth V <hemanthv@ti.com>");
index 4b42ffc..08be1a3 100644 (file)
@@ -127,14 +127,6 @@ static int __devinit pcf8574_kp_probe(struct i2c_client *client, const struct i2
        idev->id.product = 0x0001;
        idev->id.version = 0x0100;
 
-       input_set_drvdata(idev, lp);
-
-       ret = input_register_device(idev);
-       if (ret) {
-               dev_err(&client->dev, "input_register_device() failed\n");
-               goto fail_register;
-       }
-
        lp->laststate = read_state(lp);
 
        ret = request_threaded_irq(client->irq, NULL, pcf8574_kp_irq_handler,
@@ -142,16 +134,21 @@ static int __devinit pcf8574_kp_probe(struct i2c_client *client, const struct i2
                                   DRV_NAME, lp);
        if (ret) {
                dev_err(&client->dev, "IRQ %d is not free\n", client->irq);
-               goto fail_irq;
+               goto fail_free_device;
+       }
+
+       ret = input_register_device(idev);
+       if (ret) {
+               dev_err(&client->dev, "input_register_device() failed\n");
+               goto fail_free_irq;
        }
 
        i2c_set_clientdata(client, lp);
        return 0;
 
- fail_irq:
-       input_unregister_device(idev);
- fail_register:
-       input_set_drvdata(idev, NULL);
+ fail_free_irq:
+       free_irq(client->irq, lp);
+ fail_free_device:
        input_free_device(idev);
  fail_allocate:
        kfree(lp);
@@ -172,19 +169,29 @@ static int __devexit pcf8574_kp_remove(struct i2c_client *client)
 }
 
 #ifdef CONFIG_PM
-static int pcf8574_kp_resume(struct i2c_client *client)
+static int pcf8574_kp_resume(struct device *dev)
 {
+       struct i2c_client *client = to_i2c_client(dev);
+
        enable_irq(client->irq);
 
        return 0;
 }
 
-static int pcf8574_kp_suspend(struct i2c_client *client, pm_message_t mesg)
+static int pcf8574_kp_suspend(struct device *dev)
 {
+       struct i2c_client *client = to_i2c_client(dev);
+
        disable_irq(client->irq);
 
        return 0;
 }
+
+static const struct dev_pm_ops pcf8574_kp_pm_ops = {
+       .suspend        = pcf8574_kp_suspend,
+       .resume         = pcf8574_kp_resume,
+};
+
 #else
 # define pcf8574_kp_resume  NULL
 # define pcf8574_kp_suspend NULL
@@ -200,11 +207,12 @@ static struct i2c_driver pcf8574_kp_driver = {
        .driver = {
                .name  = DRV_NAME,
                .owner = THIS_MODULE,
+#ifdef CONFIG_PM
+               .pm = &pcf8574_kp_pm_ops,
+#endif
        },
        .probe    = pcf8574_kp_probe,
        .remove   = __devexit_p(pcf8574_kp_remove),
-       .suspend  = pcf8574_kp_suspend,
-       .resume   = pcf8574_kp_resume,
        .id_table = pcf8574_kp_id,
 };
 
index 1d2205b..95577c1 100644 (file)
@@ -40,6 +40,8 @@
 #include "psmouse.h"
 #include "hgpk.h"
 
+#define ILLEGAL_XY 999999
+
 static bool tpdebug;
 module_param(tpdebug, bool, 0644);
 MODULE_PARM_DESC(tpdebug, "enable debugging, dumping packets to KERN_DEBUG.");
@@ -47,48 +49,150 @@ MODULE_PARM_DESC(tpdebug, "enable debugging, dumping packets to KERN_DEBUG.");
 static int recalib_delta = 100;
 module_param(recalib_delta, int, 0644);
 MODULE_PARM_DESC(recalib_delta,
-       "packets containing a delta this large will cause a recalibration.");
+       "packets containing a delta this large will be discarded, and a "
+       "recalibration may be scheduled.");
 
-static int jumpy_delay = 1000;
+static int jumpy_delay = 20;
 module_param(jumpy_delay, int, 0644);
 MODULE_PARM_DESC(jumpy_delay,
        "delay (ms) before recal after jumpiness detected");
 
-static int spew_delay = 1000;
+static int spew_delay = 1;
 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;
+static int recal_guard_time;
 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;
+static int post_interrupt_delay = 40;
 module_param(post_interrupt_delay, int, 0644);
 MODULE_PARM_DESC(post_interrupt_delay,
        "delay (ms) before recal after recal interrupt detected");
 
+static bool autorecal = true;
+module_param(autorecal, bool, 0644);
+MODULE_PARM_DESC(autorecal, "enable recalibration in the driver");
+
+static char hgpk_mode_name[16];
+module_param_string(hgpk_mode, hgpk_mode_name, sizeof(hgpk_mode_name), 0644);
+MODULE_PARM_DESC(hgpk_mode,
+       "default hgpk mode: mouse, glidesensor or pentablet");
+
+static int hgpk_default_mode = HGPK_MODE_MOUSE;
+
+static const char * const hgpk_mode_names[] = {
+       [HGPK_MODE_MOUSE] = "Mouse",
+       [HGPK_MODE_GLIDESENSOR] = "GlideSensor",
+       [HGPK_MODE_PENTABLET] = "PenTablet",
+};
+
+static int hgpk_mode_from_name(const char *buf, int len)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(hgpk_mode_names); i++) {
+               const char *name = hgpk_mode_names[i];
+               if (strlen(name) == len && !strncasecmp(name, buf, len))
+                       return i;
+       }
+
+       return HGPK_MODE_INVALID;
+}
+
+/*
+ * see if new value is within 20% of half of old value
+ */
+static int approx_half(int curr, int prev)
+{
+       int belowhalf, abovehalf;
+
+       if (curr < 5 || prev < 5)
+               return 0;
+
+       belowhalf = (prev * 8) / 20;
+       abovehalf = (prev * 12) / 20;
+
+       return belowhalf < curr && curr <= abovehalf;
+}
+
 /*
- * 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
- * when one places their finger on the pad.  We can probably detect the
- * jump as we see a large deltas (>= 100px).  In mouse mode, I've been
- * unable to even come close to 100px deltas during normal usage, so I think
- * this threshold is safe.  If a large delta occurs, trigger a recalibration.
+ * Throw out oddly large delta packets, and any that immediately follow whose
+ * values are each approximately half of the previous.  It seems that the ALPS
+ * firmware emits errant packets, and they get averaged out slowly.
  */
-static void hgpk_jumpy_hack(struct psmouse *psmouse, int x, int y)
+static int hgpk_discard_decay_hack(struct psmouse *psmouse, int x, int y)
 {
        struct hgpk_data *priv = psmouse->private;
+       int avx, avy;
+       bool do_recal = false;
+
+       avx = abs(x);
+       avy = abs(y);
+
+       /* discard if too big, or half that but > 4 times the prev delta */
+       if (avx > recalib_delta ||
+               (avx > recalib_delta / 2 && ((avx / 4) > priv->xlast))) {
+               hgpk_err(psmouse, "detected %dpx jump in x\n", x);
+               priv->xbigj = avx;
+       } else if (approx_half(avx, priv->xbigj)) {
+               hgpk_err(psmouse, "detected secondary %dpx jump in x\n", x);
+               priv->xbigj = avx;
+               priv->xsaw_secondary++;
+       } else {
+               if (priv->xbigj && priv->xsaw_secondary > 1)
+                       do_recal = true;
+               priv->xbigj = 0;
+               priv->xsaw_secondary = 0;
+       }
+
+       if (avy > recalib_delta ||
+               (avy > recalib_delta / 2 && ((avy / 4) > priv->ylast))) {
+               hgpk_err(psmouse, "detected %dpx jump in y\n", y);
+               priv->ybigj = avy;
+       } else if (approx_half(avy, priv->ybigj)) {
+               hgpk_err(psmouse, "detected secondary %dpx jump in y\n", y);
+               priv->ybigj = avy;
+               priv->ysaw_secondary++;
+       } else {
+               if (priv->ybigj && priv->ysaw_secondary > 1)
+                       do_recal = true;
+               priv->ybigj = 0;
+               priv->ysaw_secondary = 0;
+       }
 
-       if (abs(x) > recalib_delta || abs(y) > recalib_delta) {
-               hgpk_err(psmouse, ">%dpx jump detected (%d,%d)\n",
-                               recalib_delta, x, y);
-               /* My car gets forty rods to the hogshead and that's the
-                * way I likes it! */
+       priv->xlast = avx;
+       priv->ylast = avy;
+
+       if (do_recal && jumpy_delay) {
+               hgpk_err(psmouse, "scheduling recalibration\n");
                psmouse_queue_work(psmouse, &priv->recalib_wq,
                                msecs_to_jiffies(jumpy_delay));
        }
+
+       return priv->xbigj || priv->ybigj;
+}
+
+static void hgpk_reset_spew_detection(struct hgpk_data *priv)
+{
+       priv->spew_count = 0;
+       priv->dupe_count = 0;
+       priv->x_tally = 0;
+       priv->y_tally = 0;
+       priv->spew_flag = NO_SPEW;
+}
+
+static void hgpk_reset_hack_state(struct psmouse *psmouse)
+{
+       struct hgpk_data *priv = psmouse->private;
+
+       priv->abs_x = priv->abs_y = -1;
+       priv->xlast = priv->ylast = ILLEGAL_XY;
+       priv->xbigj = priv->ybigj = 0;
+       priv->xsaw_secondary = priv->ysaw_secondary = 0;
+       hgpk_reset_spew_detection(priv);
 }
 
 /*
@@ -116,20 +220,57 @@ static void hgpk_spewing_hack(struct psmouse *psmouse,
        if (l || r)
                return;
 
+       /* don't track spew if the workaround feature has been turned off */
+       if (!spew_delay)
+               return;
+
+       if (abs(x) > 3 || abs(y) > 3) {
+               /* no spew, or spew ended */
+               hgpk_reset_spew_detection(priv);
+               return;
+       }
+
+       /* Keep a tally of the overall delta to the cursor position caused by
+        * the spew */
        priv->x_tally += x;
        priv->y_tally += y;
 
-       if (++priv->count > 100) {
+       switch (priv->spew_flag) {
+       case NO_SPEW:
+               /* we're not spewing, but this packet might be the start */
+               priv->spew_flag = MAYBE_SPEWING;
+
+               /* fall-through */
+
+       case MAYBE_SPEWING:
+               priv->spew_count++;
+
+               if (priv->spew_count < SPEW_WATCH_COUNT)
+                       break;
+
+               /* excessive spew detected, request recalibration */
+               priv->spew_flag = SPEW_DETECTED;
+
+               /* fall-through */
+
+       case SPEW_DETECTED:
+               /* only recalibrate when the overall delta to the cursor
+                * is really small. if the spew is causing significant cursor
+                * movement, it is probably a case of the user moving the
+                * cursor very slowly across the screen. */
                if (abs(priv->x_tally) < 3 && abs(priv->y_tally) < 3) {
-                       hgpk_dbg(psmouse, "packet spew detected (%d,%d)\n",
+                       hgpk_err(psmouse, "packet spew detected (%d,%d)\n",
                                 priv->x_tally, priv->y_tally);
+                       priv->spew_flag = RECALIBRATING;
                        psmouse_queue_work(psmouse, &priv->recalib_wq,
                                           msecs_to_jiffies(spew_delay));
                }
-               /* reset every 100 packets */
-               priv->count = 0;
-               priv->x_tally = 0;
-               priv->y_tally = 0;
+
+               break;
+       case RECALIBRATING:
+               /* we already detected a spew and requested a recalibration,
+                * just wait for the queue to kick into action. */
+               break;
        }
 }
 
@@ -143,25 +284,168 @@ static void hgpk_spewing_hack(struct psmouse *psmouse,
  * swr/swl are the left/right buttons.
  * x-neg/y-neg are the x and y delta negative bits
  * x-over/y-over are the x and y overflow bits
+ *
+ * ---
+ *
+ * HGPK Advanced Mode - single-mode format
+ *
+ * byte 0(PT):  1    1    0    0    1    1     1     1
+ * byte 0(GS):  1    1    1    1    1    1     1     1
+ * byte 1:      0   x6   x5   x4   x3   x2    x1    x0
+ * byte 2(PT):  0    0   x9   x8   x7    ? pt-dsw    0
+ * byte 2(GS):  0  x10   x9   x8   x7    ? gs-dsw pt-dsw
+ * byte 3:      0   y9   y8   y7    1    0   swr   swl
+ * byte 4:      0   y6   y5   y4   y3   y2    y1    y0
+ * byte 5:      0   z6   z5   z4   z3   z2    z1    z0
+ *
+ * ?'s are not defined in the protocol spec, may vary between models.
+ *
+ * swr/swl are the left/right buttons.
+ *
+ * pt-dsw/gs-dsw indicate that the pt/gs sensor is detecting a
+ * pen/finger
  */
-static int hgpk_validate_byte(unsigned char *packet)
+static bool hgpk_is_byte_valid(struct psmouse *psmouse, unsigned char *packet)
 {
-       return (packet[0] & 0x0C) != 0x08;
+       struct hgpk_data *priv = psmouse->private;
+       int pktcnt = psmouse->pktcnt;
+       bool valid;
+
+       switch (priv->mode) {
+       case HGPK_MODE_MOUSE:
+               valid = (packet[0] & 0x0C) == 0x08;
+               break;
+
+       case HGPK_MODE_GLIDESENSOR:
+               valid = pktcnt == 1 ?
+                       packet[0] == HGPK_GS : !(packet[pktcnt - 1] & 0x80);
+               break;
+
+       case HGPK_MODE_PENTABLET:
+               valid = pktcnt == 1 ?
+                       packet[0] == HGPK_PT : !(packet[pktcnt - 1] & 0x80);
+               break;
+
+       default:
+               valid = false;
+               break;
+       }
+
+       if (!valid)
+               hgpk_dbg(psmouse,
+                        "bad data, mode %d (%d) %02x %02x %02x %02x %02x %02x\n",
+                        priv->mode, pktcnt,
+                        psmouse->packet[0], psmouse->packet[1],
+                        psmouse->packet[2], psmouse->packet[3],
+                        psmouse->packet[4], psmouse->packet[5]);
+
+       return valid;
 }
 
-static void hgpk_process_packet(struct psmouse *psmouse)
+static void hgpk_process_advanced_packet(struct psmouse *psmouse)
 {
-       struct input_dev *dev = psmouse->dev;
+       struct hgpk_data *priv = psmouse->private;
+       struct input_dev *idev = psmouse->dev;
        unsigned char *packet = psmouse->packet;
-       int x, y, left, right;
+       int down = !!(packet[2] & 2);
+       int left = !!(packet[3] & 1);
+       int right = !!(packet[3] & 2);
+       int x = packet[1] | ((packet[2] & 0x78) << 4);
+       int y = packet[4] | ((packet[3] & 0x70) << 3);
+
+       if (priv->mode == HGPK_MODE_GLIDESENSOR) {
+               int pt_down = !!(packet[2] & 1);
+               int finger_down = !!(packet[2] & 2);
+               int z = packet[5];
+
+               input_report_abs(idev, ABS_PRESSURE, z);
+               if (tpdebug)
+                       hgpk_dbg(psmouse, "pd=%d fd=%d z=%d",
+                                pt_down, finger_down, z);
+       } else {
+               /*
+                * PenTablet mode does not report pressure, so we don't
+                * report it here
+                */
+               if (tpdebug)
+                       hgpk_dbg(psmouse, "pd=%d ", down);
+       }
+
+       if (tpdebug)
+               hgpk_dbg(psmouse, "l=%d r=%d x=%d y=%d\n", left, right, x, y);
+
+       input_report_key(idev, BTN_TOUCH, down);
+       input_report_key(idev, BTN_LEFT, left);
+       input_report_key(idev, BTN_RIGHT, right);
+
+       /*
+        * If this packet says that the finger was removed, reset our position
+        * tracking so that we don't erroneously detect a jump on next press.
+        */
+       if (!down) {
+               hgpk_reset_hack_state(psmouse);
+               goto done;
+       }
+
+       /*
+        * Weed out duplicate packets (we get quite a few, and they mess up
+        * our jump detection)
+        */
+       if (x == priv->abs_x && y == priv->abs_y) {
+               if (++priv->dupe_count > SPEW_WATCH_COUNT) {
+                       if (tpdebug)
+                               hgpk_dbg(psmouse, "hard spew detected\n");
+                       priv->spew_flag = RECALIBRATING;
+                       psmouse_queue_work(psmouse, &priv->recalib_wq,
+                                          msecs_to_jiffies(spew_delay));
+               }
+               goto done;
+       }
 
-       left = packet[0] & 1;
-       right = (packet[0] >> 1) & 1;
+       /* not a duplicate, continue with position reporting */
+       priv->dupe_count = 0;
+
+       /* Don't apply hacks in PT mode, it seems reliable */
+       if (priv->mode != HGPK_MODE_PENTABLET && priv->abs_x != -1) {
+               int x_diff = priv->abs_x - x;
+               int y_diff = priv->abs_y - y;
+               if (hgpk_discard_decay_hack(psmouse, x_diff, y_diff)) {
+                       if (tpdebug)
+                               hgpk_dbg(psmouse, "discarding\n");
+                       goto done;
+               }
+               hgpk_spewing_hack(psmouse, left, right, x_diff, y_diff);
+       }
 
-       x = packet[1] - ((packet[0] << 4) & 0x100);
-       y = ((packet[0] << 3) & 0x100) - packet[2];
+       input_report_abs(idev, ABS_X, x);
+       input_report_abs(idev, ABS_Y, y);
+       priv->abs_x = x;
+       priv->abs_y = y;
+
+done:
+       input_sync(idev);
+}
+
+static void hgpk_process_simple_packet(struct psmouse *psmouse)
+{
+       struct input_dev *dev = psmouse->dev;
+       unsigned char *packet = psmouse->packet;
+       int left = packet[0] & 1;
+       int right = (packet[0] >> 1) & 1;
+       int x = packet[1] - ((packet[0] << 4) & 0x100);
+       int y = ((packet[0] << 3) & 0x100) - packet[2];
+
+       if (packet[0] & 0xc0)
+               hgpk_dbg(psmouse,
+                        "overflow -- 0x%02x 0x%02x 0x%02x\n",
+                        packet[0], packet[1], packet[2]);
+
+       if (hgpk_discard_decay_hack(psmouse, x, y)) {
+               if (tpdebug)
+                       hgpk_dbg(psmouse, "discarding\n");
+               return;
+       }
 
-       hgpk_jumpy_hack(psmouse, x, y);
        hgpk_spewing_hack(psmouse, left, right, x, y);
 
        if (tpdebug)
@@ -180,15 +464,14 @@ static psmouse_ret_t hgpk_process_byte(struct psmouse *psmouse)
 {
        struct hgpk_data *priv = psmouse->private;
 
-       if (hgpk_validate_byte(psmouse->packet)) {
-               hgpk_dbg(psmouse, "%s: (%d) %02x %02x %02x\n",
-                               __func__, psmouse->pktcnt, psmouse->packet[0],
-                               psmouse->packet[1], psmouse->packet[2]);
+       if (!hgpk_is_byte_valid(psmouse, psmouse->packet))
                return PSMOUSE_BAD_DATA;
-       }
 
        if (psmouse->pktcnt >= psmouse->pktsize) {
-               hgpk_process_packet(psmouse);
+               if (priv->mode == HGPK_MODE_MOUSE)
+                       hgpk_process_simple_packet(psmouse);
+               else
+                       hgpk_process_advanced_packet(psmouse);
                return PSMOUSE_FULL_PACKET;
        }
 
@@ -210,33 +493,176 @@ static psmouse_ret_t hgpk_process_byte(struct psmouse *psmouse)
        return PSMOUSE_GOOD_DATA;
 }
 
+static int hgpk_select_mode(struct psmouse *psmouse)
+{
+       struct ps2dev *ps2dev = &psmouse->ps2dev;
+       struct hgpk_data *priv = psmouse->private;
+       int i;
+       int cmd;
+
+       /*
+        * 4 disables to enable advanced mode
+        * then 3 0xf2 bytes as the preamble for GS/PT selection
+        */
+       const int advanced_init[] = {
+               PSMOUSE_CMD_DISABLE, PSMOUSE_CMD_DISABLE,
+               PSMOUSE_CMD_DISABLE, PSMOUSE_CMD_DISABLE,
+               0xf2, 0xf2, 0xf2,
+       };
+
+       switch (priv->mode) {
+       case HGPK_MODE_MOUSE:
+               psmouse->pktsize = 3;
+               break;
+
+       case HGPK_MODE_GLIDESENSOR:
+       case HGPK_MODE_PENTABLET:
+               psmouse->pktsize = 6;
+
+               /* Switch to 'Advanced mode.', four disables in a row. */
+               for (i = 0; i < ARRAY_SIZE(advanced_init); i++)
+                       if (ps2_command(ps2dev, NULL, advanced_init[i]))
+                               return -EIO;
+
+               /* select between GlideSensor (mouse) or PenTablet */
+               cmd = priv->mode == HGPK_MODE_GLIDESENSOR ?
+                       PSMOUSE_CMD_SETSCALE11 : PSMOUSE_CMD_SETSCALE21;
+
+               if (ps2_command(ps2dev, NULL, cmd))
+                       return -EIO;
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static void hgpk_setup_input_device(struct input_dev *input,
+                                   struct input_dev *old_input,
+                                   enum hgpk_mode mode)
+{
+       if (old_input) {
+               input->name = old_input->name;
+               input->phys = old_input->phys;
+               input->id = old_input->id;
+               input->dev.parent = old_input->dev.parent;
+       }
+
+       memset(input->evbit, 0, sizeof(input->evbit));
+       memset(input->relbit, 0, sizeof(input->relbit));
+       memset(input->keybit, 0, sizeof(input->keybit));
+
+       /* All modes report left and right buttons */
+       __set_bit(EV_KEY, input->evbit);
+       __set_bit(BTN_LEFT, input->keybit);
+       __set_bit(BTN_RIGHT, input->keybit);
+
+       switch (mode) {
+       case HGPK_MODE_MOUSE:
+               __set_bit(EV_REL, input->evbit);
+               __set_bit(REL_X, input->relbit);
+               __set_bit(REL_Y, input->relbit);
+               break;
+
+       case HGPK_MODE_GLIDESENSOR:
+               __set_bit(BTN_TOUCH, input->keybit);
+               __set_bit(BTN_TOOL_FINGER, input->keybit);
+
+               __set_bit(EV_ABS, input->evbit);
+
+               /* GlideSensor has pressure sensor, PenTablet does not */
+               input_set_abs_params(input, ABS_PRESSURE, 0, 15, 0, 0);
+
+               /* From device specs */
+               input_set_abs_params(input, ABS_X, 0, 399, 0, 0);
+               input_set_abs_params(input, ABS_Y, 0, 290, 0, 0);
+
+               /* Calculated by hand based on usable size (52mm x 38mm) */
+               input_abs_set_res(input, ABS_X, 8);
+               input_abs_set_res(input, ABS_Y, 8);
+               break;
+
+       case HGPK_MODE_PENTABLET:
+               __set_bit(BTN_TOUCH, input->keybit);
+               __set_bit(BTN_TOOL_FINGER, input->keybit);
+
+               __set_bit(EV_ABS, input->evbit);
+
+               /* From device specs */
+               input_set_abs_params(input, ABS_X, 0, 999, 0, 0);
+               input_set_abs_params(input, ABS_Y, 5, 239, 0, 0);
+
+               /* Calculated by hand based on usable size (156mm x 38mm) */
+               input_abs_set_res(input, ABS_X, 6);
+               input_abs_set_res(input, ABS_Y, 8);
+               break;
+
+       default:
+               BUG();
+       }
+}
+
+static int hgpk_reset_device(struct psmouse *psmouse, bool recalibrate)
+{
+       int err;
+
+       psmouse_reset(psmouse);
+
+       if (recalibrate) {
+               struct ps2dev *ps2dev = &psmouse->ps2dev;
+
+               /* send the recalibrate request */
+               if (ps2_command(ps2dev, NULL, 0xf5) ||
+                   ps2_command(ps2dev, NULL, 0xf5) ||
+                   ps2_command(ps2dev, NULL, 0xe6) ||
+                   ps2_command(ps2dev, NULL, 0xf5)) {
+                       return -1;
+               }
+
+               /* according to ALPS, 150mS is required for recalibration */
+               msleep(150);
+       }
+
+       err = hgpk_select_mode(psmouse);
+       if (err) {
+               hgpk_err(psmouse, "failed to select mode\n");
+               return err;
+       }
+
+       hgpk_reset_hack_state(psmouse);
+
+       return 0;
+}
+
 static int hgpk_force_recalibrate(struct psmouse *psmouse)
 {
        struct ps2dev *ps2dev = &psmouse->ps2dev;
        struct hgpk_data *priv = psmouse->private;
+       int err;
 
        /* C-series touchpads added the recalibrate command */
        if (psmouse->model < HGPK_MODEL_C)
                return 0;
 
+       if (!autorecal) {
+               hgpk_dbg(psmouse, "recalibrations disabled, ignoring\n");
+               return 0;
+       }
+
+       hgpk_dbg(psmouse, "recalibrating touchpad..\n");
+
        /* we don't want to race with the irq handler, nor with resyncs */
        psmouse_set_state(psmouse, PSMOUSE_INITIALIZING);
 
        /* start by resetting the device */
-       psmouse_reset(psmouse);
-
-       /* send the recalibrate request */
-       if (ps2_command(ps2dev, NULL, 0xf5) ||
-           ps2_command(ps2dev, NULL, 0xf5) ||
-           ps2_command(ps2dev, NULL, 0xe6) ||
-           ps2_command(ps2dev, NULL, 0xf5)) {
-               return -1;
-       }
-
-       /* according to ALPS, 150mS is required for recalibration */
-       msleep(150);
+       err = hgpk_reset_device(psmouse, true);
+       if (err)
+               return err;
 
-       /* XXX: If a finger is down during this delay, recalibration will
+       /*
+        * XXX: If a finger is down during this delay, recalibration will
         * detect capacitance incorrectly.  This is a hardware bug, and
         * we don't have a good way to deal with it.  The 2s window stuff
         * (below) is our best option for now.
@@ -247,25 +673,35 @@ static int hgpk_force_recalibrate(struct psmouse *psmouse)
 
        psmouse_set_state(psmouse, PSMOUSE_ACTIVATED);
 
-       /* After we recalibrate, we shouldn't get any packets for 2s.  If
-        * we do, it's likely that someone's finger was on the touchpad.
-        * If someone's finger *was* on the touchpad, it's probably
-        * miscalibrated.  So, we should schedule another recalibration
+       if (tpdebug)
+               hgpk_dbg(psmouse, "touchpad reactivated\n");
+
+       /*
+        * If we get packets right away after recalibrating, it's likely
+        * that a finger was on the touchpad.  If so, it's probably
+        * miscalibrated, so we optionally schedule another.
         */
-       priv->recalib_window = jiffies +  msecs_to_jiffies(recal_guard_time);
+       if (recal_guard_time)
+               priv->recalib_window = jiffies +
+                       msecs_to_jiffies(recal_guard_time);
 
        return 0;
 }
 
 /*
- * This kills power to the touchpad; according to ALPS, current consumption
- * goes down to 50uA after running this.  To turn power back on, we drive
- * MS-DAT low.
+ * This puts the touchpad in a power saving mode; according to ALPS, current
+ * consumption goes down to 50uA after running this.  To turn power back on,
+ * we drive MS-DAT low.  Measuring with a 1mA resolution ammeter says that
+ * the current on the SUS_3.3V rail drops from 3mA or 4mA to 0 when we do this.
+ *
+ * We have no formal spec that details this operation -- the low-power
+ * sequence came from a long-lost email trail.
  */
-static int hgpk_toggle_power(struct psmouse *psmouse, int enable)
+static int hgpk_toggle_powersave(struct psmouse *psmouse, int enable)
 {
        struct ps2dev *ps2dev = &psmouse->ps2dev;
        int timeo;
+       int err;
 
        /* Added on D-series touchpads */
        if (psmouse->model < HGPK_MODEL_D)
@@ -279,24 +715,27 @@ static int hgpk_toggle_power(struct psmouse *psmouse, int enable)
                 * the controller.  Once we get an ACK back from it, it
                 * means we can continue with the touchpad re-init.  ALPS
                 * tells us that 1s should be long enough, so set that as
-                * the upper bound.
+                * the upper bound. (in practice, it takes about 3 loops.)
                 */
                for (timeo = 20; timeo > 0; timeo--) {
                        if (!ps2_sendbyte(&psmouse->ps2dev,
                                        PSMOUSE_CMD_DISABLE, 20))
                                break;
-                       msleep(50);
+                       msleep(25);
                }
 
-               psmouse_reset(psmouse);
+               err = hgpk_reset_device(psmouse, false);
+               if (err) {
+                       hgpk_err(psmouse, "Failed to reset device!\n");
+                       return err;
+               }
 
                /* should be all set, enable the touchpad */
                ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_ENABLE);
                psmouse_set_state(psmouse, PSMOUSE_ACTIVATED);
-
+               hgpk_dbg(psmouse, "Touchpad powered up.\n");
        } else {
                hgpk_dbg(psmouse, "Powering off touchpad.\n");
-               psmouse_set_state(psmouse, PSMOUSE_IGNORE);
 
                if (ps2_command(ps2dev, NULL, 0xec) ||
                    ps2_command(ps2dev, NULL, 0xec) ||
@@ -304,6 +743,8 @@ static int hgpk_toggle_power(struct psmouse *psmouse, int enable)
                        return -1;
                }
 
+               psmouse_set_state(psmouse, PSMOUSE_IGNORE);
+
                /* probably won't see an ACK, the touchpad will be off */
                ps2_sendbyte(&psmouse->ps2dev, 0xec, 20);
        }
@@ -319,17 +760,20 @@ static int hgpk_poll(struct psmouse *psmouse)
 
 static int hgpk_reconnect(struct psmouse *psmouse)
 {
-       /* During suspend/resume the ps2 rails remain powered.  We don't want
+       struct hgpk_data *priv = psmouse->private;
+
+       /*
+        * During suspend/resume the ps2 rails remain powered.  We don't want
         * to do a reset because it's flush data out of buffers; however,
-        * earlier prototypes (B1) had some brokenness that required a reset. */
+        * earlier prototypes (B1) had some brokenness that required a reset.
+        */
        if (olpc_board_at_least(olpc_board(0xb2)))
                if (psmouse->ps2dev.serio->dev.power.power_state.event !=
                                PM_EVENT_ON)
                        return 0;
 
-       psmouse_reset(psmouse);
-
-       return 0;
+       priv->powered = 1;
+       return hgpk_reset_device(psmouse, false);
 }
 
 static ssize_t hgpk_show_powered(struct psmouse *psmouse, void *data, char *buf)
@@ -355,7 +799,7 @@ static ssize_t hgpk_set_powered(struct psmouse *psmouse, void *data,
                 * hgpk_toggle_power will deal w/ state so
                 * we're not racing w/ irq
                 */
-               err = hgpk_toggle_power(psmouse, value);
+               err = hgpk_toggle_powersave(psmouse, value);
                if (!err)
                        priv->powered = value;
        }
@@ -366,6 +810,65 @@ static ssize_t hgpk_set_powered(struct psmouse *psmouse, void *data,
 __PSMOUSE_DEFINE_ATTR(powered, S_IWUSR | S_IRUGO, NULL,
                      hgpk_show_powered, hgpk_set_powered, false);
 
+static ssize_t attr_show_mode(struct psmouse *psmouse, void *data, char *buf)
+{
+       struct hgpk_data *priv = psmouse->private;
+
+       return sprintf(buf, "%s\n", hgpk_mode_names[priv->mode]);
+}
+
+static ssize_t attr_set_mode(struct psmouse *psmouse, void *data,
+                            const char *buf, size_t len)
+{
+       struct hgpk_data *priv = psmouse->private;
+       enum hgpk_mode old_mode = priv->mode;
+       enum hgpk_mode new_mode = hgpk_mode_from_name(buf, len);
+       struct input_dev *old_dev = psmouse->dev;
+       struct input_dev *new_dev;
+       int err;
+
+       if (new_mode == HGPK_MODE_INVALID)
+               return -EINVAL;
+
+       if (old_mode == new_mode)
+               return len;
+
+       new_dev = input_allocate_device();
+       if (!new_dev)
+               return -ENOMEM;
+
+       psmouse_set_state(psmouse, PSMOUSE_INITIALIZING);
+
+       /* Switch device into the new mode */
+       priv->mode = new_mode;
+       err = hgpk_reset_device(psmouse, false);
+       if (err)
+               goto err_try_restore;
+
+       hgpk_setup_input_device(new_dev, old_dev, new_mode);
+
+       psmouse_set_state(psmouse, PSMOUSE_CMD_MODE);
+
+       err = input_register_device(new_dev);
+       if (err)
+               goto err_try_restore;
+
+       psmouse->dev = new_dev;
+       input_unregister_device(old_dev);
+
+       return len;
+
+err_try_restore:
+       input_free_device(new_dev);
+       priv->mode = old_mode;
+       hgpk_reset_device(psmouse, false);
+
+       return err;
+}
+
+PSMOUSE_DEFINE_ATTR(hgpk_mode, S_IWUSR | S_IRUGO, NULL,
+                   attr_show_mode, attr_set_mode);
+
 static ssize_t hgpk_trigger_recal_show(struct psmouse *psmouse,
                void *data, char *buf)
 {
@@ -401,6 +904,8 @@ static void hgpk_disconnect(struct psmouse *psmouse)
 
        device_remove_file(&psmouse->ps2dev.serio->dev,
                           &psmouse_attr_powered.dattr);
+       device_remove_file(&psmouse->ps2dev.serio->dev,
+                          &psmouse_attr_hgpk_mode.dattr);
 
        if (psmouse->model >= HGPK_MODEL_C)
                device_remove_file(&psmouse->ps2dev.serio->dev,
@@ -416,14 +921,13 @@ static void hgpk_recalib_work(struct work_struct *work)
        struct hgpk_data *priv = container_of(w, struct hgpk_data, recalib_wq);
        struct psmouse *psmouse = priv->psmouse;
 
-       hgpk_dbg(psmouse, "recalibrating touchpad..\n");
-
        if (hgpk_force_recalibrate(psmouse))
                hgpk_err(psmouse, "recalibration failed!\n");
 }
 
 static int hgpk_register(struct psmouse *psmouse)
 {
+       struct hgpk_data *priv = psmouse->private;
        int err;
 
        /* register handlers */
@@ -431,13 +935,14 @@ static int hgpk_register(struct psmouse *psmouse)
        psmouse->poll = hgpk_poll;
        psmouse->disconnect = hgpk_disconnect;
        psmouse->reconnect = hgpk_reconnect;
-       psmouse->pktsize = 3;
 
        /* Disable the idle resync. */
        psmouse->resync_time = 0;
        /* Reset after a lot of bad bytes. */
        psmouse->resetafter = 1024;
 
+       hgpk_setup_input_device(psmouse->dev, NULL, priv->mode);
+
        err = device_create_file(&psmouse->ps2dev.serio->dev,
                                 &psmouse_attr_powered.dattr);
        if (err) {
@@ -445,6 +950,13 @@ static int hgpk_register(struct psmouse *psmouse)
                return err;
        }
 
+       err = device_create_file(&psmouse->ps2dev.serio->dev,
+                                &psmouse_attr_hgpk_mode.dattr);
+       if (err) {
+               hgpk_err(psmouse, "Failed creating 'hgpk_mode' sysfs node\n");
+               goto err_remove_powered;
+       }
+
        /* C-series touchpads added the recalibrate command */
        if (psmouse->model >= HGPK_MODEL_C) {
                err = device_create_file(&psmouse->ps2dev.serio->dev,
@@ -452,30 +964,40 @@ static int hgpk_register(struct psmouse *psmouse)
                if (err) {
                        hgpk_err(psmouse,
                                "Failed creating 'recalibrate' sysfs node\n");
-                       device_remove_file(&psmouse->ps2dev.serio->dev,
-                                       &psmouse_attr_powered.dattr);
-                       return err;
+                       goto err_remove_mode;
                }
        }
 
        return 0;
+
+err_remove_mode:
+       device_remove_file(&psmouse->ps2dev.serio->dev,
+                          &psmouse_attr_hgpk_mode.dattr);
+err_remove_powered:
+       device_remove_file(&psmouse->ps2dev.serio->dev,
+                          &psmouse_attr_powered.dattr);
+       return err;
 }
 
 int hgpk_init(struct psmouse *psmouse)
 {
        struct hgpk_data *priv;
-       int err = -ENOMEM;
+       int err;
 
        priv = kzalloc(sizeof(struct hgpk_data), GFP_KERNEL);
-       if (!priv)
+       if (!priv) {
+               err = -ENOMEM;
                goto alloc_fail;
+       }
 
        psmouse->private = priv;
+
        priv->psmouse = psmouse;
        priv->powered = true;
+       priv->mode = hgpk_default_mode;
        INIT_DELAYED_WORK(&priv->recalib_wq, hgpk_recalib_work);
 
-       err = psmouse_reset(psmouse);
+       err = hgpk_reset_device(psmouse, false);
        if (err)
                goto init_fail;
 
@@ -531,3 +1053,14 @@ int hgpk_detect(struct psmouse *psmouse, bool set_properties)
 
        return 0;
 }
+
+void hgpk_module_init(void)
+{
+       hgpk_default_mode = hgpk_mode_from_name(hgpk_mode_name,
+                                               strlen(hgpk_mode_name));
+       if (hgpk_default_mode == HGPK_MODE_INVALID) {
+               hgpk_default_mode = HGPK_MODE_MOUSE;
+               strlcpy(hgpk_mode_name, hgpk_mode_names[HGPK_MODE_MOUSE],
+                       sizeof(hgpk_mode_name));
+       }
+}
index d61cfd3..311c0e8 100644 (file)
@@ -5,6 +5,9 @@
 #ifndef _HGPK_H
 #define _HGPK_H
 
+#define HGPK_GS                0xff       /* The GlideSensor */
+#define HGPK_PT                0xcf       /* The PenTablet */
+
 enum hgpk_model_t {
        HGPK_MODEL_PREA = 0x0a, /* pre-B1s */
        HGPK_MODEL_A = 0x14,    /* found on B1s, PT disabled in hardware */
@@ -13,12 +16,34 @@ enum hgpk_model_t {
        HGPK_MODEL_D = 0x50,    /* C1, mass production */
 };
 
+enum hgpk_spew_flag {
+       NO_SPEW,
+       MAYBE_SPEWING,
+       SPEW_DETECTED,
+       RECALIBRATING,
+};
+
+#define SPEW_WATCH_COUNT 42  /* at 12ms/packet, this is 1/2 second */
+
+enum hgpk_mode {
+       HGPK_MODE_MOUSE,
+       HGPK_MODE_GLIDESENSOR,
+       HGPK_MODE_PENTABLET,
+       HGPK_MODE_INVALID
+};
+
 struct hgpk_data {
        struct psmouse *psmouse;
+       enum hgpk_mode mode;
        bool powered;
-       int count, x_tally, y_tally;    /* hardware workaround stuff */
+       enum hgpk_spew_flag spew_flag;
+       int spew_count, x_tally, y_tally;       /* spew detection */
        unsigned long recalib_window;
        struct delayed_work recalib_wq;
+       int abs_x, abs_y;
+       int dupe_count;
+       int xbigj, ybigj, xlast, ylast; /* jumpiness detection */
+       int xsaw_secondary, ysaw_secondary; /* jumpiness detection */
 };
 
 #define hgpk_dbg(psmouse, format, arg...)              \
@@ -33,9 +58,13 @@ struct hgpk_data {
        dev_notice(&(psmouse)->ps2dev.serio->dev, format, ## arg)
 
 #ifdef CONFIG_MOUSE_PS2_OLPC
+void hgpk_module_init(void);
 int hgpk_detect(struct psmouse *psmouse, bool set_properties);
 int hgpk_init(struct psmouse *psmouse);
 #else
+static inline void hgpk_module_init(void)
+{
+}
 static inline int hgpk_detect(struct psmouse *psmouse, bool set_properties)
 {
        return -ENODEV;
index cd9d0c9..3f74bae 100644 (file)
@@ -1711,6 +1711,7 @@ static int __init psmouse_init(void)
 
        lifebook_module_init();
        synaptics_module_init();
+       hgpk_module_init();
 
        kpsmoused_wq = create_singlethread_workqueue("kpsmoused");
        if (!kpsmoused_wq) {
index 720729a..da392c2 100644 (file)
@@ -824,15 +824,45 @@ static const struct dmi_system_id __initconst toshiba_dmi_table[] = {
 #endif
 };
 
+static bool broken_olpc_ec;
+
+static const struct dmi_system_id __initconst olpc_dmi_table[] = {
+#if defined(CONFIG_DMI) && defined(CONFIG_OLPC)
+       {
+               /* OLPC XO-1 or XO-1.5 */
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "OLPC"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "XO"),
+               },
+       },
+       { }
+#endif
+};
+
 void __init synaptics_module_init(void)
 {
        impaired_toshiba_kbc = dmi_check_system(toshiba_dmi_table);
+       broken_olpc_ec = dmi_check_system(olpc_dmi_table);
 }
 
 int synaptics_init(struct psmouse *psmouse)
 {
        struct synaptics_data *priv;
 
+       /*
+        * The OLPC XO has issues with Synaptics' absolute mode; similarly to
+        * the HGPK, it quickly degrades and the hardware becomes jumpy and
+        * overly sensitive.  Not only that, but the constant packet spew
+        * (even at a lowered 40pps rate) overloads the EC such that key
+        * presses on the keyboard are missed.  Given all of that, don't
+        * even attempt to use Synaptics mode.  Relative mode seems to work
+        * just fine.
+        */
+       if (broken_olpc_ec) {
+               printk(KERN_INFO "synaptics: OLPC XO detected, not enabling Synaptics protocol.\n");
+               return -ENODEV;
+       }
+
        psmouse->private = priv = kzalloc(sizeof(struct synaptics_data), GFP_KERNEL);
        if (!priv)
                return -ENOMEM;
@@ -887,8 +917,8 @@ int synaptics_init(struct psmouse *psmouse)
 
        /*
         * Toshiba's KBC seems to have trouble handling data from
-        * Synaptics as full rate, switch to lower rate which is roughly
-        * thye same as rate of standard PS/2 mouse.
+        * Synaptics at full rate.  Switch to a lower rate (roughly
+        * the same rate as a standard PS/2 mouse).
         */
        if (psmouse->rate >= 80 && impaired_toshiba_kbc) {
                printk(KERN_INFO "synaptics: Toshiba %s detected, limiting rate to 40pps.\n",
index 2a00ddf..7630273 100644 (file)
@@ -9,6 +9,8 @@
  * the Free Software Foundation.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #define MOUSEDEV_MINOR_BASE    32
 #define MOUSEDEV_MINORS                32
 #define MOUSEDEV_MIX           31
@@ -977,7 +979,7 @@ static int mousedev_connect(struct input_handler *handler,
                        break;
 
        if (minor == MOUSEDEV_MINORS) {
-               printk(KERN_ERR "mousedev: no more free mousedev devices\n");
+               pr_err("no more free mousedev devices\n");
                return -ENFILE;
        }
 
@@ -1087,13 +1089,13 @@ static int __init mousedev_init(void)
 #ifdef CONFIG_INPUT_MOUSEDEV_PSAUX
        error = misc_register(&psaux_mouse);
        if (error)
-               printk(KERN_WARNING "mice: could not register psaux device, "
-                       "error: %d\n", error);
+               pr_warning("could not register psaux device, error: %d\n",
+                          error);
        else
                psaux_registered = 1;
 #endif
 
-       printk(KERN_INFO "mice: PS/2 mouse device common for all mice\n");
+       pr_info("PS/2 mouse device common for all mice\n");
 
        return 0;
 }
index 8f1770e..ebe9553 100644 (file)
@@ -172,6 +172,5 @@ static void __exit ams_delta_serio_exit(void)
        free_irq(OMAP_GPIO_IRQ(AMS_DELTA_GPIO_PIN_KEYBRD_CLK), 0);
        gpio_free(AMS_DELTA_GPIO_PIN_KEYBRD_CLK);
        gpio_free(AMS_DELTA_GPIO_PIN_KEYBRD_DATA);
-       kfree(ams_delta_serio);
 }
 module_exit(ams_delta_serio_exit);
index 4a30846..448c772 100644 (file)
@@ -191,6 +191,9 @@ static int __devinit ct82c710_probe(struct platform_device *dev)
 
        serio_register_port(ct82c710_port);
 
+       printk(KERN_INFO "serio: C&T 82c710 mouse port at %#llx irq %d\n",
+               (unsigned long long)CT82C710_DATA, CT82C710_IRQ);
+
        return 0;
 }
 
@@ -237,11 +240,6 @@ static int __init ct82c710_init(void)
        if (error)
                goto err_free_device;
 
-       serio_register_port(ct82c710_port);
-
-       printk(KERN_INFO "serio: C&T 82c710 mouse port at %#llx irq %d\n",
-               (unsigned long long)CT82C710_DATA, CT82C710_IRQ);
-
        return 0;
 
  err_free_device:
index e5624d8..bfd3865 100644 (file)
@@ -932,6 +932,11 @@ int hil_mlc_register(hil_mlc *mlc)
                hil_mlc_copy_di_scratch(mlc, i);
                mlc_serio = kzalloc(sizeof(*mlc_serio), GFP_KERNEL);
                mlc->serio[i] = mlc_serio;
+               if (!mlc->serio[i]) {
+                       for (; i >= 0; i--)
+                               kfree(mlc->serio[i]);
+                       return -ENOMEM;
+               }
                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;
index 7d2b820..d50f067 100644 (file)
@@ -305,6 +305,7 @@ static void hp_sdc_mlc_out(hil_mlc *mlc)
 static int __init hp_sdc_mlc_init(void)
 {
        hil_mlc *mlc = &hp_sdc_mlc;
+       int err;
 
 #ifdef __mc68000__
        if (!MACH_IS_HP300)
@@ -323,22 +324,21 @@ static int __init hp_sdc_mlc_init(void)
        mlc->out = &hp_sdc_mlc_out;
        mlc->priv = &hp_sdc_mlc_priv;
 
-       if (hil_mlc_register(mlc)) {
+       err = hil_mlc_register(mlc);
+       if (err) {
                printk(KERN_WARNING PREFIX "Failed to register MLC structure with hil_mlc\n");
-               goto err0;
+               return err;
        }
 
        if (hp_sdc_request_hil_irq(&hp_sdc_mlc_isr)) {
                printk(KERN_WARNING PREFIX "Request for raw HIL ISR hook denied\n");
-               goto err1;
+               if (hil_mlc_unregister(mlc))
+                       printk(KERN_ERR PREFIX "Failed to unregister MLC structure with hil_mlc.\n"
+                               "This is bad.  Could cause an oops.\n");
+               return -EBUSY;
        }
+
        return 0;
- err1:
-       if (hil_mlc_unregister(mlc))
-               printk(KERN_ERR PREFIX "Failed to unregister MLC structure with hil_mlc.\n"
-                       "This is bad.  Could cause an oops.\n");
- err0:
-       return -EBUSY;
 }
 
 static void __exit hp_sdc_mlc_exit(void)
index ed7ad74..5ae0fc4 100644 (file)
@@ -351,6 +351,17 @@ static const struct dmi_system_id __initconst i8042_dmi_nomux_table[] = {
                },
        },
        {
+               /*
+                * Most (all?) VAIOs do not have external PS/2 ports nor
+                * they implement active multiplexing properly, and
+                * MUX discovery usually messes up keyboard/touchpad.
+                */
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
+                       DMI_MATCH(DMI_BOARD_NAME, "VAIO"),
+               },
+       },
+       {
                /* Amoi M636/A737 */
                .matches = {
                        DMI_MATCH(DMI_SYS_VENDOR, "Amoi Electronics CO.,LTD."),
@@ -542,6 +553,13 @@ static const struct dmi_system_id __initconst i8042_dmi_laptop_table[] = {
  */
 static const struct dmi_system_id __initconst i8042_dmi_dritek_table[] = {
        {
+               /* Acer Aspire 5100 */
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5100"),
+               },
+       },
+       {
                /* Acer Aspire 5610 */
                .matches = {
                        DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
@@ -741,7 +759,7 @@ static int __init i8042_pnp_init(void)
 #endif
 
        if (i8042_nopnp) {
-               printk(KERN_INFO "i8042: PNP detection disabled\n");
+               pr_info("PNP detection disabled\n");
                return 0;
        }
 
@@ -758,7 +776,7 @@ static int __init i8042_pnp_init(void)
 #if defined(__ia64__)
                return -ENODEV;
 #else
-               printk(KERN_INFO "PNP: No PS/2 controller found. Probing ports directly.\n");
+               pr_info("PNP: No PS/2 controller found. Probing ports directly.\n");
                return 0;
 #endif
        }
@@ -770,7 +788,7 @@ static int __init i8042_pnp_init(void)
                snprintf(aux_irq_str, sizeof(aux_irq_str),
                        "%d", i8042_pnp_aux_irq);
 
-       printk(KERN_INFO "PNP: PS/2 Controller [%s%s%s] at %#x,%#x irq %s%s%s\n",
+       pr_info("PNP: PS/2 Controller [%s%s%s] at %#x,%#x irq %s%s%s\n",
                i8042_pnp_kbd_name, (i8042_pnp_kbd_devices && i8042_pnp_aux_devices) ? "," : "",
                i8042_pnp_aux_name,
                i8042_pnp_data_reg, i8042_pnp_command_reg,
@@ -787,9 +805,7 @@ static int __init i8042_pnp_init(void)
        if (((i8042_pnp_data_reg & ~0xf) == (i8042_data_reg & ~0xf) &&
              i8042_pnp_data_reg != i8042_data_reg) ||
            !i8042_pnp_data_reg) {
-               printk(KERN_WARNING
-                       "PNP: PS/2 controller has invalid data port %#x; "
-                       "using default %#x\n",
+               pr_warn("PNP: PS/2 controller has invalid data port %#x; using default %#x\n",
                        i8042_pnp_data_reg, i8042_data_reg);
                i8042_pnp_data_reg = i8042_data_reg;
                pnp_data_busted = true;
@@ -798,33 +814,27 @@ static int __init i8042_pnp_init(void)
        if (((i8042_pnp_command_reg & ~0xf) == (i8042_command_reg & ~0xf) &&
              i8042_pnp_command_reg != i8042_command_reg) ||
            !i8042_pnp_command_reg) {
-               printk(KERN_WARNING
-                       "PNP: PS/2 controller has invalid command port %#x; "
-                       "using default %#x\n",
+               pr_warn("PNP: PS/2 controller has invalid command port %#x; using default %#x\n",
                        i8042_pnp_command_reg, i8042_command_reg);
                i8042_pnp_command_reg = i8042_command_reg;
                pnp_data_busted = true;
        }
 
        if (!i8042_nokbd && !i8042_pnp_kbd_irq) {
-               printk(KERN_WARNING
-                       "PNP: PS/2 controller doesn't have KBD irq; "
-                       "using default %d\n", i8042_kbd_irq);
+               pr_warn("PNP: PS/2 controller doesn't have KBD irq; using default %d\n",
+                       i8042_kbd_irq);
                i8042_pnp_kbd_irq = i8042_kbd_irq;
                pnp_data_busted = true;
        }
 
        if (!i8042_noaux && !i8042_pnp_aux_irq) {
                if (!pnp_data_busted && i8042_pnp_kbd_irq) {
-                       printk(KERN_WARNING
-                               "PNP: PS/2 appears to have AUX port disabled, "
-                               "if this is incorrect please boot with "
-                               "i8042.nopnp\n");
+                       pr_warn("PNP: PS/2 appears to have AUX port disabled, "
+                               "if this is incorrect please boot with i8042.nopnp\n");
                        i8042_noaux = true;
                } else {
-                       printk(KERN_WARNING
-                               "PNP: PS/2 controller doesn't have AUX irq; "
-                               "using default %d\n", i8042_aux_irq);
+                       pr_warn("PNP: PS/2 controller doesn't have AUX irq; using default %d\n",
+                               i8042_aux_irq);
                        i8042_pnp_aux_irq = i8042_aux_irq;
                }
        }
index 18db5a8..c04ff00 100644 (file)
@@ -10,6 +10,8 @@
  * the Free Software Foundation.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/types.h>
 #include <linux/delay.h>
 #include <linux/module.h>
@@ -225,8 +227,8 @@ static int i8042_flush(void)
                udelay(50);
                data = i8042_read_data();
                i++;
-               dbg("%02x <- i8042 (flush, %s)", data,
-                       str & I8042_STR_AUXDATA ? "aux" : "kbd");
+               dbg("%02x <- i8042 (flush, %s)\n",
+                   data, str & I8042_STR_AUXDATA ? "aux" : "kbd");
        }
 
        spin_unlock_irqrestore(&i8042_lock, flags);
@@ -253,32 +255,32 @@ static int __i8042_command(unsigned char *param, int command)
        if (error)
                return error;
 
-       dbg("%02x -> i8042 (command)", command & 0xff);
+       dbg("%02x -> i8042 (command)\n", command & 0xff);
        i8042_write_command(command & 0xff);
 
        for (i = 0; i < ((command >> 12) & 0xf); i++) {
                error = i8042_wait_write();
                if (error)
                        return error;
-               dbg("%02x -> i8042 (parameter)", param[i]);
+               dbg("%02x -> i8042 (parameter)\n", param[i]);
                i8042_write_data(param[i]);
        }
 
        for (i = 0; i < ((command >> 8) & 0xf); i++) {
                error = i8042_wait_read();
                if (error) {
-                       dbg("     -- i8042 (timeout)");
+                       dbg("     -- i8042 (timeout)\n");
                        return error;
                }
 
                if (command == I8042_CMD_AUX_LOOP &&
                    !(i8042_read_status() & I8042_STR_AUXDATA)) {
-                       dbg("     -- i8042 (auxerr)");
+                       dbg("     -- i8042 (auxerr)\n");
                        return -1;
                }
 
                param[i] = i8042_read_data();
-               dbg("%02x <- i8042 (return)", param[i]);
+               dbg("%02x <- i8042 (return)\n", param[i]);
        }
 
        return 0;
@@ -309,7 +311,7 @@ static int i8042_kbd_write(struct serio *port, unsigned char c)
        spin_lock_irqsave(&i8042_lock, flags);
 
        if (!(retval = i8042_wait_write())) {
-               dbg("%02x -> i8042 (kbd-data)", c);
+               dbg("%02x -> i8042 (kbd-data)\n", c);
                i8042_write_data(c);
        }
 
@@ -355,17 +357,14 @@ static void i8042_port_close(struct serio *serio)
 
        i8042_ctr &= ~irq_bit;
        if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR))
-               printk(KERN_WARNING
-                       "i8042.c: Can't write CTR while closing %s port.\n",
-                       port_name);
+               pr_warn("Can't write CTR while closing %s port\n", port_name);
 
        udelay(50);
 
        i8042_ctr &= ~disable_bit;
        i8042_ctr |= irq_bit;
        if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR))
-               printk(KERN_ERR "i8042.c: Can't reactivate %s port.\n",
-                       port_name);
+               pr_err("Can't reactivate %s port\n", port_name);
 
        /*
         * See if there is any data appeared while we were messing with
@@ -456,7 +455,8 @@ static irqreturn_t i8042_interrupt(int irq, void *dev_id)
        str = i8042_read_status();
        if (unlikely(~str & I8042_STR_OBF)) {
                spin_unlock_irqrestore(&i8042_lock, flags);
-               if (irq) dbg("Interrupt %d, without any data", irq);
+               if (irq)
+                       dbg("Interrupt %d, without any data\n", irq);
                ret = 0;
                goto out;
        }
@@ -469,7 +469,8 @@ static irqreturn_t i8042_interrupt(int irq, void *dev_id)
 
                dfl = 0;
                if (str & I8042_STR_MUXERR) {
-                       dbg("MUX error, status is %02x, data is %02x", str, data);
+                       dbg("MUX error, status is %02x, data is %02x\n",
+                           str, data);
 /*
  * When MUXERR condition is signalled the data register can only contain
  * 0xfd, 0xfe or 0xff if implementation follows the spec. Unfortunately
@@ -512,7 +513,7 @@ static irqreturn_t i8042_interrupt(int irq, void *dev_id)
        port = &i8042_ports[port_no];
        serio = port->exists ? port->serio : NULL;
 
-       dbg("%02x <- i8042 (interrupt, %d, %d%s%s)",
+       dbg("%02x <- i8042 (interrupt, %d, %d%s%s)\n",
            data, port_no, irq,
            dfl & SERIO_PARITY ? ", bad parity" : "",
            dfl & SERIO_TIMEOUT ? ", timeout" : "");
@@ -540,7 +541,7 @@ static int i8042_enable_kbd_port(void)
        if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) {
                i8042_ctr &= ~I8042_CTR_KBDINT;
                i8042_ctr |= I8042_CTR_KBDDIS;
-               printk(KERN_ERR "i8042.c: Failed to enable KBD port.\n");
+               pr_err("Failed to enable KBD port\n");
                return -EIO;
        }
 
@@ -559,7 +560,7 @@ static int i8042_enable_aux_port(void)
        if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) {
                i8042_ctr &= ~I8042_CTR_AUXINT;
                i8042_ctr |= I8042_CTR_AUXDIS;
-               printk(KERN_ERR "i8042.c: Failed to enable AUX port.\n");
+               pr_err("Failed to enable AUX port\n");
                return -EIO;
        }
 
@@ -641,7 +642,7 @@ static int __init i8042_check_mux(void)
        if (i8042_set_mux_mode(true, &mux_version))
                return -1;
 
-       printk(KERN_INFO "i8042.c: Detected active multiplexing controller, rev %d.%d.\n",
+       pr_info("Detected active multiplexing controller, rev %d.%d\n",
                (mux_version >> 4) & 0xf, mux_version & 0xf);
 
 /*
@@ -651,7 +652,7 @@ static int __init i8042_check_mux(void)
        i8042_ctr &= ~I8042_CTR_AUXINT;
 
        if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) {
-               printk(KERN_ERR "i8042.c: Failed to disable AUX port, can't use MUX.\n");
+               pr_err("Failed to disable AUX port, can't use MUX\n");
                return -EIO;
        }
 
@@ -676,8 +677,8 @@ static irqreturn_t __init i8042_aux_test_irq(int irq, void *dev_id)
        str = i8042_read_status();
        if (str & I8042_STR_OBF) {
                data = i8042_read_data();
-               dbg("%02x <- i8042 (aux_test_irq, %s)",
-                       data, str & I8042_STR_AUXDATA ? "aux" : "kbd");
+               dbg("%02x <- i8042 (aux_test_irq, %s)\n",
+                   data, str & I8042_STR_AUXDATA ? "aux" : "kbd");
                if (i8042_irq_being_tested &&
                    data == 0xa5 && (str & I8042_STR_AUXDATA))
                        complete(&i8042_aux_irq_delivered);
@@ -770,8 +771,8 @@ static int __init i8042_check_aux(void)
  */
 
        if (i8042_toggle_aux(false)) {
-               printk(KERN_WARNING "Failed to disable AUX port, but continuing anyway... Is this a SiS?\n");
-               printk(KERN_WARNING "If AUX port is really absent please use the 'i8042.noaux' option.\n");
+               pr_warn("Failed to disable AUX port, but continuing anyway... Is this a SiS?\n");
+               pr_warn("If AUX port is really absent please use the 'i8042.noaux' option\n");
        }
 
        if (i8042_toggle_aux(true))
@@ -819,7 +820,7 @@ static int __init i8042_check_aux(void)
  * AUX IRQ was never delivered so we need to flush the controller to
  * get rid of the byte we put there; otherwise keyboard may not work.
  */
-               dbg("     -- i8042 (aux irq test timeout)");
+               dbg("     -- i8042 (aux irq test timeout)\n");
                i8042_flush();
                retval = -1;
        }
@@ -845,7 +846,7 @@ static int __init i8042_check_aux(void)
 static int i8042_controller_check(void)
 {
        if (i8042_flush() == I8042_BUFFER_SIZE) {
-               printk(KERN_ERR "i8042.c: No controller found.\n");
+               pr_err("No controller found\n");
                return -ENODEV;
        }
 
@@ -864,15 +865,15 @@ static int i8042_controller_selftest(void)
        do {
 
                if (i8042_command(&param, I8042_CMD_CTL_TEST)) {
-                       printk(KERN_ERR "i8042.c: i8042 controller self test timeout.\n");
+                       pr_err("i8042 controller self test timeout\n");
                        return -ENODEV;
                }
 
                if (param == I8042_RET_CTL_TEST)
                        return 0;
 
-               printk(KERN_ERR "i8042.c: i8042 controller selftest failed. (%#x != %#x)\n",
-                       param, I8042_RET_CTL_TEST);
+               pr_err("i8042 controller selftest failed. (%#x != %#x)\n",
+                      param, I8042_RET_CTL_TEST);
                msleep(50);
        } while (i++ < 5);
 
@@ -883,8 +884,7 @@ static int i8042_controller_selftest(void)
         * and user will still get a working keyboard. This is especially
         * important on netbooks. On other arches we trust hardware more.
         */
-       printk(KERN_INFO
-               "i8042: giving up on controller selftest, continuing anyway...\n");
+       pr_info("giving up on controller selftest, continuing anyway...\n");
        return 0;
 #else
        return -EIO;
@@ -909,8 +909,7 @@ static int i8042_controller_init(void)
 
        do {
                if (n >= 10) {
-                       printk(KERN_ERR
-                               "i8042.c: Unable to get stable CTR read.\n");
+                       pr_err("Unable to get stable CTR read\n");
                        return -EIO;
                }
 
@@ -918,8 +917,7 @@ static int i8042_controller_init(void)
                        udelay(50);
 
                if (i8042_command(&ctr[n++ % 2], I8042_CMD_CTL_RCTR)) {
-                       printk(KERN_ERR
-                               "i8042.c: Can't read CTR while initializing i8042.\n");
+                       pr_err("Can't read CTR while initializing i8042\n");
                        return -EIO;
                }
 
@@ -943,7 +941,7 @@ static int i8042_controller_init(void)
                if (i8042_unlock)
                        i8042_ctr |= I8042_CTR_IGNKEYLOCK;
                else
-                       printk(KERN_WARNING "i8042.c: Warning: Keylock active.\n");
+                       pr_warn("Warning: Keylock active\n");
        }
        spin_unlock_irqrestore(&i8042_lock, flags);
 
@@ -970,7 +968,7 @@ static int i8042_controller_init(void)
  */
 
        if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) {
-               printk(KERN_ERR "i8042.c: Can't write CTR while initializing i8042.\n");
+               pr_err("Can't write CTR while initializing i8042\n");
                return -EIO;
        }
 
@@ -1000,7 +998,7 @@ static void i8042_controller_reset(void)
        i8042_ctr &= ~(I8042_CTR_KBDINT | I8042_CTR_AUXINT);
 
        if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR))
-               printk(KERN_WARNING "i8042.c: Can't write CTR while resetting.\n");
+               pr_warn("Can't write CTR while resetting\n");
 
 /*
  * Disable MUX mode if present.
@@ -1021,7 +1019,7 @@ static void i8042_controller_reset(void)
  */
 
        if (i8042_command(&i8042_initial_ctr, I8042_CMD_CTL_WCTR))
-               printk(KERN_WARNING "i8042.c: Can't restore CTR.\n");
+               pr_warn("Can't restore CTR\n");
 }
 
 
@@ -1045,14 +1043,14 @@ static long i8042_panic_blink(int state)
        led = (state) ? 0x01 | 0x04 : 0;
        while (i8042_read_status() & I8042_STR_IBF)
                DELAY;
-       dbg("%02x -> i8042 (panic blink)", 0xed);
+       dbg("%02x -> i8042 (panic blink)\n", 0xed);
        i8042_suppress_kbd_ack = 2;
        i8042_write_data(0xed); /* set leds */
        DELAY;
        while (i8042_read_status() & I8042_STR_IBF)
                DELAY;
        DELAY;
-       dbg("%02x -> i8042 (panic blink)", led);
+       dbg("%02x -> i8042 (panic blink)\n", led);
        i8042_write_data(led);
        DELAY;
        return delay;
@@ -1068,9 +1066,7 @@ static void i8042_dritek_enable(void)
 
        error = i8042_command(&param, 0x1059);
        if (error)
-               printk(KERN_WARNING
-                       "Failed to enable DRITEK extension: %d\n",
-                       error);
+               pr_warn("Failed to enable DRITEK extension: %d\n", error);
 }
 #endif
 
@@ -1105,10 +1101,10 @@ static int i8042_controller_resume(bool force_reset)
        i8042_ctr |= I8042_CTR_AUXDIS | I8042_CTR_KBDDIS;
        i8042_ctr &= ~(I8042_CTR_AUXINT | I8042_CTR_KBDINT);
        if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) {
-               printk(KERN_WARNING "i8042: Can't write CTR to resume, retrying...\n");
+               pr_warn("Can't write CTR to resume, retrying...\n");
                msleep(50);
                if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) {
-                       printk(KERN_ERR "i8042: CTR write retry failed\n");
+                       pr_err("CTR write retry failed\n");
                        return -EIO;
                }
        }
@@ -1121,9 +1117,7 @@ static int i8042_controller_resume(bool force_reset)
 
        if (i8042_mux_present) {
                if (i8042_set_mux_mode(true, NULL) || i8042_enable_mux_ports())
-                       printk(KERN_WARNING
-                               "i8042: failed to resume active multiplexor, "
-                               "mouse won't work.\n");
+                       pr_warn("failed to resume active multiplexor, mouse won't work\n");
        } else if (i8042_ports[I8042_AUX_PORT_NO].serio)
                i8042_enable_aux_port();
 
index cbc1beb..ac1d759 100644 (file)
 #ifdef DEBUG
 static unsigned long i8042_start_time;
 #define dbg_init() do { i8042_start_time = jiffies; } while (0)
-#define dbg(format, arg...)                                                    \
-       do {                                                                    \
+#define dbg(format, arg...)                                                    \
+       do {                                                                    \
                if (i8042_debug)                                                \
-                       printk(KERN_DEBUG __FILE__ ": " format " [%d]\n" ,      \
-                               ## arg, (int) (jiffies - i8042_start_time));    \
+                       printk(KERN_DEBUG KBUILD_MODNAME ": [%d] " format,      \
+                              (int) (jiffies - i8042_start_time), ##arg);      \
        } while (0)
 #else
 #define dbg_init() do { } while (0)
-#define dbg(format, arg...) do {} while (0)
+#define dbg(format, arg...)                                                    \
+       do {                                                                    \
+               if (0)                                                          \
+                       printk(KERN_DEBUG pr_fmt(format), ##arg);               \
+       } while (0)
 #endif
 
 #endif /* _I8042_H */
index 6bce22e..15aa81c 100644 (file)
@@ -207,7 +207,7 @@ static int ps2mult_connect(struct serio *serio, struct serio_driver *drv)
 err_out:
        while (--i >= 0)
                kfree(psm->ports[i].serio);
-       kfree(serio);
+       kfree(psm);
        return error;
 }
 
index 405bf21..db5b0bc 100644 (file)
 #include <linux/module.h>
 #include <linux/serio.h>
 #include <linux/errno.h>
-#include <linux/wait.h>
 #include <linux/sched.h>
 #include <linux/slab.h>
-#include <linux/kthread.h>
+#include <linux/workqueue.h>
 #include <linux/mutex.h>
 
 MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
@@ -44,7 +43,7 @@ MODULE_LICENSE("GPL");
 
 /*
  * serio_mutex protects entire serio subsystem and is taken every time
- * serio port or driver registrered or unregistered.
+ * serio port or driver registered or unregistered.
  */
 static DEFINE_MUTEX(serio_mutex);
 
@@ -165,58 +164,22 @@ struct serio_event {
 
 static DEFINE_SPINLOCK(serio_event_lock);      /* protects serio_event_list */
 static LIST_HEAD(serio_event_list);
-static DECLARE_WAIT_QUEUE_HEAD(serio_wait);
-static struct task_struct *serio_task;
 
-static int serio_queue_event(void *object, struct module *owner,
-                            enum serio_event_type event_type)
+static struct serio_event *serio_get_event(void)
 {
+       struct serio_event *event = NULL;
        unsigned long flags;
-       struct serio_event *event;
-       int retval = 0;
 
        spin_lock_irqsave(&serio_event_lock, flags);
 
-       /*
-        * Scan event list for the other events for the same serio port,
-        * starting with the most recent one. If event is the same we
-        * do not need add new one. If event is of different type we
-        * need to add this event and should not look further because
-        * we need to preseve sequence of distinct events.
-        */
-       list_for_each_entry_reverse(event, &serio_event_list, node) {
-               if (event->object == object) {
-                       if (event->type == event_type)
-                               goto out;
-                       break;
-               }
-       }
-
-       event = kmalloc(sizeof(struct serio_event), GFP_ATOMIC);
-       if (!event) {
-               pr_err("Not enough memory to queue event %d\n", event_type);
-               retval = -ENOMEM;
-               goto out;
-       }
-
-       if (!try_module_get(owner)) {
-               pr_warning("Can't get module reference, dropping event %d\n",
-                          event_type);
-               kfree(event);
-               retval = -EINVAL;
-               goto out;
+       if (!list_empty(&serio_event_list)) {
+               event = list_first_entry(&serio_event_list,
+                                        struct serio_event, node);
+               list_del_init(&event->node);
        }
 
-       event->type = event_type;
-       event->object = object;
-       event->owner = owner;
-
-       list_add_tail(&event->node, &serio_event_list);
-       wake_up(&serio_wait);
-
-out:
        spin_unlock_irqrestore(&serio_event_lock, flags);
-       return retval;
+       return event;
 }
 
 static void serio_free_event(struct serio_event *event)
@@ -250,25 +213,7 @@ static void serio_remove_duplicate_events(struct serio_event *event)
        spin_unlock_irqrestore(&serio_event_lock, flags);
 }
 
-
-static struct serio_event *serio_get_event(void)
-{
-       struct serio_event *event = NULL;
-       unsigned long flags;
-
-       spin_lock_irqsave(&serio_event_lock, flags);
-
-       if (!list_empty(&serio_event_list)) {
-               event = list_first_entry(&serio_event_list,
-                                        struct serio_event, node);
-               list_del_init(&event->node);
-       }
-
-       spin_unlock_irqrestore(&serio_event_lock, flags);
-       return event;
-}
-
-static void serio_handle_event(void)
+static void serio_handle_event(struct work_struct *work)
 {
        struct serio_event *event;
 
@@ -307,6 +252,59 @@ static void serio_handle_event(void)
        mutex_unlock(&serio_mutex);
 }
 
+static DECLARE_WORK(serio_event_work, serio_handle_event);
+
+static int serio_queue_event(void *object, struct module *owner,
+                            enum serio_event_type event_type)
+{
+       unsigned long flags;
+       struct serio_event *event;
+       int retval = 0;
+
+       spin_lock_irqsave(&serio_event_lock, flags);
+
+       /*
+        * Scan event list for the other events for the same serio port,
+        * starting with the most recent one. If event is the same we
+        * do not need add new one. If event is of different type we
+        * need to add this event and should not look further because
+        * we need to preseve sequence of distinct events.
+        */
+       list_for_each_entry_reverse(event, &serio_event_list, node) {
+               if (event->object == object) {
+                       if (event->type == event_type)
+                               goto out;
+                       break;
+               }
+       }
+
+       event = kmalloc(sizeof(struct serio_event), GFP_ATOMIC);
+       if (!event) {
+               pr_err("Not enough memory to queue event %d\n", event_type);
+               retval = -ENOMEM;
+               goto out;
+       }
+
+       if (!try_module_get(owner)) {
+               pr_warning("Can't get module reference, dropping event %d\n",
+                          event_type);
+               kfree(event);
+               retval = -EINVAL;
+               goto out;
+       }
+
+       event->type = event_type;
+       event->object = object;
+       event->owner = owner;
+
+       list_add_tail(&event->node, &serio_event_list);
+       schedule_work(&serio_event_work);
+
+out:
+       spin_unlock_irqrestore(&serio_event_lock, flags);
+       return retval;
+}
+
 /*
  * Remove all events that have been submitted for a given
  * object, be it serio port or driver.
@@ -356,18 +354,6 @@ static struct serio *serio_get_pending_child(struct serio *parent)
        return child;
 }
 
-static int serio_thread(void *nothing)
-{
-       do {
-               serio_handle_event();
-               wait_event_interruptible(serio_wait,
-                       kthread_should_stop() || !list_empty(&serio_event_list));
-       } while (!kthread_should_stop());
-
-       return 0;
-}
-
-
 /*
  * Serio port operations
  */
@@ -1040,21 +1026,18 @@ static int __init serio_init(void)
                return error;
        }
 
-       serio_task = kthread_run(serio_thread, NULL, "kseriod");
-       if (IS_ERR(serio_task)) {
-               bus_unregister(&serio_bus);
-               error = PTR_ERR(serio_task);
-               pr_err("Failed to start kseriod, error: %d\n", error);
-               return error;
-       }
-
        return 0;
 }
 
 static void __exit serio_exit(void)
 {
        bus_unregister(&serio_bus);
-       kthread_stop(serio_task);
+
+       /*
+        * There should not be any outstanding events but work may
+        * still be scheduled so simply cancel it.
+        */
+       cancel_work_sync(&serio_event_work);
 }
 
 subsys_initcall(serio_init);
index aea9a93..d94f7e9 100644 (file)
@@ -229,12 +229,13 @@ static int usb_acecad_probe(struct usb_interface *intf, const struct usb_device_
 
        err = input_register_device(acecad->input);
        if (err)
-               goto fail2;
+               goto fail3;
 
        usb_set_intfdata(intf, acecad);
 
        return 0;
 
+ fail3:        usb_free_urb(acecad->irq);
  fail2:        usb_free_coherent(dev, 8, acecad->data, acecad->data_dma);
  fail1: input_free_device(input_dev);
        kfree(acecad);
index 06ea8da..07ac77d 100644 (file)
@@ -659,17 +659,17 @@ config TOUCHSCREEN_PCAP
          To compile this driver as a module, choose M here: the
          module will be called pcap_ts.
 
-config TOUCHSCREEN_TPS6507X
-       tristate "TPS6507x based touchscreens"
+config TOUCHSCREEN_ST1232
+       tristate "Sitronix ST1232 touchscreen controllers"
        depends on I2C
        help
-         Say Y here if you have a TPS6507x based touchscreen
-         controller.
+         Say Y here if you want to support Sitronix ST1232
+         touchscreen controller.
 
          If unsure, say N.
 
          To compile this driver as a module, choose M here: the
-         module will be called tps6507x_ts.
+         module will be called st1232_ts.
 
 config TOUCHSCREEN_STMPE
        tristate "STMicroelectronics STMPE touchscreens"
@@ -681,4 +681,16 @@ config TOUCHSCREEN_STMPE
          To compile this driver as a module, choose M here: the
          module will be called stmpe-ts.
 
+config TOUCHSCREEN_TPS6507X
+       tristate "TPS6507x based touchscreens"
+       depends on I2C
+       help
+         Say Y here if you have a TPS6507x based touchscreen
+         controller.
+
+         If unsure, say N.
+
+         To compile this driver as a module, choose M here: the
+         module will be called tps6507x_ts.
+
 endif
index 7cc1b4f..718bcc8 100644 (file)
@@ -39,6 +39,7 @@ obj-$(CONFIG_TOUCHSCREEN_PCAP)                += pcap_ts.o
 obj-$(CONFIG_TOUCHSCREEN_PENMOUNT)     += penmount.o
 obj-$(CONFIG_TOUCHSCREEN_QT602240)     += qt602240_ts.o
 obj-$(CONFIG_TOUCHSCREEN_S3C2410)      += s3c2410_ts.o
+obj-$(CONFIG_TOUCHSCREEN_ST1232)       += st1232.o
 obj-$(CONFIG_TOUCHSCREEN_STMPE)                += stmpe-ts.o
 obj-$(CONFIG_TOUCHSCREEN_TNETV107X)    += tnetv107x-ts.o
 obj-$(CONFIG_TOUCHSCREEN_TOUCHIT213)   += touchit213.o
index 2ca9e5d..f7fa9ef 100644 (file)
@@ -365,7 +365,7 @@ static int bu21013_init_chip(struct bu21013_ts_data *data)
        }
 
        retval = i2c_smbus_write_byte_data(i2c, BU21013_TH_OFF_REG,
-                               BU21013_TH_OFF_4 || BU21013_TH_OFF_3);
+                               BU21013_TH_OFF_4 | BU21013_TH_OFF_3);
        if (retval < 0) {
                dev_err(&i2c->dev, "BU21013_TH_OFF reg write failed\n");
                return retval;
index 66b26ad..4dcb0e8 100644 (file)
@@ -969,7 +969,7 @@ static int qt602240_initialize(struct qt602240_data *data)
                return error;
 
        data->object_table = kcalloc(info->object_num,
-                                    sizeof(struct qt602240_data),
+                                    sizeof(struct qt602240_object),
                                     GFP_KERNEL);
        if (!data->object_table) {
                dev_err(&client->dev, "Failed to allocate memory\n");
@@ -1324,8 +1324,9 @@ static int __devexit qt602240_remove(struct i2c_client *client)
 }
 
 #ifdef CONFIG_PM
-static int qt602240_suspend(struct i2c_client *client, pm_message_t mesg)
+static int qt602240_suspend(struct device *dev)
 {
+       struct i2c_client *client = to_i2c_client(dev);
        struct qt602240_data *data = i2c_get_clientdata(client);
        struct input_dev *input_dev = data->input_dev;
 
@@ -1339,8 +1340,9 @@ static int qt602240_suspend(struct i2c_client *client, pm_message_t mesg)
        return 0;
 }
 
-static int qt602240_resume(struct i2c_client *client)
+static int qt602240_resume(struct device *dev)
 {
+       struct i2c_client *client = to_i2c_client(dev);
        struct qt602240_data *data = i2c_get_clientdata(client);
        struct input_dev *input_dev = data->input_dev;
 
@@ -1359,9 +1361,11 @@ static int qt602240_resume(struct i2c_client *client)
 
        return 0;
 }
-#else
-#define qt602240_suspend       NULL
-#define qt602240_resume                NULL
+
+static const struct dev_pm_ops qt602240_pm_ops = {
+       .suspend        = qt602240_suspend,
+       .resume         = qt602240_resume,
+};
 #endif
 
 static const struct i2c_device_id qt602240_id[] = {
@@ -1374,11 +1378,12 @@ static struct i2c_driver qt602240_driver = {
        .driver = {
                .name   = "qt602240_ts",
                .owner  = THIS_MODULE,
+#ifdef CONFIG_PM
+               .pm     = &qt602240_pm_ops,
+#endif
        },
        .probe          = qt602240_probe,
        .remove         = __devexit_p(qt602240_remove),
-       .suspend        = qt602240_suspend,
-       .resume         = qt602240_resume,
        .id_table       = qt602240_id,
 };
 
diff --git a/drivers/input/touchscreen/st1232.c b/drivers/input/touchscreen/st1232.c
new file mode 100644 (file)
index 0000000..4ab3713
--- /dev/null
@@ -0,0 +1,274 @@
+/*
+ * ST1232 Touchscreen Controller Driver
+ *
+ * Copyright (C) 2010 Renesas Solutions Corp.
+ *     Tony SIM <chinyeow.sim.xt@renesas.com>
+ *
+ * Using code from:
+ *  - android.git.kernel.org: projects/kernel/common.git: synaptics_i2c_rmi.c
+ *     Copyright (C) 2007 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+
+#define ST1232_TS_NAME "st1232-ts"
+
+#define MIN_X          0x00
+#define MIN_Y          0x00
+#define MAX_X          0x31f   /* (800 - 1) */
+#define MAX_Y          0x1df   /* (480 - 1) */
+#define MAX_AREA       0xff
+#define MAX_FINGERS    2
+
+struct st1232_ts_finger {
+       u16 x;
+       u16 y;
+       u8 t;
+       bool is_valid;
+};
+
+struct st1232_ts_data {
+       struct i2c_client *client;
+       struct input_dev *input_dev;
+       struct st1232_ts_finger finger[MAX_FINGERS];
+};
+
+static int st1232_ts_read_data(struct st1232_ts_data *ts)
+{
+       struct st1232_ts_finger *finger = ts->finger;
+       struct i2c_client *client = ts->client;
+       struct i2c_msg msg[2];
+       int error;
+       u8 start_reg;
+       u8 buf[10];
+
+       /* read touchscreen data from ST1232 */
+       msg[0].addr = client->addr;
+       msg[0].flags = 0;
+       msg[0].len = 1;
+       msg[0].buf = &start_reg;
+       start_reg = 0x10;
+
+       msg[1].addr = ts->client->addr;
+       msg[1].flags = I2C_M_RD;
+       msg[1].len = sizeof(buf);
+       msg[1].buf = buf;
+
+       error = i2c_transfer(client->adapter, msg, 2);
+       if (error < 0)
+               return error;
+
+       /* get "valid" bits */
+       finger[0].is_valid = buf[2] >> 7;
+       finger[1].is_valid = buf[5] >> 7;
+
+       /* get xy coordinate */
+       if (finger[0].is_valid) {
+               finger[0].x = ((buf[2] & 0x0070) << 4) | buf[3];
+               finger[0].y = ((buf[2] & 0x0007) << 8) | buf[4];
+               finger[0].t = buf[8];
+       }
+
+       if (finger[1].is_valid) {
+               finger[1].x = ((buf[5] & 0x0070) << 4) | buf[6];
+               finger[1].y = ((buf[5] & 0x0007) << 8) | buf[7];
+               finger[1].t = buf[9];
+       }
+
+       return 0;
+}
+
+static irqreturn_t st1232_ts_irq_handler(int irq, void *dev_id)
+{
+       struct st1232_ts_data *ts = dev_id;
+       struct st1232_ts_finger *finger = ts->finger;
+       struct input_dev *input_dev = ts->input_dev;
+       int count = 0;
+       int i, ret;
+
+       ret = st1232_ts_read_data(ts);
+       if (ret < 0)
+               goto end;
+
+       /* multi touch protocol */
+       for (i = 0; i < MAX_FINGERS; i++) {
+               if (!finger[i].is_valid)
+                       continue;
+
+               input_report_abs(input_dev, ABS_MT_TOUCH_MAJOR, finger[i].t);
+               input_report_abs(input_dev, ABS_MT_POSITION_X, finger[i].x);
+               input_report_abs(input_dev, ABS_MT_POSITION_Y, finger[i].y);
+               input_mt_sync(input_dev);
+               count++;
+       }
+
+       /* SYN_MT_REPORT only if no contact */
+       if (!count)
+               input_mt_sync(input_dev);
+
+       /* SYN_REPORT */
+       input_sync(input_dev);
+
+end:
+       return IRQ_HANDLED;
+}
+
+static int __devinit st1232_ts_probe(struct i2c_client *client,
+                                       const struct i2c_device_id *id)
+{
+       struct st1232_ts_data *ts;
+       struct input_dev *input_dev;
+       int error;
+
+       if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+               dev_err(&client->dev, "need I2C_FUNC_I2C\n");
+               return -EIO;
+       }
+
+       if (!client->irq) {
+               dev_err(&client->dev, "no IRQ?\n");
+               return -EINVAL;
+       }
+
+
+       ts = kzalloc(sizeof(struct st1232_ts_data), GFP_KERNEL);
+       input_dev = input_allocate_device();
+       if (!ts || !input_dev) {
+               error = -ENOMEM;
+               goto err_free_mem;
+       }
+
+       ts->client = client;
+       ts->input_dev = input_dev;
+
+       input_dev->name = "st1232-touchscreen";
+       input_dev->id.bustype = BUS_I2C;
+       input_dev->dev.parent = &client->dev;
+
+       __set_bit(EV_SYN, input_dev->evbit);
+       __set_bit(EV_KEY, input_dev->evbit);
+       __set_bit(EV_ABS, input_dev->evbit);
+
+       input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, 0, MAX_AREA, 0, 0);
+       input_set_abs_params(input_dev, ABS_MT_POSITION_X, MIN_X, MAX_X, 0, 0);
+       input_set_abs_params(input_dev, ABS_MT_POSITION_Y, MIN_Y, MAX_Y, 0, 0);
+
+       error = request_threaded_irq(client->irq, NULL, st1232_ts_irq_handler,
+                                    IRQF_ONESHOT, client->name, ts);
+       if (error) {
+               dev_err(&client->dev, "Failed to register interrupt\n");
+               goto err_free_mem;
+       }
+
+       error = input_register_device(ts->input_dev);
+       if (error) {
+               dev_err(&client->dev, "Unable to register %s input device\n",
+                       input_dev->name);
+               goto err_free_irq;
+       }
+
+       i2c_set_clientdata(client, ts);
+       device_init_wakeup(&client->dev, 1);
+
+       return 0;
+
+err_free_irq:
+       free_irq(client->irq, ts);
+err_free_mem:
+       input_free_device(input_dev);
+       kfree(ts);
+       return error;
+}
+
+static int __devexit st1232_ts_remove(struct i2c_client *client)
+{
+       struct st1232_ts_data *ts = i2c_get_clientdata(client);
+
+       device_init_wakeup(&client->dev, 0);
+       free_irq(client->irq, ts);
+       input_unregister_device(ts->input_dev);
+       kfree(ts);
+
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int st1232_ts_suspend(struct device *dev)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+
+       if (device_may_wakeup(&client->dev))
+               enable_irq_wake(client->irq);
+       else
+               disable_irq(client->irq);
+
+       return 0;
+}
+
+static int st1232_ts_resume(struct device *dev)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+
+       if (device_may_wakeup(&client->dev))
+               disable_irq_wake(client->irq);
+       else
+               enable_irq(client->irq);
+
+       return 0;
+}
+
+static const struct dev_pm_ops st1232_ts_pm_ops = {
+       .suspend        = st1232_ts_suspend,
+       .resume         = st1232_ts_resume,
+};
+#endif
+
+static const struct i2c_device_id st1232_ts_id[] = {
+       { ST1232_TS_NAME, 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, st1232_ts_id);
+
+static struct i2c_driver st1232_ts_driver = {
+       .probe          = st1232_ts_probe,
+       .remove         = __devexit_p(st1232_ts_remove),
+       .id_table       = st1232_ts_id,
+       .driver = {
+               .name   = ST1232_TS_NAME,
+               .owner  = THIS_MODULE,
+#ifdef CONFIG_PM
+               .pm     = &st1232_ts_pm_ops,
+#endif
+       },
+};
+
+static int __init st1232_ts_init(void)
+{
+       return i2c_add_driver(&st1232_ts_driver);
+}
+module_init(st1232_ts_init);
+
+static void __exit st1232_ts_exit(void)
+{
+       i2c_del_driver(&st1232_ts_driver);
+}
+module_exit(st1232_ts_exit);
+
+MODULE_AUTHOR("Tony SIM <chinyeow.sim.xt@renesas.com>");
+MODULE_DESCRIPTION("SITRONIX ST1232 Touchscreen Controller Driver");
+MODULE_LICENSE("GPL");
index e0c024d..7f85a86 100644 (file)
@@ -17,6 +17,8 @@
  * Switch to grant tables together with xen-fbfront.c.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/kernel.h>
 #include <linux/errno.h>
 #include <linux/module.h>
@@ -84,9 +86,8 @@ static irqreturn_t input_handler(int rq, void *dev_id)
                                input_report_key(dev, event->key.keycode,
                                                 event->key.pressed);
                        else
-                               printk(KERN_WARNING
-                                      "xenkbd: unhandled keycode 0x%x\n",
-                                      event->key.keycode);
+                               pr_warning("unhandled keycode 0x%x\n",
+                                          event->key.keycode);
                        break;
                case XENKBD_TYPE_POS:
                        input_report_abs(dev, ABS_X, event->pos.abs_x);
@@ -292,8 +293,7 @@ InitWait:
                        ret = xenbus_printf(XBT_NIL, info->xbdev->nodename,
                                            "request-abs-pointer", "1");
                        if (ret)
-                               printk(KERN_WARNING
-                                      "xenkbd: can't request abs-pointer");
+                               pr_warning("can't request abs-pointer\n");
                }
                xenbus_switch_state(dev, XenbusStateConnected);
                break;
index 067f996..6a82388 100644 (file)
@@ -23,6 +23,8 @@ static int mouse_button3_keycode = KEY_RIGHTALT;      /* right option key */
 
 static struct input_dev *mac_hid_emumouse_dev;
 
+static DEFINE_MUTEX(mac_hid_emumouse_mutex);
+
 static int mac_hid_create_emumouse(void)
 {
        static struct lock_class_key mac_hid_emumouse_dev_event_class;
@@ -187,6 +189,10 @@ static int mac_hid_toggle_emumouse(ctl_table *table, int write,
        int old_val = *valp;
        int rc;
 
+       rc = mutex_lock_killable(&mac_hid_emumouse_mutex);
+       if (rc)
+               return rc;
+
        rc = proc_dointvec(table, write, buffer, lenp, ppos);
 
        if (rc == 0 && write && *valp != old_val) {
@@ -202,6 +208,8 @@ static int mac_hid_toggle_emumouse(ctl_table *table, int write,
        if (rc)
                *valp = old_val;
 
+       mutex_unlock(&mac_hid_emumouse_mutex);
+
        return rc;
 }
 
index d4b711c..3374618 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/tty.h>
 #include <linux/console.h>
 #include <linux/vt_kern.h>
+#include <linux/input.h>
 
 #define MAX_CONFIG_LEN         40
 
@@ -37,6 +38,61 @@ static struct tty_driver     *kgdb_tty_driver;
 static int                     kgdb_tty_line;
 
 #ifdef CONFIG_KDB_KEYBOARD
+static int kgdboc_reset_connect(struct input_handler *handler,
+                               struct input_dev *dev,
+                               const struct input_device_id *id)
+{
+       input_reset_device(dev);
+
+       /* Retrun an error - we do not want to bind, just to reset */
+       return -ENODEV;
+}
+
+static void kgdboc_reset_disconnect(struct input_handle *handle)
+{
+       /* We do not expect anyone to actually bind to us */
+       BUG();
+}
+
+static const struct input_device_id kgdboc_reset_ids[] = {
+       {
+               .flags = INPUT_DEVICE_ID_MATCH_EVBIT,
+               .evbit = { BIT_MASK(EV_KEY) },
+       },
+       { }
+};
+
+static struct input_handler kgdboc_reset_handler = {
+       .connect        = kgdboc_reset_connect,
+       .disconnect     = kgdboc_reset_disconnect,
+       .name           = "kgdboc_reset",
+       .id_table       = kgdboc_reset_ids,
+};
+
+static DEFINE_MUTEX(kgdboc_reset_mutex);
+
+static void kgdboc_restore_input_helper(struct work_struct *dummy)
+{
+       /*
+        * We need to take a mutex to prevent several instances of
+        * this work running on different CPUs so they don't try
+        * to register again already registered handler.
+        */
+       mutex_lock(&kgdboc_reset_mutex);
+
+       if (input_register_handler(&kgdboc_reset_handler) == 0)
+               input_unregister_handler(&kgdboc_reset_handler);
+
+       mutex_unlock(&kgdboc_reset_mutex);
+}
+
+static DECLARE_WORK(kgdboc_restore_input_work, kgdboc_restore_input_helper);
+
+static void kgdboc_restore_input(void)
+{
+       schedule_work(&kgdboc_restore_input_work);
+}
+
 static int kgdboc_register_kbd(char **cptr)
 {
        if (strncmp(*cptr, "kbd", 3) == 0) {
@@ -64,10 +120,12 @@ static void kgdboc_unregister_kbd(void)
                        i--;
                }
        }
+       flush_work_sync(&kgdboc_restore_input_work);
 }
 #else /* ! CONFIG_KDB_KEYBOARD */
 #define kgdboc_register_kbd(x) 0
 #define kgdboc_unregister_kbd()
+#define kgdboc_restore_input()
 #endif /* ! CONFIG_KDB_KEYBOARD */
 
 static int kgdboc_option_setup(char *opt)
@@ -231,6 +289,7 @@ static void kgdboc_post_exp_handler(void)
                dbg_restore_graphics = 0;
                con_debug_leave();
        }
+       kgdboc_restore_input();
 }
 
 static struct kgdb_io kgdboc_io_ops = {
index 3c5d6b6..cec17cf 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Analog Devices ADP5588 I/O Expander and QWERTY Keypad Controller
  *
- * Copyright 2009 Analog Devices Inc.
+ * Copyright 2009-2010 Analog Devices Inc.
  *
  * Licensed under the GPL-2 or later.
  */
  /* Configuration Register1 */
 #define ADP5588_AUTO_INC       (1 << 7)
 #define ADP5588_GPIEM_CFG      (1 << 6)
+#define ADP5588_OVR_FLOW_M     (1 << 5)
 #define ADP5588_INT_CFG                (1 << 4)
+#define ADP5588_OVR_FLOW_IEN   (1 << 3)
+#define ADP5588_K_LCK_IM       (1 << 2)
 #define ADP5588_GPI_IEN                (1 << 1)
+#define ADP5588_KE_IEN         (1 << 0)
 
 /* Interrupt Status Register */
+#define ADP5588_CMP2_INT       (1 << 5)
+#define ADP5588_CMP1_INT       (1 << 4)
+#define ADP5588_OVR_FLOW_INT   (1 << 3)
+#define ADP5588_K_LCK_INT      (1 << 2)
 #define ADP5588_GPI_INT                (1 << 1)
 #define ADP5588_KE_INT         (1 << 0)
 
+/* Key Lock and Event Counter Register */
+#define ADP5588_K_LCK_EN       (1 << 6)
+#define ADP5588_LCK21          0x30
+#define ADP5588_KEC            0xF
+
 #define ADP5588_MAXGPIO                18
 #define ADP5588_BANK(offs)     ((offs) >> 3)
 #define ADP5588_BIT(offs)      (1u << ((offs) & 0x7))
index 8d9c76c..6c407e5 100644 (file)
@@ -1418,6 +1418,8 @@ static inline void input_set_drvdata(struct input_dev *dev, void *data)
 int __must_check input_register_device(struct input_dev *);
 void input_unregister_device(struct input_dev *);
 
+void input_reset_device(struct input_dev *);
+
 int __must_check input_register_handler(struct input_handler *);
 void input_unregister_handler(struct input_handler *);
 
@@ -1433,7 +1435,7 @@ void input_release_device(struct input_handle *);
 int input_open_device(struct input_handle *);
 void input_close_device(struct input_handle *);
 
-int input_flush_device(struct input_handle* handle, struct file* file);
+int input_flush_device(struct input_handle *handle, struct file *file);
 
 void input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value);
 void input_inject_event(struct input_handle *handle, unsigned int type, unsigned int code, int value);
diff --git a/include/linux/input/cma3000.h b/include/linux/input/cma3000.h
new file mode 100644 (file)
index 0000000..cbbaac2
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * VTI CMA3000_Dxx Accelerometer driver
+ *
+ * Copyright (C) 2010 Texas Instruments
+ * Author: Hemanth V <hemanthv@ti.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.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _LINUX_CMA3000_H
+#define _LINUX_CMA3000_H
+
+#define CMAMODE_DEFAULT    0
+#define CMAMODE_MEAS100    1
+#define CMAMODE_MEAS400    2
+#define CMAMODE_MEAS40     3
+#define CMAMODE_MOTDET     4
+#define CMAMODE_FF100      5
+#define CMAMODE_FF400      6
+#define CMAMODE_POFF       7
+
+#define CMARANGE_2G   2000
+#define CMARANGE_8G   8000
+
+/**
+ * struct cma3000_i2c_platform_data - CMA3000 Platform data
+ * @fuzz_x: Noise on X Axis
+ * @fuzz_y: Noise on Y Axis
+ * @fuzz_z: Noise on Z Axis
+ * @g_range: G range in milli g i.e 2000 or 8000
+ * @mode: Operating mode
+ * @mdthr: Motion detect threshold value
+ * @mdfftmr: Motion detect and free fall time value
+ * @ffthr: Free fall threshold value
+ */
+
+struct cma3000_platform_data {
+       int fuzz_x;
+       int fuzz_y;
+       int fuzz_z;
+       int g_range;
+       uint8_t mode;
+       uint8_t mdthr;
+       uint8_t mdfftmr;
+       uint8_t ffthr;
+       unsigned long irqflags;
+};
+
+#endif