Input: wacom - add support for new USB Tablet PCs
authorPing Cheng <pingc@wacom.com>
Mon, 24 Nov 2008 16:44:27 +0000 (11:44 -0500)
committerDmitry Torokhov <dmitry.torokhov@gmail.com>
Wed, 26 Nov 2008 15:14:18 +0000 (10:14 -0500)
Signed-off-by: Ping Cheng <pingc@wacom.com>
Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
drivers/input/tablet/wacom.h
drivers/input/tablet/wacom_sys.c
drivers/input/tablet/wacom_wac.c
drivers/input/tablet/wacom_wac.h

index ca62ec6..677680e 100644 (file)
@@ -66,6 +66,7 @@
  *                - Support Intuos3 4x6
  *      v1.47 (pc) - Added support for Bamboo
  *      v1.48 (pc) - Added support for Bamboo1, BambooFun, and Cintiq 12WX
+ *      v1.49 (pc) - Added support for USB Tablet PC (0x90, 0x93, and 0x9A)
  */
 
 /*
@@ -86,7 +87,7 @@
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v1.48"
+#define DRIVER_VERSION "v1.49"
 #define DRIVER_AUTHOR "Vojtech Pavlik <vojtech@ucw.cz>"
 #define DRIVER_DESC "USB Wacom Graphire and Wacom Intuos tablet driver"
 #define DRIVER_LICENSE "GPL"
@@ -103,15 +104,15 @@ struct wacom {
        struct usb_device *usbdev;
        struct usb_interface *intf;
        struct urb *irq;
-       struct wacom_wac * wacom_wac;
+       struct wacom_wac *wacom_wac;
        struct mutex lock;
        unsigned int open:1;
        char phys[32];
 };
 
 struct wacom_combo {
-       struct wacom * wacom;
-       struct urb * urb;
+       struct wacom *wacom;
+       struct urb *urb;
 };
 
 extern int wacom_wac_irq(struct wacom_wac * wacom_wac, void * wcombo);
@@ -132,7 +133,7 @@ extern void input_dev_mo(struct input_dev *input_dev, struct wacom_wac *wacom_wa
 extern void input_dev_bee(struct input_dev *input_dev, struct wacom_wac *wacom_wac);
 extern __u16 wacom_le16_to_cpu(unsigned char *data);
 extern __u16 wacom_be16_to_cpu(unsigned char *data);
-extern struct wacom_features * get_wacom_feature(const struct usb_device_id *id);
-extern const struct usb_device_id * get_device_table(void);
+extern struct wacom_features *get_wacom_feature(const struct usb_device_id *id);
+extern const struct usb_device_id *get_device_table(void);
 
 #endif
index 5fbc463..7fe7358 100644 (file)
 #include "wacom.h"
 #include "wacom_wac.h"
 
+/* defines to get HID report descriptor */
+#define HID_DEVICET_HID                (USB_TYPE_CLASS | 0x01)
+#define HID_DEVICET_REPORT     (USB_TYPE_CLASS | 0x02)
+#define HID_USAGE_UNDEFINED            0x00
+#define HID_USAGE_PAGE                 0x05
+#define HID_USAGE_PAGE_DIGITIZER       0x0d
+#define HID_USAGE_PAGE_DESKTOP         0x01
+#define HID_USAGE                      0x09
+#define HID_USAGE_X                    0x30
+#define HID_USAGE_Y                    0x31
+#define HID_USAGE_X_TILT               0x3d
+#define HID_USAGE_Y_TILT               0x3e
+#define HID_USAGE_FINGER               0x22
+#define HID_USAGE_STYLUS               0x20
+#define HID_COLLECTION                 0xc0
+
+enum {
+       WCM_UNDEFINED = 0,
+       WCM_DESKTOP,
+       WCM_DIGITIZER,
+};
+
+struct hid_descriptor {
+       struct usb_descriptor_header header;
+       __le16   bcdHID;
+       u8       bCountryCode;
+       u8       bNumDescriptors;
+       u8       bDescriptorType;
+       __le16   wDescriptorLength;
+} __attribute__ ((packed));
+
+/* defines to get/set USB message */
 #define USB_REQ_GET_REPORT     0x01
 #define USB_REQ_SET_REPORT     0x09
+#define WAC_HID_FEATURE_REPORT 0x03
 
 static int usb_get_report(struct usb_interface *intf, unsigned char type,
                                unsigned char id, void *buf, int size)
@@ -80,25 +113,21 @@ static void wacom_sys_irq(struct urb *urb)
 void wacom_report_key(void *wcombo, unsigned int key_type, int key_data)
 {
        input_report_key(get_input_dev((struct wacom_combo *)wcombo), key_type, key_data);
-       return;
 }
 
 void wacom_report_abs(void *wcombo, unsigned int abs_type, int abs_data)
 {
        input_report_abs(get_input_dev((struct wacom_combo *)wcombo), abs_type, abs_data);
-       return;
 }
 
 void wacom_report_rel(void *wcombo, unsigned int rel_type, int rel_data)
 {
        input_report_rel(get_input_dev((struct wacom_combo *)wcombo), rel_type, rel_data);
-       return;
 }
 
 void wacom_input_event(void *wcombo, unsigned int type, unsigned int code, int value)
 {
        input_event(get_input_dev((struct wacom_combo *)wcombo), type, code, value);
-       return;
 }
 
 __u16 wacom_be16_to_cpu(unsigned char *data)
@@ -118,7 +147,6 @@ __u16 wacom_le16_to_cpu(unsigned char *data)
 void wacom_input_sync(void *wcombo)
 {
        input_sync(get_input_dev((struct wacom_combo *)wcombo));
-       return;
 }
 
 static int wacom_open(struct input_dev *dev)
@@ -160,7 +188,7 @@ static void wacom_close(struct input_dev *dev)
 
 void input_dev_mo(struct input_dev *input_dev, struct wacom_wac *wacom_wac)
 {
-       input_dev->keybit[BIT_WORD(BTN_LEFT)] |= BIT_MASK(BTN_1) |
+       input_dev->keybit[BIT_WORD(BTN_MISC)] |= BIT_MASK(BTN_1) |
                BIT_MASK(BTN_5);
        input_set_abs_params(input_dev, ABS_WHEEL, 0, 71, 0, 0);
 }
@@ -170,7 +198,7 @@ void input_dev_g4(struct input_dev *input_dev, struct wacom_wac *wacom_wac)
        input_dev->evbit[0] |= BIT_MASK(EV_MSC);
        input_dev->mscbit[0] |= BIT_MASK(MSC_SERIAL);
        input_dev->keybit[BIT_WORD(BTN_DIGI)] |= BIT_MASK(BTN_TOOL_FINGER);
-       input_dev->keybit[BIT_WORD(BTN_LEFT)] |= BIT_MASK(BTN_0) |
+       input_dev->keybit[BIT_WORD(BTN_MISC)] |= BIT_MASK(BTN_0) |
                BIT_MASK(BTN_4);
 }
 
@@ -178,7 +206,7 @@ void input_dev_g(struct input_dev *input_dev, struct wacom_wac *wacom_wac)
 {
        input_dev->evbit[0] |= BIT_MASK(EV_REL);
        input_dev->relbit[0] |= BIT_MASK(REL_WHEEL);
-       input_dev->keybit[BIT_WORD(BTN_LEFT)] |= BIT_MASK(BTN_LEFT) |
+       input_dev->keybit[BIT_WORD(BTN_MOUSE)] |= BIT_MASK(BTN_LEFT) |
                BIT_MASK(BTN_RIGHT) | BIT_MASK(BTN_MIDDLE);
        input_dev->keybit[BIT_WORD(BTN_DIGI)] |= BIT_MASK(BTN_TOOL_RUBBER) |
                BIT_MASK(BTN_TOOL_MOUSE) | BIT_MASK(BTN_STYLUS2);
@@ -188,7 +216,7 @@ void input_dev_g(struct input_dev *input_dev, struct wacom_wac *wacom_wac)
 void input_dev_i3s(struct input_dev *input_dev, struct wacom_wac *wacom_wac)
 {
        input_dev->keybit[BIT_WORD(BTN_DIGI)] |= BIT_MASK(BTN_TOOL_FINGER);
-       input_dev->keybit[BIT_WORD(BTN_LEFT)] |= BIT_MASK(BTN_0) |
+       input_dev->keybit[BIT_WORD(BTN_MISC)] |= BIT_MASK(BTN_0) |
                BIT_MASK(BTN_1) | BIT_MASK(BTN_2) | BIT_MASK(BTN_3);
        input_set_abs_params(input_dev, ABS_RX, 0, 4096, 0, 0);
        input_set_abs_params(input_dev, ABS_Z, -900, 899, 0, 0);
@@ -196,14 +224,14 @@ void input_dev_i3s(struct input_dev *input_dev, struct wacom_wac *wacom_wac)
 
 void input_dev_i3(struct input_dev *input_dev, struct wacom_wac *wacom_wac)
 {
-       input_dev->keybit[BIT_WORD(BTN_LEFT)] |= BIT_MASK(BTN_4) |
+       input_dev->keybit[BIT_WORD(BTN_MISC)] |= BIT_MASK(BTN_4) |
                BIT_MASK(BTN_5) | BIT_MASK(BTN_6) | BIT_MASK(BTN_7);
        input_set_abs_params(input_dev, ABS_RY, 0, 4096, 0, 0);
 }
 
 void input_dev_bee(struct input_dev *input_dev, struct wacom_wac *wacom_wac)
 {
-       input_dev->keybit[BIT_WORD(BTN_LEFT)] |= BIT_MASK(BTN_8) | BIT_MASK(BTN_9);
+       input_dev->keybit[BIT_WORD(BTN_MISC)] |= BIT_MASK(BTN_8) | BIT_MASK(BTN_9);
 }
 
 void input_dev_i(struct input_dev *input_dev, struct wacom_wac *wacom_wac)
@@ -211,7 +239,7 @@ void input_dev_i(struct input_dev *input_dev, struct wacom_wac *wacom_wac)
        input_dev->evbit[0] |= BIT_MASK(EV_MSC) | BIT_MASK(EV_REL);
        input_dev->mscbit[0] |= BIT_MASK(MSC_SERIAL);
        input_dev->relbit[0] |= BIT_MASK(REL_WHEEL);
-       input_dev->keybit[BIT_WORD(BTN_LEFT)] |= BIT_MASK(BTN_LEFT) |
+       input_dev->keybit[BIT_WORD(BTN_MOUSE)] |= BIT_MASK(BTN_LEFT) |
                BIT_MASK(BTN_RIGHT) | BIT_MASK(BTN_MIDDLE) |
                BIT_MASK(BTN_SIDE) | BIT_MASK(BTN_EXTRA);
        input_dev->keybit[BIT_WORD(BTN_DIGI)] |= BIT_MASK(BTN_TOOL_RUBBER) |
@@ -228,8 +256,7 @@ void input_dev_i(struct input_dev *input_dev, struct wacom_wac *wacom_wac)
 
 void input_dev_pl(struct input_dev *input_dev, struct wacom_wac *wacom_wac)
 {
-       input_dev->keybit[BIT_WORD(BTN_DIGI)] |= BIT_MASK(BTN_STYLUS2) |
-               BIT_MASK(BTN_TOOL_RUBBER);
+       input_dev->keybit[BIT_WORD(BTN_DIGI)] |= BIT_MASK(BTN_STYLUS2);
 }
 
 void input_dev_pt(struct input_dev *input_dev, struct wacom_wac *wacom_wac)
@@ -237,15 +264,129 @@ void input_dev_pt(struct input_dev *input_dev, struct wacom_wac *wacom_wac)
        input_dev->keybit[BIT_WORD(BTN_DIGI)] |= BIT_MASK(BTN_TOOL_RUBBER);
 }
 
+static int wacom_parse_hid(struct usb_interface *intf, struct hid_descriptor *hid_desc,
+                          struct wacom_wac *wacom_wac)
+{
+       struct usb_device *dev = interface_to_usbdev(intf);
+       struct wacom_features *features = wacom_wac->features;
+       char limit = 0, result = 0;
+       int i = 0, usage = WCM_UNDEFINED, finger = 0, pen = 0;
+       unsigned char *report;
+
+       report = kzalloc(hid_desc->wDescriptorLength, GFP_KERNEL);
+       if (!report)
+               return -ENOMEM;
+
+       /* retrive report descriptors */
+       do {
+               result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+                       USB_REQ_GET_DESCRIPTOR,
+                       USB_RECIP_INTERFACE | USB_DIR_IN,
+                       HID_DEVICET_REPORT << 8,
+                       intf->altsetting[0].desc.bInterfaceNumber, /* interface */
+                       report,
+                       hid_desc->wDescriptorLength,
+                       5000); /* 5 secs */
+       } while (result < 0 && limit++ < 5);
+
+       if (result < 0)
+               goto out;
+
+       for (i = 0; i < hid_desc->wDescriptorLength; i++) {
+
+               switch (report[i]) {
+               case HID_USAGE_PAGE:
+                       switch (report[i + 1]) {
+                       case HID_USAGE_PAGE_DIGITIZER:
+                               usage = WCM_DIGITIZER;
+                               i++;
+                               break;
+
+                       case HID_USAGE_PAGE_DESKTOP:
+                               usage = WCM_DESKTOP;
+                               i++;
+                               break;
+                       }
+                       break;
+
+               case HID_USAGE:
+                       switch (report[i + 1]) {
+                       case HID_USAGE_X:
+                               if (usage == WCM_DESKTOP) {
+                                       if (finger) {
+                                               features->touch_x_max =
+                                                       features->touch_y_max =
+                                                       wacom_le16_to_cpu(&report[i + 3]);
+                                               features->x_max =
+                                                       wacom_le16_to_cpu(&report[i + 6]);
+                                               i += 7;
+                                       } else if (pen) {
+                                               features->x_max =
+                                                       wacom_le16_to_cpu(&report[i + 3]);
+                                               i += 4;
+                                       }
+                               } else if (usage == WCM_DIGITIZER) {
+                                       /* max pressure isn't reported
+                                       features->pressure_max = (unsigned short)
+                                                       (report[i+4] << 8  | report[i + 3]);
+                                       */
+                                       features->pressure_max = 255;
+                                       i += 4;
+                               }
+                               break;
+
+                       case HID_USAGE_Y:
+                               if (usage == WCM_DESKTOP)
+                                       features->y_max =
+                                               wacom_le16_to_cpu(&report[i + 3]);
+                               i += 4;
+                               break;
+
+                       case HID_USAGE_FINGER:
+                               finger = 1;
+                               i++;
+                               break;
+
+                       case HID_USAGE_STYLUS:
+                               pen = 1;
+                               i++;
+                               break;
+
+                       case HID_USAGE_UNDEFINED:
+                               if (usage == WCM_DESKTOP && finger) /* capacity */
+                                       features->pressure_max =
+                                               wacom_le16_to_cpu(&report[i + 3]);
+                               i += 4;
+                               break;
+                       }
+                       break;
+
+               case HID_COLLECTION:
+                       /* reset UsagePage ans Finger */
+                       finger = usage = 0;
+                       break;
+               }
+       }
+
+       result = 0;
+
+ out:
+       kfree(report);
+       return result;
+}
+
 static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *id)
 {
        struct usb_device *dev = interface_to_usbdev(intf);
+       struct usb_host_interface *interface = intf->cur_altsetting;
        struct usb_endpoint_descriptor *endpoint;
        struct wacom *wacom;
        struct wacom_wac *wacom_wac;
+       struct wacom_features *features;
        struct input_dev *input_dev;
        int error = -ENOMEM;
        char rep_data[2], limit = 0;
+       struct hid_descriptor *hid_desc;
 
        wacom = kzalloc(sizeof(struct wacom), GFP_KERNEL);
        wacom_wac = kzalloc(sizeof(struct wacom_wac), GFP_KERNEL);
@@ -268,8 +409,8 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i
        usb_make_path(dev, wacom->phys, sizeof(wacom->phys));
        strlcat(wacom->phys, "/input0", sizeof(wacom->phys));
 
-       wacom_wac->features = get_wacom_feature(id);
-       BUG_ON(wacom_wac->features->pktlen > 10);
+       wacom_wac->features = features = get_wacom_feature(id);
+       BUG_ON(features->pktlen > 10);
 
        input_dev->name = wacom_wac->features->name;
        wacom->wacom_wac = wacom_wac;
@@ -282,18 +423,37 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i
        input_dev->open = wacom_open;
        input_dev->close = wacom_close;
 
+       endpoint = &intf->cur_altsetting->endpoint[0].desc;
+
+       /* TabletPC need to retrieve the physical and logical maximum from report descriptor */
+       if (wacom_wac->features->type == TABLETPC) {
+               if (usb_get_extra_descriptor(interface, HID_DEVICET_HID, &hid_desc)) {
+                       if (usb_get_extra_descriptor(&interface->endpoint[0],
+                                                    HID_DEVICET_REPORT, &hid_desc)) {
+                               printk("wacom: can not retrive extra class descriptor\n");
+                               goto fail2;
+                       }
+               }
+               error = wacom_parse_hid(intf, hid_desc, wacom_wac);
+               if (error)
+                       goto fail2;
+       }
+
        input_dev->evbit[0] |= BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
        input_dev->keybit[BIT_WORD(BTN_DIGI)] |= BIT_MASK(BTN_TOOL_PEN) |
                BIT_MASK(BTN_TOUCH) | BIT_MASK(BTN_STYLUS);
-       input_set_abs_params(input_dev, ABS_X, 0, wacom_wac->features->x_max, 4, 0);
-       input_set_abs_params(input_dev, ABS_Y, 0, wacom_wac->features->y_max, 4, 0);
-       input_set_abs_params(input_dev, ABS_PRESSURE, 0, wacom_wac->features->pressure_max, 0, 0);
+       input_set_abs_params(input_dev, ABS_X, 0, features->x_max, 4, 0);
+       input_set_abs_params(input_dev, ABS_Y, 0, features->y_max, 4, 0);
+       input_set_abs_params(input_dev, ABS_PRESSURE, 0, features->pressure_max, 0, 0);
+       if (features->type == TABLETPC) {
+               input_dev->keybit[BIT_WORD(BTN_DIGI)] |= BIT_MASK(BTN_TOOL_DOUBLETAP);
+               input_set_abs_params(input_dev, ABS_RX, 0, features->touch_x_max, 4, 0);
+               input_set_abs_params(input_dev, ABS_RY, 0, features->touch_y_max, 4, 0);
+       }
        input_dev->absbit[BIT_WORD(ABS_MISC)] |= BIT_MASK(ABS_MISC);
 
        wacom_init_input_dev(input_dev, wacom_wac);
 
-       endpoint = &intf->cur_altsetting->endpoint[0].desc;
-
        usb_fill_int_urb(wacom->irq, dev,
                         usb_rcvintpipe(dev, endpoint->bEndpointAddress),
                         wacom_wac->data, wacom_wac->features->pktlen,
@@ -305,13 +465,22 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i
        if (error)
                goto fail3;
 
-       /* Ask the tablet to report tablet data. Repeat until it succeeds */
-       do {
-               rep_data[0] = 2;
-               rep_data[1] = 2;
-               usb_set_report(intf, 3, 2, rep_data, 2);
-               usb_get_report(intf, 3, 2, rep_data, 2);
-       } while (rep_data[1] != 2 && limit++ < 5);
+       /*
+        * Ask the tablet to report tablet data if it is not a Tablet PC.
+        * Repeat until it succeeds
+        */
+       if (wacom_wac->features->type != TABLETPC) {
+               do {
+                       rep_data[0] = 2;
+                       rep_data[1] = 2;
+                       error = usb_set_report(intf, WAC_HID_FEATURE_REPORT,
+                                               2, rep_data, 2);
+                       if (error >= 0)
+                               error = usb_get_report(intf,
+                                               WAC_HID_FEATURE_REPORT, 2,
+                                               rep_data, 2);
+               } while ((error < 0 || rep_data[1] != 2) && limit++ < 5);
+       }
 
        usb_set_intfdata(intf, wacom);
        return 0;
@@ -333,7 +502,8 @@ static void wacom_disconnect(struct usb_interface *intf)
        usb_kill_urb(wacom->irq);
        input_unregister_device(wacom->dev);
        usb_free_urb(wacom->irq);
-       usb_buffer_free(interface_to_usbdev(intf), 10, wacom->wacom_wac->data, wacom->data_dma);
+       usb_buffer_free(interface_to_usbdev(intf), 10,
+                       wacom->wacom_wac->data, wacom->data_dma);
        kfree(wacom->wacom_wac);
        kfree(wacom);
 }
index bf3d9a8..8dc8d1e 100644 (file)
@@ -535,31 +535,147 @@ static int wacom_intuos_irq(struct wacom_wac *wacom, void *wcombo)
        return 1;
 }
 
+int wacom_tpc_irq(struct wacom_wac *wacom, void *wcombo)
+{
+       char *data = wacom->data;
+       int prox = 0, pressure;
+       static int stylusInProx, touchInProx = 1, touchOut;
+       struct urb *urb = ((struct wacom_combo *)wcombo)->urb;
+
+       dbg("wacom_tpc_irq: received report #%d", data[0]);
+
+       if (urb->actual_length == 5 || data[0] == 6) { /* Touch data */
+               if (urb->actual_length == 5) {  /* with touch */
+                       prox = data[0] & 0x03;
+               } else {  /* with capacity */
+                       prox = data[1] & 0x03;
+               }
+
+               if (!stylusInProx) { /* stylus not in prox */
+                       if (prox) {
+                               if (touchInProx) {
+                                       wacom->tool[1] = BTN_TOOL_DOUBLETAP;
+                                       wacom->id[0] = TOUCH_DEVICE_ID;
+                                       if (urb->actual_length != 5) {
+                                               wacom_report_abs(wcombo, ABS_X, wacom_le16_to_cpu(&data[2]));
+                                               wacom_report_abs(wcombo, ABS_Y, wacom_le16_to_cpu(&data[4]));
+                                               wacom_report_abs(wcombo, ABS_PRESSURE, wacom_le16_to_cpu(&data[6]));
+                                               wacom_report_key(wcombo, BTN_TOUCH, wacom_le16_to_cpu(&data[6]));
+                                       } else {
+                                               wacom_report_abs(wcombo, ABS_X, wacom_le16_to_cpu(&data[1]));
+                                               wacom_report_abs(wcombo, ABS_Y, wacom_le16_to_cpu(&data[3]));
+                                               wacom_report_key(wcombo, BTN_TOUCH, 1);
+                                       }
+                                       wacom_report_abs(wcombo, ABS_MISC, wacom->id[0]);
+                                       wacom_report_key(wcombo, wacom->tool[1], prox & 0x01);
+                                       touchOut = 1;
+                                       return 1;
+                               }
+                       } else {
+                               wacom_report_abs(wcombo, ABS_MISC, wacom->id[0]);
+                               wacom_report_key(wcombo, wacom->tool[1], prox & 0x01);
+                               wacom_report_key(wcombo, BTN_TOUCH, 0);
+                               touchOut = 0;
+                               touchInProx = 1;
+                               return 1;
+                       }
+               } else if (touchOut || !prox) { /* force touch out-prox */
+                       wacom_report_abs(wcombo, ABS_MISC, TOUCH_DEVICE_ID);
+                       wacom_report_key(wcombo, BTN_TOUCH, 0);
+                       touchOut = 0;
+                       touchInProx = 1;
+                       return 1;
+               }
+       } else if (data[0] == 2) { /* Penabled */
+               prox = data[1] & 0x20;
+
+               touchInProx = 0;
+
+               wacom->id[0] = ERASER_DEVICE_ID;
+
+               /*
+                * 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 (prox) { /* in prox */
+                       if (!wacom->tool[0]) {
+                               /* Going into proximity select tool */
+                               wacom->tool[1] = (data[1] & 0x08) ? BTN_TOOL_RUBBER : BTN_TOOL_PEN;
+                               if (wacom->tool[1] == BTN_TOOL_PEN)
+                                       wacom->id[0] = STYLUS_DEVICE_ID;
+                       } else if (wacom->tool[1] == BTN_TOOL_RUBBER && !(data[1] & 0x08)) {
+                               /*
+                                * was entered with stylus2 pressed
+                                * report out proximity for previous tool
+                               */
+                               wacom_report_abs(wcombo, ABS_MISC, wacom->id[0]);
+                               wacom_report_key(wcombo, wacom->tool[1], 0);
+                               wacom_input_sync(wcombo);
+
+                               /* set new tool */
+                               wacom->tool[1] = BTN_TOOL_PEN;
+                               wacom->id[0] = STYLUS_DEVICE_ID;
+                               return 0;
+                       }
+                       if (wacom->tool[1] != BTN_TOOL_RUBBER) {
+                               /* Unknown tool selected default to pen tool */
+                               wacom->tool[1] = BTN_TOOL_PEN;
+                               wacom->id[0] = STYLUS_DEVICE_ID;
+                       }
+                       wacom_report_key(wcombo, BTN_STYLUS, data[1] & 0x02);
+                       wacom_report_key(wcombo, BTN_STYLUS2, data[1] & 0x10);
+                       wacom_report_abs(wcombo, ABS_X, wacom_le16_to_cpu(&data[2]));
+                       wacom_report_abs(wcombo, ABS_Y, wacom_le16_to_cpu(&data[4]));
+                       pressure = ((data[7] & 0x01) << 8) | data[6];
+                       if (pressure < 0)
+                               pressure = wacom->features->pressure_max + pressure + 1;
+                       wacom_report_abs(wcombo, ABS_PRESSURE, pressure);
+                       wacom_report_key(wcombo, BTN_TOUCH, pressure);
+               } else {
+                       wacom_report_abs(wcombo, ABS_PRESSURE, 0);
+                       wacom_report_key(wcombo, BTN_STYLUS, 0);
+                       wacom_report_key(wcombo, BTN_STYLUS2, 0);
+                       wacom_report_key(wcombo, BTN_TOUCH, 0);
+               }
+               wacom_report_key(wcombo, wacom->tool[1], prox);
+               wacom_report_abs(wcombo, ABS_MISC, wacom->id[0]);
+               stylusInProx = prox;
+               wacom->tool[0] = prox;
+               return 1;
+       }
+       return 0;
+}
+
 int wacom_wac_irq(struct wacom_wac *wacom_wac, void *wcombo)
 {
        switch (wacom_wac->features->type) {
                case PENPARTNER:
-                       return (wacom_penpartner_irq(wacom_wac, wcombo));
-                       break;
+                       return wacom_penpartner_irq(wacom_wac, wcombo);
+
                case PL:
-                       return (wacom_pl_irq(wacom_wac, wcombo));
-                       break;
+                       return wacom_pl_irq(wacom_wac, wcombo);
+
                case WACOM_G4:
                case GRAPHIRE:
                case WACOM_MO:
-                       return (wacom_graphire_irq(wacom_wac, wcombo));
-                       break;
+                       return wacom_graphire_irq(wacom_wac, wcombo);
+
                case PTU:
-                       return (wacom_ptu_irq(wacom_wac, wcombo));
-                       break;
+                       return wacom_ptu_irq(wacom_wac, wcombo);
+
                case INTUOS:
                case INTUOS3S:
                case INTUOS3:
                case INTUOS3L:
                case CINTIQ:
                case WACOM_BEE:
-                       return (wacom_intuos_irq(wacom_wac, wcombo));
-                       break;
+                       return wacom_intuos_irq(wacom_wac, wcombo);
+
+               case TABLETPC:
+                       return wacom_tpc_irq(wacom_wac, wcombo);
+
                default:
                        return 0;
        }
@@ -586,13 +702,15 @@ void wacom_init_input_dev(struct input_dev *input_dev, struct wacom_wac *wacom_w
                        /* fall through */
                case INTUOS3S:
                        input_dev_i3s(input_dev, wacom_wac);
+                       /* fall through */
                case INTUOS:
                        input_dev_i(input_dev, wacom_wac);
                        break;
                case PL:
                case PTU:
+               case TABLETPC:
                        input_dev_pl(input_dev, wacom_wac);
-                       break;
+                       /* fall through */
                case PENPARTNER:
                        input_dev_pt(input_dev, wacom_wac);
                        break;
@@ -611,6 +729,7 @@ static struct wacom_features wacom_features[] = {
        { "Wacom Graphire4 6x8", 8,  16704, 12064,  511, 63, WACOM_G4 },
        { "Wacom BambooFun 4x5", 9,  14760,  9225,  511, 63, WACOM_MO },
        { "Wacom BambooFun 6x8", 9,  21648, 13530,  511, 63, WACOM_MO },
+       { "Wacom Bamboo1 Medium",8,  16704, 12064,  511, 63, GRAPHIRE },
        { "Wacom Volito",        8,   5104,  3712,  511, 63, GRAPHIRE },
        { "Wacom PenStation2",   8,   3250,  2320,  255, 63, GRAPHIRE },
        { "Wacom Volito2 4x5",   8,   5104,  3712,  511, 63, GRAPHIRE },
@@ -650,6 +769,10 @@ static struct wacom_features wacom_features[] = {
        { "Wacom Cintiq 21UX",   10, 87200, 65600, 1023, 63, CINTIQ },
        { "Wacom Cintiq 20WSX",  10, 86680, 54180, 1023, 63, WACOM_BEE },
        { "Wacom Cintiq 12WX",   10, 53020, 33440, 1023, 63, WACOM_BEE },
+       { "Wacom DTU1931",        8, 37832, 30305,  511,  0, PL },
+       { "Wacom ISDv4 90",       8, 26202, 16325,  255,  0, TABLETPC },
+       { "Wacom ISDv4 93",       8, 26202, 16325,  255,  0, TABLETPC },
+       { "Wacom ISDv4 9A",       8, 26202, 16325,  255,  0, TABLETPC },
        { "Wacom Intuos2 6x8",   10, 20320, 16240, 1023, 31, INTUOS },
        { }
 };
@@ -665,6 +788,7 @@ static struct usb_device_id wacom_ids[] = {
        { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x16) },
        { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x17) },
        { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x18) },
+       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x19) },
        { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x60) },
        { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x61) },
        { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x62) },
@@ -704,18 +828,26 @@ static struct usb_device_id wacom_ids[] = {
        { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x3F) },
        { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xC5) },
        { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xC6) },
+       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xC7) },
+       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x90) },
+       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x93) },
+       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x9A) },
        { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x47) },
        { }
 };
 
-const struct usb_device_id * get_device_table(void) {
-        const struct usb_device_id * id_table = wacom_ids;
+const struct usb_device_id *get_device_table(void)
+{
+        const struct usb_device_id *id_table = wacom_ids;
+
         return id_table;
 }
 
-struct wacom_features * get_wacom_feature(const struct usb_device_id * id) {
+struct wacom_features * get_wacom_feature(const struct usb_device_id *id)
+{
         int index = id - wacom_ids;
         struct wacom_features *wf = &wacom_features[index];
+
         return wf;
 }
 
index 3342bc0..f9c8b69 100644 (file)
@@ -10,6 +10,7 @@
 #define WACOM_WAC_H
 
 #define STYLUS_DEVICE_ID       0x02
+#define TOUCH_DEVICE_ID                0x03
 #define CURSOR_DEVICE_ID       0x06
 #define ERASER_DEVICE_ID       0x0A
 #define PAD_DEVICE_ID          0x0F
@@ -27,6 +28,7 @@ enum {
        CINTIQ,
        WACOM_BEE,
        WACOM_MO,
+       TABLETPC,
        MAX_TYPE
 };
 
@@ -38,6 +40,8 @@ struct wacom_features {
        int pressure_max;
        int distance_max;
        int type;
+       int touch_x_max;
+       int touch_y_max;
 };
 
 struct wacom_wac {