Merge branches 'for-4.3/chicony', 'for-4.3/cp2112', 'for-4.3/i2c-hid', 'for-4.3/lenov...
authorJiri Kosina <jkosina@suse.cz>
Tue, 1 Sep 2015 13:37:30 +0000 (15:37 +0200)
committerJiri Kosina <jkosina@suse.cz>
Tue, 1 Sep 2015 13:37:30 +0000 (15:37 +0200)
20 files changed:
Documentation/ABI/testing/sysfs-driver-wacom
drivers/hid/Kconfig
drivers/hid/hid-chicony.c
drivers/hid/hid-core.c
drivers/hid/hid-cp2112.c
drivers/hid/hid-ids.h
drivers/hid/hid-lenovo.c
drivers/hid/hid-lg.c
drivers/hid/hid-multitouch.c
drivers/hid/hid-picolcd_backlight.c
drivers/hid/hid-picolcd_cir.c
drivers/hid/hid-picolcd_lcd.c
drivers/hid/hid-rmi.c
drivers/hid/hid-sensor-hub.c
drivers/hid/hid-sony.c
drivers/hid/i2c-hid/i2c-hid.c
drivers/hid/wacom.h
drivers/hid/wacom_sys.c
drivers/hid/wacom_wac.c
drivers/hid/wacom_wac.h

index c4f0fed64a6e5ebca402b340757f6a3eb4b0c376..dca4293407726654d4a5da02f1911c644d052972 100644 (file)
@@ -77,3 +77,22 @@ Description:
                The format is also scrambled, like in the USB mode, and it can
                be summarized by converting 76543210 into GECA6420.
                                            HGFEDCBA      HFDB7531
+
+What:          /sys/bus/hid/devices/<bus>:<vid>:<pid>.<n>/wacom_remote/unpair_remote
+Date:          July 2015
+Contact:       linux-input@vger.kernel.org
+Description:
+               Writing the character sequence '*' followed by a newline to
+               this file will delete all of the current pairings on the
+               device. Other character sequences are reserved. This file is
+               write only.
+
+What:          /sys/bus/hid/devices/<bus>:<vid>:<pid>.<n>/wacom_remote/<serial_number>/remote_mode
+Date:          July 2015
+Contact:       linux-input@vger.kernel.org
+Description:
+               Reading from this file reports the mode status of the
+               remote as indicated by the LED lights on the device. If no
+               reports have been received from the paired device, reading
+               from this file will report '-1'. The mode is read-only
+               and cannot be set through the driver.
index e48ee2ca9d22d72d310f0b02e3ae387deb373d84..6ab51ae3c39d5753f5315fd7451db737a311a24e 100644 (file)
@@ -486,6 +486,7 @@ config HID_MULTITOUCH
          - Atmel panels
          - Cando dual touch panels
          - Chunghwa panels
+         - CJTouch panels
          - CVTouch panels
          - Cypress TrueTouch panels
          - Elan Microelectronics touch panels
index b613d5a7968457b5719acaf57d9c0bc98b47ed29..bc3cec199feefdf437d0c0141c5ff6f73aa10308 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/input.h>
 #include <linux/hid.h>
 #include <linux/module.h>
+#include <linux/usb.h>
 
 #include "hid-ids.h"
 
@@ -57,10 +58,34 @@ static int ch_input_mapping(struct hid_device *hdev, struct hid_input *hi,
        return 1;
 }
 
+static __u8 *ch_switch12_report_fixup(struct hid_device *hdev, __u8 *rdesc,
+               unsigned int *rsize)
+{
+       struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
+       
+       if (intf->cur_altsetting->desc.bInterfaceNumber == 1) {
+               /* Change usage maximum and logical maximum from 0x7fff to
+                * 0x2fff, so they don't exceed HID_MAX_USAGES */
+               switch (hdev->product) {
+               case USB_DEVICE_ID_CHICONY_ACER_SWITCH12:
+                       if (*rsize >= 128 && rdesc[64] == 0xff && rdesc[65] == 0x7f
+                                       && rdesc[69] == 0xff && rdesc[70] == 0x7f) {
+                               hid_info(hdev, "Fixing up report descriptor\n");
+                               rdesc[65] = rdesc[70] = 0x2f;
+                       }
+                       break;
+               }
+
+       }
+       return rdesc;
+}
+
+
 static const struct hid_device_id ch_devices[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_TACTICAL_PAD) },
        { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_WIRELESS2) },
        { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_AK1D) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_ACER_SWITCH12) },
        { }
 };
 MODULE_DEVICE_TABLE(hid, ch_devices);
@@ -68,6 +93,7 @@ MODULE_DEVICE_TABLE(hid, ch_devices);
 static struct hid_driver ch_driver = {
        .name = "chicony",
        .id_table = ch_devices,
+       .report_fixup = ch_switch12_report_fixup,
        .input_mapping = ch_input_mapping,
 };
 module_hid_driver(ch_driver);
index d931886dffe8183a16ed2fd7f0e621b479b2fb98..8d9cb755e08add483bde47f1f9c43dd6ec1867f4 100644 (file)
@@ -1826,6 +1826,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_WIRELESS) },
        { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_WIRELESS2) },
        { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_AK1D) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_ACER_SWITCH12) },
        { HID_USB_DEVICE(USB_VENDOR_ID_CREATIVELABS, USB_DEVICE_ID_PRODIKEYS_PCMIDI) },
        { HID_USB_DEVICE(USB_VENDOR_ID_CYGNAL, USB_DEVICE_ID_CYGNAL_CP2112) },
        { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_1) },
index a2dbbbe0d8d7e81b06ac6d646737413fe4d1d357..7afc3fcc122c476a42e20f1e85e1ed409c93a734 100644 (file)
@@ -156,6 +156,7 @@ struct cp2112_device {
        wait_queue_head_t wait;
        u8 read_data[61];
        u8 read_length;
+       u8 hwversion;
        int xfer_status;
        atomic_t read_avail;
        atomic_t xfer_avail;
@@ -446,6 +447,24 @@ static int cp2112_i2c_write_req(void *buf, u8 slave_address, u8 *data,
        return data_length + 3;
 }
 
+static int cp2112_i2c_write_read_req(void *buf, u8 slave_address,
+                                    u8 *addr, int addr_length,
+                                    int read_length)
+{
+       struct cp2112_write_read_req_report *report = buf;
+
+       if (read_length < 1 || read_length > 512 ||
+           addr_length > sizeof(report->target_address))
+               return -EINVAL;
+
+       report->report = CP2112_DATA_WRITE_READ_REQUEST;
+       report->slave_address = slave_address << 1;
+       report->length = cpu_to_be16(read_length);
+       report->target_address_length = addr_length;
+       memcpy(report->target_address, addr, addr_length);
+       return addr_length + 5;
+}
+
 static int cp2112_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
                           int num)
 {
@@ -453,26 +472,46 @@ static int cp2112_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
        struct hid_device *hdev = dev->hdev;
        u8 buf[64];
        ssize_t count;
+       ssize_t read_length = 0;
+       u8 *read_buf = NULL;
        unsigned int retries;
        int ret;
 
        hid_dbg(hdev, "I2C %d messages\n", num);
 
-       if (num != 1) {
+       if (num == 1) {
+               if (msgs->flags & I2C_M_RD) {
+                       hid_dbg(hdev, "I2C read %#04x len %d\n",
+                               msgs->addr, msgs->len);
+                       read_length = msgs->len;
+                       read_buf = msgs->buf;
+                       count = cp2112_read_req(buf, msgs->addr, msgs->len);
+               } else {
+                       hid_dbg(hdev, "I2C write %#04x len %d\n",
+                               msgs->addr, msgs->len);
+                       count = cp2112_i2c_write_req(buf, msgs->addr,
+                                                    msgs->buf, msgs->len);
+               }
+               if (count < 0)
+                       return count;
+       } else if (dev->hwversion > 1 &&  /* no repeated start in rev 1 */
+                  num == 2 &&
+                  msgs[0].addr == msgs[1].addr &&
+                  !(msgs[0].flags & I2C_M_RD) && (msgs[1].flags & I2C_M_RD)) {
+               hid_dbg(hdev, "I2C write-read %#04x wlen %d rlen %d\n",
+                       msgs[0].addr, msgs[0].len, msgs[1].len);
+               read_length = msgs[1].len;
+               read_buf = msgs[1].buf;
+               count = cp2112_i2c_write_read_req(buf, msgs[0].addr,
+                               msgs[0].buf, msgs[0].len, msgs[1].len);
+               if (count < 0)
+                       return count;
+       } else {
                hid_err(hdev,
                        "Multi-message I2C transactions not supported\n");
                return -EOPNOTSUPP;
        }
 
-       if (msgs->flags & I2C_M_RD)
-               count = cp2112_read_req(buf, msgs->addr, msgs->len);
-       else
-               count = cp2112_i2c_write_req(buf, msgs->addr, msgs->buf,
-                                            msgs->len);
-
-       if (count < 0)
-               return count;
-
        ret = hid_hw_power(hdev, PM_HINT_FULLON);
        if (ret < 0) {
                hid_err(hdev, "power management error: %d\n", ret);
@@ -508,21 +547,34 @@ static int cp2112_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
                goto power_normal;
        }
 
-       if (!(msgs->flags & I2C_M_RD))
-               goto finish;
-
-       ret = cp2112_read(dev, msgs->buf, msgs->len);
-       if (ret < 0)
-               goto power_normal;
-       if (ret != msgs->len) {
-               hid_warn(hdev, "short read: %d < %d\n", ret, msgs->len);
-               ret = -EIO;
-               goto power_normal;
+       for (count = 0; count < read_length;) {
+               ret = cp2112_read(dev, read_buf + count, read_length - count);
+               if (ret < 0)
+                       goto power_normal;
+               if (ret == 0) {
+                       hid_err(hdev, "read returned 0\n");
+                       ret = -EIO;
+                       goto power_normal;
+               }
+               count += ret;
+               if (count > read_length) {
+                       /*
+                        * The hardware returned too much data.
+                        * This is mostly harmless because cp2112_read()
+                        * has a limit check so didn't overrun our
+                        * buffer.  Nevertheless, we return an error
+                        * because something is seriously wrong and
+                        * it shouldn't go unnoticed.
+                        */
+                       hid_err(hdev, "long read: %d > %zd\n",
+                               ret, read_length - count + ret);
+                       ret = -EIO;
+                       goto power_normal;
+               }
        }
 
-finish:
        /* return the number of transferred messages */
-       ret = 1;
+       ret = num;
 
 power_normal:
        hid_hw_power(hdev, PM_HINT_NORMAL);
@@ -537,7 +589,7 @@ static int cp2112_xfer(struct i2c_adapter *adap, u16 addr,
        struct cp2112_device *dev = (struct cp2112_device *)adap->algo_data;
        struct hid_device *hdev = dev->hdev;
        u8 buf[64];
-       __be16 word;
+       __le16 word;
        ssize_t count;
        size_t read_length = 0;
        unsigned int retries;
@@ -554,7 +606,7 @@ static int cp2112_xfer(struct i2c_adapter *adap, u16 addr,
                if (I2C_SMBUS_READ == read_write)
                        count = cp2112_read_req(buf, addr, read_length);
                else
-                       count = cp2112_write_req(buf, addr, data->byte, NULL,
+                       count = cp2112_write_req(buf, addr, command, NULL,
                                                 0);
                break;
        case I2C_SMBUS_BYTE_DATA:
@@ -569,7 +621,7 @@ static int cp2112_xfer(struct i2c_adapter *adap, u16 addr,
                break;
        case I2C_SMBUS_WORD_DATA:
                read_length = 2;
-               word = cpu_to_be16(data->word);
+               word = cpu_to_le16(data->word);
 
                if (I2C_SMBUS_READ == read_write)
                        count = cp2112_write_read_req(buf, addr, read_length,
@@ -582,7 +634,7 @@ static int cp2112_xfer(struct i2c_adapter *adap, u16 addr,
                size = I2C_SMBUS_WORD_DATA;
                read_write = I2C_SMBUS_READ;
                read_length = 2;
-               word = cpu_to_be16(data->word);
+               word = cpu_to_le16(data->word);
 
                count = cp2112_write_read_req(buf, addr, read_length, command,
                                              (u8 *)&word, 2);
@@ -675,7 +727,7 @@ static int cp2112_xfer(struct i2c_adapter *adap, u16 addr,
                data->byte = buf[0];
                break;
        case I2C_SMBUS_WORD_DATA:
-               data->word = be16_to_cpup((__be16 *)buf);
+               data->word = le16_to_cpup((__le16 *)buf);
                break;
        case I2C_SMBUS_BLOCK_DATA:
                if (read_length > I2C_SMBUS_BLOCK_MAX) {
@@ -1030,6 +1082,7 @@ static int cp2112_probe(struct hid_device *hdev, const struct hid_device_id *id)
        dev->adap.dev.parent    = &hdev->dev;
        snprintf(dev->adap.name, sizeof(dev->adap.name),
                 "CP2112 SMBus Bridge on hiddev%d", hdev->minor);
+       dev->hwversion = buf[2];
        init_waitqueue_head(&dev->wait);
 
        hid_device_io_start(hdev);
index 624d916d39d240c1a4bcce195015202b76f3621c..814f76fdc7daef35d31c84b376981af6306b5b67 100644 (file)
 #define USB_DEVICE_ID_CHICONY_PIXART_USB_OPTICAL_MOUSE 0x1053
 #define USB_DEVICE_ID_CHICONY_WIRELESS2        0x1123
 #define USB_DEVICE_ID_CHICONY_AK1D     0x1125
+#define USB_DEVICE_ID_CHICONY_ACER_SWITCH12    0x1421
 
 #define USB_VENDOR_ID_CHUNGHWAT                0x2247
 #define USB_DEVICE_ID_CHUNGHWAT_MULTITOUCH     0x0001
 
 #define USB_VENDOR_ID_CIDC             0x1677
 
+#define USB_VENDOR_ID_CJTOUCH          0x24b8
+#define USB_DEVICE_ID_CJTOUCH_MULTI_TOUCH_0020 0x0020
+#define USB_DEVICE_ID_CJTOUCH_MULTI_TOUCH_0040 0x0040
+
 #define USB_VENDOR_ID_CMEDIA           0x0d8c
 #define USB_DEVICE_ID_CM109            0x000e
 
 #define USB_VENDOR_ID_IRTOUCHSYSTEMS   0x6615
 #define USB_DEVICE_ID_IRTOUCH_INFRARED_USB     0x0070
 
+#define USB_VENDOR_ID_ITE               0x048d
+#define USB_DEVICE_ID_ITE_LENOVO_YOGA   0x8386
+
 #define USB_VENDOR_ID_JABRA            0x0b0e
 #define USB_DEVICE_ID_JABRA_SPEAK_410  0x0412
 #define USB_DEVICE_ID_JABRA_SPEAK_510  0x0420
 #define USB_DEVICE_ID_LOGITECH_DUAL_ACTION     0xc216
 #define USB_DEVICE_ID_LOGITECH_RUMBLEPAD2      0xc218
 #define USB_DEVICE_ID_LOGITECH_RUMBLEPAD2_2    0xc219
+#define USB_DEVICE_ID_LOGITECH_G29_WHEEL       0xc24f
 #define USB_DEVICE_ID_LOGITECH_WINGMAN_F3D     0xc283
 #define USB_DEVICE_ID_LOGITECH_FORCE3D_PRO     0xc286
 #define USB_DEVICE_ID_LOGITECH_FLIGHT_SYSTEM_G940      0xc287
index 4f59bffd020538846d88d4c85ef76168542c980e..e4bc6cb6d7fa5d5481f650c87fde01a7348fdb6a 100644 (file)
@@ -37,6 +37,7 @@ struct lenovo_drvdata_tpkbd {
 };
 
 struct lenovo_drvdata_cptkbd {
+       u8 middlebutton_state; /* 0:Up, 1:Down (undecided), 2:Scrolling */
        bool fn_lock;
        int sensitivity;
 };
@@ -146,10 +147,10 @@ static int lenovo_input_mapping_cptkbd(struct hid_device *hdev,
 
                switch (usage->hid & HID_USAGE) {
                case 0x0000:
-                       hid_map_usage(hi, usage, bit, max, EV_REL, 0x06);
+                       hid_map_usage(hi, usage, bit, max, EV_REL, REL_HWHEEL);
                        return 1;
                case 0x0001:
-                       hid_map_usage(hi, usage, bit, max, EV_REL, 0x08);
+                       hid_map_usage(hi, usage, bit, max, EV_REL, REL_WHEEL);
                        return 1;
                default:
                        return -1;
@@ -207,9 +208,12 @@ static void lenovo_features_set_cptkbd(struct hid_device *hdev)
        struct lenovo_drvdata_cptkbd *cptkbd_data = hid_get_drvdata(hdev);
 
        ret = lenovo_send_cmd_cptkbd(hdev, 0x05, cptkbd_data->fn_lock);
-       ret = lenovo_send_cmd_cptkbd(hdev, 0x02, cptkbd_data->sensitivity);
        if (ret)
                hid_err(hdev, "Fn-lock setting failed: %d\n", ret);
+
+       ret = lenovo_send_cmd_cptkbd(hdev, 0x02, cptkbd_data->sensitivity);
+       if (ret)
+               hid_err(hdev, "Sensitivity setting failed: %d\n", ret);
 }
 
 static ssize_t attr_fn_lock_show_cptkbd(struct device *dev,
@@ -313,6 +317,53 @@ static int lenovo_raw_event(struct hid_device *hdev,
        return 0;
 }
 
+static int lenovo_event_cptkbd(struct hid_device *hdev,
+               struct hid_field *field, struct hid_usage *usage, __s32 value)
+{
+       struct lenovo_drvdata_cptkbd *cptkbd_data = hid_get_drvdata(hdev);
+
+       /* "wheel" scroll events */
+       if (usage->type == EV_REL && (usage->code == REL_WHEEL ||
+                       usage->code == REL_HWHEEL)) {
+               /* Scroll events disable middle-click event */
+               cptkbd_data->middlebutton_state = 2;
+               return 0;
+       }
+
+       /* Middle click events */
+       if (usage->type == EV_KEY && usage->code == BTN_MIDDLE) {
+               if (value == 1) {
+                       cptkbd_data->middlebutton_state = 1;
+               } else if (value == 0) {
+                       if (cptkbd_data->middlebutton_state == 1) {
+                               /* No scrolling inbetween, send middle-click */
+                               input_event(field->hidinput->input,
+                                       EV_KEY, BTN_MIDDLE, 1);
+                               input_sync(field->hidinput->input);
+                               input_event(field->hidinput->input,
+                                       EV_KEY, BTN_MIDDLE, 0);
+                               input_sync(field->hidinput->input);
+                       }
+                       cptkbd_data->middlebutton_state = 0;
+               }
+               return 1;
+       }
+
+       return 0;
+}
+
+static int lenovo_event(struct hid_device *hdev, struct hid_field *field,
+               struct hid_usage *usage, __s32 value)
+{
+       switch (hdev->product) {
+       case USB_DEVICE_ID_LENOVO_CUSBKBD:
+       case USB_DEVICE_ID_LENOVO_CBTKBD:
+               return lenovo_event_cptkbd(hdev, field, usage, value);
+       default:
+               return 0;
+       }
+}
+
 static int lenovo_features_set_tpkbd(struct hid_device *hdev)
 {
        struct hid_report *report;
@@ -705,6 +756,7 @@ static int lenovo_probe_cptkbd(struct hid_device *hdev)
                hid_warn(hdev, "Failed to switch middle button: %d\n", ret);
 
        /* Set keyboard settings to known state */
+       cptkbd_data->middlebutton_state = 0;
        cptkbd_data->fn_lock = true;
        cptkbd_data->sensitivity = 0x05;
        lenovo_features_set_cptkbd(hdev);
@@ -832,6 +884,7 @@ static struct hid_driver lenovo_driver = {
        .probe = lenovo_probe,
        .remove = lenovo_remove,
        .raw_event = lenovo_raw_event,
+       .event = lenovo_event,
        .report_fixup = lenovo_report_fixup,
 };
 module_hid_driver(lenovo_driver);
index 429340d809b5546341d09fc6a3bea6fedb525497..5332fb7d072a2e2086ba445686a09a9f8dc7d525 100644 (file)
@@ -776,6 +776,8 @@ static const struct hid_device_id lg_devices[] = {
                .driver_data = LG_FF },
        { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2_2),
                .driver_data = LG_FF },
+       { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G29_WHEEL),
+               .driver_data = LG_FF4 },
        { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WINGMAN_F3D),
                .driver_data = LG_FF },
        { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_FORCE3D_PRO),
index 7c811252c1cefebb2418944a7f391117a8a92b6d..426b2f1a34501c7516ab39dc631d3c2073591aac 100644 (file)
@@ -1145,6 +1145,14 @@ static const struct hid_device_id mt_devices[] = {
                MT_USB_DEVICE(USB_VENDOR_ID_CHUNGHWAT,
                        USB_DEVICE_ID_CHUNGHWAT_MULTITOUCH) },
 
+       /* CJTouch panels */
+       { .driver_data = MT_CLS_NSMU,
+               MT_USB_DEVICE(USB_VENDOR_ID_CJTOUCH,
+                       USB_DEVICE_ID_CJTOUCH_MULTI_TOUCH_0020) },
+       { .driver_data = MT_CLS_NSMU,
+               MT_USB_DEVICE(USB_VENDOR_ID_CJTOUCH,
+                       USB_DEVICE_ID_CJTOUCH_MULTI_TOUCH_0040) },
+
        /* CVTouch panels */
        { .driver_data = MT_CLS_NSMU,
                MT_USB_DEVICE(USB_VENDOR_ID_CVTOUCH,
index a32c5f86b0b3f667466b921f1ed4581ad1857b1e..808807ad388f9c9c6048cbd30c7969e8cd1937e2 100644 (file)
@@ -94,8 +94,7 @@ void picolcd_exit_backlight(struct picolcd_data *data)
        struct backlight_device *bdev = data->backlight;
 
        data->backlight = NULL;
-       if (bdev)
-               backlight_device_unregister(bdev);
+       backlight_device_unregister(bdev);
 }
 
 int picolcd_resume_backlight(struct picolcd_data *data)
index 045f8ebf16b53747746bf92c110f434ffdaff319..96286510f42e990eef1a0fd6a03abfd57fd42f57 100644 (file)
@@ -145,7 +145,6 @@ void picolcd_exit_cir(struct picolcd_data *data)
        struct rc_dev *rdev = data->rc_dev;
 
        data->rc_dev = NULL;
-       if (rdev)
-               rc_unregister_device(rdev);
+       rc_unregister_device(rdev);
 }
 
index 89821c2da6d76b766347ae629314d68df3033942..22dcbe13da892cc3ede9f9cdccf280d752035d92 100644 (file)
@@ -92,8 +92,7 @@ void picolcd_exit_lcd(struct picolcd_data *data)
        struct lcd_device *ldev = data->lcd;
 
        data->lcd = NULL;
-       if (ldev)
-               lcd_device_unregister(ldev);
+       lcd_device_unregister(ldev);
 }
 
 int picolcd_resume_lcd(struct picolcd_data *data)
index 4cf80bb276dc34f481f8aaf10bec55966fe80657..2c148129beb2f0a746f4661660be47e79421274e 100644 (file)
 #define RMI_READ_DATA_PENDING          1
 #define RMI_STARTED                    2
 
+#define RMI_SLEEP_NORMAL               0x0
+#define RMI_SLEEP_DEEP_SLEEP           0x1
+
 /* device flags */
 #define RMI_DEVICE                     BIT(0)
 #define RMI_DEVICE_HAS_PHYS_BUTTONS    BIT(1)
 
+/*
+ * retrieve the ctrl registers
+ * the ctrl register has a size of 20 but a fw bug split it into 16 + 4,
+ * and there is no way to know if the first 20 bytes are here or not.
+ * We use only the first 12 bytes, so get only them.
+ */
+#define RMI_F11_CTRL_REG_COUNT         12
+
 enum rmi_mode_type {
        RMI_MODE_OFF                    = 0,
        RMI_MODE_ATTN_REPORTS           = 1,
@@ -113,6 +124,8 @@ struct rmi_data {
        unsigned int max_y;
        unsigned int x_size_mm;
        unsigned int y_size_mm;
+       bool read_f11_ctrl_regs;
+       u8 f11_ctrl_regs[RMI_F11_CTRL_REG_COUNT];
 
        unsigned int gpio_led_count;
        unsigned int button_count;
@@ -126,6 +139,10 @@ struct rmi_data {
 
        unsigned long device_flags;
        unsigned long firmware_id;
+
+       u8 f01_ctrl0;
+       u8 interrupt_enable_mask;
+       bool restore_interrupt_mask;
 };
 
 #define RMI_PAGE(addr) (((addr) >> 8) & 0xff)
@@ -346,13 +363,34 @@ static void rmi_f11_process_touch(struct rmi_data *hdata, int slot,
        }
 }
 
+static int rmi_reset_attn_mode(struct hid_device *hdev)
+{
+       struct rmi_data *data = hid_get_drvdata(hdev);
+       int ret;
+
+       ret = rmi_set_mode(hdev, RMI_MODE_ATTN_REPORTS);
+       if (ret)
+               return ret;
+
+       if (data->restore_interrupt_mask) {
+               ret = rmi_write(hdev, data->f01.control_base_addr + 1,
+                               &data->interrupt_enable_mask);
+               if (ret) {
+                       hid_err(hdev, "can not write F01 control register\n");
+                       return ret;
+               }
+       }
+
+       return 0;
+}
+
 static void rmi_reset_work(struct work_struct *work)
 {
        struct rmi_data *hdata = container_of(work, struct rmi_data,
                                                reset_work);
 
        /* switch the device to RMI if we receive a generic mouse report */
-       rmi_set_mode(hdata->hdev, RMI_MODE_ATTN_REPORTS);
+       rmi_reset_attn_mode(hdata->hdev);
 }
 
 static inline int rmi_schedule_reset(struct hid_device *hdev)
@@ -532,14 +570,77 @@ static int rmi_event(struct hid_device *hdev, struct hid_field *field,
 }
 
 #ifdef CONFIG_PM
+static int rmi_set_sleep_mode(struct hid_device *hdev, int sleep_mode)
+{
+       struct rmi_data *data = hid_get_drvdata(hdev);
+       int ret;
+       u8 f01_ctrl0;
+
+       f01_ctrl0 = (data->f01_ctrl0 & ~0x3) | sleep_mode;
+
+       ret = rmi_write(hdev, data->f01.control_base_addr,
+                       &f01_ctrl0);
+       if (ret) {
+               hid_err(hdev, "can not write sleep mode\n");
+               return ret;
+       }
+
+       return 0;
+}
+
+static int rmi_suspend(struct hid_device *hdev, pm_message_t message)
+{
+       struct rmi_data *data = hid_get_drvdata(hdev);
+       int ret;
+       u8 buf[RMI_F11_CTRL_REG_COUNT];
+
+       ret = rmi_read_block(hdev, data->f11.control_base_addr, buf,
+                               RMI_F11_CTRL_REG_COUNT);
+       if (ret)
+               hid_warn(hdev, "can not read F11 control registers\n");
+       else
+               memcpy(data->f11_ctrl_regs, buf, RMI_F11_CTRL_REG_COUNT);
+
+
+       if (!device_may_wakeup(hdev->dev.parent))
+               return rmi_set_sleep_mode(hdev, RMI_SLEEP_DEEP_SLEEP);
+
+       return 0;
+}
+
 static int rmi_post_reset(struct hid_device *hdev)
 {
-       return rmi_set_mode(hdev, RMI_MODE_ATTN_REPORTS);
+       struct rmi_data *data = hid_get_drvdata(hdev);
+       int ret;
+
+       ret = rmi_reset_attn_mode(hdev);
+       if (ret) {
+               hid_err(hdev, "can not set rmi mode\n");
+               return ret;
+       }
+
+       if (data->read_f11_ctrl_regs) {
+               ret = rmi_write_block(hdev, data->f11.control_base_addr,
+                               data->f11_ctrl_regs, RMI_F11_CTRL_REG_COUNT);
+               if (ret)
+                       hid_warn(hdev,
+                               "can not write F11 control registers after reset\n");
+       }
+
+       if (!device_may_wakeup(hdev->dev.parent)) {
+               ret = rmi_set_sleep_mode(hdev, RMI_SLEEP_NORMAL);
+               if (ret) {
+                       hid_err(hdev, "can not write sleep mode\n");
+                       return ret;
+               }
+       }
+
+       return ret;
 }
 
 static int rmi_post_resume(struct hid_device *hdev)
 {
-       return rmi_set_mode(hdev, RMI_MODE_ATTN_REPORTS);
+       return rmi_reset_attn_mode(hdev);
 }
 #endif /* CONFIG_PM */
 
@@ -595,6 +696,7 @@ static void rmi_register_function(struct rmi_data *data,
                f->interrupt_count = pdt_entry->interrupt_source_count;
                f->irq_mask = rmi_gen_mask(f->interrupt_base,
                                                f->interrupt_count);
+               data->interrupt_enable_mask |= f->irq_mask;
        }
 }
 
@@ -732,6 +834,35 @@ static int rmi_populate_f01(struct hid_device *hdev)
                data->firmware_id += info[2] * 65536;
        }
 
+       ret = rmi_read_block(hdev, data->f01.control_base_addr, info,
+                               2);
+
+       if (ret) {
+               hid_err(hdev, "can not read f01 ctrl registers\n");
+               return ret;
+       }
+
+       data->f01_ctrl0 = info[0];
+
+       if (!info[1]) {
+               /*
+                * Do to a firmware bug in some touchpads the F01 interrupt
+                * enable control register will be cleared on reset.
+                * This will stop the touchpad from reporting data, so
+                * if F01 CTRL1 is 0 then we need to explicitly enable
+                * interrupts for the functions we want data for.
+                */
+               data->restore_interrupt_mask = true;
+
+               ret = rmi_write(hdev, data->f01.control_base_addr + 1,
+                               &data->interrupt_enable_mask);
+               if (ret) {
+                       hid_err(hdev, "can not write to control reg 1: %d.\n",
+                               ret);
+                       return ret;
+               }
+       }
+
        return 0;
 }
 
@@ -904,24 +1035,23 @@ static int rmi_populate_f11(struct hid_device *hdev)
        if (has_data40)
                data->f11.report_size += data->max_fingers * 2;
 
-       /*
-        * retrieve the ctrl registers
-        * the ctrl register has a size of 20 but a fw bug split it into 16 + 4,
-        * and there is no way to know if the first 20 bytes are here or not.
-        * We use only the first 12 bytes, so get only them.
-        */
-       ret = rmi_read_block(hdev, data->f11.control_base_addr, buf, 12);
+       ret = rmi_read_block(hdev, data->f11.control_base_addr,
+                       data->f11_ctrl_regs, RMI_F11_CTRL_REG_COUNT);
        if (ret) {
                hid_err(hdev, "can not read ctrl block of size 11: %d.\n", ret);
                return ret;
        }
 
-       data->max_x = buf[6] | (buf[7] << 8);
-       data->max_y = buf[8] | (buf[9] << 8);
+       /* data->f11_ctrl_regs now contains valid register data */
+       data->read_f11_ctrl_regs = true;
+
+       data->max_x = data->f11_ctrl_regs[6] | (data->f11_ctrl_regs[7] << 8);
+       data->max_y = data->f11_ctrl_regs[8] | (data->f11_ctrl_regs[9] << 8);
 
        if (has_dribble) {
-               buf[0] = buf[0] & ~BIT(6);
-               ret = rmi_write(hdev, data->f11.control_base_addr, buf);
+               data->f11_ctrl_regs[0] = data->f11_ctrl_regs[0] & ~BIT(6);
+               ret = rmi_write(hdev, data->f11.control_base_addr,
+                               data->f11_ctrl_regs);
                if (ret) {
                        hid_err(hdev, "can not write to control reg 0: %d.\n",
                                ret);
@@ -930,9 +1060,9 @@ static int rmi_populate_f11(struct hid_device *hdev)
        }
 
        if (has_palm_detect) {
-               buf[11] = buf[11] & ~BIT(0);
+               data->f11_ctrl_regs[11] = data->f11_ctrl_regs[11] & ~BIT(0);
                ret = rmi_write(hdev, data->f11.control_base_addr + 11,
-                               &buf[11]);
+                               &data->f11_ctrl_regs[11]);
                if (ret) {
                        hid_err(hdev, "can not write to control reg 11: %d.\n",
                                ret);
@@ -1273,6 +1403,7 @@ static struct hid_driver rmi_driver = {
        .input_mapping          = rmi_input_mapping,
        .input_configured       = rmi_input_configured,
 #ifdef CONFIG_PM
+       .suspend                = rmi_suspend,
        .resume                 = rmi_post_resume,
        .reset_resume           = rmi_post_reset,
 #endif
index 090a1ba0abb6fb1f6c937a7190980bbd8f318a0c..a76eb2a0a987b33da708dbbaf581ef914901ffbd 100644 (file)
@@ -774,6 +774,9 @@ static const struct hid_device_id sensor_hub_devices[] = {
        { HID_DEVICE(HID_BUS_ANY, HID_GROUP_SENSOR_HUB, USB_VENDOR_ID_TEXAS_INSTRUMENTS,
                        USB_DEVICE_ID_TEXAS_INSTRUMENTS_LENOVO_YOGA),
                        .driver_data = HID_SENSOR_HUB_ENUM_QUIRK},
+       { HID_DEVICE(HID_BUS_ANY, HID_GROUP_SENSOR_HUB, USB_VENDOR_ID_ITE,
+                       USB_DEVICE_ID_ITE_LENOVO_YOGA),
+                       .driver_data = HID_SENSOR_HUB_ENUM_QUIRK},
        { HID_DEVICE(HID_BUS_ANY, HID_GROUP_SENSOR_HUB, HID_ANY_ID,
                     HID_ANY_ID) },
        { }
index ed2f008f840377c394f1a910c331ea5f472a231e..661f94f8ab8b0b0aafc9dace1073b08849e23784 100644 (file)
@@ -296,7 +296,14 @@ static __u8 navigation_rdesc[] = {
        0x09, 0x01,         /*          Usage (Pointer),            */
        0x81, 0x02,         /*          Input (Variable),           */
        0x06, 0x00, 0xFF,   /*          Usage Page (FF00h),         */
-       0x95, 0x20,         /*          Report Count (26),          */
+       0x95, 0x01,         /*          Report Count (1),           */
+       0x81, 0x02,         /*          Input (Variable),           */
+       0x05, 0x01,         /*          Usage Page (Desktop),       */
+       0x95, 0x01,         /*          Report Count (1),           */
+       0x09, 0x01,         /*          Usage (Pointer),            */
+       0x81, 0x02,         /*          Input (Variable),           */
+       0x06, 0x00, 0xFF,   /*          Usage Page (FF00h),         */
+       0x95, 0x1E,         /*          Report Count (24),          */
        0x81, 0x02,         /*          Input (Variable),           */
        0x75, 0x08,         /*          Report Size (8),            */
        0x95, 0x30,         /*          Report Count (48),          */
@@ -1270,6 +1277,17 @@ static int sony_raw_event(struct hid_device *hdev, struct hid_report *report,
         * has to be BYTE_SWAPPED before passing up to joystick interface
         */
        if ((sc->quirks & SIXAXIS_CONTROLLER) && rd[0] == 0x01 && size == 49) {
+               /*
+                * When connected via Bluetooth the Sixaxis occasionally sends
+                * a report with the second byte 0xff and the rest zeroed.
+                *
+                * This report does not reflect the actual state of the
+                * controller must be ignored to avoid generating false input
+                * events.
+                */
+               if (rd[1] == 0xff)
+                       return -EINVAL;
+
                swap(rd[41], rd[42]);
                swap(rd[43], rd[44]);
                swap(rd[45], rd[46]);
@@ -1836,7 +1854,7 @@ static void dualshock4_state_worker(struct work_struct *work)
        } else {
                memset(buf, 0, DS4_REPORT_0x11_SIZE);
                buf[0] = 0x11;
-               buf[1] = 0xB0;
+               buf[1] = 0x80;
                buf[3] = 0x0F;
                offset = 6;
        }
index f77469d4edfb0ecb1709032361913d4a92ceb919..2871f3c81a4cceb521f4c26aac4da75466f5db6f 100644 (file)
@@ -149,6 +149,8 @@ struct i2c_hid {
        int                     irq;
 
        struct i2c_hid_platform_data pdata;
+
+       bool                    irq_wake_enabled;
 };
 
 static int __i2c_hid_command(struct i2c_client *client,
@@ -1091,14 +1093,21 @@ static int i2c_hid_suspend(struct device *dev)
        struct i2c_hid *ihid = i2c_get_clientdata(client);
        struct hid_device *hid = ihid->hid;
        int ret = 0;
-
-       disable_irq(ihid->irq);
-       if (device_may_wakeup(&client->dev))
-               enable_irq_wake(ihid->irq);
+       int wake_status;
 
        if (hid->driver && hid->driver->suspend)
                ret = hid->driver->suspend(hid, PMSG_SUSPEND);
 
+       disable_irq(ihid->irq);
+       if (device_may_wakeup(&client->dev)) {
+               wake_status = enable_irq_wake(ihid->irq);
+               if (!wake_status)
+                       ihid->irq_wake_enabled = true;
+               else
+                       hid_warn(hid, "Failed to enable irq wake: %d\n",
+                               wake_status);
+       }
+
        /* Save some power */
        i2c_hid_set_power(client, I2C_HID_PWR_SLEEP);
 
@@ -1111,14 +1120,21 @@ static int i2c_hid_resume(struct device *dev)
        struct i2c_client *client = to_i2c_client(dev);
        struct i2c_hid *ihid = i2c_get_clientdata(client);
        struct hid_device *hid = ihid->hid;
+       int wake_status;
 
        enable_irq(ihid->irq);
        ret = i2c_hid_hwreset(client);
        if (ret)
                return ret;
 
-       if (device_may_wakeup(&client->dev))
-               disable_irq_wake(ihid->irq);
+       if (device_may_wakeup(&client->dev) && ihid->irq_wake_enabled) {
+               wake_status = disable_irq_wake(ihid->irq);
+               if (!wake_status)
+                       ihid->irq_wake_enabled = false;
+               else
+                       hid_warn(hid, "Failed to disable irq wake: %d\n",
+                               wake_status);
+       }
 
        if (hid->driver && hid->driver->reset_resume) {
                ret = hid->driver->reset_resume(hid);
index a533787a6d857f815bcf816aefcde3c6d7ad7a4f..4681a65a4579cf1b9fbcae830f583e4e9c3d4d73 100644 (file)
@@ -113,7 +113,7 @@ struct wacom {
        struct mutex lock;
        struct work_struct work;
        struct wacom_led {
-               u8 select[2]; /* status led selector (0..3) */
+               u8 select[5]; /* status led selector (0..3) */
                u8 llv;       /* status led brightness no button (1..127) */
                u8 hlv;       /* status led brightness button pressed (1..127) */
                u8 img_lum;   /* OLED matrix display brightness */
@@ -123,6 +123,8 @@ struct wacom {
        struct power_supply *ac;
        struct power_supply_desc battery_desc;
        struct power_supply_desc ac_desc;
+       struct kobject *remote_dir;
+       struct attribute_group remote_group[5];
 };
 
 static inline void wacom_schedule_work(struct wacom_wac *wacom_wac)
@@ -147,4 +149,7 @@ int wacom_wac_event(struct hid_device *hdev, struct hid_field *field,
                struct hid_usage *usage, __s32 value);
 void wacom_wac_report(struct hid_device *hdev, struct hid_report *report);
 void wacom_battery_work(struct work_struct *work);
+int wacom_remote_create_attr_group(struct wacom *wacom, __u32 serial,
+                                  int index);
+void wacom_remote_destroy_attr_group(struct wacom *wacom, __u32 serial);
 #endif
index 5cdb044720231e0e32a1f2eb79cacfaefe95c4ce..9a4912c1828dad3109b9473305670c79fc20d022 100644 (file)
 #define WAC_CMD_ICON_XFER      0x23
 #define WAC_CMD_ICON_BT_XFER   0x26
 #define WAC_CMD_RETRIES                10
+#define WAC_CMD_DELETE_PAIRING 0x20
+#define WAC_CMD_UNPAIR_ALL     0xFF
+#define WAC_REMOTE_SERIAL_MAX_STRLEN   9
 
 #define DEV_ATTR_RW_PERM (S_IRUGO | S_IWUSR | S_IWGRP)
 #define DEV_ATTR_WO_PERM (S_IWUSR | S_IWGRP)
+#define DEV_ATTR_RO_PERM (S_IRUSR | S_IRGRP)
 
 static int wacom_get_report(struct hid_device *hdev, u8 type, u8 *buf,
                            size_t size, unsigned int retries)
@@ -453,12 +457,11 @@ static void wacom_retrieve_hid_descriptor(struct hid_device *hdev,
         * interface number.
         */
        if (features->type == WIRELESS) {
-               if (intf->cur_altsetting->desc.bInterfaceNumber == 0) {
+               if (intf->cur_altsetting->desc.bInterfaceNumber == 0)
+                       features->device_type = WACOM_DEVICETYPE_WL_MONITOR;
+               else
                        features->device_type = WACOM_DEVICETYPE_NONE;
-               } else if (intf->cur_altsetting->desc.bInterfaceNumber == 2) {
-                       features->device_type |= WACOM_DEVICETYPE_TOUCH;
-                       features->pktlen = WACOM_PKGLEN_BBTOUCH3;
-               }
+               return;
        }
 
        wacom_parse_hid(hdev, features);
@@ -1120,6 +1123,189 @@ static ssize_t wacom_store_speed(struct device *dev,
 static DEVICE_ATTR(speed, DEV_ATTR_RW_PERM,
                wacom_show_speed, wacom_store_speed);
 
+
+static ssize_t wacom_show_remote_mode(struct kobject *kobj,
+                                     struct kobj_attribute *kattr,
+                                     char *buf, int index)
+{
+       struct device *dev = container_of(kobj->parent, struct device, kobj);
+       struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+       struct wacom *wacom = hid_get_drvdata(hdev);
+       u8 mode;
+
+       mode = wacom->led.select[index];
+       if (mode >= 0 && mode < 3)
+               return snprintf(buf, PAGE_SIZE, "%d\n", mode);
+       else
+               return snprintf(buf, PAGE_SIZE, "%d\n", -1);
+}
+
+#define DEVICE_EKR_ATTR_GROUP(SET_ID)                                  \
+static ssize_t wacom_show_remote##SET_ID##_mode(struct kobject *kobj,  \
+                              struct kobj_attribute *kattr, char *buf) \
+{                                                                      \
+       return wacom_show_remote_mode(kobj, kattr, buf, SET_ID);        \
+}                                                                      \
+static struct kobj_attribute remote##SET_ID##_mode_attr = {            \
+       .attr = {.name = "remote_mode",                                 \
+               .mode = DEV_ATTR_RO_PERM},                              \
+       .show = wacom_show_remote##SET_ID##_mode,                       \
+};                                                                     \
+static struct attribute *remote##SET_ID##_serial_attrs[] = {           \
+       &remote##SET_ID##_mode_attr.attr,                               \
+       NULL                                                            \
+};                                                                     \
+static struct attribute_group remote##SET_ID##_serial_group = {                \
+       .name = NULL,                                                   \
+       .attrs = remote##SET_ID##_serial_attrs,                         \
+}
+
+DEVICE_EKR_ATTR_GROUP(0);
+DEVICE_EKR_ATTR_GROUP(1);
+DEVICE_EKR_ATTR_GROUP(2);
+DEVICE_EKR_ATTR_GROUP(3);
+DEVICE_EKR_ATTR_GROUP(4);
+
+int wacom_remote_create_attr_group(struct wacom *wacom, __u32 serial, int index)
+{
+       int error = 0;
+       char *buf;
+       struct wacom_wac *wacom_wac = &wacom->wacom_wac;
+
+       wacom_wac->serial[index] = serial;
+
+       buf = kzalloc(WAC_REMOTE_SERIAL_MAX_STRLEN, GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+       snprintf(buf, WAC_REMOTE_SERIAL_MAX_STRLEN, "%d", serial);
+       wacom->remote_group[index].name = buf;
+
+       error = sysfs_create_group(wacom->remote_dir,
+                                  &wacom->remote_group[index]);
+       if (error) {
+               hid_err(wacom->hdev,
+                       "cannot create sysfs group err: %d\n", error);
+               kobject_put(wacom->remote_dir);
+               return error;
+       }
+
+       return 0;
+}
+
+void wacom_remote_destroy_attr_group(struct wacom *wacom, __u32 serial)
+{
+       struct wacom_wac *wacom_wac = &wacom->wacom_wac;
+       int i;
+
+       if (!serial)
+               return;
+
+       for (i = 0; i < WACOM_MAX_REMOTES; i++) {
+               if (wacom_wac->serial[i] == serial) {
+                       wacom_wac->serial[i] = 0;
+                       wacom->led.select[i] = WACOM_STATUS_UNKNOWN;
+                       if (wacom->remote_group[i].name) {
+                               sysfs_remove_group(wacom->remote_dir,
+                                                  &wacom->remote_group[i]);
+                               kfree(wacom->remote_group[i].name);
+                               wacom->remote_group[i].name = NULL;
+                       }
+               }
+       }
+}
+
+static int wacom_cmd_unpair_remote(struct wacom *wacom, unsigned char selector)
+{
+       const size_t buf_size = 2;
+       unsigned char *buf;
+       int retval;
+
+       buf = kzalloc(buf_size, GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+
+       buf[0] = WAC_CMD_DELETE_PAIRING;
+       buf[1] = selector;
+
+       retval = wacom_set_report(wacom->hdev, HID_OUTPUT_REPORT, buf,
+                                 buf_size, WAC_CMD_RETRIES);
+       kfree(buf);
+
+       return retval;
+}
+
+static ssize_t wacom_store_unpair_remote(struct kobject *kobj,
+                                        struct kobj_attribute *attr,
+                                        const char *buf, size_t count)
+{
+       unsigned char selector = 0;
+       struct device *dev = container_of(kobj->parent, struct device, kobj);
+       struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+       struct wacom *wacom = hid_get_drvdata(hdev);
+       int err;
+
+       if (!strncmp(buf, "*\n", 2)) {
+               selector = WAC_CMD_UNPAIR_ALL;
+       } else {
+               hid_info(wacom->hdev, "remote: unrecognized unpair code: %s\n",
+                        buf);
+               return -1;
+       }
+
+       mutex_lock(&wacom->lock);
+
+       err = wacom_cmd_unpair_remote(wacom, selector);
+       mutex_unlock(&wacom->lock);
+
+       return err < 0 ? err : count;
+}
+
+static struct kobj_attribute unpair_remote_attr = {
+       .attr = {.name = "unpair_remote", .mode = 0200},
+       .store = wacom_store_unpair_remote,
+};
+
+static const struct attribute *remote_unpair_attrs[] = {
+       &unpair_remote_attr.attr,
+       NULL
+};
+
+static int wacom_initialize_remote(struct wacom *wacom)
+{
+       int error = 0;
+       struct wacom_wac *wacom_wac = &(wacom->wacom_wac);
+       int i;
+
+       if (wacom->wacom_wac.features.type != REMOTE)
+               return 0;
+
+       wacom->remote_group[0] = remote0_serial_group;
+       wacom->remote_group[1] = remote1_serial_group;
+       wacom->remote_group[2] = remote2_serial_group;
+       wacom->remote_group[3] = remote3_serial_group;
+       wacom->remote_group[4] = remote4_serial_group;
+
+       wacom->remote_dir = kobject_create_and_add("wacom_remote",
+                                                  &wacom->hdev->dev.kobj);
+       if (!wacom->remote_dir)
+               return -ENOMEM;
+
+       error = sysfs_create_files(wacom->remote_dir, remote_unpair_attrs);
+
+       if (error) {
+               hid_err(wacom->hdev,
+                       "cannot create sysfs group err: %d\n", error);
+               return error;
+       }
+
+       for (i = 0; i < WACOM_MAX_REMOTES; i++) {
+               wacom->led.select[i] = WACOM_STATUS_UNKNOWN;
+               wacom_wac->serial[i] = 0;
+       }
+
+       return 0;
+}
+
 static struct input_dev *wacom_allocate_input(struct wacom *wacom)
 {
        struct input_dev *input_dev;
@@ -1130,7 +1316,7 @@ static struct input_dev *wacom_allocate_input(struct wacom *wacom)
        if (!input_dev)
                return NULL;
 
-       input_dev->name = wacom_wac->pen_name;
+       input_dev->name = wacom_wac->features.name;
        input_dev->phys = hdev->phys;
        input_dev->dev.parent = &hdev->dev;
        input_dev->open = wacom_open;
@@ -1145,40 +1331,6 @@ static struct input_dev *wacom_allocate_input(struct wacom *wacom)
        return input_dev;
 }
 
-static void wacom_free_inputs(struct wacom *wacom)
-{
-       struct wacom_wac *wacom_wac = &(wacom->wacom_wac);
-
-       input_free_device(wacom_wac->pen_input);
-       input_free_device(wacom_wac->touch_input);
-       input_free_device(wacom_wac->pad_input);
-       wacom_wac->pen_input = NULL;
-       wacom_wac->touch_input = NULL;
-       wacom_wac->pad_input = NULL;
-}
-
-static int wacom_allocate_inputs(struct wacom *wacom)
-{
-       struct input_dev *pen_input_dev, *touch_input_dev, *pad_input_dev;
-       struct wacom_wac *wacom_wac = &(wacom->wacom_wac);
-
-       pen_input_dev = wacom_allocate_input(wacom);
-       touch_input_dev = wacom_allocate_input(wacom);
-       pad_input_dev = wacom_allocate_input(wacom);
-       if (!pen_input_dev || !touch_input_dev || !pad_input_dev) {
-               wacom_free_inputs(wacom);
-               return -ENOMEM;
-       }
-
-       wacom_wac->pen_input = pen_input_dev;
-       wacom_wac->touch_input = touch_input_dev;
-       wacom_wac->touch_input->name = wacom_wac->touch_name;
-       wacom_wac->pad_input = pad_input_dev;
-       wacom_wac->pad_input->name = wacom_wac->pad_name;
-
-       return 0;
-}
-
 static void wacom_clean_inputs(struct wacom *wacom)
 {
        if (wacom->wacom_wac.pen_input) {
@@ -1199,12 +1351,33 @@ static void wacom_clean_inputs(struct wacom *wacom)
                else
                        input_free_device(wacom->wacom_wac.pad_input);
        }
+       if (wacom->remote_dir)
+               kobject_put(wacom->remote_dir);
        wacom->wacom_wac.pen_input = NULL;
        wacom->wacom_wac.touch_input = NULL;
        wacom->wacom_wac.pad_input = NULL;
        wacom_destroy_leds(wacom);
 }
 
+static int wacom_allocate_inputs(struct wacom *wacom)
+{
+       struct wacom_wac *wacom_wac = &(wacom->wacom_wac);
+
+       wacom_wac->pen_input = wacom_allocate_input(wacom);
+       wacom_wac->touch_input = wacom_allocate_input(wacom);
+       wacom_wac->pad_input = wacom_allocate_input(wacom);
+       if (!wacom_wac->pen_input || !wacom_wac->touch_input || !wacom_wac->pad_input) {
+               wacom_clean_inputs(wacom);
+               return -ENOMEM;
+       }
+
+       wacom_wac->pen_input->name = wacom_wac->pen_name;
+       wacom_wac->touch_input->name = wacom_wac->touch_name;
+       wacom_wac->pad_input->name = wacom_wac->pad_name;
+
+       return 0;
+}
+
 static int wacom_register_inputs(struct wacom *wacom)
 {
        struct input_dev *pen_input_dev, *touch_input_dev, *pad_input_dev;
@@ -1259,10 +1432,16 @@ static int wacom_register_inputs(struct wacom *wacom)
                error = wacom_initialize_leds(wacom);
                if (error)
                        goto fail_leds;
+
+               error = wacom_initialize_remote(wacom);
+               if (error)
+                       goto fail_remote;
        }
 
        return 0;
 
+fail_remote:
+       wacom_destroy_leds(wacom);
 fail_leds:
        input_unregister_device(pad_input_dev);
        pad_input_dev = NULL;
@@ -1553,11 +1732,9 @@ static int wacom_probe(struct hid_device *hdev,
        mutex_init(&wacom->lock);
        INIT_WORK(&wacom->work, wacom_wireless_work);
 
-       if (!(features->quirks & WACOM_QUIRK_NO_INPUT)) {
-               error = wacom_allocate_inputs(wacom);
-               if (error)
-                       goto fail_allocate_inputs;
-       }
+       error = wacom_allocate_inputs(wacom);
+       if (error)
+               goto fail_allocate_inputs;
 
        /*
         * Bamboo Pad has a generic hid handling for the Pen, and we switch it
@@ -1603,18 +1780,16 @@ static int wacom_probe(struct hid_device *hdev,
        if (error)
                goto fail_shared_data;
 
-       if (!(features->quirks & WACOM_QUIRK_MONITOR) &&
+       if (!(features->device_type & WACOM_DEVICETYPE_WL_MONITOR) &&
             (features->quirks & WACOM_QUIRK_BATTERY)) {
                error = wacom_initialize_battery(wacom);
                if (error)
                        goto fail_battery;
        }
 
-       if (!(features->quirks & WACOM_QUIRK_NO_INPUT)) {
-               error = wacom_register_inputs(wacom);
-               if (error)
-                       goto fail_register_inputs;
-       }
+       error = wacom_register_inputs(wacom);
+       if (error)
+               goto fail_register_inputs;
 
        if (hdev->bus == BUS_BLUETOOTH) {
                error = device_create_file(&hdev->dev, &dev_attr_speed);
@@ -1637,7 +1812,7 @@ static int wacom_probe(struct hid_device *hdev,
        /* Note that if query fails it is not a hard failure */
        wacom_query_tablet_data(hdev, features);
 
-       if (features->quirks & WACOM_QUIRK_MONITOR)
+       if (features->device_type & WACOM_DEVICETYPE_WL_MONITOR)
                error = hid_hw_open(hdev);
 
        if (wacom_wac->features.type == INTUOSHT && 
@@ -1711,7 +1886,6 @@ static struct hid_driver wacom_driver = {
        .id_table =     wacom_ids,
        .probe =        wacom_probe,
        .remove =       wacom_remove,
-       .event =        wacom_wac_event,
        .report =       wacom_wac_report,
 #ifdef CONFIG_PM
        .resume =       wacom_resume,
index 0d244239e55def103f786254f3f617a84b2f0ba2..0215ab62bb93f1b3669ed02ba1087ab43ffa6456 100644 (file)
@@ -125,61 +125,47 @@ static int wacom_pl_irq(struct wacom_wac *wacom)
 
        prox = data[1] & 0x40;
 
-       if (prox) {
-               wacom->id[0] = ERASER_DEVICE_ID;
-               pressure = (signed char)((data[7] << 1) | ((data[4] >> 2) & 1));
-               if (features->pressure_max > 255)
-                       pressure = (pressure << 1) | ((data[4] >> 6) & 1);
-               pressure += (features->pressure_max + 1) / 2;
-
-               /*
-                * if going from out of proximity into proximity select between the eraser
-                * and the pen based on the state of the stylus2 button, choose eraser if
-                * pressed else choose pen. if not a proximity change from out to in, send
-                * an out of proximity for previous tool then a in for new tool.
-                */
-               if (!wacom->tool[0]) {
-                       /* Eraser bit set for DTF */
-                       if (data[1] & 0x10)
-                               wacom->tool[1] = BTN_TOOL_RUBBER;
-                       else
-                               /* Going into proximity select tool */
-                               wacom->tool[1] = (data[4] & 0x20) ? BTN_TOOL_RUBBER : BTN_TOOL_PEN;
-               } else {
-                       /* was entered with stylus2 pressed */
-                       if (wacom->tool[1] == BTN_TOOL_RUBBER && !(data[4] & 0x20)) {
-                               /* report out proximity for previous tool */
-                               input_report_key(input, wacom->tool[1], 0);
-                               input_sync(input);
-                               wacom->tool[1] = BTN_TOOL_PEN;
-                               return 0;
-                       }
+       if (!wacom->id[0]) {
+               if ((data[0] & 0x10) || (data[4] & 0x20)) {
+                       wacom->tool[0] = BTN_TOOL_RUBBER;
+                       wacom->id[0] = ERASER_DEVICE_ID;
                }
-               if (wacom->tool[1] != BTN_TOOL_RUBBER) {
-                       /* Unknown tool selected default to pen tool */
-                       wacom->tool[1] = BTN_TOOL_PEN;
+               else {
+                       wacom->tool[0] = BTN_TOOL_PEN;
                        wacom->id[0] = STYLUS_DEVICE_ID;
                }
-               input_report_key(input, wacom->tool[1], prox); /* report in proximity for tool */
-               input_report_abs(input, ABS_MISC, wacom->id[0]); /* report tool id */
-               input_report_abs(input, ABS_X, data[3] | (data[2] << 7) | ((data[1] & 0x03) << 14));
-               input_report_abs(input, ABS_Y, data[6] | (data[5] << 7) | ((data[4] & 0x03) << 14));
-               input_report_abs(input, ABS_PRESSURE, pressure);
+       }
 
-               input_report_key(input, BTN_TOUCH, data[4] & 0x08);
-               input_report_key(input, BTN_STYLUS, data[4] & 0x10);
-               /* Only allow the stylus2 button to be reported for the pen tool. */
-               input_report_key(input, BTN_STYLUS2, (wacom->tool[1] == BTN_TOOL_PEN) && (data[4] & 0x20));
-       } else {
-               /* report proximity-out of a (valid) tool */
-               if (wacom->tool[1] != BTN_TOOL_RUBBER) {
-                       /* Unknown tool selected default to pen tool */
-                       wacom->tool[1] = BTN_TOOL_PEN;
-               }
-               input_report_key(input, wacom->tool[1], prox);
+       /* If the eraser is in prox, STYLUS2 is always set. If we
+        * mis-detected the type and notice that STYLUS2 isn't set
+        * then force the eraser out of prox and let the pen in.
+        */
+       if (wacom->tool[0] == BTN_TOOL_RUBBER && !(data[4] & 0x20)) {
+               input_report_key(input, BTN_TOOL_RUBBER, 0);
+               input_report_abs(input, ABS_MISC, 0);
+               input_sync(input);
+               wacom->tool[0] = BTN_TOOL_PEN;
+               wacom->id[0] = STYLUS_DEVICE_ID;
        }
 
-       wacom->tool[0] = prox; /* Save proximity state */
+       pressure = (signed char)((data[7] << 1) | ((data[4] >> 2) & 1));
+       if (features->pressure_max > 255)
+               pressure = (pressure << 1) | ((data[4] >> 6) & 1);
+       pressure += (features->pressure_max + 1) / 2;
+
+       input_report_abs(input, ABS_X, data[3] | (data[2] << 7) | ((data[1] & 0x03) << 14));
+       input_report_abs(input, ABS_Y, data[6] | (data[5] << 7) | ((data[4] & 0x03) << 14));
+       input_report_abs(input, ABS_PRESSURE, pressure);
+
+       input_report_key(input, BTN_TOUCH, data[4] & 0x08);
+       input_report_key(input, BTN_STYLUS, data[4] & 0x10);
+       /* Only allow the stylus2 button to be reported for the pen tool. */
+       input_report_key(input, BTN_STYLUS2, (wacom->tool[0] == BTN_TOOL_PEN) && (data[4] & 0x20));
+
+       if (!prox)
+               wacom->id[0] = 0;
+       input_report_key(input, wacom->tool[0], prox);
+       input_report_abs(input, ABS_MISC, wacom->id[0]);
        return 1;
 }
 
@@ -645,6 +631,130 @@ static int wacom_intuos_inout(struct wacom_wac *wacom)
        return 0;
 }
 
+static int wacom_remote_irq(struct wacom_wac *wacom_wac, size_t len)
+{
+       unsigned char *data = wacom_wac->data;
+       struct input_dev *input = wacom_wac->pad_input;
+       struct wacom *wacom = container_of(wacom_wac, struct wacom, wacom_wac);
+       struct wacom_features *features = &wacom_wac->features;
+       int bat_charging, bat_percent, touch_ring_mode;
+       __u32 serial;
+       int i;
+
+       if (data[0] != WACOM_REPORT_REMOTE) {
+               dev_dbg(input->dev.parent,
+                       "%s: received unknown report #%d", __func__, data[0]);
+               return 0;
+       }
+
+       serial = data[3] + (data[4] << 8) + (data[5] << 16);
+       wacom_wac->id[0] = PAD_DEVICE_ID;
+
+       input_report_key(input, BTN_0, (data[9] & 0x01));
+       input_report_key(input, BTN_1, (data[9] & 0x02));
+       input_report_key(input, BTN_2, (data[9] & 0x04));
+       input_report_key(input, BTN_3, (data[9] & 0x08));
+       input_report_key(input, BTN_4, (data[9] & 0x10));
+       input_report_key(input, BTN_5, (data[9] & 0x20));
+       input_report_key(input, BTN_6, (data[9] & 0x40));
+       input_report_key(input, BTN_7, (data[9] & 0x80));
+
+       input_report_key(input, BTN_8, (data[10] & 0x01));
+       input_report_key(input, BTN_9, (data[10] & 0x02));
+       input_report_key(input, BTN_A, (data[10] & 0x04));
+       input_report_key(input, BTN_B, (data[10] & 0x08));
+       input_report_key(input, BTN_C, (data[10] & 0x10));
+       input_report_key(input, BTN_X, (data[10] & 0x20));
+       input_report_key(input, BTN_Y, (data[10] & 0x40));
+       input_report_key(input, BTN_Z, (data[10] & 0x80));
+
+       input_report_key(input, BTN_BASE, (data[11] & 0x01));
+       input_report_key(input, BTN_BASE2, (data[11] & 0x02));
+
+       if (data[12] & 0x80)
+               input_report_abs(input, ABS_WHEEL, (data[12] & 0x7f));
+       else
+               input_report_abs(input, ABS_WHEEL, 0);
+
+       bat_percent = data[7] & 0x7f;
+       bat_charging = !!(data[7] & 0x80);
+
+       if (data[9] | data[10] | (data[11] & 0x03) | data[12])
+               input_report_abs(input, ABS_MISC, PAD_DEVICE_ID);
+       else
+               input_report_abs(input, ABS_MISC, 0);
+
+       input_event(input, EV_MSC, MSC_SERIAL, serial);
+
+       /*Which mode select (LED light) is currently on?*/
+       touch_ring_mode = (data[11] & 0xC0) >> 6;
+
+       for (i = 0; i < WACOM_MAX_REMOTES; i++) {
+               if (wacom_wac->serial[i] == serial)
+                       wacom->led.select[i] = touch_ring_mode;
+       }
+
+       if (!wacom->battery &&
+           !(features->quirks & WACOM_QUIRK_BATTERY)) {
+               features->quirks |= WACOM_QUIRK_BATTERY;
+               INIT_WORK(&wacom->work, wacom_battery_work);
+               wacom_schedule_work(wacom_wac);
+       }
+
+       wacom_notify_battery(wacom_wac, bat_percent, bat_charging, 1,
+                            bat_charging);
+
+       return 1;
+}
+
+static int wacom_remote_status_irq(struct wacom_wac *wacom_wac, size_t len)
+{
+       struct wacom *wacom = container_of(wacom_wac, struct wacom, wacom_wac);
+       unsigned char *data = wacom_wac->data;
+       int i;
+
+       if (data[0] != WACOM_REPORT_DEVICE_LIST)
+               return 0;
+
+       for (i = 0; i < WACOM_MAX_REMOTES; i++) {
+               int j = i * 6;
+               int serial = (data[j+6] << 16) + (data[j+5] << 8) + data[j+4];
+               bool connected = data[j+2];
+
+               if (connected) {
+                       int k;
+
+                       if (wacom_wac->serial[i] == serial)
+                               continue;
+
+                       if (wacom_wac->serial[i]) {
+                               wacom_remote_destroy_attr_group(wacom,
+                                                       wacom_wac->serial[i]);
+                       }
+
+                       /* A remote can pair more than once with an EKR,
+                        * check to make sure this serial isn't already paired.
+                        */
+                       for (k = 0; k < WACOM_MAX_REMOTES; k++) {
+                               if (wacom_wac->serial[k] == serial)
+                                       break;
+                       }
+
+                       if (k < WACOM_MAX_REMOTES) {
+                               wacom_wac->serial[i] = serial;
+                               continue;
+                       }
+                       wacom_remote_create_attr_group(wacom, serial, i);
+
+               } else if (wacom_wac->serial[i]) {
+                       wacom_remote_destroy_attr_group(wacom,
+                                                       wacom_wac->serial[i]);
+               }
+       }
+
+       return 0;
+}
+
 static void wacom_intuos_general(struct wacom_wac *wacom)
 {
        struct wacom_features *features = &wacom->features;
@@ -1437,6 +1547,12 @@ static int wacom_wac_pen_event(struct hid_device *hdev, struct hid_field *field,
        return 0;
 }
 
+static void wacom_wac_pen_pre_report(struct hid_device *hdev,
+               struct hid_report *report)
+{
+       return;
+}
+
 static void wacom_wac_pen_report(struct hid_device *hdev,
                struct hid_report *report)
 {
@@ -1491,6 +1607,13 @@ static void wacom_wac_finger_usage_mapping(struct hid_device *hdev,
                        wacom_map_usage(input, usage, field, EV_ABS,
                                        ABS_MT_POSITION_Y, 4);
                break;
+       case HID_DG_WIDTH:
+       case HID_DG_HEIGHT:
+               features->last_slot_field = usage->hid;
+               wacom_map_usage(input, usage, field, EV_ABS, ABS_MT_TOUCH_MAJOR, 0);
+               wacom_map_usage(input, usage, field, EV_ABS, ABS_MT_TOUCH_MINOR, 0);
+               input_set_abs_params(input, ABS_MT_ORIENTATION, 0, 1, 0, 0);
+               break;
        case HID_DG_CONTACTID:
                features->last_slot_field = usage->hid;
                break;
@@ -1504,6 +1627,10 @@ static void wacom_wac_finger_usage_mapping(struct hid_device *hdev,
                features->last_slot_field = usage->hid;
                wacom_map_usage(input, usage, field, EV_KEY, BTN_TOUCH, 0);
                break;
+       case HID_DG_CONTACTCOUNT:
+               wacom_wac->hid_data.cc_index = field->index;
+               wacom_wac->hid_data.cc_value_index = usage->usage_index;
+               break;
        }
 }
 
@@ -1515,6 +1642,10 @@ static void wacom_wac_finger_slot(struct wacom_wac *wacom_wac,
        bool prox = hid_data->tipswitch &&
                    !wacom_wac->shared->stylus_in_proximity;
 
+       wacom_wac->hid_data.num_received++;
+       if (wacom_wac->hid_data.num_received > wacom_wac->hid_data.num_expected)
+               return;
+
        if (mt) {
                int slot;
 
@@ -1531,6 +1662,13 @@ static void wacom_wac_finger_slot(struct wacom_wac *wacom_wac,
                                 hid_data->x);
                input_report_abs(input, mt ? ABS_MT_POSITION_Y : ABS_Y,
                                 hid_data->y);
+
+               if (test_bit(ABS_MT_TOUCH_MAJOR, input->absbit)) {
+                       input_report_abs(input, ABS_MT_TOUCH_MAJOR, max(hid_data->width, hid_data->height));
+                       input_report_abs(input, ABS_MT_TOUCH_MINOR, min(hid_data->width, hid_data->height));
+                       if (hid_data->width != hid_data->height)
+                               input_report_abs(input, ABS_MT_ORIENTATION, hid_data->width <= hid_data->height ? 0 : 1);
+               }
        }
 }
 
@@ -1547,6 +1685,12 @@ static int wacom_wac_finger_event(struct hid_device *hdev,
        case HID_GD_Y:
                wacom_wac->hid_data.y = value;
                break;
+       case HID_DG_WIDTH:
+               wacom_wac->hid_data.width = value;
+               break;
+       case HID_DG_HEIGHT:
+               wacom_wac->hid_data.height = value;
+               break;
        case HID_DG_CONTACTID:
                wacom_wac->hid_data.id = value;
                break;
@@ -1564,6 +1708,24 @@ static int wacom_wac_finger_event(struct hid_device *hdev,
        return 0;
 }
 
+static void wacom_wac_finger_pre_report(struct hid_device *hdev,
+               struct hid_report *report)
+{
+       struct wacom *wacom = hid_get_drvdata(hdev);
+       struct wacom_wac *wacom_wac = &wacom->wacom_wac;
+       struct hid_data* hid_data = &wacom_wac->hid_data;
+
+       if (hid_data->cc_index >= 0) {
+               struct hid_field *field = report->field[hid_data->cc_index];
+               int value = field->value[hid_data->cc_value_index];
+               if (value)
+                       hid_data->num_expected = value;
+       }
+       else {
+               hid_data->num_expected = wacom_wac->features.touch_max;
+       }
+}
+
 static void wacom_wac_finger_report(struct hid_device *hdev,
                struct hid_report *report)
 {
@@ -1572,10 +1734,18 @@ static void wacom_wac_finger_report(struct hid_device *hdev,
        struct input_dev *input = wacom_wac->touch_input;
        unsigned touch_max = wacom_wac->features.touch_max;
 
+       /* If more packets of data are expected, give us a chance to
+        * process them rather than immediately syncing a partial
+        * update.
+        */
+       if (wacom_wac->hid_data.num_received < wacom_wac->hid_data.num_expected)
+               return;
+
        if (touch_max > 1)
                input_mt_sync_frame(input);
 
        input_sync(input);
+       wacom_wac->hid_data.num_received = 0;
 
        /* keep touch state for pen event */
        wacom_wac->shared->touch_down = wacom_wac_finger_count_touches(wacom_wac);
@@ -1615,6 +1785,25 @@ int wacom_wac_event(struct hid_device *hdev, struct hid_field *field,
        return 0;
 }
 
+static void wacom_report_events(struct hid_device *hdev, struct hid_report *report)
+{
+       int r;
+
+       for (r = 0; r < report->maxfield; r++) {
+               struct hid_field *field;
+               unsigned count, n;
+
+               field = report->field[r];
+               count = field->report_count;
+
+               if (!(HID_MAIN_ITEM_VARIABLE & field->flags))
+                       continue;
+
+               for (n = 0; n < count; n++)
+                       wacom_wac_event(hdev, field, &field->usage[n], field->value[n]);
+       }
+}
+
 void wacom_wac_report(struct hid_device *hdev, struct hid_report *report)
 {
        struct wacom *wacom = hid_get_drvdata(hdev);
@@ -1624,6 +1813,14 @@ void wacom_wac_report(struct hid_device *hdev, struct hid_report *report)
        if (wacom_wac->features.type != HID_GENERIC)
                return;
 
+       if (WACOM_PEN_FIELD(field))
+               wacom_wac_pen_pre_report(hdev, report);
+
+       if (WACOM_FINGER_FIELD(field))
+               wacom_wac_finger_pre_report(hdev, report);
+
+       wacom_report_events(hdev, report);
+
        if (WACOM_PEN_FIELD(field))
                return wacom_wac_pen_report(hdev, report);
 
@@ -1699,7 +1896,7 @@ static void wacom_bpt3_touch_msg(struct wacom_wac *wacom, unsigned char *data)
                int y = (data[3] << 4) | (data[4] & 0x0f);
                int width, height;
 
-               if (features->type >= INTUOSPS && features->type <= INTUOSPL) {
+               if (features->type >= INTUOSPS && features->type <= INTUOSHT) {
                        width  = data[5] * 100;
                        height = data[6] * 100;
                } else {
@@ -2118,6 +2315,13 @@ void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t len)
                sync = wacom_wireless_irq(wacom_wac, len);
                break;
 
+       case REMOTE:
+               if (wacom_wac->data[0] == WACOM_REPORT_DEVICE_LIST)
+                       sync = wacom_remote_status_irq(wacom_wac, len);
+               else
+                       sync = wacom_remote_irq(wacom_wac, len);
+               break;
+
        default:
                sync = false;
                break;
@@ -2223,10 +2427,13 @@ void wacom_setup_device_quirks(struct wacom *wacom)
         * 0, whose HID descriptor has an application usage of 0xFF0D
         * (i.e., WACOM_VENDORDEFINED_PEN). We route pen packets back
         * out through the HID_GENERIC device created for interface 1,
-        * so rewrite this one to be of type BTN_TOOL_FINGER.
+        * so rewrite this one to be of type WACOM_DEVICETYPE_TOUCH.
         */
        if (features->type == BAMBOO_PAD)
-               features->device_type |= WACOM_DEVICETYPE_TOUCH;
+               features->device_type = WACOM_DEVICETYPE_TOUCH;
+
+       if (features->type == REMOTE)
+               features->device_type = WACOM_DEVICETYPE_PAD;
 
        if (wacom->hdev->bus == BUS_BLUETOOTH)
                features->quirks |= WACOM_QUIRK_BATTERY;
@@ -2242,13 +2449,7 @@ void wacom_setup_device_quirks(struct wacom *wacom)
        }
 
        if (features->type == WIRELESS) {
-
-               /* monitor never has input and pen/touch have delayed create */
-               features->quirks |= WACOM_QUIRK_NO_INPUT;
-
-               /* must be monitor interface if no device_type set */
-               if (features->device_type == WACOM_DEVICETYPE_NONE) {
-                       features->quirks |= WACOM_QUIRK_MONITOR;
+               if (features->device_type == WACOM_DEVICETYPE_WL_MONITOR) {
                        features->quirks |= WACOM_QUIRK_BATTERY;
                }
        }
@@ -2513,11 +2714,23 @@ int wacom_setup_touch_input_capabilities(struct input_dev *input_dev,
        return 0;
 }
 
+static void wacom_setup_numbered_buttons(struct input_dev *input_dev,
+                               int button_count)
+{
+       int i;
+
+       for (i = 0; i < button_count && i < 10; i++)
+               __set_bit(BTN_0 + i, input_dev->keybit);
+       for (i = 10; i < button_count && i < 16; i++)
+               __set_bit(BTN_A + (i-10), input_dev->keybit);
+       for (i = 16; i < button_count && i < 18; i++)
+               __set_bit(BTN_BASE + (i-16), input_dev->keybit);
+}
+
 int wacom_setup_pad_input_capabilities(struct input_dev *input_dev,
                                   struct wacom_wac *wacom_wac)
 {
        struct wacom_features *features = &wacom_wac->features;
-       int i;
 
        if (!(features->device_type & WACOM_DEVICETYPE_PAD))
                return -ENODEV;
@@ -2534,10 +2747,14 @@ int wacom_setup_pad_input_capabilities(struct input_dev *input_dev,
        /* kept for making udev and libwacom accepting the pad */
        __set_bit(BTN_STYLUS, input_dev->keybit);
 
+       wacom_setup_numbered_buttons(input_dev, features->numbered_buttons);
+
        switch (features->type) {
+
+       case CINTIQ_HYBRID:
+       case DTK:
+       case DTUS:
        case GRAPHIRE_BT:
-               __set_bit(BTN_0, input_dev->keybit);
-               __set_bit(BTN_1, input_dev->keybit);
                break;
 
        case WACOM_MO:
@@ -2555,16 +2772,6 @@ int wacom_setup_pad_input_capabilities(struct input_dev *input_dev,
                break;
 
        case WACOM_24HD:
-               __set_bit(BTN_A, input_dev->keybit);
-               __set_bit(BTN_B, input_dev->keybit);
-               __set_bit(BTN_C, input_dev->keybit);
-               __set_bit(BTN_X, input_dev->keybit);
-               __set_bit(BTN_Y, input_dev->keybit);
-               __set_bit(BTN_Z, input_dev->keybit);
-
-               for (i = 0; i < 10; i++)
-                       __set_bit(BTN_0 + i, input_dev->keybit);
-
                __set_bit(KEY_PROG1, input_dev->keybit);
                __set_bit(KEY_PROG2, input_dev->keybit);
                __set_bit(KEY_PROG3, input_dev->keybit);
@@ -2586,12 +2793,6 @@ int wacom_setup_pad_input_capabilities(struct input_dev *input_dev,
                __set_bit(INPUT_PROP_ACCELEROMETER, input_dev->propbit);
                break;
 
-       case DTK:
-               for (i = 0; i < 6; i++)
-                       __set_bit(BTN_0 + i, input_dev->keybit);
-
-               break;
-
        case WACOM_22HD:
                __set_bit(KEY_PROG1, input_dev->keybit);
                __set_bit(KEY_PROG2, input_dev->keybit);
@@ -2599,52 +2800,22 @@ int wacom_setup_pad_input_capabilities(struct input_dev *input_dev,
                /* fall through */
 
        case WACOM_21UX2:
-               __set_bit(BTN_A, input_dev->keybit);
-               __set_bit(BTN_B, input_dev->keybit);
-               __set_bit(BTN_C, input_dev->keybit);
-               __set_bit(BTN_X, input_dev->keybit);
-               __set_bit(BTN_Y, input_dev->keybit);
-               __set_bit(BTN_Z, input_dev->keybit);
-               __set_bit(BTN_BASE, input_dev->keybit);
-               __set_bit(BTN_BASE2, input_dev->keybit);
-               /* fall through */
-
        case WACOM_BEE:
-               __set_bit(BTN_8, input_dev->keybit);
-               __set_bit(BTN_9, input_dev->keybit);
-               /* fall through */
-
        case CINTIQ:
-               for (i = 0; i < 8; i++)
-                       __set_bit(BTN_0 + i, input_dev->keybit);
-
                input_set_abs_params(input_dev, ABS_RX, 0, 4096, 0, 0);
                input_set_abs_params(input_dev, ABS_RY, 0, 4096, 0, 0);
                break;
 
        case WACOM_13HD:
-               for (i = 0; i < 9; i++)
-                       __set_bit(BTN_0 + i, input_dev->keybit);
-
                input_set_abs_params(input_dev, ABS_WHEEL, 0, 71, 0, 0);
                break;
 
        case INTUOS3:
        case INTUOS3L:
-               __set_bit(BTN_4, input_dev->keybit);
-               __set_bit(BTN_5, input_dev->keybit);
-               __set_bit(BTN_6, input_dev->keybit);
-               __set_bit(BTN_7, input_dev->keybit);
-
                input_set_abs_params(input_dev, ABS_RY, 0, 4096, 0, 0);
                /* fall through */
 
        case INTUOS3S:
-               __set_bit(BTN_0, input_dev->keybit);
-               __set_bit(BTN_1, input_dev->keybit);
-               __set_bit(BTN_2, input_dev->keybit);
-               __set_bit(BTN_3, input_dev->keybit);
-
                input_set_abs_params(input_dev, ABS_RX, 0, 4096, 0, 0);
                break;
 
@@ -2652,15 +2823,8 @@ int wacom_setup_pad_input_capabilities(struct input_dev *input_dev,
        case INTUOS5L:
        case INTUOSPM:
        case INTUOSPL:
-               __set_bit(BTN_7, input_dev->keybit);
-               __set_bit(BTN_8, input_dev->keybit);
-               /* fall through */
-
        case INTUOS5S:
        case INTUOSPS:
-               for (i = 0; i < 7; i++)
-                       __set_bit(BTN_0 + i, input_dev->keybit);
-
                input_set_abs_params(input_dev, ABS_WHEEL, 0, 71, 0, 0);
                break;
 
@@ -2675,28 +2839,10 @@ int wacom_setup_pad_input_capabilities(struct input_dev *input_dev,
 
        case INTUOS4:
        case INTUOS4L:
-               __set_bit(BTN_7, input_dev->keybit);
-               __set_bit(BTN_8, input_dev->keybit);
-               /* fall through */
-
        case INTUOS4S:
-               for (i = 0; i < 7; i++)
-                       __set_bit(BTN_0 + i, input_dev->keybit);
-
                input_set_abs_params(input_dev, ABS_WHEEL, 0, 71, 0, 0);
                break;
 
-       case CINTIQ_HYBRID:
-               for (i = 0; i < 9; i++)
-                       __set_bit(BTN_0 + i, input_dev->keybit);
-
-               break;
-
-       case DTUS:
-               for (i = 0; i < 4; i++)
-                       __set_bit(BTN_0 + i, input_dev->keybit);
-               break;
-
        case INTUOSHT:
        case BAMBOO_PT:
                __clear_bit(ABS_MISC, input_dev->absbit);
@@ -2708,6 +2854,11 @@ int wacom_setup_pad_input_capabilities(struct input_dev *input_dev,
 
                break;
 
+       case REMOTE:
+               input_set_capability(input_dev, EV_MSC, MSC_SERIAL);
+               input_set_abs_params(input_dev, ABS_WHEEL, 0, 71, 0, 0);
+               break;
+
        default:
                /* no pad supported */
                return -ENODEV;
@@ -2723,7 +2874,7 @@ static const struct wacom_features wacom_features_0x10 =
          GRAPHIRE, WACOM_GRAPHIRE_RES, WACOM_GRAPHIRE_RES };
 static const struct wacom_features wacom_features_0x81 =
        { "Wacom Graphire BT", 16704, 12064, 511, 32,
-         GRAPHIRE_BT, WACOM_GRAPHIRE_RES, WACOM_GRAPHIRE_RES };
+         GRAPHIRE_BT, WACOM_GRAPHIRE_RES, WACOM_GRAPHIRE_RES, 2 };
 static const struct wacom_features wacom_features_0x11 =
        { "Wacom Graphire2 4x5", 10206, 7422, 511, 63,
          GRAPHIRE, WACOM_GRAPHIRE_RES, WACOM_GRAPHIRE_RES };
@@ -2849,77 +3000,77 @@ static const struct wacom_features wacom_features_0x45 =
          INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
 static const struct wacom_features wacom_features_0xB0 =
        { "Wacom Intuos3 4x5", 25400, 20320, 1023, 63,
-         INTUOS3S, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
+         INTUOS3S, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 4 };
 static const struct wacom_features wacom_features_0xB1 =
        { "Wacom Intuos3 6x8", 40640, 30480, 1023, 63,
-         INTUOS3, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
+         INTUOS3, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 8 };
 static const struct wacom_features wacom_features_0xB2 =
        { "Wacom Intuos3 9x12", 60960, 45720, 1023, 63,
-         INTUOS3, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
+         INTUOS3, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 8 };
 static const struct wacom_features wacom_features_0xB3 =
        { "Wacom Intuos3 12x12", 60960, 60960, 1023, 63,
-         INTUOS3L, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
+         INTUOS3L, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 8 };
 static const struct wacom_features wacom_features_0xB4 =
        { "Wacom Intuos3 12x19", 97536, 60960, 1023, 63,
-         INTUOS3L, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
+         INTUOS3L, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 8 };
 static const struct wacom_features wacom_features_0xB5 =
        { "Wacom Intuos3 6x11", 54204, 31750, 1023, 63,
-         INTUOS3, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
+         INTUOS3, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 8 };
 static const struct wacom_features wacom_features_0xB7 =
        { "Wacom Intuos3 4x6", 31496, 19685, 1023, 63,
-         INTUOS3S, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
+         INTUOS3S, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 4 };
 static const struct wacom_features wacom_features_0xB8 =
        { "Wacom Intuos4 4x6", 31496, 19685, 2047, 63,
-         INTUOS4S, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
+         INTUOS4S, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 7 };
 static const struct wacom_features wacom_features_0xB9 =
        { "Wacom Intuos4 6x9", 44704, 27940, 2047, 63,
-         INTUOS4, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
+         INTUOS4, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 9 };
 static const struct wacom_features wacom_features_0xBA =
        { "Wacom Intuos4 8x13", 65024, 40640, 2047, 63,
-         INTUOS4L, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
+         INTUOS4L, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 9 };
 static const struct wacom_features wacom_features_0xBB =
        { "Wacom Intuos4 12x19", 97536, 60960, 2047, 63,
-         INTUOS4L, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
+         INTUOS4L, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 9 };
 static const struct wacom_features wacom_features_0xBC =
        { "Wacom Intuos4 WL", 40640, 25400, 2047, 63,
-         INTUOS4, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
+         INTUOS4, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 9 };
 static const struct wacom_features wacom_features_0xBD =
        { "Wacom Intuos4 WL", 40640, 25400, 2047, 63,
-         INTUOS4WL, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
+         INTUOS4WL, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 9 };
 static const struct wacom_features wacom_features_0x26 =
        { "Wacom Intuos5 touch S", 31496, 19685, 2047, 63,
-         INTUOS5S, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, .touch_max = 16 };
+         INTUOS5S, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 7, .touch_max = 16 };
 static const struct wacom_features wacom_features_0x27 =
        { "Wacom Intuos5 touch M", 44704, 27940, 2047, 63,
-         INTUOS5, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, .touch_max = 16 };
+         INTUOS5, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 9, .touch_max = 16 };
 static const struct wacom_features wacom_features_0x28 =
        { "Wacom Intuos5 touch L", 65024, 40640, 2047, 63,
-         INTUOS5L, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, .touch_max = 16 };
+         INTUOS5L, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 9, .touch_max = 16 };
 static const struct wacom_features wacom_features_0x29 =
        { "Wacom Intuos5 S", 31496, 19685, 2047, 63,
-         INTUOS5S, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
+         INTUOS5S, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 7 };
 static const struct wacom_features wacom_features_0x2A =
        { "Wacom Intuos5 M", 44704, 27940, 2047, 63,
-         INTUOS5, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
+         INTUOS5, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 9 };
 static const struct wacom_features wacom_features_0x314 =
        { "Wacom Intuos Pro S", 31496, 19685, 2047, 63,
-         INTUOSPS, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, .touch_max = 16,
+         INTUOSPS, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 7, .touch_max = 16,
          .check_for_hid_type = true, .hid_type = HID_TYPE_USBNONE };
 static const struct wacom_features wacom_features_0x315 =
        { "Wacom Intuos Pro M", 44704, 27940, 2047, 63,
-         INTUOSPM, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, .touch_max = 16,
+         INTUOSPM, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 9, .touch_max = 16,
          .check_for_hid_type = true, .hid_type = HID_TYPE_USBNONE };
 static const struct wacom_features wacom_features_0x317 =
        { "Wacom Intuos Pro L", 65024, 40640, 2047, 63,
-         INTUOSPL, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, .touch_max = 16,
+         INTUOSPL, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 9, .touch_max = 16,
          .check_for_hid_type = true, .hid_type = HID_TYPE_USBNONE };
 static const struct wacom_features wacom_features_0xF4 =
        { "Wacom Cintiq 24HD", 104080, 65200, 2047, 63,
-         WACOM_24HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES,
+         WACOM_24HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 16,
          WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET };
 static const struct wacom_features wacom_features_0xF8 =
        { "Wacom Cintiq 24HD touch", 104080, 65200, 2047, 63, /* Pen */
-         WACOM_24HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES,
+         WACOM_24HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 16,
          WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET,
          .oVid = USB_VENDOR_ID_WACOM, .oPid = 0xf6 };
 static const struct wacom_features wacom_features_0xF6 =
@@ -2928,11 +3079,11 @@ static const struct wacom_features wacom_features_0xF6 =
          .check_for_hid_type = true, .hid_type = HID_TYPE_USBNONE };
 static const struct wacom_features wacom_features_0x32A =
        { "Wacom Cintiq 27QHD", 119740, 67520, 2047, 63,
-         WACOM_27QHD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES,
+         WACOM_27QHD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 0,
          WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET };
 static const struct wacom_features wacom_features_0x32B =
        { "Wacom Cintiq 27QHD touch", 119740, 67520, 2047, 63,
-         WACOM_27QHD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES,
+         WACOM_27QHD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 0,
          WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET,
          .oVid = USB_VENDOR_ID_WACOM, .oPid = 0x32C };
 static const struct wacom_features wacom_features_0x32C =
@@ -2940,20 +3091,20 @@ static const struct wacom_features wacom_features_0x32C =
          .oVid = USB_VENDOR_ID_WACOM, .oPid = 0x32B, .touch_max = 10 };
 static const struct wacom_features wacom_features_0x3F =
        { "Wacom Cintiq 21UX", 87200, 65600, 1023, 63,
-         CINTIQ, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
+         CINTIQ, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 8 };
 static const struct wacom_features wacom_features_0xC5 =
        { "Wacom Cintiq 20WSX", 86680, 54180, 1023, 63,
-         WACOM_BEE, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
+         WACOM_BEE, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 10 };
 static const struct wacom_features wacom_features_0xC6 =
        { "Wacom Cintiq 12WX", 53020, 33440, 1023, 63,
-         WACOM_BEE, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
+         WACOM_BEE, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 10 };
 static const struct wacom_features wacom_features_0x304 =
        { "Wacom Cintiq 13HD", 59152, 33448, 1023, 63,
-         WACOM_13HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES,
+         WACOM_13HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 9,
          WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET };
 static const struct wacom_features wacom_features_0x333 =
        { "Wacom Cintiq 13HD touch", 59152, 33448, 2047, 63,
-         WACOM_13HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES,
+         WACOM_13HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 9,
          WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET,
          .oVid = USB_VENDOR_ID_WACOM, .oPid = 0x335 };
 static const struct wacom_features wacom_features_0x335 =
@@ -2972,22 +3123,22 @@ static const struct wacom_features wacom_features_0xF0 =
          DTU, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
 static const struct wacom_features wacom_features_0xFB =
        { "Wacom DTU1031", 21896, 13760, 511, 0,
-         DTUS, WACOM_INTUOS_RES, WACOM_INTUOS_RES,
+         DTUS, WACOM_INTUOS_RES, WACOM_INTUOS_RES, 4,
          WACOM_DTU_OFFSET, WACOM_DTU_OFFSET };
 static const struct wacom_features wacom_features_0x32F =
        { "Wacom DTU1031X", 22472, 12728, 511, 0,
-         DTUSX, WACOM_INTUOS_RES, WACOM_INTUOS_RES,
+         DTUSX, WACOM_INTUOS_RES, WACOM_INTUOS_RES, 0,
          WACOM_DTU_OFFSET, WACOM_DTU_OFFSET };
 static const struct wacom_features wacom_features_0x336 =
        { "Wacom DTU1141", 23472, 13203, 1023, 0,
-         DTUS, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+         DTUS, WACOM_INTUOS_RES, WACOM_INTUOS_RES, 4 };
 static const struct wacom_features wacom_features_0x57 =
        { "Wacom DTK2241", 95640, 54060, 2047, 63,
-         DTK, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES,
+         DTK, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 6,
          WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET };
 static const struct wacom_features wacom_features_0x59 = /* Pen */
        { "Wacom DTH2242", 95640, 54060, 2047, 63,
-         DTK, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES,
+         DTK, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 6,
          WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET,
          .oVid = USB_VENDOR_ID_WACOM, .oPid = 0x5D };
 static const struct wacom_features wacom_features_0x5D = /* Touch */
@@ -2996,15 +3147,15 @@ static const struct wacom_features wacom_features_0x5D = /* Touch */
          .check_for_hid_type = true, .hid_type = HID_TYPE_USBNONE };
 static const struct wacom_features wacom_features_0xCC =
        { "Wacom Cintiq 21UX2", 86800, 65200, 2047, 63,
-         WACOM_21UX2, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES,
+         WACOM_21UX2, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 18,
          WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET };
 static const struct wacom_features wacom_features_0xFA =
        { "Wacom Cintiq 22HD", 95440, 53860, 2047, 63,
-         WACOM_22HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES,
+         WACOM_22HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 18,
          WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET };
 static const struct wacom_features wacom_features_0x5B =
        { "Wacom Cintiq 22HDT", 95440, 53860, 2047, 63,
-         WACOM_22HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES,
+         WACOM_22HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 18,
          WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET,
          .oVid = USB_VENDOR_ID_WACOM, .oPid = 0x5e };
 static const struct wacom_features wacom_features_0x5E =
@@ -3151,7 +3302,7 @@ static const struct wacom_features wacom_features_0x6004 =
          TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
 static const struct wacom_features wacom_features_0x307 =
        { "Wacom ISDv5 307", 59152, 33448, 2047, 63,
-         CINTIQ_HYBRID, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES,
+         CINTIQ_HYBRID, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 9,
          WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET,
          .oVid = USB_VENDOR_ID_WACOM, .oPid = 0x309 };
 static const struct wacom_features wacom_features_0x309 =
@@ -3160,7 +3311,7 @@ static const struct wacom_features wacom_features_0x309 =
          .check_for_hid_type = true, .hid_type = HID_TYPE_USBNONE };
 static const struct wacom_features wacom_features_0x30A =
        { "Wacom ISDv5 30A", 59152, 33448, 2047, 63,
-         CINTIQ_HYBRID, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES,
+         CINTIQ_HYBRID, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 9,
          WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET,
          .oVid = USB_VENDOR_ID_WACOM, .oPid = 0x30C };
 static const struct wacom_features wacom_features_0x30C =
@@ -3177,6 +3328,10 @@ static const struct wacom_features wacom_features_0x323 =
        { "Wacom Intuos P M", 21600, 13500, 1023, 31,
          INTUOSHT, WACOM_INTUOS_RES, WACOM_INTUOS_RES,
          .check_for_hid_type = true, .hid_type = HID_TYPE_USBNONE };
+static const struct wacom_features wacom_features_0x331 =
+       { "Wacom Express Key Remote", 0, 0, 0, 0,
+         REMOTE, 0, 0, 18, .check_for_hid_type = true,
+         .hid_type = HID_TYPE_USBNONE };
 
 static const struct wacom_features wacom_features_HID_ANY_ID =
        { "Wacom HID", .type = HID_GENERIC };
@@ -3332,6 +3487,7 @@ const struct hid_device_id wacom_ids[] = {
        { USB_DEVICE_WACOM(0x32B) },
        { USB_DEVICE_WACOM(0x32C) },
        { USB_DEVICE_WACOM(0x32F) },
+       { USB_DEVICE_WACOM(0x331) },
        { USB_DEVICE_WACOM(0x333) },
        { USB_DEVICE_WACOM(0x335) },
        { USB_DEVICE_WACOM(0x336) },
index 2978c303909d396acfe9f8e0cbe96307cf8aefa4..1e270d401e181e45802cb869d30998d1017ff735 100644 (file)
@@ -16,6 +16,8 @@
 #define WACOM_PKGLEN_MAX       192
 
 #define WACOM_NAME_MAX         64
+#define WACOM_MAX_REMOTES      5
+#define WACOM_STATUS_UNKNOWN   255
 
 /* packet length for individual models */
 #define WACOM_PKGLEN_BBFUN      9
 #define WACOM_REPORT_USB               192
 #define WACOM_REPORT_BPAD_PEN          3
 #define WACOM_REPORT_BPAD_TOUCH                16
+#define WACOM_REPORT_DEVICE_LIST       16
+#define WACOM_REPORT_REMOTE            17
 
 /* device quirks */
 #define WACOM_QUIRK_BBTOUCH_LOWRES     0x0001
-#define WACOM_QUIRK_NO_INPUT           0x0002
-#define WACOM_QUIRK_MONITOR            0x0004
 #define WACOM_QUIRK_BATTERY            0x0008
 
 /* device types */
@@ -77,6 +79,7 @@
 #define WACOM_DEVICETYPE_PEN            0x0001
 #define WACOM_DEVICETYPE_TOUCH          0x0002
 #define WACOM_DEVICETYPE_PAD            0x0004
+#define WACOM_DEVICETYPE_WL_MONITOR     0x0008
 
 #define WACOM_VENDORDEFINED_PEN                0xff0d0001
 
@@ -130,6 +133,7 @@ enum {
        WACOM_24HDT,
        WACOM_27QHDT,
        BAMBOO_PAD,
+       REMOTE,
        TABLETPC,   /* add new TPC below */
        TABLETPCE,
        TABLETPC2FG,
@@ -149,6 +153,7 @@ struct wacom_features {
        int type;
        int x_resolution;
        int y_resolution;
+       int numbered_buttons;
        int x_min;
        int y_min;
        int device_type;
@@ -193,6 +198,10 @@ struct hid_data {
        int width;
        int height;
        int id;
+       int cc_index;
+       int cc_value_index;
+       int num_expected;
+       int num_received;
 };
 
 struct wacom_wac {
@@ -204,7 +213,7 @@ struct wacom_wac {
        unsigned char data[WACOM_PKGLEN_MAX];
        int tool[2];
        int id[2];
-       __u32 serial[2];
+       __u32 serial[5];
        bool reporting_data;
        struct wacom_features features;
        struct wacom_shared *shared;