Skip to content

Commit 4a79bcc

Browse files
jwrdegoedebentiss
authored andcommitted
HID: logitech-hidpp: add support for HID++ 1.0 wheel reports
Add a quirk for switching wheel event reporting to using the HID++ report for this. This has 2 advantages: 1) Without this tilting the scrollwheel left / right will send a scroll-lock + cursor-left/-right + scroll-lock key-sequence instead of hwheel events 2) The HID++ reports contain the device index instead of using the generic HID implementation, so this will make scroll-wheel events from the wheel on some keyboards be emitted by the right event node. 2. also fixes keyboard scroll-wheel events getting lost in the (mostly theoretical) case of there not being a mouse paired with the receiver. This commit enables this quirk for all 27Mhz mice, it cannot hurt to have it enabled and this avoids the need to keep adding more and more quirks for this. This has been tested in 5 different 27MHz mice, 3 of which have a wheel which can tilt. This commit also adds explicit quirks for 3 keyboards with a zoom-/scroll- wheel. The MX3000 keyboard scroll-wheel can also tilt. I've defined aliases to the new HIDPP_QUIRK_HIDPP_WHEELS for this, so that it is clear why the keyboard has the quirk and in case we want to handle the keyboard wheels and especially the keyboard zoom-wheels differently in the future. Signed-off-by: Hans de Goede <[email protected]> Signed-off-by: Benjamin Tissoires <[email protected]>
1 parent 35839f7 commit 4a79bcc

File tree

1 file changed

+94
-0
lines changed

1 file changed

+94
-0
lines changed

drivers/hid/hid-logitech-hidpp.c

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,9 @@ MODULE_PARM_DESC(disable_tap_to_click,
5353
#define HIDPP_REPORT_LONG_LENGTH 20
5454
#define HIDPP_REPORT_VERY_LONG_MAX_LENGTH 64
5555

56+
#define HIDPP_SUB_ID_ROLLER 0x05
57+
#define HIDPP_SUB_ID_MOUSE_EXTRA_BTNS 0x06
58+
5659
#define HIDPP_QUIRK_CLASS_WTP BIT(0)
5760
#define HIDPP_QUIRK_CLASS_M560 BIT(1)
5861
#define HIDPP_QUIRK_CLASS_K400 BIT(2)
@@ -68,6 +71,11 @@ MODULE_PARM_DESC(disable_tap_to_click,
6871
#define HIDPP_QUIRK_HI_RES_SCROLL_1P0 BIT(26)
6972
#define HIDPP_QUIRK_HI_RES_SCROLL_X2120 BIT(27)
7073
#define HIDPP_QUIRK_HI_RES_SCROLL_X2121 BIT(28)
74+
#define HIDPP_QUIRK_HIDPP_WHEELS BIT(29)
75+
76+
/* These are just aliases for now */
77+
#define HIDPP_QUIRK_KBD_SCROLL_WHEEL HIDPP_QUIRK_HIDPP_WHEELS
78+
#define HIDPP_QUIRK_KBD_ZOOM_WHEEL HIDPP_QUIRK_HIDPP_WHEELS
7179

7280
/* Convenience constant to check for any high-res support. */
7381
#define HIDPP_QUIRK_HI_RES_SCROLL (HIDPP_QUIRK_HI_RES_SCROLL_1P0 | \
@@ -2738,6 +2746,52 @@ static int g920_get_config(struct hidpp_device *hidpp)
27382746
return 0;
27392747
}
27402748

2749+
/* -------------------------------------------------------------------------- */
2750+
/* HID++1.0 devices which use HID++ reports for their wheels */
2751+
/* -------------------------------------------------------------------------- */
2752+
static int hidpp10_wheel_connect(struct hidpp_device *hidpp)
2753+
{
2754+
return hidpp10_set_register(hidpp, HIDPP_REG_ENABLE_REPORTS, 0,
2755+
HIDPP_ENABLE_WHEEL_REPORT | HIDPP_ENABLE_HWHEEL_REPORT,
2756+
HIDPP_ENABLE_WHEEL_REPORT | HIDPP_ENABLE_HWHEEL_REPORT);
2757+
}
2758+
2759+
static int hidpp10_wheel_raw_event(struct hidpp_device *hidpp,
2760+
u8 *data, int size)
2761+
{
2762+
s8 value, hvalue;
2763+
2764+
if (!hidpp->input)
2765+
return -EINVAL;
2766+
2767+
if (size < 7)
2768+
return 0;
2769+
2770+
if (data[0] != REPORT_ID_HIDPP_SHORT || data[2] != HIDPP_SUB_ID_ROLLER)
2771+
return 0;
2772+
2773+
value = data[3];
2774+
hvalue = data[4];
2775+
2776+
input_report_rel(hidpp->input, REL_WHEEL, value);
2777+
input_report_rel(hidpp->input, REL_WHEEL_HI_RES, value * 120);
2778+
input_report_rel(hidpp->input, REL_HWHEEL, hvalue);
2779+
input_report_rel(hidpp->input, REL_HWHEEL_HI_RES, hvalue * 120);
2780+
input_sync(hidpp->input);
2781+
2782+
return 1;
2783+
}
2784+
2785+
static void hidpp10_wheel_populate_input(struct hidpp_device *hidpp,
2786+
struct input_dev *input_dev)
2787+
{
2788+
__set_bit(EV_REL, input_dev->evbit);
2789+
__set_bit(REL_WHEEL, input_dev->relbit);
2790+
__set_bit(REL_WHEEL_HI_RES, input_dev->relbit);
2791+
__set_bit(REL_HWHEEL, input_dev->relbit);
2792+
__set_bit(REL_HWHEEL_HI_RES, input_dev->relbit);
2793+
}
2794+
27412795
/* -------------------------------------------------------------------------- */
27422796
/* High-resolution scroll wheels */
27432797
/* -------------------------------------------------------------------------- */
@@ -2822,6 +2876,9 @@ static void hidpp_populate_input(struct hidpp_device *hidpp,
28222876
wtp_populate_input(hidpp, input);
28232877
else if (hidpp->quirks & HIDPP_QUIRK_CLASS_M560)
28242878
m560_populate_input(hidpp, input);
2879+
2880+
if (hidpp->quirks & HIDPP_QUIRK_HIDPP_WHEELS)
2881+
hidpp10_wheel_populate_input(hidpp, input);
28252882
}
28262883

28272884
static int hidpp_input_configured(struct hid_device *hdev,
@@ -2893,6 +2950,12 @@ static int hidpp_raw_hidpp_event(struct hidpp_device *hidpp, u8 *data,
28932950
return ret;
28942951
}
28952952

2953+
if (hidpp->quirks & HIDPP_QUIRK_HIDPP_WHEELS) {
2954+
ret = hidpp10_wheel_raw_event(hidpp, data, size);
2955+
if (ret != 0)
2956+
return ret;
2957+
}
2958+
28962959
return 0;
28972960
}
28982961

@@ -3140,6 +3203,12 @@ static void hidpp_connect_event(struct hidpp_device *hidpp)
31403203
return;
31413204
}
31423205

3206+
if (hidpp->quirks & HIDPP_QUIRK_HIDPP_WHEELS) {
3207+
ret = hidpp10_wheel_connect(hidpp);
3208+
if (ret)
3209+
return;
3210+
}
3211+
31433212
/* the device is already connected, we can ask for its name and
31443213
* protocol */
31453214
if (!hidpp->protocol_major) {
@@ -3254,6 +3323,17 @@ static bool hidpp_validate_device(struct hid_device *hdev)
32543323
HIDPP_REPORT_LONG_LENGTH, true);
32553324
}
32563325

3326+
static bool hidpp_application_equals(struct hid_device *hdev,
3327+
unsigned int application)
3328+
{
3329+
struct list_head *report_list;
3330+
struct hid_report *report;
3331+
3332+
report_list = &hdev->report_enum[HID_INPUT_REPORT].report_list;
3333+
report = list_first_entry_or_null(report_list, struct hid_report, list);
3334+
return report && report->application == application;
3335+
}
3336+
32573337
static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id)
32583338
{
32593339
struct hidpp_device *hidpp;
@@ -3292,6 +3372,10 @@ static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id)
32923372
if (id->group == HID_GROUP_LOGITECH_DJ_DEVICE)
32933373
hidpp->quirks |= HIDPP_QUIRK_UNIFYING;
32943374

3375+
if (id->group == HID_GROUP_LOGITECH_27MHZ_DEVICE &&
3376+
hidpp_application_equals(hdev, HID_GD_MOUSE))
3377+
hidpp->quirks |= HIDPP_QUIRK_HIDPP_WHEELS;
3378+
32953379
if (disable_raw_mode) {
32963380
hidpp->quirks &= ~HIDPP_QUIRK_CLASS_WTP;
32973381
hidpp->quirks &= ~HIDPP_QUIRK_NO_HIDINPUT;
@@ -3472,6 +3556,16 @@ static const struct hid_device_id hidpp_devices[] = {
34723556

34733557
{ LDJ_DEVICE(HID_ANY_ID) },
34743558

3559+
{ /* Keyboard LX501 (Y-RR53) */
3560+
L27MHZ_DEVICE(0x0049),
3561+
.driver_data = HIDPP_QUIRK_KBD_ZOOM_WHEEL },
3562+
{ /* Keyboard MX3000 (Y-RAM74) */
3563+
L27MHZ_DEVICE(0x0057),
3564+
.driver_data = HIDPP_QUIRK_KBD_SCROLL_WHEEL },
3565+
{ /* Keyboard MX3200 (Y-RAV80) */
3566+
L27MHZ_DEVICE(0x005c),
3567+
.driver_data = HIDPP_QUIRK_KBD_ZOOM_WHEEL },
3568+
34753569
{ L27MHZ_DEVICE(HID_ANY_ID) },
34763570

34773571
{ /* Logitech G403 Gaming Mouse over USB */

0 commit comments

Comments
 (0)