|
|
@@ -13,23 +13,26 @@
|
|
|
|
|
|
#include "wacom_wac.h"
|
|
|
#include "wacom.h"
|
|
|
-#include <linux/hid.h>
|
|
|
|
|
|
#define WAC_MSG_RETRIES 5
|
|
|
|
|
|
+#define WAC_CMD_WL_LED_CONTROL 0x03
|
|
|
#define WAC_CMD_LED_CONTROL 0x20
|
|
|
#define WAC_CMD_ICON_START 0x21
|
|
|
#define WAC_CMD_ICON_XFER 0x23
|
|
|
#define WAC_CMD_ICON_BT_XFER 0x26
|
|
|
#define WAC_CMD_RETRIES 10
|
|
|
|
|
|
-static int wacom_get_report(struct hid_device *hdev, u8 type, u8 id,
|
|
|
- void *buf, size_t size, unsigned int retries)
|
|
|
+#define DEV_ATTR_RW_PERM (S_IRUGO | S_IWUSR | S_IWGRP)
|
|
|
+#define DEV_ATTR_WO_PERM (S_IWUSR | S_IWGRP)
|
|
|
+
|
|
|
+static int wacom_get_report(struct hid_device *hdev, u8 type, u8 *buf,
|
|
|
+ size_t size, unsigned int retries)
|
|
|
{
|
|
|
int retval;
|
|
|
|
|
|
do {
|
|
|
- retval = hid_hw_raw_request(hdev, id, buf, size, type,
|
|
|
+ retval = hid_hw_raw_request(hdev, buf[0], buf, size, type,
|
|
|
HID_REQ_GET_REPORT);
|
|
|
} while ((retval == -ETIMEDOUT || retval == -EPIPE) && --retries);
|
|
|
|
|
|
@@ -106,12 +109,35 @@ static void wacom_feature_mapping(struct hid_device *hdev,
|
|
|
{
|
|
|
struct wacom *wacom = hid_get_drvdata(hdev);
|
|
|
struct wacom_features *features = &wacom->wacom_wac.features;
|
|
|
+ struct hid_data *hid_data = &wacom->wacom_wac.hid_data;
|
|
|
+ u8 *data;
|
|
|
+ int ret;
|
|
|
|
|
|
switch (usage->hid) {
|
|
|
case HID_DG_CONTACTMAX:
|
|
|
/* leave touch_max as is if predefined */
|
|
|
- if (!features->touch_max)
|
|
|
- features->touch_max = field->value[0];
|
|
|
+ if (!features->touch_max) {
|
|
|
+ /* read manually */
|
|
|
+ data = kzalloc(2, GFP_KERNEL);
|
|
|
+ if (!data)
|
|
|
+ break;
|
|
|
+ data[0] = field->report->id;
|
|
|
+ ret = wacom_get_report(hdev, HID_FEATURE_REPORT,
|
|
|
+ data, 2, 0);
|
|
|
+ if (ret == 2)
|
|
|
+ features->touch_max = data[1];
|
|
|
+ kfree(data);
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ case HID_DG_INPUTMODE:
|
|
|
+ /* Ignore if value index is out of bounds. */
|
|
|
+ if (usage->usage_index >= field->report_count) {
|
|
|
+ dev_err(&hdev->dev, "HID_DG_INPUTMODE out of range\n");
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ hid_data->inputmode = field->report->id;
|
|
|
+ hid_data->inputmode_index = usage->usage_index;
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
@@ -199,6 +225,9 @@ static void wacom_usage_mapping(struct hid_device *hdev,
|
|
|
features->pressure_max = field->logical_maximum;
|
|
|
break;
|
|
|
}
|
|
|
+
|
|
|
+ if (features->type == HID_GENERIC)
|
|
|
+ wacom_wac_usage_mapping(hdev, field, usage);
|
|
|
}
|
|
|
|
|
|
static void wacom_parse_hid(struct hid_device *hdev,
|
|
|
@@ -237,6 +266,25 @@ static void wacom_parse_hid(struct hid_device *hdev,
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+static int wacom_hid_set_device_mode(struct hid_device *hdev)
|
|
|
+{
|
|
|
+ struct wacom *wacom = hid_get_drvdata(hdev);
|
|
|
+ struct hid_data *hid_data = &wacom->wacom_wac.hid_data;
|
|
|
+ struct hid_report *r;
|
|
|
+ struct hid_report_enum *re;
|
|
|
+
|
|
|
+ if (hid_data->inputmode < 0)
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ re = &(hdev->report_enum[HID_FEATURE_REPORT]);
|
|
|
+ r = re->report_id_hash[hid_data->inputmode];
|
|
|
+ if (r) {
|
|
|
+ r->field[0]->value[hid_data->inputmode_index] = 2;
|
|
|
+ hid_hw_request(hdev, r, HID_REQ_SET_REPORT);
|
|
|
+ }
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
static int wacom_set_device_mode(struct hid_device *hdev, int report_id,
|
|
|
int length, int mode)
|
|
|
{
|
|
|
@@ -255,7 +303,7 @@ static int wacom_set_device_mode(struct hid_device *hdev, int report_id,
|
|
|
length, 1);
|
|
|
if (error >= 0)
|
|
|
error = wacom_get_report(hdev, HID_FEATURE_REPORT,
|
|
|
- report_id, rep_data, length, 1);
|
|
|
+ rep_data, length, 1);
|
|
|
} while ((error < 0 || rep_data[1] != mode) && limit++ < WAC_MSG_RETRIES);
|
|
|
|
|
|
kfree(rep_data);
|
|
|
@@ -329,6 +377,9 @@ static int wacom_query_tablet_data(struct hid_device *hdev,
|
|
|
if (hdev->bus == BUS_BLUETOOTH)
|
|
|
return wacom_bt_query_tablet_data(hdev, 1, features);
|
|
|
|
|
|
+ if (features->type == HID_GENERIC)
|
|
|
+ return wacom_hid_set_device_mode(hdev);
|
|
|
+
|
|
|
if (features->device_type == BTN_TOOL_FINGER) {
|
|
|
if (features->type > TABLETPC) {
|
|
|
/* MT Tablet PC touch */
|
|
|
@@ -487,8 +538,14 @@ static int wacom_led_control(struct wacom *wacom)
|
|
|
{
|
|
|
unsigned char *buf;
|
|
|
int retval;
|
|
|
+ unsigned char report_id = WAC_CMD_LED_CONTROL;
|
|
|
+ int buf_size = 9;
|
|
|
|
|
|
- buf = kzalloc(9, GFP_KERNEL);
|
|
|
+ if (wacom->wacom_wac.pid) { /* wireless connected */
|
|
|
+ report_id = WAC_CMD_WL_LED_CONTROL;
|
|
|
+ buf_size = 13;
|
|
|
+ }
|
|
|
+ buf = kzalloc(buf_size, GFP_KERNEL);
|
|
|
if (!buf)
|
|
|
return -ENOMEM;
|
|
|
|
|
|
@@ -502,9 +559,16 @@ static int wacom_led_control(struct wacom *wacom)
|
|
|
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);
|
|
|
+ unsigned char led_bits = (crop_lum << 4) | (ring_lum << 2) | (ring_led);
|
|
|
+
|
|
|
+ buf[0] = report_id;
|
|
|
+ if (wacom->wacom_wac.pid) {
|
|
|
+ wacom_get_report(wacom->hdev, HID_FEATURE_REPORT,
|
|
|
+ buf, buf_size, WAC_CMD_RETRIES);
|
|
|
+ buf[0] = report_id;
|
|
|
+ buf[4] = led_bits;
|
|
|
+ } else
|
|
|
+ buf[1] = led_bits;
|
|
|
}
|
|
|
else {
|
|
|
int led = wacom->led.select[0] | 0x4;
|
|
|
@@ -513,14 +577,14 @@ static int wacom_led_control(struct wacom *wacom)
|
|
|
wacom->wacom_wac.features.type == WACOM_24HD)
|
|
|
led |= (wacom->led.select[1] << 4) | 0x40;
|
|
|
|
|
|
- buf[0] = WAC_CMD_LED_CONTROL;
|
|
|
+ buf[0] = report_id;
|
|
|
buf[1] = led;
|
|
|
buf[2] = wacom->led.llv;
|
|
|
buf[3] = wacom->led.hlv;
|
|
|
buf[4] = wacom->led.img_lum;
|
|
|
}
|
|
|
|
|
|
- retval = wacom_set_report(wacom->hdev, HID_FEATURE_REPORT, buf, 9,
|
|
|
+ retval = wacom_set_report(wacom->hdev, HID_FEATURE_REPORT, buf, buf_size,
|
|
|
WAC_CMD_RETRIES);
|
|
|
kfree(buf);
|
|
|
|
|
|
@@ -602,9 +666,10 @@ static ssize_t wacom_led##SET_ID##_select_show(struct device *dev, \
|
|
|
{ \
|
|
|
struct hid_device *hdev = container_of(dev, struct hid_device, dev);\
|
|
|
struct wacom *wacom = hid_get_drvdata(hdev); \
|
|
|
- return snprintf(buf, 2, "%d\n", wacom->led.select[SET_ID]); \
|
|
|
+ return scnprintf(buf, PAGE_SIZE, "%d\n", \
|
|
|
+ wacom->led.select[SET_ID]); \
|
|
|
} \
|
|
|
-static DEVICE_ATTR(status_led##SET_ID##_select, S_IWUSR | S_IRUSR, \
|
|
|
+static DEVICE_ATTR(status_led##SET_ID##_select, DEV_ATTR_RW_PERM, \
|
|
|
wacom_led##SET_ID##_select_show, \
|
|
|
wacom_led##SET_ID##_select_store)
|
|
|
|
|
|
@@ -641,8 +706,15 @@ static ssize_t wacom_##name##_luminance_store(struct device *dev, \
|
|
|
return wacom_luminance_store(wacom, &wacom->led.field, \
|
|
|
buf, count); \
|
|
|
} \
|
|
|
-static DEVICE_ATTR(name##_luminance, S_IWUSR, \
|
|
|
- NULL, wacom_##name##_luminance_store)
|
|
|
+static ssize_t wacom_##name##_luminance_show(struct device *dev, \
|
|
|
+ struct device_attribute *attr, char *buf) \
|
|
|
+{ \
|
|
|
+ struct wacom *wacom = dev_get_drvdata(dev); \
|
|
|
+ return scnprintf(buf, PAGE_SIZE, "%d\n", wacom->led.field); \
|
|
|
+} \
|
|
|
+static DEVICE_ATTR(name##_luminance, DEV_ATTR_RW_PERM, \
|
|
|
+ wacom_##name##_luminance_show, \
|
|
|
+ wacom_##name##_luminance_store)
|
|
|
|
|
|
DEVICE_LUMINANCE_ATTR(status0, llv);
|
|
|
DEVICE_LUMINANCE_ATTR(status1, hlv);
|
|
|
@@ -683,7 +755,7 @@ static ssize_t wacom_btnimg##BUTTON_ID##_store(struct device *dev, \
|
|
|
{ \
|
|
|
return wacom_button_image_store(dev, BUTTON_ID, buf, count); \
|
|
|
} \
|
|
|
-static DEVICE_ATTR(button##BUTTON_ID##_rawimg, S_IWUSR, \
|
|
|
+static DEVICE_ATTR(button##BUTTON_ID##_rawimg, DEV_ATTR_WO_PERM, \
|
|
|
NULL, wacom_btnimg##BUTTON_ID##_store)
|
|
|
|
|
|
DEVICE_BTNIMG_ATTR(0);
|
|
|
@@ -989,7 +1061,7 @@ static ssize_t wacom_store_speed(struct device *dev,
|
|
|
return count;
|
|
|
}
|
|
|
|
|
|
-static DEVICE_ATTR(speed, S_IRUGO | S_IWUSR | S_IWGRP,
|
|
|
+static DEVICE_ATTR(speed, DEV_ATTR_RW_PERM,
|
|
|
wacom_show_speed, wacom_store_speed);
|
|
|
|
|
|
static struct input_dev *wacom_allocate_input(struct wacom *wacom)
|
|
|
@@ -1010,47 +1082,82 @@ static struct input_dev *wacom_allocate_input(struct wacom *wacom)
|
|
|
input_dev->uniq = hdev->uniq;
|
|
|
input_dev->id.bustype = hdev->bus;
|
|
|
input_dev->id.vendor = hdev->vendor;
|
|
|
- input_dev->id.product = hdev->product;
|
|
|
+ input_dev->id.product = wacom_wac->pid ? wacom_wac->pid : hdev->product;
|
|
|
input_dev->id.version = hdev->version;
|
|
|
input_set_drvdata(input_dev, wacom);
|
|
|
|
|
|
return input_dev;
|
|
|
}
|
|
|
|
|
|
-static void wacom_unregister_inputs(struct wacom *wacom)
|
|
|
+static void wacom_free_inputs(struct wacom *wacom)
|
|
|
{
|
|
|
- if (wacom->wacom_wac.input)
|
|
|
- input_unregister_device(wacom->wacom_wac.input);
|
|
|
- if (wacom->wacom_wac.pad_input)
|
|
|
- input_unregister_device(wacom->wacom_wac.pad_input);
|
|
|
- wacom->wacom_wac.input = NULL;
|
|
|
- wacom->wacom_wac.pad_input = NULL;
|
|
|
+ struct wacom_wac *wacom_wac = &(wacom->wacom_wac);
|
|
|
+
|
|
|
+ if (wacom_wac->input)
|
|
|
+ input_free_device(wacom_wac->input);
|
|
|
+ if (wacom_wac->pad_input)
|
|
|
+ input_free_device(wacom_wac->pad_input);
|
|
|
+ wacom_wac->input = NULL;
|
|
|
+ wacom_wac->pad_input = NULL;
|
|
|
}
|
|
|
|
|
|
-static int wacom_register_inputs(struct wacom *wacom)
|
|
|
+static int wacom_allocate_inputs(struct wacom *wacom)
|
|
|
{
|
|
|
struct input_dev *input_dev, *pad_input_dev;
|
|
|
struct wacom_wac *wacom_wac = &(wacom->wacom_wac);
|
|
|
- int error;
|
|
|
|
|
|
input_dev = wacom_allocate_input(wacom);
|
|
|
pad_input_dev = wacom_allocate_input(wacom);
|
|
|
if (!input_dev || !pad_input_dev) {
|
|
|
- error = -ENOMEM;
|
|
|
- goto fail1;
|
|
|
+ wacom_free_inputs(wacom);
|
|
|
+ return -ENOMEM;
|
|
|
}
|
|
|
|
|
|
wacom_wac->input = input_dev;
|
|
|
wacom_wac->pad_input = pad_input_dev;
|
|
|
wacom_wac->pad_input->name = wacom_wac->pad_name;
|
|
|
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static void wacom_clean_inputs(struct wacom *wacom)
|
|
|
+{
|
|
|
+ if (wacom->wacom_wac.input) {
|
|
|
+ if (wacom->wacom_wac.input_registered)
|
|
|
+ input_unregister_device(wacom->wacom_wac.input);
|
|
|
+ else
|
|
|
+ input_free_device(wacom->wacom_wac.input);
|
|
|
+ }
|
|
|
+ if (wacom->wacom_wac.pad_input) {
|
|
|
+ if (wacom->wacom_wac.input_registered)
|
|
|
+ input_unregister_device(wacom->wacom_wac.pad_input);
|
|
|
+ else
|
|
|
+ input_free_device(wacom->wacom_wac.pad_input);
|
|
|
+ }
|
|
|
+ wacom->wacom_wac.input = NULL;
|
|
|
+ wacom->wacom_wac.pad_input = NULL;
|
|
|
+ wacom_destroy_leds(wacom);
|
|
|
+}
|
|
|
+
|
|
|
+static int wacom_register_inputs(struct wacom *wacom)
|
|
|
+{
|
|
|
+ struct input_dev *input_dev, *pad_input_dev;
|
|
|
+ struct wacom_wac *wacom_wac = &(wacom->wacom_wac);
|
|
|
+ int error;
|
|
|
+
|
|
|
+ input_dev = wacom_wac->input;
|
|
|
+ pad_input_dev = wacom_wac->pad_input;
|
|
|
+
|
|
|
+ if (!input_dev || !pad_input_dev)
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
error = wacom_setup_input_capabilities(input_dev, wacom_wac);
|
|
|
if (error)
|
|
|
- goto fail2;
|
|
|
+ return error;
|
|
|
|
|
|
error = input_register_device(input_dev);
|
|
|
if (error)
|
|
|
- goto fail2;
|
|
|
+ return error;
|
|
|
|
|
|
error = wacom_setup_pad_input_capabilities(pad_input_dev, wacom_wac);
|
|
|
if (error) {
|
|
|
@@ -1061,22 +1168,23 @@ static int wacom_register_inputs(struct wacom *wacom)
|
|
|
} else {
|
|
|
error = input_register_device(pad_input_dev);
|
|
|
if (error)
|
|
|
- goto fail3;
|
|
|
+ goto fail_register_pad_input;
|
|
|
+
|
|
|
+ error = wacom_initialize_leds(wacom);
|
|
|
+ if (error)
|
|
|
+ goto fail_leds;
|
|
|
}
|
|
|
|
|
|
+ wacom_wac->input_registered = true;
|
|
|
+
|
|
|
return 0;
|
|
|
|
|
|
-fail3:
|
|
|
+fail_leds:
|
|
|
+ input_unregister_device(pad_input_dev);
|
|
|
+ pad_input_dev = NULL;
|
|
|
+fail_register_pad_input:
|
|
|
input_unregister_device(input_dev);
|
|
|
- input_dev = NULL;
|
|
|
-fail2:
|
|
|
wacom_wac->input = NULL;
|
|
|
- wacom_wac->pad_input = NULL;
|
|
|
-fail1:
|
|
|
- if (input_dev)
|
|
|
- input_free_device(input_dev);
|
|
|
- if (pad_input_dev)
|
|
|
- input_free_device(pad_input_dev);
|
|
|
return error;
|
|
|
}
|
|
|
|
|
|
@@ -1101,13 +1209,13 @@ static void wacom_wireless_work(struct work_struct *work)
|
|
|
hdev1 = usb_get_intfdata(usbdev->config->interface[1]);
|
|
|
wacom1 = hid_get_drvdata(hdev1);
|
|
|
wacom_wac1 = &(wacom1->wacom_wac);
|
|
|
- wacom_unregister_inputs(wacom1);
|
|
|
+ wacom_clean_inputs(wacom1);
|
|
|
|
|
|
/* Touch interface */
|
|
|
hdev2 = usb_get_intfdata(usbdev->config->interface[2]);
|
|
|
wacom2 = hid_get_drvdata(hdev2);
|
|
|
wacom_wac2 = &(wacom2->wacom_wac);
|
|
|
- wacom_unregister_inputs(wacom2);
|
|
|
+ wacom_clean_inputs(wacom2);
|
|
|
|
|
|
if (wacom_wac->pid == 0) {
|
|
|
hid_info(wacom->hdev, "wireless tablet disconnected\n");
|
|
|
@@ -1140,7 +1248,9 @@ static void wacom_wireless_work(struct work_struct *work)
|
|
|
wacom_wac1->features.name);
|
|
|
wacom_wac1->shared->touch_max = wacom_wac1->features.touch_max;
|
|
|
wacom_wac1->shared->type = wacom_wac1->features.type;
|
|
|
- error = wacom_register_inputs(wacom1);
|
|
|
+ wacom_wac1->pid = wacom_wac->pid;
|
|
|
+ error = wacom_allocate_inputs(wacom1) ||
|
|
|
+ wacom_register_inputs(wacom1);
|
|
|
if (error)
|
|
|
goto fail;
|
|
|
|
|
|
@@ -1160,7 +1270,9 @@ static void wacom_wireless_work(struct work_struct *work)
|
|
|
"%s (WL) Pad",wacom_wac2->features.name);
|
|
|
snprintf(wacom_wac2->pad_name, WACOM_NAME_MAX,
|
|
|
"%s (WL) Pad", wacom_wac2->features.name);
|
|
|
- error = wacom_register_inputs(wacom2);
|
|
|
+ wacom_wac2->pid = wacom_wac->pid;
|
|
|
+ error = wacom_allocate_inputs(wacom2) ||
|
|
|
+ wacom_register_inputs(wacom2);
|
|
|
if (error)
|
|
|
goto fail;
|
|
|
|
|
|
@@ -1177,8 +1289,8 @@ static void wacom_wireless_work(struct work_struct *work)
|
|
|
return;
|
|
|
|
|
|
fail:
|
|
|
- wacom_unregister_inputs(wacom1);
|
|
|
- wacom_unregister_inputs(wacom2);
|
|
|
+ wacom_clean_inputs(wacom1);
|
|
|
+ wacom_clean_inputs(wacom2);
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
@@ -1241,10 +1353,13 @@ static int wacom_probe(struct hid_device *hdev,
|
|
|
struct wacom_wac *wacom_wac;
|
|
|
struct wacom_features *features;
|
|
|
int error;
|
|
|
+ unsigned int connect_mask = HID_CONNECT_HIDRAW;
|
|
|
|
|
|
if (!id->driver_data)
|
|
|
return -EINVAL;
|
|
|
|
|
|
+ hdev->quirks |= HID_QUIRK_NO_INIT_REPORTS;
|
|
|
+
|
|
|
wacom = kzalloc(sizeof(struct wacom), GFP_KERNEL);
|
|
|
if (!wacom)
|
|
|
return -ENOMEM;
|
|
|
@@ -1256,7 +1371,7 @@ static int wacom_probe(struct hid_device *hdev,
|
|
|
error = hid_parse(hdev);
|
|
|
if (error) {
|
|
|
hid_err(hdev, "parse failed\n");
|
|
|
- goto fail1;
|
|
|
+ goto fail_parse;
|
|
|
}
|
|
|
|
|
|
wacom_wac = &wacom->wacom_wac;
|
|
|
@@ -1265,12 +1380,12 @@ static int wacom_probe(struct hid_device *hdev,
|
|
|
features->pktlen = wacom_compute_pktlen(hdev);
|
|
|
if (features->pktlen > WACOM_PKGLEN_MAX) {
|
|
|
error = -EINVAL;
|
|
|
- goto fail1;
|
|
|
+ goto fail_pktlen;
|
|
|
}
|
|
|
|
|
|
if (features->check_for_hid_type && features->hid_type != hdev->type) {
|
|
|
error = -ENODEV;
|
|
|
- goto fail1;
|
|
|
+ goto fail_type;
|
|
|
}
|
|
|
|
|
|
wacom->usbdev = dev;
|
|
|
@@ -1278,6 +1393,12 @@ static int wacom_probe(struct hid_device *hdev,
|
|
|
mutex_init(&wacom->lock);
|
|
|
INIT_WORK(&wacom->work, wacom_wireless_work);
|
|
|
|
|
|
+ if (!(features->quirks & WACOM_QUIRK_NO_INPUT)) {
|
|
|
+ error = wacom_allocate_inputs(wacom);
|
|
|
+ if (error)
|
|
|
+ goto fail_allocate_inputs;
|
|
|
+ }
|
|
|
+
|
|
|
/* set the default size in case we do not get them from hid */
|
|
|
wacom_set_default_phy(features);
|
|
|
|
|
|
@@ -1339,24 +1460,20 @@ static int wacom_probe(struct hid_device *hdev,
|
|
|
|
|
|
error = wacom_add_shared_data(hdev);
|
|
|
if (error)
|
|
|
- goto fail1;
|
|
|
+ goto fail_shared_data;
|
|
|
}
|
|
|
|
|
|
- error = wacom_initialize_leds(wacom);
|
|
|
- if (error)
|
|
|
- goto fail2;
|
|
|
-
|
|
|
if (!(features->quirks & WACOM_QUIRK_MONITOR) &&
|
|
|
(features->quirks & WACOM_QUIRK_BATTERY)) {
|
|
|
error = wacom_initialize_battery(wacom);
|
|
|
if (error)
|
|
|
- goto fail3;
|
|
|
+ goto fail_battery;
|
|
|
}
|
|
|
|
|
|
if (!(features->quirks & WACOM_QUIRK_NO_INPUT)) {
|
|
|
error = wacom_register_inputs(wacom);
|
|
|
if (error)
|
|
|
- goto fail4;
|
|
|
+ goto fail_register_inputs;
|
|
|
}
|
|
|
|
|
|
if (hdev->bus == BUS_BLUETOOTH) {
|
|
|
@@ -1367,16 +1484,19 @@ static int wacom_probe(struct hid_device *hdev,
|
|
|
error);
|
|
|
}
|
|
|
|
|
|
- /* Note that if query fails it is not a hard failure */
|
|
|
- wacom_query_tablet_data(hdev, features);
|
|
|
+ if (features->type == HID_GENERIC)
|
|
|
+ connect_mask |= HID_CONNECT_DRIVER;
|
|
|
|
|
|
/* Regular HID work starts now */
|
|
|
- error = hid_hw_start(hdev, HID_CONNECT_HIDRAW);
|
|
|
+ error = hid_hw_start(hdev, connect_mask);
|
|
|
if (error) {
|
|
|
hid_err(hdev, "hw start failed\n");
|
|
|
- goto fail5;
|
|
|
+ goto fail_hw_start;
|
|
|
}
|
|
|
|
|
|
+ /* Note that if query fails it is not a hard failure */
|
|
|
+ wacom_query_tablet_data(hdev, features);
|
|
|
+
|
|
|
if (features->quirks & WACOM_QUIRK_MONITOR)
|
|
|
error = hid_hw_open(hdev);
|
|
|
|
|
|
@@ -1387,13 +1507,21 @@ static int wacom_probe(struct hid_device *hdev,
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
- fail5: if (hdev->bus == BUS_BLUETOOTH)
|
|
|
+fail_hw_start:
|
|
|
+ if (hdev->bus == BUS_BLUETOOTH)
|
|
|
device_remove_file(&hdev->dev, &dev_attr_speed);
|
|
|
- wacom_unregister_inputs(wacom);
|
|
|
- fail4: wacom_destroy_battery(wacom);
|
|
|
- fail3: wacom_destroy_leds(wacom);
|
|
|
- fail2: wacom_remove_shared_data(wacom_wac);
|
|
|
- fail1: kfree(wacom);
|
|
|
+fail_register_inputs:
|
|
|
+ wacom_clean_inputs(wacom);
|
|
|
+ wacom_destroy_battery(wacom);
|
|
|
+fail_battery:
|
|
|
+ wacom_remove_shared_data(wacom_wac);
|
|
|
+fail_shared_data:
|
|
|
+ wacom_clean_inputs(wacom);
|
|
|
+fail_allocate_inputs:
|
|
|
+fail_type:
|
|
|
+fail_pktlen:
|
|
|
+fail_parse:
|
|
|
+ kfree(wacom);
|
|
|
hid_set_drvdata(hdev, NULL);
|
|
|
return error;
|
|
|
}
|
|
|
@@ -1405,11 +1533,10 @@ static void wacom_remove(struct hid_device *hdev)
|
|
|
hid_hw_stop(hdev);
|
|
|
|
|
|
cancel_work_sync(&wacom->work);
|
|
|
- wacom_unregister_inputs(wacom);
|
|
|
+ wacom_clean_inputs(wacom);
|
|
|
if (hdev->bus == BUS_BLUETOOTH)
|
|
|
device_remove_file(&hdev->dev, &dev_attr_speed);
|
|
|
wacom_destroy_battery(wacom);
|
|
|
- wacom_destroy_leds(wacom);
|
|
|
wacom_remove_shared_data(&wacom->wacom_wac);
|
|
|
|
|
|
hid_set_drvdata(hdev, NULL);
|
|
|
@@ -1444,6 +1571,8 @@ static struct hid_driver wacom_driver = {
|
|
|
.id_table = wacom_ids,
|
|
|
.probe = wacom_probe,
|
|
|
.remove = wacom_remove,
|
|
|
+ .event = wacom_wac_event,
|
|
|
+ .report = wacom_wac_report,
|
|
|
#ifdef CONFIG_PM
|
|
|
.resume = wacom_resume,
|
|
|
.reset_resume = wacom_reset_resume,
|