summaryrefslogtreecommitdiffstats
path: root/drivers/input/tablet/wacom_sys.c
diff options
context:
space:
mode:
authorBenjamin Tissoires2014-07-24 21:52:23 +0200
committerDmitry Torokhov2014-07-26 03:53:50 +0200
commit29b4739134c73a2873adec93346f09bb76d6a794 (patch)
treefbb2527a5c99a8a613adc043dbc05417139f5050 /drivers/input/tablet/wacom_sys.c
parentInput: wacom - include and use linux/hid.h (diff)
downloadkernel-qcow2-linux-29b4739134c73a2873adec93346f09bb76d6a794.tar.gz
kernel-qcow2-linux-29b4739134c73a2873adec93346f09bb76d6a794.tar.xz
kernel-qcow2-linux-29b4739134c73a2873adec93346f09bb76d6a794.zip
Input: wacom - switch from an USB driver to a HID driver
All USB Wacom tablets are actually HID devices. For historical reasons, they are handled as plain USB devices. The current code makes more and more reference to the HID subsystem like implementing its own HID report descriptor parser to handle new devices. From the user point of view, we can transparently switch from this state to a driver handled in the HID subsystem and clean up a lot of USB specific code in the wacom.ko driver. The other benefit once the USB dependecies have been removed is that we can use a tool like uhid to make regression tests and allow further cleanup or new implementations without risking breaking current behaviors. To match the current handling of devices in wacom_wac.c, we rely on the hid_type set by usbhid. usbhid sets the hid_type to HID_TYPE_USBMOUSE when it sees a USB boot mouse protocol declared and HID_TYPE_USBNONE when the device is plain HID. There is thus a one to one matching between the list of supported devices before and after the switch from USB to HID. Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com> Reviewed-by: Jason Gerecke <killertofu@gmail.com> Tested-by: Jason Gerecke <killertofu@gmail.com> Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Diffstat (limited to 'drivers/input/tablet/wacom_sys.c')
-rw-r--r--drivers/input/tablet/wacom_sys.c222
1 files changed, 81 insertions, 141 deletions
diff --git a/drivers/input/tablet/wacom_sys.c b/drivers/input/tablet/wacom_sys.c
index c34791e7f0b9..5ceeab6e95f1 100644
--- a/drivers/input/tablet/wacom_sys.c
+++ b/drivers/input/tablet/wacom_sys.c
@@ -83,86 +83,40 @@ static int wacom_set_report(struct usb_interface *intf, u8 type, u8 id,
return retval;
}
-static void wacom_sys_irq(struct urb *urb)
+static int wacom_raw_event(struct hid_device *hdev, struct hid_report *report,
+ u8 *raw_data, int size)
{
- struct wacom *wacom = urb->context;
- struct device *dev = &wacom->intf->dev;
- int retval;
+ struct wacom *wacom = hid_get_drvdata(hdev);
- switch (urb->status) {
- case 0:
- /* success */
- break;
- case -ECONNRESET:
- case -ENOENT:
- case -ESHUTDOWN:
- /* this urb is terminated, clean up */
- dev_dbg(dev, "%s - urb shutting down with status: %d\n",
- __func__, urb->status);
- return;
- default:
- dev_dbg(dev, "%s - nonzero urb status received: %d\n",
- __func__, urb->status);
- goto exit;
- }
+ if (size > WACOM_PKGLEN_MAX)
+ return 1;
- wacom_wac_irq(&wacom->wacom_wac, urb->actual_length);
+ memcpy(wacom->wacom_wac.data, raw_data, size);
- exit:
- usb_mark_last_busy(wacom->usbdev);
- retval = usb_submit_urb(urb, GFP_ATOMIC);
- if (retval)
- dev_err(dev, "%s - usb_submit_urb failed with result %d\n",
- __func__, retval);
+ wacom_wac_irq(&wacom->wacom_wac, size);
+
+ return 0;
}
static int wacom_open(struct input_dev *dev)
{
struct wacom *wacom = input_get_drvdata(dev);
- int retval = 0;
-
- if (usb_autopm_get_interface(wacom->intf) < 0)
- return -EIO;
+ int retval;
mutex_lock(&wacom->lock);
-
- if (wacom->open)
- goto out;
-
- if (usb_submit_urb(wacom->irq, GFP_KERNEL)) {
- retval = -EIO;
- goto out;
- }
-
- wacom->open = true;
- wacom->intf->needs_remote_wakeup = 1;
-
-out:
+ retval = hid_hw_open(wacom->hdev);
mutex_unlock(&wacom->lock);
- usb_autopm_put_interface(wacom->intf);
+
return retval;
}
static void wacom_close(struct input_dev *dev)
{
struct wacom *wacom = input_get_drvdata(dev);
- int autopm_error;
-
- autopm_error = usb_autopm_get_interface(wacom->intf);
mutex_lock(&wacom->lock);
- if (!wacom->open)
- goto out;
-
- usb_kill_urb(wacom->irq);
- wacom->open = false;
- wacom->intf->needs_remote_wakeup = 0;
-
-out:
+ hid_hw_close(wacom->hdev);
mutex_unlock(&wacom->lock);
-
- if (!autopm_error)
- usb_autopm_put_interface(wacom->intf);
}
/*
@@ -807,7 +761,8 @@ out:
static ssize_t wacom_led_select_store(struct device *dev, int set_id,
const char *buf, size_t count)
{
- struct wacom *wacom = dev_get_drvdata(dev);
+ struct hid_device *hdev = dev_get_drvdata(dev);
+ struct wacom *wacom = hid_get_drvdata(hdev);
unsigned int id;
int err;
@@ -834,7 +789,8 @@ static ssize_t wacom_led##SET_ID##_select_store(struct device *dev, \
static ssize_t wacom_led##SET_ID##_select_show(struct device *dev, \
struct device_attribute *attr, char *buf) \
{ \
- struct wacom *wacom = dev_get_drvdata(dev); \
+ struct hid_device *hdev = dev_get_drvdata(dev); \
+ struct wacom *wacom = hid_get_drvdata(hdev); \
return snprintf(buf, 2, "%d\n", wacom->led.select[SET_ID]); \
} \
static DEVICE_ATTR(status_led##SET_ID##_select, S_IWUSR | S_IRUSR, \
@@ -868,7 +824,8 @@ static ssize_t wacom_luminance_store(struct wacom *wacom, u8 *dest,
static ssize_t wacom_##name##_luminance_store(struct device *dev, \
struct device_attribute *attr, const char *buf, size_t count) \
{ \
- struct wacom *wacom = dev_get_drvdata(dev); \
+ struct hid_device *hdev = dev_get_drvdata(dev); \
+ struct wacom *wacom = hid_get_drvdata(hdev); \
\
return wacom_luminance_store(wacom, &wacom->led.field, \
buf, count); \
@@ -883,7 +840,8 @@ DEVICE_LUMINANCE_ATTR(buttons, img_lum);
static ssize_t wacom_button_image_store(struct device *dev, int button_id,
const char *buf, size_t count)
{
- struct wacom *wacom = dev_get_drvdata(dev);
+ struct hid_device *hdev = dev_get_drvdata(dev);
+ struct wacom *wacom = hid_get_drvdata(hdev);
int err;
if (count != 1024)
@@ -1201,6 +1159,7 @@ static void wacom_wireless_work(struct work_struct *work)
struct wacom *wacom = container_of(work, struct wacom, work);
struct usb_device *usbdev = wacom->usbdev;
struct wacom_wac *wacom_wac = &wacom->wacom_wac;
+ struct hid_device *hdev1, *hdev2;
struct wacom *wacom1, *wacom2;
struct wacom_wac *wacom_wac1, *wacom_wac2;
int error;
@@ -1213,32 +1172,34 @@ static void wacom_wireless_work(struct work_struct *work)
wacom_destroy_battery(wacom);
/* Stylus interface */
- wacom1 = usb_get_intfdata(usbdev->config->interface[1]);
+ hdev1 = usb_get_intfdata(usbdev->config->interface[1]);
+ wacom1 = hid_get_drvdata(hdev1);
wacom_wac1 = &(wacom1->wacom_wac);
wacom_unregister_inputs(wacom1);
/* Touch interface */
- wacom2 = usb_get_intfdata(usbdev->config->interface[2]);
+ hdev2 = usb_get_intfdata(usbdev->config->interface[2]);
+ wacom2 = hid_get_drvdata(hdev2);
wacom_wac2 = &(wacom2->wacom_wac);
wacom_unregister_inputs(wacom2);
if (wacom_wac->pid == 0) {
dev_info(&wacom->intf->dev, "wireless tablet disconnected\n");
} else {
- const struct usb_device_id *id = wacom_ids;
+ const struct hid_device_id *id = wacom_ids;
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 &&
- id->idProduct == wacom_wac->pid)
+ while (id->bus) {
+ if (id->vendor == USB_VENDOR_ID_WACOM &&
+ id->product == wacom_wac->pid)
break;
id++;
}
- if (!id->match_flags) {
+ if (!id->bus) {
dev_info(&wacom->intf->dev,
"ignoring unknown PID.\n");
return;
@@ -1246,7 +1207,7 @@ static void wacom_wireless_work(struct work_struct *work)
/* Stylus interface */
wacom_wac1->features =
- *((struct wacom_features *)id->driver_info);
+ *((struct wacom_features *)id->driver_data);
wacom_wac1->features.device_type = BTN_TOOL_PEN;
snprintf(wacom_wac1->name, WACOM_NAME_MAX, "%s (WL) Pen",
wacom_wac1->features.name);
@@ -1262,7 +1223,7 @@ static void wacom_wireless_work(struct work_struct *work)
if (wacom_wac1->features.touch_max ||
wacom_wac1->features.type == INTUOSHT) {
wacom_wac2->features =
- *((struct wacom_features *)id->driver_info);
+ *((struct wacom_features *)id->driver_data);
wacom_wac2->features.pktlen = WACOM_PKGLEN_BBTOUCH3;
wacom_wac2->features.device_type = BTN_TOOL_FINGER;
wacom_wac2->features.x_max = wacom_wac2->features.y_max = 4096;
@@ -1323,8 +1284,10 @@ static void wacom_calculate_res(struct wacom_features *features)
features->unitExpo);
}
-static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *id)
+static int wacom_probe(struct hid_device *hdev,
+ const struct hid_device_id *id)
{
+ struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
struct usb_device *dev = interface_to_usbdev(intf);
struct usb_endpoint_descriptor *endpoint;
struct wacom *wacom;
@@ -1332,34 +1295,29 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i
struct wacom_features *features;
int error;
- if (!id->driver_info)
+ if (!id->driver_data)
return -EINVAL;
wacom = kzalloc(sizeof(struct wacom), GFP_KERNEL);
if (!wacom)
return -ENOMEM;
+ hid_set_drvdata(hdev, wacom);
+ wacom->hdev = hdev;
+
wacom_wac = &wacom->wacom_wac;
- wacom_wac->features = *((struct wacom_features *)id->driver_info);
+ wacom_wac->features = *((struct wacom_features *)id->driver_data);
features = &wacom_wac->features;
if (features->pktlen > WACOM_PKGLEN_MAX) {
error = -EINVAL;
goto fail1;
}
- wacom_wac->data = usb_alloc_coherent(dev, WACOM_PKGLEN_MAX,
- GFP_KERNEL, &wacom->data_dma);
- if (!wacom_wac->data) {
- error = -ENOMEM;
+ if (features->check_for_hid_type && features->hid_type != hdev->type) {
+ error = -ENODEV;
goto fail1;
}
- wacom->irq = usb_alloc_urb(0, GFP_KERNEL);
- if (!wacom->irq) {
- error = -ENOMEM;
- goto fail2;
- }
-
wacom->usbdev = dev;
wacom->intf = intf;
mutex_init(&wacom->lock);
@@ -1375,7 +1333,7 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i
/* Retrieve the physical and logical size for touch devices */
error = wacom_retrieve_hid_descriptor(intf, features);
if (error)
- goto fail3;
+ goto fail1;
/*
* Intuos5 has no useful data about its touch interface in its
@@ -1423,38 +1381,38 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i
other_dev = dev;
error = wacom_add_shared_data(wacom_wac, other_dev);
if (error)
- goto fail3;
+ goto fail1;
}
- usb_fill_int_urb(wacom->irq, dev,
- usb_rcvintpipe(dev, endpoint->bEndpointAddress),
- wacom_wac->data, features->pktlen,
- wacom_sys_irq, wacom, endpoint->bInterval);
- wacom->irq->transfer_dma = wacom->data_dma;
- wacom->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
-
error = wacom_initialize_leds(wacom);
if (error)
- goto fail4;
+ goto fail2;
if (!(features->quirks & WACOM_QUIRK_NO_INPUT)) {
error = wacom_register_inputs(wacom);
if (error)
- goto fail5;
+ goto fail3;
}
/* Note that if query fails it is not a hard failure */
wacom_query_tablet_data(intf, features);
- usb_set_intfdata(intf, wacom);
+ /* Regular HID work starts now */
+ error = hid_parse(hdev);
+ if (error) {
+ hid_err(hdev, "parse failed\n");
+ goto fail4;
+ }
- if (features->quirks & WACOM_QUIRK_MONITOR) {
- if (usb_submit_urb(wacom->irq, GFP_KERNEL)) {
- error = -EIO;
- goto fail5;
- }
+ error = hid_hw_start(hdev, HID_CONNECT_HIDRAW);
+ if (error) {
+ hid_err(hdev, "hw start failed\n");
+ goto fail4;
}
+ if (features->quirks & WACOM_QUIRK_MONITOR)
+ error = hid_hw_open(hdev);
+
if (wacom_wac->features.type == INTUOSHT && wacom_wac->features.touch_max) {
if (wacom_wac->features.device_type == BTN_TOOL_FINGER)
wacom_wac->shared->touch_input = wacom_wac->input;
@@ -1462,78 +1420,60 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i
return 0;
- fail5: wacom_destroy_leds(wacom);
- fail4: wacom_remove_shared_data(wacom_wac);
- fail3: usb_free_urb(wacom->irq);
- fail2: usb_free_coherent(dev, WACOM_PKGLEN_MAX, wacom_wac->data, wacom->data_dma);
+ fail4: wacom_unregister_inputs(wacom);
+ fail3: wacom_destroy_leds(wacom);
+ fail2: wacom_remove_shared_data(wacom_wac);
fail1: kfree(wacom);
+ hid_set_drvdata(hdev, NULL);
return error;
}
-static void wacom_disconnect(struct usb_interface *intf)
+static void wacom_remove(struct hid_device *hdev)
{
- struct wacom *wacom = usb_get_intfdata(intf);
+ struct wacom *wacom = hid_get_drvdata(hdev);
- usb_set_intfdata(intf, NULL);
+ hid_hw_stop(hdev);
- usb_kill_urb(wacom->irq);
cancel_work_sync(&wacom->work);
wacom_unregister_inputs(wacom);
wacom_destroy_battery(wacom);
wacom_destroy_leds(wacom);
- usb_free_urb(wacom->irq);
- usb_free_coherent(interface_to_usbdev(intf), WACOM_PKGLEN_MAX,
- wacom->wacom_wac.data, wacom->data_dma);
wacom_remove_shared_data(&wacom->wacom_wac);
- kfree(wacom);
-}
-
-static int wacom_suspend(struct usb_interface *intf, pm_message_t message)
-{
- struct wacom *wacom = usb_get_intfdata(intf);
-
- mutex_lock(&wacom->lock);
- usb_kill_urb(wacom->irq);
- mutex_unlock(&wacom->lock);
- return 0;
+ hid_set_drvdata(hdev, NULL);
+ kfree(wacom);
}
-static int wacom_resume(struct usb_interface *intf)
+static int wacom_resume(struct hid_device *hdev)
{
- struct wacom *wacom = usb_get_intfdata(intf);
+ struct wacom *wacom = hid_get_drvdata(hdev);
struct wacom_features *features = &wacom->wacom_wac.features;
- int rv = 0;
mutex_lock(&wacom->lock);
/* switch to wacom mode first */
- wacom_query_tablet_data(intf, features);
+ wacom_query_tablet_data(wacom->intf, features);
wacom_led_control(wacom);
- if ((wacom->open || (features->quirks & WACOM_QUIRK_MONITOR)) &&
- usb_submit_urb(wacom->irq, GFP_NOIO) < 0)
- rv = -EIO;
-
mutex_unlock(&wacom->lock);
- return rv;
+ return 0;
}
-static int wacom_reset_resume(struct usb_interface *intf)
+static int wacom_reset_resume(struct hid_device *hdev)
{
- return wacom_resume(intf);
+ return wacom_resume(hdev);
}
-static struct usb_driver wacom_driver = {
+static struct hid_driver wacom_driver = {
.name = "wacom",
.id_table = wacom_ids,
.probe = wacom_probe,
- .disconnect = wacom_disconnect,
- .suspend = wacom_suspend,
+ .remove = wacom_remove,
+#ifdef CONFIG_PM
.resume = wacom_resume,
.reset_resume = wacom_reset_resume,
- .supports_autosuspend = 1,
+#endif
+ .raw_event = wacom_raw_event,
};
-
-module_usb_driver(wacom_driver);
+module_hid_driver(wacom_driver);