Commit ed80cc46 authored by Stuart Hayhurst's avatar Stuart Hayhurst Committed by Jiri Kosina
Browse files

HID: logitech-hidpp: Add HIDPP_QUIRK_RESET_HI_RES_SCROLL

The Logitech G502 Hero Wireless's high resolution scrolling resets after
being unplugged without notifying the driver, causing extremely slow
scrolling.

The only indication of this is a battery update packet, so add a quirk to
detect when the device is unplugged and re-enable the scrolling.

Link: https://bugzilla.kernel.org/show_bug.cgi?id=218037


Signed-off-by: default avatarStuart Hayhurst <stuart.a.hayhurst@gmail.com>
Signed-off-by: default avatarJiri Kosina <jkosina@suse.com>
parent d9b3014a
Loading
Loading
Loading
Loading
+21 −0
Original line number Diff line number Diff line
@@ -75,6 +75,7 @@ MODULE_PARM_DESC(disable_tap_to_click,
#define HIDPP_QUIRK_HIDPP_CONSUMER_VENDOR_KEYS	BIT(27)
#define HIDPP_QUIRK_HI_RES_SCROLL_1P0		BIT(28)
#define HIDPP_QUIRK_WIRELESS_STATUS		BIT(29)
#define HIDPP_QUIRK_RESET_HI_RES_SCROLL		BIT(30)

/* These are just aliases for now */
#define HIDPP_QUIRK_KBD_SCROLL_WHEEL HIDPP_QUIRK_HIDPP_WHEELS
@@ -193,6 +194,7 @@ struct hidpp_device {
	void *private_data;

	struct work_struct work;
	struct work_struct reset_hi_res_work;
	struct kfifo delayed_work_fifo;
	struct input_dev *delayed_input;

@@ -3836,6 +3838,7 @@ static int hidpp_raw_hidpp_event(struct hidpp_device *hidpp, u8 *data,
	struct hidpp_report *answer = hidpp->send_receive_buf;
	struct hidpp_report *report = (struct hidpp_report *)data;
	int ret;
	int last_online;

	/*
	 * If the mutex is locked then we have a pending answer from a
@@ -3877,6 +3880,7 @@ static int hidpp_raw_hidpp_event(struct hidpp_device *hidpp, u8 *data,
			"See: https://gitlab.freedesktop.org/jwrdegoede/logitech-27mhz-keyboard-encryption-setup/\n");
	}

	last_online = hidpp->battery.online;
	if (hidpp->capabilities & HIDPP_CAPABILITY_HIDPP20_BATTERY) {
		ret = hidpp20_battery_event_1000(hidpp, data, size);
		if (ret != 0)
@@ -3901,6 +3905,11 @@ static int hidpp_raw_hidpp_event(struct hidpp_device *hidpp, u8 *data,
			return ret;
	}

	if (hidpp->quirks & HIDPP_QUIRK_RESET_HI_RES_SCROLL) {
		if (last_online == 0 && hidpp->battery.online == 1)
			schedule_work(&hidpp->reset_hi_res_work);
	}

	if (hidpp->quirks & HIDPP_QUIRK_HIDPP_WHEELS) {
		ret = hidpp10_wheel_raw_event(hidpp, data, size);
		if (ret != 0)
@@ -4274,6 +4283,13 @@ static void hidpp_connect_event(struct work_struct *work)
	hidpp->delayed_input = input;
}

static void hidpp_reset_hi_res_handler(struct work_struct *work)
{
	struct hidpp_device *hidpp = container_of(work, struct hidpp_device, reset_hi_res_work);

	hi_res_scroll_enable(hidpp);
}

static DEVICE_ATTR(builtin_power_supply, 0000, NULL, NULL);

static struct attribute *sysfs_attrs[] = {
@@ -4404,6 +4420,7 @@ static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id)
	}

	INIT_WORK(&hidpp->work, hidpp_connect_event);
	INIT_WORK(&hidpp->reset_hi_res_work, hidpp_reset_hi_res_handler);
	mutex_init(&hidpp->send_mutex);
	init_waitqueue_head(&hidpp->wait);

@@ -4499,6 +4516,7 @@ static void hidpp_remove(struct hid_device *hdev)

	hid_hw_stop(hdev);
	cancel_work_sync(&hidpp->work);
	cancel_work_sync(&hidpp->reset_hi_res_work);
	mutex_destroy(&hidpp->send_mutex);
}

@@ -4546,6 +4564,9 @@ static const struct hid_device_id hidpp_devices[] = {
	{ /* Keyboard MX5500 (Bluetooth-receiver in HID proxy mode) */
	  LDJ_DEVICE(0xb30b),
	  .driver_data = HIDPP_QUIRK_HIDPP_CONSUMER_VENDOR_KEYS },
	{ /* Logitech G502 Lightspeed Wireless Gaming Mouse */
	  LDJ_DEVICE(0x407f),
	  .driver_data = HIDPP_QUIRK_RESET_HI_RES_SCROLL },

	{ LDJ_DEVICE(HID_ANY_ID) },