diff options
| author | Benjamin Tissoires <benjamin.tissoires@redhat.com> | 2014-09-30 13:18:33 -0400 |
|---|---|---|
| committer | Jiri Kosina <jkosina@suse.cz> | 2014-10-29 05:51:41 -0400 |
| commit | 586bdc4e4f15fec37dc37167d6f314ea94aa14d1 (patch) | |
| tree | 3a29aad0a77f40c984ca854939c31e6bf6792b03 | |
| parent | c39e3d5fc9dd3e16c6f59dd94d827540040de66d (diff) | |
HID: logitech-hidpp: Add Wireless Touchpad T650 support
All the bits are now in place to add the support of the
Touchpad T650.
The creation/population of the input device is delayed until
the device is ready.
The T650 uses the special HID++ reporting protocol, so activate
this on connect.
Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
Tested-by: Andrew de los Reyes <adlr@chromium.org>
Signed-off-by: Jiri Kosina <jkosina@suse.cz>
| -rw-r--r-- | drivers/hid/hid-logitech-hidpp.c | 105 |
1 files changed, 103 insertions, 2 deletions
diff --git a/drivers/hid/hid-logitech-hidpp.c b/drivers/hid/hid-logitech-hidpp.c index 9561a1f9b42b..f9a4ec0ff76d 100644 --- a/drivers/hid/hid-logitech-hidpp.c +++ b/drivers/hid/hid-logitech-hidpp.c | |||
| @@ -471,6 +471,9 @@ out_err: | |||
| 471 | #define HIDPP_PAGE_TOUCHPAD_RAW_XY 0x6100 | 471 | #define HIDPP_PAGE_TOUCHPAD_RAW_XY 0x6100 |
| 472 | 472 | ||
| 473 | #define CMD_TOUCHPAD_GET_RAW_INFO 0x01 | 473 | #define CMD_TOUCHPAD_GET_RAW_INFO 0x01 |
| 474 | #define CMD_TOUCHPAD_SET_RAW_REPORT_STATE 0x21 | ||
| 475 | |||
| 476 | #define EVENT_TOUCHPAD_RAW_XY 0x00 | ||
| 474 | 477 | ||
| 475 | #define TOUCHPAD_RAW_XY_ORIGIN_LOWER_LEFT 0x01 | 478 | #define TOUCHPAD_RAW_XY_ORIGIN_LOWER_LEFT 0x01 |
| 476 | #define TOUCHPAD_RAW_XY_ORIGIN_UPPER_LEFT 0x03 | 479 | #define TOUCHPAD_RAW_XY_ORIGIN_UPPER_LEFT 0x03 |
| @@ -530,6 +533,59 @@ static int hidpp_touchpad_get_raw_info(struct hidpp_device *hidpp, | |||
| 530 | return ret; | 533 | return ret; |
| 531 | } | 534 | } |
| 532 | 535 | ||
| 536 | static int hidpp_touchpad_set_raw_report_state(struct hidpp_device *hidpp_dev, | ||
| 537 | u8 feature_index, bool send_raw_reports, | ||
| 538 | bool sensor_enhanced_settings) | ||
| 539 | { | ||
| 540 | struct hidpp_report response; | ||
| 541 | |||
| 542 | /* | ||
| 543 | * Params: | ||
| 544 | * bit 0 - enable raw | ||
| 545 | * bit 1 - 16bit Z, no area | ||
| 546 | * bit 2 - enhanced sensitivity | ||
| 547 | * bit 3 - width, height (4 bits each) instead of area | ||
| 548 | * bit 4 - send raw + gestures (degrades smoothness) | ||
| 549 | * remaining bits - reserved | ||
| 550 | */ | ||
| 551 | u8 params = send_raw_reports | (sensor_enhanced_settings << 2); | ||
| 552 | |||
| 553 | return hidpp_send_fap_command_sync(hidpp_dev, feature_index, | ||
| 554 | CMD_TOUCHPAD_SET_RAW_REPORT_STATE, ¶ms, 1, &response); | ||
| 555 | } | ||
| 556 | |||
| 557 | static void hidpp_touchpad_touch_event(u8 *data, | ||
| 558 | struct hidpp_touchpad_raw_xy_finger *finger) | ||
| 559 | { | ||
| 560 | u8 x_m = data[0] << 2; | ||
| 561 | u8 y_m = data[2] << 2; | ||
| 562 | |||
| 563 | finger->x = x_m << 6 | data[1]; | ||
| 564 | finger->y = y_m << 6 | data[3]; | ||
| 565 | |||
| 566 | finger->contact_type = data[0] >> 6; | ||
| 567 | finger->contact_status = data[2] >> 6; | ||
| 568 | |||
| 569 | finger->z = data[4]; | ||
| 570 | finger->area = data[5]; | ||
| 571 | finger->finger_id = data[6] >> 4; | ||
| 572 | } | ||
| 573 | |||
| 574 | static void hidpp_touchpad_raw_xy_event(struct hidpp_device *hidpp_dev, | ||
| 575 | u8 *data, struct hidpp_touchpad_raw_xy *raw_xy) | ||
| 576 | { | ||
| 577 | memset(raw_xy, 0, sizeof(struct hidpp_touchpad_raw_xy)); | ||
| 578 | raw_xy->end_of_frame = data[8] & 0x01; | ||
| 579 | raw_xy->spurious_flag = (data[8] >> 1) & 0x01; | ||
| 580 | raw_xy->finger_count = data[15] & 0x0f; | ||
| 581 | raw_xy->button = (data[8] >> 2) & 0x01; | ||
| 582 | |||
| 583 | if (raw_xy->finger_count) { | ||
| 584 | hidpp_touchpad_touch_event(&data[2], &raw_xy->fingers[0]); | ||
| 585 | hidpp_touchpad_touch_event(&data[9], &raw_xy->fingers[1]); | ||
| 586 | } | ||
| 587 | } | ||
| 588 | |||
| 533 | /* ************************************************************************** */ | 589 | /* ************************************************************************** */ |
| 534 | /* */ | 590 | /* */ |
| 535 | /* Device Support */ | 591 | /* Device Support */ |
| @@ -672,11 +728,28 @@ static int wtp_raw_event(struct hid_device *hdev, u8 *data, int size) | |||
| 672 | { | 728 | { |
| 673 | struct hidpp_device *hidpp = hid_get_drvdata(hdev); | 729 | struct hidpp_device *hidpp = hid_get_drvdata(hdev); |
| 674 | struct wtp_data *wd = hidpp->private_data; | 730 | struct wtp_data *wd = hidpp->private_data; |
| 731 | struct hidpp_report *report = (struct hidpp_report *)data; | ||
| 732 | struct hidpp_touchpad_raw_xy raw; | ||
| 675 | 733 | ||
| 676 | if (!wd || !wd->input || (data[0] != 0x02) || size < 21) | 734 | if (!wd || !wd->input) |
| 677 | return 1; | 735 | return 1; |
| 678 | 736 | ||
| 679 | return wtp_mouse_raw_xy_event(hidpp, &data[7]); | 737 | switch (data[0]) { |
| 738 | case 0x02: | ||
| 739 | if (size < 21) | ||
| 740 | return 1; | ||
| 741 | return wtp_mouse_raw_xy_event(hidpp, &data[7]); | ||
| 742 | case REPORT_ID_HIDPP_LONG: | ||
| 743 | if ((report->fap.feature_index != wd->mt_feature_index) || | ||
| 744 | (report->fap.funcindex_clientid != EVENT_TOUCHPAD_RAW_XY)) | ||
| 745 | return 1; | ||
| 746 | hidpp_touchpad_raw_xy_event(hidpp, data + 4, &raw); | ||
| 747 | |||
| 748 | wtp_send_raw_xy_event(hidpp, &raw); | ||
| 749 | return 0; | ||
| 750 | } | ||
| 751 | |||
| 752 | return 0; | ||
| 680 | } | 753 | } |
| 681 | 754 | ||
| 682 | static int wtp_get_config(struct hidpp_device *hidpp) | 755 | static int wtp_get_config(struct hidpp_device *hidpp) |
| @@ -721,6 +794,27 @@ static int wtp_allocate(struct hid_device *hdev, const struct hid_device_id *id) | |||
| 721 | return 0; | 794 | return 0; |
| 722 | }; | 795 | }; |
| 723 | 796 | ||
| 797 | static void wtp_connect(struct hid_device *hdev, bool connected) | ||
| 798 | { | ||
| 799 | struct hidpp_device *hidpp = hid_get_drvdata(hdev); | ||
| 800 | struct wtp_data *wd = hidpp->private_data; | ||
| 801 | int ret; | ||
| 802 | |||
| 803 | if (!connected) | ||
| 804 | return; | ||
| 805 | |||
| 806 | if (!wd->x_size) { | ||
| 807 | ret = wtp_get_config(hidpp); | ||
| 808 | if (ret) { | ||
| 809 | hid_err(hdev, "Can not get wtp config: %d\n", ret); | ||
| 810 | return; | ||
| 811 | } | ||
| 812 | } | ||
| 813 | |||
| 814 | hidpp_touchpad_set_raw_report_state(hidpp, wd->mt_feature_index, | ||
| 815 | true, true); | ||
| 816 | } | ||
| 817 | |||
| 724 | /* -------------------------------------------------------------------------- */ | 818 | /* -------------------------------------------------------------------------- */ |
| 725 | /* Generic HID++ devices */ | 819 | /* Generic HID++ devices */ |
| 726 | /* -------------------------------------------------------------------------- */ | 820 | /* -------------------------------------------------------------------------- */ |
| @@ -897,6 +991,9 @@ static void hidpp_connect_event(struct hidpp_device *hidpp) | |||
| 897 | char *name, *devm_name; | 991 | char *name, *devm_name; |
| 898 | u8 name_length; | 992 | u8 name_length; |
| 899 | 993 | ||
| 994 | if (hidpp->quirks & HIDPP_QUIRK_CLASS_WTP) | ||
| 995 | wtp_connect(hdev, connected); | ||
| 996 | |||
| 900 | if (!connected || hidpp->delayed_input) | 997 | if (!connected || hidpp->delayed_input) |
| 901 | return; | 998 | return; |
| 902 | 999 | ||
| @@ -1033,6 +1130,10 @@ static void hidpp_remove(struct hid_device *hdev) | |||
| 1033 | } | 1130 | } |
| 1034 | 1131 | ||
| 1035 | static const struct hid_device_id hidpp_devices[] = { | 1132 | static const struct hid_device_id hidpp_devices[] = { |
| 1133 | { /* wireless touchpad T650 */ | ||
| 1134 | HID_DEVICE(BUS_USB, HID_GROUP_LOGITECH_DJ_DEVICE, | ||
| 1135 | USB_VENDOR_ID_LOGITECH, 0x4101), | ||
| 1136 | .driver_data = HIDPP_QUIRK_CLASS_WTP | HIDPP_QUIRK_DELAYED_INIT }, | ||
| 1036 | { /* wireless touchpad T651 */ | 1137 | { /* wireless touchpad T651 */ |
| 1037 | HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, | 1138 | HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, |
| 1038 | USB_DEVICE_ID_LOGITECH_T651), | 1139 | USB_DEVICE_ID_LOGITECH_T651), |
