Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input
Linus Torvalds [Mon, 1 Mar 2010 18:38:09 +0000 (10:38 -0800)]
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input: (62 commits)
  Input: atkbd - release previously reserved keycodes 248 - 254
  Input: add KEY_WPS_BUTTON definition
  Input: ads7846 - add regulator support
  Input: winbond-cir - fix suspend/resume
  Input: gamecon - use pr_err() and friends
  Input: gamecon - constify some of the setup structures
  Input: gamecon - simplify pad type handling
  Input: gamecon - simplify coordinate calculation for PSX
  Input: gamecon - fix some formatting issues
  Input: gamecon - add rumble support for N64 pads
  Input: wacom - add device type to device name string
  Input: s3c24xx_ts - report touch only when stylus is down
  Input: s3c24xx_ts - re-enable IRQ on resume
  Input: wacom - constify product features data
  Input: wacom - use per-device instance of wacom_features
  Input: sh_keysc - enable building on SH-Mobile ARM
  Input: wacom - get features from driver info
  Input: rotary-encoder - set gpio direction for each requested gpio
  Input: sh_keysc - update the driver with mode 6
  Input: sh_keysc - switch to using bitmaps
  ...

53 files changed:
Documentation/feature-removal-schedule.txt
Documentation/input/sentelic.txt
arch/arm/mach-ep93xx/include/mach/ep93xx_keypad.h
drivers/char/keyboard.c
drivers/input/evdev.c
drivers/input/gameport/emu10k1-gp.c
drivers/input/gameport/fm801-gp.c
drivers/input/gameport/gameport.c
drivers/input/gameport/ns558.c
drivers/input/input.c
drivers/input/joydev.c
drivers/input/joystick/Kconfig
drivers/input/joystick/gamecon.c
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/ep93xx_keypad.c
drivers/input/keyboard/gpio_keys.c
drivers/input/keyboard/imx_keypad.c [new file with mode: 0644]
drivers/input/keyboard/qt2160.c
drivers/input/keyboard/sh_keysc.c
drivers/input/misc/apanel.c
drivers/input/misc/rotary_encoder.c
drivers/input/misc/uinput.c
drivers/input/misc/winbond-cir.c
drivers/input/mouse/hgpk.c
drivers/input/serio/pcips2.c
drivers/input/serio/serio.c
drivers/input/serio/xilinx_ps2.c
drivers/input/tablet/gtco.c
drivers/input/tablet/wacom.h
drivers/input/tablet/wacom_sys.c
drivers/input/tablet/wacom_wac.c
drivers/input/tablet/wacom_wac.h
drivers/input/touchscreen/Kconfig
drivers/input/touchscreen/ads7846.c
drivers/input/touchscreen/elo.c
drivers/input/touchscreen/mainstone-wm97xx.c
drivers/input/touchscreen/s3c2410_ts.c
drivers/input/touchscreen/tsc2007.c
drivers/input/touchscreen/usbtouchscreen.c
drivers/input/touchscreen/zylonite-wm97xx.c
drivers/input/xen-kbdfront.c
drivers/macintosh/Kconfig
drivers/macintosh/mac_hid.c
include/linux/gameport.h
include/linux/gpio_keys.h
include/linux/input.h
include/linux/input/sh_keysc.h
include/linux/kbd_kern.h
include/linux/serio.h

index ea40149..732b1fa 100644 (file)
@@ -538,3 +538,26 @@ Why:       Duplicate functionality with the gspca_zc3xx driver, zc0301 only
        sensors) wich are also supported by the gspca_zc3xx driver
        (which supports 53 USB-ID's in total)
 Who:   Hans de Goede <hdegoede@redhat.com>
+
+----------------------------
+
+What:  corgikbd, spitzkbd, tosakbd driver
+When:  2.6.35
+Files: drivers/input/keyboard/{corgi,spitz,tosa}kbd.c
+Why:   We now have a generic GPIO based matrix keyboard driver that
+       are fully capable of handling all the keys on these devices.
+       The original drivers manipulate the GPIO registers directly
+       and so are difficult to maintain.
+Who:   Eric Miao <eric.y.miao@gmail.com>
+
+----------------------------
+
+What:  corgi_ssp and corgi_ts driver
+When:  2.6.35
+Files: arch/arm/mach-pxa/corgi_ssp.c, drivers/input/touchscreen/corgi_ts.c
+Why:   The corgi touchscreen is now deprecated in favour of the generic
+       ads7846.c driver. The noise reduction technique used in corgi_ts.c,
+       that's to wait till vsync before ADC sampling, is also integrated into
+       ads7846 driver now. Provided that the original driver is not generic
+       and is difficult to maintain, it will be removed later.
+Who:   Eric Miao <eric.y.miao@gmail.com>
index f7160a2..b35affd 100644 (file)
@@ -1,5 +1,5 @@
-Copyright (C) 2002-2008 Sentelic Corporation.
-Last update: Oct-31-2008
+Copyright (C) 2002-2010 Sentelic Corporation.
+Last update: Jan-13-2010
 
 ==============================================================================
 * Finger Sensing Pad Intellimouse Mode(scrolling wheel, 4th and 5th buttons)
@@ -44,7 +44,7 @@ B) MSID 6: Horizontal and Vertical scrolling.
 Packet 1
    Bit 7 6 5 4 3 2 1 0       7 6 5 4 3 2 1 0      7 6 5 4 3 2 1 0      7 6 5 4 3 2 1 0
 BYTE  |---------------|BYTE |---------------|BYTE|---------------|BYTE|---------------|
-  1   |Y|X|y|x|1|M|R|L|  2  |X|X|X|X|X|X|X|X|  3 |Y|Y|Y|Y|Y|Y|Y|Y|  4 | | |B|F|l|r|u|d|
+  1   |Y|X|y|x|1|M|R|L|  2  |X|X|X|X|X|X|X|X|  3 |Y|Y|Y|Y|Y|Y|Y|Y|  4 | | |B|F|r|l|u|d|
       |---------------|     |---------------|    |---------------|    |---------------|
 
 Byte 1: Bit7 => Y overflow
@@ -59,15 +59,15 @@ Byte 2: X Movement(9-bit 2's complement integers)
 Byte 3: Y Movement(9-bit 2's complement integers)
 Byte 4: Bit0 => the Vertical scrolling movement downward.
        Bit1 => the Vertical scrolling movement upward.
-       Bit2 => the Vertical scrolling movement rightward.
-       Bit3 => the Vertical scrolling movement leftward.
+       Bit2 => the Horizontal scrolling movement leftward.
+       Bit3 => the Horizontal scrolling movement rightward.
         Bit4 => 1 = 4th mouse button is pressed, Forward one page.
                 0 = 4th mouse button is not pressed.
         Bit5 => 1 = 5th mouse button is pressed, Backward one page.
                 0 = 5th mouse button is not pressed.
 
 C) MSID 7:
-# FSP uses 2 packets(8 Bytes) data to represent Absolute Position
+# FSP uses 2 packets (8 Bytes) to represent Absolute Position.
   so we have PACKET NUMBER to identify packets.
   If PACKET NUMBER is 0, the packet is Packet 1.
   If PACKET NUMBER is 1, the packet is Packet 2.
@@ -129,7 +129,7 @@ Byte 3: Message Type => 0x00 (Disabled)
 Byte 4: Bit7~Bit0 => Don't Care
 
 ==============================================================================
-* Absolute position for STL3888-A0.
+* Absolute position for STL3888-Ax.
 ==============================================================================
 Packet 1 (ABSOLUTE POSITION)
    Bit 7 6 5 4 3 2 1 0       7 6 5 4 3 2 1 0      7 6 5 4 3 2 1 0      7 6 5 4 3 2 1 0
@@ -179,14 +179,14 @@ Byte 4: Bit1~Bit0 => Y coordinate (xpos[1:0])
         Bit5~Bit4 => y2_g
         Bit7~Bit6 => x2_g
 
-Notify Packet for STL3888-A0
+Notify Packet for STL3888-Ax
    Bit 7 6 5 4 3 2 1 0       7 6 5 4 3 2 1 0      7 6 5 4 3 2 1 0      7 6 5 4 3 2 1 0
 BYTE  |---------------|BYTE |---------------|BYTE|---------------|BYTE|---------------|
   1   |1|0|1|P|1|M|R|L|  2  |C|C|C|C|C|C|C|C|  3 |0|0|F|F|0|0|0|i|  4 |r|l|d|u|0|0|0|0|
       |---------------|     |---------------|    |---------------|    |---------------|
 
 Byte 1: Bit7~Bit6 => 00, Normal data packet
-                  => 01, Absolute coordination packet
+                  => 01, Absolute coordinates packet
                   => 10, Notify packet
         Bit5 => 1
         Bit4 => when in absolute coordinates mode (valid when EN_PKT_GO is 1):
@@ -205,15 +205,106 @@ Byte 4: Bit7 => scroll right button
         Bit6 => scroll left button
         Bit5 => scroll down button
         Bit4 => scroll up button
-            * Note that if gesture and additional button (Bit4~Bit7)
-             happen at the same time, the button information will not
-             be sent.
+            * Note that if gesture and additional buttoni (Bit4~Bit7)
+              happen at the same time, the button information will not
+              be sent.
+        Bit3~Bit0 => Reserved
+
+Sample sequence of Multi-finger, Multi-coordinate mode:
+
+       notify packet (valid bit == 1), abs pkt 1, abs pkt 2, abs pkt 1,
+       abs pkt 2, ..., notify packet (valid bit == 0)
+
+==============================================================================
+* Absolute position for STL3888-B0.
+==============================================================================
+Packet 1(ABSOLUTE POSITION)
+   Bit 7 6 5 4 3 2 1 0       7 6 5 4 3 2 1 0      7 6 5 4 3 2 1 0      7 6 5 4 3 2 1 0
+BYTE  |---------------|BYTE |---------------|BYTE|---------------|BYTE|---------------|
+  1   |0|1|V|F|1|0|R|L|  2  |X|X|X|X|X|X|X|X|  3 |Y|Y|Y|Y|Y|Y|Y|Y|  4 |r|l|u|d|X|X|Y|Y|
+      |---------------|     |---------------|    |---------------|    |---------------|
+
+Byte 1: Bit7~Bit6 => 00, Normal data packet
+                  => 01, Absolute coordinates packet
+                  => 10, Notify packet
+        Bit5 => Valid bit, 0 means that the coordinate is invalid or finger up.
+                When both fingers are up, the last two reports have zero valid
+                bit.
+        Bit4 => finger up/down information. 1: finger down, 0: finger up.
+        Bit3 => 1
+        Bit2 => finger index, 0 is the first finger, 1 is the second finger.
+        Bit1 => Right Button, 1 is pressed, 0 is not pressed.
+        Bit0 => Left Button, 1 is pressed, 0 is not pressed.
+Byte 2: X coordinate (xpos[9:2])
+Byte 3: Y coordinate (ypos[9:2])
+Byte 4: Bit1~Bit0 => Y coordinate (xpos[1:0])
+        Bit3~Bit2 => X coordinate (ypos[1:0])
+        Bit4 => scroll down button
+        Bit5 => scroll up button
+        Bit6 => scroll left button
+        Bit7 => scroll right button
+
+Packet 2 (ABSOLUTE POSITION)
+   Bit 7 6 5 4 3 2 1 0       7 6 5 4 3 2 1 0      7 6 5 4 3 2 1 0      7 6 5 4 3 2 1 0
+BYTE  |---------------|BYTE |---------------|BYTE|---------------|BYTE|---------------|
+  1   |0|1|V|F|1|1|R|L|  2  |X|X|X|X|X|X|X|X|  3 |Y|Y|Y|Y|Y|Y|Y|Y|  4 |r|l|u|d|X|X|Y|Y|
+      |---------------|     |---------------|    |---------------|    |---------------|
+
+Byte 1: Bit7~Bit6 => 00, Normal data packet
+                  => 01, Absolute coordination packet
+                  => 10, Notify packet
+        Bit5 => Valid bit, 0 means that the coordinate is invalid or finger up.
+                When both fingers are up, the last two reports have zero valid
+                bit.
+        Bit4 => finger up/down information. 1: finger down, 0: finger up.
+        Bit3 => 1
+        Bit2 => finger index, 0 is the first finger, 1 is the second finger.
+        Bit1 => Right Button, 1 is pressed, 0 is not pressed.
+        Bit0 => Left Button, 1 is pressed, 0 is not pressed.
+Byte 2: X coordinate (xpos[9:2])
+Byte 3: Y coordinate (ypos[9:2])
+Byte 4: Bit1~Bit0 => Y coordinate (xpos[1:0])
+        Bit3~Bit2 => X coordinate (ypos[1:0])
+        Bit4 => scroll down button
+        Bit5 => scroll up button
+        Bit6 => scroll left button
+        Bit7 => scroll right button
+
+Notify Packet for STL3888-B0
+   Bit 7 6 5 4 3 2 1 0       7 6 5 4 3 2 1 0      7 6 5 4 3 2 1 0      7 6 5 4 3 2 1 0
+BYTE  |---------------|BYTE |---------------|BYTE|---------------|BYTE|---------------|
+  1   |1|0|1|P|1|M|R|L|  2  |C|C|C|C|C|C|C|C|  3 |0|0|F|F|0|0|0|i|  4 |r|l|u|d|0|0|0|0|
+      |---------------|     |---------------|    |---------------|    |---------------|
+
+Byte 1: Bit7~Bit6 => 00, Normal data packet
+                  => 01, Absolute coordination packet
+                  => 10, Notify packet
+        Bit5 => 1
+        Bit4 => when in absolute coordinate mode (valid when EN_PKT_GO is 1):
+                0: left button is generated by the on-pad command
+                1: left button is generated by the external button
+        Bit3 => 1
+        Bit2 => Middle Button, 1 is pressed, 0 is not pressed.
+        Bit1 => Right Button, 1 is pressed, 0 is not pressed.
+        Bit0 => Left Button, 1 is pressed, 0 is not pressed.
+Byte 2: Message Type => 0xB7 (Multi Finger, Multi Coordinate mode)
+Byte 3: Bit7~Bit6 => Don't care
+        Bit5~Bit4 => Number of fingers
+        Bit3~Bit1 => Reserved
+        Bit0 => 1: enter gesture mode; 0: leaving gesture mode
+Byte 4: Bit7 => scroll right button
+        Bit6 => scroll left button
+        Bit5 => scroll up button
+        Bit4 => scroll down button
+            * Note that if gesture and additional button(Bit4~Bit7)
+              happen at the same time, the button information will not
+              be sent.
         Bit3~Bit0 => Reserved
 
 Sample sequence of Multi-finger, Multi-coordinate mode:
 
        notify packet (valid bit == 1), abs pkt 1, abs pkt 2, abs pkt 1,
-       abs pkt 2, ..., notify packet(valid bit == 0)
+       abs pkt 2, ..., notify packet (valid bit == 0)
 
 ==============================================================================
 * FSP Enable/Disable packet
@@ -409,7 +500,8 @@ offset      width           default r/w     name
                                        0: read only, 1: read/write enable
        (Note that following registers does not require clock gating being
        enabled prior to write: 05 06 07 08 09 0c 0f 10 11 12 16 17 18 23 2e
-       40 41 42 43.)
+       40 41 42 43.  In addition to that, this bit must be 1 when gesture
+       mode is enabled)
 
 0x31                           RW      on-pad command detection
        bit7            0       RW      on-pad command left button down tag
@@ -463,6 +555,10 @@ offset     width           default r/w     name
        absolute coordinates; otherwise, host only receives packets with
        relative coordinate.)
 
+       bit7            0       RW      EN_PS2_F2: PS/2 gesture mode 2nd
+                                       finger packet enable
+                                       0: disable, 1: enable
+
 0x43                           RW      on-pad control
        bit0            0       RW      on-pad control enable
                                        0: disable, 1: enable
index 62d1742..1e2f4e9 100644 (file)
@@ -5,6 +5,8 @@
 #ifndef __ASM_ARCH_EP93XX_KEYPAD_H
 #define __ASM_ARCH_EP93XX_KEYPAD_H
 
+struct matrix_keymap_data;
+
 /* flags for the ep93xx_keypad driver */
 #define EP93XX_KEYPAD_DISABLE_3_KEY    (1<<0)  /* disable 3-key reset */
 #define EP93XX_KEYPAD_DIAG_MODE                (1<<1)  /* diagnostic mode */
 
 /**
  * struct ep93xx_keypad_platform_data - platform specific device structure
- * @matrix_key_map:            array of keycodes defining the keypad matrix
- * @matrix_key_map_size:       ARRAY_SIZE(matrix_key_map)
- * @debounce:                  debounce start count; terminal count is 0xff
- * @prescale:                  row/column counter pre-scaler load value
- * @flags:                     see above
+ * @keymap_data:       pointer to &matrix_keymap_data
+ * @debounce:          debounce start count; terminal count is 0xff
+ * @prescale:          row/column counter pre-scaler load value
+ * @flags:             see above
  */
 struct ep93xx_keypad_platform_data {
-       unsigned int    *matrix_key_map;
-       int             matrix_key_map_size;
+       struct matrix_keymap_data *keymap_data;
        unsigned int    debounce;
        unsigned int    prescale;
        unsigned int    flags;
index f706b1d..ada25bb 100644 (file)
@@ -1185,11 +1185,6 @@ static void kbd_keycode(unsigned int keycode, int down, int hw_raw)
 
        rep = (down == 2);
 
-#ifdef CONFIG_MAC_EMUMOUSEBTN
-       if (mac_hid_mouse_emulate_buttons(1, keycode, down))
-               return;
-#endif /* CONFIG_MAC_EMUMOUSEBTN */
-
        if ((raw_mode = (kbd->kbdmode == VC_RAW)) && !hw_raw)
                if (emulate_raw(vc, keycode, !down << 7))
                        if (keycode < BTN_MISC && printk_ratelimit())
@@ -1328,6 +1323,21 @@ static void kbd_event(struct input_handle *handle, unsigned int event_type,
        schedule_console_callback();
 }
 
+static bool kbd_match(struct input_handler *handler, struct input_dev *dev)
+{
+       int i;
+
+       if (test_bit(EV_SND, dev->evbit))
+               return true;
+
+       if (test_bit(EV_KEY, dev->evbit))
+               for (i = KEY_RESERVED; i < BTN_MISC; i++)
+                       if (test_bit(i, dev->keybit))
+                               return true;
+
+       return false;
+}
+
 /*
  * When a keyboard (or other input device) is found, the kbd_connect
  * function is called. The function then looks at the device, and if it
@@ -1339,14 +1349,6 @@ static int kbd_connect(struct input_handler *handler, struct input_dev *dev,
 {
        struct input_handle *handle;
        int error;
-       int i;
-
-       for (i = KEY_RESERVED; i < BTN_MISC; i++)
-               if (test_bit(i, dev->keybit))
-                       break;
-
-       if (i == BTN_MISC && !test_bit(EV_SND, dev->evbit))
-               return -ENODEV;
 
        handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL);
        if (!handle)
@@ -1412,6 +1414,7 @@ MODULE_DEVICE_TABLE(input, kbd_ids);
 
 static struct input_handler kbd_handler = {
        .event          = kbd_event,
+       .match          = kbd_match,
        .connect        = kbd_connect,
        .disconnect     = kbd_disconnect,
        .start          = kbd_start,
index 258c639..9f9816b 100644 (file)
@@ -278,6 +278,8 @@ static int evdev_open(struct inode *inode, struct file *file)
                goto err_free_client;
 
        file->private_data = client;
+       nonseekable_open(inode, file);
+
        return 0;
 
  err_free_client:
index b04930f..7392992 100644 (file)
@@ -46,7 +46,7 @@ struct emu {
        int size;
 };
 
-static struct pci_device_id emu_tbl[] = {
+static const struct pci_device_id emu_tbl[] = {
 
        { 0x1102, 0x7002, PCI_ANY_ID, PCI_ANY_ID }, /* SB Live gameport */
        { 0x1102, 0x7003, PCI_ANY_ID, PCI_ANY_ID }, /* Audigy gameport */
index 8a1810f..14d3f3e 100644 (file)
@@ -140,7 +140,7 @@ static void __devexit fm801_gp_remove(struct pci_dev *pci)
        }
 }
 
-static struct pci_device_id fm801_gp_id_table[] = {
+static const struct pci_device_id fm801_gp_id_table[] = {
        { PCI_VENDOR_ID_FORTEMEDIA, PCI_DEVICE_ID_FM801_GP, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0  },
        { 0 }
 };
index ac11be0..7e18bcf 100644 (file)
@@ -11,6 +11,8 @@
  * the Free Software Foundation.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/stddef.h>
 #include <linux/module.h>
 #include <linux/ioport.h>
@@ -190,9 +192,8 @@ static int gameport_bind_driver(struct gameport *gameport, struct gameport_drive
 
        error = device_bind_driver(&gameport->dev);
        if (error) {
-               printk(KERN_WARNING
-                       "gameport: device_bind_driver() failed "
-                       "for %s (%s) and %s, error: %d\n",
+               dev_warn(&gameport->dev,
+                        "device_bind_driver() failed for %s (%s) and %s, error: %d\n",
                        gameport->phys, gameport->name,
                        drv->description, error);
                drv->disconnect(gameport);
@@ -209,9 +210,9 @@ static void gameport_find_driver(struct gameport *gameport)
 
        error = device_attach(&gameport->dev);
        if (error < 0)
-               printk(KERN_WARNING
-                       "gameport: device_attach() failed for %s (%s), error: %d\n",
-                       gameport->phys, gameport->name, error);
+               dev_warn(&gameport->dev,
+                        "device_attach() failed for %s (%s), error: %d\n",
+                        gameport->phys, gameport->name, error);
 }
 
 
@@ -262,17 +263,14 @@ static int gameport_queue_event(void *object, struct module *owner,
 
        event = kmalloc(sizeof(struct gameport_event), GFP_ATOMIC);
        if (!event) {
-               printk(KERN_ERR
-                       "gameport: Not enough memory to queue event %d\n",
-                       event_type);
+               pr_err("Not enough memory to queue event %d\n", event_type);
                retval = -ENOMEM;
                goto out;
        }
 
        if (!try_module_get(owner)) {
-               printk(KERN_WARNING
-                       "gameport: Can't get module reference, dropping event %d\n",
-                       event_type);
+               pr_warning("Can't get module reference, dropping event %d\n",
+                          event_type);
                kfree(event);
                retval = -EINVAL;
                goto out;
@@ -298,14 +296,12 @@ static void gameport_free_event(struct gameport_event *event)
 
 static void gameport_remove_duplicate_events(struct gameport_event *event)
 {
-       struct list_head *node, *next;
-       struct gameport_event *e;
+       struct gameport_event *e, *next;
        unsigned long flags;
 
        spin_lock_irqsave(&gameport_event_lock, flags);
 
-       list_for_each_safe(node, next, &gameport_event_list) {
-               e = list_entry(node, struct gameport_event, node);
+       list_for_each_entry_safe(e, next, &gameport_event_list, node) {
                if (event->object == e->object) {
                        /*
                         * If this event is of different type we should not
@@ -315,7 +311,7 @@ static void gameport_remove_duplicate_events(struct gameport_event *event)
                        if (event->type != e->type)
                                break;
 
-                       list_del_init(node);
+                       list_del_init(&e->node);
                        gameport_free_event(e);
                }
        }
@@ -325,23 +321,18 @@ static void gameport_remove_duplicate_events(struct gameport_event *event)
 
 static struct gameport_event *gameport_get_event(void)
 {
-       struct gameport_event *event;
-       struct list_head *node;
+       struct gameport_event *event = NULL;
        unsigned long flags;
 
        spin_lock_irqsave(&gameport_event_lock, flags);
 
-       if (list_empty(&gameport_event_list)) {
-               spin_unlock_irqrestore(&gameport_event_lock, flags);
-               return NULL;
+       if (!list_empty(&gameport_event_list)) {
+               event = list_first_entry(&gameport_event_list,
+                                        struct gameport_event, node);
+               list_del_init(&event->node);
        }
 
-       node = gameport_event_list.next;
-       event = list_entry(node, struct gameport_event, node);
-       list_del_init(node);
-
        spin_unlock_irqrestore(&gameport_event_lock, flags);
-
        return event;
 }
 
@@ -360,16 +351,14 @@ static void gameport_handle_event(void)
        if ((event = gameport_get_event())) {
 
                switch (event->type) {
-                       case GAMEPORT_REGISTER_PORT:
-                               gameport_add_port(event->object);
-                               break;
 
-                       case GAMEPORT_ATTACH_DRIVER:
-                               gameport_attach_driver(event->object);
-                               break;
+               case GAMEPORT_REGISTER_PORT:
+                       gameport_add_port(event->object);
+                       break;
 
-                       default:
-                               break;
+               case GAMEPORT_ATTACH_DRIVER:
+                       gameport_attach_driver(event->object);
+                       break;
                }
 
                gameport_remove_duplicate_events(event);
@@ -385,16 +374,14 @@ static void gameport_handle_event(void)
  */
 static void gameport_remove_pending_events(void *object)
 {
-       struct list_head *node, *next;
-       struct gameport_event *event;
+       struct gameport_event *event, *next;
        unsigned long flags;
 
        spin_lock_irqsave(&gameport_event_lock, flags);
 
-       list_for_each_safe(node, next, &gameport_event_list) {
-               event = list_entry(node, struct gameport_event, node);
+       list_for_each_entry_safe(event, next, &gameport_event_list, node) {
                if (event->object == object) {
-                       list_del_init(node);
+                       list_del_init(&event->node);
                        gameport_free_event(event);
                }
        }
@@ -441,7 +428,6 @@ static int gameport_thread(void *nothing)
                        kthread_should_stop() || !list_empty(&gameport_event_list));
        } while (!kthread_should_stop());
 
-       printk(KERN_DEBUG "gameport: kgameportd exiting\n");
        return 0;
 }
 
@@ -453,6 +439,7 @@ static int gameport_thread(void *nothing)
 static ssize_t gameport_show_description(struct device *dev, struct device_attribute *attr, char *buf)
 {
        struct gameport *gameport = to_gameport_port(dev);
+
        return sprintf(buf, "%s\n", gameport->name);
 }
 
@@ -521,7 +508,8 @@ static void gameport_init_port(struct gameport *gameport)
 
        mutex_init(&gameport->drv_mutex);
        device_initialize(&gameport->dev);
-       dev_set_name(&gameport->dev, "gameport%lu", (unsigned long)atomic_inc_return(&gameport_no) - 1);
+       dev_set_name(&gameport->dev, "gameport%lu",
+                       (unsigned long)atomic_inc_return(&gameport_no) - 1);
        gameport->dev.bus = &gameport_bus;
        gameport->dev.release = gameport_release_port;
        if (gameport->parent)
@@ -550,19 +538,17 @@ static void gameport_add_port(struct gameport *gameport)
        list_add_tail(&gameport->node, &gameport_list);
 
        if (gameport->io)
-               printk(KERN_INFO "gameport: %s is %s, io %#x, speed %dkHz\n",
-                       gameport->name, gameport->phys, gameport->io, gameport->speed);
+               dev_info(&gameport->dev, "%s is %s, io %#x, speed %dkHz\n",
+                        gameport->name, gameport->phys, gameport->io, gameport->speed);
        else
-               printk(KERN_INFO "gameport: %s is %s, speed %dkHz\n",
+               dev_info(&gameport->dev, "%s is %s, speed %dkHz\n",
                        gameport->name, gameport->phys, gameport->speed);
 
        error = device_add(&gameport->dev);
        if (error)
-               printk(KERN_ERR
-                       "gameport: device_add() failed for %s (%s), error: %d\n",
+               dev_err(&gameport->dev,
+                       "device_add() failed for %s (%s), error: %d\n",
                        gameport->phys, gameport->name, error);
-       else
-               gameport->registered = 1;
 }
 
 /*
@@ -584,10 +570,8 @@ static void gameport_destroy_port(struct gameport *gameport)
                gameport->parent = NULL;
        }
 
-       if (gameport->registered) {
+       if (device_is_registered(&gameport->dev))
                device_del(&gameport->dev);
-               gameport->registered = 0;
-       }
 
        list_del_init(&gameport->node);
 
@@ -705,8 +689,7 @@ static void gameport_attach_driver(struct gameport_driver *drv)
 
        error = driver_attach(&drv->driver);
        if (error)
-               printk(KERN_ERR
-                       "gameport: driver_attach() failed for %s, error: %d\n",
+               pr_err("driver_attach() failed for %s, error: %d\n",
                        drv->driver.name, error);
 }
 
@@ -727,8 +710,7 @@ int __gameport_register_driver(struct gameport_driver *drv, struct module *owner
 
        error = driver_register(&drv->driver);
        if (error) {
-               printk(KERN_ERR
-                       "gameport: driver_register() failed for %s, error: %d\n",
+               pr_err("driver_register() failed for %s, error: %d\n",
                        drv->driver.name, error);
                return error;
        }
@@ -828,7 +810,7 @@ static int __init gameport_init(void)
 
        error = bus_register(&gameport_bus);
        if (error) {
-               printk(KERN_ERR "gameport: failed to register gameport bus, error: %d\n", error);
+               pr_err("failed to register gameport bus, error: %d\n", error);
                return error;
        }
 
@@ -836,7 +818,7 @@ static int __init gameport_init(void)
        if (IS_ERR(gameport_task)) {
                bus_unregister(&gameport_bus);
                error = PTR_ERR(gameport_task);
-               printk(KERN_ERR "gameport: Failed to start kgameportd, error: %d\n", error);
+               pr_err("Failed to start kgameportd, error: %d\n", error);
                return error;
        }
 
index db556b7..7c21784 100644 (file)
@@ -166,7 +166,7 @@ static int ns558_isa_probe(int io)
 
 #ifdef CONFIG_PNP
 
-static struct pnp_device_id pnp_devids[] = {
+static const struct pnp_device_id pnp_devids[] = {
        { .id = "@P@0001", .driver_data = 0 }, /* ALS 100 */
        { .id = "@P@0020", .driver_data = 0 }, /* ALS 200 */
        { .id = "@P@1001", .driver_data = 0 }, /* ALS 100+ */
index 86cb2d2..41168d5 100644 (file)
@@ -87,12 +87,14 @@ static int input_defuzz_abs_event(int value, int old_val, int fuzz)
 }
 
 /*
- * Pass event through all open handles. This function is called with
+ * Pass event first through all filters and then, if event has not been
+ * filtered out, through all open handles. This function is called with
  * dev->event_lock held and interrupts disabled.
  */
 static void input_pass_event(struct input_dev *dev,
                             unsigned int type, unsigned int code, int value)
 {
+       struct input_handler *handler;
        struct input_handle *handle;
 
        rcu_read_lock();
@@ -100,11 +102,25 @@ static void input_pass_event(struct input_dev *dev,
        handle = rcu_dereference(dev->grab);
        if (handle)
                handle->handler->event(handle, type, code, value);
-       else
-               list_for_each_entry_rcu(handle, &dev->h_list, d_node)
-                       if (handle->open)
-                               handle->handler->event(handle,
-                                                       type, code, value);
+       else {
+               bool filtered = false;
+
+               list_for_each_entry_rcu(handle, &dev->h_list, d_node) {
+                       if (!handle->open)
+                               continue;
+
+                       handler = handle->handler;
+                       if (!handler->filter) {
+                               if (filtered)
+                                       break;
+
+                               handler->event(handle, type, code, value);
+
+                       } else if (handler->filter(handle, type, code, value))
+                               filtered = true;
+               }
+       }
+
        rcu_read_unlock();
 }
 
@@ -615,12 +631,12 @@ static int input_default_setkeycode(struct input_dev *dev,
                }
        }
 
-       clear_bit(old_keycode, dev->keybit);
-       set_bit(keycode, dev->keybit);
+       __clear_bit(old_keycode, dev->keybit);
+       __set_bit(keycode, dev->keybit);
 
        for (i = 0; i < dev->keycodemax; i++) {
                if (input_fetch_keycode(dev, i) == old_keycode) {
-                       set_bit(old_keycode, dev->keybit);
+                       __set_bit(old_keycode, dev->keybit);
                        break; /* Setting the bit twice is useless, so break */
                }
        }
@@ -678,6 +694,9 @@ int input_set_keycode(struct input_dev *dev, int scancode, int keycode)
        if (retval)
                goto out;
 
+       /* Make sure KEY_RESERVED did not get enabled. */
+       __clear_bit(KEY_RESERVED, dev->keybit);
+
        /*
         * Simulate keyup event if keycode is not present
         * in the keymap anymore
@@ -705,12 +724,13 @@ EXPORT_SYMBOL(input_set_keycode);
                if (i != BITS_TO_LONGS(max)) \
                        continue;
 
-static const struct input_device_id *input_match_device(const struct input_device_id *id,
+static const struct input_device_id *input_match_device(struct input_handler *handler,
                                                        struct input_dev *dev)
 {
+       const struct input_device_id *id;
        int i;
 
-       for (; id->flags || id->driver_info; id++) {
+       for (id = handler->id_table; id->flags || id->driver_info; id++) {
 
                if (id->flags & INPUT_DEVICE_ID_MATCH_BUS)
                        if (id->bustype != dev->id.bustype)
@@ -738,7 +758,8 @@ static const struct input_device_id *input_match_device(const struct input_devic
                MATCH_BIT(ffbit,  FF_MAX);
                MATCH_BIT(swbit,  SW_MAX);
 
-               return id;
+               if (!handler->match || handler->match(handler, dev))
+                       return id;
        }
 
        return NULL;
@@ -749,10 +770,7 @@ static int input_attach_handler(struct input_dev *dev, struct input_handler *han
        const struct input_device_id *id;
        int error;
 
-       if (handler->blacklist && input_match_device(handler->blacklist, dev))
-               return -ENODEV;
-
-       id = input_match_device(handler->id_table, dev);
+       id = input_match_device(handler, dev);
        if (!id)
                return -ENODEV;
 
@@ -988,6 +1006,8 @@ static int input_handlers_seq_show(struct seq_file *seq, void *v)
        union input_seq_state *state = (union input_seq_state *)&seq->private;
 
        seq_printf(seq, "N: Number=%u Name=%s", state->pos, handler->name);
+       if (handler->filter)
+               seq_puts(seq, " (filter)");
        if (handler->fops)
                seq_printf(seq, " Minor=%d", handler->minor);
        seq_putc(seq, '\n');
@@ -1551,6 +1571,25 @@ void input_set_capability(struct input_dev *dev, unsigned int type, unsigned int
 }
 EXPORT_SYMBOL(input_set_capability);
 
+#define INPUT_CLEANSE_BITMASK(dev, type, bits)                         \
+       do {                                                            \
+               if (!test_bit(EV_##type, dev->evbit))                   \
+                       memset(dev->bits##bit, 0,                       \
+                               sizeof(dev->bits##bit));                \
+       } while (0)
+
+static void input_cleanse_bitmasks(struct input_dev *dev)
+{
+       INPUT_CLEANSE_BITMASK(dev, KEY, key);
+       INPUT_CLEANSE_BITMASK(dev, REL, rel);
+       INPUT_CLEANSE_BITMASK(dev, ABS, abs);
+       INPUT_CLEANSE_BITMASK(dev, MSC, msc);
+       INPUT_CLEANSE_BITMASK(dev, LED, led);
+       INPUT_CLEANSE_BITMASK(dev, SND, snd);
+       INPUT_CLEANSE_BITMASK(dev, FF, ff);
+       INPUT_CLEANSE_BITMASK(dev, SW, sw);
+}
+
 /**
  * input_register_device - register device with input core
  * @dev: device to be registered
@@ -1570,13 +1609,19 @@ int input_register_device(struct input_dev *dev)
        const char *path;
        int error;
 
+       /* Every input device generates EV_SYN/SYN_REPORT events. */
        __set_bit(EV_SYN, dev->evbit);
 
+       /* KEY_RESERVED is not supposed to be transmitted to userspace. */
+       __clear_bit(KEY_RESERVED, dev->keybit);
+
+       /* Make sure that bitmasks not mentioned in dev->evbit are clean. */
+       input_cleanse_bitmasks(dev);
+
        /*
         * If delay and period are pre-set by the driver, then autorepeating
         * is handled by the driver itself and we don't do it in input.c.
         */
-
        init_timer(&dev->timer);
        if (!dev->rep[REP_DELAY] && !dev->rep[REP_PERIOD]) {
                dev->timer.data = (long) dev;
@@ -1776,7 +1821,16 @@ int input_register_handle(struct input_handle *handle)
        error = mutex_lock_interruptible(&dev->mutex);
        if (error)
                return error;
-       list_add_tail_rcu(&handle->d_node, &dev->h_list);
+
+       /*
+        * Filters go to the head of the list, normal handlers
+        * to the tail.
+        */
+       if (handler->filter)
+               list_add_rcu(&handle->d_node, &dev->h_list);
+       else
+               list_add_tail_rcu(&handle->d_node, &dev->h_list);
+
        mutex_unlock(&dev->mutex);
 
        /*
index b1bd6dd..c52bec4 100644 (file)
@@ -286,6 +286,8 @@ static int joydev_open(struct inode *inode, struct file *file)
                goto err_free_client;
 
        file->private_data = client;
+       nonseekable_open(inode, file);
+
        return 0;
 
  err_free_client:
@@ -775,6 +777,20 @@ static void joydev_cleanup(struct joydev *joydev)
                input_close_device(handle);
 }
 
+
+static bool joydev_match(struct input_handler *handler, struct input_dev *dev)
+{
+       /* Avoid touchpads and touchscreens */
+       if (test_bit(EV_KEY, dev->evbit) && test_bit(BTN_TOUCH, dev->keybit))
+               return false;
+
+       /* Avoid tablets, digitisers and similar devices */
+       if (test_bit(EV_KEY, dev->evbit) && test_bit(BTN_DIGI, dev->keybit))
+               return false;
+
+       return true;
+}
+
 static int joydev_connect(struct input_handler *handler, struct input_dev *dev,
                          const struct input_device_id *id)
 {
@@ -894,22 +910,6 @@ static void joydev_disconnect(struct input_handle *handle)
        put_device(&joydev->dev);
 }
 
-static const struct input_device_id joydev_blacklist[] = {
-       {
-               .flags = INPUT_DEVICE_ID_MATCH_EVBIT |
-                               INPUT_DEVICE_ID_MATCH_KEYBIT,
-               .evbit = { BIT_MASK(EV_KEY) },
-               .keybit = { [BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH) },
-       },      /* Avoid itouchpads and touchscreens */
-       {
-               .flags = INPUT_DEVICE_ID_MATCH_EVBIT |
-                               INPUT_DEVICE_ID_MATCH_KEYBIT,
-               .evbit = { BIT_MASK(EV_KEY) },
-               .keybit = { [BIT_WORD(BTN_DIGI)] = BIT_MASK(BTN_DIGI) },
-       },      /* Avoid tablets, digitisers and similar devices */
-       { }     /* Terminating entry */
-};
-
 static const struct input_device_id joydev_ids[] = {
        {
                .flags = INPUT_DEVICE_ID_MATCH_EVBIT |
@@ -936,13 +936,13 @@ MODULE_DEVICE_TABLE(input, joydev_ids);
 
 static struct input_handler joydev_handler = {
        .event          = joydev_event,
+       .match          = joydev_match,
        .connect        = joydev_connect,
        .disconnect     = joydev_disconnect,
        .fops           = &joydev_fops,
        .minor          = JOYDEV_MINOR_BASE,
        .name           = "joydev",
        .id_table       = joydev_ids,
-       .blacklist      = joydev_blacklist,
 };
 
 static int __init joydev_init(void)
index b114195..5b59616 100644 (file)
@@ -221,6 +221,7 @@ config JOYSTICK_DB9
 config JOYSTICK_GAMECON
        tristate "Multisystem, NES, SNES, N64, PSX joysticks and gamepads"
        depends on PARPORT
+       select INPUT_FF_MEMLESS
        ---help---
          Say Y here if you have a Nintendo Entertainment System gamepad,
          Super Nintendo Entertainment System gamepad, Nintendo 64 gamepad,
index 07a32af..ae998d9 100644 (file)
@@ -30,6 +30,8 @@
  * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/kernel.h>
 #include <linux/delay.h>
 #include <linux/module.h>
@@ -61,48 +63,73 @@ MODULE_PARM_DESC(map3, "Describes third set of devices");
 
 /* see also gs_psx_delay parameter in PSX support section */
 
-#define GC_SNES                1
-#define GC_NES         2
-#define GC_NES4                3
-#define GC_MULTI       4
-#define GC_MULTI2      5
-#define GC_N64         6
-#define GC_PSX         7
-#define GC_DDR         8
-#define GC_SNESMOUSE   9
-
-#define GC_MAX         9
+enum gc_type {
+       GC_NONE = 0,
+       GC_SNES,
+       GC_NES,
+       GC_NES4,
+       GC_MULTI,
+       GC_MULTI2,
+       GC_N64,
+       GC_PSX,
+       GC_DDR,
+       GC_SNESMOUSE,
+       GC_MAX
+};
 
 #define GC_REFRESH_TIME        HZ/100
 
+struct gc_pad {
+       struct input_dev *dev;
+       enum gc_type type;
+       char phys[32];
+};
+
 struct gc {
        struct pardevice *pd;
+       struct gc_pad pads[GC_MAX_DEVICES];
        struct input_dev *dev[GC_MAX_DEVICES];
        struct timer_list timer;
-       unsigned char pads[GC_MAX + 1];
+       int pad_count[GC_MAX];
        int used;
        struct mutex mutex;
-       char phys[GC_MAX_DEVICES][32];
+};
+
+struct gc_subdev {
+       unsigned int idx;
 };
 
 static struct gc *gc_base[3];
 
-static int gc_status_bit[] = { 0x40, 0x80, 0x20, 0x10, 0x08 };
+static const int gc_status_bit[] = { 0x40, 0x80, 0x20, 0x10, 0x08 };
+
+static const char *gc_names[] = {
+       NULL, "SNES pad", "NES pad", "NES FourPort", "Multisystem joystick",
+       "Multisystem 2-button joystick", "N64 controller", "PSX controller",
+       "PSX DDR controller", "SNES mouse"
+};
 
-static char *gc_names[] = { NULL, "SNES pad", "NES pad", "NES FourPort", "Multisystem joystick",
-                               "Multisystem 2-button joystick", "N64 controller", "PSX controller",
-                               "PSX DDR controller", "SNES mouse" };
 /*
  * N64 support.
  */
 
-static unsigned char gc_n64_bytes[] = { 0, 1, 13, 15, 14, 12, 10, 11, 2, 3 };
-static short gc_n64_btn[] = { BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_TL, BTN_TR, BTN_TRIGGER, BTN_START };
+static const unsigned char gc_n64_bytes[] = { 0, 1, 13, 15, 14, 12, 10, 11, 2, 3 };
+static const short gc_n64_btn[] = {
+       BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z,
+       BTN_TL, BTN_TR, BTN_TRIGGER, BTN_START
+};
 
 #define GC_N64_LENGTH          32              /* N64 bit length, not including stop bit */
-#define GC_N64_REQUEST_LENGTH  37              /* transmit request sequence is 9 bits long */
+#define GC_N64_STOP_LENGTH     5               /* Length of encoded stop bit */
+#define GC_N64_CMD_00          0x11111111UL
+#define GC_N64_CMD_01          0xd1111111UL
+#define GC_N64_CMD_03          0xdd111111UL
+#define GC_N64_CMD_1b          0xdd1dd111UL
+#define GC_N64_CMD_c0          0x111111ddUL
+#define GC_N64_CMD_80          0x1111111dUL
+#define GC_N64_STOP_BIT                0x1d            /* Encoded stop bit */
+#define GC_N64_REQUEST_DATA    GC_N64_CMD_01   /* the request data command */
 #define GC_N64_DELAY           133             /* delay between transmit request, and response ready (us) */
-#define GC_N64_REQUEST         0x1dd1111111ULL /* the request data command (encoded for 000000011) */
 #define GC_N64_DWS             3               /* delay between write segments (required for sound playback because of ISA DMA) */
                                                /* GC_N64_DWS > 24 is known to fail */
 #define GC_N64_POWER_W         0xe2            /* power during write (transmit request) */
@@ -114,8 +141,40 @@ static short gc_n64_btn[] = { BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_TL,
 #define GC_N64_CLOCK           0x02            /* clock bits for read */
 
 /*
+ * Used for rumble code.
+ */
+
+/* Send encoded command */
+static void gc_n64_send_command(struct gc *gc, unsigned long cmd,
+                               unsigned char target)
+{
+       struct parport *port = gc->pd->port;
+       int i;
+
+       for (i = 0; i < GC_N64_LENGTH; i++) {
+               unsigned char data = (cmd >> i) & 1 ? target : 0;
+               parport_write_data(port, GC_N64_POWER_W | data);
+               udelay(GC_N64_DWS);
+       }
+}
+
+/* Send stop bit */
+static void gc_n64_send_stop_bit(struct gc *gc, unsigned char target)
+{
+       struct parport *port = gc->pd->port;
+       int i;
+
+       for (i = 0; i < GC_N64_STOP_LENGTH; i++) {
+               unsigned char data = (GC_N64_STOP_BIT >> i) & 1 ? target : 0;
+               parport_write_data(port, GC_N64_POWER_W | data);
+               udelay(GC_N64_DWS);
+       }
+}
+
+/*
  * gc_n64_read_packet() reads an N64 packet.
- * Each pad uses one bit per byte. So all pads connected to this port are read in parallel.
+ * Each pad uses one bit per byte. So all pads connected to this port
+ * are read in parallel.
  */
 
 static void gc_n64_read_packet(struct gc *gc, unsigned char *data)
@@ -128,14 +187,13 @@ static void gc_n64_read_packet(struct gc *gc, unsigned char *data)
  */
 
        local_irq_save(flags);
-       for (i = 0; i < GC_N64_REQUEST_LENGTH; i++) {
-               parport_write_data(gc->pd->port, GC_N64_POWER_W | ((GC_N64_REQUEST >> i) & 1 ? GC_N64_OUT : 0));
-               udelay(GC_N64_DWS);
-       }
+       gc_n64_send_command(gc, GC_N64_REQUEST_DATA, GC_N64_OUT);
+       gc_n64_send_stop_bit(gc, GC_N64_OUT);
        local_irq_restore(flags);
 
 /*
- * Wait for the pad response to be loaded into the 33-bit register of the adapter
+ * Wait for the pad response to be loaded into the 33-bit register
+ * of the adapter.
  */
 
        udelay(GC_N64_DELAY);
@@ -146,13 +204,15 @@ static void gc_n64_read_packet(struct gc *gc, unsigned char *data)
 
        for (i = 0; i < GC_N64_LENGTH; i++) {
                parport_write_data(gc->pd->port, GC_N64_POWER_R);
+               udelay(2);
                data[i] = parport_read_status(gc->pd->port);
                parport_write_data(gc->pd->port, GC_N64_POWER_R | GC_N64_CLOCK);
         }
 
 /*
- * We must wait 200 ms here for the controller to reinitialize before the next read request.
- * No worries as long as gc_read is polled less frequently than this.
+ * We must wait 200 ms here for the controller to reinitialize before
+ * the next read request. No worries as long as gc_read is polled less
+ * frequently than this.
  */
 
 }
@@ -160,45 +220,112 @@ static void gc_n64_read_packet(struct gc *gc, unsigned char *data)
 static void gc_n64_process_packet(struct gc *gc)
 {
        unsigned char data[GC_N64_LENGTH];
-       signed char axes[2];
        struct input_dev *dev;
        int i, j, s;
+       signed char x, y;
 
        gc_n64_read_packet(gc, data);
 
        for (i = 0; i < GC_MAX_DEVICES; i++) {
 
-               dev = gc->dev[i];
-               if (!dev)
+               if (gc->pads[i].type != GC_N64)
                        continue;
 
+               dev = gc->pads[i].dev;
                s = gc_status_bit[i];
 
-               if (s & gc->pads[GC_N64] & ~(data[8] | data[9])) {
+               if (s & ~(data[8] | data[9])) {
 
-                       axes[0] = axes[1] = 0;
+                       x = y = 0;
 
                        for (j = 0; j < 8; j++) {
                                if (data[23 - j] & s)
-                                       axes[0] |= 1 << j;
+                                       x |= 1 << j;
                                if (data[31 - j] & s)
-                                       axes[1] |= 1 << j;
+                                       y |= 1 << j;
                        }
 
-                       input_report_abs(dev, ABS_X,  axes[0]);
-                       input_report_abs(dev, ABS_Y, -axes[1]);
+                       input_report_abs(dev, ABS_X,  x);
+                       input_report_abs(dev, ABS_Y, -y);
 
-                       input_report_abs(dev, ABS_HAT0X, !(s & data[6]) - !(s & data[7]));
-                       input_report_abs(dev, ABS_HAT0Y, !(s & data[4]) - !(s & data[5]));
+                       input_report_abs(dev, ABS_HAT0X,
+                                        !(s & data[6]) - !(s & data[7]));
+                       input_report_abs(dev, ABS_HAT0Y,
+                                        !(s & data[4]) - !(s & data[5]));
 
                        for (j = 0; j < 10; j++)
-                               input_report_key(dev, gc_n64_btn[j], s & data[gc_n64_bytes[j]]);
+                               input_report_key(dev, gc_n64_btn[j],
+                                                s & data[gc_n64_bytes[j]]);
 
                        input_sync(dev);
                }
        }
 }
 
+static int gc_n64_play_effect(struct input_dev *dev, void *data,
+                             struct ff_effect *effect)
+{
+       int i;
+       unsigned long flags;
+       struct gc *gc = input_get_drvdata(dev);
+       struct gc_subdev *sdev = data;
+       unsigned char target = 1 << sdev->idx; /* select desired pin */
+
+       if (effect->type == FF_RUMBLE) {
+               struct ff_rumble_effect *rumble = &effect->u.rumble;
+               unsigned int cmd =
+                       rumble->strong_magnitude || rumble->weak_magnitude ?
+                       GC_N64_CMD_01 : GC_N64_CMD_00;
+
+               local_irq_save(flags);
+
+               /* Init Rumble - 0x03, 0x80, 0x01, (34)0x80 */
+               gc_n64_send_command(gc, GC_N64_CMD_03, target);
+               gc_n64_send_command(gc, GC_N64_CMD_80, target);
+               gc_n64_send_command(gc, GC_N64_CMD_01, target);
+               for (i = 0; i < 32; i++)
+                       gc_n64_send_command(gc, GC_N64_CMD_80, target);
+               gc_n64_send_stop_bit(gc, target);
+
+               udelay(GC_N64_DELAY);
+
+               /* Now start or stop it - 0x03, 0xc0, 0zx1b, (32)0x01/0x00 */
+               gc_n64_send_command(gc, GC_N64_CMD_03, target);
+               gc_n64_send_command(gc, GC_N64_CMD_c0, target);
+               gc_n64_send_command(gc, GC_N64_CMD_1b, target);
+               for (i = 0; i < 32; i++)
+                       gc_n64_send_command(gc, cmd, target);
+               gc_n64_send_stop_bit(gc, target);
+
+               local_irq_restore(flags);
+
+       }
+
+       return 0;
+}
+
+static int __init gc_n64_init_ff(struct input_dev *dev, int i)
+{
+       struct gc_subdev *sdev;
+       int err;
+
+       sdev = kmalloc(sizeof(*sdev), GFP_KERNEL);
+       if (!sdev)
+               return -ENOMEM;
+
+       sdev->idx = i;
+
+       input_set_capability(dev, EV_FF, FF_RUMBLE);
+
+       err = input_ff_create_memless(dev, sdev, gc_n64_play_effect);
+       if (err) {
+               kfree(sdev);
+               return err;
+       }
+
+       return 0;
+}
+
 /*
  * NES/SNES support.
  */
@@ -214,9 +341,11 @@ static void gc_n64_process_packet(struct gc *gc)
 #define GC_NES_CLOCK   0x01
 #define GC_NES_LATCH   0x02
 
-static unsigned char gc_nes_bytes[] = { 0, 1, 2, 3 };
-static unsigned char gc_snes_bytes[] = { 8, 0, 2, 3, 9, 1, 10, 11 };
-static short gc_snes_btn[] = { BTN_A, BTN_B, BTN_SELECT, BTN_START, BTN_X, BTN_Y, BTN_TL, BTN_TR };
+static const unsigned char gc_nes_bytes[] = { 0, 1, 2, 3 };
+static const unsigned char gc_snes_bytes[] = { 8, 0, 2, 3, 9, 1, 10, 11 };
+static const short gc_snes_btn[] = {
+       BTN_A, BTN_B, BTN_SELECT, BTN_START, BTN_X, BTN_Y, BTN_TL, BTN_TR
+};
 
 /*
  * gc_nes_read_packet() reads a NES/SNES packet.
@@ -244,40 +373,51 @@ static void gc_nes_read_packet(struct gc *gc, int length, unsigned char *data)
 static void gc_nes_process_packet(struct gc *gc)
 {
        unsigned char data[GC_SNESMOUSE_LENGTH];
+       struct gc_pad *pad;
        struct input_dev *dev;
        int i, j, s, len;
        char x_rel, y_rel;
 
-       len = gc->pads[GC_SNESMOUSE] ? GC_SNESMOUSE_LENGTH :
-                       (gc->pads[GC_SNES] ? GC_SNES_LENGTH : GC_NES_LENGTH);
+       len = gc->pad_count[GC_SNESMOUSE] ? GC_SNESMOUSE_LENGTH :
+                       (gc->pad_count[GC_SNES] ? GC_SNES_LENGTH : GC_NES_LENGTH);
 
        gc_nes_read_packet(gc, len, data);
 
        for (i = 0; i < GC_MAX_DEVICES; i++) {
 
+               pad = &gc->pads[i];
                dev = gc->dev[i];
-               if (!dev)
-                       continue;
-
                s = gc_status_bit[i];
 
-               if (s & (gc->pads[GC_NES] | gc->pads[GC_SNES])) {
+               switch (pad->type) {
+
+               case GC_NES:
+
                        input_report_abs(dev, ABS_X, !(s & data[6]) - !(s & data[7]));
                        input_report_abs(dev, ABS_Y, !(s & data[4]) - !(s & data[5]));
-               }
 
-               if (s & gc->pads[GC_NES])
                        for (j = 0; j < 4; j++)
-                               input_report_key(dev, gc_snes_btn[j], s & data[gc_nes_bytes[j]]);
+                               input_report_key(dev, gc_snes_btn[j],
+                                                s & data[gc_nes_bytes[j]]);
+                       input_sync(dev);
+                       break;
+
+               case GC_SNES:
+
+                       input_report_abs(dev, ABS_X, !(s & data[6]) - !(s & data[7]));
+                       input_report_abs(dev, ABS_Y, !(s & data[4]) - !(s & data[5]));
 
-               if (s & gc->pads[GC_SNES])
                        for (j = 0; j < 8; j++)
-                               input_report_key(dev, gc_snes_btn[j], s & data[gc_snes_bytes[j]]);
+                               input_report_key(dev, gc_snes_btn[j],
+                                                s & data[gc_snes_bytes[j]]);
+                       input_sync(dev);
+                       break;
 
-               if (s & gc->pads[GC_SNESMOUSE]) {
+               case GC_SNESMOUSE:
                        /*
-                        * The 4 unused bits from SNES controllers appear to be ID bits
-                        * so use them to make sure iwe are dealing with a mouse.
+                        * The 4 unused bits from SNES controllers appear
+                        * to be ID bits so use them to make sure we are
+                        * dealing with a mouse.
                         * gamepad is connected. This is important since
                         * my SNES gamepad sends 1's for bits 16-31, which
                         * cause the mouse pointer to quickly move to the
@@ -310,9 +450,14 @@ static void gc_nes_process_packet(struct gc *gc)
                                                y_rel = -y_rel;
                                        input_report_rel(dev, REL_Y, y_rel);
                                }
+
+                               input_sync(dev);
                        }
+                       break;
+
+               default:
+                       break;
                }
-               input_sync(dev);
        }
 }
 
@@ -340,29 +485,35 @@ static void gc_multi_read_packet(struct gc *gc, int length, unsigned char *data)
 static void gc_multi_process_packet(struct gc *gc)
 {
        unsigned char data[GC_MULTI2_LENGTH];
+       int data_len = gc->pad_count[GC_MULTI2] ? GC_MULTI2_LENGTH : GC_MULTI_LENGTH;
+       struct gc_pad *pad;
        struct input_dev *dev;
        int i, s;
 
-       gc_multi_read_packet(gc, gc->pads[GC_MULTI2] ? GC_MULTI2_LENGTH : GC_MULTI_LENGTH, data);
+       gc_multi_read_packet(gc, data_len, data);
 
        for (i = 0; i < GC_MAX_DEVICES; i++) {
-
-               dev = gc->dev[i];
-               if (!dev)
-                       continue;
-
+               pad = &gc->pads[i];
+               dev = pad->dev;
                s = gc_status_bit[i];
 
-               if (s & (gc->pads[GC_MULTI] | gc->pads[GC_MULTI2])) {
-                       input_report_abs(dev, ABS_X,  !(s & data[2]) - !(s & data[3]));
-                       input_report_abs(dev, ABS_Y,  !(s & data[0]) - !(s & data[1]));
-                       input_report_key(dev, BTN_TRIGGER, s & data[4]);
-               }
-
-               if (s & gc->pads[GC_MULTI2])
+               switch (pad->type) {
+               case GC_MULTI2:
                        input_report_key(dev, BTN_THUMB, s & data[5]);
+                       /* fall through */
 
-               input_sync(dev);
+               case GC_MULTI:
+                       input_report_abs(dev, ABS_X,
+                                        !(s & data[2]) - !(s & data[3]));
+                       input_report_abs(dev, ABS_Y,
+                                        !(s & data[0]) - !(s & data[1]));
+                       input_report_key(dev, BTN_TRIGGER, s & data[4]);
+                       input_sync(dev);
+                       break;
+
+               default:
+                       break;
+               }
        }
 }
 
@@ -398,30 +549,41 @@ static int gc_psx_delay = GC_PSX_DELAY;
 module_param_named(psx_delay, gc_psx_delay, uint, 0);
 MODULE_PARM_DESC(psx_delay, "Delay when accessing Sony PSX controller (usecs)");
 
-static short gc_psx_abs[] = { ABS_X, ABS_Y, ABS_RX, ABS_RY, ABS_HAT0X, ABS_HAT0Y };
-static short gc_psx_btn[] = { BTN_TL, BTN_TR, BTN_TL2, BTN_TR2, BTN_A, BTN_B, BTN_X, BTN_Y,
-                               BTN_START, BTN_SELECT, BTN_THUMBL, BTN_THUMBR };
-static short gc_psx_ddr_btn[] = { BTN_0, BTN_1, BTN_2, BTN_3 };
+static const short gc_psx_abs[] = {
+       ABS_X, ABS_Y, ABS_RX, ABS_RY, ABS_HAT0X, ABS_HAT0Y
+};
+static const short gc_psx_btn[] = {
+       BTN_TL, BTN_TR, BTN_TL2, BTN_TR2, BTN_A, BTN_B, BTN_X, BTN_Y,
+       BTN_START, BTN_SELECT, BTN_THUMBL, BTN_THUMBR
+};
+static const short gc_psx_ddr_btn[] = { BTN_0, BTN_1, BTN_2, BTN_3 };
 
 /*
  * gc_psx_command() writes 8bit command and reads 8bit data from
  * the psx pad.
  */
 
-static void gc_psx_command(struct gc *gc, int b, unsigned char data[GC_MAX_DEVICES])
+static void gc_psx_command(struct gc *gc, int b, unsigned char *data)
 {
+       struct parport *port = gc->pd->port;
        int i, j, cmd, read;
 
-       for (i = 0; i < GC_MAX_DEVICES; i++)
-               data[i] = 0;
+       memset(data, 0, GC_MAX_DEVICES);
 
        for (i = 0; i < GC_PSX_LENGTH; i++, b >>= 1) {
                cmd = (b & 1) ? GC_PSX_COMMAND : 0;
-               parport_write_data(gc->pd->port, cmd | GC_PSX_POWER);
+               parport_write_data(port, cmd | GC_PSX_POWER);
                udelay(gc_psx_delay);
-               read = parport_read_status(gc->pd->port) ^ 0x80;
-               for (j = 0; j < GC_MAX_DEVICES; j++)
-                       data[j] |= (read & gc_status_bit[j] & (gc->pads[GC_PSX] | gc->pads[GC_DDR])) ? (1 << i) : 0;
+
+               read = parport_read_status(port) ^ 0x80;
+
+               for (j = 0; j < GC_MAX_DEVICES; j++) {
+                       struct gc_pad *pad = &gc->pads[i];
+
+                       if (pad->type == GC_PSX || pad->type == GC_DDR)
+                               data[j] |= (read & gc_status_bit[j]) ? (1 << i) : 0;
+               }
+
                parport_write_data(gc->pd->port, cmd | GC_PSX_CLOCK | GC_PSX_POWER);
                udelay(gc_psx_delay);
        }
@@ -432,31 +594,40 @@ static void gc_psx_command(struct gc *gc, int b, unsigned char data[GC_MAX_DEVIC
  * device identifier code.
  */
 
-static void gc_psx_read_packet(struct gc *gc, unsigned char data[GC_MAX_DEVICES][GC_PSX_BYTES],
+static void gc_psx_read_packet(struct gc *gc,
+                              unsigned char data[GC_MAX_DEVICES][GC_PSX_BYTES],
                               unsigned char id[GC_MAX_DEVICES])
 {
        int i, j, max_len = 0;
        unsigned long flags;
        unsigned char data2[GC_MAX_DEVICES];
 
-       parport_write_data(gc->pd->port, GC_PSX_CLOCK | GC_PSX_SELECT | GC_PSX_POWER);  /* Select pad */
+       /* Select pad */
+       parport_write_data(gc->pd->port, GC_PSX_CLOCK | GC_PSX_SELECT | GC_PSX_POWER);
        udelay(gc_psx_delay);
-       parport_write_data(gc->pd->port, GC_PSX_CLOCK | GC_PSX_POWER);                  /* Deselect, begin command */
+       /* Deselect, begin command */
+       parport_write_data(gc->pd->port, GC_PSX_CLOCK | GC_PSX_POWER);
        udelay(gc_psx_delay);
 
        local_irq_save(flags);
 
-       gc_psx_command(gc, 0x01, data2);                                                /* Access pad */
-       gc_psx_command(gc, 0x42, id);                                                   /* Get device ids */
-       gc_psx_command(gc, 0, data2);                                                   /* Dump status */
+       gc_psx_command(gc, 0x01, data2);        /* Access pad */
+       gc_psx_command(gc, 0x42, id);           /* Get device ids */
+       gc_psx_command(gc, 0, data2);           /* Dump status */
+
+       /* Find the longest pad */
+       for (i = 0; i < GC_MAX_DEVICES; i++) {
+               struct gc_pad *pad = &gc->pads[i];
 
-       for (i =0; i < GC_MAX_DEVICES; i++)                                                             /* Find the longest pad */
-               if((gc_status_bit[i] & (gc->pads[GC_PSX] | gc->pads[GC_DDR]))
-                       && (GC_PSX_LEN(id[i]) > max_len)
-                       && (GC_PSX_LEN(id[i]) <= GC_PSX_BYTES))
+               if ((pad->type == GC_PSX || pad->type == GC_DDR) &&
+                   GC_PSX_LEN(id[i]) > max_len &&
+                   GC_PSX_LEN(id[i]) <= GC_PSX_BYTES) {
                        max_len = GC_PSX_LEN(id[i]);
+               }
+       }
 
-       for (i = 0; i < max_len; i++) {                                         /* Read in all the data */
+       /* Read in all the data */
+       for (i = 0; i < max_len; i++) {
                gc_psx_command(gc, 0, data2);
                for (j = 0; j < GC_MAX_DEVICES; j++)
                        data[j][i] = data2[j];
@@ -466,86 +637,104 @@ static void gc_psx_read_packet(struct gc *gc, unsigned char data[GC_MAX_DEVICES]
 
        parport_write_data(gc->pd->port, GC_PSX_CLOCK | GC_PSX_SELECT | GC_PSX_POWER);
 
-       for(i = 0; i < GC_MAX_DEVICES; i++)                                                             /* Set id's to the real value */
+       /* Set id's to the real value */
+       for (i = 0; i < GC_MAX_DEVICES; i++)
                id[i] = GC_PSX_ID(id[i]);
 }
 
-static void gc_psx_process_packet(struct gc *gc)
+static void gc_psx_report_one(struct gc_pad *pad, unsigned char psx_type,
+                             unsigned char *data)
 {
-       unsigned char data[GC_MAX_DEVICES][GC_PSX_BYTES];
-       unsigned char id[GC_MAX_DEVICES];
-       struct input_dev *dev;
-       int i, j;
+       struct input_dev *dev = pad->dev;
+       int i;
 
-       gc_psx_read_packet(gc, data, id);
+       switch (psx_type) {
 
-       for (i = 0; i < GC_MAX_DEVICES; i++) {
+       case GC_PSX_RUMBLE:
 
-               dev = gc->dev[i];
-               if (!dev)
-                       continue;
+               input_report_key(dev, BTN_THUMBL, ~data[0] & 0x04);
+               input_report_key(dev, BTN_THUMBR, ~data[0] & 0x02);
 
-               switch (id[i]) {
+       case GC_PSX_NEGCON:
+       case GC_PSX_ANALOG:
 
-                       case GC_PSX_RUMBLE:
+               if (pad->type == GC_DDR) {
+                       for (i = 0; i < 4; i++)
+                               input_report_key(dev, gc_psx_ddr_btn[i],
+                                                ~data[0] & (0x10 << i));
+               } else {
+                       for (i = 0; i < 4; i++)
+                               input_report_abs(dev, gc_psx_abs[i + 2],
+                                                data[i + 2]);
 
-                               input_report_key(dev, BTN_THUMBL, ~data[i][0] & 0x04);
-                               input_report_key(dev, BTN_THUMBR, ~data[i][0] & 0x02);
+                       input_report_abs(dev, ABS_X,
+                               !!(data[0] & 0x80) * 128 + !(data[0] & 0x20) * 127);
+                       input_report_abs(dev, ABS_Y,
+                               !!(data[0] & 0x10) * 128 + !(data[0] & 0x40) * 127);
+               }
 
-                       case GC_PSX_NEGCON:
-                       case GC_PSX_ANALOG:
+               for (i = 0; i < 8; i++)
+                       input_report_key(dev, gc_psx_btn[i], ~data[1] & (1 << i));
 
-                               if (gc->pads[GC_DDR] & gc_status_bit[i]) {
-                                       for(j = 0; j < 4; j++)
-                                               input_report_key(dev, gc_psx_ddr_btn[j], ~data[i][0] & (0x10 << j));
-                               } else {
-                                       for (j = 0; j < 4; j++)
-                                               input_report_abs(dev, gc_psx_abs[j + 2], data[i][j + 2]);
+               input_report_key(dev, BTN_START,  ~data[0] & 0x08);
+               input_report_key(dev, BTN_SELECT, ~data[0] & 0x01);
 
-                                       input_report_abs(dev, ABS_X, 128 + !(data[i][0] & 0x20) * 127 - !(data[i][0] & 0x80) * 128);
-                                       input_report_abs(dev, ABS_Y, 128 + !(data[i][0] & 0x40) * 127 - !(data[i][0] & 0x10) * 128);
-                               }
+               input_sync(dev);
 
-                               for (j = 0; j < 8; j++)
-                                       input_report_key(dev, gc_psx_btn[j], ~data[i][1] & (1 << j));
+               break;
 
-                               input_report_key(dev, BTN_START,  ~data[i][0] & 0x08);
-                               input_report_key(dev, BTN_SELECT, ~data[i][0] & 0x01);
+       case GC_PSX_NORMAL:
 
-                               input_sync(dev);
+               if (pad->type == GC_DDR) {
+                       for (i = 0; i < 4; i++)
+                               input_report_key(dev, gc_psx_ddr_btn[i],
+                                                ~data[0] & (0x10 << i));
+               } else {
+                       input_report_abs(dev, ABS_X,
+                               !!(data[0] & 0x80) * 128 + !(data[0] & 0x20) * 127);
+                       input_report_abs(dev, ABS_Y,
+                               !!(data[0] & 0x10) * 128 + !(data[0] & 0x40) * 127);
 
-                               break;
-
-                       case GC_PSX_NORMAL:
-                               if (gc->pads[GC_DDR] & gc_status_bit[i]) {
-                                       for(j = 0; j < 4; j++)
-                                               input_report_key(dev, gc_psx_ddr_btn[j], ~data[i][0] & (0x10 << j));
-                               } else {
-                                       input_report_abs(dev, ABS_X, 128 + !(data[i][0] & 0x20) * 127 - !(data[i][0] & 0x80) * 128);
-                                       input_report_abs(dev, ABS_Y, 128 + !(data[i][0] & 0x40) * 127 - !(data[i][0] & 0x10) * 128);
-
-                                       /* for some reason if the extra axes are left unset they drift */
-                                       /* for (j = 0; j < 4; j++)
-                                               input_report_abs(dev, gc_psx_abs[j + 2], 128);
-                                        * This needs to be debugged properly,
-                                        * maybe fuzz processing needs to be done in input_sync()
-                                        *                               --vojtech
-                                        */
-                               }
+                       /*
+                        * For some reason if the extra axes are left unset
+                        * they drift.
+                        * for (i = 0; i < 4; i++)
+                               input_report_abs(dev, gc_psx_abs[i + 2], 128);
+                        * This needs to be debugged properly,
+                        * maybe fuzz processing needs to be done
+                        * in input_sync()
+                        *                               --vojtech
+                        */
+               }
 
-                               for (j = 0; j < 8; j++)
-                                       input_report_key(dev, gc_psx_btn[j], ~data[i][1] & (1 << j));
+               for (i = 0; i < 8; i++)
+                       input_report_key(dev, gc_psx_btn[i], ~data[1] & (1 << i));
 
-                               input_report_key(dev, BTN_START,  ~data[i][0] & 0x08);
-                               input_report_key(dev, BTN_SELECT, ~data[i][0] & 0x01);
+               input_report_key(dev, BTN_START,  ~data[0] & 0x08);
+               input_report_key(dev, BTN_SELECT, ~data[0] & 0x01);
 
-                               input_sync(dev);
+               input_sync(dev);
 
-                               break;
+               break;
 
-                       case 0: /* not a pad, ignore */
-                               break;
-               }
+       default: /* not a pad, ignore */
+               break;
+       }
+}
+
+static void gc_psx_process_packet(struct gc *gc)
+{
+       unsigned char data[GC_MAX_DEVICES][GC_PSX_BYTES];
+       unsigned char id[GC_MAX_DEVICES];
+       struct gc_pad *pad;
+       int i;
+
+       gc_psx_read_packet(gc, data, id);
+
+       for (i = 0; i < GC_MAX_DEVICES; i++) {
+               pad = &gc->pads[i];
+               if (pad->type == GC_PSX || pad->type == GC_DDR)
+                       gc_psx_report_one(pad, id[i], data[i]);
        }
 }
 
@@ -561,28 +750,31 @@ static void gc_timer(unsigned long private)
  * N64 pads - must be read first, any read confuses them for 200 us
  */
 
-       if (gc->pads[GC_N64])
+       if (gc->pad_count[GC_N64])
                gc_n64_process_packet(gc);
 
 /*
  * NES and SNES pads or mouse
  */
 
-       if (gc->pads[GC_NES] || gc->pads[GC_SNES] || gc->pads[GC_SNESMOUSE])
+       if (gc->pad_count[GC_NES] ||
+           gc->pad_count[GC_SNES] ||
+           gc->pad_count[GC_SNESMOUSE]) {
                gc_nes_process_packet(gc);
+       }
 
 /*
  * Multi and Multi2 joysticks
  */
 
-       if (gc->pads[GC_MULTI] || gc->pads[GC_MULTI2])
+       if (gc->pad_count[GC_MULTI] || gc->pad_count[GC_MULTI2])
                gc_multi_process_packet(gc);
 
 /*
  * PSX controllers
  */
 
-       if (gc->pads[GC_PSX] || gc->pads[GC_DDR])
+       if (gc->pad_count[GC_PSX] || gc->pad_count[GC_DDR])
                gc_psx_process_packet(gc);
 
        mod_timer(&gc->timer, jiffies + GC_REFRESH_TIME);
@@ -622,25 +814,29 @@ static void gc_close(struct input_dev *dev)
 
 static int __init gc_setup_pad(struct gc *gc, int idx, int pad_type)
 {
+       struct gc_pad *pad = &gc->pads[idx];
        struct input_dev *input_dev;
        int i;
-
-       if (!pad_type)
-               return 0;
+       int err;
 
        if (pad_type < 1 || pad_type > GC_MAX) {
-               printk(KERN_WARNING "gamecon.c: Pad type %d unknown\n", pad_type);
+               pr_err("Pad type %d unknown\n", pad_type);
                return -EINVAL;
        }
 
-       gc->dev[idx] = input_dev = input_allocate_device();
+       pad->dev = input_dev = input_allocate_device();
        if (!input_dev) {
-               printk(KERN_ERR "gamecon.c: Not enough memory for input device\n");
+               pr_err("Not enough memory for input device\n");
                return -ENOMEM;
        }
 
+       pad->type = pad_type;
+
+       snprintf(pad->phys, sizeof(pad->phys),
+                "%s/input%d", gc->pd->port->name, idx);
+
        input_dev->name = gc_names[pad_type];
-       input_dev->phys = gc->phys[idx];
+       input_dev->phys = pad->phys;
        input_dev->id.bustype = BUS_PARPORT;
        input_dev->id.vendor = 0x0001;
        input_dev->id.product = pad_type;
@@ -659,61 +855,76 @@ static int __init gc_setup_pad(struct gc *gc, int idx, int pad_type)
        } else
                input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL);
 
-       gc->pads[0] |= gc_status_bit[idx];
-       gc->pads[pad_type] |= gc_status_bit[idx];
+       gc->pad_count[pad_type]++;
 
        switch (pad_type) {
 
-               case GC_N64:
-                       for (i = 0; i < 10; i++)
-                               set_bit(gc_n64_btn[i], input_dev->keybit);
-
-                       for (i = 0; i < 2; i++) {
-                               input_set_abs_params(input_dev, ABS_X + i, -127, 126, 0, 2);
-                               input_set_abs_params(input_dev, ABS_HAT0X + i, -1, 1, 0, 0);
-                       }
-
-                       break;
-
-               case GC_SNESMOUSE:
-                       set_bit(BTN_LEFT, input_dev->keybit);
-                       set_bit(BTN_RIGHT, input_dev->keybit);
-                       set_bit(REL_X, input_dev->relbit);
-                       set_bit(REL_Y, input_dev->relbit);
-                       break;
-
-               case GC_SNES:
-                       for (i = 4; i < 8; i++)
-                               set_bit(gc_snes_btn[i], input_dev->keybit);
-               case GC_NES:
-                       for (i = 0; i < 4; i++)
-                               set_bit(gc_snes_btn[i], input_dev->keybit);
-                       break;
-
-               case GC_MULTI2:
-                       set_bit(BTN_THUMB, input_dev->keybit);
-               case GC_MULTI:
-                       set_bit(BTN_TRIGGER, input_dev->keybit);
-                       break;
-
-               case GC_PSX:
-                       for (i = 0; i < 6; i++)
-                               input_set_abs_params(input_dev, gc_psx_abs[i], 4, 252, 0, 2);
-                       for (i = 0; i < 12; i++)
-                               set_bit(gc_psx_btn[i], input_dev->keybit);
+       case GC_N64:
+               for (i = 0; i < 10; i++)
+                       __set_bit(gc_n64_btn[i], input_dev->keybit);
 
-                       break;
+               for (i = 0; i < 2; i++) {
+                       input_set_abs_params(input_dev, ABS_X + i, -127, 126, 0, 2);
+                       input_set_abs_params(input_dev, ABS_HAT0X + i, -1, 1, 0, 0);
+               }
 
-               case GC_DDR:
-                       for (i = 0; i < 4; i++)
-                               set_bit(gc_psx_ddr_btn[i], input_dev->keybit);
-                       for (i = 0; i < 12; i++)
-                               set_bit(gc_psx_btn[i], input_dev->keybit);
+               err = gc_n64_init_ff(input_dev, idx);
+               if (err) {
+                       pr_warning("Failed to initiate rumble for N64 device %d\n", idx);
+                       goto err_free_dev;
+               }
 
-                       break;
+               break;
+
+       case GC_SNESMOUSE:
+               __set_bit(BTN_LEFT, input_dev->keybit);
+               __set_bit(BTN_RIGHT, input_dev->keybit);
+               __set_bit(REL_X, input_dev->relbit);
+               __set_bit(REL_Y, input_dev->relbit);
+               break;
+
+       case GC_SNES:
+               for (i = 4; i < 8; i++)
+                       __set_bit(gc_snes_btn[i], input_dev->keybit);
+       case GC_NES:
+               for (i = 0; i < 4; i++)
+                       __set_bit(gc_snes_btn[i], input_dev->keybit);
+               break;
+
+       case GC_MULTI2:
+               __set_bit(BTN_THUMB, input_dev->keybit);
+       case GC_MULTI:
+               __set_bit(BTN_TRIGGER, input_dev->keybit);
+               break;
+
+       case GC_PSX:
+               for (i = 0; i < 6; i++)
+                       input_set_abs_params(input_dev,
+                                            gc_psx_abs[i], 4, 252, 0, 2);
+               for (i = 0; i < 12; i++)
+                       __set_bit(gc_psx_btn[i], input_dev->keybit);
+
+               break;
+
+       case GC_DDR:
+               for (i = 0; i < 4; i++)
+                       __set_bit(gc_psx_ddr_btn[i], input_dev->keybit);
+               for (i = 0; i < 12; i++)
+                       __set_bit(gc_psx_btn[i], input_dev->keybit);
+
+               break;
        }
 
+       err = input_register_device(pad->dev);
+       if (err)
+               goto err_free_dev;
+
        return 0;
+
+err_free_dev:
+       input_free_device(pad->dev);
+       pad->dev = NULL;
+       return err;
 }
 
 static struct gc __init *gc_probe(int parport, int *pads, int n_pads)
@@ -722,52 +933,47 @@ static struct gc __init *gc_probe(int parport, int *pads, int n_pads)
        struct parport *pp;
        struct pardevice *pd;
        int i;
+       int count = 0;
        int err;
 
        pp = parport_find_number(parport);
        if (!pp) {
-               printk(KERN_ERR "gamecon.c: no such parport\n");
+               pr_err("no such parport %d\n", parport);
                err = -EINVAL;
                goto err_out;
        }
 
        pd = parport_register_device(pp, "gamecon", NULL, NULL, NULL, PARPORT_DEV_EXCL, NULL);
        if (!pd) {
-               printk(KERN_ERR "gamecon.c: parport busy already - lp.o loaded?\n");
+               pr_err("parport busy already - lp.o loaded?\n");
                err = -EBUSY;
                goto err_put_pp;
        }
 
        gc = kzalloc(sizeof(struct gc), GFP_KERNEL);
        if (!gc) {
-               printk(KERN_ERR "gamecon.c: Not enough memory\n");
+               pr_err("Not enough memory\n");
                err = -ENOMEM;
                goto err_unreg_pardev;
        }
 
        mutex_init(&gc->mutex);
        gc->pd = pd;
-       init_timer(&gc->timer);
-       gc->timer.data = (long) gc;
-       gc->timer.function = gc_timer;
+       setup_timer(&gc->timer, gc_timer, (long) gc);
 
        for (i = 0; i < n_pads && i < GC_MAX_DEVICES; i++) {
                if (!pads[i])
                        continue;
 
-               snprintf(gc->phys[i], sizeof(gc->phys[i]),
-                        "%s/input%d", gc->pd->port->name, i);
                err = gc_setup_pad(gc, i, pads[i]);
                if (err)
                        goto err_unreg_devs;
 
-               err = input_register_device(gc->dev[i]);
-               if (err)
-                       goto err_free_dev;
+               count++;
        }
 
-       if (!gc->pads[0]) {
-               printk(KERN_ERR "gamecon.c: No valid devices specified\n");
+       if (count == 0) {
+               pr_err("No valid devices specified\n");
                err = -EINVAL;
                goto err_free_gc;
        }
@@ -775,12 +981,10 @@ static struct gc __init *gc_probe(int parport, int *pads, int n_pads)
        parport_put_port(pp);
        return gc;
 
- err_free_dev:
-       input_free_device(gc->dev[i]);
  err_unreg_devs:
        while (--i >= 0)
-               if (gc->dev[i])
-                       input_unregister_device(gc->dev[i]);
+               if (gc->pads[i].dev)
+                       input_unregister_device(gc->pads[i].dev);
  err_free_gc:
        kfree(gc);
  err_unreg_pardev:
@@ -796,8 +1000,8 @@ static void gc_remove(struct gc *gc)
        int i;
 
        for (i = 0; i < GC_MAX_DEVICES; i++)
-               if (gc->dev[i])
-                       input_unregister_device(gc->dev[i]);
+               if (gc->pads[i].dev)
+                       input_unregister_device(gc->pads[i].dev);
        parport_unregister_device(gc->pd);
        kfree(gc);
 }
@@ -813,7 +1017,7 @@ static int __init gc_init(void)
                        continue;
 
                if (gc_cfg[i].nargs < 2) {
-                       printk(KERN_ERR "gamecon.c: at least one device must be specified\n");
+                       pr_err("at least one device must be specified\n");
                        err = -EINVAL;
                        break;
                }
index 8a28fb7..9b3353b 100644 (file)
@@ -86,9 +86,8 @@
 
 /* xbox d-pads should map to buttons, as is required for DDR pads
    but we map them to axes when possible to simplify things */
-#define MAP_DPAD_TO_BUTTONS    0
-#define MAP_DPAD_TO_AXES       1
-#define MAP_DPAD_UNKNOWN       2
+#define MAP_DPAD_TO_BUTTONS            (1 << 0)
+#define MAP_TRIGGERS_TO_BUTTONS                (1 << 1)
 
 #define XTYPE_XBOX        0
 #define XTYPE_XBOX360     1
@@ -99,57 +98,61 @@ static int dpad_to_buttons;
 module_param(dpad_to_buttons, bool, S_IRUGO);
 MODULE_PARM_DESC(dpad_to_buttons, "Map D-PAD to buttons rather than axes for unknown pads");
 
+static int triggers_to_buttons;
+module_param(triggers_to_buttons, bool, S_IRUGO);
+MODULE_PARM_DESC(triggers_to_buttons, "Map triggers to buttons rather than axes for unknown pads");
+
 static const struct xpad_device {
        u16 idVendor;
        u16 idProduct;
        char *name;
-       u8 dpad_mapping;
+       u8 mapping;
        u8 xtype;
 } xpad_device[] = {
-       { 0x045e, 0x0202, "Microsoft X-Box pad v1 (US)", MAP_DPAD_TO_AXES, XTYPE_XBOX },
-       { 0x045e, 0x0289, "Microsoft X-Box pad v2 (US)", MAP_DPAD_TO_AXES, XTYPE_XBOX },
-       { 0x045e, 0x0285, "Microsoft X-Box pad (Japan)", MAP_DPAD_TO_AXES, XTYPE_XBOX },
-       { 0x045e, 0x0287, "Microsoft Xbox Controller S", MAP_DPAD_TO_AXES, XTYPE_XBOX },
+       { 0x045e, 0x0202, "Microsoft X-Box pad v1 (US)", 0, XTYPE_XBOX },
+       { 0x045e, 0x0289, "Microsoft X-Box pad v2 (US)", 0, XTYPE_XBOX },
+       { 0x045e, 0x0285, "Microsoft X-Box pad (Japan)", 0, XTYPE_XBOX },
+       { 0x045e, 0x0287, "Microsoft Xbox Controller S", 0, XTYPE_XBOX },
        { 0x045e, 0x0719, "Xbox 360 Wireless Receiver", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360W },
        { 0x0c12, 0x8809, "RedOctane Xbox Dance Pad", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX },
-       { 0x044f, 0x0f07, "Thrustmaster, Inc. Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX },
-       { 0x046d, 0xc242, "Logitech Chillstream Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX360 },
-       { 0x046d, 0xca84, "Logitech Xbox Cordless Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX },
-       { 0x046d, 0xca88, "Logitech Compact Controller for Xbox", MAP_DPAD_TO_AXES, XTYPE_XBOX },
-       { 0x05fd, 0x1007, "Mad Catz Controller (unverified)", MAP_DPAD_TO_AXES, XTYPE_XBOX },
-       { 0x05fd, 0x107a, "InterAct 'PowerPad Pro' X-Box pad (Germany)", MAP_DPAD_TO_AXES, XTYPE_XBOX },
-       { 0x0738, 0x4516, "Mad Catz Control Pad", MAP_DPAD_TO_AXES, XTYPE_XBOX },
-       { 0x0738, 0x4522, "Mad Catz LumiCON", MAP_DPAD_TO_AXES, XTYPE_XBOX },
-       { 0x0738, 0x4526, "Mad Catz Control Pad Pro", MAP_DPAD_TO_AXES, XTYPE_XBOX },
-       { 0x0738, 0x4536, "Mad Catz MicroCON", MAP_DPAD_TO_AXES, XTYPE_XBOX },
+       { 0x044f, 0x0f07, "Thrustmaster, Inc. Controller", 0, XTYPE_XBOX },
+       { 0x046d, 0xc242, "Logitech Chillstream Controller", 0, XTYPE_XBOX360 },
+       { 0x046d, 0xca84, "Logitech Xbox Cordless Controller", 0, XTYPE_XBOX },
+       { 0x046d, 0xca88, "Logitech Compact Controller for Xbox", 0, XTYPE_XBOX },
+       { 0x05fd, 0x1007, "Mad Catz Controller (unverified)", 0, XTYPE_XBOX },
+       { 0x05fd, 0x107a, "InterAct 'PowerPad Pro' X-Box pad (Germany)", 0, XTYPE_XBOX },
+       { 0x0738, 0x4516, "Mad Catz Control Pad", 0, XTYPE_XBOX },
+       { 0x0738, 0x4522, "Mad Catz LumiCON", 0, XTYPE_XBOX },
+       { 0x0738, 0x4526, "Mad Catz Control Pad Pro", 0, XTYPE_XBOX },
+       { 0x0738, 0x4536, "Mad Catz MicroCON", 0, XTYPE_XBOX },
        { 0x0738, 0x4540, "Mad Catz Beat Pad", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX },
-       { 0x0738, 0x4556, "Mad Catz Lynx Wireless Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX },
-       { 0x0738, 0x4716, "Mad Catz Wired Xbox 360 Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX360 },
-       { 0x0738, 0x4738, "Mad Catz Wired Xbox 360 Controller (SFIV)", MAP_DPAD_TO_AXES, XTYPE_XBOX360 },
+       { 0x0738, 0x4556, "Mad Catz Lynx Wireless Controller", 0, XTYPE_XBOX },
+       { 0x0738, 0x4716, "Mad Catz Wired Xbox 360 Controller", 0, XTYPE_XBOX360 },
+       { 0x0738, 0x4738, "Mad Catz Wired Xbox 360 Controller (SFIV)", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 },
        { 0x0738, 0x6040, "Mad Catz Beat Pad Pro", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX },
-       { 0x0c12, 0x8802, "Zeroplus Xbox Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX },
-       { 0x0c12, 0x880a, "Pelican Eclipse PL-2023", MAP_DPAD_TO_AXES, XTYPE_XBOX },
-       { 0x0c12, 0x8810, "Zeroplus Xbox Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX },
-       { 0x0c12, 0x9902, "HAMA VibraX - *FAULTY HARDWARE*", MAP_DPAD_TO_AXES, XTYPE_XBOX },
-       { 0x0e4c, 0x1097, "Radica Gamester Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX },
-       { 0x0e4c, 0x2390, "Radica Games Jtech Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX },
-       { 0x0e6f, 0x0003, "Logic3 Freebird wireless Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX },
-       { 0x0e6f, 0x0005, "Eclipse wireless Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX },
-       { 0x0e6f, 0x0006, "Edge wireless Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX },
-       { 0x0e6f, 0x0006, "Pelican 'TSZ' Wired Xbox 360 Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX360 },
-       { 0x0e8f, 0x0201, "SmartJoy Frag Xpad/PS2 adaptor", MAP_DPAD_TO_AXES, XTYPE_XBOX },
-       { 0x0f30, 0x0202, "Joytech Advanced Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX },
-       { 0x0f30, 0x8888, "BigBen XBMiniPad Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX },
-       { 0x102c, 0xff0c, "Joytech Wireless Advanced Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX },
+       { 0x0c12, 0x8802, "Zeroplus Xbox Controller", 0, XTYPE_XBOX },
+       { 0x0c12, 0x880a, "Pelican Eclipse PL-2023", 0, XTYPE_XBOX },
+       { 0x0c12, 0x8810, "Zeroplus Xbox Controller", 0, XTYPE_XBOX },
+       { 0x0c12, 0x9902, "HAMA VibraX - *FAULTY HARDWARE*", 0, XTYPE_XBOX },
+       { 0x0e4c, 0x1097, "Radica Gamester Controller", 0, XTYPE_XBOX },
+       { 0x0e4c, 0x2390, "Radica Games Jtech Controller", 0, XTYPE_XBOX },
+       { 0x0e6f, 0x0003, "Logic3 Freebird wireless Controller", 0, XTYPE_XBOX },
+       { 0x0e6f, 0x0005, "Eclipse wireless Controller", 0, XTYPE_XBOX },
+       { 0x0e6f, 0x0006, "Edge wireless Controller", 0, XTYPE_XBOX },
+       { 0x0e6f, 0x0006, "Pelican 'TSZ' Wired Xbox 360 Controller", 0, XTYPE_XBOX360 },
+       { 0x0e8f, 0x0201, "SmartJoy Frag Xpad/PS2 adaptor", 0, XTYPE_XBOX },
+       { 0x0f30, 0x0202, "Joytech Advanced Controller", 0, XTYPE_XBOX },
+       { 0x0f30, 0x8888, "BigBen XBMiniPad Controller", 0, XTYPE_XBOX },
+       { 0x102c, 0xff0c, "Joytech Wireless Advanced Controller", 0, XTYPE_XBOX },
        { 0x12ab, 0x8809, "Xbox DDR dancepad", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX },
-       { 0x1430, 0x4748, "RedOctane Guitar Hero X-plorer", MAP_DPAD_TO_AXES, XTYPE_XBOX360 },
+       { 0x1430, 0x4748, "RedOctane Guitar Hero X-plorer", 0, XTYPE_XBOX360 },
        { 0x1430, 0x8888, "TX6500+ Dance Pad (first generation)", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX },
-       { 0x146b, 0x0601, "BigBen Interactive XBOX 360 Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX360 },
-       { 0x045e, 0x028e, "Microsoft X-Box 360 pad", MAP_DPAD_TO_AXES, XTYPE_XBOX360 },
+       { 0x146b, 0x0601, "BigBen Interactive XBOX 360 Controller", 0, XTYPE_XBOX360 },
+       { 0x045e, 0x028e, "Microsoft X-Box 360 pad", 0, XTYPE_XBOX360 },
        { 0x1bad, 0x0003, "Harmonix Rock Band Drumkit", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360 },
-       { 0x0f0d, 0x0016, "Hori Real Arcade Pro.EX", MAP_DPAD_TO_AXES, XTYPE_XBOX360 },
-       { 0xffff, 0xffff, "Chinese-made Xbox Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX },
-       { 0x0000, 0x0000, "Generic X-Box pad", MAP_DPAD_UNKNOWN, XTYPE_UNKNOWN }
+       { 0x0f0d, 0x0016, "Hori Real Arcade Pro.EX", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 },
+       { 0xffff, 0xffff, "Chinese-made Xbox Controller", 0, XTYPE_XBOX },
+       { 0x0000, 0x0000, "Generic X-Box pad", 0, XTYPE_UNKNOWN }
 };
 
 /* buttons shared with xbox and xbox360 */
@@ -165,13 +168,20 @@ static const signed short xpad_btn[] = {
        -1                      /* terminating entry */
 };
 
-/* only used if MAP_DPAD_TO_BUTTONS */
+/* used when dpad is mapped to nuttons */
 static const signed short xpad_btn_pad[] = {
        BTN_LEFT, BTN_RIGHT,            /* d-pad left, right */
        BTN_0, BTN_1,                   /* d-pad up, down (XXX names??) */
        -1                              /* terminating entry */
 };
 
+/* used when triggers are mapped to buttons */
+static const signed short xpad_btn_triggers[] = {
+       BTN_TL2, BTN_TR2,               /* triggers left/right */
+       -1
+};
+
+
 static const signed short xpad360_btn[] = {  /* buttons for x360 controller */
        BTN_TL, BTN_TR,         /* Button LB/RB */
        BTN_MODE,               /* The big X button */
@@ -181,16 +191,21 @@ static const signed short xpad360_btn[] = {  /* buttons for x360 controller */
 static const signed short xpad_abs[] = {
        ABS_X, ABS_Y,           /* left stick */
        ABS_RX, ABS_RY,         /* right stick */
-       ABS_Z, ABS_RZ,          /* triggers left/right */
        -1                      /* terminating entry */
 };
 
-/* only used if MAP_DPAD_TO_AXES */
+/* used when dpad is mapped to axes */
 static const signed short xpad_abs_pad[] = {
        ABS_HAT0X, ABS_HAT0Y,   /* d-pad axes */
        -1                      /* terminating entry */
 };
 
+/* used when triggers are mapped to axes */
+static const signed short xpad_abs_triggers[] = {
+       ABS_Z, ABS_RZ,          /* triggers left/right */
+       -1
+};
+
 /* Xbox 360 has a vendor-specific class, so we cannot match it with only
  * USB_INTERFACE_INFO (also specifically refused by USB subsystem), so we
  * match against vendor id as well. Wired Xbox 360 devices have protocol 1,
@@ -246,7 +261,7 @@ struct usb_xpad {
 
        char phys[64];                  /* physical device path */
 
-       int dpad_mapping;               /* map d-pad to buttons or to axes */
+       int mapping;                    /* map d-pad to buttons or to axes */
        int xtype;                      /* type of xbox device */
 };
 
@@ -277,20 +292,25 @@ static void xpad_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char *d
                         ~(__s16) le16_to_cpup((__le16 *)(data + 18)));
 
        /* triggers left/right */
-       input_report_abs(dev, ABS_Z, data[10]);
-       input_report_abs(dev, ABS_RZ, data[11]);
+       if (xpad->mapping & MAP_TRIGGERS_TO_BUTTONS) {
+               input_report_key(dev, BTN_TL2, data[10]);
+               input_report_key(dev, BTN_TR2, data[11]);
+       } else {
+               input_report_abs(dev, ABS_Z, data[10]);
+               input_report_abs(dev, ABS_RZ, data[11]);
+       }
 
        /* digital pad */
-       if (xpad->dpad_mapping == MAP_DPAD_TO_AXES) {
-               input_report_abs(dev, ABS_HAT0X,
-                                !!(data[2] & 0x08) - !!(data[2] & 0x04));
-               input_report_abs(dev, ABS_HAT0Y,
-                                !!(data[2] & 0x02) - !!(data[2] & 0x01));
-       } else /* xpad->dpad_mapping == MAP_DPAD_TO_BUTTONS */ {
+       if (xpad->mapping & MAP_DPAD_TO_BUTTONS) {
                input_report_key(dev, BTN_LEFT,  data[2] & 0x04);
                input_report_key(dev, BTN_RIGHT, data[2] & 0x08);
                input_report_key(dev, BTN_0,     data[2] & 0x01); /* up */
                input_report_key(dev, BTN_1,     data[2] & 0x02); /* down */
+       } else {
+               input_report_abs(dev, ABS_HAT0X,
+                                !!(data[2] & 0x08) - !!(data[2] & 0x04));
+               input_report_abs(dev, ABS_HAT0Y,
+                                !!(data[2] & 0x02) - !!(data[2] & 0x01));
        }
 
        /* start/back buttons and stick press left/right */
@@ -328,17 +348,17 @@ static void xpad360_process_packet(struct usb_xpad *xpad,
        struct input_dev *dev = xpad->dev;
 
        /* digital pad */
-       if (xpad->dpad_mapping == MAP_DPAD_TO_AXES) {
-               input_report_abs(dev, ABS_HAT0X,
-                                !!(data[2] & 0x08) - !!(data[2] & 0x04));
-               input_report_abs(dev, ABS_HAT0Y,
-                                !!(data[2] & 0x02) - !!(data[2] & 0x01));
-       } else if (xpad->dpad_mapping == MAP_DPAD_TO_BUTTONS) {
+       if (xpad->mapping & MAP_DPAD_TO_BUTTONS) {
                /* dpad as buttons (right, left, down, up) */
                input_report_key(dev, BTN_LEFT, data[2] & 0x04);
                input_report_key(dev, BTN_RIGHT, data[2] & 0x08);
                input_report_key(dev, BTN_0, data[2] & 0x01);   /* up */
                input_report_key(dev, BTN_1, data[2] & 0x02);   /* down */
+       } else {
+               input_report_abs(dev, ABS_HAT0X,
+                                !!(data[2] & 0x08) - !!(data[2] & 0x04));
+               input_report_abs(dev, ABS_HAT0Y,
+                                !!(data[2] & 0x02) - !!(data[2] & 0x01));
        }
 
        /* start/back buttons */
@@ -371,8 +391,13 @@ static void xpad360_process_packet(struct usb_xpad *xpad,
                         ~(__s16) le16_to_cpup((__le16 *)(data + 12)));
 
        /* triggers left/right */
-       input_report_abs(dev, ABS_Z, data[4]);
-       input_report_abs(dev, ABS_RZ, data[5]);
+       if (xpad->mapping & MAP_TRIGGERS_TO_BUTTONS) {
+               input_report_key(dev, BTN_TL2, data[4]);
+               input_report_key(dev, BTN_TR2, data[5]);
+       } else {
+               input_report_abs(dev, ABS_Z, data[4]);
+               input_report_abs(dev, ABS_RZ, data[5]);
+       }
 
        input_sync(dev);
 }
@@ -505,7 +530,7 @@ static int xpad_init_output(struct usb_interface *intf, struct usb_xpad *xpad)
        struct usb_endpoint_descriptor *ep_irq_out;
        int error = -ENOMEM;
 
-       if (xpad->xtype != XTYPE_XBOX360)
+       if (xpad->xtype != XTYPE_XBOX360 && xpad->xtype != XTYPE_XBOX)
                return 0;
 
        xpad->odata = usb_buffer_alloc(xpad->udev, XPAD_PKT_LEN,
@@ -535,13 +560,13 @@ static int xpad_init_output(struct usb_interface *intf, struct usb_xpad *xpad)
 
 static void xpad_stop_output(struct usb_xpad *xpad)
 {
-       if (xpad->xtype == XTYPE_XBOX360)
+       if (xpad->xtype == XTYPE_XBOX360 || xpad->xtype == XTYPE_XBOX)
                usb_kill_urb(xpad->irq_out);
 }
 
 static void xpad_deinit_output(struct usb_xpad *xpad)
 {
-       if (xpad->xtype == XTYPE_XBOX360) {
+       if (xpad->xtype == XTYPE_XBOX360 || xpad->xtype == XTYPE_XBOX) {
                usb_free_urb(xpad->irq_out);
                usb_buffer_free(xpad->udev, XPAD_PKT_LEN,
                                xpad->odata, xpad->odata_dma);
@@ -554,24 +579,45 @@ static void xpad_stop_output(struct usb_xpad *xpad) {}
 #endif
 
 #ifdef CONFIG_JOYSTICK_XPAD_FF
-static int xpad_play_effect(struct input_dev *dev, void *data,
-                           struct ff_effect *effect)
+static int xpad_play_effect(struct input_dev *dev, void *data, struct ff_effect *effect)
 {
        struct usb_xpad *xpad = input_get_drvdata(dev);
 
        if (effect->type == FF_RUMBLE) {
                __u16 strong = effect->u.rumble.strong_magnitude;
                __u16 weak = effect->u.rumble.weak_magnitude;
-               xpad->odata[0] = 0x00;
-               xpad->odata[1] = 0x08;
-               xpad->odata[2] = 0x00;
-               xpad->odata[3] = strong / 256;
-               xpad->odata[4] = weak / 256;
-               xpad->odata[5] = 0x00;
-               xpad->odata[6] = 0x00;
-               xpad->odata[7] = 0x00;
-               xpad->irq_out->transfer_buffer_length = 8;
-               usb_submit_urb(xpad->irq_out, GFP_ATOMIC);
+
+               switch (xpad->xtype) {
+
+               case XTYPE_XBOX:
+                       xpad->odata[0] = 0x00;
+                       xpad->odata[1] = 0x06;
+                       xpad->odata[2] = 0x00;
+                       xpad->odata[3] = strong / 256;  /* left actuator */
+                       xpad->odata[4] = 0x00;
+                       xpad->odata[5] = weak / 256;    /* right actuator */
+                       xpad->irq_out->transfer_buffer_length = 6;
+
+                       return usb_submit_urb(xpad->irq_out, GFP_ATOMIC);
+
+               case XTYPE_XBOX360:
+                       xpad->odata[0] = 0x00;
+                       xpad->odata[1] = 0x08;
+                       xpad->odata[2] = 0x00;
+                       xpad->odata[3] = strong / 256;  /* left actuator? */
+                       xpad->odata[4] = weak / 256;    /* right actuator? */
+                       xpad->odata[5] = 0x00;
+                       xpad->odata[6] = 0x00;
+                       xpad->odata[7] = 0x00;
+                       xpad->irq_out->transfer_buffer_length = 8;
+
+                       return usb_submit_urb(xpad->irq_out, GFP_ATOMIC);
+
+               default:
+                       dbg("%s - rumble command sent to unsupported xpad type: %d",
+                               __func__, xpad->xtype);
+                       return -1;
+               }
        }
 
        return 0;
@@ -579,7 +625,7 @@ static int xpad_play_effect(struct input_dev *dev, void *data,
 
 static int xpad_init_ff(struct usb_xpad *xpad)
 {
-       if (xpad->xtype != XTYPE_XBOX360)
+       if (xpad->xtype != XTYPE_XBOX360 && xpad->xtype != XTYPE_XBOX)
                return 0;
 
        input_set_capability(xpad->dev, EV_FF, FF_RUMBLE);
@@ -712,11 +758,11 @@ static void xpad_set_up_abs(struct input_dev *input_dev, signed short abs)
                input_set_abs_params(input_dev, abs, -32768, 32767, 16, 128);
                break;
        case ABS_Z:
-       case ABS_RZ:    /* the triggers */
+       case ABS_RZ:    /* the triggers (if mapped to axes) */
                input_set_abs_params(input_dev, abs, 0, 255, 0, 0);
                break;
        case ABS_HAT0X:
-       case ABS_HAT0Y: /* the d-pad (only if MAP_DPAD_TO_AXES) */
+       case ABS_HAT0Y: /* the d-pad (only if dpad is mapped to axes */
                input_set_abs_params(input_dev, abs, -1, 1, 0, 0);
                break;
        }
@@ -752,10 +798,9 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
                goto fail2;
 
        xpad->udev = udev;
-       xpad->dpad_mapping = xpad_device[i].dpad_mapping;
+       xpad->mapping = xpad_device[i].mapping;
        xpad->xtype = xpad_device[i].xtype;
-       if (xpad->dpad_mapping == MAP_DPAD_UNKNOWN)
-               xpad->dpad_mapping = !dpad_to_buttons;
+
        if (xpad->xtype == XTYPE_UNKNOWN) {
                if (intf->cur_altsetting->desc.bInterfaceClass == USB_CLASS_VENDOR_SPEC) {
                        if (intf->cur_altsetting->desc.bInterfaceProtocol == 129)
@@ -764,7 +809,13 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
                                xpad->xtype = XTYPE_XBOX360;
                } else
                        xpad->xtype = XTYPE_XBOX;
+
+               if (dpad_to_buttons)
+                       xpad->mapping |= MAP_DPAD_TO_BUTTONS;
+               if (triggers_to_buttons)
+                       xpad->mapping |= MAP_TRIGGERS_TO_BUTTONS;
        }
+
        xpad->dev = input_dev;
        usb_make_path(udev, xpad->phys, sizeof(xpad->phys));
        strlcat(xpad->phys, "/input0", sizeof(xpad->phys));
@@ -781,25 +832,37 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
 
        input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
 
-       /* set up buttons */
+       /* set up standard buttons and axes */
        for (i = 0; xpad_common_btn[i] >= 0; i++)
-               set_bit(xpad_common_btn[i], input_dev->keybit);
-       if ((xpad->xtype == XTYPE_XBOX360) || (xpad->xtype == XTYPE_XBOX360W))
-               for (i = 0; xpad360_btn[i] >= 0; i++)
-                       set_bit(xpad360_btn[i], input_dev->keybit);
-       else
-               for (i = 0; xpad_btn[i] >= 0; i++)
-                       set_bit(xpad_btn[i], input_dev->keybit);
-       if (xpad->dpad_mapping == MAP_DPAD_TO_BUTTONS)
-               for (i = 0; xpad_btn_pad[i] >= 0; i++)
-                       set_bit(xpad_btn_pad[i], input_dev->keybit);
+               __set_bit(xpad_common_btn[i], input_dev->keybit);
 
-       /* set up axes */
        for (i = 0; xpad_abs[i] >= 0; i++)
                xpad_set_up_abs(input_dev, xpad_abs[i]);
-       if (xpad->dpad_mapping == MAP_DPAD_TO_AXES)
+
+       /* Now set up model-specific ones */
+       if (xpad->xtype == XTYPE_XBOX360 || xpad->xtype == XTYPE_XBOX360W) {
+               for (i = 0; xpad360_btn[i] >= 0; i++)
+                       __set_bit(xpad360_btn[i], input_dev->keybit);
+       } else {
+               for (i = 0; xpad_btn[i] >= 0; i++)
+                       __set_bit(xpad_btn[i], input_dev->keybit);
+       }
+
+       if (xpad->mapping & MAP_DPAD_TO_BUTTONS) {
+               for (i = 0; xpad_btn_pad[i] >= 0; i++)
+                       __set_bit(xpad_btn_pad[i], input_dev->keybit);
+       } else {
                for (i = 0; xpad_abs_pad[i] >= 0; i++)
                    xpad_set_up_abs(input_dev, xpad_abs_pad[i]);
+       }
+
+       if (xpad->mapping & MAP_TRIGGERS_TO_BUTTONS) {
+               for (i = 0; xpad_btn_triggers[i] >= 0; i++)
+                       __set_bit(xpad_btn_triggers[i], input_dev->keybit);
+       } else {
+               for (i = 0; xpad_abs_triggers[i] >= 0; i++)
+                       xpad_set_up_abs(input_dev, xpad_abs_triggers[i]);
+       }
 
        error = xpad_init_output(intf, xpad);
        if (error)
index 02c836e..64c1023 100644 (file)
@@ -35,10 +35,10 @@ config KEYBOARD_ADP5520
          be called adp5520-keys.
 
 config KEYBOARD_ADP5588
-       tristate "ADP5588 I2C QWERTY Keypad and IO Expander"
+       tristate "ADP5588/87 I2C QWERTY Keypad and IO Expander"
        depends on I2C
        help
-         Say Y here if you want to use a ADP5588 attached to your
+         Say Y here if you want to use a ADP5588/87 attached to your
          system I2C bus.
 
          To compile this driver as a module, choose M here: the
@@ -144,13 +144,15 @@ config KEYBOARD_BFIN
          module will be called bf54x-keys.
 
 config KEYBOARD_CORGI
-       tristate "Corgi keyboard"
+       tristate "Corgi keyboard (deprecated)"
        depends on PXA_SHARPSL
-       default y
        help
          Say Y here to enable the keyboard on the Sharp Zaurus SL-C7xx
          series of PDAs.
 
+         This driver is now deprecated, use generic GPIO based matrix
+         keyboard driver instead.
+
          To compile this driver as a module, choose M here: the
          module will be called corgikbd.
 
@@ -292,6 +294,15 @@ config KEYBOARD_MAX7359
          To compile this driver as a module, choose M here: the
          module will be called max7359_keypad.
 
+config KEYBOARD_IMX
+       tristate "IMX keypad support"
+       depends on ARCH_MXC
+       help
+         Enable support for IMX keypad port.
+
+         To compile this driver as a module, choose M here: the
+         module will be called imx_keypad.
+
 config KEYBOARD_NEWTON
        tristate "Newton keyboard"
        select SERIO
@@ -329,13 +340,15 @@ config KEYBOARD_PXA930_ROTARY
          module will be called pxa930_rotary.
 
 config KEYBOARD_SPITZ
-       tristate "Spitz keyboard"
+       tristate "Spitz keyboard (deprecated)"
        depends on PXA_SHARPSL
-       default y
        help
          Say Y here to enable the keyboard on the Sharp Zaurus SL-C1000,
          SL-C3000 and Sl-C3100 series of PDAs.
 
+         This driver is now deprecated, use generic GPIO based matrix
+         keyboard driver instead.
+
          To compile this driver as a module, choose M here: the
          module will be called spitzkbd.
 
@@ -363,7 +376,7 @@ config KEYBOARD_SUNKBD
 
 config KEYBOARD_SH_KEYSC
        tristate "SuperH KEYSC keypad support"
-       depends on SUPERH
+       depends on SUPERH || ARCH_SHMOBILE
        help
          Say Y here if you want to use a keypad attached to the KEYSC block
          on SuperH processors such as sh7722 and sh7343.
@@ -402,12 +415,14 @@ config KEYBOARD_TWL4030
          module will be called twl4030_keypad.
 
 config KEYBOARD_TOSA
-       tristate "Tosa keyboard"
+       tristate "Tosa keyboard (deprecated)"
        depends on MACH_TOSA
-       default y
        help
          Say Y here to enable the keyboard on the Sharp Zaurus SL-6000x (Tosa)
 
+         This driver is now deprecated, use generic GPIO based matrix
+         keyboard driver instead.
+
          To compile this driver as a module, choose M here: the
          module will be called tosakbd.
 
index 78654ef..706c6b5 100644 (file)
@@ -17,6 +17,7 @@ obj-$(CONFIG_KEYBOARD_EP93XX)         += ep93xx_keypad.o
 obj-$(CONFIG_KEYBOARD_GPIO)            += gpio_keys.o
 obj-$(CONFIG_KEYBOARD_HIL)             += hil_kbd.o
 obj-$(CONFIG_KEYBOARD_HIL_OLD)         += hilkbd.o
+obj-$(CONFIG_KEYBOARD_IMX)             += imx_keypad.o
 obj-$(CONFIG_KEYBOARD_HP6XX)           += jornada680_kbd.o
 obj-$(CONFIG_KEYBOARD_HP7XX)           += jornada720_kbd.o
 obj-$(CONFIG_KEYBOARD_LKKBD)           += lkkbd.o
index 1edb596..b5142d2 100644 (file)
@@ -1,6 +1,7 @@
 /*
  * File: drivers/input/keyboard/adp5588_keys.c
- * Description:  keypad driver for ADP5588 I2C QWERTY Keypad and IO Expander
+ * Description:  keypad driver for ADP5588 and ADP5587
+ *              I2C QWERTY Keypad and IO Expander
  * Bugs: Enter bugs at http://blackfin.uclinux.org/
  *
  * Copyright (C) 2008-2009 Analog Devices Inc.
@@ -327,6 +328,7 @@ static const struct dev_pm_ops adp5588_dev_pm_ops = {
 
 static const struct i2c_device_id adp5588_id[] = {
        { KBUILD_MODNAME, 0 },
+       { "adp5587-keys", 0 },
        { }
 };
 MODULE_DEVICE_TABLE(i2c, adp5588_id);
@@ -357,5 +359,5 @@ module_exit(adp5588_exit);
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
-MODULE_DESCRIPTION("ADP5588 Keypad driver");
+MODULE_DESCRIPTION("ADP5588/87 Keypad driver");
 MODULE_ALIAS("platform:adp5588-keys");
index 7b40562..d358ef8 100644 (file)
@@ -40,26 +40,26 @@ module_param_named(set, atkbd_set, int, 0);
 MODULE_PARM_DESC(set, "Select keyboard code set (2 = default, 3 = PS/2 native)");
 
 #if defined(__i386__) || defined(__x86_64__) || defined(__hppa__)
-static int atkbd_reset;
+static bool atkbd_reset;
 #else
-static int atkbd_reset = 1;
+static bool atkbd_reset = true;
 #endif
 module_param_named(reset, atkbd_reset, bool, 0);
 MODULE_PARM_DESC(reset, "Reset keyboard during initialization");
 
-static int atkbd_softrepeat;
+static bool atkbd_softrepeat;
 module_param_named(softrepeat, atkbd_softrepeat, bool, 0);
 MODULE_PARM_DESC(softrepeat, "Use software keyboard repeat");
 
-static int atkbd_softraw = 1;
+static bool atkbd_softraw = true;
 module_param_named(softraw, atkbd_softraw, bool, 0);
 MODULE_PARM_DESC(softraw, "Use software generated rawmode");
 
-static int atkbd_scroll;
+static bool atkbd_scroll;
 module_param_named(scroll, atkbd_scroll, bool, 0);
 MODULE_PARM_DESC(scroll, "Enable scroll-wheel on MS Office and similar keyboards");
 
-static int atkbd_extra;
+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");
 
@@ -153,16 +153,16 @@ static const unsigned short atkbd_unxlate_table[128] = {
 #define ATKBD_RET_HANGEUL      0xf2
 #define ATKBD_RET_ERR          0xff
 
-#define ATKBD_KEY_UNKNOWN        0
+#define ATKBD_KEY_UNKNOWN      0
 #define ATKBD_KEY_NULL         255
 
-#define ATKBD_SCR_1            254
-#define ATKBD_SCR_2            253
-#define ATKBD_SCR_4            252
-#define ATKBD_SCR_8            251
-#define ATKBD_SCR_CLICK                250
-#define ATKBD_SCR_LEFT         249
-#define ATKBD_SCR_RIGHT                248
+#define ATKBD_SCR_1            0xfffe
+#define ATKBD_SCR_2            0xfffd
+#define ATKBD_SCR_4            0xfffc
+#define ATKBD_SCR_8            0xfffb
+#define ATKBD_SCR_CLICK                0xfffa
+#define ATKBD_SCR_LEFT         0xfff9
+#define ATKBD_SCR_RIGHT                0xfff8
 
 #define ATKBD_SPECIAL          ATKBD_SCR_RIGHT
 
@@ -177,7 +177,7 @@ static const unsigned short atkbd_unxlate_table[128] = {
 #define ATKBD_XL_HANJA         0x20
 
 static const struct {
-       unsigned char keycode;
+       unsigned short keycode;
        unsigned char set2;
 } atkbd_scroll_keys[] = {
        { ATKBD_SCR_1,     0xc5 },
@@ -206,18 +206,18 @@ struct atkbd {
        unsigned short keycode[ATKBD_KEYMAP_SIZE];
        DECLARE_BITMAP(force_release_mask, ATKBD_KEYMAP_SIZE);
        unsigned char set;
-       unsigned char translated;
-       unsigned char extra;
-       unsigned char write;
-       unsigned char softrepeat;
-       unsigned char softraw;
-       unsigned char scroll;
-       unsigned char enabled;
+       bool translated;
+       bool extra;
+       bool write;
+       bool softrepeat;
+       bool softraw;
+       bool scroll;
+       bool enabled;
 
        /* Accessed only from interrupt */
        unsigned char emul;
-       unsigned char resend;
-       unsigned char release;
+       bool resend;
+       bool release;
        unsigned long xl_bit;
        unsigned int last;
        unsigned long time;
@@ -301,18 +301,18 @@ static const unsigned int xl_table[] = {
  * Checks if we should mangle the scancode to extract 'release' bit
  * in translated mode.
  */
-static int atkbd_need_xlate(unsigned long xl_bit, unsigned char code)
+static bool atkbd_need_xlate(unsigned long xl_bit, unsigned char code)
 {
        int i;
 
        if (code == ATKBD_RET_EMUL0 || code == ATKBD_RET_EMUL1)
-               return 0;
+               return false;
 
        for (i = 0; i < ARRAY_SIZE(xl_table); i++)
                if (code == xl_table[i])
                        return test_bit(i, &xl_bit);
 
-       return 1;
+       return true;
 }
 
 /*
@@ -359,7 +359,7 @@ static unsigned int atkbd_compat_scancode(struct atkbd *atkbd, unsigned int code
  */
 
 static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data,
-                       unsigned int flags)
+                                  unsigned int flags)
 {
        struct atkbd *atkbd = serio_get_drvdata(serio);
        struct input_dev *dev = atkbd->dev;
@@ -368,20 +368,18 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data,
        int value;
        unsigned short keycode;
 
-#ifdef ATKBD_DEBUG
-       printk(KERN_DEBUG "atkbd.c: Received %02x flags %02x\n", data, flags);
-#endif
+       dev_dbg(&serio->dev, "Received %02x flags %02x\n", data, flags);
 
 #if !defined(__i386__) && !defined (__x86_64__)
        if ((flags & (SERIO_FRAME | SERIO_PARITY)) && (~flags & SERIO_TIMEOUT) && !atkbd->resend && atkbd->write) {
-               printk(KERN_WARNING "atkbd.c: frame/parity error: %02x\n", flags);
+               dev_warn(&serio->dev, "Frame/parity error: %02x\n", flags);
                serio_write(serio, ATKBD_CMD_RESEND);
-               atkbd->resend = 1;
+               atkbd->resend = true;
                goto out;
        }
 
        if (!flags && data == ATKBD_RET_ACK)
-               atkbd->resend = 0;
+               atkbd->resend = false;
 #endif
 
        if (unlikely(atkbd->ps2dev.flags & PS2_FLAG_ACK))
@@ -412,32 +410,32 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data,
        }
 
        switch (code) {
-               case ATKBD_RET_BAT:
-                       atkbd->enabled = 0;
-                       serio_reconnect(atkbd->ps2dev.serio);
-                       goto out;
-               case ATKBD_RET_EMUL0:
-                       atkbd->emul = 1;
-                       goto out;
-               case ATKBD_RET_EMUL1:
-                       atkbd->emul = 2;
-                       goto out;
-               case ATKBD_RET_RELEASE:
-                       atkbd->release = 1;
-                       goto out;
-               case ATKBD_RET_ACK:
-               case ATKBD_RET_NAK:
-                       if (printk_ratelimit())
-                               printk(KERN_WARNING "atkbd.c: Spurious %s on %s. "
-                                      "Some program might be trying access hardware directly.\n",
-                                      data == ATKBD_RET_ACK ? "ACK" : "NAK", serio->phys);
-                       goto out;
-               case ATKBD_RET_ERR:
-                       atkbd->err_count++;
-#ifdef ATKBD_DEBUG
-                       printk(KERN_DEBUG "atkbd.c: Keyboard on %s reports too many keys pressed.\n", serio->phys);
-#endif
-                       goto out;
+       case ATKBD_RET_BAT:
+               atkbd->enabled = false;
+               serio_reconnect(atkbd->ps2dev.serio);
+               goto out;
+       case ATKBD_RET_EMUL0:
+               atkbd->emul = 1;
+               goto out;
+       case ATKBD_RET_EMUL1:
+               atkbd->emul = 2;
+               goto out;
+       case ATKBD_RET_RELEASE:
+               atkbd->release = true;
+               goto out;
+       case ATKBD_RET_ACK:
+       case ATKBD_RET_NAK:
+               if (printk_ratelimit())
+                       dev_warn(&serio->dev,
+                                "Spurious %s on %s. "
+                                "Some program might be trying access hardware directly.\n",
+                                data == ATKBD_RET_ACK ? "ACK" : "NAK", serio->phys);
+               goto out;
+       case ATKBD_RET_ERR:
+               atkbd->err_count++;
+               dev_dbg(&serio->dev, "Keyboard on %s reports too many keys pressed.\n",
+                       serio->phys);
+               goto out;
        }
 
        code = atkbd_compat_scancode(atkbd, code);
@@ -451,71 +449,72 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data,
                input_event(dev, EV_MSC, MSC_SCAN, code);
 
        switch (keycode) {
-               case ATKBD_KEY_NULL:
-                       break;
-               case ATKBD_KEY_UNKNOWN:
-                       printk(KERN_WARNING
-                              "atkbd.c: Unknown key %s (%s set %d, code %#x on %s).\n",
-                              atkbd->release ? "released" : "pressed",
-                              atkbd->translated ? "translated" : "raw",
-                              atkbd->set, code, serio->phys);
-                       printk(KERN_WARNING
-                              "atkbd.c: Use 'setkeycodes %s%02x <keycode>' to make it known.\n",
-                              code & 0x80 ? "e0" : "", code & 0x7f);
-                       input_sync(dev);
-                       break;
-               case ATKBD_SCR_1:
-                       scroll = 1 - atkbd->release * 2;
-                       break;
-               case ATKBD_SCR_2:
-                       scroll = 2 - atkbd->release * 4;
-                       break;
-               case ATKBD_SCR_4:
-                       scroll = 4 - atkbd->release * 8;
-                       break;
-               case ATKBD_SCR_8:
-                       scroll = 8 - atkbd->release * 16;
-                       break;
-               case ATKBD_SCR_CLICK:
-                       click = !atkbd->release;
-                       break;
-               case ATKBD_SCR_LEFT:
-                       hscroll = -1;
-                       break;
-               case ATKBD_SCR_RIGHT:
-                       hscroll = 1;
-                       break;
-               default:
-                       if (atkbd->release) {
-                               value = 0;
-                               atkbd->last = 0;
-                       } else if (!atkbd->softrepeat && test_bit(keycode, dev->key)) {
-                               /* Workaround Toshiba laptop multiple keypress */
-                               value = time_before(jiffies, atkbd->time) && atkbd->last == code ? 1 : 2;
-                       } else {
-                               value = 1;
-                               atkbd->last = code;
-                               atkbd->time = jiffies + msecs_to_jiffies(dev->rep[REP_DELAY]) / 2;
-                       }
-
-                       input_event(dev, EV_KEY, keycode, value);
-                       input_sync(dev);
+       case ATKBD_KEY_NULL:
+               break;
+       case ATKBD_KEY_UNKNOWN:
+               dev_warn(&serio->dev,
+                        "Unknown key %s (%s set %d, code %#x on %s).\n",
+                        atkbd->release ? "released" : "pressed",
+                        atkbd->translated ? "translated" : "raw",
+                        atkbd->set, code, serio->phys);
+               dev_warn(&serio->dev,
+                        "Use 'setkeycodes %s%02x <keycode>' to make it known.\n",
+                        code & 0x80 ? "e0" : "", code & 0x7f);
+               input_sync(dev);
+               break;
+       case ATKBD_SCR_1:
+               scroll = 1;
+               break;
+       case ATKBD_SCR_2:
+               scroll = 2;
+               break;
+       case ATKBD_SCR_4:
+               scroll = 4;
+               break;
+       case ATKBD_SCR_8:
+               scroll = 8;
+               break;
+       case ATKBD_SCR_CLICK:
+               click = !atkbd->release;
+               break;
+       case ATKBD_SCR_LEFT:
+               hscroll = -1;
+               break;
+       case ATKBD_SCR_RIGHT:
+               hscroll = 1;
+               break;
+       default:
+               if (atkbd->release) {
+                       value = 0;
+                       atkbd->last = 0;
+               } else if (!atkbd->softrepeat && test_bit(keycode, dev->key)) {
+                       /* Workaround Toshiba laptop multiple keypress */
+                       value = time_before(jiffies, atkbd->time) && atkbd->last == code ? 1 : 2;
+               } else {
+                       value = 1;
+                       atkbd->last = code;
+                       atkbd->time = jiffies + msecs_to_jiffies(dev->rep[REP_DELAY]) / 2;
+               }
+
+               input_event(dev, EV_KEY, keycode, value);
+               input_sync(dev);
 
-                       if (value && test_bit(code, atkbd->force_release_mask)) {
-                               input_report_key(dev, keycode, 0);
-                               input_sync(dev);
-                       }
+               if (value && test_bit(code, atkbd->force_release_mask)) {
+                       input_report_key(dev, keycode, 0);
+                       input_sync(dev);
+               }
        }
 
        if (atkbd->scroll) {
                if (click != -1)
                        input_report_key(dev, BTN_MIDDLE, click);
-               input_report_rel(dev, REL_WHEEL, scroll);
+               input_report_rel(dev, REL_WHEEL,
+                                atkbd->release ? -scroll : scroll);
                input_report_rel(dev, REL_HWHEEL, hscroll);
                input_sync(dev);
        }
 
-       atkbd->release = 0;
+       atkbd->release = false;
 out:
        return IRQ_HANDLED;
 }
@@ -634,17 +633,18 @@ static int atkbd_event(struct input_dev *dev,
 
        switch (type) {
 
-               case EV_LED:
-                       atkbd_schedule_event_work(atkbd, ATKBD_LED_EVENT_BIT);
-                       return 0;
+       case EV_LED:
+               atkbd_schedule_event_work(atkbd, ATKBD_LED_EVENT_BIT);
+               return 0;
 
-               case EV_REP:
-                       if (!atkbd->softrepeat)
-                               atkbd_schedule_event_work(atkbd, ATKBD_REP_EVENT_BIT);
-                       return 0;
-       }
+       case EV_REP:
+               if (!atkbd->softrepeat)
+                       atkbd_schedule_event_work(atkbd, ATKBD_REP_EVENT_BIT);
+               return 0;
 
-       return -1;
+       default:
+               return -1;
+       }
 }
 
 /*
@@ -655,7 +655,7 @@ static int atkbd_event(struct input_dev *dev,
 static inline void atkbd_enable(struct atkbd *atkbd)
 {
        serio_pause_rx(atkbd->ps2dev.serio);
-       atkbd->enabled = 1;
+       atkbd->enabled = true;
        serio_continue_rx(atkbd->ps2dev.serio);
 }
 
@@ -667,7 +667,7 @@ static inline void atkbd_enable(struct atkbd *atkbd)
 static inline void atkbd_disable(struct atkbd *atkbd)
 {
        serio_pause_rx(atkbd->ps2dev.serio);
-       atkbd->enabled = 0;
+       atkbd->enabled = false;
        serio_continue_rx(atkbd->ps2dev.serio);
 }
 
@@ -688,7 +688,9 @@ static int atkbd_probe(struct atkbd *atkbd)
 
        if (atkbd_reset)
                if (ps2_command(ps2dev, NULL, ATKBD_CMD_RESET_BAT))
-                       printk(KERN_WARNING "atkbd.c: keyboard reset failed on %s\n", ps2dev->serio->phys);
+                       dev_warn(&ps2dev->serio->dev,
+                                "keyboard reset failed on %s\n",
+                                ps2dev->serio->phys);
 
 /*
  * Then we check the keyboard ID. We should get 0xab83 under normal conditions.
@@ -718,8 +720,9 @@ static int atkbd_probe(struct atkbd *atkbd)
        atkbd->id = (param[0] << 8) | param[1];
 
        if (atkbd->id == 0xaca1 && atkbd->translated) {
-               printk(KERN_ERR "atkbd.c: NCD terminal keyboards are only supported on non-translating\n");
-               printk(KERN_ERR "atkbd.c: controllers. Use i8042.direct=1 to disable translation.\n");
+               dev_err(&ps2dev->serio->dev,
+                       "NCD terminal keyboards are only supported on non-translating controlelrs. "
+                       "Use i8042.direct=1 to disable translation.\n");
                return -1;
        }
 
@@ -737,7 +740,7 @@ static int atkbd_select_set(struct atkbd *atkbd, int target_set, int allow_extra
        struct ps2dev *ps2dev = &atkbd->ps2dev;
        unsigned char param[2];
 
-       atkbd->extra = 0;
+       atkbd->extra = false;
 /*
  * For known special keyboards we can go ahead and set the correct set.
  * We check for NCD PS/2 Sun, NorthGate OmniKey 101 and
@@ -756,7 +759,7 @@ static int atkbd_select_set(struct atkbd *atkbd, int target_set, int allow_extra
        if (allow_extra) {
                param[0] = 0x71;
                if (!ps2_command(ps2dev, param, ATKBD_CMD_EX_ENABLE)) {
-                       atkbd->extra = 1;
+                       atkbd->extra = true;
                        return 2;
                }
        }
@@ -821,7 +824,8 @@ static int atkbd_activate(struct atkbd *atkbd)
  */
 
        if (ps2_command(ps2dev, NULL, ATKBD_CMD_ENABLE)) {
-               printk(KERN_ERR "atkbd.c: Failed to enable keyboard on %s\n",
+               dev_err(&ps2dev->serio->dev,
+                       "Failed to enable keyboard on %s\n",
                        ps2dev->serio->phys);
                return -1;
        }
@@ -1070,9 +1074,13 @@ static void atkbd_set_device_attrs(struct atkbd *atkbd)
        input_dev->keycodesize = sizeof(unsigned short);
        input_dev->keycodemax = ARRAY_SIZE(atkbd_set2_keycode);
 
-       for (i = 0; i < ATKBD_KEYMAP_SIZE; i++)
-               if (atkbd->keycode[i] && atkbd->keycode[i] < ATKBD_SPECIAL)
+       for (i = 0; i < ATKBD_KEYMAP_SIZE; i++) {
+               if (atkbd->keycode[i] != KEY_RESERVED &&
+                   atkbd->keycode[i] != ATKBD_KEY_NULL &&
+                   atkbd->keycode[i] < ATKBD_SPECIAL) {
                        __set_bit(atkbd->keycode[i], input_dev->keybit);
+               }
+       }
 }
 
 /*
@@ -1100,12 +1108,14 @@ static int atkbd_connect(struct serio *serio, struct serio_driver *drv)
 
        switch (serio->id.type) {
 
-               case SERIO_8042_XL:
-                       atkbd->translated = 1;
-               case SERIO_8042:
-                       if (serio->write)
-                               atkbd->write = 1;
-                       break;
+       case SERIO_8042_XL:
+               atkbd->translated = true;
+               /* Fall through */
+
+       case SERIO_8042:
+               if (serio->write)
+                       atkbd->write = true;
+               break;
        }
 
        atkbd->softraw = atkbd_softraw;
@@ -1113,7 +1123,7 @@ static int atkbd_connect(struct serio *serio, struct serio_driver *drv)
        atkbd->scroll = atkbd_scroll;
 
        if (atkbd->softrepeat)
-               atkbd->softraw = 1;
+               atkbd->softraw = true;
 
        serio_set_drvdata(serio, atkbd);
 
@@ -1172,7 +1182,8 @@ static int atkbd_reconnect(struct serio *serio)
        int retval = -1;
 
        if (!atkbd || !drv) {
-               printk(KERN_DEBUG "atkbd: reconnect request, but serio is disconnected, ignoring...\n");
+               dev_dbg(&serio->dev,
+                       "reconnect request, but serio is disconnected, ignoring...\n");
                return -1;
        }
 
@@ -1286,7 +1297,8 @@ static ssize_t atkbd_set_extra(struct atkbd *atkbd, const char *buf, size_t coun
        struct input_dev *old_dev, *new_dev;
        unsigned long value;
        int err;
-       unsigned char old_extra, old_set;
+       bool old_extra;
+       unsigned char old_set;
 
        if (!atkbd->write)
                return -EIO;
@@ -1369,7 +1381,7 @@ static ssize_t atkbd_set_scroll(struct atkbd *atkbd, const char *buf, size_t cou
        struct input_dev *old_dev, *new_dev;
        unsigned long value;
        int err;
-       unsigned char old_scroll;
+       bool old_scroll;
 
        if (strict_strtoul(buf, 10, &value) || value > 1)
                return -EINVAL;
@@ -1413,7 +1425,8 @@ static ssize_t atkbd_set_set(struct atkbd *atkbd, const char *buf, size_t count)
        struct input_dev *old_dev, *new_dev;
        unsigned long value;
        int err;
-       unsigned char old_set, old_extra;
+       unsigned char old_set;
+       bool old_extra;
 
        if (!atkbd->write)
                return -EIO;
@@ -1463,7 +1476,7 @@ static ssize_t atkbd_set_softrepeat(struct atkbd *atkbd, const char *buf, size_t
        struct input_dev *old_dev, *new_dev;
        unsigned long value;
        int err;
-       unsigned char old_softrepeat, old_softraw;
+       bool old_softrepeat, old_softraw;
 
        if (!atkbd->write)
                return -EIO;
@@ -1483,7 +1496,7 @@ static ssize_t atkbd_set_softrepeat(struct atkbd *atkbd, const char *buf, size_t
                atkbd->dev = new_dev;
                atkbd->softrepeat = value;
                if (atkbd->softrepeat)
-                       atkbd->softraw = 1;
+                       atkbd->softraw = true;
                atkbd_set_device_attrs(atkbd);
 
                err = input_register_device(atkbd->dev);
@@ -1513,7 +1526,7 @@ static ssize_t atkbd_set_softraw(struct atkbd *atkbd, const char *buf, size_t co
        struct input_dev *old_dev, *new_dev;
        unsigned long value;
        int err;
-       unsigned char old_softraw;
+       bool old_softraw;
 
        if (strict_strtoul(buf, 10, &value) || value > 1)
                return -EINVAL;
index e457404..bd25a3a 100644 (file)
@@ -69,7 +69,7 @@ struct ep93xx_keypad {
 
        void __iomem *mmio_base;
 
-       unsigned int matrix_keycodes[EP93XX_MATRIX_SIZE];
+       unsigned short keycodes[EP93XX_MATRIX_SIZE];
 
        int key1;
        int key2;
@@ -79,24 +79,6 @@ struct ep93xx_keypad {
        bool enabled;
 };
 
-static void ep93xx_keypad_build_keycode(struct ep93xx_keypad *keypad)
-{
-       struct ep93xx_keypad_platform_data *pdata = keypad->pdata;
-       struct input_dev *input_dev = keypad->input_dev;
-       unsigned int *key;
-       int i;
-
-       key = &pdata->matrix_key_map[0];
-       for (i = 0; i < pdata->matrix_key_map_size; i++, key++) {
-               int row = KEY_ROW(*key);
-               int col = KEY_COL(*key);
-               int code = KEY_VAL(*key);
-
-               keypad->matrix_keycodes[(row << 3) + col] = code;
-               __set_bit(code, input_dev->keybit);
-       }
-}
-
 static irqreturn_t ep93xx_keypad_irq_handler(int irq, void *dev_id)
 {
        struct ep93xx_keypad *keypad = dev_id;
@@ -107,10 +89,10 @@ static irqreturn_t ep93xx_keypad_irq_handler(int irq, void *dev_id)
        status = __raw_readl(keypad->mmio_base + KEY_REG);
 
        keycode = (status & KEY_REG_KEY1_MASK) >> KEY_REG_KEY1_SHIFT;
-       key1 = keypad->matrix_keycodes[keycode];
+       key1 = keypad->keycodes[keycode];
 
        keycode = (status & KEY_REG_KEY2_MASK) >> KEY_REG_KEY2_SHIFT;
-       key2 = keypad->matrix_keycodes[keycode];
+       key2 = keypad->keycodes[keycode];
 
        if (status & KEY_REG_2KEYS) {
                if (keypad->key1 && key1 != keypad->key1 && key2 != keypad->key1)
@@ -256,6 +238,7 @@ static int ep93xx_keypad_resume(struct platform_device *pdev)
 static int __devinit ep93xx_keypad_probe(struct platform_device *pdev)
 {
        struct ep93xx_keypad *keypad;
+       const struct matrix_keymap_data *keymap_data;
        struct input_dev *input_dev;
        struct resource *res;
        int err;
@@ -270,6 +253,12 @@ static int __devinit ep93xx_keypad_probe(struct platform_device *pdev)
                goto failed_free;
        }
 
+       keymap_data = keypad->pdata->keymap_data;
+       if (!keymap_data) {
+               err = -EINVAL;
+               goto failed_free;
+       }
+
        keypad->irq = platform_get_irq(pdev, 0);
        if (!keypad->irq) {
                err = -ENXIO;
@@ -317,9 +306,9 @@ static int __devinit ep93xx_keypad_probe(struct platform_device *pdev)
        input_dev->open = ep93xx_keypad_open;
        input_dev->close = ep93xx_keypad_close;
        input_dev->dev.parent = &pdev->dev;
-       input_dev->keycode = keypad->matrix_keycodes;
-       input_dev->keycodesize = sizeof(keypad->matrix_keycodes[0]);
-       input_dev->keycodemax = ARRAY_SIZE(keypad->matrix_keycodes);
+       input_dev->keycode = keypad->keycodes;
+       input_dev->keycodesize = sizeof(keypad->keycodes[0]);
+       input_dev->keycodemax = ARRAY_SIZE(keypad->keycodes);
 
        input_set_drvdata(input_dev, keypad);
 
@@ -327,7 +316,8 @@ static int __devinit ep93xx_keypad_probe(struct platform_device *pdev)
        if (keypad->pdata->flags & EP93XX_KEYPAD_AUTOREPEAT)
                input_dev->evbit[0] |= BIT_MASK(EV_REP);
 
-       ep93xx_keypad_build_keycode(keypad);
+       matrix_keypad_build_keymap(keymap_data, 3,
+                                  input_dev->keycode, input_dev->keybit);
        platform_set_drvdata(pdev, keypad);
 
        err = request_irq(keypad->irq, ep93xx_keypad_irq_handler,
index 1aff3b7..2b708aa 100644 (file)
@@ -30,13 +30,289 @@ struct gpio_button_data {
        struct input_dev *input;
        struct timer_list timer;
        struct work_struct work;
+       bool disabled;
 };
 
 struct gpio_keys_drvdata {
        struct input_dev *input;
+       struct mutex disable_lock;
+       unsigned int n_buttons;
        struct gpio_button_data data[0];
 };
 
+/*
+ * SYSFS interface for enabling/disabling keys and switches:
+ *
+ * There are 4 attributes under /sys/devices/platform/gpio-keys/
+ *     keys [ro]              - bitmap of keys (EV_KEY) which can be
+ *                              disabled
+ *     switches [ro]          - bitmap of switches (EV_SW) which can be
+ *                              disabled
+ *     disabled_keys [rw]     - bitmap of keys currently disabled
+ *     disabled_switches [rw] - bitmap of switches currently disabled
+ *
+ * Userland can change these values and hence disable event generation
+ * for each key (or switch). Disabling a key means its interrupt line
+ * is disabled.
+ *
+ * For example, if we have following switches set up as gpio-keys:
+ *     SW_DOCK = 5
+ *     SW_CAMERA_LENS_COVER = 9
+ *     SW_KEYPAD_SLIDE = 10
+ *     SW_FRONT_PROXIMITY = 11
+ * This is read from switches:
+ *     11-9,5
+ * Next we want to disable proximity (11) and dock (5), we write:
+ *     11,5
+ * to file disabled_switches. Now proximity and dock IRQs are disabled.
+ * This can be verified by reading the file disabled_switches:
+ *     11,5
+ * If we now want to enable proximity (11) switch we write:
+ *     5
+ * to disabled_switches.
+ *
+ * We can disable only those keys which don't allow sharing the irq.
+ */
+
+/**
+ * get_n_events_by_type() - returns maximum number of events per @type
+ * @type: type of button (%EV_KEY, %EV_SW)
+ *
+ * Return value of this function can be used to allocate bitmap
+ * large enough to hold all bits for given type.
+ */
+static inline int get_n_events_by_type(int type)
+{
+       BUG_ON(type != EV_SW && type != EV_KEY);
+
+       return (type == EV_KEY) ? KEY_CNT : SW_CNT;
+}
+
+/**
+ * gpio_keys_disable_button() - disables given GPIO button
+ * @bdata: button data for button to be disabled
+ *
+ * Disables button pointed by @bdata. This is done by masking
+ * IRQ line. After this function is called, button won't generate
+ * input events anymore. Note that one can only disable buttons
+ * that don't share IRQs.
+ *
+ * Make sure that @bdata->disable_lock is locked when entering
+ * this function to avoid races when concurrent threads are
+ * disabling buttons at the same time.
+ */
+static void gpio_keys_disable_button(struct gpio_button_data *bdata)
+{
+       if (!bdata->disabled) {
+               /*
+                * Disable IRQ and possible debouncing timer.
+                */
+               disable_irq(gpio_to_irq(bdata->button->gpio));
+               if (bdata->button->debounce_interval)
+                       del_timer_sync(&bdata->timer);
+
+               bdata->disabled = true;
+       }
+}
+
+/**
+ * gpio_keys_enable_button() - enables given GPIO button
+ * @bdata: button data for button to be disabled
+ *
+ * Enables given button pointed by @bdata.
+ *
+ * Make sure that @bdata->disable_lock is locked when entering
+ * this function to avoid races with concurrent threads trying
+ * to enable the same button at the same time.
+ */
+static void gpio_keys_enable_button(struct gpio_button_data *bdata)
+{
+       if (bdata->disabled) {
+               enable_irq(gpio_to_irq(bdata->button->gpio));
+               bdata->disabled = false;
+       }
+}
+
+/**
+ * gpio_keys_attr_show_helper() - fill in stringified bitmap of buttons
+ * @ddata: pointer to drvdata
+ * @buf: buffer where stringified bitmap is written
+ * @type: button type (%EV_KEY, %EV_SW)
+ * @only_disabled: does caller want only those buttons that are
+ *                 currently disabled or all buttons that can be
+ *                 disabled
+ *
+ * This function writes buttons that can be disabled to @buf. If
+ * @only_disabled is true, then @buf contains only those buttons
+ * that are currently disabled. Returns 0 on success or negative
+ * errno on failure.
+ */
+static ssize_t gpio_keys_attr_show_helper(struct gpio_keys_drvdata *ddata,
+                                         char *buf, unsigned int type,
+                                         bool only_disabled)
+{
+       int n_events = get_n_events_by_type(type);
+       unsigned long *bits;
+       ssize_t ret;
+       int i;
+
+       bits = kcalloc(BITS_TO_LONGS(n_events), sizeof(*bits), GFP_KERNEL);
+       if (!bits)
+               return -ENOMEM;
+
+       for (i = 0; i < ddata->n_buttons; i++) {
+               struct gpio_button_data *bdata = &ddata->data[i];
+
+               if (bdata->button->type != type)
+                       continue;
+
+               if (only_disabled && !bdata->disabled)
+                       continue;
+
+               __set_bit(bdata->button->code, bits);
+       }
+
+       ret = bitmap_scnlistprintf(buf, PAGE_SIZE - 2, bits, n_events);
+       buf[ret++] = '\n';
+       buf[ret] = '\0';
+
+       kfree(bits);
+
+       return ret;
+}
+
+/**
+ * gpio_keys_attr_store_helper() - enable/disable buttons based on given bitmap
+ * @ddata: pointer to drvdata
+ * @buf: buffer from userspace that contains stringified bitmap
+ * @type: button type (%EV_KEY, %EV_SW)
+ *
+ * This function parses stringified bitmap from @buf and disables/enables
+ * GPIO buttons accordinly. Returns 0 on success and negative error
+ * on failure.
+ */
+static ssize_t gpio_keys_attr_store_helper(struct gpio_keys_drvdata *ddata,
+                                          const char *buf, unsigned int type)
+{
+       int n_events = get_n_events_by_type(type);
+       unsigned long *bits;
+       ssize_t error;
+       int i;
+
+       bits = kcalloc(BITS_TO_LONGS(n_events), sizeof(*bits), GFP_KERNEL);
+       if (!bits)
+               return -ENOMEM;
+
+       error = bitmap_parselist(buf, bits, n_events);
+       if (error)
+               goto out;
+
+       /* First validate */
+       for (i = 0; i < ddata->n_buttons; i++) {
+               struct gpio_button_data *bdata = &ddata->data[i];
+
+               if (bdata->button->type != type)
+                       continue;
+
+               if (test_bit(bdata->button->code, bits) &&
+                   !bdata->button->can_disable) {
+                       error = -EINVAL;
+                       goto out;
+               }
+       }
+
+       mutex_lock(&ddata->disable_lock);
+
+       for (i = 0; i < ddata->n_buttons; i++) {
+               struct gpio_button_data *bdata = &ddata->data[i];
+
+               if (bdata->button->type != type)
+                       continue;
+
+               if (test_bit(bdata->button->code, bits))
+                       gpio_keys_disable_button(bdata);
+               else
+                       gpio_keys_enable_button(bdata);
+       }
+
+       mutex_unlock(&ddata->disable_lock);
+
+out:
+       kfree(bits);
+       return error;
+}
+
+#define ATTR_SHOW_FN(name, type, only_disabled)                                \
+static ssize_t gpio_keys_show_##name(struct device *dev,               \
+                                    struct device_attribute *attr,     \
+                                    char *buf)                         \
+{                                                                      \
+       struct platform_device *pdev = to_platform_device(dev);         \
+       struct gpio_keys_drvdata *ddata = platform_get_drvdata(pdev);   \
+                                                                       \
+       return gpio_keys_attr_show_helper(ddata, buf,                   \
+                                         type, only_disabled);         \
+}
+
+ATTR_SHOW_FN(keys, EV_KEY, false);
+ATTR_SHOW_FN(switches, EV_SW, false);
+ATTR_SHOW_FN(disabled_keys, EV_KEY, true);
+ATTR_SHOW_FN(disabled_switches, EV_SW, true);
+
+/*
+ * ATTRIBUTES:
+ *
+ * /sys/devices/platform/gpio-keys/keys [ro]
+ * /sys/devices/platform/gpio-keys/switches [ro]
+ */
+static DEVICE_ATTR(keys, S_IRUGO, gpio_keys_show_keys, NULL);
+static DEVICE_ATTR(switches, S_IRUGO, gpio_keys_show_switches, NULL);
+
+#define ATTR_STORE_FN(name, type)                                      \
+static ssize_t gpio_keys_store_##name(struct device *dev,              \
+                                     struct device_attribute *attr,    \
+                                     const char *buf,                  \
+                                     size_t count)                     \
+{                                                                      \
+       struct platform_device *pdev = to_platform_device(dev);         \
+       struct gpio_keys_drvdata *ddata = platform_get_drvdata(pdev);   \
+       ssize_t error;                                                  \
+                                                                       \
+       error = gpio_keys_attr_store_helper(ddata, buf, type);          \
+       if (error)                                                      \
+               return error;                                           \
+                                                                       \
+       return count;                                                   \
+}
+
+ATTR_STORE_FN(disabled_keys, EV_KEY);
+ATTR_STORE_FN(disabled_switches, EV_SW);
+
+/*
+ * ATTRIBUTES:
+ *
+ * /sys/devices/platform/gpio-keys/disabled_keys [rw]
+ * /sys/devices/platform/gpio-keys/disables_switches [rw]
+ */
+static DEVICE_ATTR(disabled_keys, S_IWUSR | S_IRUGO,
+                  gpio_keys_show_disabled_keys,
+                  gpio_keys_store_disabled_keys);
+static DEVICE_ATTR(disabled_switches, S_IWUSR | S_IRUGO,
+                  gpio_keys_show_disabled_switches,
+                  gpio_keys_store_disabled_switches);
+
+static struct attribute *gpio_keys_attrs[] = {
+       &dev_attr_keys.attr,
+       &dev_attr_switches.attr,
+       &dev_attr_disabled_keys.attr,
+       &dev_attr_disabled_switches.attr,
+       NULL,
+};
+
+static struct attribute_group gpio_keys_attr_group = {
+       .attrs = gpio_keys_attrs,
+};
+
 static void gpio_keys_report_event(struct gpio_button_data *bdata)
 {
        struct gpio_keys_button *button = bdata->button;
@@ -79,11 +355,13 @@ static irqreturn_t gpio_keys_isr(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-static int __devinit gpio_keys_setup_key(struct device *dev,
+static int __devinit gpio_keys_setup_key(struct platform_device *pdev,
                                         struct gpio_button_data *bdata,
                                         struct gpio_keys_button *button)
 {
        char *desc = button->desc ? button->desc : "gpio_keys";
+       struct device *dev = &pdev->dev;
+       unsigned long irqflags;
        int irq, error;
 
        setup_timer(&bdata->timer, gpio_keys_timer, (unsigned long)bdata);
@@ -112,10 +390,15 @@ static int __devinit gpio_keys_setup_key(struct device *dev,
                goto fail3;
        }
 
-       error = request_irq(irq, gpio_keys_isr,
-                           IRQF_SHARED |
-                           IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
-                           desc, bdata);
+       irqflags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING;
+       /*
+        * If platform has specified that the button can be disabled,
+        * we don't want it to share the interrupt line.
+        */
+       if (!button->can_disable)
+               irqflags |= IRQF_SHARED;
+
+       error = request_irq(irq, gpio_keys_isr, irqflags, desc, bdata);
        if (error) {
                dev_err(dev, "Unable to claim irq %d; error %d\n",
                        irq, error);
@@ -149,6 +432,10 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev)
                goto fail1;
        }
 
+       ddata->input = input;
+       ddata->n_buttons = pdata->nbuttons;
+       mutex_init(&ddata->disable_lock);
+
        platform_set_drvdata(pdev, ddata);
 
        input->name = pdev->name;
@@ -164,8 +451,6 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev)
        if (pdata->rep)
                __set_bit(EV_REP, input->evbit);
 
-       ddata->input = input;
-
        for (i = 0; i < pdata->nbuttons; i++) {
                struct gpio_keys_button *button = &pdata->buttons[i];
                struct gpio_button_data *bdata = &ddata->data[i];
@@ -174,7 +459,7 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev)
                bdata->input = input;
                bdata->button = button;
 
-               error = gpio_keys_setup_key(dev, bdata, button);
+               error = gpio_keys_setup_key(pdev, bdata, button);
                if (error)
                        goto fail2;
 
@@ -184,13 +469,20 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev)
                input_set_capability(input, type, button->code);
        }
 
-       error = input_register_device(input);
+       error = sysfs_create_group(&pdev->dev.kobj, &gpio_keys_attr_group);
        if (error) {
-               dev_err(dev, "Unable to register input device, "
-                       "error: %d\n", error);
+               dev_err(dev, "Unable to export keys/switches, error: %d\n",
+                       error);
                goto fail2;
        }
 
+       error = input_register_device(input);
+       if (error) {
+               dev_err(dev, "Unable to register input device, error: %d\n",
+                       error);
+               goto fail3;
+       }
+
        /* get current state of buttons */
        for (i = 0; i < pdata->nbuttons; i++)
                gpio_keys_report_event(&ddata->data[i]);
@@ -200,6 +492,8 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev)
 
        return 0;
 
+ fail3:
+       sysfs_remove_group(&pdev->dev.kobj, &gpio_keys_attr_group);
  fail2:
        while (--i >= 0) {
                free_irq(gpio_to_irq(pdata->buttons[i].gpio), &ddata->data[i]);
@@ -224,6 +518,8 @@ static int __devexit gpio_keys_remove(struct platform_device *pdev)
        struct input_dev *input = ddata->input;
        int i;
 
+       sysfs_remove_group(&pdev->dev.kobj, &gpio_keys_attr_group);
+
        device_init_wakeup(&pdev->dev, 0);
 
        for (i = 0; i < pdata->nbuttons; i++) {
diff --git a/drivers/input/keyboard/imx_keypad.c b/drivers/input/keyboard/imx_keypad.c
new file mode 100644 (file)
index 0000000..2ee5b79
--- /dev/null
@@ -0,0 +1,594 @@
+/*
+ * Driver for the IMX keypad port.
+ * Copyright (C) 2009 Alberto Panizzo <maramaopercheseimorto@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * <<Power management needs to be implemented>>.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/input/matrix_keypad.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/jiffies.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/timer.h>
+
+/*
+ * Keypad Controller registers (halfword)
+ */
+#define KPCR           0x00 /* Keypad Control Register */
+
+#define KPSR           0x02 /* Keypad Status Register */
+#define KBD_STAT_KPKD  (0x1 << 0) /* Key Press Interrupt Status bit (w1c) */
+#define KBD_STAT_KPKR  (0x1 << 1) /* Key Release Interrupt Status bit (w1c) */
+#define KBD_STAT_KDSC  (0x1 << 2) /* Key Depress Synch Chain Status bit (w1c)*/
+#define KBD_STAT_KRSS  (0x1 << 3) /* Key Release Synch Status bit (w1c)*/
+#define KBD_STAT_KDIE  (0x1 << 8) /* Key Depress Interrupt Enable Status bit */
+#define KBD_STAT_KRIE  (0x1 << 9) /* Key Release Interrupt Enable */
+#define KBD_STAT_KPPEN (0x1 << 10) /* Keypad Clock Enable */
+
+#define KDDR           0x04 /* Keypad Data Direction Register */
+#define KPDR           0x06 /* Keypad Data Register */
+
+#define MAX_MATRIX_KEY_ROWS    8
+#define MAX_MATRIX_KEY_COLS    8
+#define MATRIX_ROW_SHIFT       3
+
+#define MAX_MATRIX_KEY_NUM     (MAX_MATRIX_KEY_ROWS * MAX_MATRIX_KEY_COLS)
+
+struct imx_keypad {
+
+       struct clk *clk;
+       struct input_dev *input_dev;
+       void __iomem *mmio_base;
+
+       int                     irq;
+       struct timer_list       check_matrix_timer;
+
+       /*
+        * The matrix is stable only if no changes are detected after
+        * IMX_KEYPAD_SCANS_FOR_STABILITY scans
+        */
+#define IMX_KEYPAD_SCANS_FOR_STABILITY 3
+       int                     stable_count;
+
+       bool                    enabled;
+
+       /* Masks for enabled rows/cols */
+       unsigned short          rows_en_mask;
+       unsigned short          cols_en_mask;
+
+       unsigned short          keycodes[MAX_MATRIX_KEY_NUM];
+
+       /*
+        * Matrix states:
+        * -stable: achieved after a complete debounce process.
+        * -unstable: used in the debouncing process.
+        */
+       unsigned short          matrix_stable_state[MAX_MATRIX_KEY_COLS];
+       unsigned short          matrix_unstable_state[MAX_MATRIX_KEY_COLS];
+};
+
+/* Scan the matrix and return the new state in *matrix_volatile_state. */
+static void imx_keypad_scan_matrix(struct imx_keypad *keypad,
+                                 unsigned short *matrix_volatile_state)
+{
+       int col;
+       unsigned short reg_val;
+
+       for (col = 0; col < MAX_MATRIX_KEY_COLS; col++) {
+               if ((keypad->cols_en_mask & (1 << col)) == 0)
+                       continue;
+               /*
+                * Discharge keypad capacitance:
+                * 2. write 1s on column data.
+                * 3. configure columns as totem-pole to discharge capacitance.
+                * 4. configure columns as open-drain.
+                */
+               reg_val = readw(keypad->mmio_base + KPDR);
+               reg_val |= 0xff00;
+               writew(reg_val, keypad->mmio_base + KPDR);
+
+               reg_val = readw(keypad->mmio_base + KPCR);
+               reg_val &= ~((keypad->cols_en_mask & 0xff) << 8);
+               writew(reg_val, keypad->mmio_base + KPCR);
+
+               udelay(2);
+
+               reg_val = readw(keypad->mmio_base + KPCR);
+               reg_val |= (keypad->cols_en_mask & 0xff) << 8;
+               writew(reg_val, keypad->mmio_base + KPCR);
+
+               /*
+                * 5. Write a single column to 0, others to 1.
+                * 6. Sample row inputs and save data.
+                * 7. Repeat steps 2 - 6 for remaining columns.
+                */
+               reg_val = readw(keypad->mmio_base + KPDR);
+               reg_val &= ~(1 << (8 + col));
+               writew(reg_val, keypad->mmio_base + KPDR);
+
+               /*
+                * Delay added to avoid propagating the 0 from column to row
+                * when scanning.
+                */
+               udelay(5);
+
+               /*
+                * 1s in matrix_volatile_state[col] means key pressures
+                * throw data from non enabled rows.
+                */
+               reg_val = readw(keypad->mmio_base + KPDR);
+               matrix_volatile_state[col] = (~reg_val) & keypad->rows_en_mask;
+       }
+
+       /*
+        * Return in standby mode:
+        * 9. write 0s to columns
+        */
+       reg_val = readw(keypad->mmio_base + KPDR);
+       reg_val &= 0x00ff;
+       writew(reg_val, keypad->mmio_base + KPDR);
+}
+
+/*
+ * Compare the new matrix state (volatile) with the stable one stored in
+ * keypad->matrix_stable_state and fire events if changes are detected.
+ */
+static void imx_keypad_fire_events(struct imx_keypad *keypad,
+                                  unsigned short *matrix_volatile_state)
+{
+       struct input_dev *input_dev = keypad->input_dev;
+       int row, col;
+
+       for (col = 0; col < MAX_MATRIX_KEY_COLS; col++) {
+               unsigned short bits_changed;
+               int code;
+
+               if ((keypad->cols_en_mask & (1 << col)) == 0)
+                       continue; /* Column is not enabled */
+
+               bits_changed = keypad->matrix_stable_state[col] ^
+                                               matrix_volatile_state[col];
+
+               if (bits_changed == 0)
+                       continue; /* Column does not contain changes */
+
+               for (row = 0; row < MAX_MATRIX_KEY_ROWS; row++) {
+                       if ((keypad->rows_en_mask & (1 << row)) == 0)
+                               continue; /* Row is not enabled */
+                       if ((bits_changed & (1 << row)) == 0)
+                               continue; /* Row does not contain changes */
+
+                       code = MATRIX_SCAN_CODE(row, col, MATRIX_ROW_SHIFT);
+                       input_event(input_dev, EV_MSC, MSC_SCAN, code);
+                       input_report_key(input_dev, keypad->keycodes[code],
+                               matrix_volatile_state[col] & (1 << row));
+                       dev_dbg(&input_dev->dev, "Event code: %d, val: %d",
+                               keypad->keycodes[code],
+                               matrix_volatile_state[col] & (1 << row));
+               }
+       }
+       input_sync(input_dev);
+}
+
+/*
+ * imx_keypad_check_for_events is the timer handler.
+ */
+static void imx_keypad_check_for_events(unsigned long data)
+{
+       struct imx_keypad *keypad = (struct imx_keypad *) data;
+       unsigned short matrix_volatile_state[MAX_MATRIX_KEY_COLS];
+       unsigned short reg_val;
+       bool state_changed, is_zero_matrix;
+       int i;
+
+       memset(matrix_volatile_state, 0, sizeof(matrix_volatile_state));
+
+       imx_keypad_scan_matrix(keypad, matrix_volatile_state);
+
+       state_changed = false;
+       for (i = 0; i < MAX_MATRIX_KEY_COLS; i++) {
+               if ((keypad->cols_en_mask & (1 << i)) == 0)
+                       continue;
+
+               if (keypad->matrix_unstable_state[i] ^ matrix_volatile_state[i]) {
+                       state_changed = true;
+                       break;
+               }
+       }
+
+       /*
+        * If the matrix state is changed from the previous scan
+        *   (Re)Begin the debouncing process, saving the new state in
+        *    keypad->matrix_unstable_state.
+        * else
+        *   Increase the count of number of scans with a stable state.
+        */
+       if (state_changed) {
+               memcpy(keypad->matrix_unstable_state, matrix_volatile_state,
+                       sizeof(matrix_volatile_state));
+               keypad->stable_count = 0;
+       } else
+               keypad->stable_count++;
+
+       /*
+        * If the matrix is not as stable as we want reschedule scan
+        * in the near future.
+        */
+       if (keypad->stable_count < IMX_KEYPAD_SCANS_FOR_STABILITY) {
+               mod_timer(&keypad->check_matrix_timer,
+                         jiffies + msecs_to_jiffies(10));
+               return;
+       }
+
+       /*
+        * If the matrix state is stable, fire the events and save the new
+        * stable state. Note, if the matrix is kept stable for longer
+        * (keypad->stable_count > IMX_KEYPAD_SCANS_FOR_STABILITY) all
+        * events have already been generated.
+        */
+       if (keypad->stable_count == IMX_KEYPAD_SCANS_FOR_STABILITY) {
+               imx_keypad_fire_events(keypad, matrix_volatile_state);
+
+               memcpy(keypad->matrix_stable_state, matrix_volatile_state,
+                       sizeof(matrix_volatile_state));
+       }
+
+       is_zero_matrix = true;
+       for (i = 0; i < MAX_MATRIX_KEY_COLS; i++) {
+               if (matrix_volatile_state[i] != 0) {
+                       is_zero_matrix = false;
+                       break;
+               }
+       }
+
+
+       if (is_zero_matrix) {
+               /*
+                * All keys have been released. Enable only the KDI
+                * interrupt for future key presses (clear the KDI
+                * status bit and its sync chain before that).
+                */
+               reg_val = readw(keypad->mmio_base + KPSR);
+               reg_val |= KBD_STAT_KPKD | KBD_STAT_KDSC;
+               writew(reg_val, keypad->mmio_base + KPSR);
+
+               reg_val = readw(keypad->mmio_base + KPSR);
+               reg_val |= KBD_STAT_KDIE;
+               reg_val &= ~KBD_STAT_KRIE;
+               writew(reg_val, keypad->mmio_base + KPSR);
+       } else {
+               /*
+                * Some keys are still pressed. Schedule a rescan in
+                * attempt to detect multiple key presses and enable
+                * the KRI interrupt to react quickly to key release
+                * event.
+                */
+               mod_timer(&keypad->check_matrix_timer,
+                         jiffies + msecs_to_jiffies(60));
+
+               reg_val = readw(keypad->mmio_base + KPSR);
+               reg_val |= KBD_STAT_KPKR | KBD_STAT_KRSS;
+               writew(reg_val, keypad->mmio_base + KPSR);
+
+               reg_val = readw(keypad->mmio_base + KPSR);
+               reg_val |= KBD_STAT_KRIE;
+               reg_val &= ~KBD_STAT_KDIE;
+               writew(reg_val, keypad->mmio_base + KPSR);
+       }
+}
+
+static irqreturn_t imx_keypad_irq_handler(int irq, void *dev_id)
+{
+       struct imx_keypad *keypad = dev_id;
+       unsigned short reg_val;
+
+       reg_val = readw(keypad->mmio_base + KPSR);
+
+       /* Disable both interrupt types */
+       reg_val &= ~(KBD_STAT_KRIE | KBD_STAT_KDIE);
+       /* Clear interrupts status bits */
+       reg_val |= KBD_STAT_KPKR | KBD_STAT_KPKD;
+       writew(reg_val, keypad->mmio_base + KPSR);
+
+       if (keypad->enabled) {
+               /* The matrix is supposed to be changed */
+               keypad->stable_count = 0;
+
+               /* Schedule the scanning procedure near in the future */
+               mod_timer(&keypad->check_matrix_timer,
+                         jiffies + msecs_to_jiffies(2));
+       }
+
+       return IRQ_HANDLED;
+}
+
+static void imx_keypad_config(struct imx_keypad *keypad)
+{
+       unsigned short reg_val;
+
+       /*
+        * Include enabled rows in interrupt generation (KPCR[7:0])
+        * Configure keypad columns as open-drain (KPCR[15:8])
+        */
+       reg_val = readw(keypad->mmio_base + KPCR);
+       reg_val |= keypad->rows_en_mask & 0xff;         /* rows */
+       reg_val |= (keypad->cols_en_mask & 0xff) << 8;  /* cols */
+       writew(reg_val, keypad->mmio_base + KPCR);
+
+       /* Write 0's to KPDR[15:8] (Colums) */
+       reg_val = readw(keypad->mmio_base + KPDR);
+       reg_val &= 0x00ff;
+       writew(reg_val, keypad->mmio_base + KPDR);
+
+       /* Configure columns as output, rows as input (KDDR[15:0]) */
+       writew(0xff00, keypad->mmio_base + KDDR);
+
+       /*
+        * Clear Key Depress and Key Release status bit.
+        * Clear both synchronizer chain.
+        */
+       reg_val = readw(keypad->mmio_base + KPSR);
+       reg_val |= KBD_STAT_KPKR | KBD_STAT_KPKD |
+                  KBD_STAT_KDSC | KBD_STAT_KRSS;
+       writew(reg_val, keypad->mmio_base + KPSR);
+
+       /* Enable KDI and disable KRI (avoid false release events). */
+       reg_val |= KBD_STAT_KDIE;
+       reg_val &= ~KBD_STAT_KRIE;
+       writew(reg_val, keypad->mmio_base + KPSR);
+}
+
+static void imx_keypad_inhibit(struct imx_keypad *keypad)
+{
+       unsigned short reg_val;
+
+       /* Inhibit KDI and KRI interrupts. */
+       reg_val = readw(keypad->mmio_base + KPSR);
+       reg_val &= ~(KBD_STAT_KRIE | KBD_STAT_KDIE);
+       writew(reg_val, keypad->mmio_base + KPSR);
+
+       /* Colums as open drain and disable all rows */
+       writew(0xff00, keypad->mmio_base + KPCR);
+}
+
+static void imx_keypad_close(struct input_dev *dev)
+{
+       struct imx_keypad *keypad = input_get_drvdata(dev);
+
+       dev_dbg(&dev->dev, ">%s\n", __func__);
+
+       /* Mark keypad as being inactive */
+       keypad->enabled = false;
+       synchronize_irq(keypad->irq);
+       del_timer_sync(&keypad->check_matrix_timer);
+
+       imx_keypad_inhibit(keypad);
+
+       /* Disable clock unit */
+       clk_disable(keypad->clk);
+}
+
+static int imx_keypad_open(struct input_dev *dev)
+{
+       struct imx_keypad *keypad = input_get_drvdata(dev);
+
+       dev_dbg(&dev->dev, ">%s\n", __func__);
+
+       /* We became active from now */
+       keypad->enabled = true;
+
+       /* Enable the kpp clock */
+       clk_enable(keypad->clk);
+       imx_keypad_config(keypad);
+
+       /* Sanity control, not all the rows must be actived now. */
+       if ((readw(keypad->mmio_base + KPDR) & keypad->rows_en_mask) == 0) {
+               dev_err(&dev->dev,
+                       "too many keys pressed, control pins initialisation\n");
+               goto open_err;
+       }
+
+       return 0;
+
+open_err:
+       imx_keypad_close(dev);
+       return -EIO;
+}
+
+static int __devinit imx_keypad_probe(struct platform_device *pdev)
+{
+       const struct matrix_keymap_data *keymap_data = pdev->dev.platform_data;
+       struct imx_keypad *keypad;
+       struct input_dev *input_dev;
+       struct resource *res;
+       int irq, error, i;
+
+       if (keymap_data == NULL) {
+               dev_err(&pdev->dev, "no keymap defined\n");
+               return -EINVAL;
+       }
+
+       irq = platform_get_irq(pdev, 0);
+       if (irq < 0) {
+               dev_err(&pdev->dev, "no irq defined in platform data\n");
+               return -EINVAL;
+       }
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (res == NULL) {
+               dev_err(&pdev->dev, "no I/O memory defined in platform data\n");
+               return -EINVAL;
+       }
+
+       res = request_mem_region(res->start, resource_size(res), pdev->name);
+       if (res == NULL) {
+               dev_err(&pdev->dev, "failed to request I/O memory\n");
+               return -EBUSY;
+       }
+
+       input_dev = input_allocate_device();
+       if (!input_dev) {
+               dev_err(&pdev->dev, "failed to allocate the input device\n");
+               error = -ENOMEM;
+               goto failed_rel_mem;
+       }
+
+       keypad = kzalloc(sizeof(struct imx_keypad), GFP_KERNEL);
+       if (!keypad) {
+               dev_err(&pdev->dev, "not enough memory for driver data\n");
+               error = -ENOMEM;
+               goto failed_free_input;
+       }
+
+       keypad->input_dev = input_dev;
+       keypad->irq = irq;
+       keypad->stable_count = 0;
+
+       setup_timer(&keypad->check_matrix_timer,
+                   imx_keypad_check_for_events, (unsigned long) keypad);
+
+       keypad->mmio_base = ioremap(res->start, resource_size(res));
+       if (keypad->mmio_base == NULL) {
+               dev_err(&pdev->dev, "failed to remap I/O memory\n");
+               error = -ENOMEM;
+               goto failed_free_priv;
+       }
+
+       keypad->clk = clk_get(&pdev->dev, "kpp");
+       if (IS_ERR(keypad->clk)) {
+               dev_err(&pdev->dev, "failed to get keypad clock\n");
+               error = PTR_ERR(keypad->clk);
+               goto failed_unmap;
+       }
+
+       /* Search for rows and cols enabled */
+       for (i = 0; i < keymap_data->keymap_size; i++) {
+               keypad->rows_en_mask |= 1 << KEY_ROW(keymap_data->keymap[i]);
+               keypad->cols_en_mask |= 1 << KEY_COL(keymap_data->keymap[i]);
+       }
+
+       if (keypad->rows_en_mask > ((1 << MAX_MATRIX_KEY_ROWS) - 1) ||
+          keypad->cols_en_mask > ((1 << MAX_MATRIX_KEY_COLS) - 1)) {
+               dev_err(&pdev->dev,
+                       "invalid key data (too many rows or colums)\n");
+               error = -EINVAL;
+               goto failed_clock_put;
+       }
+       dev_dbg(&pdev->dev, "enabled rows mask: %x\n", keypad->rows_en_mask);
+       dev_dbg(&pdev->dev, "enabled cols mask: %x\n", keypad->cols_en_mask);
+
+       /* Init the Input device */
+       input_dev->name = pdev->name;
+       input_dev->id.bustype = BUS_HOST;
+       input_dev->dev.parent = &pdev->dev;
+       input_dev->open = imx_keypad_open;
+       input_dev->close = imx_keypad_close;
+       input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP);
+       input_dev->keycode = keypad->keycodes;
+       input_dev->keycodesize = sizeof(keypad->keycodes[0]);
+       input_dev->keycodemax = ARRAY_SIZE(keypad->keycodes);
+
+       matrix_keypad_build_keymap(keymap_data, MATRIX_ROW_SHIFT,
+                               keypad->keycodes, input_dev->keybit);
+
+       input_set_capability(input_dev, EV_MSC, MSC_SCAN);
+       input_set_drvdata(input_dev, keypad);
+
+       /* Ensure that the keypad will stay dormant until opened */
+       imx_keypad_inhibit(keypad);
+
+       error = request_irq(irq, imx_keypad_irq_handler, IRQF_DISABLED,
+                           pdev->name, keypad);
+       if (error) {
+               dev_err(&pdev->dev, "failed to request IRQ\n");
+               goto failed_clock_put;
+       }
+
+       /* Register the input device */
+       error = input_register_device(input_dev);
+       if (error) {
+               dev_err(&pdev->dev, "failed to register input device\n");
+               goto failed_free_irq;
+       }
+
+       platform_set_drvdata(pdev, keypad);
+       device_init_wakeup(&pdev->dev, 1);
+
+       return 0;
+
+failed_free_irq:
+       free_irq(irq, pdev);
+failed_clock_put:
+       clk_put(keypad->clk);
+failed_unmap:
+       iounmap(keypad->mmio_base);
+failed_free_priv:
+       kfree(keypad);
+failed_free_input:
+       input_free_device(input_dev);
+failed_rel_mem:
+       release_mem_region(res->start, resource_size(res));
+       return error;
+}
+
+static int __devexit imx_keypad_remove(struct platform_device *pdev)
+{
+       struct imx_keypad *keypad = platform_get_drvdata(pdev);
+       struct resource *res;
+
+       dev_dbg(&pdev->dev, ">%s\n", __func__);
+
+       platform_set_drvdata(pdev, NULL);
+
+       input_unregister_device(keypad->input_dev);
+
+       free_irq(keypad->irq, keypad);
+       clk_put(keypad->clk);
+
+       iounmap(keypad->mmio_base);
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       release_mem_region(res->start, resource_size(res));
+
+       kfree(keypad);
+
+       return 0;
+}
+
+static struct platform_driver imx_keypad_driver = {
+       .driver         = {
+               .name   = "imx-keypad",
+               .owner  = THIS_MODULE,
+       },
+       .probe          = imx_keypad_probe,
+       .remove         = __devexit_p(imx_keypad_remove),
+};
+
+static int __init imx_keypad_init(void)
+{
+       return platform_driver_register(&imx_keypad_driver);
+}
+
+static void __exit imx_keypad_exit(void)
+{
+       platform_driver_unregister(&imx_keypad_driver);
+}
+
+module_init(imx_keypad_init);
+module_exit(imx_keypad_exit);
+
+MODULE_AUTHOR("Alberto Panizzo <maramaopercheseimorto@gmail.com>");
+MODULE_DESCRIPTION("IMX Keypad Port Driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:imx-keypad");
index 191cc51..31f3008 100644 (file)
@@ -362,7 +362,7 @@ static int __devexit qt2160_remove(struct i2c_client *client)
        return 0;
 }
 
-static struct i2c_device_id qt2160_idtable[] = {
+static const struct i2c_device_id qt2160_idtable[] = {
        { "qt2160", 0, },
        { }
 };
index 8e9380b..854e203 100644 (file)
 #include <linux/platform_device.h>
 #include <linux/input.h>
 #include <linux/input/sh_keysc.h>
+#include <linux/bitmap.h>
 #include <linux/clk.h>
 #include <linux/io.h>
 
-#define KYCR1_OFFS   0x00
-#define KYCR2_OFFS   0x04
-#define KYINDR_OFFS  0x08
-#define KYOUTDR_OFFS 0x0c
-
-#define KYCR2_IRQ_LEVEL    0x10
-#define KYCR2_IRQ_DISABLED 0x00
-
 static const struct {
        unsigned char kymd, keyout, keyin;
 } sh_keysc_mode[] = {
        [SH_KEYSC_MODE_1] = { 0, 6, 5 },
        [SH_KEYSC_MODE_2] = { 1, 5, 6 },
        [SH_KEYSC_MODE_3] = { 2, 4, 7 },
+       [SH_KEYSC_MODE_4] = { 3, 6, 6 },
+       [SH_KEYSC_MODE_5] = { 4, 6, 7 },
+       [SH_KEYSC_MODE_6] = { 5, 7, 7 },
 };
 
 struct sh_keysc_priv {
        void __iomem *iomem_base;
        struct clk *clk;
-       unsigned long last_keys;
+       DECLARE_BITMAP(last_keys, SH_KEYSC_MAXKEYS);
        struct input_dev *input;
        struct sh_keysc_info pdata;
 };
 
+#define KYCR1 0
+#define KYCR2 1
+#define KYINDR 2
+#define KYOUTDR 3
+
+#define KYCR2_IRQ_LEVEL    0x10
+#define KYCR2_IRQ_DISABLED 0x00
+
+static unsigned long sh_keysc_read(struct sh_keysc_priv *p, int reg_nr)
+{
+       return ioread16(p->iomem_base + (reg_nr << 2));
+}
+
+static void sh_keysc_write(struct sh_keysc_priv *p, int reg_nr,
+                          unsigned long value)
+{
+       iowrite16(value, p->iomem_base + (reg_nr << 2));
+}
+
+static void sh_keysc_level_mode(struct sh_keysc_priv *p,
+                               unsigned long keys_set)
+{
+       struct sh_keysc_info *pdata = &p->pdata;
+
+       sh_keysc_write(p, KYOUTDR, 0);
+       sh_keysc_write(p, KYCR2, KYCR2_IRQ_LEVEL | (keys_set << 8));
+
+       if (pdata->kycr2_delay)
+               udelay(pdata->kycr2_delay);
+}
+
+static void sh_keysc_map_dbg(struct device *dev, unsigned long *map,
+                            const char *str)
+{
+       int k;
+
+       for (k = 0; k < BITS_TO_LONGS(SH_KEYSC_MAXKEYS); k++)
+               dev_dbg(dev, "%s[%d] 0x%lx\n", str, k, map[k]);
+}
+
 static irqreturn_t sh_keysc_isr(int irq, void *dev_id)
 {
        struct platform_device *pdev = dev_id;
        struct sh_keysc_priv *priv = platform_get_drvdata(pdev);
        struct sh_keysc_info *pdata = &priv->pdata;
-       unsigned long keys, keys1, keys0, mask;
+       int keyout_nr = sh_keysc_mode[pdata->mode].keyout;
+       int keyin_nr = sh_keysc_mode[pdata->mode].keyin;
+       DECLARE_BITMAP(keys, SH_KEYSC_MAXKEYS);
+       DECLARE_BITMAP(keys0, SH_KEYSC_MAXKEYS);
+       DECLARE_BITMAP(keys1, SH_KEYSC_MAXKEYS);
        unsigned char keyin_set, tmp;
-       int i, k;
+       int i, k, n;
 
        dev_dbg(&pdev->dev, "isr!\n");
 
-       keys1 = ~0;
-       keys0 = 0;
+       bitmap_fill(keys1, SH_KEYSC_MAXKEYS);
+       bitmap_zero(keys0, SH_KEYSC_MAXKEYS);
 
        do {
-               keys = 0;
+               bitmap_zero(keys, SH_KEYSC_MAXKEYS);
                keyin_set = 0;
 
-               iowrite16(KYCR2_IRQ_DISABLED, priv->iomem_base + KYCR2_OFFS);
+               sh_keysc_write(priv, KYCR2, KYCR2_IRQ_DISABLED);
+
+               for (i = 0; i < keyout_nr; i++) {
+                       n = keyin_nr * i;
 
-               for (i = 0; i < sh_keysc_mode[pdata->mode].keyout; i++) {
-                       iowrite16(0xfff ^ (3 << (i * 2)),
-                                 priv->iomem_base + KYOUTDR_OFFS);
+                       /* drive one KEYOUT pin low, read KEYIN pins */
+                       sh_keysc_write(priv, KYOUTDR, 0xffff ^ (3 << (i * 2)));
                        udelay(pdata->delay);
-                       tmp = ioread16(priv->iomem_base + KYINDR_OFFS);
-                       keys |= tmp << (sh_keysc_mode[pdata->mode].keyin * i);
-                       tmp ^= (1 << sh_keysc_mode[pdata->mode].keyin) - 1;
-                       keyin_set |= tmp;
-               }
+                       tmp = sh_keysc_read(priv, KYINDR);
 
-               iowrite16(0, priv->iomem_base + KYOUTDR_OFFS);
-               iowrite16(KYCR2_IRQ_LEVEL | (keyin_set << 8),
-                         priv->iomem_base + KYCR2_OFFS);
+                       /* set bit if key press has been detected */
+                       for (k = 0; k < keyin_nr; k++) {
+                               if (tmp & (1 << k))
+                                       __set_bit(n + k, keys);
+                       }
 
-               if (pdata->kycr2_delay)
-                       udelay(pdata->kycr2_delay);
+                       /* keep track of which KEYIN bits that have been set */
+                       keyin_set |= tmp ^ ((1 << keyin_nr) - 1);
+               }
 
-               keys ^= ~0;
-               keys &= (1 << (sh_keysc_mode[pdata->mode].keyin *
-                              sh_keysc_mode[pdata->mode].keyout)) - 1;
-               keys1 &= keys;
-               keys0 |= keys;
+               sh_keysc_level_mode(priv, keyin_set);
 
-               dev_dbg(&pdev->dev, "keys 0x%08lx\n", keys);
+               bitmap_complement(keys, keys, SH_KEYSC_MAXKEYS);
+               bitmap_and(keys1, keys1, keys, SH_KEYSC_MAXKEYS);
+               bitmap_or(keys0, keys0, keys, SH_KEYSC_MAXKEYS);
 
-       } while (ioread16(priv->iomem_base + KYCR2_OFFS) & 0x01);
+               sh_keysc_map_dbg(&pdev->dev, keys, "keys");
 
-       dev_dbg(&pdev->dev, "last_keys 0x%08lx keys0 0x%08lx keys1 0x%08lx\n",
-               priv->last_keys, keys0, keys1);
+       } while (sh_keysc_read(priv, KYCR2) & 0x01);
+
+       sh_keysc_map_dbg(&pdev->dev, priv->last_keys, "last_keys");
+       sh_keysc_map_dbg(&pdev->dev, keys0, "keys0");
+       sh_keysc_map_dbg(&pdev->dev, keys1, "keys1");
 
        for (i = 0; i < SH_KEYSC_MAXKEYS; i++) {
                k = pdata->keycodes[i];
                if (!k)
                        continue;
 
-               mask = 1 << i;
-
-               if (!((priv->last_keys ^ keys0) & mask))
+               if (test_bit(i, keys0) == test_bit(i, priv->last_keys))
                        continue;
 
-               if ((keys1 | keys0) & mask) {
+               if (test_bit(i, keys1) || test_bit(i, keys0)) {
                        input_event(priv->input, EV_KEY, k, 1);
-                       priv->last_keys |= mask;
+                       __set_bit(i, priv->last_keys);
                }
 
-               if (!(keys1 & mask)) {
+               if (!test_bit(i, keys1)) {
                        input_event(priv->input, EV_KEY, k, 0);
-                       priv->last_keys &= ~mask;
+                       __clear_bit(i, priv->last_keys);
                }
 
        }
@@ -122,8 +162,6 @@ static irqreturn_t sh_keysc_isr(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-#define res_size(res) ((res)->end - (res)->start + 1)
-
 static int __devinit sh_keysc_probe(struct platform_device *pdev)
 {
        struct sh_keysc_priv *priv;
@@ -164,7 +202,7 @@ static int __devinit sh_keysc_probe(struct platform_device *pdev)
        memcpy(&priv->pdata, pdev->dev.platform_data, sizeof(priv->pdata));
        pdata = &priv->pdata;
 
-       priv->iomem_base = ioremap_nocache(res->start, res_size(res));
+       priv->iomem_base = ioremap_nocache(res->start, resource_size(res));
        if (priv->iomem_base == NULL) {
                dev_err(&pdev->dev, "failed to remap I/O memory\n");
                error = -ENXIO;
@@ -220,10 +258,9 @@ static int __devinit sh_keysc_probe(struct platform_device *pdev)
 
        clk_enable(priv->clk);
 
-       iowrite16((sh_keysc_mode[pdata->mode].kymd << 8) |
-                 pdata->scan_timing, priv->iomem_base + KYCR1_OFFS);
-       iowrite16(0, priv->iomem_base + KYOUTDR_OFFS);
-       iowrite16(KYCR2_IRQ_LEVEL, priv->iomem_base + KYCR2_OFFS);
+       sh_keysc_write(priv, KYCR1, (sh_keysc_mode[pdata->mode].kymd << 8) |
+                      pdata->scan_timing);
+       sh_keysc_level_mode(priv, 0);
 
        device_init_wakeup(&pdev->dev, 1);
 
@@ -248,7 +285,7 @@ static int __devexit sh_keysc_remove(struct platform_device *pdev)
 {
        struct sh_keysc_priv *priv = platform_get_drvdata(pdev);
 
-       iowrite16(KYCR2_IRQ_DISABLED, priv->iomem_base + KYCR2_OFFS);
+       sh_keysc_write(priv, KYCR2, KYCR2_IRQ_DISABLED);
 
        input_unregister_device(priv->input);
        free_irq(platform_get_irq(pdev, 0), pdev);
@@ -270,7 +307,7 @@ static int sh_keysc_suspend(struct device *dev)
        int irq = platform_get_irq(pdev, 0);
        unsigned short value;
 
-       value = ioread16(priv->iomem_base + KYCR1_OFFS);
+       value = sh_keysc_read(priv, KYCR1);
 
        if (device_may_wakeup(dev)) {
                value |= 0x80;
@@ -279,7 +316,7 @@ static int sh_keysc_suspend(struct device *dev)
                value &= ~0x80;
        }
 
-       iowrite16(value, priv->iomem_base + KYCR1_OFFS);
+       sh_keysc_write(priv, KYCR1, value);
 
        return 0;
 }
index 71b8243..a8d2b8d 100644 (file)
@@ -149,7 +149,7 @@ static void apanel_shutdown(struct i2c_client *client)
        apanel_remove(client);
 }
 
-static struct i2c_device_id apanel_id[] = {
+static const struct i2c_device_id apanel_id[] = {
        { "fujitsu_apanel", 0 },
        { }
 };
index 3b9f588..4ae0793 100644 (file)
@@ -152,6 +152,13 @@ static int __devinit rotary_encoder_probe(struct platform_device *pdev)
                goto exit_unregister_input;
        }
 
+       err = gpio_direction_input(pdata->gpio_a);
+       if (err) {
+               dev_err(&pdev->dev, "unable to set GPIO %d for input\n",
+                       pdata->gpio_a);
+               goto exit_unregister_input;
+       }
+
        err = gpio_request(pdata->gpio_b, DRV_NAME);
        if (err) {
                dev_err(&pdev->dev, "unable to request GPIO %d\n",
@@ -159,6 +166,13 @@ static int __devinit rotary_encoder_probe(struct platform_device *pdev)
                goto exit_free_gpio_a;
        }
 
+       err = gpio_direction_input(pdata->gpio_b);
+       if (err) {
+               dev_err(&pdev->dev, "unable to set GPIO %d for input\n",
+                       pdata->gpio_b);
+               goto exit_free_gpio_a;
+       }
+
        /* request the IRQs */
        err = request_irq(encoder->irq_a, &rotary_encoder_irq,
                          IORESOURCE_IRQ_HIGHEDGE | IORESOURCE_IRQ_LOWEDGE,
index d3f5724..1477466 100644 (file)
@@ -34,7 +34,6 @@
 #include <linux/slab.h>
 #include <linux/module.h>
 #include <linux/init.h>
-#include <linux/smp_lock.h>
 #include <linux/fs.h>
 #include <linux/miscdevice.h>
 #include <linux/uinput.h>
@@ -284,7 +283,6 @@ static int uinput_open(struct inode *inode, struct file *file)
        if (!newdev)
                return -ENOMEM;
 
-       lock_kernel();
        mutex_init(&newdev->mutex);
        spin_lock_init(&newdev->requests_lock);
        init_waitqueue_head(&newdev->requests_waitq);
@@ -292,7 +290,7 @@ static int uinput_open(struct inode *inode, struct file *file)
        newdev->state = UIST_NEW_DEVICE;
 
        file->private_data = newdev;
-       unlock_kernel();
+       nonseekable_open(inode, file);
 
        return 0;
 }
index c8f5a9a..cbec3df 100644 (file)
@@ -538,6 +538,7 @@ wbcir_reset_irdata(struct wbcir_data *data)
        data->irdata_count = 0;
        data->irdata_off = 0;
        data->irdata_error = 0;
+       data->idle_count = 0;
 }
 
 /* Adds one bit of irdata */
@@ -1006,7 +1007,6 @@ wbcir_irq_handler(int irqno, void *cookie)
                }
 
                wbcir_reset_irdata(data);
-               data->idle_count = 0;
        }
 
 out:
@@ -1018,7 +1018,7 @@ out:
 
 /*****************************************************************************
  *
- * SUSPEND/RESUME FUNCTIONS
+ * SETUP/INIT/SUSPEND/RESUME FUNCTIONS
  *
  *****************************************************************************/
 
@@ -1197,7 +1197,16 @@ finish:
        }
 
        /* Disable interrupts */
+       wbcir_select_bank(data, WBCIR_BANK_0);
        outb(WBCIR_IRQ_NONE, data->sbase + WBCIR_REG_SP3_IER);
+
+       /*
+        * ACPI will set the HW disable bit for SP3 which means that the
+        * output signals are left in an undefined state which may cause
+        * spurious interrupts which we need to ignore until the hardware
+        * is reinitialized.
+        */
+       disable_irq(data->irq);
 }
 
 static int
@@ -1207,37 +1216,15 @@ wbcir_suspend(struct pnp_dev *device, pm_message_t state)
        return 0;
 }
 
-static int
-wbcir_resume(struct pnp_dev *device)
-{
-       struct wbcir_data *data = pnp_get_drvdata(device);
-
-       /* Clear BUFF_EN, Clear END_EN, Clear MATCH_EN */
-       wbcir_set_bits(data->wbase + WBCIR_REG_WCEIR_EV_EN, 0x00, 0x07);
-
-       /* Clear CEIR_EN */
-       wbcir_set_bits(data->wbase + WBCIR_REG_WCEIR_CTL, 0x00, 0x01);
-
-       /* Enable interrupts */
-       wbcir_reset_irdata(data);
-       outb(WBCIR_IRQ_RX | WBCIR_IRQ_ERR, data->sbase + WBCIR_REG_SP3_IER);
-
-       return 0;
-}
-
-
-
-/*****************************************************************************
- *
- * SETUP/INIT FUNCTIONS
- *
- *****************************************************************************/
-
 static void
-wbcir_cfg_ceir(struct wbcir_data *data)
+wbcir_init_hw(struct wbcir_data *data)
 {
        u8 tmp;
 
+       /* Disable interrupts */
+       wbcir_select_bank(data, WBCIR_BANK_0);
+       outb(WBCIR_IRQ_NONE, data->sbase + WBCIR_REG_SP3_IER);
+
        /* Set PROT_SEL, RX_INV, Clear CEIR_EN (needed for the led) */
        tmp = protocol << 4;
        if (invert)
@@ -1264,6 +1251,93 @@ wbcir_cfg_ceir(struct wbcir_data *data)
         * set SP3_IRRX_SW to binary 01, helpfully not documented
         */
        outb(0x10, data->ebase + WBCIR_REG_ECEIR_CTS);
+
+       /* Enable extended mode */
+       wbcir_select_bank(data, WBCIR_BANK_2);
+       outb(WBCIR_EXT_ENABLE, data->sbase + WBCIR_REG_SP3_EXCR1);
+
+       /*
+        * Configure baud generator, IR data will be sampled at
+        * a bitrate of: (24Mhz * prescaler) / (divisor * 16).
+        *
+        * The ECIR registers include a flag to change the
+        * 24Mhz clock freq to 48Mhz.
+        *
+        * It's not documented in the specs, but fifo levels
+        * other than 16 seems to be unsupported.
+        */
+
+       /* prescaler 1.0, tx/rx fifo lvl 16 */
+       outb(0x30, data->sbase + WBCIR_REG_SP3_EXCR2);
+
+       /* Set baud divisor to generate one byte per bit/cell */
+       switch (protocol) {
+       case IR_PROTOCOL_RC5:
+               outb(0xA7, data->sbase + WBCIR_REG_SP3_BGDL);
+               break;
+       case IR_PROTOCOL_RC6:
+               outb(0x53, data->sbase + WBCIR_REG_SP3_BGDL);
+               break;
+       case IR_PROTOCOL_NEC:
+               outb(0x69, data->sbase + WBCIR_REG_SP3_BGDL);
+               break;
+       }
+       outb(0x00, data->sbase + WBCIR_REG_SP3_BGDH);
+
+       /* Set CEIR mode */
+       wbcir_select_bank(data, WBCIR_BANK_0);
+       outb(0xC0, data->sbase + WBCIR_REG_SP3_MCR);
+       inb(data->sbase + WBCIR_REG_SP3_LSR); /* Clear LSR */
+       inb(data->sbase + WBCIR_REG_SP3_MSR); /* Clear MSR */
+
+       /* Disable RX demod, run-length encoding/decoding, set freq span */
+       wbcir_select_bank(data, WBCIR_BANK_7);
+       outb(0x10, data->sbase + WBCIR_REG_SP3_RCCFG);
+
+       /* Disable timer */
+       wbcir_select_bank(data, WBCIR_BANK_4);
+       outb(0x00, data->sbase + WBCIR_REG_SP3_IRCR1);
+
+       /* Enable MSR interrupt, Clear AUX_IRX */
+       wbcir_select_bank(data, WBCIR_BANK_5);
+       outb(0x00, data->sbase + WBCIR_REG_SP3_IRCR2);
+
+       /* Disable CRC */
+       wbcir_select_bank(data, WBCIR_BANK_6);
+       outb(0x20, data->sbase + WBCIR_REG_SP3_IRCR3);
+
+       /* Set RX/TX (de)modulation freq, not really used */
+       wbcir_select_bank(data, WBCIR_BANK_7);
+       outb(0xF2, data->sbase + WBCIR_REG_SP3_IRRXDC);
+       outb(0x69, data->sbase + WBCIR_REG_SP3_IRTXMC);
+
+       /* Set invert and pin direction */
+       if (invert)
+               outb(0x10, data->sbase + WBCIR_REG_SP3_IRCFG4);
+       else
+               outb(0x00, data->sbase + WBCIR_REG_SP3_IRCFG4);
+
+       /* Set FIFO thresholds (RX = 8, TX = 3), reset RX/TX */
+       wbcir_select_bank(data, WBCIR_BANK_0);
+       outb(0x97, data->sbase + WBCIR_REG_SP3_FCR);
+
+       /* Clear AUX status bits */
+       outb(0xE0, data->sbase + WBCIR_REG_SP3_ASCR);
+
+       /* Enable interrupts */
+       wbcir_reset_irdata(data);
+       outb(WBCIR_IRQ_RX | WBCIR_IRQ_ERR, data->sbase + WBCIR_REG_SP3_IER);
+}
+
+static int
+wbcir_resume(struct pnp_dev *device)
+{
+       struct wbcir_data *data = pnp_get_drvdata(device);
+
+       wbcir_init_hw(data);
+       enable_irq(data->irq);
+
+       return 0;
 }
 
 static int __devinit
@@ -1393,86 +1467,7 @@ wbcir_probe(struct pnp_dev *device, const struct pnp_device_id *dev_id)
 
        device_init_wakeup(&device->dev, 1);
 
-       wbcir_cfg_ceir(data);
-
-       /* Disable interrupts */
-       wbcir_select_bank(data, WBCIR_BANK_0);
-       outb(WBCIR_IRQ_NONE, data->sbase + WBCIR_REG_SP3_IER);
-
-       /* Enable extended mode */
-       wbcir_select_bank(data, WBCIR_BANK_2);
-       outb(WBCIR_EXT_ENABLE, data->sbase + WBCIR_REG_SP3_EXCR1);
-
-       /*
-        * Configure baud generator, IR data will be sampled at
-        * a bitrate of: (24Mhz * prescaler) / (divisor * 16).
-        *
-        * The ECIR registers include a flag to change the
-        * 24Mhz clock freq to 48Mhz.
-        *
-        * It's not documented in the specs, but fifo levels
-        * other than 16 seems to be unsupported.
-        */
-
-       /* prescaler 1.0, tx/rx fifo lvl 16 */
-       outb(0x30, data->sbase + WBCIR_REG_SP3_EXCR2);
-
-       /* Set baud divisor to generate one byte per bit/cell */
-       switch (protocol) {
-       case IR_PROTOCOL_RC5:
-               outb(0xA7, data->sbase + WBCIR_REG_SP3_BGDL);
-               break;
-       case IR_PROTOCOL_RC6:
-               outb(0x53, data->sbase + WBCIR_REG_SP3_BGDL);
-               break;
-       case IR_PROTOCOL_NEC:
-               outb(0x69, data->sbase + WBCIR_REG_SP3_BGDL);
-               break;
-       }
-       outb(0x00, data->sbase + WBCIR_REG_SP3_BGDH);
-
-       /* Set CEIR mode */
-       wbcir_select_bank(data, WBCIR_BANK_0);
-       outb(0xC0, data->sbase + WBCIR_REG_SP3_MCR);
-       inb(data->sbase + WBCIR_REG_SP3_LSR); /* Clear LSR */
-       inb(data->sbase + WBCIR_REG_SP3_MSR); /* Clear MSR */
-
-       /* Disable RX demod, run-length encoding/decoding, set freq span */
-       wbcir_select_bank(data, WBCIR_BANK_7);
-       outb(0x10, data->sbase + WBCIR_REG_SP3_RCCFG);
-
-       /* Disable timer */
-       wbcir_select_bank(data, WBCIR_BANK_4);
-       outb(0x00, data->sbase + WBCIR_REG_SP3_IRCR1);
-
-       /* Enable MSR interrupt, Clear AUX_IRX */
-       wbcir_select_bank(data, WBCIR_BANK_5);
-       outb(0x00, data->sbase + WBCIR_REG_SP3_IRCR2);
-
-       /* Disable CRC */
-       wbcir_select_bank(data, WBCIR_BANK_6);
-       outb(0x20, data->sbase + WBCIR_REG_SP3_IRCR3);
-
-       /* Set RX/TX (de)modulation freq, not really used */
-       wbcir_select_bank(data, WBCIR_BANK_7);
-       outb(0xF2, data->sbase + WBCIR_REG_SP3_IRRXDC);
-       outb(0x69, data->sbase + WBCIR_REG_SP3_IRTXMC);
-
-       /* Set invert and pin direction */
-       if (invert)
-               outb(0x10, data->sbase + WBCIR_REG_SP3_IRCFG4);
-       else
-               outb(0x00, data->sbase + WBCIR_REG_SP3_IRCFG4);
-
-       /* Set FIFO thresholds (RX = 8, TX = 3), reset RX/TX */
-       wbcir_select_bank(data, WBCIR_BANK_0);
-       outb(0x97, data->sbase + WBCIR_REG_SP3_FCR);
-
-       /* Clear AUX status bits */
-       outb(0xE0, data->sbase + WBCIR_REG_SP3_ASCR);
-
-       /* Enable interrupts */
-       outb(WBCIR_IRQ_RX | WBCIR_IRQ_ERR, data->sbase + WBCIR_REG_SP3_IER);
+       wbcir_init_hw(data);
 
        return 0;
 
index 90be30e..9169d15 100644 (file)
@@ -68,10 +68,6 @@ module_param(post_interrupt_delay, int, 0644);
 MODULE_PARM_DESC(post_interrupt_delay,
        "delay (ms) before recal after recal interrupt detected");
 
-static int autorecal = 1;
-module_param(autorecal, int, 0644);
-MODULE_PARM_DESC(autorecal, "enable recalibration in the driver");
-
 /*
  * When the touchpad gets ultra-sensitive, one can keep their finger 1/2"
  * above the pad and still have it send packets.  This causes a jump cursor
index 1dacbe0..797314b 100644 (file)
@@ -186,7 +186,7 @@ static void __devexit pcips2_remove(struct pci_dev *dev)
        pci_disable_device(dev);
 }
 
-static struct pci_device_id pcips2_ids[] = {
+static const struct pci_device_id pcips2_ids[] = {
        {
                .vendor         = 0x14f2,       /* MOBILITY */
                .device         = 0x0123,       /* Keyboard */
index e0f3018..c3b626e 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/stddef.h>
 #include <linux/module.h>
 #include <linux/serio.h>
@@ -119,11 +121,10 @@ static int serio_bind_driver(struct serio *serio, struct serio_driver *drv)
 
                error = device_bind_driver(&serio->dev);
                if (error) {
-                       printk(KERN_WARNING
-                               "serio: device_bind_driver() failed "
-                               "for %s (%s) and %s, error: %d\n",
-                               serio->phys, serio->name,
-                               drv->description, error);
+                       dev_warn(&serio->dev,
+                                "device_bind_driver() failed for %s (%s) and %s, error: %d\n",
+                                serio->phys, serio->name,
+                                drv->description, error);
                        serio_disconnect_driver(serio);
                        serio->dev.driver = NULL;
                        return error;
@@ -138,9 +139,9 @@ static void serio_find_driver(struct serio *serio)
 
        error = device_attach(&serio->dev);
        if (error < 0)
-               printk(KERN_WARNING
-                       "serio: device_attach() failed for %s (%s), error: %d\n",
-                       serio->phys, serio->name, error);
+               dev_warn(&serio->dev,
+                        "device_attach() failed for %s (%s), error: %d\n",
+                        serio->phys, serio->name, error);
 }
 
 
@@ -194,17 +195,14 @@ static int serio_queue_event(void *object, struct module *owner,
 
        event = kmalloc(sizeof(struct serio_event), GFP_ATOMIC);
        if (!event) {
-               printk(KERN_ERR
-                       "serio: Not enough memory to queue event %d\n",
-                       event_type);
+               pr_err("Not enough memory to queue event %d\n", event_type);
                retval = -ENOMEM;
                goto out;
        }
 
        if (!try_module_get(owner)) {
-               printk(KERN_WARNING
-                       "serio: Can't get module reference, dropping event %d\n",
-                       event_type);
+               pr_warning("Can't get module reference, dropping event %d\n",
+                          event_type);
                kfree(event);
                retval = -EINVAL;
                goto out;
@@ -230,14 +228,12 @@ static void serio_free_event(struct serio_event *event)
 
 static void serio_remove_duplicate_events(struct serio_event *event)
 {
-       struct list_head *node, *next;
-       struct serio_event *e;
+       struct serio_event *e, *next;
        unsigned long flags;
 
        spin_lock_irqsave(&serio_event_lock, flags);
 
-       list_for_each_safe(node, next, &serio_event_list) {
-               e = list_entry(node, struct serio_event, node);
+       list_for_each_entry_safe(e, next, &serio_event_list, node) {
                if (event->object == e->object) {
                        /*
                         * If this event is of different type we should not
@@ -247,7 +243,7 @@ static void serio_remove_duplicate_events(struct serio_event *event)
                        if (event->type != e->type)
                                break;
 
-                       list_del_init(node);
+                       list_del_init(&e->node);
                        serio_free_event(e);
                }
        }
@@ -258,23 +254,18 @@ static void serio_remove_duplicate_events(struct serio_event *event)
 
 static struct serio_event *serio_get_event(void)
 {
-       struct serio_event *event;
-       struct list_head *node;
+       struct serio_event *event = NULL;
        unsigned long flags;
 
        spin_lock_irqsave(&serio_event_lock, flags);
 
-       if (list_empty(&serio_event_list)) {
-               spin_unlock_irqrestore(&serio_event_lock, flags);
-               return NULL;
+       if (!list_empty(&serio_event_list)) {
+               event = list_first_entry(&serio_event_list,
+                                        struct serio_event, node);
+               list_del_init(&event->node);
        }
 
-       node = serio_event_list.next;
-       event = list_entry(node, struct serio_event, node);
-       list_del_init(node);
-
        spin_unlock_irqrestore(&serio_event_lock, flags);
-
        return event;
 }
 
@@ -287,29 +278,27 @@ static void serio_handle_event(void)
        while ((event = serio_get_event())) {
 
                switch (event->type) {
-                       case SERIO_REGISTER_PORT:
-                               serio_add_port(event->object);
-                               break;
 
-                       case SERIO_RECONNECT_PORT:
-                               serio_reconnect_port(event->object);
-                               break;
+               case SERIO_REGISTER_PORT:
+                       serio_add_port(event->object);
+                       break;
 
-                       case SERIO_RESCAN_PORT:
-                               serio_disconnect_port(event->object);
-                               serio_find_driver(event->object);
-                               break;
+               case SERIO_RECONNECT_PORT:
+                       serio_reconnect_port(event->object);
+                       break;
 
-                       case SERIO_RECONNECT_CHAIN:
-                               serio_reconnect_chain(event->object);
-                               break;
+               case SERIO_RESCAN_PORT:
+                       serio_disconnect_port(event->object);
+                       serio_find_driver(event->object);
+                       break;
 
-                       case SERIO_ATTACH_DRIVER:
-                               serio_attach_driver(event->object);
-                               break;
+               case SERIO_RECONNECT_CHAIN:
+                       serio_reconnect_chain(event->object);
+                       break;
 
-                       default:
-                               break;
+               case SERIO_ATTACH_DRIVER:
+                       serio_attach_driver(event->object);
+                       break;
                }
 
                serio_remove_duplicate_events(event);
@@ -325,16 +314,14 @@ static void serio_handle_event(void)
  */
 static void serio_remove_pending_events(void *object)
 {
-       struct list_head *node, *next;
-       struct serio_event *event;
+       struct serio_event *event, *next;
        unsigned long flags;
 
        spin_lock_irqsave(&serio_event_lock, flags);
 
-       list_for_each_safe(node, next, &serio_event_list) {
-               event = list_entry(node, struct serio_event, node);
+       list_for_each_entry_safe(event, next, &serio_event_list, node) {
                if (event->object == object) {
-                       list_del_init(node);
+                       list_del_init(&event->node);
                        serio_free_event(event);
                }
        }
@@ -380,7 +367,6 @@ static int serio_thread(void *nothing)
                        kthread_should_stop() || !list_empty(&serio_event_list));
        } while (!kthread_should_stop());
 
-       printk(KERN_DEBUG "serio: kseriod exiting\n");
        return 0;
 }
 
@@ -445,6 +431,11 @@ static struct attribute_group serio_id_attr_group = {
        .attrs  = serio_device_id_attrs,
 };
 
+static const struct attribute_group *serio_device_attr_groups[] = {
+       &serio_id_attr_group,
+       NULL
+};
+
 static ssize_t serio_rebind_driver(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
 {
        struct serio *serio = to_serio_port(dev);
@@ -532,6 +523,7 @@ static void serio_init_port(struct serio *serio)
                        (long)atomic_inc_return(&serio_no) - 1);
        serio->dev.bus = &serio_bus;
        serio->dev.release = serio_release_port;
+       serio->dev.groups = serio_device_attr_groups;
        if (serio->parent) {
                serio->dev.parent = &serio->parent->dev;
                serio->depth = serio->parent->depth + 1;
@@ -555,21 +547,15 @@ static void serio_add_port(struct serio *serio)
        }
 
        list_add_tail(&serio->node, &serio_list);
+
        if (serio->start)
                serio->start(serio);
+
        error = device_add(&serio->dev);
        if (error)
-               printk(KERN_ERR
-                       "serio: device_add() failed for %s (%s), error: %d\n",
+               dev_err(&serio->dev,
+                       "device_add() failed for %s (%s), error: %d\n",
                        serio->phys, serio->name, error);
-       else {
-               serio->registered = true;
-               error = sysfs_create_group(&serio->dev.kobj, &serio_id_attr_group);
-               if (error)
-                       printk(KERN_ERR
-                               "serio: sysfs_create_group() failed for %s (%s), error: %d\n",
-                               serio->phys, serio->name, error);
-       }
 }
 
 /*
@@ -596,11 +582,8 @@ static void serio_destroy_port(struct serio *serio)
                serio->parent = NULL;
        }
 
-       if (serio->registered) {
-               sysfs_remove_group(&serio->dev.kobj, &serio_id_attr_group);
+       if (device_is_registered(&serio->dev))
                device_del(&serio->dev);
-               serio->registered = false;
-       }
 
        list_del_init(&serio->node);
        serio_remove_pending_events(serio);
@@ -798,9 +781,8 @@ static void serio_attach_driver(struct serio_driver *drv)
 
        error = driver_attach(&drv->driver);
        if (error)
-               printk(KERN_WARNING
-                       "serio: driver_attach() failed for %s with error %d\n",
-                       drv->driver.name, error);
+               pr_warning("driver_attach() failed for %s with error %d\n",
+                          drv->driver.name, error);
 }
 
 int __serio_register_driver(struct serio_driver *drv, struct module *owner, const char *mod_name)
@@ -820,8 +802,7 @@ int __serio_register_driver(struct serio_driver *drv, struct module *owner, cons
 
        error = driver_register(&drv->driver);
        if (error) {
-               printk(KERN_ERR
-                       "serio: driver_register() failed for %s, error: %d\n",
+               pr_err("driver_register() failed for %s, error: %d\n",
                        drv->driver.name, error);
                return error;
        }
@@ -987,7 +968,7 @@ irqreturn_t serio_interrupt(struct serio *serio,
 
         if (likely(serio->drv)) {
                 ret = serio->drv->interrupt(serio, data, dfl);
-       } else if (!dfl && serio->registered) {
+       } else if (!dfl && device_is_registered(&serio->dev)) {
                serio_rescan(serio);
                ret = IRQ_HANDLED;
        }
@@ -1018,7 +999,7 @@ static int __init serio_init(void)
 
        error = bus_register(&serio_bus);
        if (error) {
-               printk(KERN_ERR "serio: failed to register serio bus, error: %d\n", error);
+               pr_err("Failed to register serio bus, error: %d\n", error);
                return error;
        }
 
@@ -1026,7 +1007,7 @@ static int __init serio_init(void)
        if (IS_ERR(serio_task)) {
                bus_unregister(&serio_bus);
                error = PTR_ERR(serio_task);
-               printk(KERN_ERR "serio: Failed to start kseriod, error: %d\n", error);
+               pr_err("Failed to start kseriod, error: %d\n", error);
                return error;
        }
 
index ebb22f8..8298e1f 100644 (file)
@@ -270,7 +270,7 @@ static int __devinit xps2_of_probe(struct of_device *ofdev,
        drvdata->irq = r_irq.start;
 
        phys_addr = r_mem.start;
-       remap_size = r_mem.end - r_mem.start + 1;
+       remap_size = resource_size(&r_mem);
        if (!request_mem_region(phys_addr, remap_size, DRIVER_NAME)) {
                dev_err(dev, "Couldn't lock memory region at 0x%08llX\n",
                        (unsigned long long)phys_addr);
@@ -344,7 +344,7 @@ static int __devexit xps2_of_remove(struct of_device *of_dev)
        if (of_address_to_resource(of_dev->node, 0, &r_mem))
                dev_err(dev, "invalid address\n");
        else
-               release_mem_region(r_mem.start, r_mem.end - r_mem.start + 1);
+               release_mem_region(r_mem.start, resource_size(&r_mem));
 
        kfree(drvdata);
 
@@ -354,7 +354,7 @@ static int __devexit xps2_of_remove(struct of_device *of_dev)
 }
 
 /* Match table for of_platform binding */
-static struct of_device_id xps2_of_match[] __devinitdata = {
+static const struct of_device_id xps2_of_match[] __devinitconst = {
        { .compatible = "xlnx,xps-ps2-1.00.a", },
        { /* end of list */ },
 };
index 3d32d3f..866a9ee 100644 (file)
@@ -92,7 +92,7 @@ Scott Hill shill@gtcocalcomp.com
 /* DATA STRUCTURES */
 
 /* Device table */
-static struct usb_device_id gtco_usbid_table [] = {
+static const struct usb_device_id gtco_usbid_table[] = {
        { USB_DEVICE(VENDOR_ID_GTCO, PID_400) },
        { USB_DEVICE(VENDOR_ID_GTCO, PID_401) },
        { USB_DEVICE(VENDOR_ID_GTCO, PID_1000) },
index 16310f3..8fef1b6 100644 (file)
@@ -85,6 +85,7 @@
 #include <linux/kernel.h>
 #include <linux/slab.h>
 #include <linux/module.h>
+#include <linux/mod_devicetable.h>
 #include <linux/init.h>
 #include <linux/usb/input.h>
 #include <asm/unaligned.h>
@@ -120,6 +121,8 @@ struct wacom_combo {
        struct urb *urb;
 };
 
+extern const struct usb_device_id wacom_ids[];
+
 extern int wacom_wac_irq(struct wacom_wac * wacom_wac, void * wcombo);
 extern void wacom_report_abs(void *wcombo, unsigned int abs_type, int abs_data);
 extern void wacom_report_rel(void *wcombo, unsigned int rel_type, int rel_data);
@@ -142,7 +145,5 @@ extern void input_dev_mo(struct input_dev *input_dev, struct wacom_wac *wacom_wa
 extern void input_dev_bee(struct input_dev *input_dev, struct wacom_wac *wacom_wac);
 extern __u16 wacom_le16_to_cpu(unsigned char *data);
 extern __u16 wacom_be16_to_cpu(unsigned char *data);
-extern struct wacom_features *get_wacom_feature(const struct usb_device_id *id);
-extern const struct usb_device_id *get_device_table(void);
 
 #endif
index 072f33b..a1770e6 100644 (file)
@@ -211,7 +211,8 @@ void input_dev_g(struct input_dev *input_dev, struct wacom_wac *wacom_wac)
        input_dev->keybit[BIT_WORD(BTN_DIGI)] |= BIT_MASK(BTN_TOOL_RUBBER) |
                BIT_MASK(BTN_TOOL_PEN) | BIT_MASK(BTN_STYLUS) |
                BIT_MASK(BTN_TOOL_MOUSE) | BIT_MASK(BTN_STYLUS2);
-       input_set_abs_params(input_dev, ABS_DISTANCE, 0, wacom_wac->features->distance_max, 0, 0);
+       input_set_abs_params(input_dev, ABS_DISTANCE,
+                            0, wacom_wac->features.distance_max, 0, 0);
 }
 
 void input_dev_i3s(struct input_dev *input_dev, struct wacom_wac *wacom_wac)
@@ -261,7 +262,8 @@ void input_dev_i(struct input_dev *input_dev, struct wacom_wac *wacom_wac)
                BIT_MASK(BTN_TOOL_MOUSE) | BIT_MASK(BTN_TOOL_BRUSH) |
                BIT_MASK(BTN_TOOL_PENCIL) | BIT_MASK(BTN_TOOL_AIRBRUSH) |
                BIT_MASK(BTN_TOOL_LENS) | BIT_MASK(BTN_STYLUS2);
-       input_set_abs_params(input_dev, ABS_DISTANCE, 0, wacom_wac->features->distance_max, 0, 0);
+       input_set_abs_params(input_dev, ABS_DISTANCE,
+                            0, wacom_wac->features.distance_max, 0, 0);
        input_set_abs_params(input_dev, ABS_WHEEL, 0, 1023, 0, 0);
        input_set_abs_params(input_dev, ABS_TILT_X, 0, 127, 0, 0);
        input_set_abs_params(input_dev, ABS_TILT_Y, 0, 127, 0, 0);
@@ -282,17 +284,19 @@ void input_dev_pt(struct input_dev *input_dev, struct wacom_wac *wacom_wac)
 
 void input_dev_tpc(struct input_dev *input_dev, struct wacom_wac *wacom_wac)
 {
-       if (wacom_wac->features->device_type == BTN_TOOL_DOUBLETAP ||
-           wacom_wac->features->device_type == BTN_TOOL_TRIPLETAP) {
-               input_set_abs_params(input_dev, ABS_RX, 0, wacom_wac->features->x_phy, 0, 0);
-               input_set_abs_params(input_dev, ABS_RY, 0, wacom_wac->features->y_phy, 0, 0);
-               input_dev->keybit[BIT_WORD(BTN_DIGI)] |= BIT_MASK(BTN_TOOL_DOUBLETAP);
+       struct wacom_features *features = &wacom_wac->features;
+
+       if (features->device_type == BTN_TOOL_DOUBLETAP ||
+           features->device_type == BTN_TOOL_TRIPLETAP) {
+               input_set_abs_params(input_dev, ABS_RX, 0, features->x_phy, 0, 0);
+               input_set_abs_params(input_dev, ABS_RY, 0, features->y_phy, 0, 0);
+               __set_bit(BTN_TOOL_DOUBLETAP, input_dev->keybit);
        }
 }
 
 void input_dev_tpc2fg(struct input_dev *input_dev, struct wacom_wac *wacom_wac)
 {
-       if (wacom_wac->features->device_type == BTN_TOOL_TRIPLETAP) {
+       if (wacom_wac->features.device_type == BTN_TOOL_TRIPLETAP) {
                input_dev->keybit[BIT_WORD(BTN_DIGI)] |= BIT_MASK(BTN_TOOL_TRIPLETAP);
                input_dev->evbit[0] |= BIT_MASK(EV_MSC);
                input_dev->mscbit[0] |= BIT_MASK(MSC_SERIAL);
@@ -532,21 +536,38 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i
        struct wacom_wac *wacom_wac;
        struct wacom_features *features;
        struct input_dev *input_dev;
-       int error = -ENOMEM;
+       int error;
+
+       if (!id->driver_info)
+               return -EINVAL;
 
        wacom = kzalloc(sizeof(struct wacom), GFP_KERNEL);
        wacom_wac = kzalloc(sizeof(struct wacom_wac), GFP_KERNEL);
        input_dev = input_allocate_device();
-       if (!wacom || !input_dev || !wacom_wac)
+       if (!wacom || !input_dev || !wacom_wac) {
+               error = -ENOMEM;
                goto fail1;
+       }
 
-       wacom_wac->data = usb_buffer_alloc(dev, WACOM_PKGLEN_MAX, GFP_KERNEL, &wacom->data_dma);
-       if (!wacom_wac->data)
+       wacom_wac->features = *((struct wacom_features *)id->driver_info);
+       features = &wacom_wac->features;
+       if (features->pktlen > WACOM_PKGLEN_MAX) {
+               error = -EINVAL;
                goto fail1;
+       }
+
+       wacom_wac->data = usb_buffer_alloc(dev, WACOM_PKGLEN_MAX,
+                                          GFP_KERNEL, &wacom->data_dma);
+       if (!wacom_wac->data) {
+               error = -ENOMEM;
+               goto fail1;
+       }
 
        wacom->irq = usb_alloc_urb(0, GFP_KERNEL);
-       if (!wacom->irq)
+       if (!wacom->irq) {
+               error = -ENOMEM;
                goto fail2;
+       }
 
        wacom->usbdev = dev;
        wacom->dev = input_dev;
@@ -555,11 +576,6 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i
        usb_make_path(dev, wacom->phys, sizeof(wacom->phys));
        strlcat(wacom->phys, "/input0", sizeof(wacom->phys));
 
-       wacom_wac->features = features = get_wacom_feature(id);
-       BUG_ON(features->pktlen > WACOM_PKGLEN_MAX);
-
-       input_dev->name = wacom_wac->features->name;
-       wacom->wacom_wac = wacom_wac;
        usb_to_input_id(dev, &input_dev->id);
 
        input_dev->dev.parent = &intf->dev;
@@ -576,6 +592,19 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i
        if (error)
                goto fail2;
 
+       strlcpy(wacom_wac->name, features->name, sizeof(wacom_wac->name));
+
+       if (features->type == TABLETPC || features->type == TABLETPC2FG) {
+               /* Append the device type to the name */
+               strlcat(wacom_wac->name,
+                       features->device_type == BTN_TOOL_PEN ?
+                               " Pen" : " Finger",
+                       sizeof(wacom_wac->name));
+       }
+
+       input_dev->name = wacom_wac->name;
+       wacom->wacom_wac = wacom_wac;
+
        input_dev->evbit[0] |= BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
        input_dev->keybit[BIT_WORD(BTN_DIGI)] |= BIT_MASK(BTN_TOUCH);
 
@@ -640,7 +669,7 @@ static int wacom_suspend(struct usb_interface *intf, pm_message_t message)
 static int wacom_resume(struct usb_interface *intf)
 {
        struct wacom *wacom = usb_get_intfdata(intf);
-       struct wacom_features *features = wacom->wacom_wac->features;
+       struct wacom_features *features = &wacom->wacom_wac->features;
        int rv;
 
        mutex_lock(&wacom->lock);
@@ -663,6 +692,7 @@ static int wacom_reset_resume(struct usb_interface *intf)
 
 static struct usb_driver wacom_driver = {
        .name =         "wacom",
+       .id_table =     wacom_ids,
        .probe =        wacom_probe,
        .disconnect =   wacom_disconnect,
        .suspend =      wacom_suspend,
@@ -674,7 +704,7 @@ static struct usb_driver wacom_driver = {
 static int __init wacom_init(void)
 {
        int result;
-       wacom_driver.id_table = get_device_table();
+
        result = usb_register(&wacom_driver);
        if (result == 0)
                printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
index 1056f14..3d81443 100644 (file)
@@ -55,6 +55,7 @@ static int wacom_penpartner_irq(struct wacom_wac *wacom, void *wcombo)
 
 static int wacom_pl_irq(struct wacom_wac *wacom, void *wcombo)
 {
+       struct wacom_features *features = &wacom->features;
        unsigned char *data = wacom->data;
        int prox, pressure;
 
@@ -68,9 +69,9 @@ static int wacom_pl_irq(struct wacom_wac *wacom, void *wcombo)
        if (prox) {
                wacom->id[0] = ERASER_DEVICE_ID;
                pressure = (signed char)((data[7] << 1) | ((data[4] >> 2) & 1));
-               if (wacom->features->pressure_max > 255)
+               if (features->pressure_max > 255)
                        pressure = (pressure << 1) | ((data[4] >> 6) & 1);
-               pressure += (wacom->features->pressure_max + 1) / 2;
+               pressure += (features->pressure_max + 1) / 2;
 
                /*
                 * if going from out of proximity into proximity select between the eraser
@@ -152,6 +153,7 @@ static int wacom_ptu_irq(struct wacom_wac *wacom, void *wcombo)
 
 static int wacom_graphire_irq(struct wacom_wac *wacom, void *wcombo)
 {
+       struct wacom_features *features = &wacom->features;
        unsigned char *data = wacom->data;
        int x, y, rw;
        static int penData = 0;
@@ -179,8 +181,7 @@ static int wacom_graphire_irq(struct wacom_wac *wacom, void *wcombo)
 
                        case 2: /* Mouse with wheel */
                                wacom_report_key(wcombo, BTN_MIDDLE, data[1] & 0x04);
-                               if (wacom->features->type == WACOM_G4 ||
-                                               wacom->features->type == WACOM_MO) {
+                               if (features->type == WACOM_G4 || features->type == WACOM_MO) {
                                        rw = data[7] & 0x04 ? (data[7] & 0x03)-4 : (data[7] & 0x03);
                                        wacom_report_rel(wcombo, REL_WHEEL, -rw);
                                } else
@@ -192,8 +193,7 @@ static int wacom_graphire_irq(struct wacom_wac *wacom, void *wcombo)
                                wacom->id[0] = CURSOR_DEVICE_ID;
                                wacom_report_key(wcombo, BTN_LEFT, data[1] & 0x01);
                                wacom_report_key(wcombo, BTN_RIGHT, data[1] & 0x02);
-                               if (wacom->features->type == WACOM_G4 ||
-                                               wacom->features->type == WACOM_MO)
+                               if (features->type == WACOM_G4 || features->type == WACOM_MO)
                                        wacom_report_abs(wcombo, ABS_DISTANCE, data[6] & 0x3f);
                                else
                                        wacom_report_abs(wcombo, ABS_DISTANCE, data[7] & 0x3f);
@@ -230,7 +230,7 @@ static int wacom_graphire_irq(struct wacom_wac *wacom, void *wcombo)
        }
 
        /* send pad data */
-       switch (wacom->features->type) {
+       switch (features->type) {
            case WACOM_G4:
                if (data[7] & 0xf8) {
                        if (penData) {
@@ -300,11 +300,12 @@ static int wacom_graphire_irq(struct wacom_wac *wacom, void *wcombo)
 
 static int wacom_intuos_inout(struct wacom_wac *wacom, void *wcombo)
 {
+       struct wacom_features *features = &wacom->features;
        unsigned char *data = wacom->data;
        int idx = 0;
 
        /* tool number */
-       if (wacom->features->type == INTUOS)
+       if (features->type == INTUOS)
                idx = data[1] & 0x01;
 
        /* Enter report */
@@ -402,7 +403,7 @@ static int wacom_intuos_inout(struct wacom_wac *wacom, void *wcombo)
                        wacom_report_key(wcombo, BTN_STYLUS2, 0);
                        wacom_report_key(wcombo, BTN_TOUCH, 0);
                        wacom_report_abs(wcombo, ABS_WHEEL, 0);
-                       if (wacom->features->type >= INTUOS3S)
+                       if (features->type >= INTUOS3S)
                                wacom_report_abs(wcombo, ABS_Z, 0);
                }
                wacom_report_key(wcombo, wacom->tool[idx], 0);
@@ -416,13 +417,14 @@ static int wacom_intuos_inout(struct wacom_wac *wacom, void *wcombo)
 
 static void wacom_intuos_general(struct wacom_wac *wacom, void *wcombo)
 {
+       struct wacom_features *features = &wacom->features;
        unsigned char *data = wacom->data;
        unsigned int t;
 
        /* general pen packet */
        if ((data[1] & 0xb8) == 0xa0) {
                t = (data[6] << 2) | ((data[7] >> 6) & 3);
-               if (wacom->features->type >= INTUOS4S && wacom->features->type <= INTUOS4L)
+               if (features->type >= INTUOS4S && features->type <= INTUOS4L)
                        t = (t << 1) | (data[1] & 1);
                wacom_report_abs(wcombo, ABS_PRESSURE, t);
                wacom_report_abs(wcombo, ABS_TILT_X,
@@ -446,6 +448,7 @@ static void wacom_intuos_general(struct wacom_wac *wacom, void *wcombo)
 
 static int wacom_intuos_irq(struct wacom_wac *wacom, void *wcombo)
 {
+       struct wacom_features *features = &wacom->features;
        unsigned char *data = wacom->data;
        unsigned int t;
        int idx = 0, result;
@@ -457,7 +460,7 @@ static int wacom_intuos_irq(struct wacom_wac *wacom, void *wcombo)
        }
 
        /* tool number */
-       if (wacom->features->type == INTUOS)
+       if (features->type == INTUOS)
                idx = data[1] & 0x01;
 
        /* pad packets. Works as a second tool and is always in prox */
@@ -466,7 +469,7 @@ static int wacom_intuos_irq(struct wacom_wac *wacom, void *wcombo)
                if (wacom->tool[1] != BTN_TOOL_FINGER)
                        wacom->tool[1] = BTN_TOOL_FINGER;
 
-               if (wacom->features->type >= INTUOS4S && wacom->features->type <= INTUOS4L) {
+               if (features->type >= INTUOS4S && features->type <= INTUOS4L) {
                        wacom_report_key(wcombo, BTN_0, (data[2] & 0x01));
                        wacom_report_key(wcombo, BTN_1, (data[3] & 0x01));
                        wacom_report_key(wcombo, BTN_2, (data[3] & 0x02));
@@ -480,7 +483,7 @@ static int wacom_intuos_irq(struct wacom_wac *wacom, void *wcombo)
                                /* Out of proximity, clear wheel value. */
                                wacom_report_abs(wcombo, ABS_WHEEL, 0);
                        }
-                       if (wacom->features->type != INTUOS4S) {
+                       if (features->type != INTUOS4S) {
                                wacom_report_key(wcombo, BTN_7, (data[3] & 0x40));
                                wacom_report_key(wcombo, BTN_8, (data[3] & 0x80));
                        }
@@ -528,18 +531,20 @@ static int wacom_intuos_irq(struct wacom_wac *wacom, void *wcombo)
                return 0;
 
        /* Only large Intuos support Lense Cursor */
-       if ((wacom->tool[idx] == BTN_TOOL_LENS)
-                       && ((wacom->features->type == INTUOS3)
-                       || (wacom->features->type == INTUOS3S)
-                       || (wacom->features->type == INTUOS4)
-                       || (wacom->features->type == INTUOS4S)))
+       if (wacom->tool[idx] == BTN_TOOL_LENS &&
+           (features->type == INTUOS3 ||
+            features->type == INTUOS3S ||
+            features->type == INTUOS4 ||
+            features->type == INTUOS4S)) {
+
                return 0;
+       }
 
        /* Cintiq doesn't send data when RDY bit isn't set */
-       if ((wacom->features->type == CINTIQ) && !(data[1] & 0x40))
+       if (features->type == CINTIQ && !(data[1] & 0x40))
                  return 0;
 
-       if (wacom->features->type >= INTUOS3S) {
+       if (features->type >= INTUOS3S) {
                wacom_report_abs(wcombo, ABS_X, (data[2] << 9) | (data[3] << 1) | ((data[9] >> 1) & 1));
                wacom_report_abs(wcombo, ABS_Y, (data[4] << 9) | (data[5] << 1) | (data[9] & 1));
                wacom_report_abs(wcombo, ABS_DISTANCE, ((data[9] >> 2) & 0x3f));
@@ -557,7 +562,7 @@ static int wacom_intuos_irq(struct wacom_wac *wacom, void *wcombo)
 
                if (data[1] & 0x02) {
                        /* Rotation packet */
-                       if (wacom->features->type >= INTUOS3S) {
+                       if (features->type >= INTUOS3S) {
                                /* I3 marker pen rotation */
                                t = (data[6] << 3) | ((data[7] >> 5) & 7);
                                t = (data[7] & 0x20) ? ((t > 900) ? ((t-1) / 2 - 1350) :
@@ -570,7 +575,7 @@ static int wacom_intuos_irq(struct wacom_wac *wacom, void *wcombo)
                                        ((t - 1) / 2) : -t / 2);
                        }
 
-               } else if (!(data[1] & 0x10) && wacom->features->type < INTUOS3S) {
+               } else if (!(data[1] & 0x10) && features->type < INTUOS3S) {
                        /* 4D mouse packet */
                        wacom_report_key(wcombo, BTN_LEFT,   data[8] & 0x01);
                        wacom_report_key(wcombo, BTN_MIDDLE, data[8] & 0x02);
@@ -583,7 +588,7 @@ static int wacom_intuos_irq(struct wacom_wac *wacom, void *wcombo)
 
                } else if (wacom->tool[idx] == BTN_TOOL_MOUSE) {
                        /* I4 mouse */
-                       if (wacom->features->type >= INTUOS4S && wacom->features->type <= INTUOS4L) {
+                       if (features->type >= INTUOS4S && features->type <= INTUOS4L) {
                                wacom_report_key(wcombo, BTN_LEFT,   data[6] & 0x01);
                                wacom_report_key(wcombo, BTN_MIDDLE, data[6] & 0x02);
                                wacom_report_key(wcombo, BTN_RIGHT,  data[6] & 0x04);
@@ -604,13 +609,13 @@ static int wacom_intuos_irq(struct wacom_wac *wacom, void *wcombo)
                                                 - ((data[8] & 0x02) >> 1));
 
                                /* I3 2D mouse side buttons */
-                               if (wacom->features->type >= INTUOS3S && wacom->features->type <= INTUOS3L) {
+                               if (features->type >= INTUOS3S && features->type <= INTUOS3L) {
                                        wacom_report_key(wcombo, BTN_SIDE,   data[8] & 0x40);
                                        wacom_report_key(wcombo, BTN_EXTRA,  data[8] & 0x20);
                                }
                        }
-               } else if ((wacom->features->type < INTUOS3S || wacom->features->type == INTUOS3L ||
-                               wacom->features->type == INTUOS4L) &&
+               } else if ((features->type < INTUOS3S || features->type == INTUOS3L ||
+                               features->type == INTUOS4L) &&
                           wacom->tool[idx] == BTN_TOOL_LENS) {
                        /* Lens cursor packets */
                        wacom_report_key(wcombo, BTN_LEFT,   data[8] & 0x01);
@@ -718,6 +723,7 @@ static void wacom_tpc_touch_in(struct wacom_wac *wacom, void *wcombo)
 
 static int wacom_tpc_irq(struct wacom_wac *wacom, void *wcombo)
 {
+       struct wacom_features *features = &wacom->features;
        char *data = wacom->data;
        int prox = 0, pressure, idx = -1;
        static int stylusInProx, touchInProx = 1, touchOut;
@@ -791,7 +797,7 @@ static int wacom_tpc_irq(struct wacom_wac *wacom, void *wcombo)
                        wacom_report_abs(wcombo, ABS_Y, wacom_le16_to_cpu(&data[4]));
                        pressure = ((data[7] & 0x01) << 8) | data[6];
                        if (pressure < 0)
-                               pressure = wacom->features->pressure_max + pressure + 1;
+                               pressure = features->pressure_max + pressure + 1;
                        wacom_report_abs(wcombo, ABS_PRESSURE, pressure);
                        wacom_report_key(wcombo, BTN_TOUCH, data[1] & 0x05);
                } else {
@@ -815,7 +821,7 @@ static int wacom_tpc_irq(struct wacom_wac *wacom, void *wcombo)
 
 int wacom_wac_irq(struct wacom_wac *wacom_wac, void *wcombo)
 {
-       switch (wacom_wac->features->type) {
+       switch (wacom_wac->features.type) {
                case PENPARTNER:
                        return wacom_penpartner_irq(wacom_wac, wcombo);
 
@@ -853,7 +859,7 @@ int wacom_wac_irq(struct wacom_wac *wacom_wac, void *wcombo)
 
 void wacom_init_input_dev(struct input_dev *input_dev, struct wacom_wac *wacom_wac)
 {
-       switch (wacom_wac->features->type) {
+       switch (wacom_wac->features.type) {
                case WACOM_MO:
                        input_dev_mo(input_dev, wacom_wac);
                case WACOM_G4:
@@ -888,7 +894,7 @@ void wacom_init_input_dev(struct input_dev *input_dev, struct wacom_wac *wacom_w
                        /* fall through */
                case TABLETPC:
                        input_dev_tpc(input_dev, wacom_wac);
-                       if (wacom_wac->features->device_type != BTN_TOOL_PEN)
+                       if (wacom_wac->features.device_type != BTN_TOOL_PEN)
                                break;  /* no need to process stylus stuff */
 
                        /* fall through */
@@ -903,153 +909,201 @@ void wacom_init_input_dev(struct input_dev *input_dev, struct wacom_wac *wacom_w
        return;
 }
 
-static struct wacom_features wacom_features[] = {
-       { "Wacom Penpartner",     WACOM_PKGLEN_PENPRTN,    5040,  3780,  255,  0, PENPARTNER },
-       { "Wacom Graphire",       WACOM_PKGLEN_GRAPHIRE,  10206,  7422,  511, 63, GRAPHIRE },
-       { "Wacom Graphire2 4x5",  WACOM_PKGLEN_GRAPHIRE,  10206,  7422,  511, 63, GRAPHIRE },
-       { "Wacom Graphire2 5x7",  WACOM_PKGLEN_GRAPHIRE,  13918, 10206,  511, 63, GRAPHIRE },
-       { "Wacom Graphire3",      WACOM_PKGLEN_GRAPHIRE,  10208,  7424,  511, 63, GRAPHIRE },
-       { "Wacom Graphire3 6x8",  WACOM_PKGLEN_GRAPHIRE,  16704, 12064,  511, 63, GRAPHIRE },
-       { "Wacom Graphire4 4x5",  WACOM_PKGLEN_GRAPHIRE,  10208,  7424,  511, 63, WACOM_G4 },
-       { "Wacom Graphire4 6x8",  WACOM_PKGLEN_GRAPHIRE,  16704, 12064,  511, 63, WACOM_G4 },
-       { "Wacom BambooFun 4x5",  WACOM_PKGLEN_BBFUN,     14760,  9225,  511, 63, WACOM_MO },
-       { "Wacom BambooFun 6x8",  WACOM_PKGLEN_BBFUN,     21648, 13530,  511, 63, WACOM_MO },
-       { "Wacom Bamboo1 Medium", WACOM_PKGLEN_GRAPHIRE,  16704, 12064,  511, 63, GRAPHIRE },
-       { "Wacom Volito",         WACOM_PKGLEN_GRAPHIRE,   5104,  3712,  511, 63, GRAPHIRE },
-       { "Wacom PenStation2",    WACOM_PKGLEN_GRAPHIRE,   3250,  2320,  255, 63, GRAPHIRE },
-       { "Wacom Volito2 4x5",    WACOM_PKGLEN_GRAPHIRE,   5104,  3712,  511, 63, GRAPHIRE },
-       { "Wacom Volito2 2x3",    WACOM_PKGLEN_GRAPHIRE,   3248,  2320,  511, 63, GRAPHIRE },
-       { "Wacom PenPartner2",    WACOM_PKGLEN_GRAPHIRE,   3250,  2320,  511, 63, GRAPHIRE },
-       { "Wacom Bamboo",         WACOM_PKGLEN_BBFUN,     14760,  9225,  511, 63, WACOM_MO },
-       { "Wacom Bamboo1",        WACOM_PKGLEN_GRAPHIRE,   5104,  3712,  511, 63, GRAPHIRE },
-       { "Wacom Intuos 4x5",     WACOM_PKGLEN_INTUOS,    12700, 10600, 1023, 31, INTUOS },
-       { "Wacom Intuos 6x8",     WACOM_PKGLEN_INTUOS,    20320, 16240, 1023, 31, INTUOS },
-       { "Wacom Intuos 9x12",    WACOM_PKGLEN_INTUOS,    30480, 24060, 1023, 31, INTUOS },
-       { "Wacom Intuos 12x12",   WACOM_PKGLEN_INTUOS,    30480, 31680, 1023, 31, INTUOS },
-       { "Wacom Intuos 12x18",   WACOM_PKGLEN_INTUOS,    45720, 31680, 1023, 31, INTUOS },
-       { "Wacom PL400",          WACOM_PKGLEN_GRAPHIRE,   5408,  4056,  255,  0, PL },
-       { "Wacom PL500",          WACOM_PKGLEN_GRAPHIRE,   6144,  4608,  255,  0, PL },
-       { "Wacom PL600",          WACOM_PKGLEN_GRAPHIRE,   6126,  4604,  255,  0, PL },
-       { "Wacom PL600SX",        WACOM_PKGLEN_GRAPHIRE,   6260,  5016,  255,  0, PL },
-       { "Wacom PL550",          WACOM_PKGLEN_GRAPHIRE,   6144,  4608,  511,  0, PL },
-       { "Wacom PL800",          WACOM_PKGLEN_GRAPHIRE,   7220,  5780,  511,  0, PL },
-       { "Wacom PL700",          WACOM_PKGLEN_GRAPHIRE,   6758,  5406,  511,  0, PL },
-       { "Wacom PL510",          WACOM_PKGLEN_GRAPHIRE,   6282,  4762,  511,  0, PL },
-       { "Wacom DTU710",         WACOM_PKGLEN_GRAPHIRE,  34080, 27660,  511,  0, PL },
-       { "Wacom DTF521",         WACOM_PKGLEN_GRAPHIRE,   6282,  4762,  511,  0, PL },
-       { "Wacom DTF720",         WACOM_PKGLEN_GRAPHIRE,   6858,  5506,  511,  0, PL },
-       { "Wacom DTF720a",        WACOM_PKGLEN_GRAPHIRE,   6858,  5506,  511,  0, PL },
-       { "Wacom Cintiq Partner", WACOM_PKGLEN_GRAPHIRE,  20480, 15360,  511,  0, PTU },
-       { "Wacom Intuos2 4x5",    WACOM_PKGLEN_INTUOS,    12700, 10600, 1023, 31, INTUOS },
-       { "Wacom Intuos2 6x8",    WACOM_PKGLEN_INTUOS,    20320, 16240, 1023, 31, INTUOS },
-       { "Wacom Intuos2 9x12",   WACOM_PKGLEN_INTUOS,    30480, 24060, 1023, 31, INTUOS },
-       { "Wacom Intuos2 12x12",  WACOM_PKGLEN_INTUOS,    30480, 31680, 1023, 31, INTUOS },
-       { "Wacom Intuos2 12x18",  WACOM_PKGLEN_INTUOS,    45720, 31680, 1023, 31, INTUOS },
-       { "Wacom Intuos3 4x5",    WACOM_PKGLEN_INTUOS,    25400, 20320, 1023, 63, INTUOS3S },
-       { "Wacom Intuos3 6x8",    WACOM_PKGLEN_INTUOS,    40640, 30480, 1023, 63, INTUOS3 },
-       { "Wacom Intuos3 9x12",   WACOM_PKGLEN_INTUOS,    60960, 45720, 1023, 63, INTUOS3 },
-       { "Wacom Intuos3 12x12",  WACOM_PKGLEN_INTUOS,    60960, 60960, 1023, 63, INTUOS3L },
-       { "Wacom Intuos3 12x19",  WACOM_PKGLEN_INTUOS,    97536, 60960, 1023, 63, INTUOS3L },
-       { "Wacom Intuos3 6x11",   WACOM_PKGLEN_INTUOS,    54204, 31750, 1023, 63, INTUOS3 },
-       { "Wacom Intuos3 4x6",    WACOM_PKGLEN_INTUOS,    31496, 19685, 1023, 63, INTUOS3S },
-       { "Wacom Intuos4 4x6",    WACOM_PKGLEN_INTUOS,    31496, 19685, 2047, 63, INTUOS4S },
-       { "Wacom Intuos4 6x9",    WACOM_PKGLEN_INTUOS,    44704, 27940, 2047, 63, INTUOS4 },
-       { "Wacom Intuos4 8x13",   WACOM_PKGLEN_INTUOS,    65024, 40640, 2047, 63, INTUOS4L },
-       { "Wacom Intuos4 12x19",  WACOM_PKGLEN_INTUOS,    97536, 60960, 2047, 63, INTUOS4L },
-       { "Wacom Cintiq 21UX",    WACOM_PKGLEN_INTUOS,    87200, 65600, 1023, 63, CINTIQ },
-       { "Wacom Cintiq 20WSX",   WACOM_PKGLEN_INTUOS,    86680, 54180, 1023, 63, WACOM_BEE },
-       { "Wacom Cintiq 12WX",    WACOM_PKGLEN_INTUOS,    53020, 33440, 1023, 63, WACOM_BEE },
-       { "Wacom DTU1931",        WACOM_PKGLEN_GRAPHIRE,  37832, 30305,  511,  0, PL },
-       { "Wacom ISDv4 90",       WACOM_PKGLEN_GRAPHIRE,  26202, 16325,  255,  0, TABLETPC },
-       { "Wacom ISDv4 93",       WACOM_PKGLEN_GRAPHIRE,  26202, 16325,  255,  0, TABLETPC },
-       { "Wacom ISDv4 9A",       WACOM_PKGLEN_GRAPHIRE,  26202, 16325,  255,  0, TABLETPC },
-       { "Wacom ISDv4 9F",       WACOM_PKGLEN_PENABLED,  26202, 16325,  255,  0, TABLETPC },
-       { "Wacom ISDv4 E2",       WACOM_PKGLEN_TPC2FG,    26202, 16325,  255,  0, TABLETPC2FG },
-       { "Wacom ISDv4 E3",       WACOM_PKGLEN_TPC2FG,    26202, 16325,  255,  0, TABLETPC2FG },
-       { "Wacom Intuos2 6x8",    WACOM_PKGLEN_INTUOS,    20320, 16240, 1023, 31, INTUOS },
+static const struct wacom_features wacom_features_0x00 =
+       { "Wacom Penpartner",     WACOM_PKGLEN_PENPRTN,    5040,  3780,  255,  0, PENPARTNER };
+static const struct wacom_features wacom_features_0x10 =
+       { "Wacom Graphire",       WACOM_PKGLEN_GRAPHIRE,  10206,  7422,  511, 63, GRAPHIRE };
+static const struct wacom_features wacom_features_0x11 =
+       { "Wacom Graphire2 4x5",  WACOM_PKGLEN_GRAPHIRE,  10206,  7422,  511, 63, GRAPHIRE };
+static const struct wacom_features wacom_features_0x12 =
+       { "Wacom Graphire2 5x7",  WACOM_PKGLEN_GRAPHIRE,  13918, 10206,  511, 63, GRAPHIRE };
+static const struct wacom_features wacom_features_0x13 =
+       { "Wacom Graphire3",      WACOM_PKGLEN_GRAPHIRE,  10208,  7424,  511, 63, GRAPHIRE };
+static const struct wacom_features wacom_features_0x14 =
+       { "Wacom Graphire3 6x8",  WACOM_PKGLEN_GRAPHIRE,  16704, 12064,  511, 63, GRAPHIRE };
+static const struct wacom_features wacom_features_0x15 =
+       { "Wacom Graphire4 4x5",  WACOM_PKGLEN_GRAPHIRE,  10208,  7424,  511, 63, WACOM_G4 };
+static const struct wacom_features wacom_features_0x16 =
+       { "Wacom Graphire4 6x8",  WACOM_PKGLEN_GRAPHIRE,  16704, 12064,  511, 63, WACOM_G4 };
+static const struct wacom_features wacom_features_0x17 =
+       { "Wacom BambooFun 4x5",  WACOM_PKGLEN_BBFUN,     14760,  9225,  511, 63, WACOM_MO };
+static const struct wacom_features wacom_features_0x18 =
+       { "Wacom BambooFun 6x8",  WACOM_PKGLEN_BBFUN,     21648, 13530,  511, 63, WACOM_MO };
+static const struct wacom_features wacom_features_0x19 =
+       { "Wacom Bamboo1 Medium", WACOM_PKGLEN_GRAPHIRE,  16704, 12064,  511, 63, GRAPHIRE };
+static const struct wacom_features wacom_features_0x60 =
+       { "Wacom Volito",         WACOM_PKGLEN_GRAPHIRE,   5104,  3712,  511, 63, GRAPHIRE };
+static const struct wacom_features wacom_features_0x61 =
+       { "Wacom PenStation2",    WACOM_PKGLEN_GRAPHIRE,   3250,  2320,  255, 63, GRAPHIRE };
+static const struct wacom_features wacom_features_0x62 =
+       { "Wacom Volito2 4x5",    WACOM_PKGLEN_GRAPHIRE,   5104,  3712,  511, 63, GRAPHIRE };
+static const struct wacom_features wacom_features_0x63 =
+       { "Wacom Volito2 2x3",    WACOM_PKGLEN_GRAPHIRE,   3248,  2320,  511, 63, GRAPHIRE };
+static const struct wacom_features wacom_features_0x64 =
+       { "Wacom PenPartner2",    WACOM_PKGLEN_GRAPHIRE,   3250,  2320,  511, 63, GRAPHIRE };
+static const struct wacom_features wacom_features_0x65 =
+       { "Wacom Bamboo",         WACOM_PKGLEN_BBFUN,     14760,  9225,  511, 63, WACOM_MO };
+static const struct wacom_features wacom_features_0x69 =
+       { "Wacom Bamboo1",        WACOM_PKGLEN_GRAPHIRE,   5104,  3712,  511, 63, GRAPHIRE };
+static const struct wacom_features wacom_features_0x20 =
+       { "Wacom Intuos 4x5",     WACOM_PKGLEN_INTUOS,    12700, 10600, 1023, 31, INTUOS };
+static const struct wacom_features wacom_features_0x21 =
+       { "Wacom Intuos 6x8",     WACOM_PKGLEN_INTUOS,    20320, 16240, 1023, 31, INTUOS };
+static const struct wacom_features wacom_features_0x22 =
+       { "Wacom Intuos 9x12",    WACOM_PKGLEN_INTUOS,    30480, 24060, 1023, 31, INTUOS };
+static const struct wacom_features wacom_features_0x23 =
+       { "Wacom Intuos 12x12",   WACOM_PKGLEN_INTUOS,    30480, 31680, 1023, 31, INTUOS };
+static const struct wacom_features wacom_features_0x24 =
+       { "Wacom Intuos 12x18",   WACOM_PKGLEN_INTUOS,    45720, 31680, 1023, 31, INTUOS };
+static const struct wacom_features wacom_features_0x30 =
+       { "Wacom PL400",          WACOM_PKGLEN_GRAPHIRE,   5408,  4056,  255,  0, PL };
+static const struct wacom_features wacom_features_0x31 =
+       { "Wacom PL500",          WACOM_PKGLEN_GRAPHIRE,   6144,  4608,  255,  0, PL };
+static const struct wacom_features wacom_features_0x32 =
+       { "Wacom PL600",          WACOM_PKGLEN_GRAPHIRE,   6126,  4604,  255,  0, PL };
+static const struct wacom_features wacom_features_0x33 =
+       { "Wacom PL600SX",        WACOM_PKGLEN_GRAPHIRE,   6260,  5016,  255,  0, PL };
+static const struct wacom_features wacom_features_0x34 =
+       { "Wacom PL550",          WACOM_PKGLEN_GRAPHIRE,   6144,  4608,  511,  0, PL };
+static const struct wacom_features wacom_features_0x35 =
+       { "Wacom PL800",          WACOM_PKGLEN_GRAPHIRE,   7220,  5780,  511,  0, PL };
+static const struct wacom_features wacom_features_0x37 =
+       { "Wacom PL700",          WACOM_PKGLEN_GRAPHIRE,   6758,  5406,  511,  0, PL };
+static const struct wacom_features wacom_features_0x38 =
+       { "Wacom PL510",          WACOM_PKGLEN_GRAPHIRE,   6282,  4762,  511,  0, PL };
+static const struct wacom_features wacom_features_0x39 =
+       { "Wacom DTU710",         WACOM_PKGLEN_GRAPHIRE,  34080, 27660,  511,  0, PL };
+static const struct wacom_features wacom_features_0xC4 =
+       { "Wacom DTF521",         WACOM_PKGLEN_GRAPHIRE,   6282,  4762,  511,  0, PL };
+static const struct wacom_features wacom_features_0xC0 =
+       { "Wacom DTF720",         WACOM_PKGLEN_GRAPHIRE,   6858,  5506,  511,  0, PL };
+static const struct wacom_features wacom_features_0xC2 =
+       { "Wacom DTF720a",        WACOM_PKGLEN_GRAPHIRE,   6858,  5506,  511,  0, PL };
+static const struct wacom_features wacom_features_0x03 =
+       { "Wacom Cintiq Partner", WACOM_PKGLEN_GRAPHIRE,  20480, 15360,  511,  0, PTU };
+static const struct wacom_features wacom_features_0x41 =
+       { "Wacom Intuos2 4x5",    WACOM_PKGLEN_INTUOS,    12700, 10600, 1023, 31, INTUOS };
+static const struct wacom_features wacom_features_0x42 =
+       { "Wacom Intuos2 6x8",    WACOM_PKGLEN_INTUOS,    20320, 16240, 1023, 31, INTUOS };
+static const struct wacom_features wacom_features_0x43 =
+       { "Wacom Intuos2 9x12",   WACOM_PKGLEN_INTUOS,    30480, 24060, 1023, 31, INTUOS };
+static const struct wacom_features wacom_features_0x44 =
+       { "Wacom Intuos2 12x12",  WACOM_PKGLEN_INTUOS,    30480, 31680, 1023, 31, INTUOS };
+static const struct wacom_features wacom_features_0x45 =
+       { "Wacom Intuos2 12x18",  WACOM_PKGLEN_INTUOS,    45720, 31680, 1023, 31, INTUOS };
+static const struct wacom_features wacom_features_0xB0 =
+       { "Wacom Intuos3 4x5",    WACOM_PKGLEN_INTUOS,    25400, 20320, 1023, 63, INTUOS3S };
+static const struct wacom_features wacom_features_0xB1 =
+       { "Wacom Intuos3 6x8",    WACOM_PKGLEN_INTUOS,    40640, 30480, 1023, 63, INTUOS3 };
+static const struct wacom_features wacom_features_0xB2 =
+       { "Wacom Intuos3 9x12",   WACOM_PKGLEN_INTUOS,    60960, 45720, 1023, 63, INTUOS3 };
+static const struct wacom_features wacom_features_0xB3 =
+       { "Wacom Intuos3 12x12",  WACOM_PKGLEN_INTUOS,    60960, 60960, 1023, 63, INTUOS3L };
+static const struct wacom_features wacom_features_0xB4 =
+       { "Wacom Intuos3 12x19",  WACOM_PKGLEN_INTUOS,    97536, 60960, 1023, 63, INTUOS3L };
+static const struct wacom_features wacom_features_0xB5 =
+       { "Wacom Intuos3 6x11",   WACOM_PKGLEN_INTUOS,    54204, 31750, 1023, 63, INTUOS3 };
+static const struct wacom_features wacom_features_0xB7 =
+       { "Wacom Intuos3 4x6",    WACOM_PKGLEN_INTUOS,    31496, 19685, 1023, 63, INTUOS3S };
+static const struct wacom_features wacom_features_0xB8 =
+       { "Wacom Intuos4 4x6",    WACOM_PKGLEN_INTUOS,    31496, 19685, 2047, 63, INTUOS4S };
+static const struct wacom_features wacom_features_0xB9 =
+       { "Wacom Intuos4 6x9",    WACOM_PKGLEN_INTUOS,    44704, 27940, 2047, 63, INTUOS4 };
+static const struct wacom_features wacom_features_0xBA =
+       { "Wacom Intuos4 8x13",   WACOM_PKGLEN_INTUOS,    65024, 40640, 2047, 63, INTUOS4L };
+static const struct wacom_features wacom_features_0xBB =
+       { "Wacom Intuos4 12x19",  WACOM_PKGLEN_INTUOS,    97536, 60960, 2047, 63, INTUOS4L };
+static const struct wacom_features wacom_features_0x3F =
+       { "Wacom Cintiq 21UX",    WACOM_PKGLEN_INTUOS,    87200, 65600, 1023, 63, CINTIQ };
+static const struct wacom_features wacom_features_0xC5 =
+       { "Wacom Cintiq 20WSX",   WACOM_PKGLEN_INTUOS,    86680, 54180, 1023, 63, WACOM_BEE };
+static const struct wacom_features wacom_features_0xC6 =
+       { "Wacom Cintiq 12WX",    WACOM_PKGLEN_INTUOS,    53020, 33440, 1023, 63, WACOM_BEE };
+static const struct wacom_features wacom_features_0xC7 =
+       { "Wacom DTU1931",        WACOM_PKGLEN_GRAPHIRE,  37832, 30305,  511,  0, PL };
+static const struct wacom_features wacom_features_0x90 =
+       { "Wacom ISDv4 90",       WACOM_PKGLEN_GRAPHIRE,  26202, 16325,  255,  0, TABLETPC };
+static const struct wacom_features wacom_features_0x93 =
+       { "Wacom ISDv4 93",       WACOM_PKGLEN_GRAPHIRE,  26202, 16325,  255,  0, TABLETPC };
+static const struct wacom_features wacom_features_0x9A =
+       { "Wacom ISDv4 9A",       WACOM_PKGLEN_GRAPHIRE,  26202, 16325,  255,  0, TABLETPC };
+static const struct wacom_features wacom_features_0x9F =
+       { "Wacom ISDv4 9F",       WACOM_PKGLEN_PENABLED,  26202, 16325,  255,  0, TABLETPC };
+static const struct wacom_features wacom_features_0xE2 =
+       { "Wacom ISDv4 E2",       WACOM_PKGLEN_TPC2FG,    26202, 16325,  255,  0, TABLETPC2FG };
+static const struct wacom_features wacom_features_0xE3 =
+       { "Wacom ISDv4 E3",       WACOM_PKGLEN_TPC2FG,    26202, 16325,  255,  0, TABLETPC2FG };
+static const struct wacom_features wacom_features_0x47 =
+       { "Wacom Intuos2 6x8",    WACOM_PKGLEN_INTUOS,    20320, 16240, 1023, 31, INTUOS };
+
+#define USB_DEVICE_WACOM(prod)                                 \
+       USB_DEVICE(USB_VENDOR_ID_WACOM, prod),                  \
+       .driver_info = (kernel_ulong_t)&wacom_features_##prod
+
+const struct usb_device_id wacom_ids[] = {
+       { USB_DEVICE_WACOM(0x00) },
+       { USB_DEVICE_WACOM(0x10) },
+       { USB_DEVICE_WACOM(0x11) },
+       { USB_DEVICE_WACOM(0x12) },
+       { USB_DEVICE_WACOM(0x13) },
+       { USB_DEVICE_WACOM(0x14) },
+       { USB_DEVICE_WACOM(0x15) },
+       { USB_DEVICE_WACOM(0x16) },
+       { USB_DEVICE_WACOM(0x17) },
+       { USB_DEVICE_WACOM(0x18) },
+       { USB_DEVICE_WACOM(0x19) },
+       { USB_DEVICE_WACOM(0x60) },
+       { USB_DEVICE_WACOM(0x61) },
+       { USB_DEVICE_WACOM(0x62) },
+       { USB_DEVICE_WACOM(0x63) },
+       { USB_DEVICE_WACOM(0x64) },
+       { USB_DEVICE_WACOM(0x65) },
+       { USB_DEVICE_WACOM(0x69) },
+       { USB_DEVICE_WACOM(0x20) },
+       { USB_DEVICE_WACOM(0x21) },
+       { USB_DEVICE_WACOM(0x22) },
+       { USB_DEVICE_WACOM(0x23) },
+       { USB_DEVICE_WACOM(0x24) },
+       { USB_DEVICE_WACOM(0x30) },
+       { USB_DEVICE_WACOM(0x31) },
+       { USB_DEVICE_WACOM(0x32) },
+       { USB_DEVICE_WACOM(0x33) },
+       { USB_DEVICE_WACOM(0x34) },
+       { USB_DEVICE_WACOM(0x35) },
+       { USB_DEVICE_WACOM(0x37) },
+       { USB_DEVICE_WACOM(0x38) },
+       { USB_DEVICE_WACOM(0x39) },
+       { USB_DEVICE_WACOM(0xC4) },
+       { USB_DEVICE_WACOM(0xC0) },
+       { USB_DEVICE_WACOM(0xC2) },
+       { USB_DEVICE_WACOM(0x03) },
+       { USB_DEVICE_WACOM(0x41) },
+       { USB_DEVICE_WACOM(0x42) },
+       { USB_DEVICE_WACOM(0x43) },
+       { USB_DEVICE_WACOM(0x44) },
+       { USB_DEVICE_WACOM(0x45) },
+       { USB_DEVICE_WACOM(0xB0) },
+       { USB_DEVICE_WACOM(0xB1) },
+       { USB_DEVICE_WACOM(0xB2) },
+       { USB_DEVICE_WACOM(0xB3) },
+       { USB_DEVICE_WACOM(0xB4) },
+       { USB_DEVICE_WACOM(0xB5) },
+       { USB_DEVICE_WACOM(0xB7) },
+       { USB_DEVICE_WACOM(0xB8) },
+       { USB_DEVICE_WACOM(0xB9) },
+       { USB_DEVICE_WACOM(0xBA) },
+       { USB_DEVICE_WACOM(0xBB) },
+       { USB_DEVICE_WACOM(0x3F) },
+       { USB_DEVICE_WACOM(0xC5) },
+       { USB_DEVICE_WACOM(0xC6) },
+       { USB_DEVICE_WACOM(0xC7) },
+       { USB_DEVICE_WACOM(0x90) },
+       { USB_DEVICE_WACOM(0x93) },
+       { USB_DEVICE_WACOM(0x9A) },
+       { USB_DEVICE_WACOM(0x9F) },
+       { USB_DEVICE_WACOM(0xE2) },
+       { USB_DEVICE_WACOM(0xE3) },
+       { USB_DEVICE_WACOM(0x47) },
        { }
 };
-
-static struct usb_device_id wacom_ids[] = {
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x00) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x10) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x11) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x12) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x13) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x14) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x15) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x16) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x17) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x18) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x19) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x60) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x61) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x62) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x63) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x64) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x65) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x69) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x20) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x21) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x22) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x23) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x24) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x30) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x31) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x32) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x33) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x34) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x35) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x37) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x38) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x39) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xC4) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xC0) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xC2) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x03) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x41) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x42) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x43) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x44) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x45) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB0) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB1) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB2) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB3) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB4) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB5) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB7) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB8) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB9) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xBA) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xBB) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x3F) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xC5) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xC6) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xC7) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x90) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x93) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x9A) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x9F) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xE2) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xE3) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x47) },
-       { }
-};
-
-const struct usb_device_id *get_device_table(void)
-{
-        const struct usb_device_id *id_table = wacom_ids;
-
-        return id_table;
-}
-
-struct wacom_features * get_wacom_feature(const struct usb_device_id *id)
-{
-        int index = id - wacom_ids;
-        struct wacom_features *wf = &wacom_features[index];
-
-        return wf;
-}
-
 MODULE_DEVICE_TABLE(usb, wacom_ids);
index ee01e19..8590b1e 100644 (file)
 /* packet length for individual models */
 #define WACOM_PKGLEN_PENPRTN    7
 #define WACOM_PKGLEN_GRAPHIRE   8
-#define WACOM_PKGLEN_BBFUN      9
-#define WACOM_PKGLEN_INTUOS    10
+#define WACOM_PKGLEN_BBFUN      9
+#define WACOM_PKGLEN_INTUOS    10
 #define WACOM_PKGLEN_PENABLED   8
 #define WACOM_PKGLEN_TPC1FG     5
-#define WACOM_PKGLEN_TPC2FG    14
+#define WACOM_PKGLEN_TPC2FG    14
 
 /* device IDs */
 #define STYLUS_DEVICE_ID       0x02
@@ -58,7 +58,7 @@ enum {
 };
 
 struct wacom_features {
-       char *name;
+       const char *name;
        int pktlen;
        int x_max;
        int y_max;
@@ -73,11 +73,12 @@ struct wacom_features {
 };
 
 struct wacom_wac {
+       char name[64];
        unsigned char *data;
-        int tool[2];
-        int id[2];
-        __u32 serial[2];
-       struct wacom_features *features;
+       int tool[2];
+       int id[2];
+       __u32 serial[2];
+       struct wacom_features features;
 };
 
 #endif
index dfafc76..6457e06 100644 (file)
@@ -90,7 +90,6 @@ config TOUCHSCREEN_CORGI
        tristate "SharpSL (Corgi and Spitz series) touchscreen driver (DEPRECATED)"
        depends on PXA_SHARPSL
        select CORGI_SSP_DEPRECATED
-       default y
        help
          Say Y here to enable the driver for the touchscreen on the
          Sharp SL-C7xx and SL-Cxx00 series of PDAs.
@@ -537,6 +536,11 @@ config TOUCHSCREEN_USB_ETT_TC5UH
        bool "ET&T TC5UH touchscreen controler support" if EMBEDDED
        depends on TOUCHSCREEN_USB_COMPOSITE
 
+config TOUCHSCREEN_USB_NEXIO
+       default y
+       bool "NEXIO/iNexio device support" if EMBEDDED
+       depends on TOUCHSCREEN_USB_COMPOSITE
+
 config TOUCHSCREEN_TOUCHIT213
        tristate "Sahara TouchIT-213 touchscreen"
        select SERIO
index 52d2ca1..8b05d8e 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/gpio.h>
 #include <linux/spi/spi.h>
 #include <linux/spi/ads7846.h>
+#include <linux/regulator/consumer.h>
 #include <asm/irq.h>
 
 /*
@@ -85,6 +86,7 @@ struct ads7846 {
        char                    name[32];
 
        struct spi_device       *spi;
+       struct regulator        *reg;
 
 #if defined(CONFIG_HWMON) || defined(CONFIG_HWMON_MODULE)
        struct attribute_group  *attr_group;
@@ -788,6 +790,8 @@ static void ads7846_disable(struct ads7846 *ts)
                }
        }
 
+       regulator_disable(ts->reg);
+
        /* we know the chip's in lowpower mode since we always
         * leave it that way after every request
         */
@@ -799,6 +803,8 @@ static void ads7846_enable(struct ads7846 *ts)
        if (!ts->disabled)
                return;
 
+       regulator_enable(ts->reg);
+
        ts->disabled = 0;
        ts->irq_disabled = 0;
        enable_irq(ts->spi->irq);
@@ -1139,6 +1145,19 @@ static int __devinit ads7846_probe(struct spi_device *spi)
 
        ts->last_msg = m;
 
+       ts->reg = regulator_get(&spi->dev, "vcc");
+       if (IS_ERR(ts->reg)) {
+               dev_err(&spi->dev, "unable to get regulator: %ld\n",
+                       PTR_ERR(ts->reg));
+               goto err_free_gpio;
+       }
+
+       err = regulator_enable(ts->reg);
+       if (err) {
+               dev_err(&spi->dev, "unable to enable regulator: %d\n", err);
+               goto err_put_regulator;
+       }
+
        if (request_irq(spi->irq, ads7846_irq, IRQF_TRIGGER_FALLING,
                        spi->dev.driver->name, ts)) {
                dev_info(&spi->dev,
@@ -1148,7 +1167,7 @@ static int __devinit ads7846_probe(struct spi_device *spi)
                                  spi->dev.driver->name, ts);
                if (err) {
                        dev_dbg(&spi->dev, "irq %d busy?\n", spi->irq);
-                       goto err_free_gpio;
+                       goto err_disable_regulator;
                }
        }
 
@@ -1180,6 +1199,10 @@ static int __devinit ads7846_probe(struct spi_device *spi)
        ads784x_hwmon_unregister(spi, ts);
  err_free_irq:
        free_irq(spi->irq, ts);
+ err_disable_regulator:
+       regulator_disable(ts->reg);
+ err_put_regulator:
+       regulator_put(ts->reg);
  err_free_gpio:
        if (ts->gpio_pendown != -1)
                gpio_free(ts->gpio_pendown);
@@ -1208,6 +1231,9 @@ static int __devexit ads7846_remove(struct spi_device *spi)
        /* suspend left the IRQ disabled */
        enable_irq(ts->spi->irq);
 
+       regulator_disable(ts->reg);
+       regulator_put(ts->reg);
+
        if (ts->gpio_pendown != -1)
                gpio_free(ts->gpio_pendown);
 
index 8f38c5e..486d31b 100644 (file)
@@ -72,45 +72,49 @@ static void elo_process_data_10(struct elo *elo, unsigned char data)
        struct input_dev *dev = elo->dev;
 
        elo->data[elo->idx] = data;
-       switch (elo->idx++) {
-               case 0:
-                       elo->csum = 0xaa;
-                       if (data != ELO10_LEAD_BYTE) {
-                               pr_debug("elo: unsynchronized data: 0x%02x\n", data);
-                               elo->idx = 0;
-                       }
-                       break;
 
-               case 9:
+       switch (elo->idx++) {
+       case 0:
+               elo->csum = 0xaa;
+               if (data != ELO10_LEAD_BYTE) {
+                       dev_dbg(&elo->serio->dev,
+                               "unsynchronized data: 0x%02x\n", data);
                        elo->idx = 0;
-                       if (data != elo->csum) {
-                               pr_debug("elo: bad checksum: 0x%02x, expected 0x%02x\n",
-                                        data, elo->csum);
-                               break;
-                       }
-                       if (elo->data[1] != elo->expected_packet) {
-                               if (elo->data[1] != ELO10_TOUCH_PACKET)
-                                       pr_debug("elo: unexpected packet: 0x%02x\n",
-                                                elo->data[1]);
-                               break;
-                       }
-                       if (likely(elo->data[1] == ELO10_TOUCH_PACKET)) {
-                               input_report_abs(dev, ABS_X, (elo->data[4] << 8) | elo->data[3]);
-                               input_report_abs(dev, ABS_Y, (elo->data[6] << 8) | elo->data[5]);
-                               if (elo->data[2] & ELO10_PRESSURE)
-                                       input_report_abs(dev, ABS_PRESSURE,
-                                                       (elo->data[8] << 8) | elo->data[7]);
-                               input_report_key(dev, BTN_TOUCH, elo->data[2] & ELO10_TOUCH);
-                               input_sync(dev);
-                       } else if (elo->data[1] == ELO10_ACK_PACKET) {
-                               if (elo->data[2] == '0')
-                                       elo->expected_packet = ELO10_TOUCH_PACKET;
-                               complete(&elo->cmd_done);
-                       } else {
-                               memcpy(elo->response, &elo->data[1], ELO10_PACKET_LEN);
-                               elo->expected_packet = ELO10_ACK_PACKET;
-                       }
+               }
+               break;
+
+       case 9:
+               elo->idx = 0;
+               if (data != elo->csum) {
+                       dev_dbg(&elo->serio->dev,
+                               "bad checksum: 0x%02x, expected 0x%02x\n",
+                                data, elo->csum);
+                       break;
+               }
+               if (elo->data[1] != elo->expected_packet) {
+                       if (elo->data[1] != ELO10_TOUCH_PACKET)
+                               dev_dbg(&elo->serio->dev,
+                                       "unexpected packet: 0x%02x\n",
+                                        elo->data[1]);
                        break;
+               }
+               if (likely(elo->data[1] == ELO10_TOUCH_PACKET)) {
+                       input_report_abs(dev, ABS_X, (elo->data[4] << 8) | elo->data[3]);
+                       input_report_abs(dev, ABS_Y, (elo->data[6] << 8) | elo->data[5]);
+                       if (elo->data[2] & ELO10_PRESSURE)
+                               input_report_abs(dev, ABS_PRESSURE,
+                                               (elo->data[8] << 8) | elo->data[7]);
+                       input_report_key(dev, BTN_TOUCH, elo->data[2] & ELO10_TOUCH);
+                       input_sync(dev);
+               } else if (elo->data[1] == ELO10_ACK_PACKET) {
+                       if (elo->data[2] == '0')
+                               elo->expected_packet = ELO10_TOUCH_PACKET;
+                       complete(&elo->cmd_done);
+               } else {
+                       memcpy(elo->response, &elo->data[1], ELO10_PACKET_LEN);
+                       elo->expected_packet = ELO10_ACK_PACKET;
+               }
+               break;
        }
        elo->csum += data;
 }
@@ -123,42 +127,53 @@ static void elo_process_data_6(struct elo *elo, unsigned char data)
 
        switch (elo->idx++) {
 
-               case 0: if ((data & 0xc0) != 0xc0) elo->idx = 0; break;
-               case 1: if ((data & 0xc0) != 0x80) elo->idx = 0; break;
-               case 2: if ((data & 0xc0) != 0x40) elo->idx = 0; break;
-
-               case 3:
-                       if (data & 0xc0) {
-                               elo->idx = 0;
-                               break;
-                       }
+       case 0:
+               if ((data & 0xc0) != 0xc0)
+                       elo->idx = 0;
+               break;
 
-                       input_report_abs(dev, ABS_X, ((elo->data[0] & 0x3f) << 6) | (elo->data[1] & 0x3f));
-                       input_report_abs(dev, ABS_Y, ((elo->data[2] & 0x3f) << 6) | (elo->data[3] & 0x3f));
+       case 1:
+               if ((data & 0xc0) != 0x80)
+                       elo->idx = 0;
+               break;
 
-                       if (elo->id == 2) {
-                               input_report_key(dev, BTN_TOUCH, 1);
-                               input_sync(dev);
-                               elo->idx = 0;
-                       }
+       case 2:
+               if ((data & 0xc0) != 0x40)
+                       elo->idx = 0;
+               break;
 
+       case 3:
+               if (data & 0xc0) {
+                       elo->idx = 0;
                        break;
+               }
 
-               case 4:
-                       if (data) {
-                               input_sync(dev);
-                               elo->idx = 0;
-                       }
-                       break;
+               input_report_abs(dev, ABS_X, ((elo->data[0] & 0x3f) << 6) | (elo->data[1] & 0x3f));
+               input_report_abs(dev, ABS_Y, ((elo->data[2] & 0x3f) << 6) | (elo->data[3] & 0x3f));
 
-               case 5:
-                       if ((data & 0xf0) == 0) {
-                               input_report_abs(dev, ABS_PRESSURE, elo->data[5]);
-                               input_report_key(dev, BTN_TOUCH, !!elo->data[5]);
-                       }
+               if (elo->id == 2) {
+                       input_report_key(dev, BTN_TOUCH, 1);
                        input_sync(dev);
                        elo->idx = 0;
-                       break;
+               }
+
+               break;
+
+       case 4:
+               if (data) {
+                       input_sync(dev);
+                       elo->idx = 0;
+               }
+               break;
+
+       case 5:
+               if ((data & 0xf0) == 0) {
+                       input_report_abs(dev, ABS_PRESSURE, elo->data[5]);
+                       input_report_key(dev, BTN_TOUCH, !!elo->data[5]);
+               }
+               input_sync(dev);
+               elo->idx = 0;
+               break;
        }
 }
 
@@ -170,17 +185,17 @@ static void elo_process_data_3(struct elo *elo, unsigned char data)
 
        switch (elo->idx++) {
 
-               case 0:
-                       if ((data & 0x7f) != 0x01)
-                               elo->idx = 0;
-                       break;
-               case 2:
-                       input_report_key(dev, BTN_TOUCH, !(elo->data[1] & 0x80));
-                       input_report_abs(dev, ABS_X, elo->data[1]);
-                       input_report_abs(dev, ABS_Y, elo->data[2]);
-                       input_sync(dev);
+       case 0:
+               if ((data & 0x7f) != 0x01)
                        elo->idx = 0;
-                       break;
+               break;
+       case 2:
+               input_report_key(dev, BTN_TOUCH, !(elo->data[1] & 0x80));
+               input_report_abs(dev, ABS_X, elo->data[1]);
+               input_report_abs(dev, ABS_Y, elo->data[2]);
+               input_sync(dev);
+               elo->idx = 0;
+               break;
        }
 }
 
@@ -189,19 +204,19 @@ static irqreturn_t elo_interrupt(struct serio *serio,
 {
        struct elo *elo = serio_get_drvdata(serio);
 
-       switch(elo->id) {
-               case 0:
-                       elo_process_data_10(elo, data);
-                       break;
-
-               case 1:
-               case 2:
-                       elo_process_data_6(elo, data);
-                       break;
-
-               case 3:
-                       elo_process_data_3(elo, data);
-                       break;
+       switch (elo->id) {
+       case 0:
+               elo_process_data_10(elo, data);
+               break;
+
+       case 1:
+       case 2:
+               elo_process_data_6(elo, data);
+               break;
+
+       case 3:
+               elo_process_data_3(elo, data);
+               break;
        }
 
        return IRQ_HANDLED;
@@ -261,10 +276,10 @@ static int elo_setup_10(struct elo *elo)
        if (packet[3] & ELO10_PRESSURE)
                input_set_abs_params(dev, ABS_PRESSURE, 0, 255, 0, 0);
 
-       printk(KERN_INFO "elo: %sTouch touchscreen, fw: %02x.%02x, "
-               "features: 0x%02x, controller: 0x%02x\n",
-               elo_types[(packet[1] -'0') & 0x03],
-               packet[5], packet[4], packet[3], packet[7]);
+       dev_info(&elo->serio->dev,
+                "%sTouch touchscreen, fw: %02x.%02x, features: 0x%02x, controller: 0x%02x\n",
+                elo_types[(packet[1] -'0') & 0x03],
+                packet[5], packet[4], packet[3], packet[7]);
 
        return 0;
 }
@@ -330,24 +345,24 @@ static int elo_connect(struct serio *serio, struct serio_driver *drv)
 
        switch (elo->id) {
 
-               case 0: /* 10-byte protocol */
-                       if (elo_setup_10(elo))
-                               goto fail3;
+       case 0: /* 10-byte protocol */
+               if (elo_setup_10(elo))
+                       goto fail3;
 
-                       break;
+               break;
 
-               case 1: /* 6-byte protocol */
-                       input_set_abs_params(input_dev, ABS_PRESSURE, 0, 15, 0, 0);
+       case 1: /* 6-byte protocol */
+               input_set_abs_params(input_dev, ABS_PRESSURE, 0, 15, 0, 0);
 
-               case 2: /* 4-byte protocol */
-                       input_set_abs_params(input_dev, ABS_X, 96, 4000, 0, 0);
-                       input_set_abs_params(input_dev, ABS_Y, 96, 4000, 0, 0);
-                       break;
+       case 2: /* 4-byte protocol */
+               input_set_abs_params(input_dev, ABS_X, 96, 4000, 0, 0);
+               input_set_abs_params(input_dev, ABS_Y, 96, 4000, 0, 0);
+               break;
 
-               case 3: /* 3-byte protocol */
-                       input_set_abs_params(input_dev, ABS_X, 0, 255, 0, 0);
-                       input_set_abs_params(input_dev, ABS_Y, 0, 255, 0, 0);
-                       break;
+       case 3: /* 3-byte protocol */
+               input_set_abs_params(input_dev, ABS_X, 0, 255, 0, 0);
+               input_set_abs_params(input_dev, ABS_Y, 0, 255, 0, 0);
+               break;
        }
 
        err = input_register_device(elo->dev);
index 6cdcf2a..b6b8b1c 100644 (file)
@@ -153,6 +153,9 @@ static int wm97xx_acc_pen_down(struct wm97xx *wm)
                if (pressure)
                        p = MODR;
 
+               dev_dbg(wm->dev, "Raw coordinates: x=%x, y=%x, p=%x\n",
+                       x, y, p);
+
                /* are samples valid */
                if ((x & WM97XX_ADCSRC_MASK) != WM97XX_ADCSEL_X ||
                    (y & WM97XX_ADCSRC_MASK) != WM97XX_ADCSEL_Y ||
index 6386b44..3755a47 100644 (file)
@@ -128,27 +128,29 @@ static void touch_timer_fire(unsigned long data)
 
        down = get_down(data0, data1);
 
-       if (ts.count == (1 << ts.shift)) {
-               ts.xp >>= ts.shift;
-               ts.yp >>= ts.shift;
+       if (down) {
+               if (ts.count == (1 << ts.shift)) {
+                       ts.xp >>= ts.shift;
+                       ts.yp >>= ts.shift;
 
-               dev_dbg(ts.dev, "%s: X=%lu, Y=%lu, count=%d\n",
-                       __func__, ts.xp, ts.yp, ts.count);
+                       dev_dbg(ts.dev, "%s: X=%lu, Y=%lu, count=%d\n",
+                               __func__, ts.xp, ts.yp, ts.count);
 
-               input_report_abs(ts.input, ABS_X, ts.xp);
-               input_report_abs(ts.input, ABS_Y, ts.yp);
+                       input_report_abs(ts.input, ABS_X, ts.xp);
+                       input_report_abs(ts.input, ABS_Y, ts.yp);
 
-               input_report_key(ts.input, BTN_TOUCH, 1);
-               input_sync(ts.input);
+                       input_report_key(ts.input, BTN_TOUCH, 1);
+                       input_sync(ts.input);
 
-               ts.xp = 0;
-               ts.yp = 0;
-               ts.count = 0;
-       }
+                       ts.xp = 0;
+                       ts.yp = 0;
+                       ts.count = 0;
+               }
 
-       if (down) {
                s3c_adc_start(ts.client, 0, 1 << ts.shift);
        } else {
+               ts.xp = 0;
+               ts.yp = 0;
                ts.count = 0;
 
                input_report_key(ts.input, BTN_TOUCH, 0);
@@ -401,6 +403,7 @@ static int s3c2410ts_resume(struct device *dev)
        struct s3c2410_ts_mach_info *info = pdev->dev.platform_data;
 
        clk_enable(ts.clock);
+       enable_irq(ts.irq_tc);
 
        /* Initialise registers */
        if ((info->delay & 0xffff) > 0)
index 7ef0d14..be23780 100644 (file)
@@ -358,7 +358,7 @@ static int __devexit tsc2007_remove(struct i2c_client *client)
        return 0;
 }
 
-static struct i2c_device_id tsc2007_idtable[] = {
+static const struct i2c_device_id tsc2007_idtable[] = {
        { "tsc2007", 0 },
        { }
 };
index 5256123..99330bb 100644 (file)
@@ -15,6 +15,7 @@
  *  - GoTop Super_Q2/GogoPen/PenPower tablets
  *  - JASTEC USB touch controller/DigiTech DTR-02U
  *  - Zytronic capacitive touchscreen
+ *  - NEXIO/iNexio
  *
  * Copyright (C) 2004-2007 by Daniel Ritz <daniel.ritz@gmx.ch>
  * Copyright (C) by Todd E. Johnson (mtouchusb.c)
@@ -95,6 +96,7 @@ struct usbtouch_device_info {
 
        int  (*read_data)   (struct usbtouch_usb *usbtouch, unsigned char *pkt);
        int  (*init)        (struct usbtouch_usb *usbtouch);
+       void (*exit)        (struct usbtouch_usb *usbtouch);
 };
 
 /* a usbtouch device */
@@ -104,11 +106,12 @@ struct usbtouch_usb {
        unsigned char *buffer;
        int buf_len;
        struct urb *irq;
-       struct usb_device *udev;
+       struct usb_interface *interface;
        struct input_dev *input;
        struct usbtouch_device_info *type;
        char name[128];
        char phys[64];
+       void *priv;
 
        int x, y;
        int touch, press;
@@ -133,6 +136,7 @@ enum {
        DEVTYPE_E2I,
        DEVTYPE_ZYTRONIC,
        DEVTYPE_TC5UH,
+       DEVTYPE_NEXIO,
 };
 
 #define USB_DEVICE_HID_CLASS(vend, prod) \
@@ -144,7 +148,7 @@ enum {
        .bInterfaceClass = USB_INTERFACE_CLASS_HID, \
        .bInterfaceProtocol = USB_INTERFACE_PROTOCOL_MOUSE
 
-static struct usb_device_id usbtouch_devices[] = {
+static const struct usb_device_id usbtouch_devices[] = {
 #ifdef CONFIG_TOUCHSCREEN_USB_EGALAX
        /* ignore the HID capable devices, handled by usbhid */
        {USB_DEVICE_HID_CLASS(0x0eef, 0x0001), .driver_info = DEVTYPE_IGNORE},
@@ -222,6 +226,14 @@ static struct usb_device_id usbtouch_devices[] = {
        {USB_DEVICE(0x0664, 0x0309), .driver_info = DEVTYPE_TC5UH},
 #endif
 
+#ifdef CONFIG_TOUCHSCREEN_USB_NEXIO
+       /* data interface only */
+       {USB_DEVICE_AND_INTERFACE_INFO(0x10f0, 0x2002, 0x0a, 0x00, 0x00),
+               .driver_info = DEVTYPE_NEXIO},
+       {USB_DEVICE_AND_INTERFACE_INFO(0x1870, 0x0001, 0x0a, 0x00, 0x00),
+               .driver_info = DEVTYPE_NEXIO},
+#endif
+
        {}
 };
 
@@ -234,8 +246,9 @@ static struct usb_device_id usbtouch_devices[] = {
 static int e2i_init(struct usbtouch_usb *usbtouch)
 {
        int ret;
+       struct usb_device *udev = interface_to_usbdev(usbtouch->interface);
 
-       ret = usb_control_msg(usbtouch->udev, usb_rcvctrlpipe(usbtouch->udev, 0),
+       ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
                              0x01, 0x02, 0x0000, 0x0081,
                              NULL, 0, USB_CTRL_SET_TIMEOUT);
 
@@ -344,8 +357,9 @@ static int mtouch_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
 static int mtouch_init(struct usbtouch_usb *usbtouch)
 {
        int ret, i;
+       struct usb_device *udev = interface_to_usbdev(usbtouch->interface);
 
-       ret = usb_control_msg(usbtouch->udev, usb_rcvctrlpipe(usbtouch->udev, 0),
+       ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
                   &