aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/hid/hid-logitech-hidpp.c301
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 */
151struct 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
131struct hidpp_device { 159struct 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 */
437static 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
1258static 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
1293static 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;
1314return_default:
1315 hid_warn(hidpp->hid_dev,
1316 "Couldn't get wheel multiplier (error %d)\n", ret);
1317 return ret;
1318}
1319
1320static 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
2452static int m560_input_mapping(struct hid_device *hdev, struct hid_input *hi, 2643static 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
2746static 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
2598static int hidpp_input_configured(struct hid_device *hdev, 2823static 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
2939static 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
2714static int hidpp_initialize_battery(struct hidpp_device *hidpp) 2960static 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
3110static const struct hid_device_id hidpp_devices[] = { 3363static 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
3145MODULE_DEVICE_TABLE(hid, hidpp_devices); 3427MODULE_DEVICE_TABLE(hid, hidpp_devices);
3146 3428
3429static 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
3147static struct hid_driver hidpp_driver = { 3434static 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,