Commit 545f4e99 authored by Ping Cheng's avatar Ping Cheng Committed by Dmitry Torokhov
Browse files

Input: wacom - add support for new USB Tablet PCs



Signed-off-by: default avatarPing Cheng <pingc@wacom.com>
Signed-off-by: default avatarDmitry Torokhov <dtor@mail.ru>
parent 8442c87d
Loading
Loading
Loading
Loading
+7 −6
Original line number Diff line number Diff line
@@ -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"
+199 −29
Original line number Diff line number Diff line
@@ -14,8 +14,41 @@
#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 */
	/*
	 * 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;
		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);
			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);
}
+146 −14
Original line number Diff line number Diff line
@@ -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 *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;
}

+4 −0
Original line number Diff line number Diff line
@@ -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 {