Commit ec67bbed authored by Ping Cheng's avatar Ping Cheng Committed by Dmitry Torokhov

Input: wacom - add support for new LCD tablets

This adds support for the foolowing Wacom devices:

 - 0x9F - a single touch only LCD tablet;
 - 0xE2 - a two finger touch only LCD tablet;
 - 0xE3 -  a two finger touch, penabled LCD tablet.
Signed-off-by: default avatarPing Cheng <pingc@wacom.com>
Signed-off-by: default avatarDmitry Torokhov <dtor@mail.ru>
parent ee54500d
...@@ -71,6 +71,7 @@ ...@@ -71,6 +71,7 @@
* v1.51 (pc) - Added support for Intuos4 * v1.51 (pc) - Added support for Intuos4
* v1.52 (pc) - Query Wacom data upon system resume * v1.52 (pc) - Query Wacom data upon system resume
* - add defines for features->type * - add defines for features->type
* - add new devices (0x9F, 0xE2, and 0XE3)
*/ */
/* /*
...@@ -135,6 +136,8 @@ extern void input_dev_i4s(struct input_dev *input_dev, struct wacom_wac *wacom_w ...@@ -135,6 +136,8 @@ extern void input_dev_i4s(struct input_dev *input_dev, struct wacom_wac *wacom_w
extern void input_dev_i4(struct input_dev *input_dev, struct wacom_wac *wacom_wac); extern void input_dev_i4(struct input_dev *input_dev, struct wacom_wac *wacom_wac);
extern void input_dev_pl(struct input_dev *input_dev, struct wacom_wac *wacom_wac); extern void input_dev_pl(struct input_dev *input_dev, struct wacom_wac *wacom_wac);
extern void input_dev_pt(struct input_dev *input_dev, struct wacom_wac *wacom_wac); extern void input_dev_pt(struct input_dev *input_dev, struct wacom_wac *wacom_wac);
extern void input_dev_tpc(struct input_dev *input_dev, struct wacom_wac *wacom_wac);
extern void input_dev_tpc2fg(struct input_dev *input_dev, struct wacom_wac *wacom_wac);
extern void input_dev_mo(struct input_dev *input_dev, struct wacom_wac *wacom_wac); extern void input_dev_mo(struct input_dev *input_dev, struct wacom_wac *wacom_wac);
extern void input_dev_bee(struct input_dev *input_dev, struct wacom_wac *wacom_wac); 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_le16_to_cpu(unsigned char *data);
......
...@@ -209,6 +209,7 @@ void input_dev_g(struct input_dev *input_dev, struct wacom_wac *wacom_wac) ...@@ -209,6 +209,7 @@ void input_dev_g(struct input_dev *input_dev, struct wacom_wac *wacom_wac)
input_dev->keybit[BIT_WORD(BTN_MOUSE)] |= 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_RIGHT) | BIT_MASK(BTN_MIDDLE);
input_dev->keybit[BIT_WORD(BTN_DIGI)] |= BIT_MASK(BTN_TOOL_RUBBER) | input_dev->keybit[BIT_WORD(BTN_DIGI)] |= BIT_MASK(BTN_TOOL_RUBBER) |
BIT_MASK(BTN_TOOL_PEN) | BIT_MASK(BTN_STYLUS) |
BIT_MASK(BTN_TOOL_MOUSE) | BIT_MASK(BTN_STYLUS2); 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); input_set_abs_params(input_dev, ABS_DISTANCE, 0, wacom_wac->features->distance_max, 0, 0);
} }
...@@ -256,6 +257,7 @@ void input_dev_i(struct input_dev *input_dev, struct wacom_wac *wacom_wac) ...@@ -256,6 +257,7 @@ void input_dev_i(struct input_dev *input_dev, struct wacom_wac *wacom_wac)
BIT_MASK(BTN_RIGHT) | BIT_MASK(BTN_MIDDLE) | BIT_MASK(BTN_RIGHT) | BIT_MASK(BTN_MIDDLE) |
BIT_MASK(BTN_SIDE) | BIT_MASK(BTN_EXTRA); BIT_MASK(BTN_SIDE) | BIT_MASK(BTN_EXTRA);
input_dev->keybit[BIT_WORD(BTN_DIGI)] |= BIT_MASK(BTN_TOOL_RUBBER) | input_dev->keybit[BIT_WORD(BTN_DIGI)] |= BIT_MASK(BTN_TOOL_RUBBER) |
BIT_MASK(BTN_TOOL_PEN) | BIT_MASK(BTN_STYLUS) |
BIT_MASK(BTN_TOOL_MOUSE) | BIT_MASK(BTN_TOOL_BRUSH) | BIT_MASK(BTN_TOOL_MOUSE) | BIT_MASK(BTN_TOOL_BRUSH) |
BIT_MASK(BTN_TOOL_PENCIL) | BIT_MASK(BTN_TOOL_AIRBRUSH) | BIT_MASK(BTN_TOOL_PENCIL) | BIT_MASK(BTN_TOOL_AIRBRUSH) |
BIT_MASK(BTN_TOOL_LENS) | BIT_MASK(BTN_STYLUS2); BIT_MASK(BTN_TOOL_LENS) | BIT_MASK(BTN_STYLUS2);
...@@ -269,7 +271,8 @@ void input_dev_i(struct input_dev *input_dev, struct wacom_wac *wacom_wac) ...@@ -269,7 +271,8 @@ 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) 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); input_dev->keybit[BIT_WORD(BTN_DIGI)] |= BIT_MASK(BTN_TOOL_PEN) |
BIT_MASK(BTN_STYLUS) | BIT_MASK(BTN_STYLUS2);
} }
void input_dev_pt(struct input_dev *input_dev, struct wacom_wac *wacom_wac) void input_dev_pt(struct input_dev *input_dev, struct wacom_wac *wacom_wac)
...@@ -277,12 +280,32 @@ void input_dev_pt(struct input_dev *input_dev, struct wacom_wac *wacom_wac) ...@@ -277,12 +280,32 @@ 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); input_dev->keybit[BIT_WORD(BTN_DIGI)] |= BIT_MASK(BTN_TOOL_RUBBER);
} }
void input_dev_tpc(struct input_dev *input_dev, struct wacom_wac *wacom_wac)
{
if (wacom_wac->features->device_type == BTN_TOOL_DOUBLETAP ||
wacom_wac->features->device_type == BTN_TOOL_TRIPLETAP) {
input_set_abs_params(input_dev, ABS_RX, 0, wacom_wac->features->x_phy, 0, 0);
input_set_abs_params(input_dev, ABS_RY, 0, wacom_wac->features->y_phy, 0, 0);
input_dev->keybit[BIT_WORD(BTN_DIGI)] |= BIT_MASK(BTN_TOOL_DOUBLETAP);
}
}
void input_dev_tpc2fg(struct input_dev *input_dev, struct wacom_wac *wacom_wac)
{
if (wacom_wac->features->device_type == BTN_TOOL_TRIPLETAP) {
input_dev->keybit[BIT_WORD(BTN_DIGI)] |= BIT_MASK(BTN_TOOL_TRIPLETAP);
input_dev->evbit[0] |= BIT_MASK(EV_MSC);
input_dev->mscbit[0] |= BIT_MASK(MSC_SERIAL);
}
}
static int wacom_parse_hid(struct usb_interface *intf, struct hid_descriptor *hid_desc, 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 usb_device *dev = interface_to_usbdev(intf);
struct wacom_features *features = wacom_wac->features; char limit = 0;
char limit = 0, result = 0; /* result has to be defined as int for some devices */
int result = 0;
int i = 0, usage = WCM_UNDEFINED, finger = 0, pen = 0; int i = 0, usage = WCM_UNDEFINED, finger = 0, pen = 0;
unsigned char *report; unsigned char *report;
...@@ -328,13 +351,24 @@ static int wacom_parse_hid(struct usb_interface *intf, struct hid_descriptor *hi ...@@ -328,13 +351,24 @@ static int wacom_parse_hid(struct usb_interface *intf, struct hid_descriptor *hi
case HID_USAGE_X: case HID_USAGE_X:
if (usage == WCM_DESKTOP) { if (usage == WCM_DESKTOP) {
if (finger) { if (finger) {
features->touch_x_max = features->device_type = BTN_TOOL_DOUBLETAP;
features->touch_y_max = if (features->type == TABLETPC2FG) {
wacom_le16_to_cpu(&report[i + 3]); /* need to reset back */
features->pktlen = WACOM_PKGLEN_TPC2FG;
features->device_type = BTN_TOOL_TRIPLETAP;
}
features->x_max = features->x_max =
wacom_le16_to_cpu(&report[i + 3]);
features->x_phy =
wacom_le16_to_cpu(&report[i + 6]); wacom_le16_to_cpu(&report[i + 6]);
i += 7; features->unit = report[i + 9];
features->unitExpo = report[i + 11];
i += 12;
} else if (pen) { } else if (pen) {
/* penabled only accepts exact bytes of data */
if (features->type == TABLETPC2FG)
features->pktlen = WACOM_PKGLEN_PENABLED;
features->device_type = BTN_TOOL_PEN;
features->x_max = features->x_max =
wacom_le16_to_cpu(&report[i + 3]); wacom_le16_to_cpu(&report[i + 3]);
i += 4; i += 4;
...@@ -350,10 +384,35 @@ static int wacom_parse_hid(struct usb_interface *intf, struct hid_descriptor *hi ...@@ -350,10 +384,35 @@ static int wacom_parse_hid(struct usb_interface *intf, struct hid_descriptor *hi
break; break;
case HID_USAGE_Y: case HID_USAGE_Y:
if (usage == WCM_DESKTOP) if (usage == WCM_DESKTOP) {
features->y_max = if (finger) {
wacom_le16_to_cpu(&report[i + 3]); features->device_type = BTN_TOOL_DOUBLETAP;
i += 4; if (features->type == TABLETPC2FG) {
/* need to reset back */
features->pktlen = WACOM_PKGLEN_TPC2FG;
features->device_type = BTN_TOOL_TRIPLETAP;
features->y_max =
wacom_le16_to_cpu(&report[i + 3]);
features->y_phy =
wacom_le16_to_cpu(&report[i + 6]);
i += 7;
} else {
features->y_max =
features->x_max;
features->y_phy =
wacom_le16_to_cpu(&report[i + 3]);
i += 4;
}
} else if (pen) {
/* penabled only accepts exact bytes of data */
if (features->type == TABLETPC2FG)
features->pktlen = WACOM_PKGLEN_PENABLED;
features->device_type = BTN_TOOL_PEN;
features->y_max =
wacom_le16_to_cpu(&report[i + 3]);
i += 4;
}
}
break; break;
case HID_USAGE_FINGER: case HID_USAGE_FINGER:
...@@ -376,7 +435,7 @@ static int wacom_parse_hid(struct usb_interface *intf, struct hid_descriptor *hi ...@@ -376,7 +435,7 @@ static int wacom_parse_hid(struct usb_interface *intf, struct hid_descriptor *hi
break; break;
case HID_COLLECTION: case HID_COLLECTION:
/* reset UsagePage ans Finger */ /* reset UsagePage and Finger */
finger = usage = 0; finger = usage = 0;
break; break;
} }
...@@ -388,43 +447,92 @@ static int wacom_parse_hid(struct usb_interface *intf, struct hid_descriptor *hi ...@@ -388,43 +447,92 @@ static int wacom_parse_hid(struct usb_interface *intf, struct hid_descriptor *hi
return result; 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; unsigned char *rep_data;
int limit = 0; int limit = 0, report_id = 2;
int error; int error = -ENOMEM;
rep_data = kmalloc(2, GFP_KERNEL); rep_data = kmalloc(2, GFP_KERNEL);
if (!rep_data) if (!rep_data)
return -ENOMEM; return error;
do { /* ask to report tablet data if it is 2FGT or not a Tablet PC */
rep_data[0] = 2; if (features->device_type == BTN_TOOL_TRIPLETAP) {
rep_data[1] = 2; do {
error = usb_set_report(intf, WAC_HID_FEATURE_REPORT, rep_data[0] = 3;
2, rep_data, 2); rep_data[1] = 4;
if (error >= 0) report_id = 3;
error = usb_get_report(intf, error = usb_set_report(intf, WAC_HID_FEATURE_REPORT,
WAC_HID_FEATURE_REPORT, 2, report_id, rep_data, 2);
rep_data, 2); if (error >= 0)
} while ((error < 0 || rep_data[1] != 2) && limit++ < 5); 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); kfree(rep_data);
return error < 0 ? error : 0; 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;
}
static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *id) static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *id)
{ {
struct usb_device *dev = interface_to_usbdev(intf); struct usb_device *dev = interface_to_usbdev(intf);
struct usb_host_interface *interface = intf->cur_altsetting;
struct usb_endpoint_descriptor *endpoint; struct usb_endpoint_descriptor *endpoint;
struct wacom *wacom; struct wacom *wacom;
struct wacom_wac *wacom_wac; struct wacom_wac *wacom_wac;
struct wacom_features *features; struct wacom_features *features;
struct input_dev *input_dev; struct input_dev *input_dev;
int error = -ENOMEM; int error = -ENOMEM;
struct hid_descriptor *hid_desc;
wacom = kzalloc(sizeof(struct wacom), GFP_KERNEL); wacom = kzalloc(sizeof(struct wacom), GFP_KERNEL);
wacom_wac = kzalloc(sizeof(struct wacom_wac), GFP_KERNEL); wacom_wac = kzalloc(sizeof(struct wacom_wac), GFP_KERNEL);
...@@ -432,7 +540,7 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i ...@@ -432,7 +540,7 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i
if (!wacom || !input_dev || !wacom_wac) if (!wacom || !input_dev || !wacom_wac)
goto fail1; goto fail1;
wacom_wac->data = usb_buffer_alloc(dev, 10, GFP_KERNEL, &wacom->data_dma); wacom_wac->data = usb_buffer_alloc(dev, WACOM_PKGLEN_MAX, GFP_KERNEL, &wacom->data_dma);
if (!wacom_wac->data) if (!wacom_wac->data)
goto fail1; goto fail1;
...@@ -448,7 +556,7 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i ...@@ -448,7 +556,7 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i
strlcat(wacom->phys, "/input0", sizeof(wacom->phys)); strlcat(wacom->phys, "/input0", sizeof(wacom->phys));
wacom_wac->features = features = get_wacom_feature(id); wacom_wac->features = features = get_wacom_feature(id);
BUG_ON(features->pktlen > 10); BUG_ON(features->pktlen > WACOM_PKGLEN_MAX);
input_dev->name = wacom_wac->features->name; input_dev->name = wacom_wac->features->name;
wacom->wacom_wac = wacom_wac; wacom->wacom_wac = wacom_wac;
...@@ -463,47 +571,24 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i ...@@ -463,47 +571,24 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i
endpoint = &intf->cur_altsetting->endpoint[0].desc; endpoint = &intf->cur_altsetting->endpoint[0].desc;
/* Initialize touch_x_max and touch_y_max in case it is not defined */ /* Retrieve the physical and logical size for OEM devices */
if (wacom_wac->features->type == TABLETPC) { error = wacom_retrieve_hid_descriptor(intf, features);
features->touch_x_max = 1023; if (error)
features->touch_y_max = 1023; goto fail2;
} else {
features->touch_x_max = 0;
features->touch_y_max = 0;
}
/* 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->evbit[0] |= BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
input_dev->keybit[BIT_WORD(BTN_DIGI)] |= BIT_MASK(BTN_TOOL_PEN) | input_dev->keybit[BIT_WORD(BTN_DIGI)] |= BIT_MASK(BTN_TOUCH);
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_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_Y, 0, features->y_max, 4, 0);
input_set_abs_params(input_dev, ABS_PRESSURE, 0, features->pressure_max, 0, 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->absbit[BIT_WORD(ABS_MISC)] |= BIT_MASK(ABS_MISC);
wacom_init_input_dev(input_dev, wacom_wac); wacom_init_input_dev(input_dev, wacom_wac);
usb_fill_int_urb(wacom->irq, dev, usb_fill_int_urb(wacom->irq, dev,
usb_rcvintpipe(dev, endpoint->bEndpointAddress), usb_rcvintpipe(dev, endpoint->bEndpointAddress),
wacom_wac->data, wacom_wac->features->pktlen, wacom_wac->data, features->pktlen,
wacom_sys_irq, wacom, endpoint->bInterval); wacom_sys_irq, wacom, endpoint->bInterval);
wacom->irq->transfer_dma = wacom->data_dma; wacom->irq->transfer_dma = wacom->data_dma;
wacom->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; wacom->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
...@@ -512,18 +597,14 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i ...@@ -512,18 +597,14 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i
if (error) if (error)
goto fail3; goto fail3;
/* /* Note that if query fails it is not a hard failure */
* Ask the tablet to report tablet data if it is not a Tablet PC. wacom_query_tablet_data(intf, features);
* Note that if query fails it is not a hard failure.
*/
if (wacom_wac->features->type != TABLETPC)
wacom_query_tablet_data(intf);
usb_set_intfdata(intf, wacom); usb_set_intfdata(intf, wacom);
return 0; return 0;
fail3: usb_free_urb(wacom->irq); 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); fail1: input_free_device(input_dev);
kfree(wacom); kfree(wacom);
kfree(wacom_wac); kfree(wacom_wac);
...@@ -539,7 +620,7 @@ static void wacom_disconnect(struct usb_interface *intf) ...@@ -539,7 +620,7 @@ static void wacom_disconnect(struct usb_interface *intf)
usb_kill_urb(wacom->irq); usb_kill_urb(wacom->irq);
input_unregister_device(wacom->dev); input_unregister_device(wacom->dev);
usb_free_urb(wacom->irq); usb_free_urb(wacom->irq);
usb_buffer_free(interface_to_usbdev(intf), 10, usb_buffer_free(interface_to_usbdev(intf), WACOM_PKGLEN_MAX,
wacom->wacom_wac->data, wacom->data_dma); wacom->wacom_wac->data, wacom->data_dma);
kfree(wacom->wacom_wac); kfree(wacom->wacom_wac);
kfree(wacom); kfree(wacom);
...@@ -559,12 +640,15 @@ static int wacom_suspend(struct usb_interface *intf, pm_message_t message) ...@@ -559,12 +640,15 @@ static int wacom_suspend(struct usb_interface *intf, pm_message_t message)
static int wacom_resume(struct usb_interface *intf) static int wacom_resume(struct usb_interface *intf)
{ {
struct wacom *wacom = usb_get_intfdata(intf); struct wacom *wacom = usb_get_intfdata(intf);
struct wacom_features *features = wacom->wacom_wac->features;
int rv; int rv;
mutex_lock(&wacom->lock); mutex_lock(&wacom->lock);
if (wacom->open) { if (wacom->open) {
rv = usb_submit_urb(wacom->irq, GFP_NOIO); rv = usb_submit_urb(wacom->irq, GFP_NOIO);
wacom_query_tablet_data(intf); /* switch to wacom mode if needed */
if (!wacom_retrieve_hid_descriptor(intf, features))
wacom_query_tablet_data(intf, features);
} else } else
rv = 0; rv = 0;
mutex_unlock(&wacom->lock); mutex_unlock(&wacom->lock);
......
...@@ -65,9 +65,8 @@ static int wacom_pl_irq(struct wacom_wac *wacom, void *wcombo) ...@@ -65,9 +65,8 @@ static int wacom_pl_irq(struct wacom_wac *wacom, void *wcombo)
prox = data[1] & 0x40; prox = data[1] & 0x40;
wacom->id[0] = ERASER_DEVICE_ID;
if (prox) { if (prox) {
wacom->id[0] = ERASER_DEVICE_ID;
pressure = (signed char)((data[7] << 1) | ((data[4] >> 2) & 1)); pressure = (signed char)((data[7] << 1) | ((data[4] >> 2) & 1));
if (wacom->features->pressure_max > 255) if (wacom->features->pressure_max > 255)
pressure = (pressure << 1) | ((data[4] >> 6) & 1); pressure = (pressure << 1) | ((data[4] >> 6) & 1);
...@@ -608,54 +607,146 @@ static int wacom_intuos_irq(struct wacom_wac *wacom, void *wcombo) ...@@ -608,54 +607,146 @@ static int wacom_intuos_irq(struct wacom_wac *wacom, void *wcombo)
return 1; return 1;
} }
static void wacom_tpc_finger_in(struct wacom_wac *wacom, void *wcombo, char *data, int idx)
{
wacom_report_abs(wcombo, ABS_X,
(data[2 + idx * 2] & 0xff) | ((data[3 + idx * 2] & 0x7f) << 8));
wacom_report_abs(wcombo, ABS_Y,
(data[6 + idx * 2] & 0xff) | ((data[7 + idx * 2] & 0x7f) << 8));
wacom_report_abs(wcombo, ABS_MISC, wacom->id[0]);
wacom_report_key(wcombo, wacom->tool[idx], 1);
if (idx)
wacom_input_event(wcombo, EV_MSC, MSC_SERIAL, 0xf0);
else
wacom_report_key(wcombo, BTN_TOUCH, 1);
}
static void wacom_tpc_touch_out(struct wacom_wac *wacom, void *wcombo, int idx)
{
wacom_report_abs(wcombo, ABS_X, 0);
wacom_report_abs(wcombo, ABS_Y, 0);
wacom_report_abs(wcombo, ABS_MISC, 0);
wacom_report_key(wcombo, wacom->tool[idx], 0);
if (idx)
wacom_input_event(wcombo, EV_MSC, MSC_SERIAL, 0xf0);
else
wacom_report_key(wcombo, BTN_TOUCH, 0);
return;
}
static void wacom_tpc_touch_in(struct wacom_wac *wacom, void *wcombo)
{
char *data = wacom->data;
struct urb *urb = ((struct wacom_combo *)wcombo)->urb;
static int firstFinger = 0;
static int secondFinger = 0;
wacom->tool[0] = BTN_TOOL_DOUBLETAP;
wacom->id[0] = TOUCH_DEVICE_ID;
wacom->tool[1] = BTN_TOOL_TRIPLETAP;
if (urb->actual_length != WACOM_PKGLEN_TPC1FG) {
switch (data[0]) {
case 6:
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]));
wacom_report_abs(wcombo, ABS_MISC, wacom->id[0]);
wacom_report_key(wcombo, wacom->tool[0], 1);
break;
case 13:
/* keep this byte to send proper out-prox event */
wacom->id[1] = data[1] & 0x03;
if (data[1] & 0x01) {
wacom_tpc_finger_in(wacom, wcombo, data, 0);
firstFinger = 1;
} else if (firstFinger) {
wacom_tpc_touch_out(wacom, wcombo, 0);
}
if (data[1] & 0x02) {
/* sync first finger data */
if (firstFinger)
wacom_input_sync(wcombo);
wacom_tpc_finger_in(wacom, wcombo, data, 1);
secondFinger = 1;
} else if (secondFinger) {
/* sync first finger data */
if (firstFinger)
wacom_input_sync(wcombo);
wacom_tpc_touch_out(wacom, wcombo, 1);
secondFinger = 0;
}
if (!(data[1] & 0x01))
firstFinger = 0;
break;
}
} 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[0], 1);
}
return;
}
static int wacom_tpc_irq(struct wacom_wac *wacom, void *wcombo) static int wacom_tpc_irq(struct wacom_wac *wacom, void *wcombo)
{ {
char *data = wacom->data; char *data = wacom->data;
int prox = 0, pressure; int prox = 0, pressure, idx = -1;
static int stylusInProx, touchInProx = 1, touchOut; static int stylusInProx, touchInProx = 1, touchOut;
struct urb *urb = ((struct wacom_combo *)wcombo)->urb; struct urb *urb = ((struct wacom_combo *)wcombo)->urb;
dbg("wacom_tpc_irq: received report #%d", data[0]); dbg("wacom_tpc_irq: received report #%d", data[0]);
if (urb->actual_length == WACOM_PKGLEN_TPC1FG || data[0] == 6) { /* Touch data */ if (urb->actual_length == WACOM_PKGLEN_TPC1FG ||
data[0] == 6 || /* single touch */
data[0] == 13) { /* 2FG touch */
if (urb->actual_length == WACOM_PKGLEN_TPC1FG) { /* with touch */ if (urb->actual_length == WACOM_PKGLEN_TPC1FG) { /* with touch */
prox = data[0] & 0x03; prox = data[0] & 0x01;
} else { /* with capacity */ } else { /* with capacity */
prox = data[1] & 0x03; if (data[0] == 6)
/* single touch */
prox = data[1] & 0x01;
else
/* 2FG touch data */
prox = data[1] & 0x03;
} }
if (!stylusInProx) { /* stylus not in prox */ if (!stylusInProx) { /* stylus not in prox */
if (prox) { if (prox) {
if (touchInProx) { if (touchInProx) {
wacom->tool[1] = BTN_TOOL_DOUBLETAP; wacom_tpc_touch_in(wacom, wcombo);
wacom->id[0] = TOUCH_DEVICE_ID;
if (urb->actual_length != WACOM_PKGLEN_TPC1FG) {
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; touchOut = 1;
return 1; return 1;
} }
} else { } else {
wacom_report_abs(wcombo, ABS_MISC, wacom->id[0]); /* 2FGT out-prox */
wacom_report_key(wcombo, wacom->tool[1], prox & 0x01); if ((data[0] & 0xff) == 13) {
wacom_report_key(wcombo, BTN_TOUCH, 0); idx = (wacom->id[1] & 0x01) - 1;
if (idx == 0) {
wacom_tpc_touch_out(wacom, wcombo, idx);
/* sync first finger event */
if (wacom->id[1] & 0x02)
wacom_input_sync(wcombo);
}
idx = (wacom->id[1] & 0x02) - 1;
if (idx == 1)
wacom_tpc_touch_out(wacom, wcombo, idx);
} else /* one finger touch */
wacom_tpc_touch_out(wacom, wcombo, 0);
touchOut = 0; touchOut = 0;
touchInProx = 1; touchInProx = 1;
return 1; return 1;
} }
} else if (touchOut || !prox) { /* force touch out-prox */ } else if (touchOut || !prox) { /* force touch out-prox */
wacom_report_abs(wcombo, ABS_MISC, TOUCH_DEVICE_ID); wacom_tpc_touch_out(wacom, wcombo, 0);
wacom_report_key(wcombo, wacom->tool[1], 0);
wacom_report_key(wcombo, BTN_TOUCH, 0);
touchOut = 0; touchOut = 0;
touchInProx = 1; touchInProx = 1;
return 1; return 1;
...@@ -665,38 +756,14 @@ static int wacom_tpc_irq(struct wacom_wac *wacom, void *wcombo) ...@@ -665,38 +756,14 @@ static int wacom_tpc_irq(struct wacom_wac *wacom, void *wcombo)
touchInProx = 0; 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 (prox) { /* in prox */
if (!wacom->tool[0]) { if (!wacom->id[0]) {
/* Going into proximity select tool */ /* Going into proximity select tool */
wacom->tool[1] = (data[1] & 0x08) ? BTN_TOOL_RUBBER : BTN_TOOL_PEN; wacom->tool[0] = (data[1] & 0x0c) ? BTN_TOOL_RUBBER : BTN_TOOL_PEN;
if (wacom->tool[1] == BTN_TOOL_PEN) if (wacom->tool[0] == BTN_TOOL_PEN)
wacom->id[0] = STYLUS_DEVICE_ID; wacom->id[0] = STYLUS_DEVICE_ID;
} else if (wacom->tool[1] == BTN_TOOL_RUBBER && !(data[1] & 0x08)) { else
/* wacom->id[0] = ERASER_DEVICE_ID;
* 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_STYLUS, data[1] & 0x02);
wacom_report_key(wcombo, BTN_STYLUS2, data[1] & 0x10); wacom_report_key(wcombo, BTN_STYLUS2, data[1] & 0x10);
...@@ -706,17 +773,21 @@ static int wacom_tpc_irq(struct wacom_wac *wacom, void *wcombo) ...@@ -706,17 +773,21 @@ static int wacom_tpc_irq(struct wacom_wac *wacom, void *wcombo)
if (pressure < 0) if (pressure < 0)
pressure = wacom->features->pressure_max + pressure + 1; pressure = wacom->features->pressure_max + pressure + 1;
wacom_report_abs(wcombo, ABS_PRESSURE, pressure); wacom_report_abs(wcombo, ABS_PRESSURE, pressure);
wacom_report_key(wcombo, BTN_TOUCH, pressure); wacom_report_key(wcombo, BTN_TOUCH, data[1] & 0x05);
} else { } else {
wacom_report_abs(wcombo, ABS_X, 0);
wacom_report_abs(wcombo, ABS_Y, 0);
wacom_report_abs(wcombo, ABS_PRESSURE, 0); wacom_report_abs(wcombo, ABS_PRESSURE, 0);
wacom_report_key(wcombo, BTN_STYLUS, 0); wacom_report_key(wcombo, BTN_STYLUS, 0);
wacom_report_key(wcombo, BTN_STYLUS2, 0); wacom_report_key(wcombo, BTN_STYLUS2, 0);
wacom_report_key(wcombo, BTN_TOUCH, 0); wacom_report_key(wcombo, BTN_TOUCH, 0);
wacom->id[0] = 0;
/* pen is out so touch can be enabled now */
touchInProx = 1;
} }
wacom_report_key(wcombo, wacom->tool[1], prox); wacom_report_key(wcombo, wacom->tool[0], prox);
wacom_report_abs(wcombo, ABS_MISC, wacom->id[0]); wacom_report_abs(wcombo, ABS_MISC, wacom->id[0]);
stylusInProx = prox; stylusInProx = prox;
wacom->tool[0] = prox;
return 1; return 1;
} }
return 0; return 0;
...@@ -751,6 +822,7 @@ int wacom_wac_irq(struct wacom_wac *wacom_wac, void *wcombo) ...@@ -751,6 +822,7 @@ int wacom_wac_irq(struct wacom_wac *wacom_wac, void *wcombo)
return wacom_intuos_irq(wacom_wac, wcombo); return wacom_intuos_irq(wacom_wac, wcombo);
case TABLETPC: case TABLETPC:
case TABLETPC2FG:
return wacom_tpc_irq(wacom_wac, wcombo); return wacom_tpc_irq(wacom_wac, wcombo);
default: default:
...@@ -791,9 +863,17 @@ void wacom_init_input_dev(struct input_dev *input_dev, struct wacom_wac *wacom_w ...@@ -791,9 +863,17 @@ void wacom_init_input_dev(struct input_dev *input_dev, struct wacom_wac *wacom_w
input_dev_i4s(input_dev, wacom_wac); input_dev_i4s(input_dev, wacom_wac);
input_dev_i(input_dev, wacom_wac); input_dev_i(input_dev, wacom_wac);
break; break;
case TABLETPC2FG:
input_dev_tpc2fg(input_dev, wacom_wac);
/* fall through */
case TABLETPC:
input_dev_tpc(input_dev, wacom_wac);
if (wacom_wac->features->device_type != BTN_TOOL_PEN)
break; /* no need to process stylus stuff */
/* fall through */
case PL: case PL:
case PTU: case PTU:
case TABLETPC:
input_dev_pl(input_dev, wacom_wac); input_dev_pl(input_dev, wacom_wac);
/* fall through */ /* fall through */
case PENPARTNER: case PENPARTNER:
...@@ -863,6 +943,9 @@ static struct wacom_features wacom_features[] = { ...@@ -863,6 +943,9 @@ static struct wacom_features wacom_features[] = {
{ "Wacom ISDv4 90", WACOM_PKGLEN_GRAPHIRE, 26202, 16325, 255, 0, TABLETPC }, { "Wacom ISDv4 90", WACOM_PKGLEN_GRAPHIRE, 26202, 16325, 255, 0, TABLETPC },
{ "Wacom ISDv4 93", WACOM_PKGLEN_GRAPHIRE, 26202, 16325, 255, 0, TABLETPC }, { "Wacom ISDv4 93", WACOM_PKGLEN_GRAPHIRE, 26202, 16325, 255, 0, TABLETPC },
{ "Wacom ISDv4 9A", WACOM_PKGLEN_GRAPHIRE, 26202, 16325, 255, 0, TABLETPC }, { "Wacom ISDv4 9A", WACOM_PKGLEN_GRAPHIRE, 26202, 16325, 255, 0, TABLETPC },
{ "Wacom ISDv4 9F", WACOM_PKGLEN_PENABLED, 26202, 16325, 255, 0, TABLETPC },
{ "Wacom ISDv4 E2", WACOM_PKGLEN_TPC2FG, 26202, 16325, 255, 0, TABLETPC2FG },
{ "Wacom ISDv4 E3", WACOM_PKGLEN_TPC2FG, 26202, 16325, 255, 0, TABLETPC2FG },
{ "Wacom Intuos2 6x8", WACOM_PKGLEN_INTUOS, 20320, 16240, 1023, 31, INTUOS }, { "Wacom Intuos2 6x8", WACOM_PKGLEN_INTUOS, 20320, 16240, 1023, 31, INTUOS },
{ } { }
}; };
...@@ -927,6 +1010,9 @@ static struct usb_device_id wacom_ids[] = { ...@@ -927,6 +1010,9 @@ static struct usb_device_id wacom_ids[] = {
{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0x90) }, { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x90) },
{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0x93) }, { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x93) },
{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0x9A) }, { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x9A) },
{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0x9F) },
{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0xE2) },
{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0xE3) },
{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0x47) }, { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x47) },
{ } { }
}; };
......
...@@ -19,7 +19,9 @@ ...@@ -19,7 +19,9 @@
#define WACOM_PKGLEN_INTUOS 10 #define WACOM_PKGLEN_INTUOS 10
#define WACOM_PKGLEN_PENABLED 8 #define WACOM_PKGLEN_PENABLED 8
#define WACOM_PKGLEN_TPC1FG 5 #define WACOM_PKGLEN_TPC1FG 5
#define WACOM_PKGLEN_TPC2FG 14
/* device IDs */
#define STYLUS_DEVICE_ID 0x02 #define STYLUS_DEVICE_ID 0x02
#define TOUCH_DEVICE_ID 0x03 #define TOUCH_DEVICE_ID 0x03
#define CURSOR_DEVICE_ID 0x06 #define CURSOR_DEVICE_ID 0x06
...@@ -43,6 +45,7 @@ enum { ...@@ -43,6 +45,7 @@ enum {
WACOM_BEE, WACOM_BEE,
WACOM_MO, WACOM_MO,
TABLETPC, TABLETPC,
TABLETPC2FG,
MAX_TYPE MAX_TYPE
}; };
...@@ -54,8 +57,11 @@ struct wacom_features { ...@@ -54,8 +57,11 @@ struct wacom_features {
int pressure_max; int pressure_max;
int distance_max; int distance_max;
int type; int type;
int touch_x_max; int device_type;
int touch_y_max; int x_phy;
int y_phy;
unsigned char unit;
unsigned char unitExpo;
}; };
struct wacom_wac { struct wacom_wac {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment