summaryrefslogtreecommitdiff
path: root/drivers/input/tablet
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/input/tablet')
-rw-r--r--drivers/input/tablet/acecad.c15
-rw-r--r--drivers/input/tablet/aiptek.c30
-rw-r--r--drivers/input/tablet/gtco.c110
-rw-r--r--drivers/input/tablet/kbtab.c15
-rw-r--r--drivers/input/tablet/wacom.h4
-rw-r--r--drivers/input/tablet/wacom_sys.c257
-rw-r--r--drivers/input/tablet/wacom_wac.c298
-rw-r--r--drivers/input/tablet/wacom_wac.h13
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, &gtco->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