if (features->type == HID_GENERIC) {
/* Any last-minute generic device setup */
+++++++++++ if (wacom_wac->has_mode_change) {
+++++++++++ if (wacom_wac->is_direct_mode)
+++++++++++ features->device_type |= WACOM_DEVICETYPE_DIRECT;
+++++++++++ else
+++++++++++ features->device_type &= ~WACOM_DEVICETYPE_DIRECT;
+++++++++++ }
+++++++++++
if (features->touch_max > 1) {
- input_mt_init_slots(wacom_wac->touch_input, wacom_wac->features.touch_max,
- INPUT_MT_DIRECT);
+ if (features->device_type & WACOM_DEVICETYPE_DIRECT)
+ input_mt_init_slots(wacom_wac->touch_input,
+ wacom_wac->features.touch_max,
+ INPUT_MT_DIRECT);
+ else
+ input_mt_init_slots(wacom_wac->touch_input,
+ wacom_wac->features.touch_max,
+ INPUT_MT_POINTER);
}
}
}
"%s%s Pad", name, suffix);
}
------- --- if (wacom_wac->has_mute_touch_switch)
+ static void wacom_release_resources(struct wacom *wacom)
+ {
+ struct hid_device *hdev = wacom->hdev;
+
+ if (!wacom->resources)
+ return;
+
+ devres_release_group(&hdev->dev, wacom);
+
+ wacom->resources = false;
+
+ wacom->wacom_wac.pen_input = NULL;
+ wacom->wacom_wac.touch_input = NULL;
+ wacom->wacom_wac.pad_input = NULL;
+ }
+
+ static void wacom_set_shared_values(struct wacom_wac *wacom_wac)
+ {
+ if (wacom_wac->features.device_type & WACOM_DEVICETYPE_TOUCH) {
+ wacom_wac->shared->type = wacom_wac->features.type;
+ wacom_wac->shared->touch_input = wacom_wac->touch_input;
+ }
+
+++++++++++ if (wacom_wac->has_mute_touch_switch) {
+ wacom_wac->shared->has_mute_touch_switch = true;
+++++++++++ wacom_wac->shared->is_touch_on = true;
+++++++++++ }
+
+ if (wacom_wac->shared->has_mute_touch_switch &&
+ wacom_wac->shared->touch_input) {
+ set_bit(EV_SW, wacom_wac->shared->touch_input->evbit);
+ input_set_capability(wacom_wac->shared->touch_input, EV_SW,
+ SW_MUTE_DEVICE);
+ }
+ }
+
static int wacom_parse_and_register(struct wacom *wacom, bool wireless)
{
struct wacom_wac *wacom_wac = &wacom->wacom_wac;
wacom_update_name(wacom, wireless ? " (WL)" : "");
+++++++++++ /* pen only Bamboo neither support touch nor pad */
+++++++++++ if ((features->type == BAMBOO_PEN) &&
+++++++++++ ((features->device_type & WACOM_DEVICETYPE_TOUCH) ||
+++++++++++ (features->device_type & WACOM_DEVICETYPE_PAD))) {
+++++++++++ error = -ENODEV;
+++++++++++ goto fail;
+++++++++++ }
+++++++++++
error = wacom_add_shared_data(hdev);
if (error)
- goto fail_shared_data;
+ goto fail;
if (!(features->device_type & WACOM_DEVICETYPE_WL_MONITOR) &&
(features->quirks & WACOM_QUIRK_BATTERY)) {
/* touch only Bamboo doesn't support pen */
if ((features->type == BAMBOO_TOUCH) &&
(features->device_type & WACOM_DEVICETYPE_PEN)) {
------ ---- error = -ENODEV;
------ ---- goto fail_quirks;
------ ---- }
------ ----
------ ---- /* pen only Bamboo neither support touch nor pad */
------ ---- if ((features->type == BAMBOO_PEN) &&
------ ---- ((features->device_type & WACOM_DEVICETYPE_TOUCH) ||
------ ---- (features->device_type & WACOM_DEVICETYPE_PAD))) {
+++++++++++ cancel_delayed_work_sync(&wacom->init_work);
+++++++++++ _wacom_query_tablet_data(wacom);
error = -ENODEV;
- goto fail_hw_start;
- }
-
- /* pen only Bamboo neither support touch nor pad */
- if ((features->type == BAMBOO_PEN) &&
- ((features->device_type & WACOM_DEVICETYPE_TOUCH) ||
- (features->device_type & WACOM_DEVICETYPE_PAD))) {
- error = -ENODEV;
- goto fail_hw_start;
+ goto fail_quirks;
}
if (features->device_type & WACOM_DEVICETYPE_WL_MONITOR)
return;
fail:
- wacom_clean_inputs(wacom1);
- wacom_clean_inputs(wacom2);
+ wacom_release_resources(wacom1);
+ wacom_release_resources(wacom2);
+ return;
+ }
+
+ static void wacom_remote_destroy_one(struct wacom *wacom, unsigned int index)
+ {
+ struct wacom_remote *remote = wacom->remote;
+ u32 serial = remote->remotes[index].serial;
+ int i;
+ unsigned long flags;
+
+ spin_lock_irqsave(&remote->remote_lock, flags);
+ remote->remotes[index].registered = false;
+ spin_unlock_irqrestore(&remote->remote_lock, flags);
+
+ if (remote->remotes[index].battery.battery)
+ devres_release_group(&wacom->hdev->dev,
+ &remote->remotes[index].battery.bat_desc);
+
+ if (remote->remotes[index].group.name)
+ devres_release_group(&wacom->hdev->dev,
+ &remote->remotes[index]);
+
+ for (i = 0; i < WACOM_MAX_REMOTES; i++) {
+ if (remote->remotes[i].serial == serial) {
+ remote->remotes[i].serial = 0;
+ remote->remotes[i].group.name = NULL;
+ remote->remotes[i].registered = false;
+ remote->remotes[i].battery.battery = NULL;
+ wacom->led.groups[i].select = WACOM_STATUS_UNKNOWN;
+ }
+ }
+ }
+
+ static int wacom_remote_create_one(struct wacom *wacom, u32 serial,
+ unsigned int index)
+ {
+ struct wacom_remote *remote = wacom->remote;
+ struct device *dev = &wacom->hdev->dev;
+ int error, k;
+
+ /* A remote can pair more than once with an EKR,
+ * check to make sure this serial isn't already paired.
+ */
+ for (k = 0; k < WACOM_MAX_REMOTES; k++) {
+ if (remote->remotes[k].serial == serial)
+ break;
+ }
+
+ if (k < WACOM_MAX_REMOTES) {
+ remote->remotes[index].serial = serial;
+ return 0;
+ }
+
+ if (!devres_open_group(dev, &remote->remotes[index], GFP_KERNEL))
+ return -ENOMEM;
+
+ error = wacom_remote_create_attr_group(wacom, serial, index);
+ if (error)
+ goto fail;
+
+ remote->remotes[index].input = wacom_allocate_input(wacom);
+ if (!remote->remotes[index].input) {
+ error = -ENOMEM;
+ goto fail;
+ }
+ remote->remotes[index].input->uniq = remote->remotes[index].group.name;
+ remote->remotes[index].input->name = wacom->wacom_wac.pad_name;
+
+ if (!remote->remotes[index].input->name) {
+ error = -EINVAL;
+ goto fail;
+ }
+
+ error = wacom_setup_pad_input_capabilities(remote->remotes[index].input,
+ &wacom->wacom_wac);
+ if (error)
+ goto fail;
+
+ remote->remotes[index].serial = serial;
+
+ error = input_register_device(remote->remotes[index].input);
+ if (error)
+ goto fail;
+
+ error = wacom_led_groups_alloc_and_register_one(
+ &remote->remotes[index].input->dev,
+ wacom, index, 3, true);
+ if (error)
+ goto fail;
+
+ remote->remotes[index].registered = true;
+
+ devres_close_group(dev, &remote->remotes[index]);
+ return 0;
+
+ fail:
+ devres_release_group(dev, &remote->remotes[index]);
+ remote->remotes[index].serial = 0;
+ return error;
+ }
+
+ static int wacom_remote_attach_battery(struct wacom *wacom, int index)
+ {
+ struct wacom_remote *remote = wacom->remote;
+ int error;
+
+ if (!remote->remotes[index].registered)
+ return 0;
+
+ if (remote->remotes[index].battery.battery)
+ return 0;
+
+ if (wacom->led.groups[index].select == WACOM_STATUS_UNKNOWN)
+ return 0;
+
+ error = __wacom_initialize_battery(wacom,
+ &wacom->remote->remotes[index].battery);
+ if (error)
+ return error;
+
+ return 0;
+ }
+
+ static void wacom_remote_work(struct work_struct *work)
+ {
+ struct wacom *wacom = container_of(work, struct wacom, remote_work);
+ struct wacom_remote *remote = wacom->remote;
+ struct wacom_remote_data data;
+ unsigned long flags;
+ unsigned int count;
+ u32 serial;
+ int i;
+
+ spin_lock_irqsave(&remote->remote_lock, flags);
+
+ count = kfifo_out(&remote->remote_fifo, &data, sizeof(data));
+
+ if (count != sizeof(data)) {
+ hid_err(wacom->hdev,
+ "workitem triggered without status available\n");
+ spin_unlock_irqrestore(&remote->remote_lock, flags);
+ return;
+ }
+
+ if (!kfifo_is_empty(&remote->remote_fifo))
+ wacom_schedule_work(&wacom->wacom_wac, WACOM_WORKER_REMOTE);
+
+ spin_unlock_irqrestore(&remote->remote_lock, flags);
+
+ for (i = 0; i < WACOM_MAX_REMOTES; i++) {
+ serial = data.remote[i].serial;
+ if (data.remote[i].connected) {
+
+ if (remote->remotes[i].serial == serial) {
+ wacom_remote_attach_battery(wacom, i);
+ continue;
+ }
+
+ if (remote->remotes[i].serial)
+ wacom_remote_destroy_one(wacom, i);
+
+ wacom_remote_create_one(wacom, serial, i);
+
+ } else if (remote->remotes[i].serial) {
+ wacom_remote_destroy_one(wacom, i);
+ }
+ }
+ }
+
+++++++++++ static void wacom_mode_change_work(struct work_struct *work)
+++++++++++ {
+++++++++++ struct wacom *wacom = container_of(work, struct wacom, mode_change_work);
+++++++++++ struct wacom_shared *shared = wacom->wacom_wac.shared;
+++++++++++ struct wacom *wacom1 = NULL;
+++++++++++ struct wacom *wacom2 = NULL;
+++++++++++ bool is_direct = wacom->wacom_wac.is_direct_mode;
+++++++++++ int error = 0;
+++++++++++
+++++++++++ if (shared->pen) {
+++++++++++ wacom1 = hid_get_drvdata(shared->pen);
+++++++++++ wacom_release_resources(wacom1);
+++++++++++ hid_hw_stop(wacom1->hdev);
+++++++++++ wacom1->wacom_wac.has_mode_change = true;
+++++++++++ wacom1->wacom_wac.is_direct_mode = is_direct;
+++++++++++ }
+++++++++++
+++++++++++ if (shared->touch) {
+++++++++++ wacom2 = hid_get_drvdata(shared->touch);
+++++++++++ wacom_release_resources(wacom2);
+++++++++++ hid_hw_stop(wacom2->hdev);
+++++++++++ wacom2->wacom_wac.has_mode_change = true;
+++++++++++ wacom2->wacom_wac.is_direct_mode = is_direct;
+++++++++++ }
+++++++++++
+++++++++++ if (wacom1) {
+++++++++++ error = wacom_parse_and_register(wacom1, false);
+++++++++++ if (error)
+++++++++++ return;
+++++++++++ }
+++++++++++
+++++++++++ if (wacom2) {
+++++++++++ error = wacom_parse_and_register(wacom2, false);
+++++++++++ if (error)
+++++++++++ return;
+++++++++++ }
+++++++++++
+++++++ +++ return;
+++++++ +++ }
+++++++ +++
static int wacom_probe(struct hid_device *hdev,
const struct hid_device_id *id)
{
wacom->usbdev = dev;
wacom->intf = intf;
mutex_init(&wacom->lock);
- INIT_WORK(&wacom->work, wacom_wireless_work);
+ INIT_DELAYED_WORK(&wacom->init_work, wacom_init_work);
+ INIT_WORK(&wacom->wireless_work, wacom_wireless_work);
+ INIT_WORK(&wacom->battery_work, wacom_battery_work);
+ INIT_WORK(&wacom->remote_work, wacom_remote_work);
+++++++++++ INIT_WORK(&wacom->mode_change_work, wacom_mode_change_work);
/* ask for the report descriptor to be loaded by HID */
error = hid_parse(hdev);
hid_hw_stop(hdev);
- cancel_work_sync(&wacom->work);
- wacom_clean_inputs(wacom);
+ cancel_delayed_work_sync(&wacom->init_work);
+ cancel_work_sync(&wacom->wireless_work);
+ cancel_work_sync(&wacom->battery_work);
+ cancel_work_sync(&wacom->remote_work);
+++++++++++ cancel_work_sync(&wacom->mode_change_work);
if (hdev->bus == BUS_BLUETOOTH)
device_remove_file(&hdev->dev, &dev_attr_speed);
- wacom_destroy_battery(wacom);
- wacom_remove_shared_data(wacom);
+
+ /* make sure we don't trigger the LEDs */
+ wacom_led_groups_release(wacom);
------ ---- wacom_release_resources(wacom);
+++++++++++
+++++++++++ if (wacom->wacom_wac.features.type != REMOTE)
+++++++++++ wacom_release_resources(wacom);
hid_set_drvdata(hdev, NULL);
- kfree(wacom);
}
#ifdef CONFIG_PM
return 0;
}
----------- static int wacom_remote_irq(struct wacom_wac *wacom_wac, size_t len)
------- --- {
------- --- unsigned char *data = wacom_wac->data;
------- --- struct input_dev *input;
------- --- struct wacom *wacom = container_of(wacom_wac, struct wacom, wacom_wac);
------- --- struct wacom_remote *remote = wacom->remote;
------- --- int bat_charging, bat_percent, touch_ring_mode;
------- --- __u32 serial;
------- --- int i, index = -1;
------- --- unsigned long flags;
------- ---
------- --- if (data[0] != WACOM_REPORT_REMOTE) {
------- --- hid_dbg(wacom->hdev, "%s: received unknown report #%d",
------- --- __func__, data[0]);
------- --- return 0;
------- --- }
------- ---
------- --- serial = data[3] + (data[4] << 8) + (data[5] << 16);
------- --- wacom_wac->id[0] = PAD_DEVICE_ID;
------- ---
------- --- spin_lock_irqsave(&remote->remote_lock, flags);
------- ---
------- --- for (i = 0; i < WACOM_MAX_REMOTES; i++) {
------- --- if (remote->remotes[i].serial == serial) {
------- --- index = i;
------- --- break;
------- --- }
------- --- }
------- ---
------- --- if (index < 0 || !remote->remotes[index].registered)
------- --- goto out;
------- ---
------- --- input = remote->remotes[index].input;
------- ---
------- --- input_report_key(input, BTN_0, (data[9] & 0x01));
------- --- input_report_key(input, BTN_1, (data[9] & 0x02));
------- --- input_report_key(input, BTN_2, (data[9] & 0x04));
------- --- input_report_key(input, BTN_3, (data[9] & 0x08));
------- --- input_report_key(input, BTN_4, (data[9] & 0x10));
------- --- input_report_key(input, BTN_5, (data[9] & 0x20));
------- --- input_report_key(input, BTN_6, (data[9] & 0x40));
------- --- input_report_key(input, BTN_7, (data[9] & 0x80));
------- ---
------- --- input_report_key(input, BTN_8, (data[10] & 0x01));
------- --- input_report_key(input, BTN_9, (data[10] & 0x02));
------- --- input_report_key(input, BTN_A, (data[10] & 0x04));
------- --- input_report_key(input, BTN_B, (data[10] & 0x08));
------- --- input_report_key(input, BTN_C, (data[10] & 0x10));
------- --- input_report_key(input, BTN_X, (data[10] & 0x20));
------- --- input_report_key(input, BTN_Y, (data[10] & 0x40));
------- --- input_report_key(input, BTN_Z, (data[10] & 0x80));
------- ---
------- --- input_report_key(input, BTN_BASE, (data[11] & 0x01));
------- --- input_report_key(input, BTN_BASE2, (data[11] & 0x02));
------- ---
------- --- if (data[12] & 0x80)
------- --- input_report_abs(input, ABS_WHEEL, (data[12] & 0x7f));
------- --- else
------- --- input_report_abs(input, ABS_WHEEL, 0);
------- ---
------- --- bat_percent = data[7] & 0x7f;
------- --- bat_charging = !!(data[7] & 0x80);
------- ---
------- --- if (data[9] | data[10] | (data[11] & 0x03) | data[12])
------- --- input_report_abs(input, ABS_MISC, PAD_DEVICE_ID);
------- --- else
------- --- input_report_abs(input, ABS_MISC, 0);
------- ---
------- --- input_event(input, EV_MSC, MSC_SERIAL, serial);
------- ---
------- --- input_sync(input);
------- ---
------- --- /*Which mode select (LED light) is currently on?*/
------- --- touch_ring_mode = (data[11] & 0xC0) >> 6;
------- ---
------- --- for (i = 0; i < WACOM_MAX_REMOTES; i++) {
------- --- if (remote->remotes[i].serial == serial)
------- --- wacom->led.groups[i].select = touch_ring_mode;
------- --- }
------- ---
------- --- __wacom_notify_battery(&remote->remotes[index].battery, bat_percent,
------- --- bat_charging, 1, bat_charging);
------- ---
------- --- out:
------- --- spin_unlock_irqrestore(&remote->remote_lock, flags);
------- --- return 0;
------- --- }
------- ---
------- --- static void wacom_remote_status_irq(struct wacom_wac *wacom_wac, size_t len)
------- --- {
------- --- struct wacom *wacom = container_of(wacom_wac, struct wacom, wacom_wac);
------- --- unsigned char *data = wacom_wac->data;
------- --- struct wacom_remote *remote = wacom->remote;
------- --- struct wacom_remote_data remote_data;
------- --- unsigned long flags;
------- --- int i, ret;
------- ---
------- --- if (data[0] != WACOM_REPORT_DEVICE_LIST)
------- --- return;
------- ---
------- --- memset(&remote_data, 0, sizeof(struct wacom_remote_data));
------- ---
------- --- for (i = 0; i < WACOM_MAX_REMOTES; i++) {
------- --- int j = i * 6;
------- --- int serial = (data[j+6] << 16) + (data[j+5] << 8) + data[j+4];
------- --- bool connected = data[j+2];
------- ---
------- --- remote_data.remote[i].serial = serial;
------- --- remote_data.remote[i].connected = connected;
------- --- }
------- ---
------- --- spin_lock_irqsave(&remote->remote_lock, flags);
------- ---
------- --- ret = kfifo_in(&remote->remote_fifo, &remote_data, sizeof(remote_data));
------- --- if (ret != sizeof(remote_data)) {
------- --- spin_unlock_irqrestore(&remote->remote_lock, flags);
------- --- hid_err(wacom->hdev, "Can't queue Remote status event.\n");
------- --- return;
------- --- }
------- ---
------- --- spin_unlock_irqrestore(&remote->remote_lock, flags);
------- ---
------- --- wacom_schedule_work(wacom_wac, WACOM_WORKER_REMOTE);
------- --- }
------- ---
+ static inline bool report_touch_events(struct wacom_wac *wacom)
{
- unsigned char *data = wacom_wac->data;
- struct input_dev *input = wacom_wac->pad_input;
- struct wacom *wacom = container_of(wacom_wac, struct wacom, wacom_wac);
- struct wacom_features *features = &wacom_wac->features;
- int bat_charging, bat_percent, touch_ring_mode;
- __u32 serial;
- int i;
-
- if (data[0] != WACOM_REPORT_REMOTE) {
- dev_dbg(input->dev.parent,
- "%s: received unknown report #%d", __func__, data[0]);
- return 0;
- }
-
- serial = data[3] + (data[4] << 8) + (data[5] << 16);
- wacom_wac->id[0] = PAD_DEVICE_ID;
-
- input_report_key(input, BTN_0, (data[9] & 0x01));
- input_report_key(input, BTN_1, (data[9] & 0x02));
- input_report_key(input, BTN_2, (data[9] & 0x04));
- input_report_key(input, BTN_3, (data[9] & 0x08));
- input_report_key(input, BTN_4, (data[9] & 0x10));
- input_report_key(input, BTN_5, (data[9] & 0x20));
- input_report_key(input, BTN_6, (data[9] & 0x40));
- input_report_key(input, BTN_7, (data[9] & 0x80));
-
- input_report_key(input, BTN_8, (data[10] & 0x01));
- input_report_key(input, BTN_9, (data[10] & 0x02));
- input_report_key(input, BTN_A, (data[10] & 0x04));
- input_report_key(input, BTN_B, (data[10] & 0x08));
- input_report_key(input, BTN_C, (data[10] & 0x10));
- input_report_key(input, BTN_X, (data[10] & 0x20));
- input_report_key(input, BTN_Y, (data[10] & 0x40));
- input_report_key(input, BTN_Z, (data[10] & 0x80));
-
- input_report_key(input, BTN_BASE, (data[11] & 0x01));
- input_report_key(input, BTN_BASE2, (data[11] & 0x02));
-
- if (data[12] & 0x80)
- input_report_abs(input, ABS_WHEEL, (data[12] & 0x7f));
- else
- input_report_abs(input, ABS_WHEEL, 0);
-
- bat_percent = data[7] & 0x7f;
- bat_charging = !!(data[7] & 0x80);
-
- if (data[9] | data[10] | (data[11] & 0x03) | data[12])
- input_report_abs(input, ABS_MISC, PAD_DEVICE_ID);
- else
- input_report_abs(input, ABS_MISC, 0);
-
- input_event(input, EV_MSC, MSC_SERIAL, serial);
-
- /*Which mode select (LED light) is currently on?*/
- touch_ring_mode = (data[11] & 0xC0) >> 6;
-
- for (i = 0; i < WACOM_MAX_REMOTES; i++) {
- if (wacom_wac->serial[i] == serial)
- wacom->led.select[i] = touch_ring_mode;
- }
-
- if (!wacom->battery &&
- !(features->quirks & WACOM_QUIRK_BATTERY)) {
- features->quirks |= WACOM_QUIRK_BATTERY;
- INIT_WORK(&wacom->work, wacom_battery_work);
- wacom_schedule_work(wacom_wac);
- }
-
- wacom_notify_battery(wacom_wac, bat_percent, bat_charging, 1,
- bat_charging);
-
- return 1;
+ return (touch_arbitration ? !wacom->shared->stylus_in_proximity : 1);
}
- static int wacom_remote_status_irq(struct wacom_wac *wacom_wac, size_t len)
+ static inline bool delay_pen_events(struct wacom_wac *wacom)
{
- struct wacom *wacom = container_of(wacom_wac, struct wacom, wacom_wac);
- unsigned char *data = wacom_wac->data;
- int i;
-
- if (data[0] != WACOM_REPORT_DEVICE_LIST)
- return 0;
-
- for (i = 0; i < WACOM_MAX_REMOTES; i++) {
- int j = i * 6;
- int serial = (data[j+6] << 16) + (data[j+5] << 8) + data[j+4];
- bool connected = data[j+2];
-
- if (connected) {
- int k;
-
- if (wacom_wac->serial[i] == serial)
- continue;
-
- if (wacom_wac->serial[i]) {
- wacom_remote_destroy_attr_group(wacom,
- wacom_wac->serial[i]);
- }
-
- /* A remote can pair more than once with an EKR,
- * check to make sure this serial isn't already paired.
- */
- for (k = 0; k < WACOM_MAX_REMOTES; k++) {
- if (wacom_wac->serial[k] == serial)
- break;
- }
-
- if (k < WACOM_MAX_REMOTES) {
- wacom_wac->serial[i] = serial;
- continue;
- }
- wacom_remote_create_attr_group(wacom, serial, i);
-
- } else if (wacom_wac->serial[i]) {
- wacom_remote_destroy_attr_group(wacom,
- wacom_wac->serial[i]);
- }
- }
-
- return 0;
+ return (wacom->shared->touch_down && touch_arbitration);
}
static int wacom_intuos_general(struct wacom_wac *wacom)
static void wacom_map_usage(struct input_dev *input, struct hid_usage *usage,
struct hid_field *field, __u8 type, __u16 code, int fuzz)
{
+ struct wacom *wacom = input_get_drvdata(input);
+ struct wacom_wac *wacom_wac = &wacom->wacom_wac;
+ struct wacom_features *features = &wacom_wac->features;
int fmin = field->logical_minimum;
int fmax = field->logical_maximum;
------- --- if (!usage->type)
+ unsigned int equivalent_usage = wacom_equivalent_usage(usage->hid);
+ int resolution_code = code;
+
+ if (equivalent_usage == HID_DG_TWIST) {
+ resolution_code = ABS_RZ;
+ }
+
+ if (equivalent_usage == HID_GD_X) {
+ fmin += features->offset_left;
+ fmax -= features->offset_right;
+ }
+ if (equivalent_usage == HID_GD_Y) {
+ fmin += features->offset_top;
+ fmax -= features->offset_bottom;
+ }
+
+ usage->type = type;
+ usage->code = code;
+
+ set_bit(type, input->evbit);
+
+ switch (type) {
+ case EV_ABS:
+ input_set_abs_params(input, code, fmin, fmax, fuzz, 0);
+ input_abs_set_res(input, code,
+ hidinput_calc_abs_res(field, resolution_code));
+ break;
+ case EV_KEY:
+ input_set_capability(input, EV_KEY, code);
+ break;
+ case EV_MSC:
+ input_set_capability(input, EV_MSC, code);
+ break;
+ case EV_SW:
+ input_set_capability(input, EV_SW, code);
+ break;
+ }
+ }
+
+ static void wacom_wac_pad_usage_mapping(struct hid_device *hdev,
+ struct hid_field *field, struct hid_usage *usage)
+ {
+ struct wacom *wacom = hid_get_drvdata(hdev);
+ struct wacom_wac *wacom_wac = &wacom->wacom_wac;
+ struct wacom_features *features = &wacom_wac->features;
+ struct input_dev *input = wacom_wac->pad_input;
+ unsigned equivalent_usage = wacom_equivalent_usage(usage->hid);
+
+ switch (equivalent_usage) {
+ case WACOM_HID_WD_BATTERY_LEVEL:
+ case WACOM_HID_WD_BATTERY_CHARGING:
+ features->quirks |= WACOM_QUIRK_BATTERY;
+ break;
+ case WACOM_HID_WD_ACCELEROMETER_X:
+ __set_bit(INPUT_PROP_ACCELEROMETER, input->propbit);
+ wacom_map_usage(input, usage, field, EV_ABS, ABS_X, 0);
+ features->device_type |= WACOM_DEVICETYPE_PAD;
+ break;
+ case WACOM_HID_WD_ACCELEROMETER_Y:
+ __set_bit(INPUT_PROP_ACCELEROMETER, input->propbit);
+ wacom_map_usage(input, usage, field, EV_ABS, ABS_Y, 0);
+ features->device_type |= WACOM_DEVICETYPE_PAD;
+ break;
+ case WACOM_HID_WD_ACCELEROMETER_Z:
+ __set_bit(INPUT_PROP_ACCELEROMETER, input->propbit);
+ wacom_map_usage(input, usage, field, EV_ABS, ABS_Z, 0);
+ features->device_type |= WACOM_DEVICETYPE_PAD;
+ break;
+ case WACOM_HID_WD_BUTTONCENTER:
+ wacom->generic_has_leds = true;
+ /* fall through */
+ case WACOM_HID_WD_BUTTONHOME:
+ case WACOM_HID_WD_BUTTONUP:
+ case WACOM_HID_WD_BUTTONDOWN:
+ case WACOM_HID_WD_BUTTONLEFT:
+ case WACOM_HID_WD_BUTTONRIGHT:
+ wacom_map_usage(input, usage, field, EV_KEY,
+ wacom_numbered_button_to_key(features->numbered_buttons),
+ 0);
+ features->numbered_buttons++;
+ features->device_type |= WACOM_DEVICETYPE_PAD;
+ break;
+ case WACOM_HID_WD_TOUCHONOFF:
+++++++++++ case WACOM_HID_WD_MUTE_DEVICE:
+ /*
+ * This usage, which is used to mute touch events, comes
+ * from the pad packet, but is reported on the touch
+ * interface. Because the touch interface may not have
+ * been created yet, we cannot call wacom_map_usage(). In
+ * order to process this usage when we receive it, we set
+ * the usage type and code directly.
+ */
+ wacom_wac->has_mute_touch_switch = true;
+ usage->type = EV_SW;
+ usage->code = SW_MUTE_DEVICE;
+ features->device_type |= WACOM_DEVICETYPE_PAD;
+ break;
+ case WACOM_HID_WD_TOUCHSTRIP:
+ wacom_map_usage(input, usage, field, EV_ABS, ABS_RX, 0);
+ features->device_type |= WACOM_DEVICETYPE_PAD;
+ break;
+ case WACOM_HID_WD_TOUCHSTRIP2:
+ wacom_map_usage(input, usage, field, EV_ABS, ABS_RY, 0);
+ features->device_type |= WACOM_DEVICETYPE_PAD;
+ break;
+ case WACOM_HID_WD_TOUCHRING:
+ wacom_map_usage(input, usage, field, EV_ABS, ABS_WHEEL, 0);
+ features->device_type |= WACOM_DEVICETYPE_PAD;
+ break;
+ case WACOM_HID_WD_TOUCHRINGSTATUS:
+ wacom_map_usage(input, usage, field, EV_ABS, ABS_WHEEL, 0);
+ features->device_type |= WACOM_DEVICETYPE_PAD;
+ break;
+++++++++++ case WACOM_HID_WD_BUTTONCONFIG:
+++++++++++ wacom_map_usage(input, usage, field, EV_KEY, KEY_BUTTONCONFIG, 0);
+++++++++++ features->device_type |= WACOM_DEVICETYPE_PAD;
+++++++++++ break;
+++++++++++ case WACOM_HID_WD_ONSCREEN_KEYBOARD:
+++++++++++ wacom_map_usage(input, usage, field, EV_KEY, KEY_ONSCREEN_KEYBOARD, 0);
+++++++++++ features->device_type |= WACOM_DEVICETYPE_PAD;
+++++++++++ break;
+++++++++++ case WACOM_HID_WD_CONTROLPANEL:
+++++++++++ wacom_map_usage(input, usage, field, EV_KEY, KEY_CONTROLPANEL, 0);
+++++++++++ features->device_type |= WACOM_DEVICETYPE_PAD;
+++++++++++ break;
+++++++++++ case WACOM_HID_WD_MODE_CHANGE:
+++++++++++ /* do not overwrite previous data */
+++++++++++ if (!wacom_wac->has_mode_change) {
+++++++++++ wacom_wac->has_mode_change = true;
+++++++++++ wacom_wac->is_direct_mode = true;
+++++++++++ }
+++++++++++ features->device_type |= WACOM_DEVICETYPE_PAD;
+++++++++++ break;
+ }
+
+ switch (equivalent_usage & 0xfffffff0) {
+ case WACOM_HID_WD_EXPRESSKEY00:
+ wacom_map_usage(input, usage, field, EV_KEY,
+ wacom_numbered_button_to_key(features->numbered_buttons),
+ 0);
+ features->numbered_buttons++;
+ features->device_type |= WACOM_DEVICETYPE_PAD;
+ break;
+ }
+ }
+
+ static void wacom_wac_pad_battery_event(struct hid_device *hdev, struct hid_field *field,
+ struct hid_usage *usage, __s32 value)
+ {
+ struct wacom *wacom = hid_get_drvdata(hdev);
+ struct wacom_wac *wacom_wac = &wacom->wacom_wac;
+ unsigned equivalent_usage = wacom_equivalent_usage(usage->hid);
+
+ switch (equivalent_usage) {
+ case WACOM_HID_WD_BATTERY_LEVEL:
+ wacom_wac->hid_data.battery_capacity = value;
+ wacom_wac->hid_data.bat_connected = 1;
+ break;
+
+ case WACOM_HID_WD_BATTERY_CHARGING:
+ wacom_wac->hid_data.bat_charging = value;
+ wacom_wac->hid_data.ps_connected = value;
+ wacom_wac->hid_data.bat_connected = 1;
+ break;
+ }
+ }
+
+ static void wacom_wac_pad_event(struct hid_device *hdev, struct hid_field *field,
+ struct hid_usage *usage, __s32 value)
+ {
+ struct wacom *wacom = hid_get_drvdata(hdev);
+ struct wacom_wac *wacom_wac = &wacom->wacom_wac;
+ struct input_dev *input = wacom_wac->pad_input;
+ struct wacom_features *features = &wacom_wac->features;
+ unsigned equivalent_usage = wacom_equivalent_usage(usage->hid);
+ int i;
+++++++++++ bool is_touch_on = value;
+
+ /*
+ * Avoid reporting this event and setting inrange_state if this usage
+ * hasn't been mapped.
+ */
------- --- SW_MUTE_DEVICE, !value);
+++++++++++ if (!usage->type && equivalent_usage != WACOM_HID_WD_MODE_CHANGE)
+ return;
+
+ if (wacom_equivalent_usage(field->physical) == HID_DG_TABLETFUNCTIONKEY) {
+ if (usage->hid != WACOM_HID_WD_TOUCHRING)
+ wacom_wac->hid_data.inrange_state |= value;
+ }
+
+ switch (equivalent_usage) {
+ case WACOM_HID_WD_TOUCHRINGSTATUS:
+ if (!value)
+ input_event(input, usage->type, usage->code, 0);
+ break;
+
+++++++++++ case WACOM_HID_WD_MUTE_DEVICE:
+++++++++++ if (wacom_wac->shared->touch_input && value) {
+++++++++++ wacom_wac->shared->is_touch_on = !wacom_wac->shared->is_touch_on;
+++++++++++ is_touch_on = wacom_wac->shared->is_touch_on;
+++++++++++ }
+++++++++++
+++++++++++ /* fall through*/
+ case WACOM_HID_WD_TOUCHONOFF:
+ if (wacom_wac->shared->touch_input) {
+ input_report_switch(wacom_wac->shared->touch_input,
+++++++++++ SW_MUTE_DEVICE, !is_touch_on);
+ input_sync(wacom_wac->shared->touch_input);
+ }
+ break;
+
+++++++++++ case WACOM_HID_WD_MODE_CHANGE:
+++++++++++ if (wacom_wac->is_direct_mode != value) {
+++++++++++ wacom_wac->is_direct_mode = value;
+++++++++++ wacom_schedule_work(&wacom->wacom_wac, WACOM_WORKER_MODE_CHANGE);
+++++++++++ }
+++++++++++ break;
+++++++++++
+ case WACOM_HID_WD_BUTTONCENTER:
+ for (i = 0; i < wacom->led.count; i++)
+ wacom_update_led(wacom, features->numbered_buttons,
+ value, i);
+ /* fall through*/
+ default:
+ input_event(input, usage->type, usage->code, value);
+++++++++++ if (value)
+++++++++++ wacom_wac->hid_data.pad_input_event_flag = true;
+ break;
+ }
+ }
+
+ static void wacom_wac_pad_pre_report(struct hid_device *hdev,
+ struct hid_report *report)
+ {
+ struct wacom *wacom = hid_get_drvdata(hdev);
+ struct wacom_wac *wacom_wac = &wacom->wacom_wac;
+
+ wacom_wac->hid_data.inrange_state = 0;
+ }
+
+ static void wacom_wac_pad_battery_report(struct hid_device *hdev,
+ struct hid_report *report)
+ {
+ struct wacom *wacom = hid_get_drvdata(hdev);
+ struct wacom_wac *wacom_wac = &wacom->wacom_wac;
+ struct wacom_features *features = &wacom_wac->features;
- usage->type = type;
- usage->code = code;
+ if (features->quirks & WACOM_QUIRK_BATTERY) {
+ int capacity = wacom_wac->hid_data.battery_capacity;
+ bool charging = wacom_wac->hid_data.bat_charging;
+ bool connected = wacom_wac->hid_data.bat_connected;
+ bool powered = wacom_wac->hid_data.ps_connected;
- set_bit(type, input->evbit);
+ wacom_notify_battery(wacom_wac, capacity, charging,
+ connected, powered);
+ }
+ }
- switch (type) {
- case EV_ABS:
- input_set_abs_params(input, code, fmin, fmax, fuzz, 0);
- input_abs_set_res(input, code,
- hidinput_calc_abs_res(field, code));
- break;
- case EV_KEY:
- input_set_capability(input, EV_KEY, code);
- break;
- case EV_MSC:
- input_set_capability(input, EV_MSC, code);
- break;
+ static void wacom_wac_pad_report(struct hid_device *hdev,
+ struct hid_report *report)
+ {
+ struct wacom *wacom = hid_get_drvdata(hdev);
+ struct wacom_wac *wacom_wac = &wacom->wacom_wac;
+ struct input_dev *input = wacom_wac->pad_input;
+ bool active = wacom_wac->hid_data.inrange_state != 0;
+
+ /* report prox for expresskey events */
------- --- if (wacom_equivalent_usage(report->field[0]->physical) == HID_DG_TABLETFUNCTIONKEY) {
+++++++++++ if ((wacom_equivalent_usage(report->field[0]->physical) == HID_DG_TABLETFUNCTIONKEY) &&
+++++++++++ wacom_wac->hid_data.pad_input_event_flag) {
+ input_event(input, EV_ABS, ABS_MISC, active ? PAD_DEVICE_ID : 0);
+ input_sync(input);
+++++++++++ if (!active)
+++++++++++ wacom_wac->hid_data.pad_input_event_flag = false;
}
+
}
static void wacom_wac_pen_usage_mapping(struct hid_device *hdev,
case HID_DG_TOOLSERIALNUMBER:
wacom_map_usage(input, usage, field, EV_MSC, MSC_SERIAL, 0);
break;
------ ---- input_set_capability(input, EV_KEY, BTN_TOOL_MOUSE);
------ ---- input_set_capability(input, EV_KEY, BTN_TOOL_LENS);
+ case WACOM_HID_WD_SENSE:
+ features->quirks |= WACOM_QUIRK_SENSE;
+ wacom_map_usage(input, usage, field, EV_KEY, BTN_TOOL_PEN, 0);
+ break;
+ case WACOM_HID_WD_SERIALHI:
+ wacom_map_usage(input, usage, field, EV_ABS, ABS_MISC, 0);
+ set_bit(EV_KEY, input->evbit);
+ input_set_capability(input, EV_KEY, BTN_TOOL_PEN);
+ input_set_capability(input, EV_KEY, BTN_TOOL_RUBBER);
+ input_set_capability(input, EV_KEY, BTN_TOOL_BRUSH);
+ input_set_capability(input, EV_KEY, BTN_TOOL_PENCIL);
+ input_set_capability(input, EV_KEY, BTN_TOOL_AIRBRUSH);
+++++++++++ if (!(features->device_type & WACOM_DEVICETYPE_DIRECT)) {
+++++++++++ input_set_capability(input, EV_KEY, BTN_TOOL_MOUSE);
+++++++++++ input_set_capability(input, EV_KEY, BTN_TOOL_LENS);
+++++++++++ }
+ break;
+ case WACOM_HID_WD_FINGERWHEEL:
+ wacom_map_usage(input, usage, field, EV_ABS, ABS_WHEEL, 0);
+ break;
}
}
case HID_DG_ERASER:
case HID_DG_TIPSWITCH:
wacom_wac->hid_data.tipswitch |= value;
- return 0;
+ return;
+ case HID_DG_TOOLSERIALNUMBER:
+ wacom_wac->serial[0] = (wacom_wac->serial[0] & ~0xFFFFFFFFULL);
------ ---- wacom_wac->serial[0] |= value;
+++++++++++ wacom_wac->serial[0] |= (__u32)value;
+ return;
+ case WACOM_HID_WD_SENSE:
+ wacom_wac->hid_data.sense_state = value;
+ return;
+ case WACOM_HID_WD_SERIALHI:
+ wacom_wac->serial[0] = (wacom_wac->serial[0] & 0xFFFFFFFF);
+ wacom_wac->serial[0] |= ((__u64)value) << 32;
+ /*
+ * Non-USI EMR devices may contain additional tool type
+ * information here. See WACOM_HID_WD_TOOLTYPE case for
+ * more details.
+ */
+ if (value >> 20 == 1) {
+ wacom_wac->id[0] |= value & 0xFFFFF;
+ }
+ return;
+ case WACOM_HID_WD_TOOLTYPE:
+ /*
+ * Some devices (MobileStudio Pro, and possibly later
+ * devices as well) do not return the complete tool
+ * type in their WACOM_HID_WD_TOOLTYPE usage. Use a
+ * bitwise OR so the complete value can be built
+ * up over time :(
+ */
+ wacom_wac->id[0] |= value;
+ return;
+ case WACOM_HID_WD_OFFSETLEFT:
+ if (features->offset_left && value != features->offset_left)
+ hid_warn(hdev, "%s: overriding exising left offset "
+ "%d -> %d\n", __func__, value,
+ features->offset_left);
+ features->offset_left = value;
+ return;
+ case WACOM_HID_WD_OFFSETRIGHT:
+ if (features->offset_right && value != features->offset_right)
+ hid_warn(hdev, "%s: overriding exising right offset "
+ "%d -> %d\n", __func__, value,
+ features->offset_right);
+ features->offset_right = value;
+ return;
+ case WACOM_HID_WD_OFFSETTOP:
+ if (features->offset_top && value != features->offset_top)
+ hid_warn(hdev, "%s: overriding exising top offset "
+ "%d -> %d\n", __func__, value,
+ features->offset_top);
+ features->offset_top = value;
+ return;
+ case WACOM_HID_WD_OFFSETBOTTOM:
+ if (features->offset_bottom && value != features->offset_bottom)
+ hid_warn(hdev, "%s: overriding exising bottom offset "
+ "%d -> %d\n", __func__, value,
+ features->offset_bottom);
+ features->offset_bottom = value;
+ return;
}
- /* send pen events only when touch is up or forced out */
- if (!usage->type || wacom_wac->shared->touch_down)
- return 0;
+ /* send pen events only when touch is up or forced out
+ * or touch arbitration is off
+ */
+ if (!usage->type || delay_pen_events(wacom_wac))
+ return;
- input_event(input, usage->type, usage->code, value);
+ /* send pen events only when the pen is in/entering/leaving proximity */
+ if (!wacom_wac->hid_data.inrange_state && !wacom_wac->tool[0])
+ return;
- return 0;
+ input_event(input, usage->type, usage->code, value);
}
static void wacom_wac_pen_pre_report(struct hid_device *hdev,
struct hid_data *hid_data = &wacom_wac->hid_data;
bool mt = wacom_wac->features.touch_max > 1;
bool prox = hid_data->tipswitch &&
- !wacom_wac->shared->stylus_in_proximity;
+ report_touch_events(wacom_wac);
+
+++++++++++ if (wacom_wac->shared->has_mute_touch_switch &&
+++++++++++ !wacom_wac->shared->is_touch_on) {
+++++++++++ if (!wacom_wac->shared->touch_down)
+++++++++++ return;
+++++++++++ prox = 0;
+++++++++++ }
+++++++ +++
wacom_wac->hid_data.num_received++;
if (wacom_wac->hid_data.num_received > wacom_wac->hid_data.num_expected)
return;
INTUOSHT2, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 16,
.check_for_hid_type = true, .hid_type = HID_TYPE_USBNONE };
static const struct wacom_features wacom_features_0x343 =
- { "Wacom DTK1651", 34616, 19559, 1023, 0,
+ { "Wacom DTK1651", 34816, 19759, 1023, 0,
DTUS, WACOM_INTUOS_RES, WACOM_INTUOS_RES, 4,
+ WACOM_DTU_OFFSET, WACOM_DTU_OFFSET,
WACOM_DTU_OFFSET, WACOM_DTU_OFFSET };
------ ---- INTUOSP2_BT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, 9, .touch_max = 10 };
+ static const struct wacom_features wacom_features_0x360 =
+ { "Wacom Intuos Pro M", 44800, 29600, 8191, 63,
------ ---- INTUOSP2_BT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, 9, .touch_max = 10 };
+++++++++++ INTUOSP2_BT, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 9, .touch_max = 10 };
+ static const struct wacom_features wacom_features_0x361 =
+ { "Wacom Intuos Pro L", 62200, 43200, 8191, 63,
+++++++++++ INTUOSP2_BT, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 9, .touch_max = 10 };
static const struct wacom_features wacom_features_HID_ANY_ID =
- { "Wacom HID", .type = HID_GENERIC };
+ { "Wacom HID", .type = HID_GENERIC, .oVid = HID_ANY_ID, .oPid = HID_ANY_ID };
#define USB_DEVICE_WACOM(prod) \
HID_DEVICE(BUS_USB, HID_GROUP_WACOM, USB_VENDOR_ID_WACOM, prod),\