HID: waltop: Add support for tablet with PID 0038
Nikolai Kondrashov [Tue, 6 Mar 2012 07:54:24 +0000 (09:54 +0200)]
Add support for unknown Waltop tablet with product ID 0x0038.
This tablet is sold as Genius G-Pen F509.

Signed-off-by: Nikolai Kondrashov <spbnick@gmail.com>
Signed-off-by: Jiri Kosina <jkosina@suse.cz>

drivers/hid/hid-core.c
drivers/hid/hid-ids.h
drivers/hid/hid-waltop.c

index ed96333..d76d85a 100644 (file)
@@ -1566,6 +1566,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_SLIM_TABLET_5_8_INCH) },
        { HID_USB_DEVICE(USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_SLIM_TABLET_12_1_INCH) },
        { HID_USB_DEVICE(USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_Q_PAD) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_PID_0038) },
        { HID_USB_DEVICE(USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_MEDIA_TABLET_10_6_INCH) },
        { HID_USB_DEVICE(USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_MEDIA_TABLET_14_1_INCH) },
        { HID_USB_DEVICE(USB_VENDOR_ID_XAT, USB_DEVICE_ID_XAT_CSR) },
index 6e119a3..afe878f 100644 (file)
 #define USB_DEVICE_ID_WALTOP_SLIM_TABLET_5_8_INCH      0x0032
 #define USB_DEVICE_ID_WALTOP_SLIM_TABLET_12_1_INCH     0x0034
 #define USB_DEVICE_ID_WALTOP_Q_PAD                     0x0037
+#define USB_DEVICE_ID_WALTOP_PID_0038                  0x0038
 #define USB_DEVICE_ID_WALTOP_MEDIA_TABLET_10_6_INCH    0x0501
 #define USB_DEVICE_ID_WALTOP_MEDIA_TABLET_14_1_INCH    0x0500
 
index c1dce51..2cfd95c 100644 (file)
@@ -211,6 +211,64 @@ static __u8 q_pad_rdesc_fixed[] = {
 };
 
 /*
+ * See description, device and HID report descriptors of tablet with PID 0038 at
+ * http://sf.net/apps/mediawiki/digimend/?title=Waltop_PID_0038
+ */
+
+/* Size of the original report descriptor of tablet with PID 0038 */
+#define PID_0038_RDESC_ORIG_SIZE       241
+
+/*
+ * Fixed report descriptor for tablet with PID 0038.
+ */
+static __u8 pid_0038_rdesc_fixed[] = {
+       0x05, 0x0D,         /*  Usage Page (Digitizer),             */
+       0x09, 0x02,         /*  Usage (Pen),                        */
+       0xA1, 0x01,         /*  Collection (Application),           */
+       0x85, 0x10,         /*      Report ID (16),                 */
+       0x09, 0x20,         /*      Usage (Stylus),                 */
+       0xA0,               /*      Collection (Physical),          */
+       0x09, 0x42,         /*          Usage (Tip Switch),         */
+       0x09, 0x44,         /*          Usage (Barrel Switch),      */
+       0x09, 0x46,         /*          Usage (Tablet Pick),        */
+       0x15, 0x01,         /*          Logical Minimum (1),        */
+       0x25, 0x03,         /*          Logical Maximum (3),        */
+       0x75, 0x04,         /*          Report Size (4),            */
+       0x95, 0x01,         /*          Report Count (1),           */
+       0x80,               /*          Input,                      */
+       0x09, 0x32,         /*          Usage (In Range),           */
+       0x14,               /*          Logical Minimum (0),        */
+       0x25, 0x01,         /*          Logical Maximum (1),        */
+       0x75, 0x01,         /*          Report Size (1),            */
+       0x95, 0x01,         /*          Report Count (1),           */
+       0x81, 0x02,         /*          Input (Variable),           */
+       0x95, 0x03,         /*          Report Count (3),           */
+       0x81, 0x03,         /*          Input (Constant, Variable), */
+       0x75, 0x10,         /*          Report Size (16),           */
+       0x95, 0x01,         /*          Report Count (1),           */
+       0x14,               /*          Logical Minimum (0),        */
+       0xA4,               /*          Push,                       */
+       0x05, 0x01,         /*          Usage Page (Desktop),       */
+       0x65, 0x13,         /*          Unit (Inch),                */
+       0x55, 0xFD,         /*          Unit Exponent (-3),         */
+       0x34,               /*          Physical Minimum (0),       */
+       0x09, 0x30,         /*          Usage (X),                  */
+       0x46, 0x2E, 0x22,   /*          Physical Maximum (8750),    */
+       0x26, 0x00, 0x46,   /*          Logical Maximum (17920),    */
+       0x81, 0x02,         /*          Input (Variable),           */
+       0x09, 0x31,         /*          Usage (Y),                  */
+       0x46, 0x82, 0x14,   /*          Physical Maximum (5250),    */
+       0x26, 0x00, 0x2A,   /*          Logical Maximum (10752),    */
+       0x81, 0x02,         /*          Input (Variable),           */
+       0xB4,               /*          Pop,                        */
+       0x09, 0x30,         /*          Usage (Tip Pressure),       */
+       0x26, 0xFF, 0x03,   /*          Logical Maximum (1023),     */
+       0x81, 0x02,         /*          Input (Variable),           */
+       0xC0,               /*      End Collection,                 */
+       0xC0                /*  End Collection                      */
+};
+
+/*
  * See Media Tablet 10.6 inch description, device and HID report descriptors at
  * http://sf.net/apps/mediawiki/digimend/?title=Waltop_Media_Tablet_10.6%22
  */
@@ -444,6 +502,47 @@ static __u8 media_tablet_14_1_inch_rdesc_fixed[] = {
        0xC0                /*  End Collection                      */
 };
 
+struct waltop_state {
+       u8 pressure0;
+       u8 pressure1;
+};
+
+static int waltop_probe(struct hid_device *hdev,
+                       const struct hid_device_id *id)
+{
+       int ret;
+       struct waltop_state *s;
+
+       s = kzalloc(sizeof(*s), GFP_KERNEL);
+       if (s == NULL) {
+               hid_err(hdev, "can't allocate device state\n");
+               ret = -ENOMEM;
+               goto err;
+       }
+
+       s->pressure0 = 0;
+       s->pressure1 = 0;
+
+       hid_set_drvdata(hdev, s);
+
+       ret = hid_parse(hdev);
+       if (ret) {
+               hid_err(hdev, "parse failed\n");
+               goto err;
+       }
+
+       ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
+       if (ret) {
+               hid_err(hdev, "hw start failed\n");
+               goto err;
+       }
+
+       return 0;
+err:
+       kfree(s);
+       return ret;
+}
+
 static __u8 *waltop_report_fixup(struct hid_device *hdev, __u8 *rdesc,
                unsigned int *rsize)
 {
@@ -466,6 +565,12 @@ static __u8 *waltop_report_fixup(struct hid_device *hdev, __u8 *rdesc,
                        *rsize = sizeof(q_pad_rdesc_fixed);
                }
                break;
+       case USB_DEVICE_ID_WALTOP_PID_0038:
+               if (*rsize == PID_0038_RDESC_ORIG_SIZE) {
+                       rdesc = pid_0038_rdesc_fixed;
+                       *rsize = sizeof(pid_0038_rdesc_fixed);
+               }
+               break;
        case USB_DEVICE_ID_WALTOP_MEDIA_TABLET_10_6_INCH:
                if (*rsize == MEDIA_TABLET_10_6_INCH_RDESC_ORIG_SIZE) {
                        rdesc = media_tablet_10_6_inch_rdesc_fixed;
@@ -482,6 +587,44 @@ static __u8 *waltop_report_fixup(struct hid_device *hdev, __u8 *rdesc,
        return rdesc;
 }
 
+static int waltop_raw_event(struct hid_device *hdev, struct hid_report *report,
+                    u8 *data, int size)
+{
+       /* If this is a pen input report of a tablet with PID 0038 */
+       if (hdev->product == USB_DEVICE_ID_WALTOP_PID_0038 &&
+           report->type == HID_INPUT_REPORT &&
+           report->id == 16 &&
+           size == 8) {
+               struct waltop_state *s = hid_get_drvdata(hdev);
+
+               /*
+                * Ignore maximum pressure reported when a barrel button is
+                * pressed.
+                */
+
+               /* If a barrel button is pressed */
+               if ((data[1] & 0xF) > 1) {
+                       /* Use the last known pressure */
+                       data[6] = s->pressure0;
+                       data[7] = s->pressure1;
+               } else {
+                       /* Remember reported pressure */
+                       s->pressure0 = data[6];
+                       s->pressure1 = data[7];
+               }
+       }
+
+       return 0;
+}
+
+static void waltop_remove(struct hid_device *hdev)
+{
+       struct waltop_state *s = hid_get_drvdata(hdev);
+
+       hid_hw_stop(hdev);
+       kfree(s);
+}
+
 static const struct hid_device_id waltop_devices[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_WALTOP,
                                USB_DEVICE_ID_WALTOP_SLIM_TABLET_5_8_INCH) },
@@ -490,6 +633,8 @@ static const struct hid_device_id waltop_devices[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_WALTOP,
                                USB_DEVICE_ID_WALTOP_Q_PAD) },
        { HID_USB_DEVICE(USB_VENDOR_ID_WALTOP,
+                               USB_DEVICE_ID_WALTOP_PID_0038) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_WALTOP,
                                USB_DEVICE_ID_WALTOP_MEDIA_TABLET_10_6_INCH) },
        { HID_USB_DEVICE(USB_VENDOR_ID_WALTOP,
                                USB_DEVICE_ID_WALTOP_MEDIA_TABLET_14_1_INCH) },
@@ -500,7 +645,10 @@ MODULE_DEVICE_TABLE(hid, waltop_devices);
 static struct hid_driver waltop_driver = {
        .name = "waltop",
        .id_table = waltop_devices,
+       .probe = waltop_probe,
        .report_fixup = waltop_report_fixup,
+       .raw_event = waltop_raw_event,
+       .remove = waltop_remove,
 };
 
 static int __init waltop_init(void)