diff options
Diffstat (limited to 'drivers/hid/wacom_wac.c')
-rw-r--r-- | drivers/hid/wacom_wac.c | 152 |
1 files changed, 117 insertions, 35 deletions
diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c index 43f6da357165..8fc36a28081b 100644 --- a/drivers/hid/wacom_wac.c +++ b/drivers/hid/wacom_wac.c @@ -1216,7 +1216,8 @@ static void wacom_intuos_pro2_bt_pen(struct wacom_wac *wacom) unsigned char *data = wacom->data; int i; - if (wacom->features.type == INTUOSP2_BT) { + if (wacom->features.type == INTUOSP2_BT || + wacom->features.type == INTUOSP2S_BT) { wacom->serial[0] = get_unaligned_le64(&data[99]); wacom->id[0] = get_unaligned_le16(&data[107]); pen_frame_len = 14; @@ -1268,7 +1269,8 @@ static void wacom_intuos_pro2_bt_pen(struct wacom_wac *wacom) input_report_abs(pen_input, ABS_X, get_unaligned_le16(&frame[1])); input_report_abs(pen_input, ABS_Y, get_unaligned_le16(&frame[3])); - if (wacom->features.type == INTUOSP2_BT) { + if (wacom->features.type == INTUOSP2_BT || + wacom->features.type == INTUOSP2S_BT) { /* Fix rotation alignment: userspace expects zero at left */ int16_t rotation = (int16_t)get_unaligned_le16(&frame[9]); @@ -1286,7 +1288,6 @@ static void wacom_intuos_pro2_bt_pen(struct wacom_wac *wacom) get_unaligned_le16(&frame[11])); } } - if (wacom->tool[0]) { input_report_abs(pen_input, ABS_PRESSURE, get_unaligned_le16(&frame[5])); if (wacom->features.type == INTUOSP2_BT) { @@ -1456,7 +1457,8 @@ static int wacom_intuos_pro2_bt_irq(struct wacom_wac *wacom, size_t len) } wacom_intuos_pro2_bt_pen(wacom); - if (wacom->features.type == INTUOSP2_BT) { + if (wacom->features.type == INTUOSP2_BT || + wacom->features.type == INTUOSP2S_BT) { wacom_intuos_pro2_bt_touch(wacom); wacom_intuos_pro2_bt_pad(wacom); wacom_intuos_pro2_bt_battery(wacom); @@ -1768,6 +1770,9 @@ int wacom_equivalent_usage(int usage) int subpage = (usage & 0xFF00) << 8; int subusage = (usage & 0xFF); + if (usage == WACOM_HID_WT_REPORT_VALID) + return usage; + if (subpage == HID_UP_UNDEFINED) subpage = WACOM_HID_SP_DIGITIZER; @@ -1926,8 +1931,6 @@ static void wacom_wac_pad_usage_mapping(struct hid_device *hdev, 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: @@ -2043,12 +2046,16 @@ static void wacom_wac_pad_event(struct hid_device *hdev, struct hid_field *field */ if (hdev->vendor == 0x56a && (hdev->product == 0x34d || hdev->product == 0x34e || /* MobileStudio Pro */ - hdev->product == 0x357 || hdev->product == 0x358)) { /* Intuos Pro 2 */ + hdev->product == 0x357 || hdev->product == 0x358 || /* Intuos Pro 2 */ + hdev->product == 0x392 || /* Intuos Pro 2 */ + hdev->product == 0x399)) { /* MobileStudio Pro */ value = (field->logical_maximum - value); - if (hdev->product == 0x357 || hdev->product == 0x358) + if (hdev->product == 0x357 || hdev->product == 0x358 || + hdev->product == 0x392) value = wacom_offset_rotation(input, usage, value, 3, 16); - else if (hdev->product == 0x34d || hdev->product == 0x34e) + else if (hdev->product == 0x34d || hdev->product == 0x34e || + hdev->product == 0x399) value = wacom_offset_rotation(input, usage, value, 1, 2); } else { @@ -2119,14 +2126,12 @@ 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(field->physical) == HID_DG_TABLETFUNCTIONKEY) && - wacom_wac->hid_data.pad_input_event_flag) { + if (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, @@ -2512,6 +2517,10 @@ static void wacom_wac_finger_event(struct hid_device *hdev, struct wacom *wacom = hid_get_drvdata(hdev); struct wacom_wac *wacom_wac = &wacom->wacom_wac; unsigned equivalent_usage = wacom_equivalent_usage(usage->hid); + struct wacom_features *features = &wacom->wacom_wac.features; + + if (wacom_wac->is_invalid_bt_frame) + return; switch (equivalent_usage) { case HID_GD_X: @@ -2532,9 +2541,14 @@ static void wacom_wac_finger_event(struct hid_device *hdev, case HID_DG_TIPSWITCH: wacom_wac->hid_data.tipswitch = value; break; + case WACOM_HID_WT_REPORT_VALID: + wacom_wac->is_invalid_bt_frame = !value; + return; + case HID_DG_CONTACTMAX: + features->touch_max = value; + return; } - if (usage->usage_index + 1 == field->report_count) { if (equivalent_usage == wacom_wac->hid_data.last_slot_field) wacom_wac_finger_slot(wacom_wac, wacom_wac->touch_input); @@ -2549,6 +2563,8 @@ static void wacom_wac_finger_pre_report(struct hid_device *hdev, struct hid_data* hid_data = &wacom_wac->hid_data; int i; + wacom_wac->is_invalid_bt_frame = false; + for (i = 0; i < report->maxfield; i++) { struct hid_field *field = report->field[i]; int j; @@ -2569,25 +2585,9 @@ static void wacom_wac_finger_pre_report(struct hid_device *hdev, case HID_DG_TIPSWITCH: hid_data->last_slot_field = equivalent_usage; break; - case HID_DG_CONTACTCOUNT: - hid_data->cc_report = report->id; - hid_data->cc_index = i; - hid_data->cc_value_index = j; - break; } } } - - if (hid_data->cc_report != 0 && - hid_data->cc_index >= 0) { - struct hid_field *field = report->field[hid_data->cc_index]; - int value = field->value[hid_data->cc_value_index]; - if (value) - hid_data->num_expected = value; - } - else { - hid_data->num_expected = wacom_wac->features.touch_max; - } } static void wacom_wac_finger_report(struct hid_device *hdev, @@ -2597,6 +2597,7 @@ static void wacom_wac_finger_report(struct hid_device *hdev, struct wacom_wac *wacom_wac = &wacom->wacom_wac; struct input_dev *input = wacom_wac->touch_input; unsigned touch_max = wacom_wac->features.touch_max; + struct hid_data *hid_data = &wacom_wac->hid_data; /* If more packets of data are expected, give us a chance to * process them rather than immediately syncing a partial @@ -2610,6 +2611,7 @@ static void wacom_wac_finger_report(struct hid_device *hdev, input_sync(input); wacom_wac->hid_data.num_received = 0; + hid_data->num_expected = 0; /* keep touch state for pen event */ wacom_wac->shared->touch_down = wacom_wac_finger_count_touches(wacom_wac); @@ -2684,12 +2686,73 @@ static void wacom_report_events(struct hid_device *hdev, } } +static void wacom_set_num_expected(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_data *hid_data = &wacom_wac->hid_data; + unsigned int original_collection_level = + hdev->collection[collection_index].level; + bool end_collection = false; + int i; + + if (hid_data->num_expected) + return; + + // find the contact count value for this segment + for (i = field_index; i < report->maxfield && !end_collection; i++) { + struct hid_field *field = report->field[i]; + unsigned int field_level = + hdev->collection[field->usage[0].collection_index].level; + unsigned int j; + + if (field_level != original_collection_level) + continue; + + for (j = 0; j < field->maxusage; j++) { + struct hid_usage *usage = &field->usage[j]; + + if (usage->collection_index != collection_index) { + end_collection = true; + break; + } + if (wacom_equivalent_usage(usage->hid) == HID_DG_CONTACTCOUNT) { + hid_data->cc_report = report->id; + hid_data->cc_index = i; + hid_data->cc_value_index = j; + + if (hid_data->cc_report != 0 && + hid_data->cc_index >= 0) { + + struct hid_field *field = + report->field[hid_data->cc_index]; + int value = + field->value[hid_data->cc_value_index]; + + if (value) + hid_data->num_expected = value; + } + } + } + } + + if (hid_data->cc_report == 0 || hid_data->cc_index < 0) + hid_data->num_expected = wacom_wac->features.touch_max; +} + static 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); + if (WACOM_FINGER_FIELD(field)) + wacom_set_num_expected(hdev, report, collection_index, field, + field_index); wacom_report_events(hdev, report, collection_index, field_index); /* @@ -2702,9 +2765,7 @@ static int wacom_wac_collection(struct hid_device *hdev, struct hid_report *repo if (report->type != HID_INPUT_REPORT) return -1; - if (WACOM_PAD_FIELD(field) && wacom->wacom_wac.pad_input) - wacom_wac_pad_report(hdev, report, field); - else if (WACOM_PEN_FIELD(field) && wacom->wacom_wac.pen_input) + 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); @@ -2718,7 +2779,7 @@ void wacom_wac_report(struct hid_device *hdev, struct hid_report *report) 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; + finger_in_hid_field = false, true_pad = false; int r; int prev_collection = -1; @@ -2734,6 +2795,8 @@ void wacom_wac_report(struct hid_device *hdev, struct hid_report *report) pen_in_hid_field = true; if (WACOM_FINGER_FIELD(field)) finger_in_hid_field = true; + if (wacom_equivalent_usage(field->physical) == HID_DG_TABLETFUNCTIONKEY) + true_pad = true; } wacom_wac_battery_pre_report(hdev, report); @@ -2757,6 +2820,9 @@ void wacom_wac_report(struct hid_device *hdev, struct hid_report *report) } wacom_wac_battery_report(hdev, report); + + if (true_pad && wacom->wacom_wac.pad_input) + wacom_wac_pad_report(hdev, report, field); } static int wacom_bpt_touch(struct wacom_wac *wacom) @@ -3225,6 +3291,7 @@ void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t len) break; case INTUOSP2_BT: + case INTUOSP2S_BT: case INTUOSHT3_BT: sync = wacom_intuos_pro2_bt_irq(wacom_wac, len); break; @@ -3405,7 +3472,8 @@ void wacom_setup_device_quirks(struct wacom *wacom) if (features->type == REMOTE) features->device_type = WACOM_DEVICETYPE_PAD; - if (features->type == INTUOSP2_BT) { + if (features->type == INTUOSP2_BT || + features->type == INTUOSP2S_BT) { features->device_type |= WACOM_DEVICETYPE_PEN | WACOM_DEVICETYPE_PAD | WACOM_DEVICETYPE_TOUCH; @@ -3586,6 +3654,7 @@ int wacom_setup_pen_input_capabilities(struct input_dev *input_dev, case INTUOS5S: case INTUOSPS: case INTUOSP2_BT: + case INTUOSP2S_BT: input_set_abs_params(input_dev, ABS_DISTANCE, 0, features->distance_max, features->distance_fuzz, 0); @@ -3697,6 +3766,7 @@ int wacom_setup_touch_input_capabilities(struct input_dev *input_dev, switch (features->type) { case INTUOSP2_BT: + case INTUOSP2S_BT: input_dev->evbit[0] |= BIT_MASK(EV_SW); __set_bit(SW_MUTE_DEVICE, input_dev->swbit); @@ -3712,8 +3782,14 @@ int wacom_setup_touch_input_capabilities(struct input_dev *input_dev, input_set_abs_params(input_dev, ABS_MT_POSITION_Y, 0, 5920, 4, 0); } + else if (wacom_wac->shared->touch->product == 0x393) { + input_set_abs_params(input_dev, ABS_MT_POSITION_X, + 0, 6400, 4, 0); + input_set_abs_params(input_dev, ABS_MT_POSITION_Y, + 0, 4000, 4, 0); + } input_abs_set_res(input_dev, ABS_MT_POSITION_X, 40); - input_abs_set_res(input_dev, ABS_MT_POSITION_X, 40); + input_abs_set_res(input_dev, ABS_MT_POSITION_Y, 40); /* fall through */ @@ -4021,6 +4097,7 @@ int wacom_setup_pad_input_capabilities(struct input_dev *input_dev, case INTUOS5S: case INTUOSPS: case INTUOSP2_BT: + case INTUOSP2S_BT: input_set_abs_params(input_dev, ABS_WHEEL, 0, 71, 0, 0); break; @@ -4598,6 +4675,10 @@ static const struct wacom_features wacom_features_0x37A = static const struct wacom_features wacom_features_0x37B = { "Wacom One by Wacom M", 21600, 13500, 2047, 63, BAMBOO_PEN, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; +static const struct wacom_features wacom_features_0x393 = + { "Wacom Intuos Pro S", 31920, 19950, 8191, 63, + INTUOSP2S_BT, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 7, + .touch_max = 10 }; static const struct wacom_features wacom_features_HID_ANY_ID = { "Wacom HID", .type = HID_GENERIC, .oVid = HID_ANY_ID, .oPid = HID_ANY_ID }; @@ -4770,6 +4851,7 @@ const struct hid_device_id wacom_ids[] = { { BT_DEVICE_WACOM(0x379) }, { USB_DEVICE_WACOM(0x37A) }, { USB_DEVICE_WACOM(0x37B) }, + { BT_DEVICE_WACOM(0x393) }, { USB_DEVICE_WACOM(0x4001) }, { USB_DEVICE_WACOM(0x4004) }, { USB_DEVICE_WACOM(0x5000) }, |