Input: wacom - use get_unaligned to access unaligned data
[safe/jmp/linux-2.6] / drivers / input / tablet / wacom_sys.c
index ea30c98..d90f4e0 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * drivers/input/tablet/wacom_sys.c
  *
- *  USB Wacom Graphire and Wacom Intuos tablet support - system specific code
+ *  USB Wacom tablet support - system specific code
  */
 
 /*
@@ -11,8 +11,8 @@
  * (at your option) any later version.
  */
 
-#include "wacom.h"
 #include "wacom_wac.h"
+#include "wacom.h"
 
 /* defines to get HID report descriptor */
 #define HID_DEVICET_HID                (USB_TYPE_CLASS | 0x01)
@@ -70,15 +70,9 @@ static int usb_set_report(struct usb_interface *intf, unsigned char type,
                buf, size, 1000);
 }
 
-static struct input_dev * get_input_dev(struct wacom_combo *wcombo)
-{
-       return wcombo->wacom->dev;
-}
-
 static void wacom_sys_irq(struct urb *urb)
 {
        struct wacom *wacom = urb->context;
-       struct wacom_combo wcombo;
        int retval;
 
        switch (urb->status) {
@@ -96,59 +90,16 @@ static void wacom_sys_irq(struct urb *urb)
                goto exit;
        }
 
-       wcombo.wacom = wacom;
-       wcombo.urb = urb;
-
-       if (wacom_wac_irq(wacom->wacom_wac, (void *)&wcombo))
-               input_sync(get_input_dev(&wcombo));
+       wacom_wac_irq(&wacom->wacom_wac, urb->actual_length);
 
  exit:
        usb_mark_last_busy(wacom->usbdev);
-       retval = usb_submit_urb (urb, GFP_ATOMIC);
+       retval = usb_submit_urb(urb, GFP_ATOMIC);
        if (retval)
                err ("%s - usb_submit_urb failed with result %d",
                     __func__, retval);
 }
 
-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);
-}
-
-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);
-}
-
-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);
-}
-
-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);
-}
-
-__u16 wacom_be16_to_cpu(unsigned char *data)
-{
-       __u16 value;
-       value = be16_to_cpu(*(__be16 *) data);
-       return value;
-}
-
-__u16 wacom_le16_to_cpu(unsigned char *data)
-{
-       __u16 value;
-       value = le16_to_cpu(*(__le16 *) data);
-       return value;
-}
-
-void wacom_input_sync(void *wcombo)
-{
-       input_sync(get_input_dev((struct wacom_combo *)wcombo));
-}
-
 static int wacom_open(struct input_dev *dev)
 {
        struct wacom *wacom = input_get_drvdata(dev);
@@ -168,7 +119,7 @@ static int wacom_open(struct input_dev *dev)
                return -EIO;
        }
 
-       wacom->open = 1;
+       wacom->open = true;
        wacom->intf->needs_remote_wakeup = 1;
 
        mutex_unlock(&wacom->lock);
@@ -181,108 +132,18 @@ static void wacom_close(struct input_dev *dev)
 
        mutex_lock(&wacom->lock);
        usb_kill_urb(wacom->irq);
-       wacom->open = 0;
+       wacom->open = false;
        wacom->intf->needs_remote_wakeup = 0;
        mutex_unlock(&wacom->lock);
 }
 
-void input_dev_mo(struct input_dev *input_dev, struct wacom_wac *wacom_wac)
-{
-       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);
-}
-
-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_MISC)] |= BIT_MASK(BTN_0) |
-               BIT_MASK(BTN_4);
-}
-
-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_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);
-       input_set_abs_params(input_dev, ABS_DISTANCE, 0, wacom_wac->features->distance_max, 0, 0);
-}
-
-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_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);
-}
-
-void input_dev_i3(struct input_dev *input_dev, struct wacom_wac *wacom_wac)
-{
-       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_i4s(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_MISC)] |= BIT_MASK(BTN_0) | BIT_MASK(BTN_1) | BIT_MASK(BTN_2) | BIT_MASK(BTN_3);
-       input_dev->keybit[BIT_WORD(BTN_MISC)] |= BIT_MASK(BTN_4) | BIT_MASK(BTN_5) | BIT_MASK(BTN_6);
-       input_set_abs_params(input_dev, ABS_Z, -900, 899, 0, 0);
-}
-
-void input_dev_i4(struct input_dev *input_dev, struct wacom_wac *wacom_wac)
-{
-       input_dev->keybit[BIT_WORD(BTN_MISC)] |= BIT_MASK(BTN_7) | BIT_MASK(BTN_8);
-}
-
-void input_dev_bee(struct input_dev *input_dev, struct wacom_wac *wacom_wac)
-{
-       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)
-{
-       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_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) |
-               BIT_MASK(BTN_TOOL_MOUSE) | BIT_MASK(BTN_TOOL_BRUSH) |
-               BIT_MASK(BTN_TOOL_PENCIL) | BIT_MASK(BTN_TOOL_AIRBRUSH) |
-               BIT_MASK(BTN_TOOL_LENS) | BIT_MASK(BTN_STYLUS2);
-       input_set_abs_params(input_dev, ABS_DISTANCE, 0, wacom_wac->features->distance_max, 0, 0);
-       input_set_abs_params(input_dev, ABS_WHEEL, 0, 1023, 0, 0);
-       input_set_abs_params(input_dev, ABS_TILT_X, 0, 127, 0, 0);
-       input_set_abs_params(input_dev, ABS_TILT_Y, 0, 127, 0, 0);
-       input_set_abs_params(input_dev, ABS_RZ, -900, 899, 0, 0);
-       input_set_abs_params(input_dev, ABS_THROTTLE, -1023, 1023, 0, 0);
-}
-
-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);
-}
-
-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 wacom_features *features)
 {
        struct usb_device *dev = interface_to_usbdev(intf);
-       struct wacom_features *features = wacom_wac->features;
-       char limit = 0, result = 0;
+       char limit = 0;
+       /* result has to be defined as int for some devices */
+       int result = 0;
        int i = 0, usage = WCM_UNDEFINED, finger = 0, pen = 0;
        unsigned char *report;
 
@@ -328,15 +189,26 @@ static int wacom_parse_hid(struct usb_interface *intf, struct hid_descriptor *hi
                        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->device_type = BTN_TOOL_DOUBLETAP;
+                                               if (features->type == TABLETPC2FG) {
+                                                       /* need to reset back */
+                                                       features->pktlen = WACOM_PKGLEN_TPC2FG;
+                                                       features->device_type = BTN_TOOL_TRIPLETAP;
+                                               }
                                                features->x_max =
-                                                       wacom_le16_to_cpu(&report[i + 6]);
-                                               i += 7;
+                                                       get_unaligned_le16(&report[i + 3]);
+                                               features->x_phy =
+                                                       get_unaligned_le16(&report[i + 6]);
+                                               features->unit = report[i + 9];
+                                               features->unitExpo = report[i + 11];
+                                               i += 12;
                                        } else if (pen) {
+                                               /* penabled only accepts exact bytes of data */
+                                               if (features->type == TABLETPC2FG)
+                                                       features->pktlen = WACOM_PKGLEN_GRAPHIRE;
+                                               features->device_type = BTN_TOOL_PEN;
                                                features->x_max =
-                                                       wacom_le16_to_cpu(&report[i + 3]);
+                                                       get_unaligned_le16(&report[i + 3]);
                                                i += 4;
                                        }
                                } else if (usage == WCM_DIGITIZER) {
@@ -350,10 +222,35 @@ static int wacom_parse_hid(struct usb_interface *intf, struct hid_descriptor *hi
                                break;
 
                        case HID_USAGE_Y:
-                               if (usage == WCM_DESKTOP)
-                                       features->y_max =
-                                               wacom_le16_to_cpu(&report[i + 3]);
-                               i += 4;
+                               if (usage == WCM_DESKTOP) {
+                                       if (finger) {
+                                               features->device_type = BTN_TOOL_DOUBLETAP;
+                                               if (features->type == TABLETPC2FG) {
+                                                       /* need to reset back */
+                                                       features->pktlen = WACOM_PKGLEN_TPC2FG;
+                                                       features->device_type = BTN_TOOL_TRIPLETAP;
+                                                       features->y_max =
+                                                               get_unaligned_le16(&report[i + 3]);
+                                                       features->y_phy =
+                                                               get_unaligned_le16(&report[i + 6]);
+                                                       i += 7;
+                                               } else {
+                                                       features->y_max =
+                                                               features->x_max;
+                                                       features->y_phy =
+                                                               get_unaligned_le16(&report[i + 3]);
+                                                       i += 4;
+                                               }
+                                       } else if (pen) {
+                                               /* penabled only accepts exact bytes of data */
+                                               if (features->type == TABLETPC2FG)
+                                                       features->pktlen = WACOM_PKGLEN_GRAPHIRE;
+                                               features->device_type = BTN_TOOL_PEN;
+                                               features->y_max =
+                                                       get_unaligned_le16(&report[i + 3]);
+                                               i += 4;
+                                       }
+                               }
                                break;
 
                        case HID_USAGE_FINGER:
@@ -369,14 +266,14 @@ static int wacom_parse_hid(struct usb_interface *intf, struct hid_descriptor *hi
                        case HID_USAGE_UNDEFINED:
                                if (usage == WCM_DESKTOP && finger) /* capacity */
                                        features->pressure_max =
-                                               wacom_le16_to_cpu(&report[i + 3]);
+                                               get_unaligned_le16(&report[i + 3]);
                                i += 4;
                                break;
                        }
                        break;
 
                case HID_COLLECTION:
-                       /* reset UsagePage ans Finger */
+                       /* reset UsagePage and Finger */
                        finger = usage = 0;
                        break;
                }
@@ -388,145 +285,260 @@ static int wacom_parse_hid(struct usb_interface *intf, struct hid_descriptor *hi
        return result;
 }
 
-static int wacom_query_tablet_data(struct usb_interface *intf)
+static int wacom_query_tablet_data(struct usb_interface *intf, struct wacom_features *features)
 {
        unsigned char *rep_data;
-       int limit = 0;
-       int error;
+       int limit = 0, report_id = 2;
+       int error = -ENOMEM;
 
        rep_data = kmalloc(2, GFP_KERNEL);
        if (!rep_data)
-               return -ENOMEM;
-
-       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);
+               return error;
+
+       /* ask to report tablet data if it is 2FGT or not a Tablet PC */
+       if (features->device_type == BTN_TOOL_TRIPLETAP) {
+               do {
+                       rep_data[0] = 3;
+                       rep_data[1] = 4;
+                       report_id = 3;
+                       error = usb_set_report(intf, WAC_HID_FEATURE_REPORT,
+                               report_id, rep_data, 2);
+                       if (error >= 0)
+                               error = usb_get_report(intf,
+                                       WAC_HID_FEATURE_REPORT, report_id,
+                                       rep_data, 3);
+               } while ((error < 0 || rep_data[1] != 4) && limit++ < 5);
+       } else if (features->type != TABLETPC && features->type != TABLETPC2FG) {
+               do {
+                       rep_data[0] = 2;
+                       rep_data[1] = 2;
+                       error = usb_set_report(intf, WAC_HID_FEATURE_REPORT,
+                               report_id, rep_data, 2);
+                       if (error >= 0)
+                               error = usb_get_report(intf,
+                                       WAC_HID_FEATURE_REPORT, report_id,
+                                       rep_data, 2);
+               } while ((error < 0 || rep_data[1] != 2) && limit++ < 5);
+       }
 
        kfree(rep_data);
 
        return error < 0 ? error : 0;
 }
 
+static int wacom_retrieve_hid_descriptor(struct usb_interface *intf,
+               struct wacom_features *features)
+{
+       int error = 0;
+       struct usb_host_interface *interface = intf->cur_altsetting;
+       struct hid_descriptor *hid_desc;
+
+       /* default device to penabled */
+       features->device_type = BTN_TOOL_PEN;
+
+       /* only Tablet PCs need to retrieve the info */
+       if ((features->type != TABLETPC) && (features->type != TABLETPC2FG))
+               goto out;
+
+       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 retrieve extra class descriptor\n");
+                       error = 1;
+                       goto out;
+               }
+       }
+       error = wacom_parse_hid(intf, hid_desc, features);
+       if (error)
+               goto out;
+
+       /* touch device found but size is not defined. use default */
+       if (features->device_type == BTN_TOOL_DOUBLETAP && !features->x_max) {
+               features->x_max = 1023;
+               features->y_max = 1023;
+       }
+
+ out:
+       return error;
+}
+
+struct wacom_usbdev_data {
+       struct list_head list;
+       struct kref kref;
+       struct usb_device *dev;
+       struct wacom_shared shared;
+};
+
+static LIST_HEAD(wacom_udev_list);
+static DEFINE_MUTEX(wacom_udev_list_lock);
+
+static struct wacom_usbdev_data *wacom_get_usbdev_data(struct usb_device *dev)
+{
+       struct wacom_usbdev_data *data;
+
+       list_for_each_entry(data, &wacom_udev_list, list) {
+               if (data->dev == dev) {
+                       kref_get(&data->kref);
+                       return data;
+               }
+       }
+
+       return NULL;
+}
+
+static int wacom_add_shared_data(struct wacom_wac *wacom,
+                                struct usb_device *dev)
+{
+       struct wacom_usbdev_data *data;
+       int retval = 0;
+
+       mutex_lock(&wacom_udev_list_lock);
+
+       data = wacom_get_usbdev_data(dev);
+       if (!data) {
+               data = kzalloc(sizeof(struct wacom_usbdev_data), GFP_KERNEL);
+               if (!data) {
+                       retval = -ENOMEM;
+                       goto out;
+               }
+
+               kref_init(&data->kref);
+               data->dev = dev;
+               list_add_tail(&data->list, &wacom_udev_list);
+       }
+
+       wacom->shared = &data->shared;
+
+out:
+       mutex_unlock(&wacom_udev_list_lock);
+       return retval;
+}
+
+static void wacom_release_shared_data(struct kref *kref)
+{
+       struct wacom_usbdev_data *data =
+               container_of(kref, struct wacom_usbdev_data, kref);
+
+       mutex_lock(&wacom_udev_list_lock);
+       list_del(&data->list);
+       mutex_unlock(&wacom_udev_list_lock);
+
+       kfree(data);
+}
+
+static void wacom_remove_shared_data(struct wacom_wac *wacom)
+{
+       struct wacom_usbdev_data *data;
+
+       if (wacom->shared) {
+               data = container_of(wacom->shared, struct wacom_usbdev_data, shared);
+               kref_put(&data->kref, wacom_release_shared_data);
+               wacom->shared = NULL;
+       }
+}
+
 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;
-       struct hid_descriptor *hid_desc;
+       int error;
+
+       if (!id->driver_info)
+               return -EINVAL;
 
        wacom = kzalloc(sizeof(struct wacom), GFP_KERNEL);
-       wacom_wac = kzalloc(sizeof(struct wacom_wac), GFP_KERNEL);
        input_dev = input_allocate_device();
-       if (!wacom || !input_dev || !wacom_wac)
+       if (!wacom || !input_dev) {
+               error = -ENOMEM;
+               goto fail1;
+       }
+
+       wacom_wac = &wacom->wacom_wac;
+       wacom_wac->features = *((struct wacom_features *)id->driver_info);
+       features = &wacom_wac->features;
+       if (features->pktlen > WACOM_PKGLEN_MAX) {
+               error = -EINVAL;
                goto fail1;
+       }
 
-       wacom_wac->data = usb_buffer_alloc(dev, 10, GFP_KERNEL, &wacom->data_dma);
-       if (!wacom_wac->data)
+       wacom_wac->data = usb_buffer_alloc(dev, WACOM_PKGLEN_MAX,
+                                          GFP_KERNEL, &wacom->data_dma);
+       if (!wacom_wac->data) {
+               error = -ENOMEM;
                goto fail1;
+       }
 
        wacom->irq = usb_alloc_urb(0, GFP_KERNEL);
-       if (!wacom->irq)
+       if (!wacom->irq) {
+               error = -ENOMEM;
                goto fail2;
+       }
 
        wacom->usbdev = dev;
-       wacom->dev = input_dev;
        wacom->intf = intf;
        mutex_init(&wacom->lock);
        usb_make_path(dev, wacom->phys, sizeof(wacom->phys));
        strlcat(wacom->phys, "/input0", sizeof(wacom->phys));
 
-       wacom_wac->features = features = get_wacom_feature(id);
-       BUG_ON(features->pktlen > 10);
+       wacom_wac->input = input_dev;
 
-       input_dev->name = wacom_wac->features->name;
-       wacom->wacom_wac = wacom_wac;
-       usb_to_input_id(dev, &input_dev->id);
-
-       input_dev->dev.parent = &intf->dev;
-
-       input_set_drvdata(input_dev, wacom);
+       endpoint = &intf->cur_altsetting->endpoint[0].desc;
 
-       input_dev->open = wacom_open;
-       input_dev->close = wacom_close;
+       /* Retrieve the physical and logical size for OEM devices */
+       error = wacom_retrieve_hid_descriptor(intf, features);
+       if (error)
+               goto fail2;
 
-       endpoint = &intf->cur_altsetting->endpoint[0].desc;
+       strlcpy(wacom_wac->name, features->name, sizeof(wacom_wac->name));
 
-       /* Initialize touch_x_max and touch_y_max in case it is not defined */
-       if (wacom_wac->features->type == TABLETPC) {
-               features->touch_x_max = 1023;
-               features->touch_y_max = 1023;
-       } else {
-               features->touch_x_max = 0;
-               features->touch_y_max = 0;
-       }
+       if (features->type == TABLETPC || features->type == TABLETPC2FG) {
+               /* Append the device type to the name */
+               strlcat(wacom_wac->name,
+                       features->device_type == BTN_TOOL_PEN ?
+                               " Pen" : " Finger",
+                       sizeof(wacom_wac->name));
 
-       /* 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);
+               error = wacom_add_shared_data(wacom_wac, dev);
                if (error)
-                       goto fail2;
+                       goto fail3;
        }
 
-       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, 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);
+       input_dev->name = wacom_wac->name;
+       input_dev->name = wacom_wac->name;
+       input_dev->dev.parent = &intf->dev;
+       input_dev->open = wacom_open;
+       input_dev->close = wacom_close;
+       usb_to_input_id(dev, &input_dev->id);
+       input_set_drvdata(input_dev, wacom);
 
-       wacom_init_input_dev(input_dev, wacom_wac);
+       wacom_setup_input_capabilities(input_dev, wacom_wac);
 
        usb_fill_int_urb(wacom->irq, dev,
                         usb_rcvintpipe(dev, endpoint->bEndpointAddress),
-                        wacom_wac->data, wacom_wac->features->pktlen,
+                        wacom_wac->data, features->pktlen,
                         wacom_sys_irq, wacom, endpoint->bInterval);
        wacom->irq->transfer_dma = wacom->data_dma;
        wacom->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
 
-       error = input_register_device(wacom->dev);
+       error = input_register_device(input_dev);
        if (error)
-               goto fail3;
+               goto fail4;
 
-       /*
-        * Ask the tablet to report tablet data if it is not a Tablet PC.
-        * Note that if query fails it is not a hard failure.
-        */
-       if (wacom_wac->features->type != TABLETPC)
-               wacom_query_tablet_data(intf);
+       /* Note that if query fails it is not a hard failure */
+       wacom_query_tablet_data(intf, features);
 
        usb_set_intfdata(intf, wacom);
        return 0;
 
+ fail4:        wacom_remove_shared_data(wacom_wac);
  fail3:        usb_free_urb(wacom->irq);
- fail2:        usb_buffer_free(dev, 10, wacom_wac->data, wacom->data_dma);
+ fail2:        usb_buffer_free(dev, WACOM_PKGLEN_MAX, wacom_wac->data, wacom->data_dma);
  fail1:        input_free_device(input_dev);
        kfree(wacom);
-       kfree(wacom_wac);
        return error;
 }
 
@@ -537,11 +549,11 @@ static void wacom_disconnect(struct usb_interface *intf)
        usb_set_intfdata(intf, NULL);
 
        usb_kill_urb(wacom->irq);
-       input_unregister_device(wacom->dev);
+       input_unregister_device(wacom->wacom_wac.input);
        usb_free_urb(wacom->irq);
-       usb_buffer_free(interface_to_usbdev(intf), 10,
-                       wacom->wacom_wac->data, wacom->data_dma);
-       kfree(wacom->wacom_wac);
+       usb_buffer_free(interface_to_usbdev(intf), WACOM_PKGLEN_MAX,
+                       wacom->wacom_wac.data, wacom->data_dma);
+       wacom_remove_shared_data(&wacom->wacom_wac);
        kfree(wacom);
 }
 
@@ -559,13 +571,19 @@ static int wacom_suspend(struct usb_interface *intf, pm_message_t message)
 static int wacom_resume(struct usb_interface *intf)
 {
        struct wacom *wacom = usb_get_intfdata(intf);
+       struct wacom_features *features = &wacom->wacom_wac.features;
        int rv;
 
        mutex_lock(&wacom->lock);
+
+       /* switch to wacom mode first */
+       wacom_query_tablet_data(intf, features);
+
        if (wacom->open)
                rv = usb_submit_urb(wacom->irq, GFP_NOIO);
        else
                rv = 0;
+
        mutex_unlock(&wacom->lock);
 
        return rv;
@@ -578,6 +596,7 @@ static int wacom_reset_resume(struct usb_interface *intf)
 
 static struct usb_driver wacom_driver = {
        .name =         "wacom",
+       .id_table =     wacom_ids,
        .probe =        wacom_probe,
        .disconnect =   wacom_disconnect,
        .suspend =      wacom_suspend,
@@ -589,7 +608,7 @@ static struct usb_driver wacom_driver = {
 static int __init wacom_init(void)
 {
        int result;
-       wacom_driver.id_table = get_device_table();
+
        result = usb_register(&wacom_driver);
        if (result == 0)
                printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"