]> git.kernelconcepts.de Git - karo-tx-linux.git/commitdiff
Merge commit 'v3.2-rc3' into next
authorDmitry Torokhov <dmitry.torokhov@gmail.com>
Tue, 29 Nov 2011 09:51:07 +0000 (01:51 -0800)
committerDmitry Torokhov <dmitry.torokhov@gmail.com>
Tue, 29 Nov 2011 09:51:07 +0000 (01:51 -0800)
1  2 
drivers/input/input-polldev.c
drivers/input/misc/adxl34x.c
drivers/input/misc/ati_remote2.c
drivers/input/mouse/elantech.c
drivers/input/tablet/wacom_sys.c
drivers/input/tablet/wacom_wac.c
drivers/input/touchscreen/ad7877.c
drivers/input/touchscreen/ad7879-spi.c
drivers/input/touchscreen/ad7879.c
drivers/input/touchscreen/ads7846.c

index 1986a52a7ab9a03c0fc4f3dc37c2fefe47ba315f,7dfe1009fae09b6101133d8e471a0d4b1ef039cd..7f161d93203c09a7fbb31a6522ed81c00d47ca13
@@@ -14,6 -14,7 +14,7 @@@
  #include <linux/slab.h>
  #include <linux/mutex.h>
  #include <linux/workqueue.h>
+ #include <linux/module.h>
  #include <linux/input-polldev.h>
  
  MODULE_AUTHOR("Dmitry Torokhov <dtor@mail.ru>");
@@@ -83,12 -84,10 +84,12 @@@ static ssize_t input_polldev_set_poll(s
  {
        struct input_polled_dev *polldev = dev_get_drvdata(dev);
        struct input_dev *input = polldev->input;
 -      unsigned long interval;
 +      unsigned int interval;
 +      int err;
  
 -      if (strict_strtoul(buf, 0, &interval))
 -              return -EINVAL;
 +      err = kstrtouint(buf, 0, &interval);
 +      if (err)
 +              return err;
  
        if (interval < polldev->poll_interval_min)
                return -EINVAL;
index 87918592993c8a4278d7e2ee4663428542959693,09244804fb97674adfd9d39b28fc94c05bf651a3..1cf72fe513e6934af7fb4ab0d5742c3155537146
@@@ -16,6 -16,7 +16,7 @@@
  #include <linux/slab.h>
  #include <linux/workqueue.h>
  #include <linux/input/adxl34x.h>
+ #include <linux/module.h>
  
  #include "adxl34x.h"
  
@@@ -451,10 -452,10 +452,10 @@@ static ssize_t adxl34x_disable_store(st
                                     const char *buf, size_t count)
  {
        struct adxl34x *ac = dev_get_drvdata(dev);
 -      unsigned long val;
 +      unsigned int val;
        int error;
  
 -      error = strict_strtoul(buf, 10, &val);
 +      error = kstrtouint(buf, 10, &val);
        if (error)
                return error;
  
@@@ -540,10 -541,10 +541,10 @@@ static ssize_t adxl34x_rate_store(struc
                                  const char *buf, size_t count)
  {
        struct adxl34x *ac = dev_get_drvdata(dev);
 -      unsigned long val;
 +      unsigned char val;
        int error;
  
 -      error = strict_strtoul(buf, 10, &val);
 +      error = kstrtou8(buf, 10, &val);
        if (error)
                return error;
  
@@@ -575,10 -576,10 +576,10 @@@ static ssize_t adxl34x_autosleep_store(
                                  const char *buf, size_t count)
  {
        struct adxl34x *ac = dev_get_drvdata(dev);
 -      unsigned long val;
 +      unsigned int val;
        int error;
  
 -      error = strict_strtoul(buf, 10, &val);
 +      error = kstrtouint(buf, 10, &val);
        if (error)
                return error;
  
@@@ -622,13 -623,13 +623,13 @@@ static ssize_t adxl34x_write_store(stru
                                   const char *buf, size_t count)
  {
        struct adxl34x *ac = dev_get_drvdata(dev);
 -      unsigned long val;
 +      unsigned int val;
        int error;
  
        /*
         * This allows basic ADXL register write access for debug purposes.
         */
 -      error = strict_strtoul(buf, 16, &val);
 +      error = kstrtouint(buf, 16, &val);
        if (error)
                return error;
  
index afbe3e760551a80e0e1d763896b0531ef72d711b,8d345e87075e6b8704ef72231f59e4d477374d73..a34896ed7ed3a53ac31a7b05d420285d9503ac28
@@@ -11,6 -11,7 +11,7 @@@
  
  #include <linux/usb/input.h>
  #include <linux/slab.h>
+ #include <linux/module.h>
  
  #define DRIVER_DESC    "ATI/Philips USB RF remote driver"
  #define DRIVER_VERSION "0.3"
@@@ -41,13 -42,13 +42,13 @@@ static int ati_remote2_set_mask(const c
                                const struct kernel_param *kp,
                                unsigned int max)
  {
 -      unsigned long mask;
 +      unsigned int mask;
        int ret;
  
        if (!val)
                return -EINVAL;
  
 -      ret = strict_strtoul(val, 0, &mask);
 +      ret = kstrtouint(val, 0, &mask);
        if (ret)
                return ret;
  
@@@ -719,12 -720,11 +720,12 @@@ static ssize_t ati_remote2_store_channe
        struct usb_device *udev = to_usb_device(dev);
        struct usb_interface *intf = usb_ifnum_to_if(udev, 0);
        struct ati_remote2 *ar2 = usb_get_intfdata(intf);
 -      unsigned long mask;
 +      unsigned int mask;
        int r;
  
 -      if (strict_strtoul(buf, 0, &mask))
 -              return -EINVAL;
 +      r = kstrtouint(buf, 0, &mask);
 +      if (r)
 +              return r;
  
        if (mask & ~ATI_REMOTE2_MAX_CHANNEL_MASK)
                return -EINVAL;
@@@ -769,12 -769,10 +770,12 @@@ static ssize_t ati_remote2_store_mode_m
        struct usb_device *udev = to_usb_device(dev);
        struct usb_interface *intf = usb_ifnum_to_if(udev, 0);
        struct ati_remote2 *ar2 = usb_get_intfdata(intf);
 -      unsigned long mask;
 +      unsigned int mask;
 +      int err;
  
 -      if (strict_strtoul(buf, 0, &mask))
 -              return -EINVAL;
 +      err = kstrtouint(buf, 0, &mask);
 +      if (err)
 +              return err;
  
        if (mask & ~ATI_REMOTE2_MAX_MODE_MASK)
                return -EINVAL;
index 59bfb70d330a03cd8cd8230e031319544309739c,e2a9867c19d52fce53cac578bdaf265d3211bba1..d2c0db159b18dfc364c2ff7fc036863ef2de9614
@@@ -42,24 -42,6 +42,24 @@@ static int synaptics_send_cmd(struct ps
        return 0;
  }
  
 +/*
 + * V3 and later support this fast command
 + */
 +static int elantech_send_cmd(struct psmouse *psmouse, unsigned char c,
 +                              unsigned char *param)
 +{
 +      struct ps2dev *ps2dev = &psmouse->ps2dev;
 +
 +      if (ps2_command(ps2dev, NULL, ETP_PS2_CUSTOM_COMMAND) ||
 +          ps2_command(ps2dev, NULL, c) ||
 +          ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO)) {
 +              psmouse_err(psmouse, "%s query 0x%02x failed.\n", __func__, c);
 +              return -1;
 +      }
 +
 +      return 0;
 +}
 +
  /*
   * A retrying version of ps2_command
   */
@@@ -881,13 -863,13 +881,13 @@@ static int elantech_set_range(struct ps
                        i = (etd->fw_version > 0x020800 &&
                             etd->fw_version < 0x020900) ? 1 : 2;
  
 -                      if (synaptics_send_cmd(psmouse, ETP_FW_ID_QUERY, param))
 +                      if (etd->send_cmd(psmouse, ETP_FW_ID_QUERY, param))
                                return -1;
  
                        fixed_dpi = param[1] & 0x10;
  
                        if (((etd->fw_version >> 16) == 0x14) && fixed_dpi) {
 -                              if (synaptics_send_cmd(psmouse, ETP_SAMPLE_QUERY, param))
 +                              if (etd->send_cmd(psmouse, ETP_SAMPLE_QUERY, param))
                                        return -1;
  
                                *x_max = (etd->capabilities[1] - i) * param[1] / 2;
                break;
  
        case 3:
 -              if (synaptics_send_cmd(psmouse, ETP_FW_ID_QUERY, param))
 +              if (etd->send_cmd(psmouse, ETP_FW_ID_QUERY, param))
                        return -1;
  
                *x_max = (0x0f & param[0]) << 8 | param[1];
                break;
  
        case 4:
 -              if (synaptics_send_cmd(psmouse, ETP_FW_ID_QUERY, param))
 +              if (etd->send_cmd(psmouse, ETP_FW_ID_QUERY, param))
                        return -1;
  
                *x_max = (0x0f & param[0]) << 8 | param[1];
        return 0;
  }
  
 +/*
 + * (value from firmware) * 10 + 790 = dpi
 + * we also have to convert dpi to dots/mm (*10/254 to avoid floating point)
 + */
 +static unsigned int elantech_convert_res(unsigned int val)
 +{
 +      return (val * 10 + 790) * 10 / 254;
 +}
 +
 +static int elantech_get_resolution_v4(struct psmouse *psmouse,
 +                                    unsigned int *x_res,
 +                                    unsigned int *y_res)
 +{
 +      unsigned char param[3];
 +
 +      if (elantech_send_cmd(psmouse, ETP_RESOLUTION_QUERY, param))
 +              return -1;
 +
 +      *x_res = elantech_convert_res(param[1] & 0x0f);
 +      *y_res = elantech_convert_res((param[1] & 0xf0) >> 4);
 +
 +      return 0;
 +}
 +
  /*
   * Set the appropriate event bits for the input subsystem
   */
@@@ -962,7 -920,6 +962,7 @@@ static int elantech_set_input_params(st
        struct input_dev *dev = psmouse->dev;
        struct elantech_data *etd = psmouse->private;
        unsigned int x_min = 0, y_min = 0, x_max = 0, y_max = 0, width = 0;
 +      unsigned int x_res = 0, y_res = 0;
  
        if (elantech_set_range(psmouse, &x_min, &y_min, &x_max, &y_max, &width))
                return -1;
                break;
  
        case 4:
 +              if (elantech_get_resolution_v4(psmouse, &x_res, &y_res)) {
 +                      /*
 +                       * if query failed, print a warning and leave the values
 +                       * zero to resemble synaptics.c behavior.
 +                       */
 +                      psmouse_warn(psmouse, "couldn't query resolution data.\n");
 +              }
 +
                __set_bit(BTN_TOOL_QUADTAP, dev->keybit);
                /* For X to recognize me as touchpad. */
                input_set_abs_params(dev, ABS_X, x_min, x_max, 0, 0);
                input_set_abs_params(dev, ABS_Y, y_min, y_max, 0, 0);
 +              input_abs_set_res(dev, ABS_X, x_res);
 +              input_abs_set_res(dev, ABS_Y, y_res);
                /*
                 * range of pressure and width is the same as v2,
                 * report ABS_PRESSURE, ABS_TOOL_WIDTH for compatibility.
                input_mt_init_slots(dev, ETP_MAX_FINGERS);
                input_set_abs_params(dev, ABS_MT_POSITION_X, x_min, x_max, 0, 0);
                input_set_abs_params(dev, ABS_MT_POSITION_Y, y_min, y_max, 0, 0);
 +              input_abs_set_res(dev, ABS_MT_POSITION_X, x_res);
 +              input_abs_set_res(dev, ABS_MT_POSITION_Y, y_res);
                input_set_abs_params(dev, ABS_MT_PRESSURE, ETP_PMIN_V2,
                                     ETP_PMAX_V2, 0, 0);
                /*
@@@ -1086,13 -1031,16 +1086,13 @@@ static ssize_t elantech_set_int_attr(st
        struct elantech_data *etd = psmouse->private;
        struct elantech_attr_data *attr = data;
        unsigned char *reg = (unsigned char *) etd + attr->field_offset;
 -      unsigned long value;
 +      unsigned char value;
        int err;
  
 -      err = strict_strtoul(buf, 16, &value);
 +      err = kstrtou8(buf, 16, &value);
        if (err)
                return err;
  
 -      if (value > 0xff)
 -              return -EINVAL;
 -
        /* Do we need to preserve some bits for version 2 hardware too? */
        if (etd->hw_version == 1) {
                if (attr->reg == 0x10)
@@@ -1262,24 -1210,32 +1262,34 @@@ static int elantech_reconnect(struct ps
   */
  static int elantech_set_properties(struct elantech_data *etd)
  {
+       /* This represents the version of IC body. */
        int ver = (etd->fw_version & 0x0f0000) >> 16;
  
+       /* Early version of Elan touchpads doesn't obey the rule. */
        if (etd->fw_version < 0x020030 || etd->fw_version == 0x020600)
                etd->hw_version = 1;
-       else if (etd->fw_version < 0x150600)
-               etd->hw_version = 2;
-       else if (ver == 5)
-               etd->hw_version = 3;
-       else if (ver == 6)
-               etd->hw_version = 4;
-       else
-               return -1;
+       else {
+               switch (ver) {
+               case 2:
+               case 4:
+                       etd->hw_version = 2;
+                       break;
+               case 5:
+                       etd->hw_version = 3;
+                       break;
+               case 6:
+                       etd->hw_version = 4;
+                       break;
+               default:
+                       return -1;
+               }
+       }
  
 -      /*
 -       * Turn on packet checking by default.
 -       */
 +      /* decide which send_cmd we're gonna use early */
 +      etd->send_cmd = etd->hw_version >= 3 ? elantech_send_cmd :
 +                                             synaptics_send_cmd;
 +
 +      /* Turn on packet checking by default */
        etd->paritycheck = 1;
  
        /*
@@@ -1335,7 -1291,7 +1345,7 @@@ int elantech_init(struct psmouse *psmou
                     "assuming hardware version %d (with firmware version 0x%02x%02x%02x)\n",
                     etd->hw_version, param[0], param[1], param[2]);
  
 -      if (synaptics_send_cmd(psmouse, ETP_CAPABILITIES_QUERY,
 +      if (etd->send_cmd(psmouse, ETP_CAPABILITIES_QUERY,
            etd->capabilities)) {
                psmouse_err(psmouse, "failed to query capabilities.\n");
                goto init_fail;
index ab498e480f3bf4627c153972c447d24faf22e9ea,1c1b7b43cf923f728c697514fec2cc5afaa7cd31..2fe21d1a18b7af9ed5b409e484b004af321e5e27
@@@ -28,9 -28,7 +28,9 @@@
  #define HID_USAGE_Y_TILT              0x3e
  #define HID_USAGE_FINGER              0x22
  #define HID_USAGE_STYLUS              0x20
 -#define HID_COLLECTION                        0xc0
 +#define HID_COLLECTION                        0xa1
 +#define HID_COLLECTION_LOGICAL                0x02
 +#define HID_COLLECTION_END            0xc0
  
  enum {
        WCM_UNDEFINED = 0,
@@@ -68,8 -66,7 +68,8 @@@ static int wacom_get_report(struct usb_
        do {
                retval = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
                                USB_REQ_GET_REPORT,
 -                              USB_TYPE_CLASS | USB_RECIP_INTERFACE,
 +                              USB_DIR_IN | USB_TYPE_CLASS |
 +                              USB_RECIP_INTERFACE,
                                (type << 8) + id,
                                intf->altsetting[0].desc.bInterfaceNumber,
                                buf, size, 100);
@@@ -167,70 -164,7 +167,70 @@@ static void wacom_close(struct input_de
                usb_autopm_put_interface(wacom->intf);
  }
  
 -static int wacom_parse_hid(struct usb_interface *intf, struct hid_descriptor *hid_desc,
 +static int wacom_parse_logical_collection(unsigned char *report,
 +                                        struct wacom_features *features)
 +{
 +      int length = 0;
 +
 +      if (features->type == BAMBOO_PT) {
 +
 +              /* Logical collection is only used by 3rd gen Bamboo Touch */
 +              features->pktlen = WACOM_PKGLEN_BBTOUCH3;
 +              features->device_type = BTN_TOOL_DOUBLETAP;
 +
 +              /*
 +               * Stylus and Touch have same active area
 +               * so compute physical size based on stylus
 +               * data before its overwritten.
 +               */
 +              features->x_phy =
 +                      (features->x_max * features->x_resolution) / 100;
 +              features->y_phy =
 +                      (features->y_max * features->y_resolution) / 100;
 +
 +              features->x_max = features->y_max =
 +                      get_unaligned_le16(&report[10]);
 +
 +              length = 11;
 +      }
 +      return length;
 +}
 +
 +/*
 + * Interface Descriptor of wacom devices can be incomplete and
 + * inconsistent so wacom_features table is used to store stylus
 + * device's packet lengths, various maximum values, and tablet
 + * resolution based on product ID's.
 + *
 + * For devices that contain 2 interfaces, wacom_features table is
 + * inaccurate for the touch interface.  Since the Interface Descriptor
 + * for touch interfaces has pretty complete data, this function exists
 + * to query tablet for this missing information instead of hard coding in
 + * an additional table.
 + *
 + * A typical Interface Descriptor for a stylus will contain a
 + * boot mouse application collection that is not of interest and this
 + * function will ignore it.
 + *
 + * It also contains a digitizer application collection that also is not
 + * of interest since any information it contains would be duplicate
 + * of what is in wacom_features. Usually it defines a report of an array
 + * of bytes that could be used as max length of the stylus packet returned.
 + * If it happens to define a Digitizer-Stylus Physical Collection then
 + * the X and Y logical values contain valid data but it is ignored.
 + *
 + * A typical Interface Descriptor for a touch interface will contain a
 + * Digitizer-Finger Physical Collection which will define both logical
 + * X/Y maximum as well as the physical size of tablet. Since touch
 + * interfaces haven't supported pressure or distance, this is enough
 + * information to override invalid values in the wacom_features table.
 + *
 + * 3rd gen Bamboo Touch no longer define a Digitizer-Finger Pysical
 + * Collection. Instead they define a Logical Collection with a single
 + * Logical Maximum for both X and Y.
 + */
 +static int wacom_parse_hid(struct usb_interface *intf,
 +                         struct hid_descriptor *hid_desc,
                           struct wacom_features *features)
  {
        struct usb_device *dev = interface_to_usbdev(intf);
                                                /* penabled only accepts exact bytes of data */
                                                if (features->type == TABLETPC2FG)
                                                        features->pktlen = WACOM_PKGLEN_GRAPHIRE;
 -                                              if (features->type == BAMBOO_PT)
 -                                                      features->pktlen = WACOM_PKGLEN_BBFUN;
                                                features->device_type = BTN_TOOL_PEN;
                                                features->x_max =
                                                        get_unaligned_le16(&report[i + 3]);
                                                i += 4;
                                        }
-                               } else if (usage == WCM_DIGITIZER) {
-                                       /* max pressure isn't reported
-                                       features->pressure_max = (unsigned short)
-                                                       (report[i+4] << 8  | report[i + 3]);
-                                       */
-                                       features->pressure_max = 255;
-                                       i += 4;
                                }
                                break;
  
                                                /* penabled only accepts exact bytes of data */
                                                if (features->type == TABLETPC2FG)
                                                        features->pktlen = WACOM_PKGLEN_GRAPHIRE;
 -                                              if (features->type == BAMBOO_PT)
 -                                                      features->pktlen = WACOM_PKGLEN_BBFUN;
                                                features->device_type = BTN_TOOL_PEN;
                                                features->y_max =
                                                        get_unaligned_le16(&report[i + 3]);
                                i++;
                                break;
  
 +                      /*
 +                       * Requiring Stylus Usage will ignore boot mouse
 +                       * X/Y values and some cases of invalid Digitizer X/Y
 +                       * values commonly reported.
 +                       */
                        case HID_USAGE_STYLUS:
                                pen = 1;
                                i++;
                                break;
-                       case HID_USAGE_UNDEFINED:
-                               if (usage == WCM_DESKTOP && finger) /* capacity */
-                                       features->pressure_max =
-                                               get_unaligned_le16(&report[i + 3]);
-                               i += 4;
-                               break;
                        }
                        break;
  
 -              case HID_COLLECTION:
 +              case HID_COLLECTION_END:
                        /* reset UsagePage and Finger */
                        finger = usage = 0;
                        break;
 +
 +              case HID_COLLECTION:
 +                      i++;
 +                      switch (report[i]) {
 +                      case HID_COLLECTION_LOGICAL:
 +                              i += wacom_parse_logical_collection(&report[i],
 +                                                                  features);
 +                              break;
 +                      }
 +                      break;
                }
        }
  
@@@ -439,8 -348,7 +425,8 @@@ static int wacom_query_tablet_data(stru
                                                WAC_HID_FEATURE_REPORT,
                                                report_id, rep_data, 4, 1);
                } while ((error < 0 || rep_data[1] != 4) && limit++ < WAC_MSG_RETRIES);
 -      } else if (features->type != TABLETPC) {
 +      } else if (features->type != TABLETPC &&
 +                 features->device_type == BTN_TOOL_PEN) {
                do {
                        rep_data[0] = 2;
                        rep_data[1] = 2;
index 6b9adc7bec6ea5afa1ab1860de41222edf0216c8,da0d8761e778cfd8f79e64b26a0ce3acd8cf60c5..ecfcbc8144dca62757b105b5275e71f3b8371b64
@@@ -799,29 -799,27 +799,30 @@@ static int wacom_bpt_touch(struct wacom
        unsigned char *data = wacom->data;
        int i;
  
 +      if (data[0] != 0x02)
 +          return 0;
 +
        for (i = 0; i < 2; i++) {
-               int p = data[9 * i + 2];
-               bool touch = p && !wacom->shared->stylus_in_proximity;
+               int offset = (data[1] & 0x80) ? (8 * i) : (9 * i);
+               bool touch = data[offset + 3] & 0x80;
  
-               input_mt_slot(input, i);
-               input_mt_report_slot_state(input, MT_TOOL_FINGER, touch);
                /*
                 * Touch events need to be disabled while stylus is
                 * in proximity because user's hand is resting on touchpad
                 * and sending unwanted events.  User expects tablet buttons
                 * to continue working though.
                 */
+               touch = touch && !wacom->shared->stylus_in_proximity;
+               input_mt_slot(input, i);
+               input_mt_report_slot_state(input, MT_TOOL_FINGER, touch);
                if (touch) {
-                       int x = get_unaligned_be16(&data[9 * i + 3]) & 0x7ff;
-                       int y = get_unaligned_be16(&data[9 * i + 5]) & 0x7ff;
+                       int x = get_unaligned_be16(&data[offset + 3]) & 0x7ff;
+                       int y = get_unaligned_be16(&data[offset + 5]) & 0x7ff;
                        if (features->quirks & WACOM_QUIRK_BBTOUCH_LOWRES) {
                                x <<= 5;
                                y <<= 5;
                        }
-                       input_report_abs(input, ABS_MT_PRESSURE, p);
                        input_report_abs(input, ABS_MT_POSITION_X, x);
                        input_report_abs(input, ABS_MT_POSITION_Y, y);
                }
        return 0;
  }
  
 +static void wacom_bpt3_touch_msg(struct wacom_wac *wacom, unsigned char *data)
 +{
 +      struct input_dev *input = wacom->input;
 +      int slot_id = data[0] - 2;  /* data[0] is between 2 and 17 */
 +      bool touch = data[1] & 0x80;
 +
 +      touch = touch && !wacom->shared->stylus_in_proximity;
 +
 +      input_mt_slot(input, slot_id);
 +      input_mt_report_slot_state(input, MT_TOOL_FINGER, touch);
 +
 +      if (touch) {
 +              int x = (data[2] << 4) | (data[4] >> 4);
 +              int y = (data[3] << 4) | (data[4] & 0x0f);
 +              int w = data[6];
 +
 +              input_report_abs(input, ABS_MT_POSITION_X, x);
 +              input_report_abs(input, ABS_MT_POSITION_Y, y);
 +              input_report_abs(input, ABS_MT_TOUCH_MAJOR, w);
 +      }
 +}
 +
 +static void wacom_bpt3_button_msg(struct wacom_wac *wacom, unsigned char *data)
 +{
 +      struct input_dev *input = wacom->input;
 +
 +      input_report_key(input, BTN_LEFT, (data[1] & 0x08) != 0);
 +      input_report_key(input, BTN_FORWARD, (data[1] & 0x04) != 0);
 +      input_report_key(input, BTN_BACK, (data[1] & 0x02) != 0);
 +      input_report_key(input, BTN_RIGHT, (data[1] & 0x01) != 0);
 +}
 +
 +static int wacom_bpt3_touch(struct wacom_wac *wacom)
 +{
 +      struct input_dev *input = wacom->input;
 +      unsigned char *data = wacom->data;
 +      int count = data[1] & 0x03;
 +      int i;
 +
 +      if (data[0] != 0x02)
 +          return 0;
 +
 +      /* data has up to 7 fixed sized 8-byte messages starting at data[2] */
 +      for (i = 0; i < count; i++) {
 +              int offset = (8 * i) + 2;
 +              int msg_id = data[offset];
 +
 +              if (msg_id >= 2 && msg_id <= 17)
 +                      wacom_bpt3_touch_msg(wacom, data + offset);
 +              else if (msg_id == 128)
 +                      wacom_bpt3_button_msg(wacom, data + offset);
 +
 +      }
 +
 +      input_mt_report_pointer_emulation(input, true);
 +
 +      input_sync(input);
 +
 +      return 0;
 +}
 +
  static int wacom_bpt_pen(struct wacom_wac *wacom)
  {
        struct input_dev *input = wacom->input;
        unsigned char *data = wacom->data;
        int prox = 0, x = 0, y = 0, p = 0, d = 0, pen = 0, btn1 = 0, btn2 = 0;
  
 -      /*
 -       * Similar to Graphire protocol, data[1] & 0x20 is proximity and
 -       * data[1] & 0x18 is tool ID.  0x30 is safety check to ignore
 -       * 2 unused tool ID's.
 -       */
 -      prox = (data[1] & 0x30) == 0x30;
 +      if (data[0] != 0x02)
 +          return 0;
 +
 +      prox = (data[1] & 0x20) == 0x20;
  
        /*
         * All reports shared between PEN and RUBBER tool must be
@@@ -973,9 -912,7 +974,9 @@@ static int wacom_bpt_irq(struct wacom_w
  {
        if (len == WACOM_PKGLEN_BBTOUCH)
                return wacom_bpt_touch(wacom);
 -      else if (len == WACOM_PKGLEN_BBFUN)
 +      else if (len == WACOM_PKGLEN_BBTOUCH3)
 +              return wacom_bpt3_touch(wacom);
 +      else if (len == WACOM_PKGLEN_BBFUN || len == WACOM_PKGLEN_BBPEN)
                return wacom_bpt_pen(wacom);
  
        return 0;
@@@ -1094,9 -1031,9 +1095,9 @@@ void wacom_setup_device_quirks(struct w
            features->type == BAMBOO_PT)
                features->quirks |= WACOM_QUIRK_MULTI_INPUT;
  
 -      /* quirks for bamboo touch */
 +      /* quirk for bamboo touch with 2 low res touches */
        if (features->type == BAMBOO_PT &&
 -          features->device_type == BTN_TOOL_DOUBLETAP) {
 +          features->pktlen == WACOM_PKGLEN_BBTOUCH) {
                features->x_max <<= 5;
                features->y_max <<= 5;
                features->x_fuzz <<= 5;
@@@ -1126,10 -1063,11 +1127,11 @@@ void wacom_setup_input_capabilities(str
                             features->x_fuzz, 0);
        input_set_abs_params(input_dev, ABS_Y, 0, features->y_max,
                             features->y_fuzz, 0);
-       input_set_abs_params(input_dev, ABS_PRESSURE, 0, features->pressure_max,
-                            features->pressure_fuzz, 0);
  
        if (features->device_type == BTN_TOOL_PEN) {
+               input_set_abs_params(input_dev, ABS_PRESSURE, 0, features->pressure_max,
+                            features->pressure_fuzz, 0);
                /* penabled devices have fixed resolution for each model */
                input_abs_set_res(input_dev, ABS_X, features->x_resolution);
                input_abs_set_res(input_dev, ABS_Y, features->y_resolution);
                __set_bit(BTN_TOOL_MOUSE, input_dev->keybit);
                __set_bit(BTN_STYLUS, input_dev->keybit);
                __set_bit(BTN_STYLUS2, input_dev->keybit);
+               __set_bit(INPUT_PROP_POINTER, input_dev->propbit);
                break;
  
        case WACOM_21UX2:
                for (i = 0; i < 8; i++)
                        __set_bit(BTN_0 + i, input_dev->keybit);
  
-               if (wacom_wac->features.type != WACOM_21UX2) {
-                       input_set_abs_params(input_dev, ABS_RX, 0, 4096, 0, 0);
-                       input_set_abs_params(input_dev, ABS_RY, 0, 4096, 0, 0);
-               }
+               input_set_abs_params(input_dev, ABS_RX, 0, 4096, 0, 0);
+               input_set_abs_params(input_dev, ABS_RY, 0, 4096, 0, 0);
                input_set_abs_params(input_dev, ABS_Z, -900, 899, 0, 0);
+               __set_bit(INPUT_PROP_DIRECT, input_dev->propbit);
                wacom_setup_cintiq(wacom_wac);
                break;
  
                /* fall through */
  
        case INTUOS:
+               __set_bit(INPUT_PROP_POINTER, input_dev->propbit);
                wacom_setup_intuos(wacom_wac);
                break;
  
  
                input_set_abs_params(input_dev, ABS_Z, -900, 899, 0, 0);
                wacom_setup_intuos(wacom_wac);
+               __set_bit(INPUT_PROP_POINTER, input_dev->propbit);
                break;
  
        case TABLETPC2FG:
        case TABLETPC:
                __clear_bit(ABS_MISC, input_dev->absbit);
  
+               __set_bit(INPUT_PROP_DIRECT, input_dev->propbit);
                if (features->device_type != BTN_TOOL_PEN)
                        break;  /* no need to process stylus stuff */
  
                /* fall through */
  
        case PL:
-       case PTU:
        case DTU:
                __set_bit(BTN_TOOL_PEN, input_dev->keybit);
+               __set_bit(BTN_TOOL_RUBBER, input_dev->keybit);
                __set_bit(BTN_STYLUS, input_dev->keybit);
                __set_bit(BTN_STYLUS2, input_dev->keybit);
+               __set_bit(INPUT_PROP_DIRECT, input_dev->propbit);
+               break;
+       case PTU:
+               __set_bit(BTN_STYLUS2, input_dev->keybit);
                /* fall through */
  
        case PENPARTNER:
+               __set_bit(BTN_TOOL_PEN, input_dev->keybit);
                __set_bit(BTN_TOOL_RUBBER, input_dev->keybit);
+               __set_bit(BTN_STYLUS, input_dev->keybit);
+               __set_bit(INPUT_PROP_POINTER, input_dev->propbit);
                break;
  
        case BAMBOO_PT:
                __clear_bit(ABS_MISC, input_dev->absbit);
  
+               __set_bit(INPUT_PROP_POINTER, input_dev->propbit);
                if (features->device_type == BTN_TOOL_DOUBLETAP) {
                        __set_bit(BTN_LEFT, input_dev->keybit);
                        __set_bit(BTN_FORWARD, input_dev->keybit);
                        __set_bit(BTN_TOOL_FINGER, input_dev->keybit);
                        __set_bit(BTN_TOOL_DOUBLETAP, input_dev->keybit);
  
 -                      input_mt_init_slots(input_dev, 2);
 +                      if (features->pktlen == WACOM_PKGLEN_BBTOUCH3) {
 +                              __set_bit(BTN_TOOL_TRIPLETAP,
 +                                        input_dev->keybit);
 +                              __set_bit(BTN_TOOL_QUADTAP,
 +                                        input_dev->keybit);
 +
 +                              input_mt_init_slots(input_dev, 16);
 +
 +                              input_set_abs_params(input_dev,
 +                                                   ABS_MT_TOUCH_MAJOR,
 +                                                   0, 255, 0, 0);
 +                      } else {
 +                              input_mt_init_slots(input_dev, 2);
 +                      }
 +
                        input_set_abs_params(input_dev, ABS_MT_POSITION_X,
                                             0, features->x_max,
                                             features->x_fuzz, 0);
@@@ -1562,15 -1506,6 +1584,15 @@@ static const struct wacom_features waco
  static struct wacom_features wacom_features_0xDB =
        { "Wacom Bamboo 2FG 6x8 SE", WACOM_PKGLEN_BBFUN,  21648, 13700, 1023,
          31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
 +static const struct wacom_features wacom_features_0xDD =
 +        { "Wacom Bamboo Connect", WACOM_PKGLEN_BBPEN,     14720,  9200, 1023,
 +          31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
 +static const struct wacom_features wacom_features_0xDE =
 +        { "Wacom Bamboo 16FG 4x5", WACOM_PKGLEN_BBPEN,    14720,  9200, 1023,
 +          31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
 +static const struct wacom_features wacom_features_0xDF =
 +        { "Wacom Bamboo 16FG 6x8", WACOM_PKGLEN_BBPEN,    21648, 13700, 1023,
 +          31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
  static const struct wacom_features wacom_features_0x6004 =
        { "ISD-V4",               WACOM_PKGLEN_GRAPHIRE,  12800,  8000,  255,
          0, TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
@@@ -1666,9 -1601,6 +1688,9 @@@ const struct usb_device_id wacom_ids[] 
        { USB_DEVICE_WACOM(0xD8) },
        { USB_DEVICE_WACOM(0xDA) },
        { USB_DEVICE_WACOM(0xDB) },
 +      { USB_DEVICE_WACOM(0xDD) },
 +      { USB_DEVICE_WACOM(0xDE) },
 +      { USB_DEVICE_WACOM(0xDF) },
        { USB_DEVICE_WACOM(0xF0) },
        { USB_DEVICE_WACOM(0xCC) },
        { USB_DEVICE_WACOM(0x90) },
index 374370ec73ac948e34cde9424a5bcc97ba853fd0,400131df677b424c025682f0a61c97fe4bc85109..2da9f189e4938d8628b5056b292cac75c7522495
@@@ -45,6 -45,7 +45,7 @@@
  #include <linux/slab.h>
  #include <linux/spi/spi.h>
  #include <linux/spi/ad7877.h>
+ #include <linux/module.h>
  #include <asm/irq.h>
  
  #define       TS_PEN_UP_TIMEOUT       msecs_to_jiffies(100)
@@@ -487,10 -488,10 +488,10 @@@ static ssize_t ad7877_disable_store(str
                                     const char *buf, size_t count)
  {
        struct ad7877 *ts = dev_get_drvdata(dev);
 -      unsigned long val;
 +      unsigned int val;
        int error;
  
 -      error = strict_strtoul(buf, 10, &val);
 +      error = kstrtouint(buf, 10, &val);
        if (error)
                return error;
  
@@@ -517,10 -518,10 +518,10 @@@ static ssize_t ad7877_dac_store(struct 
                                     const char *buf, size_t count)
  {
        struct ad7877 *ts = dev_get_drvdata(dev);
 -      unsigned long val;
 +      unsigned int val;
        int error;
  
 -      error = strict_strtoul(buf, 10, &val);
 +      error = kstrtouint(buf, 10, &val);
        if (error)
                return error;
  
@@@ -547,10 -548,10 +548,10 @@@ static ssize_t ad7877_gpio3_store(struc
                                     const char *buf, size_t count)
  {
        struct ad7877 *ts = dev_get_drvdata(dev);
 -      unsigned long val;
 +      unsigned int val;
        int error;
  
 -      error = strict_strtoul(buf, 10, &val);
 +      error = kstrtouint(buf, 10, &val);
        if (error)
                return error;
  
@@@ -578,10 -579,10 +579,10 @@@ static ssize_t ad7877_gpio4_store(struc
                                     const char *buf, size_t count)
  {
        struct ad7877 *ts = dev_get_drvdata(dev);
 -      unsigned long val;
 +      unsigned int val;
        int error;
  
 -      error = strict_strtoul(buf, 10, &val);
 +      error = kstrtouint(buf, 10, &val);
        if (error)
                return error;
  
index 8b44fc7682515058afa99719d406a2f64745bcbe,b1643c8fa7c9a1bca311e90e2cfc39e7ba836e2f..8f391ffbf441ddc25c21b5a18da9c0bce05a88fe
@@@ -9,6 -9,7 +9,7 @@@
  #include <linux/input.h>      /* BUS_SPI */
  #include <linux/pm.h>
  #include <linux/spi/spi.h>
+ #include <linux/module.h>
  
  #include "ad7879.h"
  
  #define AD7879_WRITECMD(reg) (AD7879_CMD(reg))
  #define AD7879_READCMD(reg)  (AD7879_CMD(reg) | AD7879_CMD_READ)
  
 -#ifdef CONFIG_PM_SLEEP
 -static int ad7879_spi_suspend(struct device *dev)
 -{
 -      struct spi_device *spi = to_spi_device(dev);
 -      struct ad7879 *ts = spi_get_drvdata(spi);
 -
 -      ad7879_suspend(ts);
 -
 -      return 0;
 -}
 -
 -static int ad7879_spi_resume(struct device *dev)
 -{
 -      struct spi_device *spi = to_spi_device(dev);
 -      struct ad7879 *ts = spi_get_drvdata(spi);
 -
 -      ad7879_resume(ts);
 -
 -      return 0;
 -}
 -#endif
 -
 -static SIMPLE_DEV_PM_OPS(ad7879_spi_pm, ad7879_spi_suspend, ad7879_spi_resume);
 -
  /*
   * ad7879_read/write are only used for initial setup and for sysfs controls.
   * The main traffic is done in ad7879_collect().
@@@ -151,7 -176,7 +152,7 @@@ static struct spi_driver ad7879_spi_dri
                .name   = "ad7879",
                .bus    = &spi_bus_type,
                .owner  = THIS_MODULE,
 -              .pm     = &ad7879_spi_pm,
 +              .pm     = &ad7879_pm_ops,
        },
        .probe          = ad7879_spi_probe,
        .remove         = __devexit_p(ad7879_spi_remove),
index dce60b816b5865dd4026b166781a15a9b1ab69ce,3b2e9ed2aeec3482c7ec178b238410fc93424ff2..e2482b40da5198fdb1406e135fff827d049e5895
@@@ -33,6 -33,7 +33,7 @@@
  #include <linux/gpio.h>
  
  #include <linux/spi/ad7879.h>
+ #include <linux/module.h>
  #include "ad7879.h"
  
  #define AD7879_REG_ZEROS              0
@@@ -280,11 -281,8 +281,11 @@@ static void ad7879_close(struct input_d
                __ad7879_disable(ts);
  }
  
 -void ad7879_suspend(struct ad7879 *ts)
 +#ifdef CONFIG_PM_SLEEP
 +static int ad7879_suspend(struct device *dev)
  {
 +      struct ad7879 *ts = dev_get_drvdata(dev);
 +
        mutex_lock(&ts->input->mutex);
  
        if (!ts->suspended && !ts->disabled && ts->input->users)
        ts->suspended = true;
  
        mutex_unlock(&ts->input->mutex);
 +
 +      return 0;
  }
 -EXPORT_SYMBOL(ad7879_suspend);
  
 -void ad7879_resume(struct ad7879 *ts)
 +static int ad7879_resume(struct device *dev)
  {
 +      struct ad7879 *ts = dev_get_drvdata(dev);
 +
        mutex_lock(&ts->input->mutex);
  
        if (ts->suspended && !ts->disabled && ts->input->users)
        ts->suspended = false;
  
        mutex_unlock(&ts->input->mutex);
 +
 +      return 0;
  }
 -EXPORT_SYMBOL(ad7879_resume);
 +#endif
 +
 +SIMPLE_DEV_PM_OPS(ad7879_pm_ops, ad7879_suspend, ad7879_resume);
 +EXPORT_SYMBOL(ad7879_pm_ops);
  
  static void ad7879_toggle(struct ad7879 *ts, bool disable)
  {
@@@ -350,10 -340,10 +351,10 @@@ static ssize_t ad7879_disable_store(str
                                     const char *buf, size_t count)
  {
        struct ad7879 *ts = dev_get_drvdata(dev);
 -      unsigned long val;
 +      unsigned int val;
        int error;
  
 -      error = strict_strtoul(buf, 10, &val);
 +      error = kstrtouint(buf, 10, &val);
        if (error)
                return error;
  
index c69536c97c0f4202ec7dd742653066a7cb273277,de31ec6fe9e47005ba94cc9eae222f922bb9c4b9..4cedae6a36eaa0328abb1831647784a6c29d6747
@@@ -31,6 -31,7 +31,7 @@@
  #include <linux/spi/spi.h>
  #include <linux/spi/ads7846.h>
  #include <linux/regulator/consumer.h>
+ #include <linux/module.h>
  #include <asm/irq.h>
  
  /*
@@@ -601,12 -602,10 +602,12 @@@ static ssize_t ads7846_disable_store(st
                                     const char *buf, size_t count)
  {
        struct ads7846 *ts = dev_get_drvdata(dev);
 -      unsigned long i;
 +      unsigned int i;
 +      int err;
  
 -      if (strict_strtoul(buf, 10, &i))
 -              return -EINVAL;
 +      err = kstrtouint(buf, 10, &i);
 +      if (err)
 +              return err;
  
        if (i)
                ads7846_disable(ts);