diff options
-rw-r--r-- | Documentation/input/event-codes.rst | 11 | ||||
-rw-r--r-- | drivers/hid/hid-input.c | 45 | ||||
-rw-r--r-- | drivers/hid/hid-logitech-hidpp.c | 309 | ||||
-rw-r--r-- | include/linux/hid.h | 28 | ||||
-rw-r--r-- | include/uapi/linux/input-event-codes.h | 18 |
5 files changed, 383 insertions, 28 deletions
diff --git a/Documentation/input/event-codes.rst b/Documentation/input/event-codes.rst index a8c0873beb95..cef220c176a4 100644 --- a/Documentation/input/event-codes.rst +++ b/Documentation/input/event-codes.rst | |||
@@ -190,7 +190,16 @@ A few EV_REL codes have special meanings: | |||
190 | * REL_WHEEL, REL_HWHEEL: | 190 | * REL_WHEEL, REL_HWHEEL: |
191 | 191 | ||
192 | - These codes are used for vertical and horizontal scroll wheels, | 192 | - These codes are used for vertical and horizontal scroll wheels, |
193 | respectively. | 193 | respectively. The value is the number of "notches" moved on the wheel, the |
194 | physical size of which varies by device. For high-resolution wheels (which | ||
195 | report multiple events for each notch of movement, or do not have notches) | ||
196 | this may be an approximation based on the high-resolution scroll events. | ||
197 | |||
198 | * REL_WHEEL_HI_RES: | ||
199 | |||
200 | - If a vertical scroll wheel supports high-resolution scrolling, this code | ||
201 | will be emitted in addition to REL_WHEEL. The value is the (approximate) | ||
202 | distance travelled by the user's finger, in microns. | ||
194 | 203 | ||
195 | EV_ABS | 204 | EV_ABS |
196 | ------ | 205 | ------ |
diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c index ad823a01bd65..567c3bf64515 100644 --- a/drivers/hid/hid-input.c +++ b/drivers/hid/hid-input.c | |||
@@ -1838,3 +1838,48 @@ void hidinput_disconnect(struct hid_device *hid) | |||
1838 | } | 1838 | } |
1839 | EXPORT_SYMBOL_GPL(hidinput_disconnect); | 1839 | EXPORT_SYMBOL_GPL(hidinput_disconnect); |
1840 | 1840 | ||
1841 | /** | ||
1842 | * hid_scroll_counter_handle_scroll() - Send high- and low-resolution scroll | ||
1843 | * events given a high-resolution wheel | ||
1844 | * movement. | ||
1845 | * @counter: a hid_scroll_counter struct describing the wheel. | ||
1846 | * @hi_res_value: the movement of the wheel, in the mouse's high-resolution | ||
1847 | * units. | ||
1848 | * | ||
1849 | * Given a high-resolution movement, this function converts the movement into | ||
1850 | * microns and emits high-resolution scroll events for the input device. It also | ||
1851 | * uses the multiplier from &struct hid_scroll_counter to emit low-resolution | ||
1852 | * scroll events when appropriate for backwards-compatibility with userspace | ||
1853 | * input libraries. | ||
1854 | */ | ||
1855 | void hid_scroll_counter_handle_scroll(struct hid_scroll_counter *counter, | ||
1856 | int hi_res_value) | ||
1857 | { | ||
1858 | int low_res_scroll_amount; | ||
1859 | /* Some wheels will rest 7/8ths of a notch from the previous notch | ||
1860 | * after slow movement, so we want the threshold for low-res events to | ||
1861 | * be in the middle of the notches (e.g. after 4/8ths) as opposed to on | ||
1862 | * the notches themselves (8/8ths). | ||
1863 | */ | ||
1864 | int threshold = counter->resolution_multiplier / 2; | ||
1865 | |||
1866 | input_report_rel(counter->dev, REL_WHEEL_HI_RES, | ||
1867 | hi_res_value * counter->microns_per_hi_res_unit); | ||
1868 | |||
1869 | counter->remainder += hi_res_value; | ||
1870 | if (abs(counter->remainder) >= threshold) { | ||
1871 | /* Add (or subtract) 1 because we want to trigger when the wheel | ||
1872 | * is half-way to the next notch (i.e. scroll 1 notch after a | ||
1873 | * 1/2 notch movement, 2 notches after a 1 1/2 notch movement, | ||
1874 | * etc.). | ||
1875 | */ | ||
1876 | low_res_scroll_amount = | ||
1877 | counter->remainder / counter->resolution_multiplier | ||
1878 | + (hi_res_value > 0 ? 1 : -1); | ||
1879 | input_report_rel(counter->dev, REL_WHEEL, | ||
1880 | low_res_scroll_amount); | ||
1881 | counter->remainder -= | ||
1882 | low_res_scroll_amount * counter->resolution_multiplier; | ||
1883 | } | ||
1884 | } | ||
1885 | EXPORT_SYMBOL_GPL(hid_scroll_counter_handle_scroll); | ||
diff --git a/drivers/hid/hid-logitech-hidpp.c b/drivers/hid/hid-logitech-hidpp.c index 19cc980eebce..f01280898b24 100644 --- a/drivers/hid/hid-logitech-hidpp.c +++ b/drivers/hid/hid-logitech-hidpp.c | |||
@@ -64,6 +64,14 @@ MODULE_PARM_DESC(disable_tap_to_click, | |||
64 | #define HIDPP_QUIRK_NO_HIDINPUT BIT(23) | 64 | #define HIDPP_QUIRK_NO_HIDINPUT BIT(23) |
65 | #define HIDPP_QUIRK_FORCE_OUTPUT_REPORTS BIT(24) | 65 | #define HIDPP_QUIRK_FORCE_OUTPUT_REPORTS BIT(24) |
66 | #define HIDPP_QUIRK_UNIFYING BIT(25) | 66 | #define HIDPP_QUIRK_UNIFYING BIT(25) |
67 | #define HIDPP_QUIRK_HI_RES_SCROLL_1P0 BIT(26) | ||
68 | #define HIDPP_QUIRK_HI_RES_SCROLL_X2120 BIT(27) | ||
69 | #define HIDPP_QUIRK_HI_RES_SCROLL_X2121 BIT(28) | ||
70 | |||
71 | /* Convenience constant to check for any high-res support. */ | ||
72 | #define HIDPP_QUIRK_HI_RES_SCROLL (HIDPP_QUIRK_HI_RES_SCROLL_1P0 | \ | ||
73 | HIDPP_QUIRK_HI_RES_SCROLL_X2120 | \ | ||
74 | HIDPP_QUIRK_HI_RES_SCROLL_X2121) | ||
67 | 75 | ||
68 | #define HIDPP_QUIRK_DELAYED_INIT HIDPP_QUIRK_NO_HIDINPUT | 76 | #define HIDPP_QUIRK_DELAYED_INIT HIDPP_QUIRK_NO_HIDINPUT |
69 | 77 | ||
@@ -149,6 +157,7 @@ struct hidpp_device { | |||
149 | unsigned long capabilities; | 157 | unsigned long capabilities; |
150 | 158 | ||
151 | struct hidpp_battery battery; | 159 | struct hidpp_battery battery; |
160 | struct hid_scroll_counter vertical_wheel_counter; | ||
152 | }; | 161 | }; |
153 | 162 | ||
154 | /* HID++ 1.0 error codes */ | 163 | /* HID++ 1.0 error codes */ |
@@ -400,32 +409,53 @@ static void hidpp_prefix_name(char **name, int name_length) | |||
400 | #define HIDPP_SET_LONG_REGISTER 0x82 | 409 | #define HIDPP_SET_LONG_REGISTER 0x82 |
401 | #define HIDPP_GET_LONG_REGISTER 0x83 | 410 | #define HIDPP_GET_LONG_REGISTER 0x83 |
402 | 411 | ||
403 | #define HIDPP_REG_GENERAL 0x00 | 412 | /** |
404 | 413 | * hidpp10_set_register_bit() - Sets a single bit in a HID++ 1.0 register. | |
405 | static int hidpp10_enable_battery_reporting(struct hidpp_device *hidpp_dev) | 414 | * @hidpp_dev: the device to set the register on. |
415 | * @register_address: the address of the register to modify. | ||
416 | * @byte: the byte of the register to modify. Should be less than 3. | ||
417 | * Return: 0 if successful, otherwise a negative error code. | ||
418 | */ | ||
419 | static int hidpp10_set_register_bit(struct hidpp_device *hidpp_dev, | ||
420 | u8 register_address, u8 byte, u8 bit) | ||
406 | { | 421 | { |
407 | struct hidpp_report response; | 422 | struct hidpp_report response; |
408 | int ret; | 423 | int ret; |
409 | u8 params[3] = { 0 }; | 424 | u8 params[3] = { 0 }; |
410 | 425 | ||
411 | ret = hidpp_send_rap_command_sync(hidpp_dev, | 426 | ret = hidpp_send_rap_command_sync(hidpp_dev, |
412 | REPORT_ID_HIDPP_SHORT, | 427 | REPORT_ID_HIDPP_SHORT, |
413 | HIDPP_GET_REGISTER, | 428 | HIDPP_GET_REGISTER, |
414 | HIDPP_REG_GENERAL, | 429 | register_address, |
415 | NULL, 0, &response); | 430 | NULL, 0, &response); |
416 | if (ret) | 431 | if (ret) |
417 | return ret; | 432 | return ret; |
418 | 433 | ||
419 | memcpy(params, response.rap.params, 3); | 434 | memcpy(params, response.rap.params, 3); |
420 | 435 | ||
421 | /* Set the battery bit */ | 436 | params[byte] |= BIT(bit); |
422 | params[0] |= BIT(4); | ||
423 | 437 | ||
424 | return hidpp_send_rap_command_sync(hidpp_dev, | 438 | return hidpp_send_rap_command_sync(hidpp_dev, |
425 | REPORT_ID_HIDPP_SHORT, | 439 | REPORT_ID_HIDPP_SHORT, |
426 | HIDPP_SET_REGISTER, | 440 | HIDPP_SET_REGISTER, |
427 | HIDPP_REG_GENERAL, | 441 | register_address, |
428 | params, 3, &response); | 442 | params, 3, &response); |
443 | } | ||
444 | |||
445 | |||
446 | #define HIDPP_REG_GENERAL 0x00 | ||
447 | |||
448 | static int hidpp10_enable_battery_reporting(struct hidpp_device *hidpp_dev) | ||
449 | { | ||
450 | return hidpp10_set_register_bit(hidpp_dev, HIDPP_REG_GENERAL, 0, 4); | ||
451 | } | ||
452 | |||
453 | #define HIDPP_REG_FEATURES 0x01 | ||
454 | |||
455 | /* On HID++ 1.0 devices, high-res scroll was called "scrolling acceleration". */ | ||
456 | static int hidpp10_enable_scrolling_acceleration(struct hidpp_device *hidpp_dev) | ||
457 | { | ||
458 | return hidpp10_set_register_bit(hidpp_dev, HIDPP_REG_FEATURES, 0, 6); | ||
429 | } | 459 | } |
430 | 460 | ||
431 | #define HIDPP_REG_BATTERY_STATUS 0x07 | 461 | #define HIDPP_REG_BATTERY_STATUS 0x07 |
@@ -1137,6 +1167,100 @@ static int hidpp_battery_get_property(struct power_supply *psy, | |||
1137 | } | 1167 | } |
1138 | 1168 | ||
1139 | /* -------------------------------------------------------------------------- */ | 1169 | /* -------------------------------------------------------------------------- */ |
1170 | /* 0x2120: Hi-resolution scrolling */ | ||
1171 | /* -------------------------------------------------------------------------- */ | ||
1172 | |||
1173 | #define HIDPP_PAGE_HI_RESOLUTION_SCROLLING 0x2120 | ||
1174 | |||
1175 | #define CMD_HI_RESOLUTION_SCROLLING_SET_HIGHRES_SCROLLING_MODE 0x10 | ||
1176 | |||
1177 | static int hidpp_hrs_set_highres_scrolling_mode(struct hidpp_device *hidpp, | ||
1178 | bool enabled, u8 *multiplier) | ||
1179 | { | ||
1180 | u8 feature_index; | ||
1181 | u8 feature_type; | ||
1182 | int ret; | ||
1183 | u8 params[1]; | ||
1184 | struct hidpp_report response; | ||
1185 | |||
1186 | ret = hidpp_root_get_feature(hidpp, | ||
1187 | HIDPP_PAGE_HI_RESOLUTION_SCROLLING, | ||
1188 | &feature_index, | ||
1189 | &feature_type); | ||
1190 | if (ret) | ||
1191 | return ret; | ||
1192 | |||
1193 | params[0] = enabled ? BIT(0) : 0; | ||
1194 | ret = hidpp_send_fap_command_sync(hidpp, feature_index, | ||
1195 | CMD_HI_RESOLUTION_SCROLLING_SET_HIGHRES_SCROLLING_MODE, | ||
1196 | params, sizeof(params), &response); | ||
1197 | if (ret) | ||
1198 | return ret; | ||
1199 | *multiplier = response.fap.params[1]; | ||
1200 | return 0; | ||
1201 | } | ||
1202 | |||
1203 | /* -------------------------------------------------------------------------- */ | ||
1204 | /* 0x2121: HiRes Wheel */ | ||
1205 | /* -------------------------------------------------------------------------- */ | ||
1206 | |||
1207 | #define HIDPP_PAGE_HIRES_WHEEL 0x2121 | ||
1208 | |||
1209 | #define CMD_HIRES_WHEEL_GET_WHEEL_CAPABILITY 0x00 | ||
1210 | #define CMD_HIRES_WHEEL_SET_WHEEL_MODE 0x20 | ||
1211 | |||
1212 | static int hidpp_hrw_get_wheel_capability(struct hidpp_device *hidpp, | ||
1213 | u8 *multiplier) | ||
1214 | { | ||
1215 | u8 feature_index; | ||
1216 | u8 feature_type; | ||
1217 | int ret; | ||
1218 | struct hidpp_report response; | ||
1219 | |||
1220 | ret = hidpp_root_get_feature(hidpp, HIDPP_PAGE_HIRES_WHEEL, | ||
1221 | &feature_index, &feature_type); | ||
1222 | if (ret) | ||
1223 | goto return_default; | ||
1224 | |||
1225 | ret = hidpp_send_fap_command_sync(hidpp, feature_index, | ||
1226 | CMD_HIRES_WHEEL_GET_WHEEL_CAPABILITY, | ||
1227 | NULL, 0, &response); | ||
1228 | if (ret) | ||
1229 | goto return_default; | ||
1230 | |||
1231 | *multiplier = response.fap.params[0]; | ||
1232 | return 0; | ||
1233 | return_default: | ||
1234 | hid_warn(hidpp->hid_dev, | ||
1235 | "Couldn't get wheel multiplier (error %d), assuming %d.\n", | ||
1236 | ret, *multiplier); | ||
1237 | return ret; | ||
1238 | } | ||
1239 | |||
1240 | static int hidpp_hrw_set_wheel_mode(struct hidpp_device *hidpp, bool invert, | ||
1241 | bool high_resolution, bool use_hidpp) | ||
1242 | { | ||
1243 | u8 feature_index; | ||
1244 | u8 feature_type; | ||
1245 | int ret; | ||
1246 | u8 params[1]; | ||
1247 | struct hidpp_report response; | ||
1248 | |||
1249 | ret = hidpp_root_get_feature(hidpp, HIDPP_PAGE_HIRES_WHEEL, | ||
1250 | &feature_index, &feature_type); | ||
1251 | if (ret) | ||
1252 | return ret; | ||
1253 | |||
1254 | params[0] = (invert ? BIT(2) : 0) | | ||
1255 | (high_resolution ? BIT(1) : 0) | | ||
1256 | (use_hidpp ? BIT(0) : 0); | ||
1257 | |||
1258 | return hidpp_send_fap_command_sync(hidpp, feature_index, | ||
1259 | CMD_HIRES_WHEEL_SET_WHEEL_MODE, | ||
1260 | params, sizeof(params), &response); | ||
1261 | } | ||
1262 | |||
1263 | /* -------------------------------------------------------------------------- */ | ||
1140 | /* 0x4301: Solar Keyboard */ | 1264 | /* 0x4301: Solar Keyboard */ |
1141 | /* -------------------------------------------------------------------------- */ | 1265 | /* -------------------------------------------------------------------------- */ |
1142 | 1266 | ||
@@ -2399,7 +2523,8 @@ static int m560_raw_event(struct hid_device *hdev, u8 *data, int size) | |||
2399 | input_report_rel(mydata->input, REL_Y, v); | 2523 | input_report_rel(mydata->input, REL_Y, v); |
2400 | 2524 | ||
2401 | v = hid_snto32(data[6], 8); | 2525 | v = hid_snto32(data[6], 8); |
2402 | input_report_rel(mydata->input, REL_WHEEL, v); | 2526 | hid_scroll_counter_handle_scroll( |
2527 | &hidpp->vertical_wheel_counter, v); | ||
2403 | 2528 | ||
2404 | input_sync(mydata->input); | 2529 | input_sync(mydata->input); |
2405 | } | 2530 | } |
@@ -2528,6 +2653,72 @@ static int g920_get_config(struct hidpp_device *hidpp) | |||
2528 | } | 2653 | } |
2529 | 2654 | ||
2530 | /* -------------------------------------------------------------------------- */ | 2655 | /* -------------------------------------------------------------------------- */ |
2656 | /* High-resolution scroll wheels */ | ||
2657 | /* -------------------------------------------------------------------------- */ | ||
2658 | |||
2659 | /** | ||
2660 | * struct hi_res_scroll_info - Stores info on a device's high-res scroll wheel. | ||
2661 | * @product_id: the HID product ID of the device being described. | ||
2662 | * @microns_per_hi_res_unit: the distance moved by the user's finger for each | ||
2663 | * high-resolution unit reported by the device, in | ||
2664 | * 256ths of a millimetre. | ||
2665 | */ | ||
2666 | struct hi_res_scroll_info { | ||
2667 | __u32 product_id; | ||
2668 | int microns_per_hi_res_unit; | ||
2669 | }; | ||
2670 | |||
2671 | static struct hi_res_scroll_info hi_res_scroll_devices[] = { | ||
2672 | { /* Anywhere MX */ | ||
2673 | .product_id = 0x1017, .microns_per_hi_res_unit = 445 }, | ||
2674 | { /* Performance MX */ | ||
2675 | .product_id = 0x101a, .microns_per_hi_res_unit = 406 }, | ||
2676 | { /* M560 */ | ||
2677 | .product_id = 0x402d, .microns_per_hi_res_unit = 435 }, | ||
2678 | { /* MX Master 2S */ | ||
2679 | .product_id = 0x4069, .microns_per_hi_res_unit = 406 }, | ||
2680 | }; | ||
2681 | |||
2682 | static int hi_res_scroll_look_up_microns(__u32 product_id) | ||
2683 | { | ||
2684 | int i; | ||
2685 | int num_devices = sizeof(hi_res_scroll_devices) | ||
2686 | / sizeof(hi_res_scroll_devices[0]); | ||
2687 | for (i = 0; i < num_devices; i++) { | ||
2688 | if (hi_res_scroll_devices[i].product_id == product_id) | ||
2689 | return hi_res_scroll_devices[i].microns_per_hi_res_unit; | ||
2690 | } | ||
2691 | /* We don't have a value for this device, so use a sensible default. */ | ||
2692 | return 406; | ||
2693 | } | ||
2694 | |||
2695 | static int hi_res_scroll_enable(struct hidpp_device *hidpp) | ||
2696 | { | ||
2697 | int ret; | ||
2698 | u8 multiplier = 8; | ||
2699 | |||
2700 | if (hidpp->quirks & HIDPP_QUIRK_HI_RES_SCROLL_X2121) { | ||
2701 | ret = hidpp_hrw_set_wheel_mode(hidpp, false, true, false); | ||
2702 | hidpp_hrw_get_wheel_capability(hidpp, &multiplier); | ||
2703 | } else if (hidpp->quirks & HIDPP_QUIRK_HI_RES_SCROLL_X2120) { | ||
2704 | ret = hidpp_hrs_set_highres_scrolling_mode(hidpp, true, | ||
2705 | &multiplier); | ||
2706 | } else /* if (hidpp->quirks & HIDPP_QUIRK_HI_RES_SCROLL_1P0) */ | ||
2707 | ret = hidpp10_enable_scrolling_acceleration(hidpp); | ||
2708 | |||
2709 | if (ret) | ||
2710 | return ret; | ||
2711 | |||
2712 | hidpp->vertical_wheel_counter.resolution_multiplier = multiplier; | ||
2713 | hidpp->vertical_wheel_counter.microns_per_hi_res_unit = | ||
2714 | hi_res_scroll_look_up_microns(hidpp->hid_dev->product); | ||
2715 | hid_info(hidpp->hid_dev, "multiplier = %d, microns = %d\n", | ||
2716 | multiplier, | ||
2717 | hidpp->vertical_wheel_counter.microns_per_hi_res_unit); | ||
2718 | return 0; | ||
2719 | } | ||
2720 | |||
2721 | /* -------------------------------------------------------------------------- */ | ||
2531 | /* Generic HID++ devices */ | 2722 | /* Generic HID++ devices */ |
2532 | /* -------------------------------------------------------------------------- */ | 2723 | /* -------------------------------------------------------------------------- */ |
2533 | 2724 | ||
@@ -2572,6 +2763,11 @@ static void hidpp_populate_input(struct hidpp_device *hidpp, | |||
2572 | wtp_populate_input(hidpp, input, origin_is_hid_core); | 2763 | wtp_populate_input(hidpp, input, origin_is_hid_core); |
2573 | else if (hidpp->quirks & HIDPP_QUIRK_CLASS_M560) | 2764 | else if (hidpp->quirks & HIDPP_QUIRK_CLASS_M560) |
2574 | m560_populate_input(hidpp, input, origin_is_hid_core); | 2765 | m560_populate_input(hidpp, input, origin_is_hid_core); |
2766 | |||
2767 | if (hidpp->quirks & HIDPP_QUIRK_HI_RES_SCROLL) { | ||
2768 | input_set_capability(input, EV_REL, REL_WHEEL_HI_RES); | ||
2769 | hidpp->vertical_wheel_counter.dev = input; | ||
2770 | } | ||
2575 | } | 2771 | } |
2576 | 2772 | ||
2577 | static int hidpp_input_configured(struct hid_device *hdev, | 2773 | static int hidpp_input_configured(struct hid_device *hdev, |
@@ -2690,6 +2886,27 @@ static int hidpp_raw_event(struct hid_device *hdev, struct hid_report *report, | |||
2690 | return 0; | 2886 | return 0; |
2691 | } | 2887 | } |
2692 | 2888 | ||
2889 | static int hidpp_event(struct hid_device *hdev, struct hid_field *field, | ||
2890 | struct hid_usage *usage, __s32 value) | ||
2891 | { | ||
2892 | /* This function will only be called for scroll events, due to the | ||
2893 | * restriction imposed in hidpp_usages. | ||
2894 | */ | ||
2895 | struct hidpp_device *hidpp = hid_get_drvdata(hdev); | ||
2896 | struct hid_scroll_counter *counter = &hidpp->vertical_wheel_counter; | ||
2897 | /* A scroll event may occur before the multiplier has been retrieved or | ||
2898 | * the input device set, or high-res scroll enabling may fail. In such | ||
2899 | * cases we must return early (falling back to default behaviour) to | ||
2900 | * avoid a crash in hid_scroll_counter_handle_scroll. | ||
2901 | */ | ||
2902 | if (!(hidpp->quirks & HIDPP_QUIRK_HI_RES_SCROLL) || value == 0 | ||
2903 | || counter->dev == NULL || counter->resolution_multiplier == 0) | ||
2904 | return 0; | ||
2905 | |||
2906 | hid_scroll_counter_handle_scroll(counter, value); | ||
2907 | return 1; | ||
2908 | } | ||
2909 | |||
2693 | static int hidpp_initialize_battery(struct hidpp_device *hidpp) | 2910 | static int hidpp_initialize_battery(struct hidpp_device *hidpp) |
2694 | { | 2911 | { |
2695 | static atomic_t battery_no = ATOMIC_INIT(0); | 2912 | static atomic_t battery_no = ATOMIC_INIT(0); |
@@ -2901,6 +3118,9 @@ static void hidpp_connect_event(struct hidpp_device *hidpp) | |||
2901 | if (hidpp->battery.ps) | 3118 | if (hidpp->battery.ps) |
2902 | power_supply_changed(hidpp->battery.ps); | 3119 | power_supply_changed(hidpp->battery.ps); |
2903 | 3120 | ||
3121 | if (hidpp->quirks & HIDPP_QUIRK_HI_RES_SCROLL) | ||
3122 | hi_res_scroll_enable(hidpp); | ||
3123 | |||
2904 | if (!(hidpp->quirks & HIDPP_QUIRK_NO_HIDINPUT) || hidpp->delayed_input) | 3124 | if (!(hidpp->quirks & HIDPP_QUIRK_NO_HIDINPUT) || hidpp->delayed_input) |
2905 | /* if the input nodes are already created, we can stop now */ | 3125 | /* if the input nodes are already created, we can stop now */ |
2906 | return; | 3126 | return; |
@@ -3086,35 +3306,63 @@ static void hidpp_remove(struct hid_device *hdev) | |||
3086 | mutex_destroy(&hidpp->send_mutex); | 3306 | mutex_destroy(&hidpp->send_mutex); |
3087 | } | 3307 | } |
3088 | 3308 | ||
3309 | #define LDJ_DEVICE(product) \ | ||
3310 | HID_DEVICE(BUS_USB, HID_GROUP_LOGITECH_DJ_DEVICE, \ | ||
3311 | USB_VENDOR_ID_LOGITECH, (product)) | ||
3312 | |||
3089 | static const struct hid_device_id hidpp_devices[] = { | 3313 | static const struct hid_device_id hidpp_devices[] = { |
3090 | { /* wireless touchpad */ | 3314 | { /* wireless touchpad */ |
3091 | HID_DEVICE(BUS_USB, HID_GROUP_LOGITECH_DJ_DEVICE, | 3315 | LDJ_DEVICE(0x4011), |
3092 | USB_VENDOR_ID_LOGITECH, 0x4011), | ||
3093 | .driver_data = HIDPP_QUIRK_CLASS_WTP | HIDPP_QUIRK_DELAYED_INIT | | 3316 | .driver_data = HIDPP_QUIRK_CLASS_WTP | HIDPP_QUIRK_DELAYED_INIT | |
3094 | HIDPP_QUIRK_WTP_PHYSICAL_BUTTONS }, | 3317 | HIDPP_QUIRK_WTP_PHYSICAL_BUTTONS }, |
3095 | { /* wireless touchpad T650 */ | 3318 | { /* wireless touchpad T650 */ |
3096 | HID_DEVICE(BUS_USB, HID_GROUP_LOGITECH_DJ_DEVICE, | 3319 | LDJ_DEVICE(0x4101), |
3097 | USB_VENDOR_ID_LOGITECH, 0x4101), | ||
3098 | .driver_data = HIDPP_QUIRK_CLASS_WTP | HIDPP_QUIRK_DELAYED_INIT }, | 3320 | .driver_data = HIDPP_QUIRK_CLASS_WTP | HIDPP_QUIRK_DELAYED_INIT }, |
3099 | { /* wireless touchpad T651 */ | 3321 | { /* wireless touchpad T651 */ |
3100 | HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, | 3322 | HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, |
3101 | USB_DEVICE_ID_LOGITECH_T651), | 3323 | USB_DEVICE_ID_LOGITECH_T651), |
3102 | .driver_data = HIDPP_QUIRK_CLASS_WTP }, | 3324 | .driver_data = HIDPP_QUIRK_CLASS_WTP }, |
3325 | { /* Mouse Logitech Anywhere MX */ | ||
3326 | LDJ_DEVICE(0x1017), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_1P0 }, | ||
3327 | { /* Mouse Logitech Cube */ | ||
3328 | LDJ_DEVICE(0x4010), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2120 }, | ||
3329 | { /* Mouse Logitech M335 */ | ||
3330 | LDJ_DEVICE(0x4050), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 }, | ||
3331 | { /* Mouse Logitech M515 */ | ||
3332 | LDJ_DEVICE(0x4007), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2120 }, | ||
3103 | { /* Mouse logitech M560 */ | 3333 | { /* Mouse logitech M560 */ |
3104 | HID_DEVICE(BUS_USB, HID_GROUP_LOGITECH_DJ_DEVICE, | 3334 | LDJ_DEVICE(0x402d), |
3105 | USB_VENDOR_ID_LOGITECH, 0x402d), | 3335 | .driver_data = HIDPP_QUIRK_DELAYED_INIT | HIDPP_QUIRK_CLASS_M560 |
3106 | .driver_data = HIDPP_QUIRK_DELAYED_INIT | HIDPP_QUIRK_CLASS_M560 }, | 3336 | | HIDPP_QUIRK_HI_RES_SCROLL_X2120 }, |
3337 | { /* Mouse Logitech M705 (firmware RQM17) */ | ||
3338 | LDJ_DEVICE(0x101b), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_1P0 }, | ||
3339 | { /* Mouse Logitech M705 (firmware RQM67) */ | ||
3340 | LDJ_DEVICE(0x406d), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 }, | ||
3341 | { /* Mouse Logitech M720 */ | ||
3342 | LDJ_DEVICE(0x405e), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 }, | ||
3343 | { /* Mouse Logitech MX Anywhere 2 */ | ||
3344 | LDJ_DEVICE(0x404a), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 }, | ||
3345 | { LDJ_DEVICE(0xb013), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 }, | ||
3346 | { LDJ_DEVICE(0xb018), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 }, | ||
3347 | { LDJ_DEVICE(0xb01f), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 }, | ||
3348 | { /* Mouse Logitech MX Anywhere 2S */ | ||
3349 | LDJ_DEVICE(0x406a), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 }, | ||
3350 | { /* Mouse Logitech MX Master */ | ||
3351 | LDJ_DEVICE(0x4041), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 }, | ||
3352 | { LDJ_DEVICE(0x4060), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 }, | ||
3353 | { LDJ_DEVICE(0x4071), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 }, | ||
3354 | { /* Mouse Logitech MX Master 2S */ | ||
3355 | LDJ_DEVICE(0x4069), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 }, | ||
3356 | { /* Mouse Logitech Performance MX */ | ||
3357 | LDJ_DEVICE(0x101a), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_1P0 }, | ||
3107 | { /* Keyboard logitech K400 */ | 3358 | { /* Keyboard logitech K400 */ |
3108 | HID_DEVICE(BUS_USB, HID_GROUP_LOGITECH_DJ_DEVICE, | 3359 | LDJ_DEVICE(0x4024), |
3109 | USB_VENDOR_ID_LOGITECH, 0x4024), | ||
3110 | .driver_data = HIDPP_QUIRK_CLASS_K400 }, | 3360 | .driver_data = HIDPP_QUIRK_CLASS_K400 }, |
3111 | { /* Solar Keyboard Logitech K750 */ | 3361 | { /* Solar Keyboard Logitech K750 */ |
3112 | HID_DEVICE(BUS_USB, HID_GROUP_LOGITECH_DJ_DEVICE, | 3362 | LDJ_DEVICE(0x4002), |
3113 | USB_VENDOR_ID_LOGITECH, 0x4002), | ||
3114 | .driver_data = HIDPP_QUIRK_CLASS_K750 }, | 3363 | .driver_data = HIDPP_QUIRK_CLASS_K750 }, |
3115 | 3364 | ||
3116 | { HID_DEVICE(BUS_USB, HID_GROUP_LOGITECH_DJ_DEVICE, | 3365 | { LDJ_DEVICE(HID_ANY_ID) }, |
3117 | USB_VENDOR_ID_LOGITECH, HID_ANY_ID)}, | ||
3118 | 3366 | ||
3119 | { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G920_WHEEL), | 3367 | { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G920_WHEEL), |
3120 | .driver_data = HIDPP_QUIRK_CLASS_G920 | HIDPP_QUIRK_FORCE_OUTPUT_REPORTS}, | 3368 | .driver_data = HIDPP_QUIRK_CLASS_G920 | HIDPP_QUIRK_FORCE_OUTPUT_REPORTS}, |
@@ -3123,12 +3371,19 @@ static const struct hid_device_id hidpp_devices[] = { | |||
3123 | 3371 | ||
3124 | MODULE_DEVICE_TABLE(hid, hidpp_devices); | 3372 | MODULE_DEVICE_TABLE(hid, hidpp_devices); |
3125 | 3373 | ||
3374 | static const struct hid_usage_id hidpp_usages[] = { | ||
3375 | { HID_GD_WHEEL, EV_REL, REL_WHEEL }, | ||
3376 | { HID_ANY_ID - 1, HID_ANY_ID - 1, HID_ANY_ID - 1} | ||
3377 | }; | ||
3378 | |||
3126 | static struct hid_driver hidpp_driver = { | 3379 | static struct hid_driver hidpp_driver = { |
3127 | .name = "logitech-hidpp-device", | 3380 | .name = "logitech-hidpp-device", |
3128 | .id_table = hidpp_devices, | 3381 | .id_table = hidpp_devices, |
3129 | .probe = hidpp_probe, | 3382 | .probe = hidpp_probe, |
3130 | .remove = hidpp_remove, | 3383 | .remove = hidpp_remove, |
3131 | .raw_event = hidpp_raw_event, | 3384 | .raw_event = hidpp_raw_event, |
3385 | .usage_table = hidpp_usages, | ||
3386 | .event = hidpp_event, | ||
3132 | .input_configured = hidpp_input_configured, | 3387 | .input_configured = hidpp_input_configured, |
3133 | .input_mapping = hidpp_input_mapping, | 3388 | .input_mapping = hidpp_input_mapping, |
3134 | .input_mapped = hidpp_input_mapped, | 3389 | .input_mapped = hidpp_input_mapped, |
diff --git a/include/linux/hid.h b/include/linux/hid.h index d44a78362942..2827b87590d8 100644 --- a/include/linux/hid.h +++ b/include/linux/hid.h | |||
@@ -1139,6 +1139,34 @@ static inline u32 hid_report_len(struct hid_report *report) | |||
1139 | int hid_report_raw_event(struct hid_device *hid, int type, u8 *data, u32 size, | 1139 | int hid_report_raw_event(struct hid_device *hid, int type, u8 *data, u32 size, |
1140 | int interrupt); | 1140 | int interrupt); |
1141 | 1141 | ||
1142 | |||
1143 | /** | ||
1144 | * struct hid_scroll_counter - Utility class for processing high-resolution | ||
1145 | * scroll events. | ||
1146 | * @dev: the input device for which events should be reported. | ||
1147 | * @microns_per_hi_res_unit: the amount moved by the user's finger for each | ||
1148 | * high-resolution unit reported by the mouse, in | ||
1149 | * microns. | ||
1150 | * @resolution_multiplier: the wheel's resolution in high-resolution mode as a | ||
1151 | * multiple of its lower resolution. For example, if | ||
1152 | * moving the wheel by one "notch" would result in a | ||
1153 | * value of 1 in low-resolution mode but 8 in | ||
1154 | * high-resolution, the multiplier is 8. | ||
1155 | * @remainder: counts the number of high-resolution units moved since the last | ||
1156 | * low-resolution event (REL_WHEEL or REL_HWHEEL) was sent. Should | ||
1157 | * only be used by class methods. | ||
1158 | */ | ||
1159 | struct hid_scroll_counter { | ||
1160 | struct input_dev *dev; | ||
1161 | int microns_per_hi_res_unit; | ||
1162 | int resolution_multiplier; | ||
1163 | |||
1164 | int remainder; | ||
1165 | }; | ||
1166 | |||
1167 | void hid_scroll_counter_handle_scroll(struct hid_scroll_counter *counter, | ||
1168 | int hi_res_value); | ||
1169 | |||
1142 | /* HID quirks API */ | 1170 | /* HID quirks API */ |
1143 | unsigned long hid_lookup_quirk(const struct hid_device *hdev); | 1171 | unsigned long hid_lookup_quirk(const struct hid_device *hdev); |
1144 | int hid_quirks_init(char **quirks_param, __u16 bus, int count); | 1172 | int hid_quirks_init(char **quirks_param, __u16 bus, int count); |
diff --git a/include/uapi/linux/input-event-codes.h b/include/uapi/linux/input-event-codes.h index 53fbae27b280..6d180cc60a5d 100644 --- a/include/uapi/linux/input-event-codes.h +++ b/include/uapi/linux/input-event-codes.h | |||
@@ -708,6 +708,15 @@ | |||
708 | #define REL_DIAL 0x07 | 708 | #define REL_DIAL 0x07 |
709 | #define REL_WHEEL 0x08 | 709 | #define REL_WHEEL 0x08 |
710 | #define REL_MISC 0x09 | 710 | #define REL_MISC 0x09 |
711 | /* | ||
712 | * 0x0a is reserved and should not be used in input drivers. | ||
713 | * It was used by HID as REL_MISC+1 and userspace needs to detect if | ||
714 | * the next REL_* event is correct or is just REL_MISC + n. | ||
715 | * We define here REL_RESERVED so userspace can rely on it and detect | ||
716 | * the situation described above. | ||
717 | */ | ||
718 | #define REL_RESERVED 0x0a | ||
719 | #define REL_WHEEL_HI_RES 0x0b | ||
711 | #define REL_MAX 0x0f | 720 | #define REL_MAX 0x0f |
712 | #define REL_CNT (REL_MAX+1) | 721 | #define REL_CNT (REL_MAX+1) |
713 | 722 | ||
@@ -744,6 +753,15 @@ | |||
744 | 753 | ||
745 | #define ABS_MISC 0x28 | 754 | #define ABS_MISC 0x28 |
746 | 755 | ||
756 | /* | ||
757 | * 0x2e is reserved and should not be used in input drivers. | ||
758 | * It was used by HID as ABS_MISC+6 and userspace needs to detect if | ||
759 | * the next ABS_* event is correct or is just ABS_MISC + n. | ||
760 | * We define here ABS_RESERVED so userspace can rely on it and detect | ||
761 | * the situation described above. | ||
762 | */ | ||
763 | #define ABS_RESERVED 0x2e | ||
764 | |||
747 | #define ABS_MT_SLOT 0x2f /* MT slot being modified */ | 765 | #define ABS_MT_SLOT 0x2f /* MT slot being modified */ |
748 | #define ABS_MT_TOUCH_MAJOR 0x30 /* Major axis of touching ellipse */ | 766 | #define ABS_MT_TOUCH_MAJOR 0x30 /* Major axis of touching ellipse */ |
749 | #define ABS_MT_TOUCH_MINOR 0x31 /* Minor axis (omit if circular) */ | 767 | #define ABS_MT_TOUCH_MINOR 0x31 /* Minor axis (omit if circular) */ |