diff options
Diffstat (limited to 'drivers/input/tablet')
-rw-r--r-- | drivers/input/tablet/acecad.c | 15 | ||||
-rw-r--r-- | drivers/input/tablet/aiptek.c | 30 | ||||
-rw-r--r-- | drivers/input/tablet/gtco.c | 110 | ||||
-rw-r--r-- | drivers/input/tablet/kbtab.c | 15 | ||||
-rw-r--r-- | drivers/input/tablet/wacom.h | 4 | ||||
-rw-r--r-- | drivers/input/tablet/wacom_sys.c | 257 | ||||
-rw-r--r-- | drivers/input/tablet/wacom_wac.c | 298 | ||||
-rw-r--r-- | drivers/input/tablet/wacom_wac.h | 13 |
8 files changed, 563 insertions, 179 deletions
diff --git a/drivers/input/tablet/acecad.c b/drivers/input/tablet/acecad.c index f8b0b1df9138..e062ec899ca1 100644 --- a/drivers/input/tablet/acecad.c +++ b/drivers/input/tablet/acecad.c @@ -51,6 +51,7 @@ struct usb_acecad { char name[128]; char phys[64]; struct usb_device *usbdev; + struct usb_interface *intf; struct input_dev *input; struct urb *irq; @@ -63,6 +64,7 @@ static void usb_acecad_irq(struct urb *urb) struct usb_acecad *acecad = urb->context; unsigned char *data = acecad->data; struct input_dev *dev = acecad->input; + struct usb_interface *intf = acecad->intf; int prox, status; switch (urb->status) { @@ -73,10 +75,12 @@ static void usb_acecad_irq(struct urb *urb) case -ENOENT: case -ESHUTDOWN: /* this urb is terminated, clean up */ - dbg("%s - urb shutting down with status: %d", __func__, urb->status); + dev_dbg(&intf->dev, "%s - urb shutting down with status: %d\n", + __func__, urb->status); return; default: - dbg("%s - nonzero urb status received: %d", __func__, urb->status); + dev_dbg(&intf->dev, "%s - nonzero urb status received: %d\n", + __func__, urb->status); goto resubmit; } @@ -105,8 +109,10 @@ static void usb_acecad_irq(struct urb *urb) resubmit: status = usb_submit_urb(urb, GFP_ATOMIC); if (status) - err("can't resubmit intr, %s-%s/input0, status %d", - acecad->usbdev->bus->bus_name, acecad->usbdev->devpath, status); + dev_err(&intf->dev, + "can't resubmit intr, %s-%s/input0, status %d\n", + acecad->usbdev->bus->bus_name, + acecad->usbdev->devpath, status); } static int usb_acecad_open(struct input_dev *dev) @@ -168,6 +174,7 @@ static int usb_acecad_probe(struct usb_interface *intf, const struct usb_device_ } acecad->usbdev = dev; + acecad->intf = intf; acecad->input = input_dev; if (dev->manufacturer) diff --git a/drivers/input/tablet/aiptek.c b/drivers/input/tablet/aiptek.c index 205d16aab441..ee83c3904ee8 100644 --- a/drivers/input/tablet/aiptek.c +++ b/drivers/input/tablet/aiptek.c @@ -309,6 +309,7 @@ struct aiptek_settings { struct aiptek { struct input_dev *inputdev; /* input device struct */ struct usb_device *usbdev; /* usb device struct */ + struct usb_interface *intf; /* usb interface struct */ struct urb *urb; /* urb for incoming reports */ dma_addr_t data_dma; /* our dma stuffage */ struct aiptek_features features; /* tablet's array of features */ @@ -435,6 +436,7 @@ static void aiptek_irq(struct urb *urb) struct aiptek *aiptek = urb->context; unsigned char *data = aiptek->data; struct input_dev *inputdev = aiptek->inputdev; + struct usb_interface *intf = aiptek->intf; int jitterable = 0; int retval, macro, x, y, z, left, right, middle, p, dv, tip, bs, pck; @@ -447,13 +449,13 @@ static void aiptek_irq(struct urb *urb) case -ENOENT: case -ESHUTDOWN: /* This urb is terminated, clean up */ - dbg("%s - urb shutting down with status: %d", - __func__, urb->status); + dev_dbg(&intf->dev, "%s - urb shutting down with status: %d\n", + __func__, urb->status); return; default: - dbg("%s - nonzero urb status received: %d", - __func__, urb->status); + dev_dbg(&intf->dev, "%s - nonzero urb status received: %d\n", + __func__, urb->status); goto exit; } @@ -785,7 +787,7 @@ static void aiptek_irq(struct urb *urb) 1 | AIPTEK_REPORT_TOOL_UNKNOWN); input_sync(inputdev); } else { - dbg("Unknown report %d", data[0]); + dev_dbg(&intf->dev, "Unknown report %d\n", data[0]); } /* Jitter may occur when the user presses a button on the stlyus @@ -811,8 +813,9 @@ static void aiptek_irq(struct urb *urb) exit: retval = usb_submit_urb(urb, GFP_ATOMIC); if (retval != 0) { - err("%s - usb_submit_urb failed with result %d", - __func__, retval); + dev_err(&intf->dev, + "%s - usb_submit_urb failed with result %d\n", + __func__, retval); } } @@ -912,8 +915,9 @@ aiptek_command(struct aiptek *aiptek, unsigned char command, unsigned char data) if ((ret = aiptek_set_report(aiptek, 3, 2, buf, sizeof_buf)) != sizeof_buf) { - dbg("aiptek_program: failed, tried to send: 0x%02x 0x%02x", - command, data); + dev_dbg(&aiptek->intf->dev, + "aiptek_program: failed, tried to send: 0x%02x 0x%02x\n", + command, data); } kfree(buf); return ret < 0 ? ret : 0; @@ -947,8 +951,9 @@ aiptek_query(struct aiptek *aiptek, unsigned char command, unsigned char data) if ((ret = aiptek_get_report(aiptek, 3, 2, buf, sizeof_buf)) != sizeof_buf) { - dbg("aiptek_query failed: returned 0x%02x 0x%02x 0x%02x", - buf[0], buf[1], buf[2]); + dev_dbg(&aiptek->intf->dev, + "aiptek_query failed: returned 0x%02x 0x%02x 0x%02x\n", + buf[0], buf[1], buf[2]); ret = -EIO; } else { ret = get_unaligned_le16(buf + 1); @@ -1726,6 +1731,7 @@ aiptek_probe(struct usb_interface *intf, const struct usb_device_id *id) aiptek->inputdev = inputdev; aiptek->usbdev = usbdev; + aiptek->intf = intf; aiptek->ifnum = intf->altsetting[0].desc.bInterfaceNumber; aiptek->inDelay = 0; aiptek->endDelay = 0; @@ -1856,7 +1862,7 @@ aiptek_probe(struct usb_interface *intf, const struct usb_device_id *id) if (i == ARRAY_SIZE(speeds)) { dev_info(&intf->dev, "Aiptek tried all speeds, no sane response\n"); - goto fail2; + goto fail3; } /* Associate this driver's struct with the usb interface. diff --git a/drivers/input/tablet/gtco.c b/drivers/input/tablet/gtco.c index 89a297801dce..29e01ab6859f 100644 --- a/drivers/input/tablet/gtco.c +++ b/drivers/input/tablet/gtco.c @@ -2,8 +2,6 @@ GTCO digitizer USB driver -Use the err() and dbg() macros from usb.h for system logging - TO CHECK: Is pressure done right on report 5? Copyright (C) 2006 GTCO CalComp @@ -108,6 +106,7 @@ struct gtco { struct input_dev *inputdevice; /* input device struct pointer */ struct usb_device *usbdev; /* the usb device for this device */ + struct usb_interface *intf; /* the usb interface for this device */ struct urb *urbinfo; /* urb for incoming reports */ dma_addr_t buf_dma; /* dma addr of the data buffer*/ unsigned char * buffer; /* databuffer for reports */ @@ -202,6 +201,7 @@ struct hid_descriptor static void parse_hid_report_descriptor(struct gtco *device, char * report, int length) { + struct device *ddev = &device->intf->dev; int x, i = 0; /* Tag primitive vars */ @@ -228,7 +228,7 @@ static void parse_hid_report_descriptor(struct gtco *device, char * report, char indentstr[10] = ""; - dbg("======>>>>>>PARSE<<<<<<======"); + dev_dbg(ddev, "======>>>>>>PARSE<<<<<<======\n"); /* Walk this report and pull out the info we need */ while (i < length) { @@ -277,11 +277,11 @@ static void parse_hid_report_descriptor(struct gtco *device, char * report, else if (data == 3) strcpy(globtype, "Var|Const"); - dbg("::::: Saving Report: %d input #%d Max: 0x%X(%d) Min:0x%X(%d) of %d bits", - globalval[TAG_GLOB_REPORT_ID], inputnum, - globalval[TAG_GLOB_LOG_MAX], globalval[TAG_GLOB_LOG_MAX], - globalval[TAG_GLOB_LOG_MIN], globalval[TAG_GLOB_LOG_MIN], - globalval[TAG_GLOB_REPORT_SZ] * globalval[TAG_GLOB_REPORT_CNT]); + dev_dbg(ddev, "::::: Saving Report: %d input #%d Max: 0x%X(%d) Min:0x%X(%d) of %d bits\n", + globalval[TAG_GLOB_REPORT_ID], inputnum, + globalval[TAG_GLOB_LOG_MAX], globalval[TAG_GLOB_LOG_MAX], + globalval[TAG_GLOB_LOG_MIN], globalval[TAG_GLOB_LOG_MIN], + globalval[TAG_GLOB_REPORT_SZ] * globalval[TAG_GLOB_REPORT_CNT]); /* @@ -292,7 +292,7 @@ static void parse_hid_report_descriptor(struct gtco *device, char * report, */ switch (inputnum) { case 0: /* X coord */ - dbg("GER: X Usage: 0x%x", usage); + dev_dbg(ddev, "GER: X Usage: 0x%x\n", usage); if (device->max_X == 0) { device->max_X = globalval[TAG_GLOB_LOG_MAX]; device->min_X = globalval[TAG_GLOB_LOG_MIN]; @@ -300,7 +300,7 @@ static void parse_hid_report_descriptor(struct gtco *device, char * report, break; case 1: /* Y coord */ - dbg("GER: Y Usage: 0x%x", usage); + dev_dbg(ddev, "GER: Y Usage: 0x%x\n", usage); if (device->max_Y == 0) { device->max_Y = globalval[TAG_GLOB_LOG_MAX]; device->min_Y = globalval[TAG_GLOB_LOG_MIN]; @@ -350,10 +350,10 @@ static void parse_hid_report_descriptor(struct gtco *device, char * report, maintype = 'S'; if (data == 0) { - dbg("======>>>>>> Physical"); + dev_dbg(ddev, "======>>>>>> Physical\n"); strcpy(globtype, "Physical"); } else - dbg("======>>>>>>"); + dev_dbg(ddev, "======>>>>>>\n"); /* Indent the debug output */ indent++; @@ -368,7 +368,7 @@ static void parse_hid_report_descriptor(struct gtco *device, char * report, break; case TAG_MAIN_COL_END: - dbg("<<<<<<======"); + dev_dbg(ddev, "<<<<<<======\n"); maintype = 'E'; indent--; for (x = 0; x < indent; x++) @@ -384,18 +384,18 @@ static void parse_hid_report_descriptor(struct gtco *device, char * report, switch (size) { case 1: - dbg("%sMAINTAG:(%d) %c SIZE: %d Data: %s 0x%x", - indentstr, tag, maintype, size, globtype, data); + dev_dbg(ddev, "%sMAINTAG:(%d) %c SIZE: %d Data: %s 0x%x\n", + indentstr, tag, maintype, size, globtype, data); break; case 2: - dbg("%sMAINTAG:(%d) %c SIZE: %d Data: %s 0x%x", - indentstr, tag, maintype, size, globtype, data16); + dev_dbg(ddev, "%sMAINTAG:(%d) %c SIZE: %d Data: %s 0x%x\n", + indentstr, tag, maintype, size, globtype, data16); break; case 4: - dbg("%sMAINTAG:(%d) %c SIZE: %d Data: %s 0x%x", - indentstr, tag, maintype, size, globtype, data32); + dev_dbg(ddev, "%sMAINTAG:(%d) %c SIZE: %d Data: %s 0x%x\n", + indentstr, tag, maintype, size, globtype, data32); break; } break; @@ -465,26 +465,26 @@ static void parse_hid_report_descriptor(struct gtco *device, char * report, if (tag < TAG_GLOB_MAX) { switch (size) { case 1: - dbg("%sGLOBALTAG:%s(%d) SIZE: %d Data: 0x%x", - indentstr, globtype, tag, size, data); + dev_dbg(ddev, "%sGLOBALTAG:%s(%d) SIZE: %d Data: 0x%x\n", + indentstr, globtype, tag, size, data); globalval[tag] = data; break; case 2: - dbg("%sGLOBALTAG:%s(%d) SIZE: %d Data: 0x%x", - indentstr, globtype, tag, size, data16); + dev_dbg(ddev, "%sGLOBALTAG:%s(%d) SIZE: %d Data: 0x%x\n", + indentstr, globtype, tag, size, data16); globalval[tag] = data16; break; case 4: - dbg("%sGLOBALTAG:%s(%d) SIZE: %d Data: 0x%x", - indentstr, globtype, tag, size, data32); + dev_dbg(ddev, "%sGLOBALTAG:%s(%d) SIZE: %d Data: 0x%x\n", + indentstr, globtype, tag, size, data32); globalval[tag] = data32; break; } } else { - dbg("%sGLOBALTAG: ILLEGAL TAG:%d SIZE: %d ", - indentstr, tag, size); + dev_dbg(ddev, "%sGLOBALTAG: ILLEGAL TAG:%d SIZE: %d\n", + indentstr, tag, size); } break; @@ -511,18 +511,18 @@ static void parse_hid_report_descriptor(struct gtco *device, char * report, switch (size) { case 1: - dbg("%sLOCALTAG:(%d) %s SIZE: %d Data: 0x%x", - indentstr, tag, globtype, size, data); + dev_dbg(ddev, "%sLOCALTAG:(%d) %s SIZE: %d Data: 0x%x\n", + indentstr, tag, globtype, size, data); break; case 2: - dbg("%sLOCALTAG:(%d) %s SIZE: %d Data: 0x%x", - indentstr, tag, globtype, size, data16); + dev_dbg(ddev, "%sLOCALTAG:(%d) %s SIZE: %d Data: 0x%x\n", + indentstr, tag, globtype, size, data16); break; case 4: - dbg("%sLOCALTAG:(%d) %s SIZE: %d Data: 0x%x", - indentstr, tag, globtype, size, data32); + dev_dbg(ddev, "%sLOCALTAG:(%d) %s SIZE: %d Data: 0x%x\n", + indentstr, tag, globtype, size, data32); break; } @@ -714,8 +714,9 @@ static void gtco_urb_callback(struct urb *urbinfo) * the rest as 0 */ val = device->buffer[5] & MASK_BUTTON; - dbg("======>>>>>>REPORT 1: val 0x%X(%d)", - val, val); + dev_dbg(&device->intf->dev, + "======>>>>>>REPORT 1: val 0x%X(%d)\n", + val, val); /* * We don't apply any meaning to the button @@ -808,7 +809,8 @@ static void gtco_urb_callback(struct urb *urbinfo) resubmit: rc = usb_submit_urb(urbinfo, GFP_ATOMIC); if (rc != 0) - err("usb_submit_urb failed rc=0x%x", rc); + dev_err(&device->intf->dev, + "usb_submit_urb failed rc=0x%x\n", rc); } /* @@ -838,7 +840,7 @@ static int gtco_probe(struct usb_interface *usbinterface, gtco = kzalloc(sizeof(struct gtco), GFP_KERNEL); input_dev = input_allocate_device(); if (!gtco || !input_dev) { - err("No more memory"); + dev_err(&usbinterface->dev, "No more memory\n"); error = -ENOMEM; goto err_free_devs; } @@ -848,12 +850,13 @@ static int gtco_probe(struct usb_interface *usbinterface, /* Save interface information */ gtco->usbdev = usb_get_dev(interface_to_usbdev(usbinterface)); + gtco->intf = usbinterface; /* Allocate some data for incoming reports */ gtco->buffer = usb_alloc_coherent(gtco->usbdev, REPORT_MAX_SIZE, GFP_KERNEL, >co->buf_dma); if (!gtco->buffer) { - err("No more memory for us buffers"); + dev_err(&usbinterface->dev, "No more memory for us buffers\n"); error = -ENOMEM; goto err_free_devs; } @@ -861,7 +864,7 @@ static int gtco_probe(struct usb_interface *usbinterface, /* Allocate URB for reports */ gtco->urbinfo = usb_alloc_urb(0, GFP_KERNEL); if (!gtco->urbinfo) { - err("Failed to allocate URB"); + dev_err(&usbinterface->dev, "Failed to allocate URB\n"); error = -ENOMEM; goto err_free_buf; } @@ -873,14 +876,14 @@ static int gtco_probe(struct usb_interface *usbinterface, endpoint = &usbinterface->altsetting[0].endpoint[0].desc; /* Some debug */ - dbg("gtco # interfaces: %d", usbinterface->num_altsetting); - dbg("num endpoints: %d", usbinterface->cur_altsetting->desc.bNumEndpoints); - dbg("interface class: %d", usbinterface->cur_altsetting->desc.bInterfaceClass); - dbg("endpoint: attribute:0x%x type:0x%x", endpoint->bmAttributes, endpoint->bDescriptorType); + dev_dbg(&usbinterface->dev, "gtco # interfaces: %d\n", usbinterface->num_altsetting); + dev_dbg(&usbinterface->dev, "num endpoints: %d\n", usbinterface->cur_altsetting->desc.bNumEndpoints); + dev_dbg(&usbinterface->dev, "interface class: %d\n", usbinterface->cur_altsetting->desc.bInterfaceClass); + dev_dbg(&usbinterface->dev, "endpoint: attribute:0x%x type:0x%x\n", endpoint->bmAttributes, endpoint->bDescriptorType); if (usb_endpoint_xfer_int(endpoint)) - dbg("endpoint: we have interrupt endpoint\n"); + dev_dbg(&usbinterface->dev, "endpoint: we have interrupt endpoint\n"); - dbg("endpoint extra len:%d ", usbinterface->altsetting[0].extralen); + dev_dbg(&usbinterface->dev, "endpoint extra len:%d\n", usbinterface->altsetting[0].extralen); /* * Find the HID descriptor so we can find out the size of the @@ -888,17 +891,19 @@ static int gtco_probe(struct usb_interface *usbinterface, */ if (usb_get_extra_descriptor(usbinterface->cur_altsetting, HID_DEVICE_TYPE, &hid_desc) != 0){ - err("Can't retrieve exta USB descriptor to get hid report descriptor length"); + dev_err(&usbinterface->dev, + "Can't retrieve exta USB descriptor to get hid report descriptor length\n"); error = -EIO; goto err_free_urb; } - dbg("Extra descriptor success: type:%d len:%d", - hid_desc->bDescriptorType, hid_desc->wDescriptorLength); + dev_dbg(&usbinterface->dev, + "Extra descriptor success: type:%d len:%d\n", + hid_desc->bDescriptorType, hid_desc->wDescriptorLength); report = kzalloc(le16_to_cpu(hid_desc->wDescriptorLength), GFP_KERNEL); if (!report) { - err("No more memory for report"); + dev_err(&usbinterface->dev, "No more memory for report\n"); error = -ENOMEM; goto err_free_urb; } @@ -915,7 +920,7 @@ static int gtco_probe(struct usb_interface *usbinterface, le16_to_cpu(hid_desc->wDescriptorLength), 5000); /* 5 secs */ - dbg("usb_control_msg result: %d", result); + dev_dbg(&usbinterface->dev, "usb_control_msg result: %d\n", result); if (result == le16_to_cpu(hid_desc->wDescriptorLength)) { parse_hid_report_descriptor(gtco, report, result); break; @@ -926,8 +931,9 @@ static int gtco_probe(struct usb_interface *usbinterface, /* If we didn't get the report, fail */ if (result != le16_to_cpu(hid_desc->wDescriptorLength)) { - err("Failed to get HID Report Descriptor of size: %d", - hid_desc->wDescriptorLength); + dev_err(&usbinterface->dev, + "Failed to get HID Report Descriptor of size: %d\n", + hid_desc->wDescriptorLength); error = -EIO; goto err_free_urb; } diff --git a/drivers/input/tablet/kbtab.c b/drivers/input/tablet/kbtab.c index 85a5b40333ac..3fba74b9b602 100644 --- a/drivers/input/tablet/kbtab.c +++ b/drivers/input/tablet/kbtab.c @@ -33,6 +33,7 @@ struct kbtab { dma_addr_t data_dma; struct input_dev *dev; struct usb_device *usbdev; + struct usb_interface *intf; struct urb *irq; char phys[32]; }; @@ -53,10 +54,14 @@ static void kbtab_irq(struct urb *urb) case -ENOENT: case -ESHUTDOWN: /* this urb is terminated, clean up */ - dbg("%s - urb shutting down with status: %d", __func__, urb->status); + dev_dbg(&kbtab->intf->dev, + "%s - urb shutting down with status: %d\n", + __func__, urb->status); return; default: - dbg("%s - nonzero urb status received: %d", __func__, urb->status); + dev_dbg(&kbtab->intf->dev, + "%s - nonzero urb status received: %d\n", + __func__, urb->status); goto exit; } @@ -80,8 +85,9 @@ static void kbtab_irq(struct urb *urb) exit: retval = usb_submit_urb(urb, GFP_ATOMIC); if (retval) - err("%s - usb_submit_urb failed with result %d", - __func__, retval); + dev_err(&kbtab->intf->dev, + "%s - usb_submit_urb failed with result %d\n", + __func__, retval); } static struct usb_device_id kbtab_ids[] = { @@ -131,6 +137,7 @@ static int kbtab_probe(struct usb_interface *intf, const struct usb_device_id *i goto fail2; kbtab->usbdev = dev; + kbtab->intf = intf; kbtab->dev = input_dev; usb_make_path(dev, kbtab->phys, sizeof(kbtab->phys)); diff --git a/drivers/input/tablet/wacom.h b/drivers/input/tablet/wacom.h index b4842d0e61dd..b79d45198d82 100644 --- a/drivers/input/tablet/wacom.h +++ b/drivers/input/tablet/wacom.h @@ -135,6 +135,6 @@ extern const struct usb_device_id wacom_ids[]; void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t len); void wacom_setup_device_quirks(struct wacom_features *features); -void wacom_setup_input_capabilities(struct input_dev *input_dev, - struct wacom_wac *wacom_wac); +int wacom_setup_input_capabilities(struct input_dev *input_dev, + struct wacom_wac *wacom_wac); #endif diff --git a/drivers/input/tablet/wacom_sys.c b/drivers/input/tablet/wacom_sys.c index 0d269212931e..8b31473a81fe 100644 --- a/drivers/input/tablet/wacom_sys.c +++ b/drivers/input/tablet/wacom_sys.c @@ -28,6 +28,7 @@ #define HID_USAGE_Y_TILT 0x3e #define HID_USAGE_FINGER 0x22 #define HID_USAGE_STYLUS 0x20 +#define HID_USAGE_CONTACTMAX 0x55 #define HID_COLLECTION 0xa1 #define HID_COLLECTION_LOGICAL 0x02 #define HID_COLLECTION_END 0xc0 @@ -99,6 +100,7 @@ static int wacom_set_report(struct usb_interface *intf, u8 type, u8 id, static void wacom_sys_irq(struct urb *urb) { struct wacom *wacom = urb->context; + struct device *dev = &wacom->intf->dev; int retval; switch (urb->status) { @@ -109,10 +111,12 @@ static void wacom_sys_irq(struct urb *urb) case -ENOENT: case -ESHUTDOWN: /* this urb is terminated, clean up */ - dbg("%s - urb shutting down with status: %d", __func__, urb->status); + dev_dbg(dev, "%s - urb shutting down with status: %d\n", + __func__, urb->status); return; default: - dbg("%s - nonzero urb status received: %d", __func__, urb->status); + dev_dbg(dev, "%s - nonzero urb status received: %d\n", + __func__, urb->status); goto exit; } @@ -122,8 +126,8 @@ static void wacom_sys_irq(struct urb *urb) usb_mark_last_busy(wacom->usbdev); retval = usb_submit_urb(urb, GFP_ATOMIC); if (retval) - err ("%s - usb_submit_urb failed with result %d", - __func__, retval); + dev_err(dev, "%s - usb_submit_urb failed with result %d\n", + __func__, retval); } static int wacom_open(struct input_dev *dev) @@ -201,6 +205,27 @@ static int wacom_parse_logical_collection(unsigned char *report, return length; } +static void wacom_retrieve_report_data(struct usb_interface *intf, + struct wacom_features *features) +{ + int result = 0; + unsigned char *rep_data; + + rep_data = kmalloc(2, GFP_KERNEL); + if (rep_data) { + + rep_data[0] = 12; + result = wacom_get_report(intf, WAC_HID_FEATURE_REPORT, + rep_data[0], rep_data, 2, + WAC_MSG_RETRIES); + + if (result >= 0 && rep_data[1] > 2) + features->touch_max = rep_data[1]; + + kfree(rep_data); + } +} + /* * Interface Descriptor of wacom devices can be incomplete and * inconsistent so wacom_features table is used to store stylus @@ -233,6 +258,9 @@ static int wacom_parse_logical_collection(unsigned char *report, * 3rd gen Bamboo Touch no longer define a Digitizer-Finger Pysical * Collection. Instead they define a Logical Collection with a single * Logical Maximum for both X and Y. + * + * Intuos5 touch interface does not contain useful data. We deal with + * this after returning from this function. */ static int wacom_parse_hid(struct usb_interface *intf, struct hid_descriptor *hid_desc, @@ -292,6 +320,10 @@ static int wacom_parse_hid(struct usb_interface *intf, /* need to reset back */ features->pktlen = WACOM_PKGLEN_TPC2FG; } + + if (features->type == MTSCREEN) + features->pktlen = WACOM_PKGLEN_MTOUCH; + if (features->type == BAMBOO_PT) { /* need to reset back */ features->pktlen = WACOM_PKGLEN_BBTOUCH; @@ -324,18 +356,15 @@ static int wacom_parse_hid(struct usb_interface *intf, case HID_USAGE_Y: if (usage == WCM_DESKTOP) { if (finger) { - features->device_type = BTN_TOOL_FINGER; - if (features->type == TABLETPC2FG) { - /* need to reset back */ - features->pktlen = WACOM_PKGLEN_TPC2FG; + int type = features->type; + + if (type == TABLETPC2FG || type == MTSCREEN) { features->y_max = get_unaligned_le16(&report[i + 3]); features->y_phy = get_unaligned_le16(&report[i + 6]); i += 7; - } else if (features->type == BAMBOO_PT) { - /* need to reset back */ - features->pktlen = WACOM_PKGLEN_BBTOUCH; + } else if (type == BAMBOO_PT) { features->y_phy = get_unaligned_le16(&report[i + 3]); features->y_max = @@ -349,10 +378,6 @@ static int wacom_parse_hid(struct usb_interface *intf, 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; @@ -374,6 +399,13 @@ static int wacom_parse_hid(struct usb_interface *intf, pen = 1; i++; break; + + case HID_USAGE_CONTACTMAX: + /* leave touch_max as is if predefined */ + if (!features->touch_max) + wacom_retrieve_report_data(intf, features); + i++; + break; } break; @@ -410,22 +442,29 @@ static int wacom_query_tablet_data(struct usb_interface *intf, struct wacom_feat if (!rep_data) return error; - /* ask to report tablet data if it is MT Tablet PC or - * not a Tablet PC */ - if (features->type == TABLETPC2FG) { - do { - rep_data[0] = 3; - rep_data[1] = 4; - rep_data[2] = 0; - rep_data[3] = 0; - report_id = 3; - error = wacom_set_report(intf, WAC_HID_FEATURE_REPORT, - report_id, rep_data, 4, 1); - if (error >= 0) - error = wacom_get_report(intf, - WAC_HID_FEATURE_REPORT, - report_id, rep_data, 4, 1); - } while ((error < 0 || rep_data[1] != 4) && limit++ < WAC_MSG_RETRIES); + /* ask to report Wacom data */ + if (features->device_type == BTN_TOOL_FINGER) { + /* if it is an MT Tablet PC touch */ + if (features->type == TABLETPC2FG || + features->type == MTSCREEN) { + do { + rep_data[0] = 3; + rep_data[1] = 4; + rep_data[2] = 0; + rep_data[3] = 0; + report_id = 3; + error = wacom_set_report(intf, + WAC_HID_FEATURE_REPORT, + report_id, + rep_data, 4, 1); + if (error >= 0) + error = wacom_get_report(intf, + WAC_HID_FEATURE_REPORT, + report_id, + rep_data, 4, 1); + } while ((error < 0 || rep_data[1] != 4) && + limit++ < WAC_MSG_RETRIES); + } } else if (features->type != TABLETPC && features->type != WIRELESS && features->device_type == BTN_TOOL_PEN) { @@ -447,7 +486,7 @@ static int wacom_query_tablet_data(struct usb_interface *intf, struct wacom_feat } static int wacom_retrieve_hid_descriptor(struct usb_interface *intf, - struct wacom_features *features) + struct wacom_features *features) { int error = 0; struct usb_host_interface *interface = intf->cur_altsetting; @@ -475,16 +514,21 @@ static int wacom_retrieve_hid_descriptor(struct usb_interface *intf, } } - /* only Tablet PCs and Bamboo P&T need to retrieve the info */ - if ((features->type != TABLETPC) && (features->type != TABLETPC2FG) && - (features->type != BAMBOO_PT)) + /* only devices that support touch need to retrieve the info */ + if (features->type != TABLETPC && + features->type != TABLETPC2FG && + features->type != BAMBOO_PT && + features->type != MTSCREEN) { 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; + error = usb_get_extra_descriptor(interface, HID_DEVICET_HID, &hid_desc); + if (error) { + error = usb_get_extra_descriptor(&interface->endpoint[0], + HID_DEVICET_REPORT, &hid_desc); + if (error) { + dev_err(&intf->dev, + "can not retrieve extra class descriptor\n"); goto out; } } @@ -574,23 +618,39 @@ static void wacom_remove_shared_data(struct wacom_wac *wacom) static int wacom_led_control(struct wacom *wacom) { unsigned char *buf; - int retval, led = 0; + int retval; buf = kzalloc(9, GFP_KERNEL); if (!buf) return -ENOMEM; - if (wacom->wacom_wac.features.type == WACOM_21UX2 || - wacom->wacom_wac.features.type == WACOM_24HD) - led = (wacom->led.select[1] << 4) | 0x40; - - led |= wacom->led.select[0] | 0x4; - - buf[0] = WAC_CMD_LED_CONTROL; - buf[1] = led; - buf[2] = wacom->led.llv; - buf[3] = wacom->led.hlv; - buf[4] = wacom->led.img_lum; + if (wacom->wacom_wac.features.type >= INTUOS5S && + wacom->wacom_wac.features.type <= INTUOS5L) { + /* + * Touch Ring and crop mark LED luminance may take on + * one of four values: + * 0 = Low; 1 = Medium; 2 = High; 3 = Off + */ + int ring_led = wacom->led.select[0] & 0x03; + int ring_lum = (((wacom->led.llv & 0x60) >> 5) - 1) & 0x03; + int crop_lum = 0; + + buf[0] = WAC_CMD_LED_CONTROL; + buf[1] = (crop_lum << 4) | (ring_lum << 2) | (ring_led); + } + else { + int led = wacom->led.select[0] | 0x4; + + if (wacom->wacom_wac.features.type == WACOM_21UX2 || + wacom->wacom_wac.features.type == WACOM_24HD) + led |= (wacom->led.select[1] << 4) | 0x40; + + buf[0] = WAC_CMD_LED_CONTROL; + buf[1] = led; + buf[2] = wacom->led.llv; + buf[3] = wacom->led.hlv; + buf[4] = wacom->led.img_lum; + } retval = wacom_set_report(wacom->intf, 0x03, WAC_CMD_LED_CONTROL, buf, 9, WAC_CMD_RETRIES); @@ -783,6 +843,17 @@ static struct attribute_group intuos4_led_attr_group = { .attrs = intuos4_led_attrs, }; +static struct attribute *intuos5_led_attrs[] = { + &dev_attr_status0_luminance.attr, + &dev_attr_status_led0_select.attr, + NULL +}; + +static struct attribute_group intuos5_led_attr_group = { + .name = "wacom_led", + .attrs = intuos5_led_attrs, +}; + static int wacom_initialize_leds(struct wacom *wacom) { int error; @@ -812,6 +883,19 @@ static int wacom_initialize_leds(struct wacom *wacom) &cintiq_led_attr_group); break; + case INTUOS5S: + case INTUOS5: + case INTUOS5L: + wacom->led.select[0] = 0; + wacom->led.select[1] = 0; + wacom->led.llv = 32; + wacom->led.hlv = 0; + wacom->led.img_lum = 0; + + error = sysfs_create_group(&wacom->intf->dev.kobj, + &intuos5_led_attr_group); + break; + default: return 0; } @@ -840,6 +924,13 @@ static void wacom_destroy_leds(struct wacom *wacom) sysfs_remove_group(&wacom->intf->dev.kobj, &cintiq_led_attr_group); break; + + case INTUOS5S: + case INTUOS5: + case INTUOS5L: + sysfs_remove_group(&wacom->intf->dev.kobj, + &intuos5_led_attr_group); + break; } } @@ -901,8 +992,10 @@ static int wacom_register_input(struct wacom *wacom) int error; input_dev = input_allocate_device(); - if (!input_dev) - return -ENOMEM; + if (!input_dev) { + error = -ENOMEM; + goto fail1; + } input_dev->name = wacom_wac->name; input_dev->dev.parent = &intf->dev; @@ -912,14 +1005,20 @@ static int wacom_register_input(struct wacom *wacom) input_set_drvdata(input_dev, wacom); wacom_wac->input = input_dev; - wacom_setup_input_capabilities(input_dev, wacom_wac); + error = wacom_setup_input_capabilities(input_dev, wacom_wac); + if (error) + goto fail1; error = input_register_device(input_dev); - if (error) { - input_free_device(input_dev); - wacom_wac->input = NULL; - } + if (error) + goto fail2; + return 0; + +fail2: + input_free_device(input_dev); + wacom_wac->input = NULL; +fail1: return error; } @@ -938,22 +1037,22 @@ static void wacom_wireless_work(struct work_struct *work) wacom = usb_get_intfdata(usbdev->config->interface[1]); if (wacom->wacom_wac.input) input_unregister_device(wacom->wacom_wac.input); - wacom->wacom_wac.input = 0; + wacom->wacom_wac.input = NULL; /* Touch interface */ wacom = usb_get_intfdata(usbdev->config->interface[2]); if (wacom->wacom_wac.input) input_unregister_device(wacom->wacom_wac.input); - wacom->wacom_wac.input = 0; + wacom->wacom_wac.input = NULL; if (wacom_wac->pid == 0) { - printk(KERN_INFO "wacom: wireless tablet disconnected\n"); + dev_info(&wacom->intf->dev, "wireless tablet disconnected\n"); } else { const struct usb_device_id *id = wacom_ids; - printk(KERN_INFO - "wacom: wireless tablet connected with PID %x\n", - wacom_wac->pid); + dev_info(&wacom->intf->dev, + "wireless tablet connected with PID %x\n", + wacom_wac->pid); while (id->match_flags) { if (id->idVendor == USB_VENDOR_ID_WACOM && @@ -963,8 +1062,8 @@ static void wacom_wireless_work(struct work_struct *work) } if (!id->match_flags) { - printk(KERN_INFO - "wacom: ignorning unknown PID.\n"); + dev_info(&wacom->intf->dev, + "ignoring unknown PID.\n"); return; } @@ -1035,11 +1134,33 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i endpoint = &intf->cur_altsetting->endpoint[0].desc; - /* Retrieve the physical and logical size for OEM devices */ + /* Retrieve the physical and logical size for touch devices */ error = wacom_retrieve_hid_descriptor(intf, features); if (error) goto fail3; + /* + * Intuos5 has no useful data about its touch interface in its + * HID descriptor. If this is the touch interface (wMaxPacketSize + * of WACOM_PKGLEN_BBTOUCH3), override the table values. + */ + if (features->type >= INTUOS5S && features->type <= INTUOS5L) { + if (endpoint->wMaxPacketSize == WACOM_PKGLEN_BBTOUCH3) { + features->device_type = BTN_TOOL_FINGER; + features->pktlen = WACOM_PKGLEN_BBTOUCH3; + + features->x_phy = + (features->x_max * 100) / features->x_resolution; + features->y_phy = + (features->y_max * 100) / features->y_resolution; + + features->x_max = 4096; + features->y_max = 4096; + } else { + features->device_type = BTN_TOOL_PEN; + } + } + wacom_setup_device_quirks(features); strlcpy(wacom_wac->name, features->name, sizeof(wacom_wac->name)); diff --git a/drivers/input/tablet/wacom_wac.c b/drivers/input/tablet/wacom_wac.c index cecd35c8f0b3..004bc1bb1544 100644 --- a/drivers/input/tablet/wacom_wac.c +++ b/drivers/input/tablet/wacom_wac.c @@ -61,7 +61,8 @@ static int wacom_penpartner_irq(struct wacom_wac *wacom) break; default: - printk(KERN_INFO "wacom_penpartner_irq: received unknown report #%d\n", data[0]); + dev_dbg(input->dev.parent, + "%s: received unknown report #%d\n", __func__, data[0]); return 0; } @@ -76,7 +77,8 @@ static int wacom_pl_irq(struct wacom_wac *wacom) int prox, pressure; if (data[0] != WACOM_REPORT_PENABLED) { - dbg("wacom_pl_irq: received unknown report #%d", data[0]); + dev_dbg(input->dev.parent, + "%s: received unknown report #%d\n", __func__, data[0]); return 0; } @@ -146,7 +148,8 @@ static int wacom_ptu_irq(struct wacom_wac *wacom) struct input_dev *input = wacom->input; if (data[0] != WACOM_REPORT_PENABLED) { - printk(KERN_INFO "wacom_ptu_irq: received unknown report #%d\n", data[0]); + dev_dbg(input->dev.parent, + "%s: received unknown report #%d\n", __func__, data[0]); return 0; } @@ -175,7 +178,8 @@ static int wacom_dtu_irq(struct wacom_wac *wacom) struct input_dev *input = wacom->input; int prox = data[1] & 0x20, pressure; - dbg("wacom_dtu_irq: received report #%d", data[0]); + dev_dbg(input->dev.parent, + "%s: received report #%d", __func__, data[0]); if (prox) { /* Going into proximity select tool */ @@ -211,7 +215,8 @@ static int wacom_graphire_irq(struct wacom_wac *wacom) int retval = 0; if (data[0] != WACOM_REPORT_PENABLED) { - dbg("wacom_graphire_irq: received unknown report #%d", data[0]); + dev_dbg(input->dev.parent, + "%s: received unknown report #%d\n", __func__, data[0]); goto exit; } @@ -321,6 +326,9 @@ static int wacom_intuos_inout(struct wacom_wac *wacom) /* Enter report */ if ((data[1] & 0xfc) == 0xc0) { + if (features->type >= INTUOS5S && features->type <= INTUOS5L) + wacom->shared->stylus_in_proximity = true; + /* serial number of the tool */ wacom->serial[idx] = ((data[3] & 0x0f) << 28) + (data[4] << 20) + (data[5] << 12) + @@ -406,6 +414,9 @@ static int wacom_intuos_inout(struct wacom_wac *wacom) /* Exit report */ if ((data[1] & 0xfe) == 0x80) { + if (features->type >= INTUOS5S && features->type <= INTUOS5L) + wacom->shared->stylus_in_proximity = false; + /* * Reset all states otherwise we lose the initial states * when in-prox next time @@ -452,6 +463,7 @@ static void wacom_intuos_general(struct wacom_wac *wacom) if ((data[1] & 0xb8) == 0xa0) { t = (data[6] << 2) | ((data[7] >> 6) & 3); if ((features->type >= INTUOS4S && features->type <= INTUOS4L) || + (features->type >= INTUOS5S && features->type <= INTUOS5L) || features->type == WACOM_21UX2 || features->type == WACOM_24HD) { t = (t << 1) | (data[1] & 1); } @@ -482,9 +494,13 @@ static int wacom_intuos_irq(struct wacom_wac *wacom) unsigned int t; int idx = 0, result; - if (data[0] != WACOM_REPORT_PENABLED && data[0] != WACOM_REPORT_INTUOSREAD - && data[0] != WACOM_REPORT_INTUOSWRITE && data[0] != WACOM_REPORT_INTUOSPAD) { - dbg("wacom_intuos_irq: received unknown report #%d", data[0]); + if (data[0] != WACOM_REPORT_PENABLED && + data[0] != WACOM_REPORT_INTUOSREAD && + data[0] != WACOM_REPORT_INTUOSWRITE && + data[0] != WACOM_REPORT_INTUOSPAD && + data[0] != WACOM_REPORT_INTUOS5PAD) { + dev_dbg(input->dev.parent, + "%s: received unknown report #%d\n", __func__, data[0]); return 0; } @@ -493,7 +509,7 @@ static int wacom_intuos_irq(struct wacom_wac *wacom) idx = data[1] & 0x01; /* pad packets. Works as a second tool and is always in prox */ - if (data[0] == WACOM_REPORT_INTUOSPAD) { + if (data[0] == WACOM_REPORT_INTUOSPAD || data[0] == WACOM_REPORT_INTUOS5PAD) { if (features->type >= INTUOS4S && features->type <= INTUOS4L) { input_report_key(input, BTN_0, (data[2] & 0x01)); input_report_key(input, BTN_1, (data[3] & 0x01)); @@ -569,6 +585,34 @@ static int wacom_intuos_irq(struct wacom_wac *wacom) input_report_key(input, wacom->tool[1], 0); input_report_abs(input, ABS_MISC, 0); } + } else if (features->type >= INTUOS5S && features->type <= INTUOS5L) { + int i; + + /* Touch ring mode switch has no capacitive sensor */ + input_report_key(input, BTN_0, (data[3] & 0x01)); + + /* + * ExpressKeys on Intuos5 have a capacitive sensor in + * addition to the mechanical switch. Switch data is + * stored in data[4], capacitive data in data[5]. + */ + for (i = 0; i < 8; i++) + input_report_key(input, BTN_1 + i, data[4] & (1 << i)); + + if (data[2] & 0x80) { + input_report_abs(input, ABS_WHEEL, (data[2] & 0x7f)); + } else { + /* Out of proximity, clear wheel value. */ + input_report_abs(input, ABS_WHEEL, 0); + } + + if (data[2] | (data[3] & 0x01) | data[4]) { + input_report_key(input, wacom->tool[1], 1); + input_report_abs(input, ABS_MISC, PAD_DEVICE_ID); + } else { + input_report_key(input, wacom->tool[1], 0); + input_report_abs(input, ABS_MISC, 0); + } } else { if (features->type == WACOM_21UX2) { input_report_key(input, BTN_0, (data[5] & 0x01)); @@ -632,7 +676,9 @@ static int wacom_intuos_irq(struct wacom_wac *wacom) (features->type == INTUOS3 || features->type == INTUOS3S || features->type == INTUOS4 || - features->type == INTUOS4S)) { + features->type == INTUOS4S || + features->type == INTUOS5 || + features->type == INTUOS5S)) { return 0; } @@ -685,7 +731,8 @@ static int wacom_intuos_irq(struct wacom_wac *wacom) } else if (wacom->tool[idx] == BTN_TOOL_MOUSE) { /* I4 mouse */ - if (features->type >= INTUOS4S && features->type <= INTUOS4L) { + if ((features->type >= INTUOS4S && features->type <= INTUOS4L) || + (features->type >= INTUOS5S && features->type <= INTUOS5L)) { input_report_key(input, BTN_LEFT, data[6] & 0x01); input_report_key(input, BTN_MIDDLE, data[6] & 0x02); input_report_key(input, BTN_RIGHT, data[6] & 0x04); @@ -712,7 +759,7 @@ static int wacom_intuos_irq(struct wacom_wac *wacom) } } } else if ((features->type < INTUOS3S || features->type == INTUOS3L || - features->type == INTUOS4L) && + features->type == INTUOS4L || features->type == INTUOS5L) && wacom->tool[idx] == BTN_TOOL_LENS) { /* Lens cursor packets */ input_report_key(input, BTN_LEFT, data[8] & 0x01); @@ -729,6 +776,72 @@ static int wacom_intuos_irq(struct wacom_wac *wacom) return 1; } +static int find_slot_from_contactid(struct wacom_wac *wacom, int contactid) +{ + int touch_max = wacom->features.touch_max; + int i; + + if (!wacom->slots) + return -1; + + for (i = 0; i < touch_max; ++i) { + if (wacom->slots[i] == contactid) + return i; + } + for (i = 0; i < touch_max; ++i) { + if (wacom->slots[i] == -1) + return i; + } + return -1; +} + +static int wacom_mt_touch(struct wacom_wac *wacom) +{ + struct input_dev *input = wacom->input; + char *data = wacom->data; + int i; + int current_num_contacts = data[2]; + int contacts_to_send = 0; + + /* + * First packet resets the counter since only the first + * packet in series will have non-zero current_num_contacts. + */ + if (current_num_contacts) + wacom->num_contacts_left = current_num_contacts; + + /* There are at most 5 contacts per packet */ + contacts_to_send = min(5, wacom->num_contacts_left); + + for (i = 0; i < contacts_to_send; i++) { + int offset = (WACOM_BYTES_PER_MT_PACKET * i) + 3; + bool touch = data[offset] & 0x1; + int id = le16_to_cpup((__le16 *)&data[offset + 1]); + int slot = find_slot_from_contactid(wacom, id); + + if (slot < 0) + continue; + + input_mt_slot(input, slot); + input_mt_report_slot_state(input, MT_TOOL_FINGER, touch); + if (touch) { + int x = le16_to_cpup((__le16 *)&data[offset + 7]); + int y = le16_to_cpup((__le16 *)&data[offset + 9]); + input_report_abs(input, ABS_MT_POSITION_X, x); + input_report_abs(input, ABS_MT_POSITION_Y, y); + } + wacom->slots[slot] = touch ? id : -1; + } + + input_mt_report_pointer_emulation(input, true); + + wacom->num_contacts_left -= contacts_to_send; + if (wacom->num_contacts_left < 0) + wacom->num_contacts_left = 0; + + return 1; +} + static int wacom_tpc_mt_touch(struct wacom_wac *wacom) { struct input_dev *input = wacom->input; @@ -767,6 +880,9 @@ static int wacom_tpc_single_touch(struct wacom_wac *wacom, size_t len) bool prox; int x = 0, y = 0; + if (wacom->features.touch_max > 1 || len > WACOM_PKGLEN_TPC2FG) + return 0; + if (!wacom->shared->stylus_in_proximity) { if (len == WACOM_PKGLEN_TPC1FG) { prox = data[0] & 0x01; @@ -830,14 +946,15 @@ static int wacom_tpc_irq(struct wacom_wac *wacom, size_t len) { char *data = wacom->data; - dbg("wacom_tpc_irq: received report #%d", data[0]); + dev_dbg(wacom->input->dev.parent, + "%s: received report #%d\n", __func__, data[0]); switch (len) { case WACOM_PKGLEN_TPC1FG: - return wacom_tpc_single_touch(wacom, len); + return wacom_tpc_single_touch(wacom, len); case WACOM_PKGLEN_TPC2FG: - return wacom_tpc_mt_touch(wacom); + return wacom_tpc_mt_touch(wacom); default: switch (data[0]) { @@ -846,6 +963,9 @@ static int wacom_tpc_irq(struct wacom_wac *wacom, size_t len) case WACOM_REPORT_TPCST: return wacom_tpc_single_touch(wacom, len); + case WACOM_REPORT_TPCMT: + return wacom_mt_touch(wacom); + case WACOM_REPORT_PENABLED: return wacom_tpc_pen(wacom); } @@ -1114,8 +1234,18 @@ void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t len) sync = wacom_intuos_irq(wacom_wac); break; + case INTUOS5S: + case INTUOS5: + case INTUOS5L: + if (len == WACOM_PKGLEN_BBTOUCH3) + sync = wacom_bpt3_touch(wacom_wac); + else + sync = wacom_intuos_irq(wacom_wac); + break; + case TABLETPC: case TABLETPC2FG: + case MTSCREEN: sync = wacom_tpc_irq(wacom_wac, len); break; @@ -1188,7 +1318,9 @@ void wacom_setup_device_quirks(struct wacom_features *features) /* these device have multiple inputs */ if (features->type == TABLETPC || features->type == TABLETPC2FG || - features->type == BAMBOO_PT || features->type == WIRELESS) + features->type == BAMBOO_PT || features->type == WIRELESS || + (features->type >= INTUOS5S && features->type <= INTUOS5L) || + features->type == MTSCREEN) features->quirks |= WACOM_QUIRK_MULTI_INPUT; /* quirk for bamboo touch with 2 low res touches */ @@ -1219,8 +1351,8 @@ static unsigned int wacom_calculate_touch_res(unsigned int logical_max, return (logical_max * 100) / physical_max; } -void wacom_setup_input_capabilities(struct input_dev *input_dev, - struct wacom_wac *wacom_wac) +int wacom_setup_input_capabilities(struct input_dev *input_dev, + struct wacom_wac *wacom_wac) { struct wacom_features *features = &wacom_wac->features; int i; @@ -1355,6 +1487,50 @@ void wacom_setup_input_capabilities(struct input_dev *input_dev, wacom_setup_intuos(wacom_wac); break; + case INTUOS5: + case INTUOS5L: + if (features->device_type == BTN_TOOL_PEN) { + __set_bit(BTN_7, input_dev->keybit); + __set_bit(BTN_8, input_dev->keybit); + } + /* fall through */ + + case INTUOS5S: + __set_bit(INPUT_PROP_POINTER, input_dev->propbit); + + if (features->device_type == BTN_TOOL_PEN) { + for (i = 0; i < 7; i++) + __set_bit(BTN_0 + i, input_dev->keybit); + + input_set_abs_params(input_dev, ABS_DISTANCE, 0, + features->distance_max, + 0, 0); + + input_set_abs_params(input_dev, ABS_Z, -900, 899, 0, 0); + + wacom_setup_intuos(wacom_wac); + } else if (features->device_type == BTN_TOOL_FINGER) { + __clear_bit(ABS_MISC, input_dev->absbit); + + __set_bit(BTN_TOOL_FINGER, input_dev->keybit); + __set_bit(BTN_TOOL_DOUBLETAP, input_dev->keybit); + __set_bit(BTN_TOOL_TRIPLETAP, input_dev->keybit); + __set_bit(BTN_TOOL_QUADTAP, input_dev->keybit); + + input_mt_init_slots(input_dev, features->touch_max); + + input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, + 0, 255, 0, 0); + + input_set_abs_params(input_dev, ABS_MT_POSITION_X, + 0, features->x_max, + features->x_fuzz, 0); + input_set_abs_params(input_dev, ABS_MT_POSITION_Y, + 0, features->y_max, + features->y_fuzz, 0); + } + break; + case INTUOS4: case INTUOS4L: __set_bit(BTN_7, input_dev->keybit); @@ -1372,9 +1548,19 @@ void wacom_setup_input_capabilities(struct input_dev *input_dev, break; case TABLETPC2FG: + case MTSCREEN: if (features->device_type == BTN_TOOL_FINGER) { - input_mt_init_slots(input_dev, 2); + wacom_wac->slots = kmalloc(features->touch_max * + sizeof(int), + GFP_KERNEL); + if (!wacom_wac->slots) + return -ENOMEM; + + for (i = 0; i < features->touch_max; i++) + wacom_wac->slots[i] = -1; + + input_mt_init_slots(input_dev, features->touch_max); input_set_abs_params(input_dev, ABS_MT_TOOL_TYPE, 0, MT_TOOL_MAX, 0, 0); input_set_abs_params(input_dev, ABS_MT_POSITION_X, @@ -1429,6 +1615,7 @@ void wacom_setup_input_capabilities(struct input_dev *input_dev, __set_bit(BTN_TOOL_FINGER, input_dev->keybit); __set_bit(BTN_TOOL_DOUBLETAP, input_dev->keybit); + input_mt_init_slots(input_dev, features->touch_max); if (features->pktlen == WACOM_PKGLEN_BBTOUCH3) { __set_bit(BTN_TOOL_TRIPLETAP, @@ -1436,13 +1623,9 @@ void wacom_setup_input_capabilities(struct input_dev *input_dev, __set_bit(BTN_TOOL_QUADTAP, input_dev->keybit); - input_mt_init_slots(input_dev, 16); - input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0); - } else { - input_mt_init_slots(input_dev, 2); } input_set_abs_params(input_dev, ABS_MT_POSITION_X, @@ -1462,6 +1645,7 @@ void wacom_setup_input_capabilities(struct input_dev *input_dev, } break; } + return 0; } static const struct wacom_features wacom_features_0x00 = @@ -1629,6 +1813,24 @@ static const struct wacom_features wacom_features_0xBB = static const struct wacom_features wacom_features_0xBC = { "Wacom Intuos4 WL", WACOM_PKGLEN_INTUOS, 40840, 25400, 2047, 63, INTUOS4, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES }; +static const struct wacom_features wacom_features_0x26 = + { "Wacom Intuos5 touch S", WACOM_PKGLEN_INTUOS, 31496, 19685, 2047, + 63, INTUOS5S, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, + .touch_max = 16 }; +static const struct wacom_features wacom_features_0x27 = + { "Wacom Intuos5 touch M", WACOM_PKGLEN_INTUOS, 44704, 27940, 2047, + 63, INTUOS5, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, + .touch_max = 16 }; +static const struct wacom_features wacom_features_0x28 = + { "Wacom Intuos5 touch L", WACOM_PKGLEN_INTUOS, 65024, 40640, 2047, + 63, INTUOS5L, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, + .touch_max = 16 }; +static const struct wacom_features wacom_features_0x29 = + { "Wacom Intuos5 S", WACOM_PKGLEN_INTUOS, 31496, 19685, 2047, + 63, INTUOS5S, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES }; +static const struct wacom_features wacom_features_0x2A = + { "Wacom Intuos5 M", WACOM_PKGLEN_INTUOS, 44704, 27940, 2047, + 63, INTUOS5, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES }; static const struct wacom_features wacom_features_0xF4 = { "Wacom Cintiq 24HD", WACOM_PKGLEN_INTUOS, 104480, 65600, 2047, 63, WACOM_24HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES }; @@ -1670,13 +1872,19 @@ static const struct wacom_features wacom_features_0x9F = 0, TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; static const struct wacom_features wacom_features_0xE2 = { "Wacom ISDv4 E2", WACOM_PKGLEN_TPC2FG, 26202, 16325, 255, - 0, TABLETPC2FG, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; + 0, TABLETPC2FG, WACOM_INTUOS_RES, WACOM_INTUOS_RES, + .touch_max = 2 }; static const struct wacom_features wacom_features_0xE3 = { "Wacom ISDv4 E3", WACOM_PKGLEN_TPC2FG, 26202, 16325, 255, - 0, TABLETPC2FG, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; + 0, TABLETPC2FG, WACOM_INTUOS_RES, WACOM_INTUOS_RES, + .touch_max = 2 }; +static const struct wacom_features wacom_features_0xE5 = + { "Wacom ISDv4 E5", WACOM_PKGLEN_MTOUCH, 26202, 16325, 255, + 0, MTSCREEN, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; static const struct wacom_features wacom_features_0xE6 = { "Wacom ISDv4 E6", WACOM_PKGLEN_TPC2FG, 27760, 15694, 255, - 0, TABLETPC2FG, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; + 0, TABLETPC2FG, WACOM_INTUOS_RES, WACOM_INTUOS_RES, + .touch_max = 2 }; static const struct wacom_features wacom_features_0xEC = { "Wacom ISDv4 EC", WACOM_PKGLEN_GRAPHIRE, 25710, 14500, 255, 0, TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; @@ -1685,19 +1893,22 @@ static const struct wacom_features wacom_features_0x47 = 31, INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; static const struct wacom_features wacom_features_0x84 = { "Wacom Wireless Receiver", WACOM_PKGLEN_WIRELESS, 0, 0, 0, - 0, WIRELESS, 0, 0 }; + 0, WIRELESS, 0, 0, .touch_max = 16 }; static const struct wacom_features wacom_features_0xD0 = { "Wacom Bamboo 2FG", WACOM_PKGLEN_BBFUN, 14720, 9200, 1023, - 31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; + 31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, + .touch_max = 2 }; static const struct wacom_features wacom_features_0xD1 = { "Wacom Bamboo 2FG 4x5", WACOM_PKGLEN_BBFUN, 14720, 9200, 1023, - 31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; + 31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, + .touch_max = 2 }; static const struct wacom_features wacom_features_0xD2 = { "Wacom Bamboo Craft", WACOM_PKGLEN_BBFUN, 14720, 9200, 1023, 31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; static const struct wacom_features wacom_features_0xD3 = { "Wacom Bamboo 2FG 6x8", WACOM_PKGLEN_BBFUN, 21648, 13700, 1023, - 31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; + 31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, + .touch_max = 2 }; static const struct wacom_features wacom_features_0xD4 = { "Wacom Bamboo Pen", WACOM_PKGLEN_BBFUN, 14720, 9200, 1023, 31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; @@ -1706,28 +1917,35 @@ static const struct wacom_features wacom_features_0xD5 = 31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; static const struct wacom_features wacom_features_0xD6 = { "Wacom BambooPT 2FG 4x5", WACOM_PKGLEN_BBFUN, 14720, 9200, 1023, - 31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; + 31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, + .touch_max = 2 }; static const struct wacom_features wacom_features_0xD7 = { "Wacom BambooPT 2FG Small", WACOM_PKGLEN_BBFUN, 14720, 9200, 1023, - 31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; + 31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, + .touch_max = 2 }; static const struct wacom_features wacom_features_0xD8 = { "Wacom Bamboo Comic 2FG", WACOM_PKGLEN_BBFUN, 21648, 13700, 1023, - 31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; + 31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, + .touch_max = 2 }; static const struct wacom_features wacom_features_0xDA = { "Wacom Bamboo 2FG 4x5 SE", WACOM_PKGLEN_BBFUN, 14720, 9200, 1023, - 31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; + 31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, + .touch_max = 2 }; static struct wacom_features wacom_features_0xDB = { "Wacom Bamboo 2FG 6x8 SE", WACOM_PKGLEN_BBFUN, 21648, 13700, 1023, - 31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; + 31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, + .touch_max = 2 }; static const struct wacom_features wacom_features_0xDD = { "Wacom Bamboo Connect", WACOM_PKGLEN_BBPEN, 14720, 9200, 1023, 31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; static const struct wacom_features wacom_features_0xDE = { "Wacom Bamboo 16FG 4x5", WACOM_PKGLEN_BBPEN, 14720, 9200, 1023, - 31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; + 31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, + .touch_max = 16 }; static const struct wacom_features wacom_features_0xDF = { "Wacom Bamboo 16FG 6x8", WACOM_PKGLEN_BBPEN, 21648, 13700, 1023, - 31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; + 31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, + .touch_max = 16 }; static const struct wacom_features wacom_features_0x6004 = { "ISD-V4", WACOM_PKGLEN_GRAPHIRE, 12800, 8000, 255, 0, TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; @@ -1801,6 +2019,11 @@ const struct usb_device_id wacom_ids[] = { { USB_DEVICE_WACOM(0xBA) }, { USB_DEVICE_WACOM(0xBB) }, { USB_DEVICE_WACOM(0xBC) }, + { USB_DEVICE_WACOM(0x26) }, + { USB_DEVICE_WACOM(0x27) }, + { USB_DEVICE_WACOM(0x28) }, + { USB_DEVICE_WACOM(0x29) }, + { USB_DEVICE_WACOM(0x2A) }, { USB_DEVICE_WACOM(0x3F) }, { USB_DEVICE_WACOM(0xC5) }, { USB_DEVICE_WACOM(0xC6) }, @@ -1836,6 +2059,7 @@ const struct usb_device_id wacom_ids[] = { { USB_DEVICE_WACOM(0x9F) }, { USB_DEVICE_WACOM(0xE2) }, { USB_DEVICE_WACOM(0xE3) }, + { USB_DEVICE_WACOM(0xE5) }, { USB_DEVICE_WACOM(0xE6) }, { USB_DEVICE_WACOM(0xEC) }, { USB_DEVICE_WACOM(0x47) }, diff --git a/drivers/input/tablet/wacom_wac.h b/drivers/input/tablet/wacom_wac.h index ba5a334e54d6..78fbd3f42009 100644 --- a/drivers/input/tablet/wacom_wac.h +++ b/drivers/input/tablet/wacom_wac.h @@ -25,6 +25,10 @@ #define WACOM_PKGLEN_BBTOUCH3 64 #define WACOM_PKGLEN_BBPEN 10 #define WACOM_PKGLEN_WIRELESS 32 +#define WACOM_PKGLEN_MTOUCH 62 + +/* wacom data size per MT contact */ +#define WACOM_BYTES_PER_MT_PACKET 11 /* device IDs */ #define STYLUS_DEVICE_ID 0x02 @@ -38,8 +42,10 @@ #define WACOM_REPORT_INTUOSREAD 5 #define WACOM_REPORT_INTUOSWRITE 6 #define WACOM_REPORT_INTUOSPAD 12 +#define WACOM_REPORT_INTUOS5PAD 3 #define WACOM_REPORT_TPC1FG 6 #define WACOM_REPORT_TPC2FG 13 +#define WACOM_REPORT_TPCMT 13 #define WACOM_REPORT_TPCHID 15 #define WACOM_REPORT_TPCST 16 @@ -65,6 +71,9 @@ enum { INTUOS4S, INTUOS4, INTUOS4L, + INTUOS5S, + INTUOS5, + INTUOS5L, WACOM_24HD, WACOM_21UX2, CINTIQ, @@ -72,6 +81,7 @@ enum { WACOM_MO, TABLETPC, TABLETPC2FG, + MTSCREEN, MAX_TYPE }; @@ -95,6 +105,7 @@ struct wacom_features { int pressure_fuzz; int distance_fuzz; unsigned quirks; + unsigned touch_max; }; struct wacom_shared { @@ -113,6 +124,8 @@ struct wacom_wac { struct input_dev *input; int pid; int battery_capacity; + int num_contacts_left; + int *slots; }; #endif |