From 87046b6c995c50c11c8bd4a71877df83f99b3516 Mon Sep 17 00:00:00 2001 From: Aaron Armstrong Skomra Date: Tue, 6 Mar 2018 10:48:33 -0800 Subject: HID: wacom: Add support for 3rd generation Intuos BT Use the code path that predates generic device support. Signed-off-by: Aaron Armstrong Skomra Reviewed-by: Ping Cheng Reviewed-by: Jason Gerecke Signed-off-by: Jiri Kosina --- drivers/hid/wacom_wac.c | 113 +++++++++++++++++++++++++++++++++++++++--------- drivers/hid/wacom_wac.h | 1 + 2 files changed, 94 insertions(+), 20 deletions(-) diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c index 90c38a0523e9..d532c1ebf2ee 100644 --- a/drivers/hid/wacom_wac.c +++ b/drivers/hid/wacom_wac.c @@ -1202,15 +1202,24 @@ static int wacom_wac_finger_count_touches(struct wacom_wac *wacom) static void wacom_intuos_pro2_bt_pen(struct wacom_wac *wacom) { - const int pen_frame_len = 14; - const int pen_frames = 7; + int pen_frame_len, pen_frames; struct input_dev *pen_input = wacom->pen_input; unsigned char *data = wacom->data; int i; - wacom->serial[0] = get_unaligned_le64(&data[99]); - wacom->id[0] = get_unaligned_le16(&data[107]); + if (wacom->features.type == INTUOSP2_BT) { + wacom->serial[0] = get_unaligned_le64(&data[99]); + wacom->id[0] = get_unaligned_le16(&data[107]); + pen_frame_len = 14; + pen_frames = 7; + } else { + wacom->serial[0] = get_unaligned_le64(&data[33]); + wacom->id[0] = get_unaligned_le16(&data[41]); + pen_frame_len = 8; + pen_frames = 4; + } + if (wacom->serial[0] >> 52 == 1) { /* Add back in missing bits of ID for non-USI pens */ wacom->id[0] |= (wacom->serial[0] >> 32) & 0xFFFFF; @@ -1227,21 +1236,35 @@ static void wacom_intuos_pro2_bt_pen(struct wacom_wac *wacom) continue; if (range) { - /* Fix rotation alignment: userspace expects zero at left */ - int16_t rotation = (int16_t)get_unaligned_le16(&frame[9]); - rotation += 1800/4; - if (rotation > 899) - rotation -= 1800; - input_report_abs(pen_input, ABS_X, get_unaligned_le16(&frame[1])); input_report_abs(pen_input, ABS_Y, get_unaligned_le16(&frame[3])); - input_report_abs(pen_input, ABS_TILT_X, (char)frame[7]); - input_report_abs(pen_input, ABS_TILT_Y, (char)frame[8]); - input_report_abs(pen_input, ABS_Z, rotation); - input_report_abs(pen_input, ABS_WHEEL, get_unaligned_le16(&frame[11])); + + if (wacom->features.type == INTUOSP2_BT) { + /* Fix rotation alignment: userspace expects zero at left */ + int16_t rotation = + (int16_t)get_unaligned_le16(&frame[9]); + rotation += 1800/4; + + if (rotation > 899) + rotation -= 1800; + + input_report_abs(pen_input, ABS_TILT_X, + (char)frame[7]); + input_report_abs(pen_input, ABS_TILT_Y, + (char)frame[8]); + input_report_abs(pen_input, ABS_Z, rotation); + input_report_abs(pen_input, ABS_WHEEL, + get_unaligned_le16(&frame[11])); + } } input_report_abs(pen_input, ABS_PRESSURE, get_unaligned_le16(&frame[5])); - input_report_abs(pen_input, ABS_DISTANCE, range ? frame[13] : wacom->features.distance_max); + if (wacom->features.type == INTUOSP2_BT) { + input_report_abs(pen_input, ABS_DISTANCE, + range ? frame[13] : wacom->features.distance_max); + } else { + input_report_abs(pen_input, ABS_DISTANCE, + range ? frame[7] : wacom->features.distance_max); + } input_report_key(pen_input, BTN_TOUCH, frame[0] & 0x01); input_report_key(pen_input, BTN_STYLUS, frame[0] & 0x02); @@ -1357,20 +1380,52 @@ static void wacom_intuos_pro2_bt_battery(struct wacom_wac *wacom) battery_status, chg, 1, chg); } +static void wacom_intuos_gen3_bt_pad(struct wacom_wac *wacom) +{ + struct input_dev *pad_input = wacom->pad_input; + unsigned char *data = wacom->data; + + int buttons = data[44]; + + wacom_report_numbered_buttons(pad_input, 4, buttons); + + input_report_key(pad_input, wacom->tool[1], buttons ? 1 : 0); + input_report_abs(pad_input, ABS_MISC, buttons ? PAD_DEVICE_ID : 0); + input_event(pad_input, EV_MSC, MSC_SERIAL, 0xffffffff); + + input_sync(pad_input); +} + +static void wacom_intuos_gen3_bt_battery(struct wacom_wac *wacom) +{ + unsigned char *data = wacom->data; + + bool chg = data[45] & 0x80; + int battery_status = data[45] & 0x7F; + + wacom_notify_battery(wacom, WACOM_POWER_SUPPLY_STATUS_AUTO, + battery_status, chg, 1, chg); +} + static int wacom_intuos_pro2_bt_irq(struct wacom_wac *wacom, size_t len) { unsigned char *data = wacom->data; - if (data[0] != 0x80) { + if (data[0] != 0x80 && data[0] != 0x81) { dev_dbg(wacom->pen_input->dev.parent, "%s: received unknown report #%d\n", __func__, data[0]); return 0; } wacom_intuos_pro2_bt_pen(wacom); - wacom_intuos_pro2_bt_touch(wacom); - wacom_intuos_pro2_bt_pad(wacom); - wacom_intuos_pro2_bt_battery(wacom); + if (wacom->features.type == INTUOSP2_BT) { + wacom_intuos_pro2_bt_touch(wacom); + wacom_intuos_pro2_bt_pad(wacom); + wacom_intuos_pro2_bt_battery(wacom); + } else { + wacom_intuos_gen3_bt_pad(wacom); + wacom_intuos_gen3_bt_battery(wacom); + } return 0; } @@ -3093,6 +3148,7 @@ void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t len) break; case INTUOSP2_BT: + case INTUOSHT3_BT: sync = wacom_intuos_pro2_bt_irq(wacom_wac, len); break; @@ -3272,6 +3328,12 @@ void wacom_setup_device_quirks(struct wacom *wacom) features->quirks |= WACOM_QUIRK_BATTERY; } + if (features->type == INTUOSHT3_BT) { + features->device_type |= WACOM_DEVICETYPE_PEN | + WACOM_DEVICETYPE_PAD; + features->quirks |= WACOM_QUIRK_BATTERY; + } + switch (features->type) { case PL: case DTU: @@ -3466,7 +3528,9 @@ int wacom_setup_pen_input_capabilities(struct input_dev *input_dev, case BAMBOO_PT: case BAMBOO_PEN: case INTUOSHT2: - if (features->type == INTUOSHT2) { + case INTUOSHT3_BT: + if (features->type == INTUOSHT2 || + features->type == INTUOSHT3_BT) { wacom_setup_basic_pro_pen(wacom_wac); } else { __clear_bit(ABS_MISC, input_dev->absbit); @@ -3887,6 +3951,7 @@ int wacom_setup_pad_input_capabilities(struct input_dev *input_dev, input_set_abs_params(input_dev, ABS_WHEEL, 0, 71, 0, 0); break; + case INTUOSHT3_BT: case HID_GENERIC: break; @@ -4415,6 +4480,12 @@ static const struct wacom_features wacom_features_0x360 = 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_0x377 = + { "Wacom Intuos BT S", 15200, 9500, 4095, 63, + INTUOSHT3_BT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, 4 }; +static const struct wacom_features wacom_features_0x379 = + { "Wacom Intuos BT M", 21600, 13500, 4095, 63, + INTUOSHT3_BT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, 4 }; static const struct wacom_features wacom_features_0x37A = { "Wacom One by Wacom S", 15200, 9500, 2047, 63, BAMBOO_PEN, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; @@ -4589,6 +4660,8 @@ const struct hid_device_id wacom_ids[] = { { USB_DEVICE_WACOM(0x343) }, { BT_DEVICE_WACOM(0x360) }, { BT_DEVICE_WACOM(0x361) }, + { BT_DEVICE_WACOM(0x377) }, + { BT_DEVICE_WACOM(0x379) }, { USB_DEVICE_WACOM(0x37A) }, { USB_DEVICE_WACOM(0x37B) }, { USB_DEVICE_WACOM(0x4001) }, diff --git a/drivers/hid/wacom_wac.h b/drivers/hid/wacom_wac.h index 15d9c14fbdf7..827d8fc4a3f2 100644 --- a/drivers/hid/wacom_wac.h +++ b/drivers/hid/wacom_wac.h @@ -213,6 +213,7 @@ enum { INTUOSPM, INTUOSPL, INTUOSP2_BT, + INTUOSHT3_BT, WACOM_21UX2, WACOM_22HD, DTK, -- cgit v1.2.3-58-ga151 From f8b6a74719b5e003e28b2deb7ef91d7158333cbf Mon Sep 17 00:00:00 2001 From: Aaron Armstrong Skomra Date: Tue, 6 Mar 2018 10:48:34 -0800 Subject: HID: wacom: generic: Support multiple tools per report Some Wacom devices contain contain Pen and Pad usages in the same report. Future devices of this type may utilize HID Descriptors. The generic code path of the Wacom driver previously assumed pen, touch, and pad reports were delivered in separate reports. This patch adds support for processing each collection of a report separately, in order to support reports with multiple tools. Signed-off-by: Aaron Armstrong Skomra Reviewed-by: Ping Cheng Reviewed-by: Jason Gerecke Signed-off-by: Jiri Kosina --- drivers/hid/wacom_wac.c | 94 +++++++++++++++++++++++++++++++++++-------------- 1 file changed, 68 insertions(+), 26 deletions(-) diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c index d532c1ebf2ee..7a0a7f67e7ed 100644 --- a/drivers/hid/wacom_wac.c +++ b/drivers/hid/wacom_wac.c @@ -2072,7 +2072,7 @@ static void wacom_wac_pad_pre_report(struct hid_device *hdev, } static void wacom_wac_pad_report(struct hid_device *hdev, - struct hid_report *report) + struct hid_report *report, struct hid_field *field) { struct wacom *wacom = hid_get_drvdata(hdev); struct wacom_wac *wacom_wac = &wacom->wacom_wac; @@ -2080,7 +2080,7 @@ static void wacom_wac_pad_report(struct hid_device *hdev, 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(field->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); @@ -2627,11 +2627,13 @@ void wacom_wac_event(struct hid_device *hdev, struct hid_field *field, wacom_wac_finger_event(hdev, field, usage, value); } -static void wacom_report_events(struct hid_device *hdev, struct hid_report *report) +static void wacom_report_events(struct hid_device *hdev, + struct hid_report *report, int collection_index, + int field_index) { int r; - for (r = 0; r < report->maxfield; r++) { + for (r = field_index; r < report->maxfield; r++) { struct hid_field *field; unsigned count, n; @@ -2641,30 +2643,23 @@ static void wacom_report_events(struct hid_device *hdev, struct hid_report *repo if (!(HID_MAIN_ITEM_VARIABLE & field->flags)) continue; - for (n = 0; n < count; n++) - wacom_wac_event(hdev, field, &field->usage[n], field->value[n]); + for (n = 0 ; n < count; n++) { + if (field->usage[n].collection_index == collection_index) + wacom_wac_event(hdev, field, &field->usage[n], + field->value[n]); + else + return; + } } } -void wacom_wac_report(struct hid_device *hdev, struct hid_report *report) +int wacom_wac_collection(struct hid_device *hdev, struct hid_report *report, + int collection_index, struct hid_field *field, + int field_index) { struct wacom *wacom = hid_get_drvdata(hdev); - struct wacom_wac *wacom_wac = &wacom->wacom_wac; - struct hid_field *field = report->field[0]; - - if (wacom_wac->features.type != HID_GENERIC) - return; - - wacom_wac_battery_pre_report(hdev, report); - - if (WACOM_PAD_FIELD(field) && wacom->wacom_wac.pad_input) - wacom_wac_pad_pre_report(hdev, report); - else if (WACOM_PEN_FIELD(field) && wacom->wacom_wac.pen_input) - wacom_wac_pen_pre_report(hdev, report); - else if (WACOM_FINGER_FIELD(field) && wacom->wacom_wac.touch_input) - wacom_wac_finger_pre_report(hdev, report); - wacom_report_events(hdev, report); + wacom_report_events(hdev, report, collection_index, field_index); /* * Non-input reports may be sent prior to the device being @@ -2674,16 +2669,63 @@ void wacom_wac_report(struct hid_device *hdev, struct hid_report *report) * processing functions. */ if (report->type != HID_INPUT_REPORT) - return; - - wacom_wac_battery_report(hdev, report); + return -1; if (WACOM_PAD_FIELD(field) && wacom->wacom_wac.pad_input) - wacom_wac_pad_report(hdev, report); + wacom_wac_pad_report(hdev, report, field); else if (WACOM_PEN_FIELD(field) && wacom->wacom_wac.pen_input) wacom_wac_pen_report(hdev, report); else if (WACOM_FINGER_FIELD(field) && wacom->wacom_wac.touch_input) wacom_wac_finger_report(hdev, report); + + return 0; +} + +void wacom_wac_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 hid_field *field; + bool pad_in_hid_field = false, pen_in_hid_field = false, + finger_in_hid_field = false; + int r; + int prev_collection = -1; + + if (wacom_wac->features.type != HID_GENERIC) + return; + + for (r = 0; r < report->maxfield; r++) { + field = report->field[r]; + + if (WACOM_PAD_FIELD(field)) + pad_in_hid_field = true; + if (WACOM_PEN_FIELD(field)) + pen_in_hid_field = true; + if (WACOM_FINGER_FIELD(field)) + finger_in_hid_field = true; + } + + wacom_wac_battery_pre_report(hdev, report); + + if (pad_in_hid_field && wacom->wacom_wac.pad_input) + wacom_wac_pad_pre_report(hdev, report); + if (pen_in_hid_field && wacom->wacom_wac.pen_input) + wacom_wac_pen_pre_report(hdev, report); + if (finger_in_hid_field && wacom->wacom_wac.touch_input) + wacom_wac_finger_pre_report(hdev, report); + + for (r = 0; r < report->maxfield; r++) { + field = report->field[r]; + + if (field->usage[0].collection_index != prev_collection) { + if (wacom_wac_collection(hdev, report, + field->usage[0].collection_index, field, r) < 0) + return; + prev_collection = field->usage[0].collection_index; + } + } + + wacom_wac_battery_report(hdev, report); } static int wacom_bpt_touch(struct wacom_wac *wacom) -- cgit v1.2.3-58-ga151 From b1f466a90c516d54bd8bea7fb142a807d7800304 Mon Sep 17 00:00:00 2001 From: Aaron Armstrong Skomra Date: Tue, 6 Mar 2018 10:48:35 -0800 Subject: HID: wacom: generic: add the "Report Valid" usage Wacom Bluetooth reports contain multiple pen frames per report. Each frame contains a flag indicating if the frame is valid. Future Wacom devices with this type of report may contain HID descriptors, add support for this usage to the generic codepath of the Wacom driver. Signed-off-by: Aaron Armstrong Skomra Reviewed-by: Ping Cheng Reviewed-by: Jason Gerecke Signed-off-by: Jiri Kosina --- drivers/hid/wacom_wac.c | 16 +++++++++++++++- drivers/hid/wacom_wac.h | 3 ++- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c index 7a0a7f67e7ed..afa8c9f24a42 100644 --- a/drivers/hid/wacom_wac.c +++ b/drivers/hid/wacom_wac.c @@ -1715,7 +1715,8 @@ int wacom_equivalent_usage(int usage) usage == WACOM_HID_WD_TOUCHSTRIP || usage == WACOM_HID_WD_TOUCHSTRIP2 || usage == WACOM_HID_WD_TOUCHRING || - usage == WACOM_HID_WD_TOUCHRINGSTATUS) { + usage == WACOM_HID_WD_TOUCHRINGSTATUS || + usage == WACOM_HID_WD_REPORT_VALID) { return usage; } @@ -2199,6 +2200,9 @@ static void wacom_wac_pen_event(struct hid_device *hdev, struct hid_field *field struct input_dev *input = wacom_wac->pen_input; unsigned equivalent_usage = wacom_equivalent_usage(usage->hid); + if (wacom_wac->is_invalid_bt_frame) + return; + switch (equivalent_usage) { case HID_GD_Z: /* @@ -2295,6 +2299,9 @@ static void wacom_wac_pen_event(struct hid_device *hdev, struct hid_field *field features->offset_bottom); features->offset_bottom = value; return; + case WACOM_HID_WD_REPORT_VALID: + wacom_wac->is_invalid_bt_frame = !value; + return; } /* send pen events only when touch is up or forced out @@ -2313,6 +2320,10 @@ static void wacom_wac_pen_event(struct hid_device *hdev, struct hid_field *field static void wacom_wac_pen_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->is_invalid_bt_frame = false; return; } @@ -2325,6 +2336,9 @@ static void wacom_wac_pen_report(struct hid_device *hdev, bool range = wacom_wac->hid_data.inrange_state; bool sense = wacom_wac->hid_data.sense_state; + if (wacom_wac->is_invalid_bt_frame) + return; + if (!wacom_wac->tool[0] && range) { /* first in range */ /* Going into range select tool */ if (wacom_wac->hid_data.invert_state) diff --git a/drivers/hid/wacom_wac.h b/drivers/hid/wacom_wac.h index 827d8fc4a3f2..295fd3718caa 100644 --- a/drivers/hid/wacom_wac.h +++ b/drivers/hid/wacom_wac.h @@ -118,6 +118,7 @@ #define WACOM_HID_WD_TOUCHSTRIP2 (WACOM_HID_UP_WACOMDIGITIZER | 0x0137) #define WACOM_HID_WD_TOUCHRING (WACOM_HID_UP_WACOMDIGITIZER | 0x0138) #define WACOM_HID_WD_TOUCHRINGSTATUS (WACOM_HID_UP_WACOMDIGITIZER | 0x0139) +#define WACOM_HID_WD_REPORT_VALID (WACOM_HID_UP_WACOMDIGITIZER | 0x01d0) #define WACOM_HID_WD_ACCELEROMETER_X (WACOM_HID_UP_WACOMDIGITIZER | 0x0401) #define WACOM_HID_WD_ACCELEROMETER_Y (WACOM_HID_UP_WACOMDIGITIZER | 0x0402) #define WACOM_HID_WD_ACCELEROMETER_Z (WACOM_HID_UP_WACOMDIGITIZER | 0x0403) @@ -353,7 +354,7 @@ struct wacom_wac { bool has_mute_touch_switch; bool has_mode_change; bool is_direct_mode; - + bool is_invalid_bt_frame; }; #endif -- cgit v1.2.3-58-ga151 From 7ba8fc0904e3cdfe5b02aaf6fa8fcdb76ad67b0f Mon Sep 17 00:00:00 2001 From: Jiri Kosina Date: Wed, 7 Mar 2018 15:34:51 +0100 Subject: HID: wacom: wacom_wac_collection() is local to wacom_wac.c ... and therefore should be static. Signed-off-by: Jiri Kosina --- drivers/hid/wacom_wac.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c index afa8c9f24a42..6da16a879c9f 100644 --- a/drivers/hid/wacom_wac.c +++ b/drivers/hid/wacom_wac.c @@ -2667,7 +2667,7 @@ static void wacom_report_events(struct hid_device *hdev, } } -int wacom_wac_collection(struct hid_device *hdev, struct hid_report *report, +static int wacom_wac_collection(struct hid_device *hdev, struct hid_report *report, int collection_index, struct hid_field *field, int field_index) { -- cgit v1.2.3-58-ga151