diff options
| -rw-r--r-- | drivers/hid/hid-logitech-hidpp.c | 301 |
1 files changed, 295 insertions, 6 deletions
diff --git a/drivers/hid/hid-logitech-hidpp.c b/drivers/hid/hid-logitech-hidpp.c index 95ba9db6e613..a66daf8acd87 100644 --- a/drivers/hid/hid-logitech-hidpp.c +++ b/drivers/hid/hid-logitech-hidpp.c | |||
| @@ -21,6 +21,7 @@ | |||
| 21 | #include <linux/module.h> | 21 | #include <linux/module.h> |
| 22 | #include <linux/slab.h> | 22 | #include <linux/slab.h> |
| 23 | #include <linux/sched.h> | 23 | #include <linux/sched.h> |
| 24 | #include <linux/sched/clock.h> | ||
| 24 | #include <linux/kfifo.h> | 25 | #include <linux/kfifo.h> |
| 25 | #include <linux/input/mt.h> | 26 | #include <linux/input/mt.h> |
| 26 | #include <linux/workqueue.h> | 27 | #include <linux/workqueue.h> |
| @@ -64,6 +65,14 @@ MODULE_PARM_DESC(disable_tap_to_click, | |||
| 64 | #define HIDPP_QUIRK_NO_HIDINPUT BIT(23) | 65 | #define HIDPP_QUIRK_NO_HIDINPUT BIT(23) |
| 65 | #define HIDPP_QUIRK_FORCE_OUTPUT_REPORTS BIT(24) | 66 | #define HIDPP_QUIRK_FORCE_OUTPUT_REPORTS BIT(24) |
| 66 | #define HIDPP_QUIRK_UNIFYING BIT(25) | 67 | #define HIDPP_QUIRK_UNIFYING BIT(25) |
| 68 | #define HIDPP_QUIRK_HI_RES_SCROLL_1P0 BIT(26) | ||
| 69 | #define HIDPP_QUIRK_HI_RES_SCROLL_X2120 BIT(27) | ||
| 70 | #define HIDPP_QUIRK_HI_RES_SCROLL_X2121 BIT(28) | ||
| 71 | |||
| 72 | /* Convenience constant to check for any high-res support. */ | ||
| 73 | #define HIDPP_QUIRK_HI_RES_SCROLL (HIDPP_QUIRK_HI_RES_SCROLL_1P0 | \ | ||
| 74 | HIDPP_QUIRK_HI_RES_SCROLL_X2120 | \ | ||
| 75 | HIDPP_QUIRK_HI_RES_SCROLL_X2121) | ||
| 67 | 76 | ||
| 68 | #define HIDPP_QUIRK_DELAYED_INIT HIDPP_QUIRK_NO_HIDINPUT | 77 | #define HIDPP_QUIRK_DELAYED_INIT HIDPP_QUIRK_NO_HIDINPUT |
| 69 | 78 | ||
| @@ -128,6 +137,25 @@ struct hidpp_battery { | |||
| 128 | bool online; | 137 | bool online; |
| 129 | }; | 138 | }; |
| 130 | 139 | ||
| 140 | /** | ||
| 141 | * struct hidpp_scroll_counter - Utility class for processing high-resolution | ||
| 142 | * scroll events. | ||
| 143 | * @dev: the input device for which events should be reported. | ||
| 144 | * @wheel_multiplier: the scalar multiplier to be applied to each wheel event | ||
| 145 | * @remainder: counts the number of high-resolution units moved since the last | ||
| 146 | * low-resolution event (REL_WHEEL or REL_HWHEEL) was sent. Should | ||
| 147 | * only be used by class methods. | ||
| 148 | * @direction: direction of last movement (1 or -1) | ||
| 149 | * @last_time: last event time, used to reset remainder after inactivity | ||
| 150 | */ | ||
| 151 | struct hidpp_scroll_counter { | ||
| 152 | struct input_dev *dev; | ||
| 153 | int wheel_multiplier; | ||
| 154 | int remainder; | ||
| 155 | int direction; | ||
| 156 | unsigned long long last_time; | ||
| 157 | }; | ||
| 158 | |||
| 131 | struct hidpp_device { | 159 | struct hidpp_device { |
| 132 | struct hid_device *hid_dev; | 160 | struct hid_device *hid_dev; |
| 133 | struct mutex send_mutex; | 161 | struct mutex send_mutex; |
| @@ -149,6 +177,7 @@ struct hidpp_device { | |||
| 149 | unsigned long capabilities; | 177 | unsigned long capabilities; |
| 150 | 178 | ||
| 151 | struct hidpp_battery battery; | 179 | struct hidpp_battery battery; |
| 180 | struct hidpp_scroll_counter vertical_wheel_counter; | ||
| 152 | }; | 181 | }; |
| 153 | 182 | ||
| 154 | /* HID++ 1.0 error codes */ | 183 | /* HID++ 1.0 error codes */ |
| @@ -391,6 +420,67 @@ static void hidpp_prefix_name(char **name, int name_length) | |||
| 391 | *name = new_name; | 420 | *name = new_name; |
| 392 | } | 421 | } |
| 393 | 422 | ||
| 423 | /** | ||
| 424 | * hidpp_scroll_counter_handle_scroll() - Send high- and low-resolution scroll | ||
| 425 | * events given a high-resolution wheel | ||
| 426 | * movement. | ||
| 427 | * @counter: a hid_scroll_counter struct describing the wheel. | ||
| 428 | * @hi_res_value: the movement of the wheel, in the mouse's high-resolution | ||
| 429 | * units. | ||
| 430 | * | ||
| 431 | * Given a high-resolution movement, this function converts the movement into | ||
| 432 | * fractions of 120 and emits high-resolution scroll events for the input | ||
| 433 | * device. It also uses the multiplier from &struct hid_scroll_counter to | ||
| 434 | * emit low-resolution scroll events when appropriate for | ||
| 435 | * backwards-compatibility with userspace input libraries. | ||
| 436 | */ | ||
| 437 | static void hidpp_scroll_counter_handle_scroll(struct hidpp_scroll_counter *counter, | ||
| 438 | int hi_res_value) | ||
| 439 | { | ||
| 440 | int low_res_value, remainder, direction; | ||
| 441 | unsigned long long now, previous; | ||
| 442 | |||
| 443 | hi_res_value = hi_res_value * 120/counter->wheel_multiplier; | ||
| 444 | input_report_rel(counter->dev, REL_WHEEL_HI_RES, hi_res_value); | ||
| 445 | |||
| 446 | remainder = counter->remainder; | ||
| 447 | direction = hi_res_value > 0 ? 1 : -1; | ||
| 448 | |||
| 449 | now = sched_clock(); | ||
| 450 | previous = counter->last_time; | ||
| 451 | counter->last_time = now; | ||
| 452 | /* | ||
| 453 | * Reset the remainder after a period of inactivity or when the | ||
| 454 | * direction changes. This prevents the REL_WHEEL emulation point | ||
| 455 | * from sliding for devices that don't always provide the same | ||
| 456 | * number of movements per detent. | ||
| 457 | */ | ||
| 458 | if (now - previous > 1000000000 || direction != counter->direction) | ||
| 459 | remainder = 0; | ||
| 460 | |||
| 461 | counter->direction = direction; | ||
| 462 | remainder += hi_res_value; | ||
| 463 | |||
| 464 | /* Some wheels will rest 7/8ths of a detent from the previous detent | ||
| 465 | * after slow movement, so we want the threshold for low-res events to | ||
| 466 | * be in the middle between two detents (e.g. after 4/8ths) as | ||
| 467 | * opposed to on the detents themselves (8/8ths). | ||
| 468 | */ | ||
| 469 | if (abs(remainder) >= 60) { | ||
| 470 | /* Add (or subtract) 1 because we want to trigger when the wheel | ||
| 471 | * is half-way to the next detent (i.e. scroll 1 detent after a | ||
| 472 | * 1/2 detent movement, 2 detents after a 1 1/2 detent movement, | ||
| 473 | * etc.). | ||
| 474 | */ | ||
| 475 | low_res_value = remainder / 120; | ||
| 476 | if (low_res_value == 0) | ||
| 477 | low_res_value = (hi_res_value > 0 ? 1 : -1); | ||
| 478 | input_report_rel(counter->dev, REL_WHEEL, low_res_value); | ||
| 479 | remainder -= low_res_value * 120; | ||
| 480 | } | ||
| 481 | counter->remainder = remainder; | ||
| 482 | } | ||
| 483 | |||
| 394 | /* -------------------------------------------------------------------------- */ | 484 | /* -------------------------------------------------------------------------- */ |
| 395 | /* HIDP++ 1.0 commands */ | 485 | /* HIDP++ 1.0 commands */ |
| 396 | /* -------------------------------------------------------------------------- */ | 486 | /* -------------------------------------------------------------------------- */ |
| @@ -1158,6 +1248,99 @@ static int hidpp_battery_get_property(struct power_supply *psy, | |||
| 1158 | } | 1248 | } |
| 1159 | 1249 | ||
| 1160 | /* -------------------------------------------------------------------------- */ | 1250 | /* -------------------------------------------------------------------------- */ |
| 1251 | /* 0x2120: Hi-resolution scrolling */ | ||
| 1252 | /* -------------------------------------------------------------------------- */ | ||
| 1253 | |||
| 1254 | #define HIDPP_PAGE_HI_RESOLUTION_SCROLLING 0x2120 | ||
| 1255 | |||
| 1256 | #define CMD_HI_RESOLUTION_SCROLLING_SET_HIGHRES_SCROLLING_MODE 0x10 | ||
| 1257 | |||
| 1258 | static int hidpp_hrs_set_highres_scrolling_mode(struct hidpp_device *hidpp, | ||
| 1259 | bool enabled, u8 *multiplier) | ||
| 1260 | { | ||
| 1261 | u8 feature_index; | ||
| 1262 | u8 feature_type; | ||
| 1263 | int ret; | ||
| 1264 | u8 params[1]; | ||
| 1265 | struct hidpp_report response; | ||
| 1266 | |||
| 1267 | ret = hidpp_root_get_feature(hidpp, | ||
| 1268 | HIDPP_PAGE_HI_RESOLUTION_SCROLLING, | ||
| 1269 | &feature_index, | ||
| 1270 | &feature_type); | ||
| 1271 | if (ret) | ||
| 1272 | return ret; | ||
| 1273 | |||
| 1274 | params[0] = enabled ? BIT(0) : 0; | ||
| 1275 | ret = hidpp_send_fap_command_sync(hidpp, feature_index, | ||
| 1276 | CMD_HI_RESOLUTION_SCROLLING_SET_HIGHRES_SCROLLING_MODE, | ||
| 1277 | params, sizeof(params), &response); | ||
| 1278 | if (ret) | ||
| 1279 | return ret; | ||
| 1280 | *multiplier = response.fap.params[1]; | ||
| 1281 | return 0; | ||
| 1282 | } | ||
| 1283 | |||
| 1284 | /* -------------------------------------------------------------------------- */ | ||
| 1285 | /* 0x2121: HiRes Wheel */ | ||
| 1286 | /* -------------------------------------------------------------------------- */ | ||
| 1287 | |||
| 1288 | #define HIDPP_PAGE_HIRES_WHEEL 0x2121 | ||
| 1289 | |||
| 1290 | #define CMD_HIRES_WHEEL_GET_WHEEL_CAPABILITY 0x00 | ||
| 1291 | #define CMD_HIRES_WHEEL_SET_WHEEL_MODE 0x20 | ||
| 1292 | |||
| 1293 | static int hidpp_hrw_get_wheel_capability(struct hidpp_device *hidpp, | ||
| 1294 | u8 *multiplier) | ||
| 1295 | { | ||
| 1296 | u8 feature_index; | ||
| 1297 | u8 feature_type; | ||
| 1298 | int ret; | ||
| 1299 | struct hidpp_report response; | ||
| 1300 | |||
| 1301 | ret = hidpp_root_get_feature(hidpp, HIDPP_PAGE_HIRES_WHEEL, | ||
| 1302 | &feature_index, &feature_type); | ||
| 1303 | if (ret) | ||
| 1304 | goto return_default; | ||
| 1305 | |||
| 1306 | ret = hidpp_send_fap_command_sync(hidpp, feature_index, | ||
| 1307 | CMD_HIRES_WHEEL_GET_WHEEL_CAPABILITY, | ||
| 1308 | NULL, 0, &response); | ||
| 1309 | if (ret) | ||
| 1310 | goto return_default; | ||
| 1311 | |||
| 1312 | *multiplier = response.fap.params[0]; | ||
| 1313 | return 0; | ||
| 1314 | return_default: | ||
| 1315 | hid_warn(hidpp->hid_dev, | ||
| 1316 | "Couldn't get wheel multiplier (error %d)\n", ret); | ||
| 1317 | return ret; | ||
| 1318 | } | ||
| 1319 | |||
| 1320 | static int hidpp_hrw_set_wheel_mode(struct hidpp_device *hidpp, bool invert, | ||
| 1321 | bool high_resolution, bool use_hidpp) | ||
| 1322 | { | ||
| 1323 | u8 feature_index; | ||
| 1324 | u8 feature_type; | ||
| 1325 | int ret; | ||
| 1326 | u8 params[1]; | ||
| 1327 | struct hidpp_report response; | ||
| 1328 | |||
| 1329 | ret = hidpp_root_get_feature(hidpp, HIDPP_PAGE_HIRES_WHEEL, | ||
| 1330 | &feature_index, &feature_type); | ||
| 1331 | if (ret) | ||
| 1332 | return ret; | ||
| 1333 | |||
| 1334 | params[0] = (invert ? BIT(2) : 0) | | ||
| 1335 | (high_resolution ? BIT(1) : 0) | | ||
| 1336 | (use_hidpp ? BIT(0) : 0); | ||
| 1337 | |||
| 1338 | return hidpp_send_fap_command_sync(hidpp, feature_index, | ||
| 1339 | CMD_HIRES_WHEEL_SET_WHEEL_MODE, | ||
| 1340 | params, sizeof(params), &response); | ||
| 1341 | } | ||
| 1342 | |||
| 1343 | /* -------------------------------------------------------------------------- */ | ||
| 1161 | /* 0x4301: Solar Keyboard */ | 1344 | /* 0x4301: Solar Keyboard */ |
| 1162 | /* -------------------------------------------------------------------------- */ | 1345 | /* -------------------------------------------------------------------------- */ |
| 1163 | 1346 | ||
| @@ -2408,10 +2591,15 @@ static int m560_raw_event(struct hid_device *hdev, u8 *data, int size) | |||
| 2408 | input_report_key(mydata->input, BTN_RIGHT, | 2591 | input_report_key(mydata->input, BTN_RIGHT, |
| 2409 | !!(data[1] & M560_MOUSE_BTN_RIGHT)); | 2592 | !!(data[1] & M560_MOUSE_BTN_RIGHT)); |
| 2410 | 2593 | ||
| 2411 | if (data[1] & M560_MOUSE_BTN_WHEEL_LEFT) | 2594 | if (data[1] & M560_MOUSE_BTN_WHEEL_LEFT) { |
| 2412 | input_report_rel(mydata->input, REL_HWHEEL, -1); | 2595 | input_report_rel(mydata->input, REL_HWHEEL, -1); |
| 2413 | else if (data[1] & M560_MOUSE_BTN_WHEEL_RIGHT) | 2596 | input_report_rel(mydata->input, REL_HWHEEL_HI_RES, |
| 2597 | -120); | ||
| 2598 | } else if (data[1] & M560_MOUSE_BTN_WHEEL_RIGHT) { | ||
| 2414 | input_report_rel(mydata->input, REL_HWHEEL, 1); | 2599 | input_report_rel(mydata->input, REL_HWHEEL, 1); |
| 2600 | input_report_rel(mydata->input, REL_HWHEEL_HI_RES, | ||
| 2601 | 120); | ||
| 2602 | } | ||
| 2415 | 2603 | ||
| 2416 | v = hid_snto32(hid_field_extract(hdev, data+3, 0, 12), 12); | 2604 | v = hid_snto32(hid_field_extract(hdev, data+3, 0, 12), 12); |
| 2417 | input_report_rel(mydata->input, REL_X, v); | 2605 | input_report_rel(mydata->input, REL_X, v); |
| @@ -2420,7 +2608,8 @@ static int m560_raw_event(struct hid_device *hdev, u8 *data, int size) | |||
| 2420 | input_report_rel(mydata->input, REL_Y, v); | 2608 | input_report_rel(mydata->input, REL_Y, v); |
| 2421 | 2609 | ||
| 2422 | v = hid_snto32(data[6], 8); | 2610 | v = hid_snto32(data[6], 8); |
| 2423 | input_report_rel(mydata->input, REL_WHEEL, v); | 2611 | hidpp_scroll_counter_handle_scroll( |
| 2612 | &hidpp->vertical_wheel_counter, v); | ||
| 2424 | 2613 | ||
| 2425 | input_sync(mydata->input); | 2614 | input_sync(mydata->input); |
| 2426 | } | 2615 | } |
| @@ -2447,6 +2636,8 @@ static void m560_populate_input(struct hidpp_device *hidpp, | |||
| 2447 | __set_bit(REL_Y, mydata->input->relbit); | 2636 | __set_bit(REL_Y, mydata->input->relbit); |
| 2448 | __set_bit(REL_WHEEL, mydata->input->relbit); | 2637 | __set_bit(REL_WHEEL, mydata->input->relbit); |
| 2449 | __set_bit(REL_HWHEEL, mydata->input->relbit); | 2638 | __set_bit(REL_HWHEEL, mydata->input->relbit); |
| 2639 | __set_bit(REL_WHEEL_HI_RES, mydata->input->relbit); | ||
| 2640 | __set_bit(REL_HWHEEL_HI_RES, mydata->input->relbit); | ||
| 2450 | } | 2641 | } |
| 2451 | 2642 | ||
| 2452 | static int m560_input_mapping(struct hid_device *hdev, struct hid_input *hi, | 2643 | static int m560_input_mapping(struct hid_device *hdev, struct hid_input *hi, |
| @@ -2549,6 +2740,37 @@ static int g920_get_config(struct hidpp_device *hidpp) | |||
| 2549 | } | 2740 | } |
| 2550 | 2741 | ||
| 2551 | /* -------------------------------------------------------------------------- */ | 2742 | /* -------------------------------------------------------------------------- */ |
| 2743 | /* High-resolution scroll wheels */ | ||
| 2744 | /* -------------------------------------------------------------------------- */ | ||
| 2745 | |||
| 2746 | static int hi_res_scroll_enable(struct hidpp_device *hidpp) | ||
| 2747 | { | ||
| 2748 | int ret; | ||
| 2749 | u8 multiplier = 1; | ||
| 2750 | |||
| 2751 | if (hidpp->quirks & HIDPP_QUIRK_HI_RES_SCROLL_X2121) { | ||
| 2752 | ret = hidpp_hrw_set_wheel_mode(hidpp, false, true, false); | ||
| 2753 | if (ret == 0) | ||
| 2754 | ret = hidpp_hrw_get_wheel_capability(hidpp, &multiplier); | ||
| 2755 | } else if (hidpp->quirks & HIDPP_QUIRK_HI_RES_SCROLL_X2120) { | ||
| 2756 | ret = hidpp_hrs_set_highres_scrolling_mode(hidpp, true, | ||
| 2757 | &multiplier); | ||
| 2758 | } else /* if (hidpp->quirks & HIDPP_QUIRK_HI_RES_SCROLL_1P0) */ { | ||
| 2759 | ret = hidpp10_enable_scrolling_acceleration(hidpp); | ||
| 2760 | multiplier = 8; | ||
| 2761 | } | ||
| 2762 | if (ret) | ||
| 2763 | return ret; | ||
| 2764 | |||
| 2765 | if (multiplier == 0) | ||
| 2766 | multiplier = 1; | ||
| 2767 | |||
| 2768 | hidpp->vertical_wheel_counter.wheel_multiplier = multiplier; | ||
| 2769 | hid_info(hidpp->hid_dev, "multiplier = %d\n", multiplier); | ||
| 2770 | return 0; | ||
| 2771 | } | ||
| 2772 | |||
| 2773 | /* -------------------------------------------------------------------------- */ | ||
| 2552 | /* Generic HID++ devices */ | 2774 | /* Generic HID++ devices */ |
| 2553 | /* -------------------------------------------------------------------------- */ | 2775 | /* -------------------------------------------------------------------------- */ |
| 2554 | 2776 | ||
| @@ -2593,6 +2815,9 @@ static void hidpp_populate_input(struct hidpp_device *hidpp, | |||
| 2593 | wtp_populate_input(hidpp, input, origin_is_hid_core); | 2815 | wtp_populate_input(hidpp, input, origin_is_hid_core); |
| 2594 | else if (hidpp->quirks & HIDPP_QUIRK_CLASS_M560) | 2816 | else if (hidpp->quirks & HIDPP_QUIRK_CLASS_M560) |
| 2595 | m560_populate_input(hidpp, input, origin_is_hid_core); | 2817 | m560_populate_input(hidpp, input, origin_is_hid_core); |
| 2818 | |||
| 2819 | if (hidpp->quirks & HIDPP_QUIRK_HI_RES_SCROLL) | ||
| 2820 | hidpp->vertical_wheel_counter.dev = input; | ||
| 2596 | } | 2821 | } |
| 2597 | 2822 | ||
| 2598 | static int hidpp_input_configured(struct hid_device *hdev, | 2823 | static int hidpp_input_configured(struct hid_device *hdev, |
| @@ -2711,6 +2936,27 @@ static int hidpp_raw_event(struct hid_device *hdev, struct hid_report *report, | |||
| 2711 | return 0; | 2936 | return 0; |
| 2712 | } | 2937 | } |
| 2713 | 2938 | ||
| 2939 | static int hidpp_event(struct hid_device *hdev, struct hid_field *field, | ||
| 2940 | struct hid_usage *usage, __s32 value) | ||
| 2941 | { | ||
| 2942 | /* This function will only be called for scroll events, due to the | ||
| 2943 | * restriction imposed in hidpp_usages. | ||
| 2944 | */ | ||
| 2945 | struct hidpp_device *hidpp = hid_get_drvdata(hdev); | ||
| 2946 | struct hidpp_scroll_counter *counter = &hidpp->vertical_wheel_counter; | ||
| 2947 | /* A scroll event may occur before the multiplier has been retrieved or | ||
| 2948 | * the input device set, or high-res scroll enabling may fail. In such | ||
| 2949 | * cases we must return early (falling back to default behaviour) to | ||
| 2950 | * avoid a crash in hidpp_scroll_counter_handle_scroll. | ||
| 2951 | */ | ||
| 2952 | if (!(hidpp->quirks & HIDPP_QUIRK_HI_RES_SCROLL) || value == 0 | ||
| 2953 | || counter->dev == NULL || counter->wheel_multiplier == 0) | ||
| 2954 | return 0; | ||
| 2955 | |||
| 2956 | hidpp_scroll_counter_handle_scroll(counter, value); | ||
| 2957 | return 1; | ||
| 2958 | } | ||
| 2959 | |||
| 2714 | static int hidpp_initialize_battery(struct hidpp_device *hidpp) | 2960 | static int hidpp_initialize_battery(struct hidpp_device *hidpp) |
| 2715 | { | 2961 | { |
| 2716 | static atomic_t battery_no = ATOMIC_INIT(0); | 2962 | static atomic_t battery_no = ATOMIC_INIT(0); |
| @@ -2922,6 +3168,9 @@ static void hidpp_connect_event(struct hidpp_device *hidpp) | |||
| 2922 | if (hidpp->battery.ps) | 3168 | if (hidpp->battery.ps) |
| 2923 | power_supply_changed(hidpp->battery.ps); | 3169 | power_supply_changed(hidpp->battery.ps); |
| 2924 | 3170 | ||
| 3171 | if (hidpp->quirks & HIDPP_QUIRK_HI_RES_SCROLL) | ||
| 3172 | hi_res_scroll_enable(hidpp); | ||
| 3173 | |||
| 2925 | if (!(hidpp->quirks & HIDPP_QUIRK_NO_HIDINPUT) || hidpp->delayed_input) | 3174 | if (!(hidpp->quirks & HIDPP_QUIRK_NO_HIDINPUT) || hidpp->delayed_input) |
| 2926 | /* if the input nodes are already created, we can stop now */ | 3175 | /* if the input nodes are already created, we can stop now */ |
| 2927 | return; | 3176 | return; |
| @@ -3107,6 +3356,10 @@ static void hidpp_remove(struct hid_device *hdev) | |||
| 3107 | mutex_destroy(&hidpp->send_mutex); | 3356 | mutex_destroy(&hidpp->send_mutex); |
| 3108 | } | 3357 | } |
| 3109 | 3358 | ||
| 3359 | #define LDJ_DEVICE(product) \ | ||
| 3360 | HID_DEVICE(BUS_USB, HID_GROUP_LOGITECH_DJ_DEVICE, \ | ||
| 3361 | USB_VENDOR_ID_LOGITECH, (product)) | ||
| 3362 | |||
| 3110 | static const struct hid_device_id hidpp_devices[] = { | 3363 | static const struct hid_device_id hidpp_devices[] = { |
| 3111 | { /* wireless touchpad */ | 3364 | { /* wireless touchpad */ |
| 3112 | HID_DEVICE(BUS_USB, HID_GROUP_LOGITECH_DJ_DEVICE, | 3365 | HID_DEVICE(BUS_USB, HID_GROUP_LOGITECH_DJ_DEVICE, |
| @@ -3121,10 +3374,39 @@ static const struct hid_device_id hidpp_devices[] = { | |||
| 3121 | HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, | 3374 | HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, |
| 3122 | USB_DEVICE_ID_LOGITECH_T651), | 3375 | USB_DEVICE_ID_LOGITECH_T651), |
| 3123 | .driver_data = HIDPP_QUIRK_CLASS_WTP }, | 3376 | .driver_data = HIDPP_QUIRK_CLASS_WTP }, |
| 3377 | { /* Mouse Logitech Anywhere MX */ | ||
| 3378 | LDJ_DEVICE(0x1017), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_1P0 }, | ||
| 3379 | { /* Mouse Logitech Cube */ | ||
| 3380 | LDJ_DEVICE(0x4010), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2120 }, | ||
| 3381 | { /* Mouse Logitech M335 */ | ||
| 3382 | LDJ_DEVICE(0x4050), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 }, | ||
| 3383 | { /* Mouse Logitech M515 */ | ||
| 3384 | LDJ_DEVICE(0x4007), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2120 }, | ||
| 3124 | { /* Mouse logitech M560 */ | 3385 | { /* Mouse logitech M560 */ |
| 3125 | HID_DEVICE(BUS_USB, HID_GROUP_LOGITECH_DJ_DEVICE, | 3386 | LDJ_DEVICE(0x402d), |
| 3126 | USB_VENDOR_ID_LOGITECH, 0x402d), | 3387 | .driver_data = HIDPP_QUIRK_DELAYED_INIT | HIDPP_QUIRK_CLASS_M560 |
| 3127 | .driver_data = HIDPP_QUIRK_DELAYED_INIT | HIDPP_QUIRK_CLASS_M560 }, | 3388 | | HIDPP_QUIRK_HI_RES_SCROLL_X2120 }, |
| 3389 | { /* Mouse Logitech M705 (firmware RQM17) */ | ||
| 3390 | LDJ_DEVICE(0x101b), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_1P0 }, | ||
| 3391 | { /* Mouse Logitech M705 (firmware RQM67) */ | ||
| 3392 | LDJ_DEVICE(0x406d), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 }, | ||
| 3393 | { /* Mouse Logitech M720 */ | ||
| 3394 | LDJ_DEVICE(0x405e), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 }, | ||
| 3395 | { /* Mouse Logitech MX Anywhere 2 */ | ||
| 3396 | LDJ_DEVICE(0x404a), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 }, | ||
| 3397 | { LDJ_DEVICE(0xb013), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 }, | ||
| 3398 | { LDJ_DEVICE(0xb018), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 }, | ||
| 3399 | { LDJ_DEVICE(0xb01f), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 }, | ||
| 3400 | { /* Mouse Logitech MX Anywhere 2S */ | ||
| 3401 | LDJ_DEVICE(0x406a), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 }, | ||
| 3402 | { /* Mouse Logitech MX Master */ | ||
| 3403 | LDJ_DEVICE(0x4041), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 }, | ||
| 3404 | { LDJ_DEVICE(0x4060), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 }, | ||
| 3405 | { LDJ_DEVICE(0x4071), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 }, | ||
| 3406 | { /* Mouse Logitech MX Master 2S */ | ||
| 3407 | LDJ_DEVICE(0x4069), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 }, | ||
| 3408 | { /* Mouse Logitech Performance MX */ | ||
| 3409 | LDJ_DEVICE(0x101a), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_1P0 }, | ||
| 3128 | { /* Keyboard logitech K400 */ | 3410 | { /* Keyboard logitech K400 */ |
| 3129 | HID_DEVICE(BUS_USB, HID_GROUP_LOGITECH_DJ_DEVICE, | 3411 | HID_DEVICE(BUS_USB, HID_GROUP_LOGITECH_DJ_DEVICE, |
| 3130 | USB_VENDOR_ID_LOGITECH, 0x4024), | 3412 | USB_VENDOR_ID_LOGITECH, 0x4024), |
| @@ -3144,12 +3426,19 @@ static const struct hid_device_id hidpp_devices[] = { | |||
| 3144 | 3426 | ||
| 3145 | MODULE_DEVICE_TABLE(hid, hidpp_devices); | 3427 | MODULE_DEVICE_TABLE(hid, hidpp_devices); |
| 3146 | 3428 | ||
| 3429 | static const struct hid_usage_id hidpp_usages[] = { | ||
| 3430 | { HID_GD_WHEEL, EV_REL, REL_WHEEL_HI_RES }, | ||
| 3431 | { HID_ANY_ID - 1, HID_ANY_ID - 1, HID_ANY_ID - 1} | ||
| 3432 | }; | ||
| 3433 | |||
| 3147 | static struct hid_driver hidpp_driver = { | 3434 | static struct hid_driver hidpp_driver = { |
| 3148 | .name = "logitech-hidpp-device", | 3435 | .name = "logitech-hidpp-device", |
| 3149 | .id_table = hidpp_devices, | 3436 | .id_table = hidpp_devices, |
| 3150 | .probe = hidpp_probe, | 3437 | .probe = hidpp_probe, |
| 3151 | .remove = hidpp_remove, | 3438 | .remove = hidpp_remove, |
| 3152 | .raw_event = hidpp_raw_event, | 3439 | .raw_event = hidpp_raw_event, |
| 3440 | .usage_table = hidpp_usages, | ||
| 3441 | .event = hidpp_event, | ||
| 3153 | .input_configured = hidpp_input_configured, | 3442 | .input_configured = hidpp_input_configured, |
| 3154 | .input_mapping = hidpp_input_mapping, | 3443 | .input_mapping = hidpp_input_mapping, |
| 3155 | .input_mapped = hidpp_input_mapped, | 3444 | .input_mapped = hidpp_input_mapped, |
