#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,
return retval;
}
-static int wacom_set_report(struct hid_device *hdev, u8 type, u8 id,
- void *buf, size_t size, unsigned int retries)
+static int wacom_set_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_SET_REPORT);
} while ((retval == -ETIMEDOUT || retval == -EPIPE) && --retries);
rep_data[0] = report_id;
rep_data[1] = mode;
- error = wacom_set_report(hdev, HID_FEATURE_REPORT,
- report_id, rep_data, length, 1);
+ error = wacom_set_report(hdev, HID_FEATURE_REPORT, rep_data,
+ length, 1);
if (error >= 0)
error = wacom_get_report(hdev, HID_FEATURE_REPORT,
report_id, rep_data, length, 1);
static int wacom_bt_query_tablet_data(struct hid_device *hdev, u8 speed,
struct wacom_features *features)
{
+ struct wacom *wacom = hid_get_drvdata(hdev);
+ int ret;
+ u8 rep_data[2];
+
+ switch (features->type) {
+ case GRAPHIRE_BT:
+ rep_data[0] = 0x03;
+ rep_data[1] = 0x00;
+ ret = wacom_set_report(hdev, HID_FEATURE_REPORT, rep_data, 2,
+ 3);
+
+ if (ret >= 0) {
+ rep_data[0] = speed == 0 ? 0x05 : 0x06;
+ rep_data[1] = 0x00;
+
+ ret = wacom_set_report(hdev, HID_FEATURE_REPORT,
+ rep_data, 2, 3);
+
+ if (ret >= 0) {
+ wacom->wacom_wac.bt_high_speed = speed;
+ return 0;
+ }
+ }
+
+ /*
+ * Note that if the raw queries fail, it's not a hard failure
+ * and it is safe to continue
+ */
+ hid_warn(hdev, "failed to poke device, command %d, err %d\n",
+ rep_data[0], ret);
+ break;
+ case INTUOS4WL:
+ if (speed == 1)
+ wacom->wacom_wac.bt_features &= ~0x20;
+ else
+ wacom->wacom_wac.bt_features |= 0x20;
+
+ rep_data[0] = 0x03;
+ rep_data[1] = wacom->wacom_wac.bt_features;
+
+ ret = wacom_set_report(hdev, HID_FEATURE_REPORT, rep_data, 2,
+ 1);
+ if (ret >= 0)
+ wacom->wacom_wac.bt_high_speed = speed;
+ break;
+ }
+
return 0;
}
buf[4] = wacom->led.img_lum;
}
- retval = wacom_set_report(wacom->hdev, HID_FEATURE_REPORT,
- WAC_CMD_LED_CONTROL, buf, 9, WAC_CMD_RETRIES);
+ retval = wacom_set_report(wacom->hdev, HID_FEATURE_REPORT, buf, 9,
+ WAC_CMD_RETRIES);
kfree(buf);
return retval;
}
-static int wacom_led_putimage(struct wacom *wacom, int button_id, const void *img)
+static int wacom_led_putimage(struct wacom *wacom, int button_id, u8 xfer_id,
+ const unsigned len, const void *img)
{
unsigned char *buf;
int i, retval;
+ const unsigned chunk_len = len / 4; /* 4 chunks are needed to be sent */
- buf = kzalloc(259, GFP_KERNEL);
+ buf = kzalloc(chunk_len + 3 , GFP_KERNEL);
if (!buf)
return -ENOMEM;
/* Send 'start' command */
buf[0] = WAC_CMD_ICON_START;
buf[1] = 1;
- retval = wacom_set_report(wacom->hdev, HID_FEATURE_REPORT,
- WAC_CMD_ICON_START, buf, 2, WAC_CMD_RETRIES);
+ retval = wacom_set_report(wacom->hdev, HID_FEATURE_REPORT, buf, 2,
+ WAC_CMD_RETRIES);
if (retval < 0)
goto out;
- buf[0] = WAC_CMD_ICON_XFER;
+ buf[0] = xfer_id;
buf[1] = button_id & 0x07;
for (i = 0; i < 4; i++) {
buf[2] = i;
- memcpy(buf + 3, img + i * 256, 256);
+ memcpy(buf + 3, img + i * chunk_len, chunk_len);
retval = wacom_set_report(wacom->hdev, HID_FEATURE_REPORT,
- WAC_CMD_ICON_XFER,
- buf, 259, WAC_CMD_RETRIES);
+ buf, chunk_len + 3, WAC_CMD_RETRIES);
if (retval < 0)
break;
}
/* Send 'stop' */
buf[0] = WAC_CMD_ICON_START;
buf[1] = 0;
- wacom_set_report(wacom->hdev, HID_FEATURE_REPORT, WAC_CMD_ICON_START,
- buf, 2, WAC_CMD_RETRIES);
+ wacom_set_report(wacom->hdev, HID_FEATURE_REPORT, buf, 2,
+ WAC_CMD_RETRIES);
out:
kfree(buf);
struct hid_device *hdev = container_of(dev, struct hid_device, dev);
struct wacom *wacom = hid_get_drvdata(hdev);
int err;
+ unsigned len;
+ u8 xfer_id;
+
+ if (hdev->bus == BUS_BLUETOOTH) {
+ len = 256;
+ xfer_id = WAC_CMD_ICON_BT_XFER;
+ } else {
+ len = 1024;
+ xfer_id = WAC_CMD_ICON_XFER;
+ }
- if (count != 1024)
+ if (count != len)
return -EINVAL;
mutex_lock(&wacom->lock);
- err = wacom_led_putimage(wacom, button_id, buf);
+ err = wacom_led_putimage(wacom, button_id, xfer_id, len, buf);
mutex_unlock(&wacom->lock);
switch (wacom->wacom_wac.features.type) {
case INTUOS4S:
case INTUOS4:
+ case INTUOS4WL:
case INTUOS4L:
wacom->led.select[0] = 0;
wacom->led.select[1] = 0;
switch (wacom->wacom_wac.features.type) {
case INTUOS4S:
case INTUOS4:
+ case INTUOS4WL:
case INTUOS4L:
sysfs_remove_group(&wacom->hdev->dev.kobj,
&intuos4_led_attr_group);
kfree(wacom);
}
+#ifdef CONFIG_PM
static int wacom_resume(struct hid_device *hdev)
{
struct wacom *wacom = hid_get_drvdata(hdev);
{
return wacom_resume(hdev);
}
+#endif /* CONFIG_PM */
static struct hid_driver wacom_driver = {
.name = "wacom",
.raw_event = wacom_raw_event,
};
module_hid_driver(wacom_driver);
+
+MODULE_VERSION(DRIVER_VERSION);
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE(DRIVER_LICENSE);