@@ -64,6 +64,14 @@ MODULE_PARM_DESC(disable_tap_to_click,
64
64
#define HIDPP_QUIRK_NO_HIDINPUT BIT(23)
65
65
#define HIDPP_QUIRK_FORCE_OUTPUT_REPORTS BIT(24)
66
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
76
#define HIDPP_QUIRK_DELAYED_INIT HIDPP_QUIRK_NO_HIDINPUT
69
77
@@ -149,6 +157,7 @@ struct hidpp_device {
149
157
unsigned long capabilities ;
150
158
151
159
struct hidpp_battery battery ;
160
+ struct hid_scroll_counter vertical_wheel_counter ;
152
161
};
153
162
154
163
/* HID++ 1.0 error codes */
@@ -1157,6 +1166,101 @@ static int hidpp_battery_get_property(struct power_supply *psy,
1157
1166
return ret ;
1158
1167
}
1159
1168
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
+ * multiplier = 8 ;
1235
+ hid_warn (hidpp -> hid_dev ,
1236
+ "Couldn't get wheel multiplier (error %d), assuming %d.\n" ,
1237
+ ret , * multiplier );
1238
+ return ret ;
1239
+ }
1240
+
1241
+ static int hidpp_hrw_set_wheel_mode (struct hidpp_device * hidpp , bool invert ,
1242
+ bool high_resolution , bool use_hidpp )
1243
+ {
1244
+ u8 feature_index ;
1245
+ u8 feature_type ;
1246
+ int ret ;
1247
+ u8 params [1 ];
1248
+ struct hidpp_report response ;
1249
+
1250
+ ret = hidpp_root_get_feature (hidpp , HIDPP_PAGE_HIRES_WHEEL ,
1251
+ & feature_index , & feature_type );
1252
+ if (ret )
1253
+ return ret ;
1254
+
1255
+ params [0 ] = (invert ? BIT (2 ) : 0 ) |
1256
+ (high_resolution ? BIT (1 ) : 0 ) |
1257
+ (use_hidpp ? BIT (0 ) : 0 );
1258
+
1259
+ return hidpp_send_fap_command_sync (hidpp , feature_index ,
1260
+ CMD_HIRES_WHEEL_SET_WHEEL_MODE ,
1261
+ params , sizeof (params ), & response );
1262
+ }
1263
+
1160
1264
/* -------------------------------------------------------------------------- */
1161
1265
/* 0x4301: Solar Keyboard */
1162
1266
/* -------------------------------------------------------------------------- */
@@ -2420,7 +2524,8 @@ static int m560_raw_event(struct hid_device *hdev, u8 *data, int size)
2420
2524
input_report_rel (mydata -> input , REL_Y , v );
2421
2525
2422
2526
v = hid_snto32 (data [6 ], 8 );
2423
- input_report_rel (mydata -> input , REL_WHEEL , v );
2527
+ hid_scroll_counter_handle_scroll (
2528
+ & hidpp -> vertical_wheel_counter , v );
2424
2529
2425
2530
input_sync (mydata -> input );
2426
2531
}
@@ -2548,6 +2653,73 @@ static int g920_get_config(struct hidpp_device *hidpp)
2548
2653
return 0 ;
2549
2654
}
2550
2655
2656
+ /* -------------------------------------------------------------------------- */
2657
+ /* High-resolution scroll wheels */
2658
+ /* -------------------------------------------------------------------------- */
2659
+
2660
+ /**
2661
+ * struct hi_res_scroll_info - Stores info on a device's high-res scroll wheel.
2662
+ * @product_id: the HID product ID of the device being described.
2663
+ * @microns_per_hi_res_unit: the distance moved by the user's finger for each
2664
+ * high-resolution unit reported by the device, in
2665
+ * 256ths of a millimetre.
2666
+ */
2667
+ struct hi_res_scroll_info {
2668
+ __u32 product_id ;
2669
+ int microns_per_hi_res_unit ;
2670
+ };
2671
+
2672
+ static struct hi_res_scroll_info hi_res_scroll_devices [] = {
2673
+ { /* Anywhere MX */
2674
+ .product_id = 0x1017 , .microns_per_hi_res_unit = 445 },
2675
+ { /* Performance MX */
2676
+ .product_id = 0x101a , .microns_per_hi_res_unit = 406 },
2677
+ { /* M560 */
2678
+ .product_id = 0x402d , .microns_per_hi_res_unit = 435 },
2679
+ { /* MX Master 2S */
2680
+ .product_id = 0x4069 , .microns_per_hi_res_unit = 406 },
2681
+ };
2682
+
2683
+ static int hi_res_scroll_look_up_microns (__u32 product_id )
2684
+ {
2685
+ int i ;
2686
+ int num_devices = sizeof (hi_res_scroll_devices )
2687
+ / sizeof (hi_res_scroll_devices [0 ]);
2688
+ for (i = 0 ; i < num_devices ; i ++ ) {
2689
+ if (hi_res_scroll_devices [i ].product_id == product_id )
2690
+ return hi_res_scroll_devices [i ].microns_per_hi_res_unit ;
2691
+ }
2692
+ /* We don't have a value for this device, so use a sensible default. */
2693
+ return 406 ;
2694
+ }
2695
+
2696
+ static int hi_res_scroll_enable (struct hidpp_device * hidpp )
2697
+ {
2698
+ int ret ;
2699
+ u8 multiplier ;
2700
+
2701
+ if (hidpp -> quirks & HIDPP_QUIRK_HI_RES_SCROLL_X2121 ) {
2702
+ ret = hidpp_hrw_set_wheel_mode (hidpp , false, true, false);
2703
+ hidpp_hrw_get_wheel_capability (hidpp , & multiplier );
2704
+ } else if (hidpp -> quirks & HIDPP_QUIRK_HI_RES_SCROLL_X2120 ) {
2705
+ ret = hidpp_hrs_set_highres_scrolling_mode (hidpp , true,
2706
+ & multiplier );
2707
+ } else /* if (hidpp->quirks & HIDPP_QUIRK_HI_RES_SCROLL_1P0) */ {
2708
+ ret = hidpp10_enable_scrolling_acceleration (hidpp );
2709
+ multiplier = 8 ;
2710
+ }
2711
+ if (ret )
2712
+ return ret ;
2713
+
2714
+ hidpp -> vertical_wheel_counter .resolution_multiplier = multiplier ;
2715
+ hidpp -> vertical_wheel_counter .microns_per_hi_res_unit =
2716
+ hi_res_scroll_look_up_microns (hidpp -> hid_dev -> product );
2717
+ hid_info (hidpp -> hid_dev , "multiplier = %d, microns = %d\n" ,
2718
+ multiplier ,
2719
+ hidpp -> vertical_wheel_counter .microns_per_hi_res_unit );
2720
+ return 0 ;
2721
+ }
2722
+
2551
2723
/* -------------------------------------------------------------------------- */
2552
2724
/* Generic HID++ devices */
2553
2725
/* -------------------------------------------------------------------------- */
@@ -2593,6 +2765,11 @@ static void hidpp_populate_input(struct hidpp_device *hidpp,
2593
2765
wtp_populate_input (hidpp , input , origin_is_hid_core );
2594
2766
else if (hidpp -> quirks & HIDPP_QUIRK_CLASS_M560 )
2595
2767
m560_populate_input (hidpp , input , origin_is_hid_core );
2768
+
2769
+ if (hidpp -> quirks & HIDPP_QUIRK_HI_RES_SCROLL ) {
2770
+ input_set_capability (input , EV_REL , REL_WHEEL_HI_RES );
2771
+ hidpp -> vertical_wheel_counter .dev = input ;
2772
+ }
2596
2773
}
2597
2774
2598
2775
static int hidpp_input_configured (struct hid_device * hdev ,
@@ -2711,6 +2888,27 @@ static int hidpp_raw_event(struct hid_device *hdev, struct hid_report *report,
2711
2888
return 0 ;
2712
2889
}
2713
2890
2891
+ static int hidpp_event (struct hid_device * hdev , struct hid_field * field ,
2892
+ struct hid_usage * usage , __s32 value )
2893
+ {
2894
+ /* This function will only be called for scroll events, due to the
2895
+ * restriction imposed in hidpp_usages.
2896
+ */
2897
+ struct hidpp_device * hidpp = hid_get_drvdata (hdev );
2898
+ struct hid_scroll_counter * counter = & hidpp -> vertical_wheel_counter ;
2899
+ /* A scroll event may occur before the multiplier has been retrieved or
2900
+ * the input device set, or high-res scroll enabling may fail. In such
2901
+ * cases we must return early (falling back to default behaviour) to
2902
+ * avoid a crash in hid_scroll_counter_handle_scroll.
2903
+ */
2904
+ if (!(hidpp -> quirks & HIDPP_QUIRK_HI_RES_SCROLL ) || value == 0
2905
+ || counter -> dev == NULL || counter -> resolution_multiplier == 0 )
2906
+ return 0 ;
2907
+
2908
+ hid_scroll_counter_handle_scroll (counter , value );
2909
+ return 1 ;
2910
+ }
2911
+
2714
2912
static int hidpp_initialize_battery (struct hidpp_device * hidpp )
2715
2913
{
2716
2914
static atomic_t battery_no = ATOMIC_INIT (0 );
@@ -2922,6 +3120,9 @@ static void hidpp_connect_event(struct hidpp_device *hidpp)
2922
3120
if (hidpp -> battery .ps )
2923
3121
power_supply_changed (hidpp -> battery .ps );
2924
3122
3123
+ if (hidpp -> quirks & HIDPP_QUIRK_HI_RES_SCROLL )
3124
+ hi_res_scroll_enable (hidpp );
3125
+
2925
3126
if (!(hidpp -> quirks & HIDPP_QUIRK_NO_HIDINPUT ) || hidpp -> delayed_input )
2926
3127
/* if the input nodes are already created, we can stop now */
2927
3128
return ;
@@ -3107,6 +3308,10 @@ static void hidpp_remove(struct hid_device *hdev)
3107
3308
mutex_destroy (& hidpp -> send_mutex );
3108
3309
}
3109
3310
3311
+ #define LDJ_DEVICE (product ) \
3312
+ HID_DEVICE(BUS_USB, HID_GROUP_LOGITECH_DJ_DEVICE, \
3313
+ USB_VENDOR_ID_LOGITECH, (product))
3314
+
3110
3315
static const struct hid_device_id hidpp_devices [] = {
3111
3316
{ /* wireless touchpad */
3112
3317
HID_DEVICE (BUS_USB , HID_GROUP_LOGITECH_DJ_DEVICE ,
@@ -3121,10 +3326,39 @@ static const struct hid_device_id hidpp_devices[] = {
3121
3326
HID_BLUETOOTH_DEVICE (USB_VENDOR_ID_LOGITECH ,
3122
3327
USB_DEVICE_ID_LOGITECH_T651 ),
3123
3328
.driver_data = HIDPP_QUIRK_CLASS_WTP },
3329
+ { /* Mouse Logitech Anywhere MX */
3330
+ LDJ_DEVICE (0x1017 ), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_1P0 },
3331
+ { /* Mouse Logitech Cube */
3332
+ LDJ_DEVICE (0x4010 ), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2120 },
3333
+ { /* Mouse Logitech M335 */
3334
+ LDJ_DEVICE (0x4050 ), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 },
3335
+ { /* Mouse Logitech M515 */
3336
+ LDJ_DEVICE (0x4007 ), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2120 },
3124
3337
{ /* Mouse logitech M560 */
3125
- HID_DEVICE (BUS_USB , HID_GROUP_LOGITECH_DJ_DEVICE ,
3126
- USB_VENDOR_ID_LOGITECH , 0x402d ),
3127
- .driver_data = HIDPP_QUIRK_DELAYED_INIT | HIDPP_QUIRK_CLASS_M560 },
3338
+ LDJ_DEVICE (0x402d ),
3339
+ .driver_data = HIDPP_QUIRK_DELAYED_INIT | HIDPP_QUIRK_CLASS_M560
3340
+ | HIDPP_QUIRK_HI_RES_SCROLL_X2120 },
3341
+ { /* Mouse Logitech M705 (firmware RQM17) */
3342
+ LDJ_DEVICE (0x101b ), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_1P0 },
3343
+ { /* Mouse Logitech M705 (firmware RQM67) */
3344
+ LDJ_DEVICE (0x406d ), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 },
3345
+ { /* Mouse Logitech M720 */
3346
+ LDJ_DEVICE (0x405e ), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 },
3347
+ { /* Mouse Logitech MX Anywhere 2 */
3348
+ LDJ_DEVICE (0x404a ), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 },
3349
+ { LDJ_DEVICE (0xb013 ), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 },
3350
+ { LDJ_DEVICE (0xb018 ), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 },
3351
+ { LDJ_DEVICE (0xb01f ), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 },
3352
+ { /* Mouse Logitech MX Anywhere 2S */
3353
+ LDJ_DEVICE (0x406a ), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 },
3354
+ { /* Mouse Logitech MX Master */
3355
+ LDJ_DEVICE (0x4041 ), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 },
3356
+ { LDJ_DEVICE (0x4060 ), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 },
3357
+ { LDJ_DEVICE (0x4071 ), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 },
3358
+ { /* Mouse Logitech MX Master 2S */
3359
+ LDJ_DEVICE (0x4069 ), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 },
3360
+ { /* Mouse Logitech Performance MX */
3361
+ LDJ_DEVICE (0x101a ), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_1P0 },
3128
3362
{ /* Keyboard logitech K400 */
3129
3363
HID_DEVICE (BUS_USB , HID_GROUP_LOGITECH_DJ_DEVICE ,
3130
3364
USB_VENDOR_ID_LOGITECH , 0x4024 ),
@@ -3144,12 +3378,19 @@ static const struct hid_device_id hidpp_devices[] = {
3144
3378
3145
3379
MODULE_DEVICE_TABLE (hid , hidpp_devices );
3146
3380
3381
+ static const struct hid_usage_id hidpp_usages [] = {
3382
+ { HID_GD_WHEEL , EV_REL , REL_WHEEL },
3383
+ { HID_ANY_ID - 1 , HID_ANY_ID - 1 , HID_ANY_ID - 1 }
3384
+ };
3385
+
3147
3386
static struct hid_driver hidpp_driver = {
3148
3387
.name = "logitech-hidpp-device" ,
3149
3388
.id_table = hidpp_devices ,
3150
3389
.probe = hidpp_probe ,
3151
3390
.remove = hidpp_remove ,
3152
3391
.raw_event = hidpp_raw_event ,
3392
+ .usage_table = hidpp_usages ,
3393
+ .event = hidpp_event ,
3153
3394
.input_configured = hidpp_input_configured ,
3154
3395
.input_mapping = hidpp_input_mapping ,
3155
3396
.input_mapped = hidpp_input_mapped ,
0 commit comments