Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input
authorLinus Torvalds <torvalds@linux-foundation.org>
Wed, 5 May 2010 14:53:18 +0000 (07:53 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Wed, 5 May 2010 14:53:18 +0000 (07:53 -0700)
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input:
  Input: joydev - allow binding to button-only devices
  Input: elantech - ignore high bits in the position coordinates
  Input: elantech - allow forcing Elantech protocol
  Input: elantech - fix firmware version check
  Input: ati_remote - add some missing devices from lirc_atiusb
  Input: eeti_ts - cancel pending work when going to suspend
  Input: Add support of Synaptics Clickpad device
  Revert "Input: ALPS - add signature for HP Pavilion dm3 laptops"
  Input: psmouse - ignore parity error for basic protocols

1  2 
drivers/input/mouse/alps.c
drivers/input/mouse/elantech.c
drivers/input/mouse/synaptics.c
drivers/input/touchscreen/eeti_ts.c

@@@ -15,7 -15,6 +15,7 @@@
   * the Free Software Foundation.
   */
  
 +#include <linux/slab.h>
  #include <linux/input.h>
  #include <linux/serio.h>
  #include <linux/libps2.h>
@@@ -64,7 -63,6 +64,6 @@@ static const struct alps_model_info alp
        { { 0x62, 0x02, 0x14 }, 0xcf, 0xcf,
                ALPS_PASS | ALPS_DUALPOINT | ALPS_PS2_INTERLEAVED },
        { { 0x73, 0x02, 0x50 }, 0xcf, 0xcf, ALPS_FOUR_BUTTONS },          /* Dell Vostro 1400 */
-       { { 0x73, 0x02, 0x64 }, 0xf8, 0xf8, 0 },                          /* HP Pavilion dm3 */
        { { 0x52, 0x01, 0x14 }, 0xff, 0xff,
                ALPS_PASS | ALPS_DUALPOINT | ALPS_PS2_INTERLEAVED },      /* Toshiba Tecra A11-11L */
  };
@@@ -11,7 -11,6 +11,7 @@@
   */
  
  #include <linux/delay.h>
 +#include <linux/slab.h>
  #include <linux/module.h>
  #include <linux/input.h>
  #include <linux/serio.h>
                        printk(KERN_DEBUG format, ##arg);       \
        } while (0)
  
+ static bool force_elantech;
+ module_param_named(force_elantech, force_elantech, bool, 0644);
+ MODULE_PARM_DESC(force_elantech, "Force the Elantech PS/2 protocol extension to be used, 1 = enabled, 0 = disabled (default).");
  /*
   * Send a Synaptics style sliced query command
   */
@@@ -182,13 -185,17 +186,17 @@@ static void elantech_report_absolute_v1
        static int old_fingers;
  
        if (etd->fw_version_maj == 0x01) {
-               /* byte 0:  D   U  p1  p2   1  p3   R   L
-                  byte 1:  f   0  th  tw  x9  x8  y9  y8 */
+               /*
+                * byte 0:  D   U  p1  p2   1  p3   R   L
+                * byte 1:  f   0  th  tw  x9  x8  y9  y8
+                */
                fingers = ((packet[1] & 0x80) >> 7) +
                                ((packet[1] & 0x30) >> 4);
        } else {
-               /* byte 0: n1  n0  p2  p1   1  p3   R   L
-                  byte 1:  0   0   0   0  x9  x8  y9  y8 */
+               /*
+                * byte 0: n1  n0  p2  p1   1  p3   R   L
+                * byte 1:  0   0   0   0  x9  x8  y9  y8
+                */
                fingers = (packet[0] & 0xc0) >> 6;
        }
  
  
        input_report_key(dev, BTN_TOUCH, fingers != 0);
  
-       /* byte 2: x7  x6  x5  x4  x3  x2  x1  x0
-          byte 3: y7  y6  y5  y4  y3  y2  y1  y0 */
+       /*
+        * byte 2: x7  x6  x5  x4  x3  x2  x1  x0
+        * byte 3: y7  y6  y5  y4  y3  y2  y1  y0
+        */
        if (fingers) {
                input_report_abs(dev, ABS_X,
                        ((packet[1] & 0x0c) << 6) | packet[2]);
-               input_report_abs(dev, ABS_Y, ETP_YMAX_V1 -
-                       (((packet[1] & 0x03) << 8) | packet[3]));
+               input_report_abs(dev, ABS_Y,
+                       ETP_YMAX_V1 - (((packet[1] & 0x03) << 8) | packet[3]));
        }
  
        input_report_key(dev, BTN_TOOL_FINGER, fingers == 1);
@@@ -247,34 -256,47 +257,47 @@@ static void elantech_report_absolute_v2
  
        switch (fingers) {
        case 1:
-               /* byte 1: x15 x14 x13 x12 x11 x10 x9  x8
-                  byte 2: x7  x6  x5  x4  x4  x2  x1  x0 */
-               input_report_abs(dev, ABS_X, (packet[1] << 8) | packet[2]);
-               /* byte 4: y15 y14 y13 y12 y11 y10 y8  y8
-                  byte 5: y7  y6  y5  y4  y3  y2  y1  y0 */
-               input_report_abs(dev, ABS_Y, ETP_YMAX_V2 -
-                       ((packet[4] << 8) | packet[5]));
+               /*
+                * byte 1:  .   .   .   .   .  x10 x9  x8
+                * byte 2: x7  x6  x5  x4  x4  x2  x1  x0
+                */
+               input_report_abs(dev, ABS_X,
+                       ((packet[1] & 0x07) << 8) | packet[2]);
+               /*
+                * byte 4:  .   .   .   .   .   .  y9  y8
+                * byte 5: y7  y6  y5  y4  y3  y2  y1  y0
+                */
+               input_report_abs(dev, ABS_Y,
+                       ETP_YMAX_V2 - (((packet[4] & 0x03) << 8) | packet[5]));
                break;
  
        case 2:
-               /* The coordinate of each finger is reported separately with
-                  a lower resolution for two finger touches */
-               /* byte 0:  .   .  ay8 ax8  .   .   .   .
-                  byte 1: ax7 ax6 ax5 ax4 ax3 ax2 ax1 ax0 */
+               /*
+                * The coordinate of each finger is reported separately
+                * with a lower resolution for two finger touches:
+                * byte 0:  .   .  ay8 ax8  .   .   .   .
+                * byte 1: ax7 ax6 ax5 ax4 ax3 ax2 ax1 ax0
+                */
                x1 = ((packet[0] & 0x10) << 4) | packet[1];
                /* byte 2: ay7 ay6 ay5 ay4 ay3 ay2 ay1 ay0 */
                y1 = ETP_2FT_YMAX - (((packet[0] & 0x20) << 3) | packet[2]);
-               /* byte 3:  .   .  by8 bx8  .   .   .   .
-                  byte 4: bx7 bx6 bx5 bx4 bx3 bx2 bx1 bx0 */
+               /*
+                * byte 3:  .   .  by8 bx8  .   .   .   .
+                * byte 4: bx7 bx6 bx5 bx4 bx3 bx2 bx1 bx0
+                */
                x2 = ((packet[3] & 0x10) << 4) | packet[4];
                /* byte 5: by7 by8 by5 by4 by3 by2 by1 by0 */
                y2 = ETP_2FT_YMAX - (((packet[3] & 0x20) << 3) | packet[5]);
-               /* For compatibility with the X Synaptics driver scale up one
-                  coordinate and report as ordinary mouse movent */
+               /*
+                * For compatibility with the X Synaptics driver scale up
+                * one coordinate and report as ordinary mouse movent
+                */
                input_report_abs(dev, ABS_X, x1 << 2);
                input_report_abs(dev, ABS_Y, y1 << 2);
-               /* For compatibility with the proprietary X Elantech driver
-                  report both coordinates as hat coordinates */
+               /*
+                * For compatibility with the proprietary X Elantech driver
+                * report both coordinates as hat coordinates
+                */
                input_report_abs(dev, ABS_HAT0X, x1);
                input_report_abs(dev, ABS_HAT0Y, y1);
                input_report_abs(dev, ABS_HAT1X, x2);
@@@ -596,8 -618,12 +619,12 @@@ int elantech_detect(struct psmouse *psm
                 param[0], param[1], param[2]);
  
        if (param[0] == 0 || param[1] != 0) {
-               pr_debug("elantech.c: Probably not a real Elantech touchpad. Aborting.\n");
-               return -1;
+               if (!force_elantech) {
+                       pr_debug("elantech.c: Probably not a real Elantech touchpad. Aborting.\n");
+                       return -1;
+               }
+               pr_debug("elantech.c: Probably not a real Elantech touchpad. Enabling anyway due to force_elantech.\n");
        }
  
        if (set_properties) {
@@@ -666,7 -692,8 +693,8 @@@ int elantech_init(struct psmouse *psmou
         * Assume every version greater than this is new EeePC style
         * hardware with 6 byte packets
         */
-       if (etd->fw_version_maj >= 0x02 && etd->fw_version_min >= 0x30) {
+       if ((etd->fw_version_maj == 0x02 && etd->fw_version_min >= 0x30) ||
+           etd->fw_version_maj > 0x02) {
                etd->hw_version = 2;
                /* For now show extra debug information */
                etd->debug = 1;
@@@ -28,7 -28,6 +28,7 @@@
  #include <linux/input.h>
  #include <linux/serio.h>
  #include <linux/libps2.h>
 +#include <linux/slab.h>
  #include "psmouse.h"
  #include "synaptics.h"
  
@@@ -137,7 -136,8 +137,8 @@@ static int synaptics_capability(struct 
        if (synaptics_send_cmd(psmouse, SYN_QUE_CAPABILITIES, cap))
                return -1;
        priv->capabilities = (cap[0] << 16) | (cap[1] << 8) | cap[2];
-       priv->ext_cap = 0;
+       priv->ext_cap = priv->ext_cap_0c = 0;
        if (!SYN_CAP_VALID(priv->capabilities))
                return -1;
  
        if (SYN_EXT_CAP_REQUESTS(priv->capabilities) >= 1) {
                if (synaptics_send_cmd(psmouse, SYN_QUE_EXT_CAPAB, cap)) {
                        printk(KERN_ERR "Synaptics claims to have extended capabilities,"
-                              " but I'm not able to read them.");
+                              " but I'm not able to read them.\n");
                } else {
                        priv->ext_cap = (cap[0] << 16) | (cap[1] << 8) | cap[2];
  
                                priv->ext_cap &= 0xff0fff;
                }
        }
+       if (SYN_EXT_CAP_REQUESTS(priv->capabilities) >= 4) {
+               if (synaptics_send_cmd(psmouse, SYN_QUE_EXT_CAPAB_0C, cap)) {
+                       printk(KERN_ERR "Synaptics claims to have extended capability 0x0c,"
+                              " but I'm not able to read it.\n");
+               } else {
+                       priv->ext_cap_0c = (cap[0] << 16) | (cap[1] << 8) | cap[2];
+               }
+       }
        return 0;
  }
  
@@@ -348,7 -358,15 +359,15 @@@ static void synaptics_parse_hw_state(un
                hw->left  = (buf[0] & 0x01) ? 1 : 0;
                hw->right = (buf[0] & 0x02) ? 1 : 0;
  
-               if (SYN_CAP_MIDDLE_BUTTON(priv->capabilities)) {
+               if (SYN_CAP_CLICKPAD(priv->ext_cap_0c)) {
+                       /*
+                        * Clickpad's button is transmitted as middle button,
+                        * however, since it is primary button, we will report
+                        * it as BTN_LEFT.
+                        */
+                       hw->left = ((buf[0] ^ buf[3]) & 0x01) ? 1 : 0;
+               } else if (SYN_CAP_MIDDLE_BUTTON(priv->capabilities)) {
                        hw->middle = ((buf[0] ^ buf[3]) & 0x01) ? 1 : 0;
                        if (hw->w == 2)
                                hw->scroll = (signed char)(buf[1]);
@@@ -593,6 -611,12 +612,12 @@@ static void set_input_params(struct inp
  
        dev->absres[ABS_X] = priv->x_res;
        dev->absres[ABS_Y] = priv->y_res;
+       if (SYN_CAP_CLICKPAD(priv->ext_cap_0c)) {
+               /* Clickpads report only left button */
+               __clear_bit(BTN_RIGHT, dev->keybit);
+               __clear_bit(BTN_MIDDLE, dev->keybit);
+       }
  }
  
  static void synaptics_disconnect(struct psmouse *psmouse)
@@@ -697,10 -721,10 +722,10 @@@ int synaptics_init(struct psmouse *psmo
  
        priv->pkt_type = SYN_MODEL_NEWABS(priv->model_id) ? SYN_NEWABS : SYN_OLDABS;
  
-       printk(KERN_INFO "Synaptics Touchpad, model: %ld, fw: %ld.%ld, id: %#lx, caps: %#lx/%#lx\n",
+       printk(KERN_INFO "Synaptics Touchpad, model: %ld, fw: %ld.%ld, id: %#lx, caps: %#lx/%#lx/%#lx\n",
                SYN_ID_MODEL(priv->identity),
                SYN_ID_MAJOR(priv->identity), SYN_ID_MINOR(priv->identity),
-               priv->model_id, priv->capabilities, priv->ext_cap);
+               priv->model_id, priv->capabilities, priv->ext_cap, priv->ext_cap_0c);
  
        set_input_params(psmouse->dev, priv);
  
@@@ -33,7 -33,6 +33,7 @@@
  #include <linux/timer.h>
  #include <linux/gpio.h>
  #include <linux/input/eeti_ts.h>
 +#include <linux/slab.h>
  
  static int flip_x;
  module_param(flip_x, bool, 0644);
@@@ -124,14 -123,25 +124,25 @@@ static irqreturn_t eeti_ts_isr(int irq
        return IRQ_HANDLED;
  }
  
- static int eeti_ts_open(struct input_dev *dev)
+ static void eeti_ts_start(struct eeti_ts_priv *priv)
  {
-       struct eeti_ts_priv *priv = input_get_drvdata(dev);
        enable_irq(priv->irq);
  
        /* Read the events once to arm the IRQ */
        eeti_ts_read(&priv->work);
+ }
+ static void eeti_ts_stop(struct eeti_ts_priv *priv)
+ {
+       disable_irq(priv->irq);
+       cancel_work_sync(&priv->work);
+ }
+ static int eeti_ts_open(struct input_dev *dev)
+ {
+       struct eeti_ts_priv *priv = input_get_drvdata(dev);
+       eeti_ts_start(priv);
  
        return 0;
  }
@@@ -140,8 -150,7 +151,7 @@@ static void eeti_ts_close(struct input_
  {
        struct eeti_ts_priv *priv = input_get_drvdata(dev);
  
-       disable_irq(priv->irq);
-       cancel_work_sync(&priv->work);
+       eeti_ts_stop(priv);
  }
  
  static int __devinit eeti_ts_probe(struct i2c_client *client,
        unsigned int irq_flags;
        int err = -ENOMEM;
  
-       /* In contrast to what's described in the datasheet, there seems
+       /*
+        * In contrast to what's described in the datasheet, there seems
         * to be no way of probing the presence of that device using I2C
         * commands. So we need to blindly believe it is there, and wait
-        * for interrupts to occur. */
+        * for interrupts to occur.
+        */
  
        priv = kzalloc(sizeof(*priv), GFP_KERNEL);
        if (!priv) {
                goto err2;
        }
  
-       /* Disable the irq for now. It will be enabled once the input device
-        * is opened. */
-       disable_irq(priv->irq);
+       /*
+        * Disable the device for now. It will be enabled once the
+        * input device is opened.
+        */
+       eeti_ts_stop(priv);
  
        device_init_wakeup(&client->dev, 0);
        return 0;
@@@ -235,6 -248,12 +249,12 @@@ static int __devexit eeti_ts_remove(str
        struct eeti_ts_priv *priv = i2c_get_clientdata(client);
  
        free_irq(priv->irq, priv);
+       /*
+        * eeti_ts_stop() leaves IRQ disabled. We need to re-enable it
+        * so that device still works if we reload the driver.
+        */
+       enable_irq(priv->irq);
        input_unregister_device(priv->input);
        i2c_set_clientdata(client, NULL);
        kfree(priv);
  static int eeti_ts_suspend(struct i2c_client *client, pm_message_t mesg)
  {
        struct eeti_ts_priv *priv = i2c_get_clientdata(client);
+       struct input_dev *input_dev = priv->input;
+       mutex_lock(&input_dev->mutex);
+       if (input_dev->users)
+               eeti_ts_stop(priv);
+       mutex_unlock(&input_dev->mutex);
  
        if (device_may_wakeup(&client->dev))
                enable_irq_wake(priv->irq);
  static int eeti_ts_resume(struct i2c_client *client)
  {
        struct eeti_ts_priv *priv = i2c_get_clientdata(client);
+       struct input_dev *input_dev = priv->input;
  
        if (device_may_wakeup(&client->dev))
                disable_irq_wake(priv->irq);
  
+       mutex_lock(&input_dev->mutex);
+       if (input_dev->users)
+               eeti_ts_start(priv);
+       mutex_unlock(&input_dev->mutex);
        return 0;
  }
  #else