.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* |
---|
2 | | - * HIDPP protocol for Logitech Unifying receivers |
---|
| 3 | + * HIDPP protocol for Logitech receivers |
---|
3 | 4 | * |
---|
4 | 5 | * Copyright (c) 2011 Logitech (c) |
---|
5 | 6 | * Copyright (c) 2012-2013 Google (c) |
---|
6 | 7 | * Copyright (c) 2013-2014 Red Hat Inc. |
---|
7 | 8 | */ |
---|
8 | 9 | |
---|
9 | | -/* |
---|
10 | | - * This program is free software; you can redistribute it and/or modify it |
---|
11 | | - * under the terms of the GNU General Public License as published by the Free |
---|
12 | | - * Software Foundation; version 2 of the License. |
---|
13 | | - */ |
---|
14 | 10 | |
---|
15 | 11 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
---|
16 | 12 | |
---|
.. | .. |
---|
21 | 17 | #include <linux/module.h> |
---|
22 | 18 | #include <linux/slab.h> |
---|
23 | 19 | #include <linux/sched.h> |
---|
| 20 | +#include <linux/sched/clock.h> |
---|
24 | 21 | #include <linux/kfifo.h> |
---|
25 | 22 | #include <linux/input/mt.h> |
---|
26 | 23 | #include <linux/workqueue.h> |
---|
.. | .. |
---|
50 | 47 | |
---|
51 | 48 | #define HIDPP_REPORT_SHORT_LENGTH 7 |
---|
52 | 49 | #define HIDPP_REPORT_LONG_LENGTH 20 |
---|
53 | | -#define HIDPP_REPORT_VERY_LONG_LENGTH 64 |
---|
| 50 | +#define HIDPP_REPORT_VERY_LONG_MAX_LENGTH 64 |
---|
| 51 | + |
---|
| 52 | +#define HIDPP_REPORT_SHORT_SUPPORTED BIT(0) |
---|
| 53 | +#define HIDPP_REPORT_LONG_SUPPORTED BIT(1) |
---|
| 54 | +#define HIDPP_REPORT_VERY_LONG_SUPPORTED BIT(2) |
---|
| 55 | + |
---|
| 56 | +#define HIDPP_SUB_ID_CONSUMER_VENDOR_KEYS 0x03 |
---|
| 57 | +#define HIDPP_SUB_ID_ROLLER 0x05 |
---|
| 58 | +#define HIDPP_SUB_ID_MOUSE_EXTRA_BTNS 0x06 |
---|
54 | 59 | |
---|
55 | 60 | #define HIDPP_QUIRK_CLASS_WTP BIT(0) |
---|
56 | 61 | #define HIDPP_QUIRK_CLASS_M560 BIT(1) |
---|
.. | .. |
---|
64 | 69 | #define HIDPP_QUIRK_NO_HIDINPUT BIT(23) |
---|
65 | 70 | #define HIDPP_QUIRK_FORCE_OUTPUT_REPORTS BIT(24) |
---|
66 | 71 | #define HIDPP_QUIRK_UNIFYING BIT(25) |
---|
| 72 | +#define HIDPP_QUIRK_HI_RES_SCROLL_1P0 BIT(26) |
---|
| 73 | +#define HIDPP_QUIRK_HI_RES_SCROLL_X2120 BIT(27) |
---|
| 74 | +#define HIDPP_QUIRK_HI_RES_SCROLL_X2121 BIT(28) |
---|
| 75 | +#define HIDPP_QUIRK_HIDPP_WHEELS BIT(29) |
---|
| 76 | +#define HIDPP_QUIRK_HIDPP_EXTRA_MOUSE_BTNS BIT(30) |
---|
| 77 | +#define HIDPP_QUIRK_HIDPP_CONSUMER_VENDOR_KEYS BIT(31) |
---|
| 78 | + |
---|
| 79 | +/* These are just aliases for now */ |
---|
| 80 | +#define HIDPP_QUIRK_KBD_SCROLL_WHEEL HIDPP_QUIRK_HIDPP_WHEELS |
---|
| 81 | +#define HIDPP_QUIRK_KBD_ZOOM_WHEEL HIDPP_QUIRK_HIDPP_WHEELS |
---|
| 82 | + |
---|
| 83 | +/* Convenience constant to check for any high-res support. */ |
---|
| 84 | +#define HIDPP_QUIRK_HI_RES_SCROLL (HIDPP_QUIRK_HI_RES_SCROLL_1P0 | \ |
---|
| 85 | + HIDPP_QUIRK_HI_RES_SCROLL_X2120 | \ |
---|
| 86 | + HIDPP_QUIRK_HI_RES_SCROLL_X2121) |
---|
67 | 87 | |
---|
68 | 88 | #define HIDPP_QUIRK_DELAYED_INIT HIDPP_QUIRK_NO_HIDINPUT |
---|
69 | 89 | |
---|
.. | .. |
---|
71 | 91 | #define HIDPP_CAPABILITY_HIDPP20_BATTERY BIT(1) |
---|
72 | 92 | #define HIDPP_CAPABILITY_BATTERY_MILEAGE BIT(2) |
---|
73 | 93 | #define HIDPP_CAPABILITY_BATTERY_LEVEL_STATUS BIT(3) |
---|
| 94 | +#define HIDPP_CAPABILITY_BATTERY_VOLTAGE BIT(4) |
---|
| 95 | + |
---|
| 96 | +#define lg_map_key_clear(c) hid_map_usage_clear(hi, usage, bit, max, EV_KEY, (c)) |
---|
74 | 97 | |
---|
75 | 98 | /* |
---|
76 | 99 | * There are two hidpp protocols in use, the first version hidpp10 is known |
---|
.. | .. |
---|
97 | 120 | struct fap { |
---|
98 | 121 | u8 feature_index; |
---|
99 | 122 | u8 funcindex_clientid; |
---|
100 | | - u8 params[HIDPP_REPORT_VERY_LONG_LENGTH - 4U]; |
---|
| 123 | + u8 params[HIDPP_REPORT_VERY_LONG_MAX_LENGTH - 4U]; |
---|
101 | 124 | }; |
---|
102 | 125 | |
---|
103 | 126 | struct rap { |
---|
104 | 127 | u8 sub_id; |
---|
105 | 128 | u8 reg_address; |
---|
106 | | - u8 params[HIDPP_REPORT_VERY_LONG_LENGTH - 4U]; |
---|
| 129 | + u8 params[HIDPP_REPORT_VERY_LONG_MAX_LENGTH - 4U]; |
---|
107 | 130 | }; |
---|
108 | 131 | |
---|
109 | 132 | struct hidpp_report { |
---|
.. | .. |
---|
119 | 142 | struct hidpp_battery { |
---|
120 | 143 | u8 feature_index; |
---|
121 | 144 | u8 solar_feature_index; |
---|
| 145 | + u8 voltage_feature_index; |
---|
122 | 146 | struct power_supply_desc desc; |
---|
123 | 147 | struct power_supply *ps; |
---|
124 | 148 | char name[64]; |
---|
125 | 149 | int status; |
---|
126 | 150 | int capacity; |
---|
127 | 151 | int level; |
---|
| 152 | + int voltage; |
---|
| 153 | + int charge_type; |
---|
128 | 154 | bool online; |
---|
| 155 | +}; |
---|
| 156 | + |
---|
| 157 | +/** |
---|
| 158 | + * struct hidpp_scroll_counter - Utility class for processing high-resolution |
---|
| 159 | + * scroll events. |
---|
| 160 | + * @dev: the input device for which events should be reported. |
---|
| 161 | + * @wheel_multiplier: the scalar multiplier to be applied to each wheel event |
---|
| 162 | + * @remainder: counts the number of high-resolution units moved since the last |
---|
| 163 | + * low-resolution event (REL_WHEEL or REL_HWHEEL) was sent. Should |
---|
| 164 | + * only be used by class methods. |
---|
| 165 | + * @direction: direction of last movement (1 or -1) |
---|
| 166 | + * @last_time: last event time, used to reset remainder after inactivity |
---|
| 167 | + */ |
---|
| 168 | +struct hidpp_scroll_counter { |
---|
| 169 | + int wheel_multiplier; |
---|
| 170 | + int remainder; |
---|
| 171 | + int direction; |
---|
| 172 | + unsigned long long last_time; |
---|
129 | 173 | }; |
---|
130 | 174 | |
---|
131 | 175 | struct hidpp_device { |
---|
132 | 176 | struct hid_device *hid_dev; |
---|
| 177 | + struct input_dev *input; |
---|
133 | 178 | struct mutex send_mutex; |
---|
134 | 179 | void *send_receive_buf; |
---|
135 | 180 | char *name; /* will never be NULL and should not be freed */ |
---|
136 | 181 | wait_queue_head_t wait; |
---|
| 182 | + int very_long_report_length; |
---|
137 | 183 | bool answer_available; |
---|
138 | 184 | u8 protocol_major; |
---|
139 | 185 | u8 protocol_minor; |
---|
.. | .. |
---|
147 | 193 | |
---|
148 | 194 | unsigned long quirks; |
---|
149 | 195 | unsigned long capabilities; |
---|
| 196 | + u8 supported_reports; |
---|
150 | 197 | |
---|
151 | 198 | struct hidpp_battery battery; |
---|
| 199 | + struct hidpp_scroll_counter vertical_wheel_counter; |
---|
| 200 | + |
---|
| 201 | + u8 wireless_feature_index; |
---|
152 | 202 | }; |
---|
153 | 203 | |
---|
154 | 204 | /* HID++ 1.0 error codes */ |
---|
.. | .. |
---|
177 | 227 | struct hidpp_device *hidpp = hid_get_drvdata(hdev); |
---|
178 | 228 | int fields_count, ret; |
---|
179 | 229 | |
---|
180 | | - hidpp = hid_get_drvdata(hdev); |
---|
181 | | - |
---|
182 | 230 | switch (hidpp_report->report_id) { |
---|
183 | 231 | case REPORT_ID_HIDPP_SHORT: |
---|
184 | 232 | fields_count = HIDPP_REPORT_SHORT_LENGTH; |
---|
.. | .. |
---|
187 | 235 | fields_count = HIDPP_REPORT_LONG_LENGTH; |
---|
188 | 236 | break; |
---|
189 | 237 | case REPORT_ID_HIDPP_VERY_LONG: |
---|
190 | | - fields_count = HIDPP_REPORT_VERY_LONG_LENGTH; |
---|
| 238 | + fields_count = hidpp->very_long_report_length; |
---|
191 | 239 | break; |
---|
192 | 240 | default: |
---|
193 | 241 | return -ENODEV; |
---|
.. | .. |
---|
305 | 353 | struct hidpp_report *message; |
---|
306 | 354 | int ret, max_count; |
---|
307 | 355 | |
---|
| 356 | + /* Send as long report if short reports are not supported. */ |
---|
| 357 | + if (report_id == REPORT_ID_HIDPP_SHORT && |
---|
| 358 | + !(hidpp_dev->supported_reports & HIDPP_REPORT_SHORT_SUPPORTED)) |
---|
| 359 | + report_id = REPORT_ID_HIDPP_LONG; |
---|
| 360 | + |
---|
308 | 361 | switch (report_id) { |
---|
309 | 362 | case REPORT_ID_HIDPP_SHORT: |
---|
310 | 363 | max_count = HIDPP_REPORT_SHORT_LENGTH - 4; |
---|
.. | .. |
---|
313 | 366 | max_count = HIDPP_REPORT_LONG_LENGTH - 4; |
---|
314 | 367 | break; |
---|
315 | 368 | case REPORT_ID_HIDPP_VERY_LONG: |
---|
316 | | - max_count = HIDPP_REPORT_VERY_LONG_LENGTH - 4; |
---|
| 369 | + max_count = hidpp_dev->very_long_report_length - 4; |
---|
317 | 370 | break; |
---|
318 | 371 | default: |
---|
319 | 372 | return -EINVAL; |
---|
.. | .. |
---|
358 | 411 | (answer->fap.params[0] == question->fap.funcindex_clientid); |
---|
359 | 412 | } |
---|
360 | 413 | |
---|
361 | | -static inline bool hidpp_report_is_connect_event(struct hidpp_report *report) |
---|
| 414 | +static inline bool hidpp_report_is_connect_event(struct hidpp_device *hidpp, |
---|
| 415 | + struct hidpp_report *report) |
---|
362 | 416 | { |
---|
363 | | - return (report->report_id == REPORT_ID_HIDPP_SHORT) && |
---|
364 | | - (report->rap.sub_id == 0x41); |
---|
| 417 | + return (hidpp->wireless_feature_index && |
---|
| 418 | + (report->fap.feature_index == hidpp->wireless_feature_index)) || |
---|
| 419 | + ((report->report_id == REPORT_ID_HIDPP_SHORT) && |
---|
| 420 | + (report->rap.sub_id == 0x41)); |
---|
365 | 421 | } |
---|
366 | 422 | |
---|
367 | 423 | /** |
---|
.. | .. |
---|
391 | 447 | *name = new_name; |
---|
392 | 448 | } |
---|
393 | 449 | |
---|
| 450 | +/** |
---|
| 451 | + * hidpp_scroll_counter_handle_scroll() - Send high- and low-resolution scroll |
---|
| 452 | + * events given a high-resolution wheel |
---|
| 453 | + * movement. |
---|
| 454 | + * @counter: a hid_scroll_counter struct describing the wheel. |
---|
| 455 | + * @hi_res_value: the movement of the wheel, in the mouse's high-resolution |
---|
| 456 | + * units. |
---|
| 457 | + * |
---|
| 458 | + * Given a high-resolution movement, this function converts the movement into |
---|
| 459 | + * fractions of 120 and emits high-resolution scroll events for the input |
---|
| 460 | + * device. It also uses the multiplier from &struct hid_scroll_counter to |
---|
| 461 | + * emit low-resolution scroll events when appropriate for |
---|
| 462 | + * backwards-compatibility with userspace input libraries. |
---|
| 463 | + */ |
---|
| 464 | +static void hidpp_scroll_counter_handle_scroll(struct input_dev *input_dev, |
---|
| 465 | + struct hidpp_scroll_counter *counter, |
---|
| 466 | + int hi_res_value) |
---|
| 467 | +{ |
---|
| 468 | + int low_res_value, remainder, direction; |
---|
| 469 | + unsigned long long now, previous; |
---|
| 470 | + |
---|
| 471 | + hi_res_value = hi_res_value * 120/counter->wheel_multiplier; |
---|
| 472 | + input_report_rel(input_dev, REL_WHEEL_HI_RES, hi_res_value); |
---|
| 473 | + |
---|
| 474 | + remainder = counter->remainder; |
---|
| 475 | + direction = hi_res_value > 0 ? 1 : -1; |
---|
| 476 | + |
---|
| 477 | + now = sched_clock(); |
---|
| 478 | + previous = counter->last_time; |
---|
| 479 | + counter->last_time = now; |
---|
| 480 | + /* |
---|
| 481 | + * Reset the remainder after a period of inactivity or when the |
---|
| 482 | + * direction changes. This prevents the REL_WHEEL emulation point |
---|
| 483 | + * from sliding for devices that don't always provide the same |
---|
| 484 | + * number of movements per detent. |
---|
| 485 | + */ |
---|
| 486 | + if (now - previous > 1000000000 || direction != counter->direction) |
---|
| 487 | + remainder = 0; |
---|
| 488 | + |
---|
| 489 | + counter->direction = direction; |
---|
| 490 | + remainder += hi_res_value; |
---|
| 491 | + |
---|
| 492 | + /* Some wheels will rest 7/8ths of a detent from the previous detent |
---|
| 493 | + * after slow movement, so we want the threshold for low-res events to |
---|
| 494 | + * be in the middle between two detents (e.g. after 4/8ths) as |
---|
| 495 | + * opposed to on the detents themselves (8/8ths). |
---|
| 496 | + */ |
---|
| 497 | + if (abs(remainder) >= 60) { |
---|
| 498 | + /* Add (or subtract) 1 because we want to trigger when the wheel |
---|
| 499 | + * is half-way to the next detent (i.e. scroll 1 detent after a |
---|
| 500 | + * 1/2 detent movement, 2 detents after a 1 1/2 detent movement, |
---|
| 501 | + * etc.). |
---|
| 502 | + */ |
---|
| 503 | + low_res_value = remainder / 120; |
---|
| 504 | + if (low_res_value == 0) |
---|
| 505 | + low_res_value = (hi_res_value > 0 ? 1 : -1); |
---|
| 506 | + input_report_rel(input_dev, REL_WHEEL, low_res_value); |
---|
| 507 | + remainder -= low_res_value * 120; |
---|
| 508 | + } |
---|
| 509 | + counter->remainder = remainder; |
---|
| 510 | +} |
---|
| 511 | + |
---|
394 | 512 | /* -------------------------------------------------------------------------- */ |
---|
395 | 513 | /* HIDP++ 1.0 commands */ |
---|
396 | 514 | /* -------------------------------------------------------------------------- */ |
---|
.. | .. |
---|
400 | 518 | #define HIDPP_SET_LONG_REGISTER 0x82 |
---|
401 | 519 | #define HIDPP_GET_LONG_REGISTER 0x83 |
---|
402 | 520 | |
---|
403 | | -#define HIDPP_REG_GENERAL 0x00 |
---|
404 | | - |
---|
405 | | -static int hidpp10_enable_battery_reporting(struct hidpp_device *hidpp_dev) |
---|
| 521 | +/** |
---|
| 522 | + * hidpp10_set_register - Modify a HID++ 1.0 register. |
---|
| 523 | + * @hidpp_dev: the device to set the register on. |
---|
| 524 | + * @register_address: the address of the register to modify. |
---|
| 525 | + * @byte: the byte of the register to modify. Should be less than 3. |
---|
| 526 | + * @mask: mask of the bits to modify |
---|
| 527 | + * @value: new values for the bits in mask |
---|
| 528 | + * Return: 0 if successful, otherwise a negative error code. |
---|
| 529 | + */ |
---|
| 530 | +static int hidpp10_set_register(struct hidpp_device *hidpp_dev, |
---|
| 531 | + u8 register_address, u8 byte, u8 mask, u8 value) |
---|
406 | 532 | { |
---|
407 | 533 | struct hidpp_report response; |
---|
408 | 534 | int ret; |
---|
409 | 535 | u8 params[3] = { 0 }; |
---|
410 | 536 | |
---|
411 | 537 | ret = hidpp_send_rap_command_sync(hidpp_dev, |
---|
412 | | - REPORT_ID_HIDPP_SHORT, |
---|
413 | | - HIDPP_GET_REGISTER, |
---|
414 | | - HIDPP_REG_GENERAL, |
---|
415 | | - NULL, 0, &response); |
---|
| 538 | + REPORT_ID_HIDPP_SHORT, |
---|
| 539 | + HIDPP_GET_REGISTER, |
---|
| 540 | + register_address, |
---|
| 541 | + NULL, 0, &response); |
---|
416 | 542 | if (ret) |
---|
417 | 543 | return ret; |
---|
418 | 544 | |
---|
419 | 545 | memcpy(params, response.rap.params, 3); |
---|
420 | 546 | |
---|
421 | | - /* Set the battery bit */ |
---|
422 | | - params[0] |= BIT(4); |
---|
| 547 | + params[byte] &= ~mask; |
---|
| 548 | + params[byte] |= value & mask; |
---|
423 | 549 | |
---|
424 | 550 | return hidpp_send_rap_command_sync(hidpp_dev, |
---|
425 | | - REPORT_ID_HIDPP_SHORT, |
---|
426 | | - HIDPP_SET_REGISTER, |
---|
427 | | - HIDPP_REG_GENERAL, |
---|
428 | | - params, 3, &response); |
---|
| 551 | + REPORT_ID_HIDPP_SHORT, |
---|
| 552 | + HIDPP_SET_REGISTER, |
---|
| 553 | + register_address, |
---|
| 554 | + params, 3, &response); |
---|
| 555 | +} |
---|
| 556 | + |
---|
| 557 | +#define HIDPP_REG_ENABLE_REPORTS 0x00 |
---|
| 558 | +#define HIDPP_ENABLE_CONSUMER_REPORT BIT(0) |
---|
| 559 | +#define HIDPP_ENABLE_WHEEL_REPORT BIT(2) |
---|
| 560 | +#define HIDPP_ENABLE_MOUSE_EXTRA_BTN_REPORT BIT(3) |
---|
| 561 | +#define HIDPP_ENABLE_BAT_REPORT BIT(4) |
---|
| 562 | +#define HIDPP_ENABLE_HWHEEL_REPORT BIT(5) |
---|
| 563 | + |
---|
| 564 | +static int hidpp10_enable_battery_reporting(struct hidpp_device *hidpp_dev) |
---|
| 565 | +{ |
---|
| 566 | + return hidpp10_set_register(hidpp_dev, HIDPP_REG_ENABLE_REPORTS, 0, |
---|
| 567 | + HIDPP_ENABLE_BAT_REPORT, HIDPP_ENABLE_BAT_REPORT); |
---|
| 568 | +} |
---|
| 569 | + |
---|
| 570 | +#define HIDPP_REG_FEATURES 0x01 |
---|
| 571 | +#define HIDPP_ENABLE_SPECIAL_BUTTON_FUNC BIT(1) |
---|
| 572 | +#define HIDPP_ENABLE_FAST_SCROLL BIT(6) |
---|
| 573 | + |
---|
| 574 | +/* On HID++ 1.0 devices, high-res scroll was called "scrolling acceleration". */ |
---|
| 575 | +static int hidpp10_enable_scrolling_acceleration(struct hidpp_device *hidpp_dev) |
---|
| 576 | +{ |
---|
| 577 | + return hidpp10_set_register(hidpp_dev, HIDPP_REG_FEATURES, 0, |
---|
| 578 | + HIDPP_ENABLE_FAST_SCROLL, HIDPP_ENABLE_FAST_SCROLL); |
---|
429 | 579 | } |
---|
430 | 580 | |
---|
431 | 581 | #define HIDPP_REG_BATTERY_STATUS 0x07 |
---|
.. | .. |
---|
630 | 780 | if (2 + len > sizeof(response.rap.params)) |
---|
631 | 781 | return NULL; |
---|
632 | 782 | |
---|
| 783 | + if (len < 4) /* logitech devices are usually at least Xddd */ |
---|
| 784 | + return NULL; |
---|
| 785 | + |
---|
633 | 786 | name = kzalloc(len + 1, GFP_KERNEL); |
---|
634 | 787 | if (!name) |
---|
635 | 788 | return NULL; |
---|
.. | .. |
---|
675 | 828 | if (ret) |
---|
676 | 829 | return ret; |
---|
677 | 830 | |
---|
678 | | - snprintf(hdev->uniq, sizeof(hdev->uniq), "%04x-%4phD", |
---|
679 | | - hdev->product, &serial); |
---|
| 831 | + snprintf(hdev->uniq, sizeof(hdev->uniq), "%4phD", &serial); |
---|
680 | 832 | dbg_hid("HID++ Unifying: Got serial: %s\n", hdev->uniq); |
---|
681 | 833 | |
---|
682 | 834 | name = hidpp_unifying_get_name(hidpp); |
---|
.. | .. |
---|
739 | 891 | if (ret == HIDPP_ERROR_INVALID_SUBID) { |
---|
740 | 892 | hidpp->protocol_major = 1; |
---|
741 | 893 | hidpp->protocol_minor = 0; |
---|
742 | | - return 0; |
---|
| 894 | + goto print_version; |
---|
743 | 895 | } |
---|
744 | 896 | |
---|
745 | 897 | /* the device might not be connected */ |
---|
.. | .. |
---|
763 | 915 | hidpp->protocol_major = response.rap.params[0]; |
---|
764 | 916 | hidpp->protocol_minor = response.rap.params[1]; |
---|
765 | 917 | |
---|
766 | | - return ret; |
---|
| 918 | +print_version: |
---|
| 919 | + hid_info(hidpp->hid_dev, "HID++ %u.%u device connected.\n", |
---|
| 920 | + hidpp->protocol_major, hidpp->protocol_minor); |
---|
| 921 | + return 0; |
---|
767 | 922 | } |
---|
768 | 923 | |
---|
769 | | -static bool hidpp_is_connected(struct hidpp_device *hidpp) |
---|
| 924 | +/* -------------------------------------------------------------------------- */ |
---|
| 925 | +/* 0x0003: Device Information */ |
---|
| 926 | +/* -------------------------------------------------------------------------- */ |
---|
| 927 | + |
---|
| 928 | +#define HIDPP_PAGE_DEVICE_INFORMATION 0x0003 |
---|
| 929 | + |
---|
| 930 | +#define CMD_GET_DEVICE_INFO 0x00 |
---|
| 931 | + |
---|
| 932 | +static int hidpp_get_serial(struct hidpp_device *hidpp, u32 *serial) |
---|
770 | 933 | { |
---|
| 934 | + struct hidpp_report response; |
---|
| 935 | + u8 feature_type; |
---|
| 936 | + u8 feature_index; |
---|
771 | 937 | int ret; |
---|
772 | 938 | |
---|
773 | | - ret = hidpp_root_get_protocol_version(hidpp); |
---|
774 | | - if (!ret) |
---|
775 | | - hid_dbg(hidpp->hid_dev, "HID++ %u.%u device connected.\n", |
---|
776 | | - hidpp->protocol_major, hidpp->protocol_minor); |
---|
777 | | - return ret == 0; |
---|
| 939 | + ret = hidpp_root_get_feature(hidpp, HIDPP_PAGE_DEVICE_INFORMATION, |
---|
| 940 | + &feature_index, |
---|
| 941 | + &feature_type); |
---|
| 942 | + if (ret) |
---|
| 943 | + return ret; |
---|
| 944 | + |
---|
| 945 | + ret = hidpp_send_fap_command_sync(hidpp, feature_index, |
---|
| 946 | + CMD_GET_DEVICE_INFO, |
---|
| 947 | + NULL, 0, &response); |
---|
| 948 | + if (ret) |
---|
| 949 | + return ret; |
---|
| 950 | + |
---|
| 951 | + /* See hidpp_unifying_get_serial() */ |
---|
| 952 | + *serial = *((u32 *)&response.rap.params[1]); |
---|
| 953 | + return 0; |
---|
| 954 | +} |
---|
| 955 | + |
---|
| 956 | +static int hidpp_serial_init(struct hidpp_device *hidpp) |
---|
| 957 | +{ |
---|
| 958 | + struct hid_device *hdev = hidpp->hid_dev; |
---|
| 959 | + u32 serial; |
---|
| 960 | + int ret; |
---|
| 961 | + |
---|
| 962 | + ret = hidpp_get_serial(hidpp, &serial); |
---|
| 963 | + if (ret) |
---|
| 964 | + return ret; |
---|
| 965 | + |
---|
| 966 | + snprintf(hdev->uniq, sizeof(hdev->uniq), "%4phD", &serial); |
---|
| 967 | + dbg_hid("HID++ DeviceInformation: Got serial: %s\n", hdev->uniq); |
---|
| 968 | + |
---|
| 969 | + return 0; |
---|
778 | 970 | } |
---|
779 | 971 | |
---|
780 | 972 | /* -------------------------------------------------------------------------- */ |
---|
.. | .. |
---|
830 | 1022 | |
---|
831 | 1023 | switch (response.report_id) { |
---|
832 | 1024 | case REPORT_ID_HIDPP_VERY_LONG: |
---|
833 | | - count = HIDPP_REPORT_VERY_LONG_LENGTH - 4; |
---|
| 1025 | + count = hidpp->very_long_report_length - 4; |
---|
834 | 1026 | break; |
---|
835 | 1027 | case REPORT_ID_HIDPP_LONG: |
---|
836 | 1028 | count = HIDPP_REPORT_LONG_LENGTH - 4; |
---|
.. | .. |
---|
1098 | 1290 | return 0; |
---|
1099 | 1291 | } |
---|
1100 | 1292 | |
---|
| 1293 | +/* -------------------------------------------------------------------------- */ |
---|
| 1294 | +/* 0x1001: Battery voltage */ |
---|
| 1295 | +/* -------------------------------------------------------------------------- */ |
---|
| 1296 | + |
---|
| 1297 | +#define HIDPP_PAGE_BATTERY_VOLTAGE 0x1001 |
---|
| 1298 | + |
---|
| 1299 | +#define CMD_BATTERY_VOLTAGE_GET_BATTERY_VOLTAGE 0x00 |
---|
| 1300 | + |
---|
| 1301 | +#define EVENT_BATTERY_VOLTAGE_STATUS_BROADCAST 0x00 |
---|
| 1302 | + |
---|
| 1303 | +static int hidpp20_battery_map_status_voltage(u8 data[3], int *voltage, |
---|
| 1304 | + int *level, int *charge_type) |
---|
| 1305 | +{ |
---|
| 1306 | + int status; |
---|
| 1307 | + |
---|
| 1308 | + long flags = (long) data[2]; |
---|
| 1309 | + *level = POWER_SUPPLY_CAPACITY_LEVEL_UNKNOWN; |
---|
| 1310 | + |
---|
| 1311 | + if (flags & 0x80) |
---|
| 1312 | + switch (flags & 0x07) { |
---|
| 1313 | + case 0: |
---|
| 1314 | + status = POWER_SUPPLY_STATUS_CHARGING; |
---|
| 1315 | + break; |
---|
| 1316 | + case 1: |
---|
| 1317 | + status = POWER_SUPPLY_STATUS_FULL; |
---|
| 1318 | + *level = POWER_SUPPLY_CAPACITY_LEVEL_FULL; |
---|
| 1319 | + break; |
---|
| 1320 | + case 2: |
---|
| 1321 | + status = POWER_SUPPLY_STATUS_NOT_CHARGING; |
---|
| 1322 | + break; |
---|
| 1323 | + default: |
---|
| 1324 | + status = POWER_SUPPLY_STATUS_UNKNOWN; |
---|
| 1325 | + break; |
---|
| 1326 | + } |
---|
| 1327 | + else |
---|
| 1328 | + status = POWER_SUPPLY_STATUS_DISCHARGING; |
---|
| 1329 | + |
---|
| 1330 | + *charge_type = POWER_SUPPLY_CHARGE_TYPE_STANDARD; |
---|
| 1331 | + if (test_bit(3, &flags)) { |
---|
| 1332 | + *charge_type = POWER_SUPPLY_CHARGE_TYPE_FAST; |
---|
| 1333 | + } |
---|
| 1334 | + if (test_bit(4, &flags)) { |
---|
| 1335 | + *charge_type = POWER_SUPPLY_CHARGE_TYPE_TRICKLE; |
---|
| 1336 | + } |
---|
| 1337 | + if (test_bit(5, &flags)) { |
---|
| 1338 | + *level = POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL; |
---|
| 1339 | + } |
---|
| 1340 | + |
---|
| 1341 | + *voltage = get_unaligned_be16(data); |
---|
| 1342 | + |
---|
| 1343 | + return status; |
---|
| 1344 | +} |
---|
| 1345 | + |
---|
| 1346 | +static int hidpp20_battery_get_battery_voltage(struct hidpp_device *hidpp, |
---|
| 1347 | + u8 feature_index, |
---|
| 1348 | + int *status, int *voltage, |
---|
| 1349 | + int *level, int *charge_type) |
---|
| 1350 | +{ |
---|
| 1351 | + struct hidpp_report response; |
---|
| 1352 | + int ret; |
---|
| 1353 | + u8 *params = (u8 *)response.fap.params; |
---|
| 1354 | + |
---|
| 1355 | + ret = hidpp_send_fap_command_sync(hidpp, feature_index, |
---|
| 1356 | + CMD_BATTERY_VOLTAGE_GET_BATTERY_VOLTAGE, |
---|
| 1357 | + NULL, 0, &response); |
---|
| 1358 | + |
---|
| 1359 | + if (ret > 0) { |
---|
| 1360 | + hid_err(hidpp->hid_dev, "%s: received protocol error 0x%02x\n", |
---|
| 1361 | + __func__, ret); |
---|
| 1362 | + return -EPROTO; |
---|
| 1363 | + } |
---|
| 1364 | + if (ret) |
---|
| 1365 | + return ret; |
---|
| 1366 | + |
---|
| 1367 | + hidpp->capabilities |= HIDPP_CAPABILITY_BATTERY_VOLTAGE; |
---|
| 1368 | + |
---|
| 1369 | + *status = hidpp20_battery_map_status_voltage(params, voltage, |
---|
| 1370 | + level, charge_type); |
---|
| 1371 | + |
---|
| 1372 | + return 0; |
---|
| 1373 | +} |
---|
| 1374 | + |
---|
| 1375 | +static int hidpp20_query_battery_voltage_info(struct hidpp_device *hidpp) |
---|
| 1376 | +{ |
---|
| 1377 | + u8 feature_type; |
---|
| 1378 | + int ret; |
---|
| 1379 | + int status, voltage, level, charge_type; |
---|
| 1380 | + |
---|
| 1381 | + if (hidpp->battery.voltage_feature_index == 0xff) { |
---|
| 1382 | + ret = hidpp_root_get_feature(hidpp, HIDPP_PAGE_BATTERY_VOLTAGE, |
---|
| 1383 | + &hidpp->battery.voltage_feature_index, |
---|
| 1384 | + &feature_type); |
---|
| 1385 | + if (ret) |
---|
| 1386 | + return ret; |
---|
| 1387 | + } |
---|
| 1388 | + |
---|
| 1389 | + ret = hidpp20_battery_get_battery_voltage(hidpp, |
---|
| 1390 | + hidpp->battery.voltage_feature_index, |
---|
| 1391 | + &status, &voltage, &level, &charge_type); |
---|
| 1392 | + |
---|
| 1393 | + if (ret) |
---|
| 1394 | + return ret; |
---|
| 1395 | + |
---|
| 1396 | + hidpp->battery.status = status; |
---|
| 1397 | + hidpp->battery.voltage = voltage; |
---|
| 1398 | + hidpp->battery.level = level; |
---|
| 1399 | + hidpp->battery.charge_type = charge_type; |
---|
| 1400 | + hidpp->battery.online = status != POWER_SUPPLY_STATUS_NOT_CHARGING; |
---|
| 1401 | + |
---|
| 1402 | + return 0; |
---|
| 1403 | +} |
---|
| 1404 | + |
---|
| 1405 | +static int hidpp20_battery_voltage_event(struct hidpp_device *hidpp, |
---|
| 1406 | + u8 *data, int size) |
---|
| 1407 | +{ |
---|
| 1408 | + struct hidpp_report *report = (struct hidpp_report *)data; |
---|
| 1409 | + int status, voltage, level, charge_type; |
---|
| 1410 | + |
---|
| 1411 | + if (report->fap.feature_index != hidpp->battery.voltage_feature_index || |
---|
| 1412 | + report->fap.funcindex_clientid != EVENT_BATTERY_VOLTAGE_STATUS_BROADCAST) |
---|
| 1413 | + return 0; |
---|
| 1414 | + |
---|
| 1415 | + status = hidpp20_battery_map_status_voltage(report->fap.params, &voltage, |
---|
| 1416 | + &level, &charge_type); |
---|
| 1417 | + |
---|
| 1418 | + hidpp->battery.online = status != POWER_SUPPLY_STATUS_NOT_CHARGING; |
---|
| 1419 | + |
---|
| 1420 | + if (voltage != hidpp->battery.voltage || status != hidpp->battery.status) { |
---|
| 1421 | + hidpp->battery.voltage = voltage; |
---|
| 1422 | + hidpp->battery.status = status; |
---|
| 1423 | + hidpp->battery.level = level; |
---|
| 1424 | + hidpp->battery.charge_type = charge_type; |
---|
| 1425 | + if (hidpp->battery.ps) |
---|
| 1426 | + power_supply_changed(hidpp->battery.ps); |
---|
| 1427 | + } |
---|
| 1428 | + return 0; |
---|
| 1429 | +} |
---|
| 1430 | + |
---|
1101 | 1431 | static enum power_supply_property hidpp_battery_props[] = { |
---|
1102 | 1432 | POWER_SUPPLY_PROP_ONLINE, |
---|
1103 | 1433 | POWER_SUPPLY_PROP_STATUS, |
---|
.. | .. |
---|
1107 | 1437 | POWER_SUPPLY_PROP_SERIAL_NUMBER, |
---|
1108 | 1438 | 0, /* placeholder for POWER_SUPPLY_PROP_CAPACITY, */ |
---|
1109 | 1439 | 0, /* placeholder for POWER_SUPPLY_PROP_CAPACITY_LEVEL, */ |
---|
| 1440 | + 0, /* placeholder for POWER_SUPPLY_PROP_VOLTAGE_NOW, */ |
---|
1110 | 1441 | }; |
---|
1111 | 1442 | |
---|
1112 | 1443 | static int hidpp_battery_get_property(struct power_supply *psy, |
---|
.. | .. |
---|
1144 | 1475 | case POWER_SUPPLY_PROP_SERIAL_NUMBER: |
---|
1145 | 1476 | val->strval = hidpp->hid_dev->uniq; |
---|
1146 | 1477 | break; |
---|
| 1478 | + case POWER_SUPPLY_PROP_VOLTAGE_NOW: |
---|
| 1479 | + /* hardware reports voltage in in mV. sysfs expects uV */ |
---|
| 1480 | + val->intval = hidpp->battery.voltage * 1000; |
---|
| 1481 | + break; |
---|
| 1482 | + case POWER_SUPPLY_PROP_CHARGE_TYPE: |
---|
| 1483 | + val->intval = hidpp->battery.charge_type; |
---|
| 1484 | + break; |
---|
1147 | 1485 | default: |
---|
1148 | 1486 | ret = -EINVAL; |
---|
1149 | 1487 | break; |
---|
1150 | 1488 | } |
---|
1151 | 1489 | |
---|
1152 | 1490 | return ret; |
---|
| 1491 | +} |
---|
| 1492 | + |
---|
| 1493 | +/* -------------------------------------------------------------------------- */ |
---|
| 1494 | +/* 0x1d4b: Wireless device status */ |
---|
| 1495 | +/* -------------------------------------------------------------------------- */ |
---|
| 1496 | +#define HIDPP_PAGE_WIRELESS_DEVICE_STATUS 0x1d4b |
---|
| 1497 | + |
---|
| 1498 | +static int hidpp_set_wireless_feature_index(struct hidpp_device *hidpp) |
---|
| 1499 | +{ |
---|
| 1500 | + u8 feature_type; |
---|
| 1501 | + int ret; |
---|
| 1502 | + |
---|
| 1503 | + ret = hidpp_root_get_feature(hidpp, |
---|
| 1504 | + HIDPP_PAGE_WIRELESS_DEVICE_STATUS, |
---|
| 1505 | + &hidpp->wireless_feature_index, |
---|
| 1506 | + &feature_type); |
---|
| 1507 | + |
---|
| 1508 | + return ret; |
---|
| 1509 | +} |
---|
| 1510 | + |
---|
| 1511 | +/* -------------------------------------------------------------------------- */ |
---|
| 1512 | +/* 0x2120: Hi-resolution scrolling */ |
---|
| 1513 | +/* -------------------------------------------------------------------------- */ |
---|
| 1514 | + |
---|
| 1515 | +#define HIDPP_PAGE_HI_RESOLUTION_SCROLLING 0x2120 |
---|
| 1516 | + |
---|
| 1517 | +#define CMD_HI_RESOLUTION_SCROLLING_SET_HIGHRES_SCROLLING_MODE 0x10 |
---|
| 1518 | + |
---|
| 1519 | +static int hidpp_hrs_set_highres_scrolling_mode(struct hidpp_device *hidpp, |
---|
| 1520 | + bool enabled, u8 *multiplier) |
---|
| 1521 | +{ |
---|
| 1522 | + u8 feature_index; |
---|
| 1523 | + u8 feature_type; |
---|
| 1524 | + int ret; |
---|
| 1525 | + u8 params[1]; |
---|
| 1526 | + struct hidpp_report response; |
---|
| 1527 | + |
---|
| 1528 | + ret = hidpp_root_get_feature(hidpp, |
---|
| 1529 | + HIDPP_PAGE_HI_RESOLUTION_SCROLLING, |
---|
| 1530 | + &feature_index, |
---|
| 1531 | + &feature_type); |
---|
| 1532 | + if (ret) |
---|
| 1533 | + return ret; |
---|
| 1534 | + |
---|
| 1535 | + params[0] = enabled ? BIT(0) : 0; |
---|
| 1536 | + ret = hidpp_send_fap_command_sync(hidpp, feature_index, |
---|
| 1537 | + CMD_HI_RESOLUTION_SCROLLING_SET_HIGHRES_SCROLLING_MODE, |
---|
| 1538 | + params, sizeof(params), &response); |
---|
| 1539 | + if (ret) |
---|
| 1540 | + return ret; |
---|
| 1541 | + *multiplier = response.fap.params[1]; |
---|
| 1542 | + return 0; |
---|
| 1543 | +} |
---|
| 1544 | + |
---|
| 1545 | +/* -------------------------------------------------------------------------- */ |
---|
| 1546 | +/* 0x2121: HiRes Wheel */ |
---|
| 1547 | +/* -------------------------------------------------------------------------- */ |
---|
| 1548 | + |
---|
| 1549 | +#define HIDPP_PAGE_HIRES_WHEEL 0x2121 |
---|
| 1550 | + |
---|
| 1551 | +#define CMD_HIRES_WHEEL_GET_WHEEL_CAPABILITY 0x00 |
---|
| 1552 | +#define CMD_HIRES_WHEEL_SET_WHEEL_MODE 0x20 |
---|
| 1553 | + |
---|
| 1554 | +static int hidpp_hrw_get_wheel_capability(struct hidpp_device *hidpp, |
---|
| 1555 | + u8 *multiplier) |
---|
| 1556 | +{ |
---|
| 1557 | + u8 feature_index; |
---|
| 1558 | + u8 feature_type; |
---|
| 1559 | + int ret; |
---|
| 1560 | + struct hidpp_report response; |
---|
| 1561 | + |
---|
| 1562 | + ret = hidpp_root_get_feature(hidpp, HIDPP_PAGE_HIRES_WHEEL, |
---|
| 1563 | + &feature_index, &feature_type); |
---|
| 1564 | + if (ret) |
---|
| 1565 | + goto return_default; |
---|
| 1566 | + |
---|
| 1567 | + ret = hidpp_send_fap_command_sync(hidpp, feature_index, |
---|
| 1568 | + CMD_HIRES_WHEEL_GET_WHEEL_CAPABILITY, |
---|
| 1569 | + NULL, 0, &response); |
---|
| 1570 | + if (ret) |
---|
| 1571 | + goto return_default; |
---|
| 1572 | + |
---|
| 1573 | + *multiplier = response.fap.params[0]; |
---|
| 1574 | + return 0; |
---|
| 1575 | +return_default: |
---|
| 1576 | + hid_warn(hidpp->hid_dev, |
---|
| 1577 | + "Couldn't get wheel multiplier (error %d)\n", ret); |
---|
| 1578 | + return ret; |
---|
| 1579 | +} |
---|
| 1580 | + |
---|
| 1581 | +static int hidpp_hrw_set_wheel_mode(struct hidpp_device *hidpp, bool invert, |
---|
| 1582 | + bool high_resolution, bool use_hidpp) |
---|
| 1583 | +{ |
---|
| 1584 | + u8 feature_index; |
---|
| 1585 | + u8 feature_type; |
---|
| 1586 | + int ret; |
---|
| 1587 | + u8 params[1]; |
---|
| 1588 | + struct hidpp_report response; |
---|
| 1589 | + |
---|
| 1590 | + ret = hidpp_root_get_feature(hidpp, HIDPP_PAGE_HIRES_WHEEL, |
---|
| 1591 | + &feature_index, &feature_type); |
---|
| 1592 | + if (ret) |
---|
| 1593 | + return ret; |
---|
| 1594 | + |
---|
| 1595 | + params[0] = (invert ? BIT(2) : 0) | |
---|
| 1596 | + (high_resolution ? BIT(1) : 0) | |
---|
| 1597 | + (use_hidpp ? BIT(0) : 0); |
---|
| 1598 | + |
---|
| 1599 | + return hidpp_send_fap_command_sync(hidpp, feature_index, |
---|
| 1600 | + CMD_HIRES_WHEEL_SET_WHEEL_MODE, |
---|
| 1601 | + params, sizeof(params), &response); |
---|
1153 | 1602 | } |
---|
1154 | 1603 | |
---|
1155 | 1604 | /* -------------------------------------------------------------------------- */ |
---|
.. | .. |
---|
1455 | 1904 | |
---|
1456 | 1905 | #define HIDPP_FF_EFFECTID_NONE -1 |
---|
1457 | 1906 | #define HIDPP_FF_EFFECTID_AUTOCENTER -2 |
---|
| 1907 | +#define HIDPP_AUTOCENTER_PARAMS_LENGTH 18 |
---|
1458 | 1908 | |
---|
1459 | 1909 | #define HIDPP_FF_MAX_PARAMS 20 |
---|
1460 | 1910 | #define HIDPP_FF_RESERVED_SLOTS 1 |
---|
.. | .. |
---|
1481 | 1931 | u8 size; |
---|
1482 | 1932 | }; |
---|
1483 | 1933 | |
---|
1484 | | -static const signed short hiddpp_ff_effects[] = { |
---|
| 1934 | +static const signed short hidpp_ff_effects[] = { |
---|
1485 | 1935 | FF_CONSTANT, |
---|
1486 | 1936 | FF_PERIODIC, |
---|
1487 | 1937 | FF_SINE, |
---|
.. | .. |
---|
1496 | 1946 | -1 |
---|
1497 | 1947 | }; |
---|
1498 | 1948 | |
---|
1499 | | -static const signed short hiddpp_ff_effects_v2[] = { |
---|
| 1949 | +static const signed short hidpp_ff_effects_v2[] = { |
---|
1500 | 1950 | FF_RAMP, |
---|
1501 | 1951 | FF_FRICTION, |
---|
1502 | 1952 | FF_INERTIA, |
---|
.. | .. |
---|
1795 | 2245 | static void hidpp_ff_set_autocenter(struct input_dev *dev, u16 magnitude) |
---|
1796 | 2246 | { |
---|
1797 | 2247 | struct hidpp_ff_private_data *data = dev->ff->private; |
---|
1798 | | - u8 params[18]; |
---|
| 2248 | + u8 params[HIDPP_AUTOCENTER_PARAMS_LENGTH]; |
---|
1799 | 2249 | |
---|
1800 | 2250 | dbg_hid("Setting autocenter to %d.\n", magnitude); |
---|
1801 | 2251 | |
---|
.. | .. |
---|
1863 | 2313 | static void hidpp_ff_destroy(struct ff_device *ff) |
---|
1864 | 2314 | { |
---|
1865 | 2315 | struct hidpp_ff_private_data *data = ff->private; |
---|
| 2316 | + struct hid_device *hid = data->hidpp->hid_dev; |
---|
1866 | 2317 | |
---|
| 2318 | + hid_info(hid, "Unloading HID++ force feedback.\n"); |
---|
| 2319 | + |
---|
| 2320 | + device_remove_file(&hid->dev, &dev_attr_range); |
---|
| 2321 | + destroy_workqueue(data->wq); |
---|
1867 | 2322 | kfree(data->effect_ids); |
---|
1868 | 2323 | } |
---|
1869 | 2324 | |
---|
1870 | | -static int hidpp_ff_init(struct hidpp_device *hidpp, u8 feature_index) |
---|
| 2325 | +static int hidpp_ff_init(struct hidpp_device *hidpp, |
---|
| 2326 | + struct hidpp_ff_private_data *data) |
---|
1871 | 2327 | { |
---|
1872 | 2328 | struct hid_device *hid = hidpp->hid_dev; |
---|
1873 | 2329 | struct hid_input *hidinput; |
---|
.. | .. |
---|
1875 | 2331 | const struct usb_device_descriptor *udesc = &(hid_to_usb_dev(hid)->descriptor); |
---|
1876 | 2332 | const u16 bcdDevice = le16_to_cpu(udesc->bcdDevice); |
---|
1877 | 2333 | struct ff_device *ff; |
---|
1878 | | - struct hidpp_report response; |
---|
1879 | | - struct hidpp_ff_private_data *data; |
---|
1880 | | - int error, j, num_slots; |
---|
| 2334 | + int error, j, num_slots = data->num_effects; |
---|
1881 | 2335 | u8 version; |
---|
1882 | 2336 | |
---|
1883 | 2337 | if (list_empty(&hid->inputs)) { |
---|
.. | .. |
---|
1896 | 2350 | version = bcdDevice & 255; |
---|
1897 | 2351 | |
---|
1898 | 2352 | /* Set supported force feedback capabilities */ |
---|
1899 | | - for (j = 0; hiddpp_ff_effects[j] >= 0; j++) |
---|
1900 | | - set_bit(hiddpp_ff_effects[j], dev->ffbit); |
---|
| 2353 | + for (j = 0; hidpp_ff_effects[j] >= 0; j++) |
---|
| 2354 | + set_bit(hidpp_ff_effects[j], dev->ffbit); |
---|
1901 | 2355 | if (version > 1) |
---|
1902 | | - for (j = 0; hiddpp_ff_effects_v2[j] >= 0; j++) |
---|
1903 | | - set_bit(hiddpp_ff_effects_v2[j], dev->ffbit); |
---|
1904 | | - |
---|
1905 | | - /* Read number of slots available in device */ |
---|
1906 | | - error = hidpp_send_fap_command_sync(hidpp, feature_index, |
---|
1907 | | - HIDPP_FF_GET_INFO, NULL, 0, &response); |
---|
1908 | | - if (error) { |
---|
1909 | | - if (error < 0) |
---|
1910 | | - return error; |
---|
1911 | | - hid_err(hidpp->hid_dev, "%s: received protocol error 0x%02x\n", |
---|
1912 | | - __func__, error); |
---|
1913 | | - return -EPROTO; |
---|
1914 | | - } |
---|
1915 | | - |
---|
1916 | | - num_slots = response.fap.params[0] - HIDPP_FF_RESERVED_SLOTS; |
---|
| 2356 | + for (j = 0; hidpp_ff_effects_v2[j] >= 0; j++) |
---|
| 2357 | + set_bit(hidpp_ff_effects_v2[j], dev->ffbit); |
---|
1917 | 2358 | |
---|
1918 | 2359 | error = input_ff_create(dev, num_slots); |
---|
1919 | 2360 | |
---|
.. | .. |
---|
1921 | 2362 | hid_err(dev, "Failed to create FF device!\n"); |
---|
1922 | 2363 | return error; |
---|
1923 | 2364 | } |
---|
1924 | | - |
---|
1925 | | - data = kzalloc(sizeof(*data), GFP_KERNEL); |
---|
| 2365 | + /* |
---|
| 2366 | + * Create a copy of passed data, so we can transfer memory |
---|
| 2367 | + * ownership to FF core |
---|
| 2368 | + */ |
---|
| 2369 | + data = kmemdup(data, sizeof(*data), GFP_KERNEL); |
---|
1926 | 2370 | if (!data) |
---|
1927 | 2371 | return -ENOMEM; |
---|
1928 | 2372 | data->effect_ids = kcalloc(num_slots, sizeof(int), GFP_KERNEL); |
---|
.. | .. |
---|
1938 | 2382 | } |
---|
1939 | 2383 | |
---|
1940 | 2384 | data->hidpp = hidpp; |
---|
1941 | | - data->feature_index = feature_index; |
---|
1942 | 2385 | data->version = version; |
---|
1943 | | - data->slot_autocenter = 0; |
---|
1944 | | - data->num_effects = num_slots; |
---|
1945 | 2386 | for (j = 0; j < num_slots; j++) |
---|
1946 | 2387 | data->effect_ids[j] = -1; |
---|
1947 | 2388 | |
---|
.. | .. |
---|
1955 | 2396 | ff->set_autocenter = hidpp_ff_set_autocenter; |
---|
1956 | 2397 | ff->destroy = hidpp_ff_destroy; |
---|
1957 | 2398 | |
---|
1958 | | - |
---|
1959 | | - /* reset all forces */ |
---|
1960 | | - error = hidpp_send_fap_command_sync(hidpp, feature_index, |
---|
1961 | | - HIDPP_FF_RESET_ALL, NULL, 0, &response); |
---|
1962 | | - |
---|
1963 | | - /* Read current Range */ |
---|
1964 | | - error = hidpp_send_fap_command_sync(hidpp, feature_index, |
---|
1965 | | - HIDPP_FF_GET_APERTURE, NULL, 0, &response); |
---|
1966 | | - if (error) |
---|
1967 | | - hid_warn(hidpp->hid_dev, "Failed to read range from device!\n"); |
---|
1968 | | - data->range = error ? 900 : get_unaligned_be16(&response.fap.params[0]); |
---|
1969 | | - |
---|
1970 | 2399 | /* Create sysfs interface */ |
---|
1971 | 2400 | error = device_create_file(&(hidpp->hid_dev->dev), &dev_attr_range); |
---|
1972 | 2401 | if (error) |
---|
1973 | 2402 | hid_warn(hidpp->hid_dev, "Unable to create sysfs interface for \"range\", errno %d!\n", error); |
---|
1974 | 2403 | |
---|
1975 | | - /* Read the current gain values */ |
---|
1976 | | - error = hidpp_send_fap_command_sync(hidpp, feature_index, |
---|
1977 | | - HIDPP_FF_GET_GLOBAL_GAINS, NULL, 0, &response); |
---|
1978 | | - if (error) |
---|
1979 | | - hid_warn(hidpp->hid_dev, "Failed to read gain values from device!\n"); |
---|
1980 | | - data->gain = error ? 0xffff : get_unaligned_be16(&response.fap.params[0]); |
---|
1981 | | - /* ignore boost value at response.fap.params[2] */ |
---|
1982 | | - |
---|
1983 | 2404 | /* init the hardware command queue */ |
---|
1984 | 2405 | atomic_set(&data->workqueue_size, 0); |
---|
1985 | | - |
---|
1986 | | - /* initialize with zero autocenter to get wheel in usable state */ |
---|
1987 | | - hidpp_ff_set_autocenter(dev, 0); |
---|
1988 | 2406 | |
---|
1989 | 2407 | hid_info(hid, "Force feedback support loaded (firmware release %d).\n", |
---|
1990 | 2408 | version); |
---|
1991 | 2409 | |
---|
1992 | 2410 | return 0; |
---|
1993 | 2411 | } |
---|
1994 | | - |
---|
1995 | | -static int hidpp_ff_deinit(struct hid_device *hid) |
---|
1996 | | -{ |
---|
1997 | | - struct hid_input *hidinput = list_entry(hid->inputs.next, struct hid_input, list); |
---|
1998 | | - struct input_dev *dev = hidinput->input; |
---|
1999 | | - struct hidpp_ff_private_data *data; |
---|
2000 | | - |
---|
2001 | | - if (!dev) { |
---|
2002 | | - hid_err(hid, "Struct input_dev not found!\n"); |
---|
2003 | | - return -EINVAL; |
---|
2004 | | - } |
---|
2005 | | - |
---|
2006 | | - hid_info(hid, "Unloading HID++ force feedback.\n"); |
---|
2007 | | - data = dev->ff->private; |
---|
2008 | | - if (!data) { |
---|
2009 | | - hid_err(hid, "Private data not found!\n"); |
---|
2010 | | - return -EINVAL; |
---|
2011 | | - } |
---|
2012 | | - |
---|
2013 | | - destroy_workqueue(data->wq); |
---|
2014 | | - device_remove_file(&hid->dev, &dev_attr_range); |
---|
2015 | | - |
---|
2016 | | - return 0; |
---|
2017 | | -} |
---|
2018 | | - |
---|
2019 | 2412 | |
---|
2020 | 2413 | /* ************************************************************************** */ |
---|
2021 | 2414 | /* */ |
---|
.. | .. |
---|
2030 | 2423 | #define WTP_MANUAL_RESOLUTION 39 |
---|
2031 | 2424 | |
---|
2032 | 2425 | struct wtp_data { |
---|
2033 | | - struct input_dev *input; |
---|
2034 | 2426 | u16 x_size, y_size; |
---|
2035 | 2427 | u8 finger_count; |
---|
2036 | 2428 | u8 mt_feature_index; |
---|
.. | .. |
---|
2048 | 2440 | } |
---|
2049 | 2441 | |
---|
2050 | 2442 | static void wtp_populate_input(struct hidpp_device *hidpp, |
---|
2051 | | - struct input_dev *input_dev, bool origin_is_hid_core) |
---|
| 2443 | + struct input_dev *input_dev) |
---|
2052 | 2444 | { |
---|
2053 | 2445 | struct wtp_data *wd = hidpp->private_data; |
---|
2054 | 2446 | |
---|
.. | .. |
---|
2074 | 2466 | |
---|
2075 | 2467 | input_mt_init_slots(input_dev, wd->maxcontacts, INPUT_MT_POINTER | |
---|
2076 | 2468 | INPUT_MT_DROP_UNUSED); |
---|
2077 | | - |
---|
2078 | | - wd->input = input_dev; |
---|
2079 | 2469 | } |
---|
2080 | 2470 | |
---|
2081 | | -static void wtp_touch_event(struct wtp_data *wd, |
---|
| 2471 | +static void wtp_touch_event(struct hidpp_device *hidpp, |
---|
2082 | 2472 | struct hidpp_touchpad_raw_xy_finger *touch_report) |
---|
2083 | 2473 | { |
---|
| 2474 | + struct wtp_data *wd = hidpp->private_data; |
---|
2084 | 2475 | int slot; |
---|
2085 | 2476 | |
---|
2086 | 2477 | if (!touch_report->finger_id || touch_report->contact_type) |
---|
2087 | 2478 | /* no actual data */ |
---|
2088 | 2479 | return; |
---|
2089 | 2480 | |
---|
2090 | | - slot = input_mt_get_slot_by_key(wd->input, touch_report->finger_id); |
---|
| 2481 | + slot = input_mt_get_slot_by_key(hidpp->input, touch_report->finger_id); |
---|
2091 | 2482 | |
---|
2092 | | - input_mt_slot(wd->input, slot); |
---|
2093 | | - input_mt_report_slot_state(wd->input, MT_TOOL_FINGER, |
---|
| 2483 | + input_mt_slot(hidpp->input, slot); |
---|
| 2484 | + input_mt_report_slot_state(hidpp->input, MT_TOOL_FINGER, |
---|
2094 | 2485 | touch_report->contact_status); |
---|
2095 | 2486 | if (touch_report->contact_status) { |
---|
2096 | | - input_event(wd->input, EV_ABS, ABS_MT_POSITION_X, |
---|
| 2487 | + input_event(hidpp->input, EV_ABS, ABS_MT_POSITION_X, |
---|
2097 | 2488 | touch_report->x); |
---|
2098 | | - input_event(wd->input, EV_ABS, ABS_MT_POSITION_Y, |
---|
| 2489 | + input_event(hidpp->input, EV_ABS, ABS_MT_POSITION_Y, |
---|
2099 | 2490 | wd->flip_y ? wd->y_size - touch_report->y : |
---|
2100 | 2491 | touch_report->y); |
---|
2101 | | - input_event(wd->input, EV_ABS, ABS_MT_PRESSURE, |
---|
| 2492 | + input_event(hidpp->input, EV_ABS, ABS_MT_PRESSURE, |
---|
2102 | 2493 | touch_report->area); |
---|
2103 | 2494 | } |
---|
2104 | 2495 | } |
---|
.. | .. |
---|
2106 | 2497 | static void wtp_send_raw_xy_event(struct hidpp_device *hidpp, |
---|
2107 | 2498 | struct hidpp_touchpad_raw_xy *raw) |
---|
2108 | 2499 | { |
---|
2109 | | - struct wtp_data *wd = hidpp->private_data; |
---|
2110 | 2500 | int i; |
---|
2111 | 2501 | |
---|
2112 | 2502 | for (i = 0; i < 2; i++) |
---|
2113 | | - wtp_touch_event(wd, &(raw->fingers[i])); |
---|
| 2503 | + wtp_touch_event(hidpp, &(raw->fingers[i])); |
---|
2114 | 2504 | |
---|
2115 | 2505 | if (raw->end_of_frame && |
---|
2116 | 2506 | !(hidpp->quirks & HIDPP_QUIRK_WTP_PHYSICAL_BUTTONS)) |
---|
2117 | | - input_event(wd->input, EV_KEY, BTN_LEFT, raw->button); |
---|
| 2507 | + input_event(hidpp->input, EV_KEY, BTN_LEFT, raw->button); |
---|
2118 | 2508 | |
---|
2119 | 2509 | if (raw->end_of_frame || raw->finger_count <= 2) { |
---|
2120 | | - input_mt_sync_frame(wd->input); |
---|
2121 | | - input_sync(wd->input); |
---|
| 2510 | + input_mt_sync_frame(hidpp->input); |
---|
| 2511 | + input_sync(hidpp->input); |
---|
2122 | 2512 | } |
---|
2123 | 2513 | } |
---|
2124 | 2514 | |
---|
.. | .. |
---|
2168 | 2558 | struct hidpp_report *report = (struct hidpp_report *)data; |
---|
2169 | 2559 | struct hidpp_touchpad_raw_xy raw; |
---|
2170 | 2560 | |
---|
2171 | | - if (!wd || !wd->input) |
---|
| 2561 | + if (!wd || !hidpp->input) |
---|
2172 | 2562 | return 1; |
---|
2173 | 2563 | |
---|
2174 | 2564 | switch (data[0]) { |
---|
.. | .. |
---|
2179 | 2569 | return 1; |
---|
2180 | 2570 | } |
---|
2181 | 2571 | if (hidpp->quirks & HIDPP_QUIRK_WTP_PHYSICAL_BUTTONS) { |
---|
2182 | | - input_event(wd->input, EV_KEY, BTN_LEFT, |
---|
| 2572 | + input_event(hidpp->input, EV_KEY, BTN_LEFT, |
---|
2183 | 2573 | !!(data[1] & 0x01)); |
---|
2184 | | - input_event(wd->input, EV_KEY, BTN_RIGHT, |
---|
| 2574 | + input_event(hidpp->input, EV_KEY, BTN_RIGHT, |
---|
2185 | 2575 | !!(data[1] & 0x02)); |
---|
2186 | | - input_sync(wd->input); |
---|
| 2576 | + input_sync(hidpp->input); |
---|
2187 | 2577 | return 0; |
---|
2188 | 2578 | } else { |
---|
2189 | 2579 | if (size < 21) |
---|
.. | .. |
---|
2301 | 2691 | |
---|
2302 | 2692 | static const u8 m560_config_parameter[] = {0x00, 0xaf, 0x03}; |
---|
2303 | 2693 | |
---|
2304 | | -struct m560_private_data { |
---|
2305 | | - struct input_dev *input; |
---|
2306 | | -}; |
---|
2307 | | - |
---|
2308 | 2694 | /* how buttons are mapped in the report */ |
---|
2309 | 2695 | #define M560_MOUSE_BTN_LEFT 0x01 |
---|
2310 | 2696 | #define M560_MOUSE_BTN_RIGHT 0x02 |
---|
.. | .. |
---|
2332 | 2718 | ); |
---|
2333 | 2719 | } |
---|
2334 | 2720 | |
---|
2335 | | -static int m560_allocate(struct hid_device *hdev) |
---|
2336 | | -{ |
---|
2337 | | - struct hidpp_device *hidpp = hid_get_drvdata(hdev); |
---|
2338 | | - struct m560_private_data *d; |
---|
2339 | | - |
---|
2340 | | - d = devm_kzalloc(&hdev->dev, sizeof(struct m560_private_data), |
---|
2341 | | - GFP_KERNEL); |
---|
2342 | | - if (!d) |
---|
2343 | | - return -ENOMEM; |
---|
2344 | | - |
---|
2345 | | - hidpp->private_data = d; |
---|
2346 | | - |
---|
2347 | | - return 0; |
---|
2348 | | -}; |
---|
2349 | | - |
---|
2350 | 2721 | static int m560_raw_event(struct hid_device *hdev, u8 *data, int size) |
---|
2351 | 2722 | { |
---|
2352 | 2723 | struct hidpp_device *hidpp = hid_get_drvdata(hdev); |
---|
2353 | | - struct m560_private_data *mydata = hidpp->private_data; |
---|
2354 | 2724 | |
---|
2355 | 2725 | /* sanity check */ |
---|
2356 | | - if (!mydata || !mydata->input) { |
---|
| 2726 | + if (!hidpp->input) { |
---|
2357 | 2727 | hid_err(hdev, "error in parameter\n"); |
---|
2358 | 2728 | return -EINVAL; |
---|
2359 | 2729 | } |
---|
.. | .. |
---|
2380 | 2750 | |
---|
2381 | 2751 | switch (data[5]) { |
---|
2382 | 2752 | case 0xaf: |
---|
2383 | | - input_report_key(mydata->input, BTN_MIDDLE, 1); |
---|
| 2753 | + input_report_key(hidpp->input, BTN_MIDDLE, 1); |
---|
2384 | 2754 | break; |
---|
2385 | 2755 | case 0xb0: |
---|
2386 | | - input_report_key(mydata->input, BTN_FORWARD, 1); |
---|
| 2756 | + input_report_key(hidpp->input, BTN_FORWARD, 1); |
---|
2387 | 2757 | break; |
---|
2388 | 2758 | case 0xae: |
---|
2389 | | - input_report_key(mydata->input, BTN_BACK, 1); |
---|
| 2759 | + input_report_key(hidpp->input, BTN_BACK, 1); |
---|
2390 | 2760 | break; |
---|
2391 | 2761 | case 0x00: |
---|
2392 | | - input_report_key(mydata->input, BTN_BACK, 0); |
---|
2393 | | - input_report_key(mydata->input, BTN_FORWARD, 0); |
---|
2394 | | - input_report_key(mydata->input, BTN_MIDDLE, 0); |
---|
| 2762 | + input_report_key(hidpp->input, BTN_BACK, 0); |
---|
| 2763 | + input_report_key(hidpp->input, BTN_FORWARD, 0); |
---|
| 2764 | + input_report_key(hidpp->input, BTN_MIDDLE, 0); |
---|
2395 | 2765 | break; |
---|
2396 | 2766 | default: |
---|
2397 | 2767 | hid_err(hdev, "error in report\n"); |
---|
2398 | 2768 | return 0; |
---|
2399 | 2769 | } |
---|
2400 | | - input_sync(mydata->input); |
---|
| 2770 | + input_sync(hidpp->input); |
---|
2401 | 2771 | |
---|
2402 | 2772 | } else if (data[0] == 0x02) { |
---|
2403 | 2773 | /* |
---|
.. | .. |
---|
2411 | 2781 | |
---|
2412 | 2782 | int v; |
---|
2413 | 2783 | |
---|
2414 | | - input_report_key(mydata->input, BTN_LEFT, |
---|
| 2784 | + input_report_key(hidpp->input, BTN_LEFT, |
---|
2415 | 2785 | !!(data[1] & M560_MOUSE_BTN_LEFT)); |
---|
2416 | | - input_report_key(mydata->input, BTN_RIGHT, |
---|
| 2786 | + input_report_key(hidpp->input, BTN_RIGHT, |
---|
2417 | 2787 | !!(data[1] & M560_MOUSE_BTN_RIGHT)); |
---|
2418 | 2788 | |
---|
2419 | | - if (data[1] & M560_MOUSE_BTN_WHEEL_LEFT) |
---|
2420 | | - input_report_rel(mydata->input, REL_HWHEEL, -1); |
---|
2421 | | - else if (data[1] & M560_MOUSE_BTN_WHEEL_RIGHT) |
---|
2422 | | - input_report_rel(mydata->input, REL_HWHEEL, 1); |
---|
| 2789 | + if (data[1] & M560_MOUSE_BTN_WHEEL_LEFT) { |
---|
| 2790 | + input_report_rel(hidpp->input, REL_HWHEEL, -1); |
---|
| 2791 | + input_report_rel(hidpp->input, REL_HWHEEL_HI_RES, |
---|
| 2792 | + -120); |
---|
| 2793 | + } else if (data[1] & M560_MOUSE_BTN_WHEEL_RIGHT) { |
---|
| 2794 | + input_report_rel(hidpp->input, REL_HWHEEL, 1); |
---|
| 2795 | + input_report_rel(hidpp->input, REL_HWHEEL_HI_RES, |
---|
| 2796 | + 120); |
---|
| 2797 | + } |
---|
2423 | 2798 | |
---|
2424 | 2799 | v = hid_snto32(hid_field_extract(hdev, data+3, 0, 12), 12); |
---|
2425 | | - input_report_rel(mydata->input, REL_X, v); |
---|
| 2800 | + input_report_rel(hidpp->input, REL_X, v); |
---|
2426 | 2801 | |
---|
2427 | 2802 | v = hid_snto32(hid_field_extract(hdev, data+3, 12, 12), 12); |
---|
2428 | | - input_report_rel(mydata->input, REL_Y, v); |
---|
| 2803 | + input_report_rel(hidpp->input, REL_Y, v); |
---|
2429 | 2804 | |
---|
2430 | 2805 | v = hid_snto32(data[6], 8); |
---|
2431 | | - input_report_rel(mydata->input, REL_WHEEL, v); |
---|
| 2806 | + if (v != 0) |
---|
| 2807 | + hidpp_scroll_counter_handle_scroll(hidpp->input, |
---|
| 2808 | + &hidpp->vertical_wheel_counter, v); |
---|
2432 | 2809 | |
---|
2433 | | - input_sync(mydata->input); |
---|
| 2810 | + input_sync(hidpp->input); |
---|
2434 | 2811 | } |
---|
2435 | 2812 | |
---|
2436 | 2813 | return 1; |
---|
2437 | 2814 | } |
---|
2438 | 2815 | |
---|
2439 | 2816 | static void m560_populate_input(struct hidpp_device *hidpp, |
---|
2440 | | - struct input_dev *input_dev, bool origin_is_hid_core) |
---|
| 2817 | + struct input_dev *input_dev) |
---|
2441 | 2818 | { |
---|
2442 | | - struct m560_private_data *mydata = hidpp->private_data; |
---|
| 2819 | + __set_bit(EV_KEY, input_dev->evbit); |
---|
| 2820 | + __set_bit(BTN_MIDDLE, input_dev->keybit); |
---|
| 2821 | + __set_bit(BTN_RIGHT, input_dev->keybit); |
---|
| 2822 | + __set_bit(BTN_LEFT, input_dev->keybit); |
---|
| 2823 | + __set_bit(BTN_BACK, input_dev->keybit); |
---|
| 2824 | + __set_bit(BTN_FORWARD, input_dev->keybit); |
---|
2443 | 2825 | |
---|
2444 | | - mydata->input = input_dev; |
---|
2445 | | - |
---|
2446 | | - __set_bit(EV_KEY, mydata->input->evbit); |
---|
2447 | | - __set_bit(BTN_MIDDLE, mydata->input->keybit); |
---|
2448 | | - __set_bit(BTN_RIGHT, mydata->input->keybit); |
---|
2449 | | - __set_bit(BTN_LEFT, mydata->input->keybit); |
---|
2450 | | - __set_bit(BTN_BACK, mydata->input->keybit); |
---|
2451 | | - __set_bit(BTN_FORWARD, mydata->input->keybit); |
---|
2452 | | - |
---|
2453 | | - __set_bit(EV_REL, mydata->input->evbit); |
---|
2454 | | - __set_bit(REL_X, mydata->input->relbit); |
---|
2455 | | - __set_bit(REL_Y, mydata->input->relbit); |
---|
2456 | | - __set_bit(REL_WHEEL, mydata->input->relbit); |
---|
2457 | | - __set_bit(REL_HWHEEL, mydata->input->relbit); |
---|
| 2826 | + __set_bit(EV_REL, input_dev->evbit); |
---|
| 2827 | + __set_bit(REL_X, input_dev->relbit); |
---|
| 2828 | + __set_bit(REL_Y, input_dev->relbit); |
---|
| 2829 | + __set_bit(REL_WHEEL, input_dev->relbit); |
---|
| 2830 | + __set_bit(REL_HWHEEL, input_dev->relbit); |
---|
| 2831 | + __set_bit(REL_WHEEL_HI_RES, input_dev->relbit); |
---|
| 2832 | + __set_bit(REL_HWHEEL_HI_RES, input_dev->relbit); |
---|
2458 | 2833 | } |
---|
2459 | 2834 | |
---|
2460 | 2835 | static int m560_input_mapping(struct hid_device *hdev, struct hid_input *hi, |
---|
.. | .. |
---|
2536 | 2911 | |
---|
2537 | 2912 | #define HIDPP_PAGE_G920_FORCE_FEEDBACK 0x8123 |
---|
2538 | 2913 | |
---|
2539 | | -static int g920_get_config(struct hidpp_device *hidpp) |
---|
| 2914 | +static int g920_ff_set_autocenter(struct hidpp_device *hidpp, |
---|
| 2915 | + struct hidpp_ff_private_data *data) |
---|
2540 | 2916 | { |
---|
2541 | | - u8 feature_type; |
---|
2542 | | - u8 feature_index; |
---|
| 2917 | + struct hidpp_report response; |
---|
| 2918 | + u8 params[HIDPP_AUTOCENTER_PARAMS_LENGTH] = { |
---|
| 2919 | + [1] = HIDPP_FF_EFFECT_SPRING | HIDPP_FF_EFFECT_AUTOSTART, |
---|
| 2920 | + }; |
---|
2543 | 2921 | int ret; |
---|
| 2922 | + |
---|
| 2923 | + /* initialize with zero autocenter to get wheel in usable state */ |
---|
| 2924 | + |
---|
| 2925 | + dbg_hid("Setting autocenter to 0.\n"); |
---|
| 2926 | + ret = hidpp_send_fap_command_sync(hidpp, data->feature_index, |
---|
| 2927 | + HIDPP_FF_DOWNLOAD_EFFECT, |
---|
| 2928 | + params, ARRAY_SIZE(params), |
---|
| 2929 | + &response); |
---|
| 2930 | + if (ret) |
---|
| 2931 | + hid_warn(hidpp->hid_dev, "Failed to autocenter device!\n"); |
---|
| 2932 | + else |
---|
| 2933 | + data->slot_autocenter = response.fap.params[0]; |
---|
| 2934 | + |
---|
| 2935 | + return ret; |
---|
| 2936 | +} |
---|
| 2937 | + |
---|
| 2938 | +static int g920_get_config(struct hidpp_device *hidpp, |
---|
| 2939 | + struct hidpp_ff_private_data *data) |
---|
| 2940 | +{ |
---|
| 2941 | + struct hidpp_report response; |
---|
| 2942 | + u8 feature_type; |
---|
| 2943 | + int ret; |
---|
| 2944 | + |
---|
| 2945 | + memset(data, 0, sizeof(*data)); |
---|
2544 | 2946 | |
---|
2545 | 2947 | /* Find feature and store for later use */ |
---|
2546 | 2948 | ret = hidpp_root_get_feature(hidpp, HIDPP_PAGE_G920_FORCE_FEEDBACK, |
---|
2547 | | - &feature_index, &feature_type); |
---|
| 2949 | + &data->feature_index, &feature_type); |
---|
2548 | 2950 | if (ret) |
---|
2549 | 2951 | return ret; |
---|
2550 | 2952 | |
---|
2551 | | - ret = hidpp_ff_init(hidpp, feature_index); |
---|
2552 | | - if (ret) |
---|
2553 | | - hid_warn(hidpp->hid_dev, "Unable to initialize force feedback support, errno %d\n", |
---|
2554 | | - ret); |
---|
| 2953 | + /* Read number of slots available in device */ |
---|
| 2954 | + ret = hidpp_send_fap_command_sync(hidpp, data->feature_index, |
---|
| 2955 | + HIDPP_FF_GET_INFO, |
---|
| 2956 | + NULL, 0, |
---|
| 2957 | + &response); |
---|
| 2958 | + if (ret) { |
---|
| 2959 | + if (ret < 0) |
---|
| 2960 | + return ret; |
---|
| 2961 | + hid_err(hidpp->hid_dev, |
---|
| 2962 | + "%s: received protocol error 0x%02x\n", __func__, ret); |
---|
| 2963 | + return -EPROTO; |
---|
| 2964 | + } |
---|
2555 | 2965 | |
---|
| 2966 | + data->num_effects = response.fap.params[0] - HIDPP_FF_RESERVED_SLOTS; |
---|
| 2967 | + |
---|
| 2968 | + /* reset all forces */ |
---|
| 2969 | + ret = hidpp_send_fap_command_sync(hidpp, data->feature_index, |
---|
| 2970 | + HIDPP_FF_RESET_ALL, |
---|
| 2971 | + NULL, 0, |
---|
| 2972 | + &response); |
---|
| 2973 | + if (ret) |
---|
| 2974 | + hid_warn(hidpp->hid_dev, "Failed to reset all forces!\n"); |
---|
| 2975 | + |
---|
| 2976 | + ret = hidpp_send_fap_command_sync(hidpp, data->feature_index, |
---|
| 2977 | + HIDPP_FF_GET_APERTURE, |
---|
| 2978 | + NULL, 0, |
---|
| 2979 | + &response); |
---|
| 2980 | + if (ret) { |
---|
| 2981 | + hid_warn(hidpp->hid_dev, |
---|
| 2982 | + "Failed to read range from device!\n"); |
---|
| 2983 | + } |
---|
| 2984 | + data->range = ret ? |
---|
| 2985 | + 900 : get_unaligned_be16(&response.fap.params[0]); |
---|
| 2986 | + |
---|
| 2987 | + /* Read the current gain values */ |
---|
| 2988 | + ret = hidpp_send_fap_command_sync(hidpp, data->feature_index, |
---|
| 2989 | + HIDPP_FF_GET_GLOBAL_GAINS, |
---|
| 2990 | + NULL, 0, |
---|
| 2991 | + &response); |
---|
| 2992 | + if (ret) |
---|
| 2993 | + hid_warn(hidpp->hid_dev, |
---|
| 2994 | + "Failed to read gain values from device!\n"); |
---|
| 2995 | + data->gain = ret ? |
---|
| 2996 | + 0xffff : get_unaligned_be16(&response.fap.params[0]); |
---|
| 2997 | + |
---|
| 2998 | + /* ignore boost value at response.fap.params[2] */ |
---|
| 2999 | + |
---|
| 3000 | + return g920_ff_set_autocenter(hidpp, data); |
---|
| 3001 | +} |
---|
| 3002 | + |
---|
| 3003 | +/* -------------------------------------------------------------------------- */ |
---|
| 3004 | +/* Logitech Dinovo Mini keyboard with builtin touchpad */ |
---|
| 3005 | +/* -------------------------------------------------------------------------- */ |
---|
| 3006 | +#define DINOVO_MINI_PRODUCT_ID 0xb30c |
---|
| 3007 | + |
---|
| 3008 | +static int lg_dinovo_input_mapping(struct hid_device *hdev, struct hid_input *hi, |
---|
| 3009 | + struct hid_field *field, struct hid_usage *usage, |
---|
| 3010 | + unsigned long **bit, int *max) |
---|
| 3011 | +{ |
---|
| 3012 | + if ((usage->hid & HID_USAGE_PAGE) != HID_UP_LOGIVENDOR) |
---|
| 3013 | + return 0; |
---|
| 3014 | + |
---|
| 3015 | + switch (usage->hid & HID_USAGE) { |
---|
| 3016 | + case 0x00d: lg_map_key_clear(KEY_MEDIA); break; |
---|
| 3017 | + default: |
---|
| 3018 | + return 0; |
---|
| 3019 | + } |
---|
| 3020 | + return 1; |
---|
| 3021 | +} |
---|
| 3022 | + |
---|
| 3023 | +/* -------------------------------------------------------------------------- */ |
---|
| 3024 | +/* HID++1.0 devices which use HID++ reports for their wheels */ |
---|
| 3025 | +/* -------------------------------------------------------------------------- */ |
---|
| 3026 | +static int hidpp10_wheel_connect(struct hidpp_device *hidpp) |
---|
| 3027 | +{ |
---|
| 3028 | + return hidpp10_set_register(hidpp, HIDPP_REG_ENABLE_REPORTS, 0, |
---|
| 3029 | + HIDPP_ENABLE_WHEEL_REPORT | HIDPP_ENABLE_HWHEEL_REPORT, |
---|
| 3030 | + HIDPP_ENABLE_WHEEL_REPORT | HIDPP_ENABLE_HWHEEL_REPORT); |
---|
| 3031 | +} |
---|
| 3032 | + |
---|
| 3033 | +static int hidpp10_wheel_raw_event(struct hidpp_device *hidpp, |
---|
| 3034 | + u8 *data, int size) |
---|
| 3035 | +{ |
---|
| 3036 | + s8 value, hvalue; |
---|
| 3037 | + |
---|
| 3038 | + if (!hidpp->input) |
---|
| 3039 | + return -EINVAL; |
---|
| 3040 | + |
---|
| 3041 | + if (size < 7) |
---|
| 3042 | + return 0; |
---|
| 3043 | + |
---|
| 3044 | + if (data[0] != REPORT_ID_HIDPP_SHORT || data[2] != HIDPP_SUB_ID_ROLLER) |
---|
| 3045 | + return 0; |
---|
| 3046 | + |
---|
| 3047 | + value = data[3]; |
---|
| 3048 | + hvalue = data[4]; |
---|
| 3049 | + |
---|
| 3050 | + input_report_rel(hidpp->input, REL_WHEEL, value); |
---|
| 3051 | + input_report_rel(hidpp->input, REL_WHEEL_HI_RES, value * 120); |
---|
| 3052 | + input_report_rel(hidpp->input, REL_HWHEEL, hvalue); |
---|
| 3053 | + input_report_rel(hidpp->input, REL_HWHEEL_HI_RES, hvalue * 120); |
---|
| 3054 | + input_sync(hidpp->input); |
---|
| 3055 | + |
---|
| 3056 | + return 1; |
---|
| 3057 | +} |
---|
| 3058 | + |
---|
| 3059 | +static void hidpp10_wheel_populate_input(struct hidpp_device *hidpp, |
---|
| 3060 | + struct input_dev *input_dev) |
---|
| 3061 | +{ |
---|
| 3062 | + __set_bit(EV_REL, input_dev->evbit); |
---|
| 3063 | + __set_bit(REL_WHEEL, input_dev->relbit); |
---|
| 3064 | + __set_bit(REL_WHEEL_HI_RES, input_dev->relbit); |
---|
| 3065 | + __set_bit(REL_HWHEEL, input_dev->relbit); |
---|
| 3066 | + __set_bit(REL_HWHEEL_HI_RES, input_dev->relbit); |
---|
| 3067 | +} |
---|
| 3068 | + |
---|
| 3069 | +/* -------------------------------------------------------------------------- */ |
---|
| 3070 | +/* HID++1.0 mice which use HID++ reports for extra mouse buttons */ |
---|
| 3071 | +/* -------------------------------------------------------------------------- */ |
---|
| 3072 | +static int hidpp10_extra_mouse_buttons_connect(struct hidpp_device *hidpp) |
---|
| 3073 | +{ |
---|
| 3074 | + return hidpp10_set_register(hidpp, HIDPP_REG_ENABLE_REPORTS, 0, |
---|
| 3075 | + HIDPP_ENABLE_MOUSE_EXTRA_BTN_REPORT, |
---|
| 3076 | + HIDPP_ENABLE_MOUSE_EXTRA_BTN_REPORT); |
---|
| 3077 | +} |
---|
| 3078 | + |
---|
| 3079 | +static int hidpp10_extra_mouse_buttons_raw_event(struct hidpp_device *hidpp, |
---|
| 3080 | + u8 *data, int size) |
---|
| 3081 | +{ |
---|
| 3082 | + int i; |
---|
| 3083 | + |
---|
| 3084 | + if (!hidpp->input) |
---|
| 3085 | + return -EINVAL; |
---|
| 3086 | + |
---|
| 3087 | + if (size < 7) |
---|
| 3088 | + return 0; |
---|
| 3089 | + |
---|
| 3090 | + if (data[0] != REPORT_ID_HIDPP_SHORT || |
---|
| 3091 | + data[2] != HIDPP_SUB_ID_MOUSE_EXTRA_BTNS) |
---|
| 3092 | + return 0; |
---|
| 3093 | + |
---|
| 3094 | + /* |
---|
| 3095 | + * Buttons are either delivered through the regular mouse report *or* |
---|
| 3096 | + * through the extra buttons report. At least for button 6 how it is |
---|
| 3097 | + * delivered differs per receiver firmware version. Even receivers with |
---|
| 3098 | + * the same usb-id show different behavior, so we handle both cases. |
---|
| 3099 | + */ |
---|
| 3100 | + for (i = 0; i < 8; i++) |
---|
| 3101 | + input_report_key(hidpp->input, BTN_MOUSE + i, |
---|
| 3102 | + (data[3] & (1 << i))); |
---|
| 3103 | + |
---|
| 3104 | + /* Some mice report events on button 9+, use BTN_MISC */ |
---|
| 3105 | + for (i = 0; i < 8; i++) |
---|
| 3106 | + input_report_key(hidpp->input, BTN_MISC + i, |
---|
| 3107 | + (data[4] & (1 << i))); |
---|
| 3108 | + |
---|
| 3109 | + input_sync(hidpp->input); |
---|
| 3110 | + return 1; |
---|
| 3111 | +} |
---|
| 3112 | + |
---|
| 3113 | +static void hidpp10_extra_mouse_buttons_populate_input( |
---|
| 3114 | + struct hidpp_device *hidpp, struct input_dev *input_dev) |
---|
| 3115 | +{ |
---|
| 3116 | + /* BTN_MOUSE - BTN_MOUSE+7 are set already by the descriptor */ |
---|
| 3117 | + __set_bit(BTN_0, input_dev->keybit); |
---|
| 3118 | + __set_bit(BTN_1, input_dev->keybit); |
---|
| 3119 | + __set_bit(BTN_2, input_dev->keybit); |
---|
| 3120 | + __set_bit(BTN_3, input_dev->keybit); |
---|
| 3121 | + __set_bit(BTN_4, input_dev->keybit); |
---|
| 3122 | + __set_bit(BTN_5, input_dev->keybit); |
---|
| 3123 | + __set_bit(BTN_6, input_dev->keybit); |
---|
| 3124 | + __set_bit(BTN_7, input_dev->keybit); |
---|
| 3125 | +} |
---|
| 3126 | + |
---|
| 3127 | +/* -------------------------------------------------------------------------- */ |
---|
| 3128 | +/* HID++1.0 kbds which only report 0x10xx consumer usages through sub-id 0x03 */ |
---|
| 3129 | +/* -------------------------------------------------------------------------- */ |
---|
| 3130 | + |
---|
| 3131 | +/* Find the consumer-page input report desc and change Maximums to 0x107f */ |
---|
| 3132 | +static u8 *hidpp10_consumer_keys_report_fixup(struct hidpp_device *hidpp, |
---|
| 3133 | + u8 *_rdesc, unsigned int *rsize) |
---|
| 3134 | +{ |
---|
| 3135 | + /* Note 0 terminated so we can use strnstr to search for this. */ |
---|
| 3136 | + static const char consumer_rdesc_start[] = { |
---|
| 3137 | + 0x05, 0x0C, /* USAGE_PAGE (Consumer Devices) */ |
---|
| 3138 | + 0x09, 0x01, /* USAGE (Consumer Control) */ |
---|
| 3139 | + 0xA1, 0x01, /* COLLECTION (Application) */ |
---|
| 3140 | + 0x85, 0x03, /* REPORT_ID = 3 */ |
---|
| 3141 | + 0x75, 0x10, /* REPORT_SIZE (16) */ |
---|
| 3142 | + 0x95, 0x02, /* REPORT_COUNT (2) */ |
---|
| 3143 | + 0x15, 0x01, /* LOGICAL_MIN (1) */ |
---|
| 3144 | + 0x26, 0x00 /* LOGICAL_MAX (... */ |
---|
| 3145 | + }; |
---|
| 3146 | + char *consumer_rdesc, *rdesc = (char *)_rdesc; |
---|
| 3147 | + unsigned int size; |
---|
| 3148 | + |
---|
| 3149 | + consumer_rdesc = strnstr(rdesc, consumer_rdesc_start, *rsize); |
---|
| 3150 | + size = *rsize - (consumer_rdesc - rdesc); |
---|
| 3151 | + if (consumer_rdesc && size >= 25) { |
---|
| 3152 | + consumer_rdesc[15] = 0x7f; |
---|
| 3153 | + consumer_rdesc[16] = 0x10; |
---|
| 3154 | + consumer_rdesc[20] = 0x7f; |
---|
| 3155 | + consumer_rdesc[21] = 0x10; |
---|
| 3156 | + } |
---|
| 3157 | + return _rdesc; |
---|
| 3158 | +} |
---|
| 3159 | + |
---|
| 3160 | +static int hidpp10_consumer_keys_connect(struct hidpp_device *hidpp) |
---|
| 3161 | +{ |
---|
| 3162 | + return hidpp10_set_register(hidpp, HIDPP_REG_ENABLE_REPORTS, 0, |
---|
| 3163 | + HIDPP_ENABLE_CONSUMER_REPORT, |
---|
| 3164 | + HIDPP_ENABLE_CONSUMER_REPORT); |
---|
| 3165 | +} |
---|
| 3166 | + |
---|
| 3167 | +static int hidpp10_consumer_keys_raw_event(struct hidpp_device *hidpp, |
---|
| 3168 | + u8 *data, int size) |
---|
| 3169 | +{ |
---|
| 3170 | + u8 consumer_report[5]; |
---|
| 3171 | + |
---|
| 3172 | + if (size < 7) |
---|
| 3173 | + return 0; |
---|
| 3174 | + |
---|
| 3175 | + if (data[0] != REPORT_ID_HIDPP_SHORT || |
---|
| 3176 | + data[2] != HIDPP_SUB_ID_CONSUMER_VENDOR_KEYS) |
---|
| 3177 | + return 0; |
---|
| 3178 | + |
---|
| 3179 | + /* |
---|
| 3180 | + * Build a normal consumer report (3) out of the data, this detour |
---|
| 3181 | + * is necessary to get some keyboards to report their 0x10xx usages. |
---|
| 3182 | + */ |
---|
| 3183 | + consumer_report[0] = 0x03; |
---|
| 3184 | + memcpy(&consumer_report[1], &data[3], 4); |
---|
| 3185 | + /* We are called from atomic context */ |
---|
| 3186 | + hid_report_raw_event(hidpp->hid_dev, HID_INPUT_REPORT, |
---|
| 3187 | + consumer_report, 5, 1); |
---|
| 3188 | + |
---|
| 3189 | + return 1; |
---|
| 3190 | +} |
---|
| 3191 | + |
---|
| 3192 | +/* -------------------------------------------------------------------------- */ |
---|
| 3193 | +/* High-resolution scroll wheels */ |
---|
| 3194 | +/* -------------------------------------------------------------------------- */ |
---|
| 3195 | + |
---|
| 3196 | +static int hi_res_scroll_enable(struct hidpp_device *hidpp) |
---|
| 3197 | +{ |
---|
| 3198 | + int ret; |
---|
| 3199 | + u8 multiplier = 1; |
---|
| 3200 | + |
---|
| 3201 | + if (hidpp->quirks & HIDPP_QUIRK_HI_RES_SCROLL_X2121) { |
---|
| 3202 | + ret = hidpp_hrw_set_wheel_mode(hidpp, false, true, false); |
---|
| 3203 | + if (ret == 0) |
---|
| 3204 | + ret = hidpp_hrw_get_wheel_capability(hidpp, &multiplier); |
---|
| 3205 | + } else if (hidpp->quirks & HIDPP_QUIRK_HI_RES_SCROLL_X2120) { |
---|
| 3206 | + ret = hidpp_hrs_set_highres_scrolling_mode(hidpp, true, |
---|
| 3207 | + &multiplier); |
---|
| 3208 | + } else /* if (hidpp->quirks & HIDPP_QUIRK_HI_RES_SCROLL_1P0) */ { |
---|
| 3209 | + ret = hidpp10_enable_scrolling_acceleration(hidpp); |
---|
| 3210 | + multiplier = 8; |
---|
| 3211 | + } |
---|
| 3212 | + if (ret) |
---|
| 3213 | + return ret; |
---|
| 3214 | + |
---|
| 3215 | + if (multiplier == 0) |
---|
| 3216 | + multiplier = 1; |
---|
| 3217 | + |
---|
| 3218 | + hidpp->vertical_wheel_counter.wheel_multiplier = multiplier; |
---|
| 3219 | + hid_dbg(hidpp->hid_dev, "wheel multiplier = %d\n", multiplier); |
---|
2556 | 3220 | return 0; |
---|
2557 | 3221 | } |
---|
2558 | 3222 | |
---|
.. | .. |
---|
2560 | 3224 | /* Generic HID++ devices */ |
---|
2561 | 3225 | /* -------------------------------------------------------------------------- */ |
---|
2562 | 3226 | |
---|
| 3227 | +static u8 *hidpp_report_fixup(struct hid_device *hdev, u8 *rdesc, |
---|
| 3228 | + unsigned int *rsize) |
---|
| 3229 | +{ |
---|
| 3230 | + struct hidpp_device *hidpp = hid_get_drvdata(hdev); |
---|
| 3231 | + |
---|
| 3232 | + if (!hidpp) |
---|
| 3233 | + return rdesc; |
---|
| 3234 | + |
---|
| 3235 | + /* For 27 MHz keyboards the quirk gets set after hid_parse. */ |
---|
| 3236 | + if (hdev->group == HID_GROUP_LOGITECH_27MHZ_DEVICE || |
---|
| 3237 | + (hidpp->quirks & HIDPP_QUIRK_HIDPP_CONSUMER_VENDOR_KEYS)) |
---|
| 3238 | + rdesc = hidpp10_consumer_keys_report_fixup(hidpp, rdesc, rsize); |
---|
| 3239 | + |
---|
| 3240 | + return rdesc; |
---|
| 3241 | +} |
---|
| 3242 | + |
---|
2563 | 3243 | static int hidpp_input_mapping(struct hid_device *hdev, struct hid_input *hi, |
---|
2564 | 3244 | struct hid_field *field, struct hid_usage *usage, |
---|
2565 | 3245 | unsigned long **bit, int *max) |
---|
2566 | 3246 | { |
---|
2567 | 3247 | struct hidpp_device *hidpp = hid_get_drvdata(hdev); |
---|
2568 | 3248 | |
---|
| 3249 | + if (!hidpp) |
---|
| 3250 | + return 0; |
---|
| 3251 | + |
---|
2569 | 3252 | if (hidpp->quirks & HIDPP_QUIRK_CLASS_WTP) |
---|
2570 | 3253 | return wtp_input_mapping(hdev, hi, field, usage, bit, max); |
---|
2571 | 3254 | else if (hidpp->quirks & HIDPP_QUIRK_CLASS_M560 && |
---|
2572 | 3255 | field->application != HID_GD_MOUSE) |
---|
2573 | 3256 | return m560_input_mapping(hdev, hi, field, usage, bit, max); |
---|
| 3257 | + |
---|
| 3258 | + if (hdev->product == DINOVO_MINI_PRODUCT_ID) |
---|
| 3259 | + return lg_dinovo_input_mapping(hdev, hi, field, usage, bit, max); |
---|
2574 | 3260 | |
---|
2575 | 3261 | return 0; |
---|
2576 | 3262 | } |
---|
.. | .. |
---|
2580 | 3266 | unsigned long **bit, int *max) |
---|
2581 | 3267 | { |
---|
2582 | 3268 | struct hidpp_device *hidpp = hid_get_drvdata(hdev); |
---|
| 3269 | + |
---|
| 3270 | + if (!hidpp) |
---|
| 3271 | + return 0; |
---|
2583 | 3272 | |
---|
2584 | 3273 | /* Ensure that Logitech G920 is not given a default fuzz/flat value */ |
---|
2585 | 3274 | if (hidpp->quirks & HIDPP_QUIRK_CLASS_G920) { |
---|
.. | .. |
---|
2595 | 3284 | |
---|
2596 | 3285 | |
---|
2597 | 3286 | static void hidpp_populate_input(struct hidpp_device *hidpp, |
---|
2598 | | - struct input_dev *input, bool origin_is_hid_core) |
---|
| 3287 | + struct input_dev *input) |
---|
2599 | 3288 | { |
---|
| 3289 | + hidpp->input = input; |
---|
| 3290 | + |
---|
2600 | 3291 | if (hidpp->quirks & HIDPP_QUIRK_CLASS_WTP) |
---|
2601 | | - wtp_populate_input(hidpp, input, origin_is_hid_core); |
---|
| 3292 | + wtp_populate_input(hidpp, input); |
---|
2602 | 3293 | else if (hidpp->quirks & HIDPP_QUIRK_CLASS_M560) |
---|
2603 | | - m560_populate_input(hidpp, input, origin_is_hid_core); |
---|
| 3294 | + m560_populate_input(hidpp, input); |
---|
| 3295 | + |
---|
| 3296 | + if (hidpp->quirks & HIDPP_QUIRK_HIDPP_WHEELS) |
---|
| 3297 | + hidpp10_wheel_populate_input(hidpp, input); |
---|
| 3298 | + |
---|
| 3299 | + if (hidpp->quirks & HIDPP_QUIRK_HIDPP_EXTRA_MOUSE_BTNS) |
---|
| 3300 | + hidpp10_extra_mouse_buttons_populate_input(hidpp, input); |
---|
2604 | 3301 | } |
---|
2605 | 3302 | |
---|
2606 | 3303 | static int hidpp_input_configured(struct hid_device *hdev, |
---|
.. | .. |
---|
2609 | 3306 | struct hidpp_device *hidpp = hid_get_drvdata(hdev); |
---|
2610 | 3307 | struct input_dev *input = hidinput->input; |
---|
2611 | 3308 | |
---|
2612 | | - hidpp_populate_input(hidpp, input, true); |
---|
| 3309 | + if (!hidpp) |
---|
| 3310 | + return 0; |
---|
| 3311 | + |
---|
| 3312 | + hidpp_populate_input(hidpp, input); |
---|
2613 | 3313 | |
---|
2614 | 3314 | return 0; |
---|
2615 | 3315 | } |
---|
.. | .. |
---|
2646 | 3346 | } |
---|
2647 | 3347 | } |
---|
2648 | 3348 | |
---|
2649 | | - if (unlikely(hidpp_report_is_connect_event(report))) { |
---|
| 3349 | + if (unlikely(hidpp_report_is_connect_event(hidpp, report))) { |
---|
2650 | 3350 | atomic_set(&hidpp->connected, |
---|
2651 | 3351 | !(report->rap.params[0] & (1 << 6))); |
---|
2652 | 3352 | if (schedule_work(&hidpp->work) == 0) |
---|
.. | .. |
---|
2661 | 3361 | ret = hidpp_solar_battery_event(hidpp, data, size); |
---|
2662 | 3362 | if (ret != 0) |
---|
2663 | 3363 | return ret; |
---|
| 3364 | + ret = hidpp20_battery_voltage_event(hidpp, data, size); |
---|
| 3365 | + if (ret != 0) |
---|
| 3366 | + return ret; |
---|
2664 | 3367 | } |
---|
2665 | 3368 | |
---|
2666 | 3369 | if (hidpp->capabilities & HIDPP_CAPABILITY_HIDPP10_BATTERY) { |
---|
2667 | 3370 | ret = hidpp10_battery_event(hidpp, data, size); |
---|
| 3371 | + if (ret != 0) |
---|
| 3372 | + return ret; |
---|
| 3373 | + } |
---|
| 3374 | + |
---|
| 3375 | + if (hidpp->quirks & HIDPP_QUIRK_HIDPP_WHEELS) { |
---|
| 3376 | + ret = hidpp10_wheel_raw_event(hidpp, data, size); |
---|
| 3377 | + if (ret != 0) |
---|
| 3378 | + return ret; |
---|
| 3379 | + } |
---|
| 3380 | + |
---|
| 3381 | + if (hidpp->quirks & HIDPP_QUIRK_HIDPP_EXTRA_MOUSE_BTNS) { |
---|
| 3382 | + ret = hidpp10_extra_mouse_buttons_raw_event(hidpp, data, size); |
---|
| 3383 | + if (ret != 0) |
---|
| 3384 | + return ret; |
---|
| 3385 | + } |
---|
| 3386 | + |
---|
| 3387 | + if (hidpp->quirks & HIDPP_QUIRK_HIDPP_CONSUMER_VENDOR_KEYS) { |
---|
| 3388 | + ret = hidpp10_consumer_keys_raw_event(hidpp, data, size); |
---|
2668 | 3389 | if (ret != 0) |
---|
2669 | 3390 | return ret; |
---|
2670 | 3391 | } |
---|
.. | .. |
---|
2678 | 3399 | struct hidpp_device *hidpp = hid_get_drvdata(hdev); |
---|
2679 | 3400 | int ret = 0; |
---|
2680 | 3401 | |
---|
| 3402 | + if (!hidpp) |
---|
| 3403 | + return 0; |
---|
| 3404 | + |
---|
2681 | 3405 | /* Generic HID++ processing. */ |
---|
2682 | 3406 | switch (data[0]) { |
---|
2683 | 3407 | case REPORT_ID_HIDPP_VERY_LONG: |
---|
2684 | | - if (size != HIDPP_REPORT_VERY_LONG_LENGTH) { |
---|
| 3408 | + if (size != hidpp->very_long_report_length) { |
---|
2685 | 3409 | hid_err(hdev, "received hid++ report of bad size (%d)", |
---|
2686 | 3410 | size); |
---|
2687 | 3411 | return 1; |
---|
.. | .. |
---|
2719 | 3443 | return 0; |
---|
2720 | 3444 | } |
---|
2721 | 3445 | |
---|
| 3446 | +static int hidpp_event(struct hid_device *hdev, struct hid_field *field, |
---|
| 3447 | + struct hid_usage *usage, __s32 value) |
---|
| 3448 | +{ |
---|
| 3449 | + /* This function will only be called for scroll events, due to the |
---|
| 3450 | + * restriction imposed in hidpp_usages. |
---|
| 3451 | + */ |
---|
| 3452 | + struct hidpp_device *hidpp = hid_get_drvdata(hdev); |
---|
| 3453 | + struct hidpp_scroll_counter *counter; |
---|
| 3454 | + |
---|
| 3455 | + if (!hidpp) |
---|
| 3456 | + return 0; |
---|
| 3457 | + |
---|
| 3458 | + counter = &hidpp->vertical_wheel_counter; |
---|
| 3459 | + /* A scroll event may occur before the multiplier has been retrieved or |
---|
| 3460 | + * the input device set, or high-res scroll enabling may fail. In such |
---|
| 3461 | + * cases we must return early (falling back to default behaviour) to |
---|
| 3462 | + * avoid a crash in hidpp_scroll_counter_handle_scroll. |
---|
| 3463 | + */ |
---|
| 3464 | + if (!(hidpp->quirks & HIDPP_QUIRK_HI_RES_SCROLL) || value == 0 |
---|
| 3465 | + || hidpp->input == NULL || counter->wheel_multiplier == 0) |
---|
| 3466 | + return 0; |
---|
| 3467 | + |
---|
| 3468 | + hidpp_scroll_counter_handle_scroll(hidpp->input, counter, value); |
---|
| 3469 | + return 1; |
---|
| 3470 | +} |
---|
| 3471 | + |
---|
2722 | 3472 | static int hidpp_initialize_battery(struct hidpp_device *hidpp) |
---|
2723 | 3473 | { |
---|
2724 | 3474 | static atomic_t battery_no = ATOMIC_INIT(0); |
---|
.. | .. |
---|
2735 | 3485 | |
---|
2736 | 3486 | hidpp->battery.feature_index = 0xff; |
---|
2737 | 3487 | hidpp->battery.solar_feature_index = 0xff; |
---|
| 3488 | + hidpp->battery.voltage_feature_index = 0xff; |
---|
2738 | 3489 | |
---|
2739 | 3490 | if (hidpp->protocol_major >= 2) { |
---|
2740 | 3491 | if (hidpp->quirks & HIDPP_QUIRK_CLASS_K750) |
---|
2741 | 3492 | ret = hidpp_solar_request_battery_event(hidpp); |
---|
2742 | | - else |
---|
2743 | | - ret = hidpp20_query_battery_info(hidpp); |
---|
| 3493 | + else { |
---|
| 3494 | + ret = hidpp20_query_battery_voltage_info(hidpp); |
---|
| 3495 | + if (ret) |
---|
| 3496 | + ret = hidpp20_query_battery_info(hidpp); |
---|
| 3497 | + } |
---|
2744 | 3498 | |
---|
2745 | 3499 | if (ret) |
---|
2746 | 3500 | return ret; |
---|
.. | .. |
---|
2765 | 3519 | if (!battery_props) |
---|
2766 | 3520 | return -ENOMEM; |
---|
2767 | 3521 | |
---|
2768 | | - num_battery_props = ARRAY_SIZE(hidpp_battery_props) - 2; |
---|
| 3522 | + num_battery_props = ARRAY_SIZE(hidpp_battery_props) - 3; |
---|
2769 | 3523 | |
---|
2770 | 3524 | if (hidpp->capabilities & HIDPP_CAPABILITY_BATTERY_MILEAGE) |
---|
2771 | 3525 | battery_props[num_battery_props++] = |
---|
.. | .. |
---|
2774 | 3528 | if (hidpp->capabilities & HIDPP_CAPABILITY_BATTERY_LEVEL_STATUS) |
---|
2775 | 3529 | battery_props[num_battery_props++] = |
---|
2776 | 3530 | POWER_SUPPLY_PROP_CAPACITY_LEVEL; |
---|
| 3531 | + |
---|
| 3532 | + if (hidpp->capabilities & HIDPP_CAPABILITY_BATTERY_VOLTAGE) |
---|
| 3533 | + battery_props[num_battery_props++] = |
---|
| 3534 | + POWER_SUPPLY_PROP_VOLTAGE_NOW; |
---|
2777 | 3535 | |
---|
2778 | 3536 | battery = &hidpp->battery; |
---|
2779 | 3537 | |
---|
.. | .. |
---|
2887 | 3645 | return; |
---|
2888 | 3646 | } |
---|
2889 | 3647 | |
---|
| 3648 | + if (hidpp->quirks & HIDPP_QUIRK_HIDPP_WHEELS) { |
---|
| 3649 | + ret = hidpp10_wheel_connect(hidpp); |
---|
| 3650 | + if (ret) |
---|
| 3651 | + return; |
---|
| 3652 | + } |
---|
| 3653 | + |
---|
| 3654 | + if (hidpp->quirks & HIDPP_QUIRK_HIDPP_EXTRA_MOUSE_BTNS) { |
---|
| 3655 | + ret = hidpp10_extra_mouse_buttons_connect(hidpp); |
---|
| 3656 | + if (ret) |
---|
| 3657 | + return; |
---|
| 3658 | + } |
---|
| 3659 | + |
---|
| 3660 | + if (hidpp->quirks & HIDPP_QUIRK_HIDPP_CONSUMER_VENDOR_KEYS) { |
---|
| 3661 | + ret = hidpp10_consumer_keys_connect(hidpp); |
---|
| 3662 | + if (ret) |
---|
| 3663 | + return; |
---|
| 3664 | + } |
---|
| 3665 | + |
---|
2890 | 3666 | /* the device is already connected, we can ask for its name and |
---|
2891 | 3667 | * protocol */ |
---|
2892 | 3668 | if (!hidpp->protocol_major) { |
---|
2893 | | - ret = !hidpp_is_connected(hidpp); |
---|
| 3669 | + ret = hidpp_root_get_protocol_version(hidpp); |
---|
2894 | 3670 | if (ret) { |
---|
2895 | 3671 | hid_err(hdev, "Can not get the protocol version.\n"); |
---|
2896 | 3672 | return; |
---|
2897 | 3673 | } |
---|
2898 | | - hid_info(hdev, "HID++ %u.%u device connected.\n", |
---|
2899 | | - hidpp->protocol_major, hidpp->protocol_minor); |
---|
2900 | 3674 | } |
---|
2901 | 3675 | |
---|
2902 | 3676 | if (hidpp->name == hdev->name && hidpp->protocol_major >= 2) { |
---|
2903 | 3677 | name = hidpp_get_device_name(hidpp); |
---|
2904 | | - if (!name) { |
---|
2905 | | - hid_err(hdev, |
---|
2906 | | - "unable to retrieve the name of the device"); |
---|
2907 | | - return; |
---|
| 3678 | + if (name) { |
---|
| 3679 | + devm_name = devm_kasprintf(&hdev->dev, GFP_KERNEL, |
---|
| 3680 | + "%s", name); |
---|
| 3681 | + kfree(name); |
---|
| 3682 | + if (!devm_name) |
---|
| 3683 | + return; |
---|
| 3684 | + |
---|
| 3685 | + hidpp->name = devm_name; |
---|
2908 | 3686 | } |
---|
2909 | | - |
---|
2910 | | - devm_name = devm_kasprintf(&hdev->dev, GFP_KERNEL, "%s", name); |
---|
2911 | | - kfree(name); |
---|
2912 | | - if (!devm_name) |
---|
2913 | | - return; |
---|
2914 | | - |
---|
2915 | | - hidpp->name = devm_name; |
---|
2916 | 3687 | } |
---|
2917 | 3688 | |
---|
2918 | 3689 | hidpp_initialize_battery(hidpp); |
---|
.. | .. |
---|
2925 | 3696 | else |
---|
2926 | 3697 | hidpp10_query_battery_status(hidpp); |
---|
2927 | 3698 | } else if (hidpp->capabilities & HIDPP_CAPABILITY_HIDPP20_BATTERY) { |
---|
2928 | | - hidpp20_query_battery_info(hidpp); |
---|
| 3699 | + if (hidpp->capabilities & HIDPP_CAPABILITY_BATTERY_VOLTAGE) |
---|
| 3700 | + hidpp20_query_battery_voltage_info(hidpp); |
---|
| 3701 | + else |
---|
| 3702 | + hidpp20_query_battery_info(hidpp); |
---|
2929 | 3703 | } |
---|
2930 | 3704 | if (hidpp->battery.ps) |
---|
2931 | 3705 | power_supply_changed(hidpp->battery.ps); |
---|
| 3706 | + |
---|
| 3707 | + if (hidpp->quirks & HIDPP_QUIRK_HI_RES_SCROLL) |
---|
| 3708 | + hi_res_scroll_enable(hidpp); |
---|
2932 | 3709 | |
---|
2933 | 3710 | if (!(hidpp->quirks & HIDPP_QUIRK_NO_HIDINPUT) || hidpp->delayed_input) |
---|
2934 | 3711 | /* if the input nodes are already created, we can stop now */ |
---|
.. | .. |
---|
2940 | 3717 | return; |
---|
2941 | 3718 | } |
---|
2942 | 3719 | |
---|
2943 | | - hidpp_populate_input(hidpp, input, false); |
---|
| 3720 | + hidpp_populate_input(hidpp, input); |
---|
2944 | 3721 | |
---|
2945 | 3722 | ret = input_register_device(input); |
---|
2946 | 3723 | if (ret) |
---|
.. | .. |
---|
2960 | 3737 | .attrs = sysfs_attrs |
---|
2961 | 3738 | }; |
---|
2962 | 3739 | |
---|
| 3740 | +static int hidpp_get_report_length(struct hid_device *hdev, int id) |
---|
| 3741 | +{ |
---|
| 3742 | + struct hid_report_enum *re; |
---|
| 3743 | + struct hid_report *report; |
---|
| 3744 | + |
---|
| 3745 | + re = &(hdev->report_enum[HID_OUTPUT_REPORT]); |
---|
| 3746 | + report = re->report_id_hash[id]; |
---|
| 3747 | + if (!report) |
---|
| 3748 | + return 0; |
---|
| 3749 | + |
---|
| 3750 | + return report->field[0]->report_count + 1; |
---|
| 3751 | +} |
---|
| 3752 | + |
---|
| 3753 | +static u8 hidpp_validate_device(struct hid_device *hdev) |
---|
| 3754 | +{ |
---|
| 3755 | + struct hidpp_device *hidpp = hid_get_drvdata(hdev); |
---|
| 3756 | + int id, report_length; |
---|
| 3757 | + u8 supported_reports = 0; |
---|
| 3758 | + |
---|
| 3759 | + id = REPORT_ID_HIDPP_SHORT; |
---|
| 3760 | + report_length = hidpp_get_report_length(hdev, id); |
---|
| 3761 | + if (report_length) { |
---|
| 3762 | + if (report_length < HIDPP_REPORT_SHORT_LENGTH) |
---|
| 3763 | + goto bad_device; |
---|
| 3764 | + |
---|
| 3765 | + supported_reports |= HIDPP_REPORT_SHORT_SUPPORTED; |
---|
| 3766 | + } |
---|
| 3767 | + |
---|
| 3768 | + id = REPORT_ID_HIDPP_LONG; |
---|
| 3769 | + report_length = hidpp_get_report_length(hdev, id); |
---|
| 3770 | + if (report_length) { |
---|
| 3771 | + if (report_length < HIDPP_REPORT_LONG_LENGTH) |
---|
| 3772 | + goto bad_device; |
---|
| 3773 | + |
---|
| 3774 | + supported_reports |= HIDPP_REPORT_LONG_SUPPORTED; |
---|
| 3775 | + } |
---|
| 3776 | + |
---|
| 3777 | + id = REPORT_ID_HIDPP_VERY_LONG; |
---|
| 3778 | + report_length = hidpp_get_report_length(hdev, id); |
---|
| 3779 | + if (report_length) { |
---|
| 3780 | + if (report_length < HIDPP_REPORT_LONG_LENGTH || |
---|
| 3781 | + report_length > HIDPP_REPORT_VERY_LONG_MAX_LENGTH) |
---|
| 3782 | + goto bad_device; |
---|
| 3783 | + |
---|
| 3784 | + supported_reports |= HIDPP_REPORT_VERY_LONG_SUPPORTED; |
---|
| 3785 | + hidpp->very_long_report_length = report_length; |
---|
| 3786 | + } |
---|
| 3787 | + |
---|
| 3788 | + return supported_reports; |
---|
| 3789 | + |
---|
| 3790 | +bad_device: |
---|
| 3791 | + hid_warn(hdev, "not enough values in hidpp report %d\n", id); |
---|
| 3792 | + return false; |
---|
| 3793 | +} |
---|
| 3794 | + |
---|
| 3795 | +static bool hidpp_application_equals(struct hid_device *hdev, |
---|
| 3796 | + unsigned int application) |
---|
| 3797 | +{ |
---|
| 3798 | + struct list_head *report_list; |
---|
| 3799 | + struct hid_report *report; |
---|
| 3800 | + |
---|
| 3801 | + report_list = &hdev->report_enum[HID_INPUT_REPORT].report_list; |
---|
| 3802 | + report = list_first_entry_or_null(report_list, struct hid_report, list); |
---|
| 3803 | + return report && report->application == application; |
---|
| 3804 | +} |
---|
| 3805 | + |
---|
2963 | 3806 | static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id) |
---|
2964 | 3807 | { |
---|
2965 | 3808 | struct hidpp_device *hidpp; |
---|
2966 | 3809 | int ret; |
---|
2967 | 3810 | bool connected; |
---|
2968 | 3811 | unsigned int connect_mask = HID_CONNECT_DEFAULT; |
---|
| 3812 | + struct hidpp_ff_private_data data; |
---|
| 3813 | + bool will_restart = false; |
---|
2969 | 3814 | |
---|
2970 | | - hidpp = devm_kzalloc(&hdev->dev, sizeof(struct hidpp_device), |
---|
2971 | | - GFP_KERNEL); |
---|
| 3815 | + /* report_fixup needs drvdata to be set before we call hid_parse */ |
---|
| 3816 | + hidpp = devm_kzalloc(&hdev->dev, sizeof(*hidpp), GFP_KERNEL); |
---|
2972 | 3817 | if (!hidpp) |
---|
2973 | 3818 | return -ENOMEM; |
---|
2974 | 3819 | |
---|
2975 | 3820 | hidpp->hid_dev = hdev; |
---|
2976 | 3821 | hidpp->name = hdev->name; |
---|
| 3822 | + hidpp->quirks = id->driver_data; |
---|
2977 | 3823 | hid_set_drvdata(hdev, hidpp); |
---|
2978 | 3824 | |
---|
2979 | | - hidpp->quirks = id->driver_data; |
---|
| 3825 | + ret = hid_parse(hdev); |
---|
| 3826 | + if (ret) { |
---|
| 3827 | + hid_err(hdev, "%s:parse failed\n", __func__); |
---|
| 3828 | + return ret; |
---|
| 3829 | + } |
---|
| 3830 | + |
---|
| 3831 | + /* |
---|
| 3832 | + * Make sure the device is HID++ capable, otherwise treat as generic HID |
---|
| 3833 | + */ |
---|
| 3834 | + hidpp->supported_reports = hidpp_validate_device(hdev); |
---|
| 3835 | + |
---|
| 3836 | + if (!hidpp->supported_reports) { |
---|
| 3837 | + hid_set_drvdata(hdev, NULL); |
---|
| 3838 | + devm_kfree(&hdev->dev, hidpp); |
---|
| 3839 | + return hid_hw_start(hdev, HID_CONNECT_DEFAULT); |
---|
| 3840 | + } |
---|
2980 | 3841 | |
---|
2981 | 3842 | if (id->group == HID_GROUP_LOGITECH_DJ_DEVICE) |
---|
2982 | 3843 | hidpp->quirks |= HIDPP_QUIRK_UNIFYING; |
---|
| 3844 | + |
---|
| 3845 | + if (id->group == HID_GROUP_LOGITECH_27MHZ_DEVICE && |
---|
| 3846 | + hidpp_application_equals(hdev, HID_GD_MOUSE)) |
---|
| 3847 | + hidpp->quirks |= HIDPP_QUIRK_HIDPP_WHEELS | |
---|
| 3848 | + HIDPP_QUIRK_HIDPP_EXTRA_MOUSE_BTNS; |
---|
| 3849 | + |
---|
| 3850 | + if (id->group == HID_GROUP_LOGITECH_27MHZ_DEVICE && |
---|
| 3851 | + hidpp_application_equals(hdev, HID_GD_KEYBOARD)) |
---|
| 3852 | + hidpp->quirks |= HIDPP_QUIRK_HIDPP_CONSUMER_VENDOR_KEYS; |
---|
2983 | 3853 | |
---|
2984 | 3854 | if (disable_raw_mode) { |
---|
2985 | 3855 | hidpp->quirks &= ~HIDPP_QUIRK_CLASS_WTP; |
---|
.. | .. |
---|
2989 | 3859 | if (hidpp->quirks & HIDPP_QUIRK_CLASS_WTP) { |
---|
2990 | 3860 | ret = wtp_allocate(hdev, id); |
---|
2991 | 3861 | if (ret) |
---|
2992 | | - goto allocate_fail; |
---|
2993 | | - } else if (hidpp->quirks & HIDPP_QUIRK_CLASS_M560) { |
---|
2994 | | - ret = m560_allocate(hdev); |
---|
2995 | | - if (ret) |
---|
2996 | | - goto allocate_fail; |
---|
| 3862 | + return ret; |
---|
2997 | 3863 | } else if (hidpp->quirks & HIDPP_QUIRK_CLASS_K400) { |
---|
2998 | 3864 | ret = k400_allocate(hdev); |
---|
2999 | 3865 | if (ret) |
---|
3000 | | - goto allocate_fail; |
---|
| 3866 | + return ret; |
---|
3001 | 3867 | } |
---|
| 3868 | + |
---|
| 3869 | + if (hidpp->quirks & HIDPP_QUIRK_DELAYED_INIT || |
---|
| 3870 | + hidpp->quirks & HIDPP_QUIRK_UNIFYING) |
---|
| 3871 | + will_restart = true; |
---|
3002 | 3872 | |
---|
3003 | 3873 | INIT_WORK(&hidpp->work, delayed_work_cb); |
---|
3004 | 3874 | mutex_init(&hidpp->send_mutex); |
---|
.. | .. |
---|
3010 | 3880 | hid_warn(hdev, "Cannot allocate sysfs group for %s\n", |
---|
3011 | 3881 | hdev->name); |
---|
3012 | 3882 | |
---|
3013 | | - ret = hid_parse(hdev); |
---|
| 3883 | + /* |
---|
| 3884 | + * Plain USB connections need to actually call start and open |
---|
| 3885 | + * on the transport driver to allow incoming data. |
---|
| 3886 | + */ |
---|
| 3887 | + ret = hid_hw_start(hdev, will_restart ? 0 : connect_mask); |
---|
3014 | 3888 | if (ret) { |
---|
3015 | | - hid_err(hdev, "%s:parse failed\n", __func__); |
---|
3016 | | - goto hid_parse_fail; |
---|
| 3889 | + hid_err(hdev, "hw start failed\n"); |
---|
| 3890 | + goto hid_hw_start_fail; |
---|
3017 | 3891 | } |
---|
3018 | 3892 | |
---|
3019 | | - if (hidpp->quirks & HIDPP_QUIRK_NO_HIDINPUT) |
---|
3020 | | - connect_mask &= ~HID_CONNECT_HIDINPUT; |
---|
3021 | | - |
---|
3022 | | - if (hidpp->quirks & HIDPP_QUIRK_CLASS_G920) { |
---|
3023 | | - ret = hid_hw_start(hdev, connect_mask); |
---|
3024 | | - if (ret) { |
---|
3025 | | - hid_err(hdev, "hw start failed\n"); |
---|
3026 | | - goto hid_hw_start_fail; |
---|
3027 | | - } |
---|
3028 | | - ret = hid_hw_open(hdev); |
---|
3029 | | - if (ret < 0) { |
---|
3030 | | - dev_err(&hdev->dev, "%s:hid_hw_open returned error:%d\n", |
---|
3031 | | - __func__, ret); |
---|
3032 | | - hid_hw_stop(hdev); |
---|
3033 | | - goto hid_hw_start_fail; |
---|
3034 | | - } |
---|
| 3893 | + ret = hid_hw_open(hdev); |
---|
| 3894 | + if (ret < 0) { |
---|
| 3895 | + dev_err(&hdev->dev, "%s:hid_hw_open returned error:%d\n", |
---|
| 3896 | + __func__, ret); |
---|
| 3897 | + goto hid_hw_open_fail; |
---|
3035 | 3898 | } |
---|
3036 | | - |
---|
3037 | 3899 | |
---|
3038 | 3900 | /* Allow incoming packets */ |
---|
3039 | 3901 | hid_device_io_start(hdev); |
---|
3040 | 3902 | |
---|
3041 | 3903 | if (hidpp->quirks & HIDPP_QUIRK_UNIFYING) |
---|
3042 | 3904 | hidpp_unifying_init(hidpp); |
---|
| 3905 | + else if (hid_is_usb(hidpp->hid_dev)) |
---|
| 3906 | + hidpp_serial_init(hidpp); |
---|
3043 | 3907 | |
---|
3044 | | - connected = hidpp_is_connected(hidpp); |
---|
| 3908 | + connected = hidpp_root_get_protocol_version(hidpp) == 0; |
---|
3045 | 3909 | atomic_set(&hidpp->connected, connected); |
---|
3046 | 3910 | if (!(hidpp->quirks & HIDPP_QUIRK_UNIFYING)) { |
---|
3047 | 3911 | if (!connected) { |
---|
3048 | 3912 | ret = -ENODEV; |
---|
3049 | 3913 | hid_err(hdev, "Device not connected"); |
---|
3050 | | - goto hid_hw_open_failed; |
---|
| 3914 | + goto hid_hw_init_fail; |
---|
3051 | 3915 | } |
---|
3052 | 3916 | |
---|
3053 | | - hid_info(hdev, "HID++ %u.%u device connected.\n", |
---|
3054 | | - hidpp->protocol_major, hidpp->protocol_minor); |
---|
3055 | | - |
---|
3056 | 3917 | hidpp_overwrite_name(hdev); |
---|
| 3918 | + } |
---|
| 3919 | + |
---|
| 3920 | + if (connected && hidpp->protocol_major >= 2) { |
---|
| 3921 | + ret = hidpp_set_wireless_feature_index(hidpp); |
---|
| 3922 | + if (ret == -ENOENT) |
---|
| 3923 | + hidpp->wireless_feature_index = 0; |
---|
| 3924 | + else if (ret) |
---|
| 3925 | + goto hid_hw_init_fail; |
---|
| 3926 | + ret = 0; |
---|
3057 | 3927 | } |
---|
3058 | 3928 | |
---|
3059 | 3929 | if (connected && (hidpp->quirks & HIDPP_QUIRK_CLASS_WTP)) { |
---|
3060 | 3930 | ret = wtp_get_config(hidpp); |
---|
3061 | 3931 | if (ret) |
---|
3062 | | - goto hid_hw_open_failed; |
---|
| 3932 | + goto hid_hw_init_fail; |
---|
3063 | 3933 | } else if (connected && (hidpp->quirks & HIDPP_QUIRK_CLASS_G920)) { |
---|
3064 | | - ret = g920_get_config(hidpp); |
---|
| 3934 | + ret = g920_get_config(hidpp, &data); |
---|
3065 | 3935 | if (ret) |
---|
3066 | | - goto hid_hw_open_failed; |
---|
| 3936 | + goto hid_hw_init_fail; |
---|
3067 | 3937 | } |
---|
3068 | 3938 | |
---|
3069 | | - /* Block incoming packets */ |
---|
3070 | | - hid_device_io_stop(hdev); |
---|
| 3939 | + hidpp_connect_event(hidpp); |
---|
3071 | 3940 | |
---|
3072 | | - if (!(hidpp->quirks & HIDPP_QUIRK_CLASS_G920)) { |
---|
| 3941 | + if (will_restart) { |
---|
| 3942 | + /* Reset the HID node state */ |
---|
| 3943 | + hid_device_io_stop(hdev); |
---|
| 3944 | + hid_hw_close(hdev); |
---|
| 3945 | + hid_hw_stop(hdev); |
---|
| 3946 | + |
---|
| 3947 | + if (hidpp->quirks & HIDPP_QUIRK_NO_HIDINPUT) |
---|
| 3948 | + connect_mask &= ~HID_CONNECT_HIDINPUT; |
---|
| 3949 | + |
---|
| 3950 | + /* Now export the actual inputs and hidraw nodes to the world */ |
---|
3073 | 3951 | ret = hid_hw_start(hdev, connect_mask); |
---|
3074 | 3952 | if (ret) { |
---|
3075 | 3953 | hid_err(hdev, "%s:hid_hw_start returned error\n", __func__); |
---|
.. | .. |
---|
3077 | 3955 | } |
---|
3078 | 3956 | } |
---|
3079 | 3957 | |
---|
3080 | | - /* Allow incoming packets */ |
---|
3081 | | - hid_device_io_start(hdev); |
---|
3082 | | - |
---|
3083 | | - hidpp_connect_event(hidpp); |
---|
| 3958 | + if (hidpp->quirks & HIDPP_QUIRK_CLASS_G920) { |
---|
| 3959 | + ret = hidpp_ff_init(hidpp, &data); |
---|
| 3960 | + if (ret) |
---|
| 3961 | + hid_warn(hidpp->hid_dev, |
---|
| 3962 | + "Unable to initialize force feedback support, errno %d\n", |
---|
| 3963 | + ret); |
---|
| 3964 | + } |
---|
3084 | 3965 | |
---|
3085 | 3966 | return ret; |
---|
3086 | 3967 | |
---|
3087 | | -hid_hw_open_failed: |
---|
3088 | | - hid_device_io_stop(hdev); |
---|
3089 | | - if (hidpp->quirks & HIDPP_QUIRK_CLASS_G920) { |
---|
3090 | | - hid_hw_close(hdev); |
---|
3091 | | - hid_hw_stop(hdev); |
---|
3092 | | - } |
---|
| 3968 | +hid_hw_init_fail: |
---|
| 3969 | + hid_hw_close(hdev); |
---|
| 3970 | +hid_hw_open_fail: |
---|
| 3971 | + hid_hw_stop(hdev); |
---|
3093 | 3972 | hid_hw_start_fail: |
---|
3094 | | -hid_parse_fail: |
---|
3095 | 3973 | sysfs_remove_group(&hdev->dev.kobj, &ps_attribute_group); |
---|
3096 | 3974 | cancel_work_sync(&hidpp->work); |
---|
3097 | 3975 | mutex_destroy(&hidpp->send_mutex); |
---|
3098 | | -allocate_fail: |
---|
3099 | | - hid_set_drvdata(hdev, NULL); |
---|
3100 | 3976 | return ret; |
---|
3101 | 3977 | } |
---|
3102 | 3978 | |
---|
.. | .. |
---|
3104 | 3980 | { |
---|
3105 | 3981 | struct hidpp_device *hidpp = hid_get_drvdata(hdev); |
---|
3106 | 3982 | |
---|
| 3983 | + if (!hidpp) |
---|
| 3984 | + return hid_hw_stop(hdev); |
---|
| 3985 | + |
---|
3107 | 3986 | sysfs_remove_group(&hdev->dev.kobj, &ps_attribute_group); |
---|
3108 | 3987 | |
---|
3109 | | - if (hidpp->quirks & HIDPP_QUIRK_CLASS_G920) { |
---|
3110 | | - hidpp_ff_deinit(hdev); |
---|
3111 | | - hid_hw_close(hdev); |
---|
3112 | | - } |
---|
3113 | 3988 | hid_hw_stop(hdev); |
---|
3114 | 3989 | cancel_work_sync(&hidpp->work); |
---|
3115 | 3990 | mutex_destroy(&hidpp->send_mutex); |
---|
3116 | 3991 | } |
---|
3117 | 3992 | |
---|
| 3993 | +#define LDJ_DEVICE(product) \ |
---|
| 3994 | + HID_DEVICE(BUS_USB, HID_GROUP_LOGITECH_DJ_DEVICE, \ |
---|
| 3995 | + USB_VENDOR_ID_LOGITECH, (product)) |
---|
| 3996 | + |
---|
| 3997 | +#define L27MHZ_DEVICE(product) \ |
---|
| 3998 | + HID_DEVICE(BUS_USB, HID_GROUP_LOGITECH_27MHZ_DEVICE, \ |
---|
| 3999 | + USB_VENDOR_ID_LOGITECH, (product)) |
---|
| 4000 | + |
---|
3118 | 4001 | static const struct hid_device_id hidpp_devices[] = { |
---|
3119 | 4002 | { /* wireless touchpad */ |
---|
3120 | | - HID_DEVICE(BUS_USB, HID_GROUP_LOGITECH_DJ_DEVICE, |
---|
3121 | | - USB_VENDOR_ID_LOGITECH, 0x4011), |
---|
| 4003 | + LDJ_DEVICE(0x4011), |
---|
3122 | 4004 | .driver_data = HIDPP_QUIRK_CLASS_WTP | HIDPP_QUIRK_DELAYED_INIT | |
---|
3123 | 4005 | HIDPP_QUIRK_WTP_PHYSICAL_BUTTONS }, |
---|
3124 | 4006 | { /* wireless touchpad T650 */ |
---|
3125 | | - HID_DEVICE(BUS_USB, HID_GROUP_LOGITECH_DJ_DEVICE, |
---|
3126 | | - USB_VENDOR_ID_LOGITECH, 0x4101), |
---|
| 4007 | + LDJ_DEVICE(0x4101), |
---|
3127 | 4008 | .driver_data = HIDPP_QUIRK_CLASS_WTP | HIDPP_QUIRK_DELAYED_INIT }, |
---|
3128 | 4009 | { /* wireless touchpad T651 */ |
---|
3129 | 4010 | HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, |
---|
3130 | 4011 | USB_DEVICE_ID_LOGITECH_T651), |
---|
3131 | | - .driver_data = HIDPP_QUIRK_CLASS_WTP }, |
---|
| 4012 | + .driver_data = HIDPP_QUIRK_CLASS_WTP | HIDPP_QUIRK_DELAYED_INIT }, |
---|
| 4013 | + { /* Mouse Logitech Anywhere MX */ |
---|
| 4014 | + LDJ_DEVICE(0x1017), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_1P0 }, |
---|
| 4015 | + { /* Mouse Logitech Cube */ |
---|
| 4016 | + LDJ_DEVICE(0x4010), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2120 }, |
---|
| 4017 | + { /* Mouse Logitech M335 */ |
---|
| 4018 | + LDJ_DEVICE(0x4050), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 }, |
---|
| 4019 | + { /* Mouse Logitech M515 */ |
---|
| 4020 | + LDJ_DEVICE(0x4007), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2120 }, |
---|
3132 | 4021 | { /* Mouse logitech M560 */ |
---|
3133 | | - HID_DEVICE(BUS_USB, HID_GROUP_LOGITECH_DJ_DEVICE, |
---|
3134 | | - USB_VENDOR_ID_LOGITECH, 0x402d), |
---|
3135 | | - .driver_data = HIDPP_QUIRK_DELAYED_INIT | HIDPP_QUIRK_CLASS_M560 }, |
---|
| 4022 | + LDJ_DEVICE(0x402d), |
---|
| 4023 | + .driver_data = HIDPP_QUIRK_DELAYED_INIT | HIDPP_QUIRK_CLASS_M560 |
---|
| 4024 | + | HIDPP_QUIRK_HI_RES_SCROLL_X2120 }, |
---|
| 4025 | + { /* Mouse Logitech M705 (firmware RQM17) */ |
---|
| 4026 | + LDJ_DEVICE(0x101b), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_1P0 }, |
---|
| 4027 | + { /* Mouse Logitech M705 (firmware RQM67) */ |
---|
| 4028 | + LDJ_DEVICE(0x406d), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 }, |
---|
| 4029 | + { /* Mouse Logitech M720 */ |
---|
| 4030 | + LDJ_DEVICE(0x405e), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 }, |
---|
| 4031 | + { /* Mouse Logitech MX Anywhere 2 */ |
---|
| 4032 | + LDJ_DEVICE(0x404a), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 }, |
---|
| 4033 | + { LDJ_DEVICE(0x4072), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 }, |
---|
| 4034 | + { LDJ_DEVICE(0xb013), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 }, |
---|
| 4035 | + { LDJ_DEVICE(0xb018), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 }, |
---|
| 4036 | + { LDJ_DEVICE(0xb01f), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 }, |
---|
| 4037 | + { /* Mouse Logitech MX Anywhere 2S */ |
---|
| 4038 | + LDJ_DEVICE(0x406a), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 }, |
---|
| 4039 | + { /* Mouse Logitech MX Master */ |
---|
| 4040 | + LDJ_DEVICE(0x4041), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 }, |
---|
| 4041 | + { LDJ_DEVICE(0x4060), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 }, |
---|
| 4042 | + { LDJ_DEVICE(0x4071), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 }, |
---|
| 4043 | + { /* Mouse Logitech MX Master 2S */ |
---|
| 4044 | + LDJ_DEVICE(0x4069), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 }, |
---|
| 4045 | + { /* Mouse Logitech MX Master 3 */ |
---|
| 4046 | + LDJ_DEVICE(0x4082), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 }, |
---|
| 4047 | + { /* Mouse Logitech Performance MX */ |
---|
| 4048 | + LDJ_DEVICE(0x101a), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_1P0 }, |
---|
3136 | 4049 | { /* Keyboard logitech K400 */ |
---|
3137 | | - HID_DEVICE(BUS_USB, HID_GROUP_LOGITECH_DJ_DEVICE, |
---|
3138 | | - USB_VENDOR_ID_LOGITECH, 0x4024), |
---|
| 4050 | + LDJ_DEVICE(0x4024), |
---|
3139 | 4051 | .driver_data = HIDPP_QUIRK_CLASS_K400 }, |
---|
3140 | 4052 | { /* Solar Keyboard Logitech K750 */ |
---|
3141 | | - HID_DEVICE(BUS_USB, HID_GROUP_LOGITECH_DJ_DEVICE, |
---|
3142 | | - USB_VENDOR_ID_LOGITECH, 0x4002), |
---|
| 4053 | + LDJ_DEVICE(0x4002), |
---|
3143 | 4054 | .driver_data = HIDPP_QUIRK_CLASS_K750 }, |
---|
| 4055 | + { /* Keyboard MX5000 (Bluetooth-receiver in HID proxy mode) */ |
---|
| 4056 | + LDJ_DEVICE(0xb305), |
---|
| 4057 | + .driver_data = HIDPP_QUIRK_HIDPP_CONSUMER_VENDOR_KEYS }, |
---|
| 4058 | + { /* Dinovo Edge (Bluetooth-receiver in HID proxy mode) */ |
---|
| 4059 | + LDJ_DEVICE(0xb309), |
---|
| 4060 | + .driver_data = HIDPP_QUIRK_HIDPP_CONSUMER_VENDOR_KEYS }, |
---|
| 4061 | + { /* Keyboard MX5500 (Bluetooth-receiver in HID proxy mode) */ |
---|
| 4062 | + LDJ_DEVICE(0xb30b), |
---|
| 4063 | + .driver_data = HIDPP_QUIRK_HIDPP_CONSUMER_VENDOR_KEYS }, |
---|
3144 | 4064 | |
---|
3145 | | - { HID_DEVICE(BUS_USB, HID_GROUP_LOGITECH_DJ_DEVICE, |
---|
3146 | | - USB_VENDOR_ID_LOGITECH, HID_ANY_ID)}, |
---|
| 4065 | + { LDJ_DEVICE(HID_ANY_ID) }, |
---|
3147 | 4066 | |
---|
3148 | | - { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G920_WHEEL), |
---|
| 4067 | + { /* Keyboard LX501 (Y-RR53) */ |
---|
| 4068 | + L27MHZ_DEVICE(0x0049), |
---|
| 4069 | + .driver_data = HIDPP_QUIRK_KBD_ZOOM_WHEEL }, |
---|
| 4070 | + { /* Keyboard MX3000 (Y-RAM74) */ |
---|
| 4071 | + L27MHZ_DEVICE(0x0057), |
---|
| 4072 | + .driver_data = HIDPP_QUIRK_KBD_SCROLL_WHEEL }, |
---|
| 4073 | + { /* Keyboard MX3200 (Y-RAV80) */ |
---|
| 4074 | + L27MHZ_DEVICE(0x005c), |
---|
| 4075 | + .driver_data = HIDPP_QUIRK_KBD_ZOOM_WHEEL }, |
---|
| 4076 | + { /* S510 Media Remote */ |
---|
| 4077 | + L27MHZ_DEVICE(0x00fe), |
---|
| 4078 | + .driver_data = HIDPP_QUIRK_KBD_SCROLL_WHEEL }, |
---|
| 4079 | + |
---|
| 4080 | + { L27MHZ_DEVICE(HID_ANY_ID) }, |
---|
| 4081 | + |
---|
| 4082 | + { /* Logitech G403 Wireless Gaming Mouse over USB */ |
---|
| 4083 | + HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, 0xC082) }, |
---|
| 4084 | + { /* Logitech G703 Gaming Mouse over USB */ |
---|
| 4085 | + HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, 0xC087) }, |
---|
| 4086 | + { /* Logitech G703 Hero Gaming Mouse over USB */ |
---|
| 4087 | + HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, 0xC090) }, |
---|
| 4088 | + { /* Logitech G900 Gaming Mouse over USB */ |
---|
| 4089 | + HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, 0xC081) }, |
---|
| 4090 | + { /* Logitech G903 Gaming Mouse over USB */ |
---|
| 4091 | + HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, 0xC086) }, |
---|
| 4092 | + { /* Logitech G903 Hero Gaming Mouse over USB */ |
---|
| 4093 | + HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, 0xC091) }, |
---|
| 4094 | + { /* Logitech G920 Wheel over USB */ |
---|
| 4095 | + HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G920_WHEEL), |
---|
3149 | 4096 | .driver_data = HIDPP_QUIRK_CLASS_G920 | HIDPP_QUIRK_FORCE_OUTPUT_REPORTS}, |
---|
| 4097 | + { /* Logitech G Pro Gaming Mouse over USB */ |
---|
| 4098 | + HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, 0xC088) }, |
---|
| 4099 | + |
---|
| 4100 | + { /* MX5000 keyboard over Bluetooth */ |
---|
| 4101 | + HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb305), |
---|
| 4102 | + .driver_data = HIDPP_QUIRK_HIDPP_CONSUMER_VENDOR_KEYS }, |
---|
| 4103 | + { /* Dinovo Edge keyboard over Bluetooth */ |
---|
| 4104 | + HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb309), |
---|
| 4105 | + .driver_data = HIDPP_QUIRK_HIDPP_CONSUMER_VENDOR_KEYS }, |
---|
| 4106 | + { /* MX5500 keyboard over Bluetooth */ |
---|
| 4107 | + HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb30b), |
---|
| 4108 | + .driver_data = HIDPP_QUIRK_HIDPP_CONSUMER_VENDOR_KEYS }, |
---|
| 4109 | + { /* MX Master mouse over Bluetooth */ |
---|
| 4110 | + HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb012), |
---|
| 4111 | + .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 }, |
---|
| 4112 | + { /* MX Ergo trackball over Bluetooth */ |
---|
| 4113 | + HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb01d) }, |
---|
| 4114 | + { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb01e), |
---|
| 4115 | + .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 }, |
---|
| 4116 | + { /* MX Master 3 mouse over Bluetooth */ |
---|
| 4117 | + HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb023), |
---|
| 4118 | + .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 }, |
---|
3150 | 4119 | {} |
---|
3151 | 4120 | }; |
---|
3152 | 4121 | |
---|
3153 | 4122 | MODULE_DEVICE_TABLE(hid, hidpp_devices); |
---|
3154 | 4123 | |
---|
| 4124 | +static const struct hid_usage_id hidpp_usages[] = { |
---|
| 4125 | + { HID_GD_WHEEL, EV_REL, REL_WHEEL_HI_RES }, |
---|
| 4126 | + { HID_ANY_ID - 1, HID_ANY_ID - 1, HID_ANY_ID - 1} |
---|
| 4127 | +}; |
---|
| 4128 | + |
---|
3155 | 4129 | static struct hid_driver hidpp_driver = { |
---|
3156 | 4130 | .name = "logitech-hidpp-device", |
---|
3157 | 4131 | .id_table = hidpp_devices, |
---|
| 4132 | + .report_fixup = hidpp_report_fixup, |
---|
3158 | 4133 | .probe = hidpp_probe, |
---|
3159 | 4134 | .remove = hidpp_remove, |
---|
3160 | 4135 | .raw_event = hidpp_raw_event, |
---|
| 4136 | + .usage_table = hidpp_usages, |
---|
| 4137 | + .event = hidpp_event, |
---|
3161 | 4138 | .input_configured = hidpp_input_configured, |
---|
3162 | 4139 | .input_mapping = hidpp_input_mapping, |
---|
3163 | 4140 | .input_mapped = hidpp_input_mapped, |
---|