Commit a74749ef authored by Benjamin Tissoires's avatar Benjamin Tissoires
Browse files

Merge branch 'for-6.3/logitech' into for-linus

- HID++ fixes for scroll wheel, protocol and debug (Bastien Nocera)
- add support of Logitech G923 Xbox Edition steering wheel (Walt Holman)
parents 0f7566c7 1b136aeb
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -9217,6 +9217,13 @@ L: linux-input@vger.kernel.org
S:	Maintained
F:	drivers/hid/hid-logitech-*
HID++ LOGITECH DRIVERS
R:	Filipe Laíns <lains@riseup.net>
R:	Bastien Nocera <hadess@hadess.net>
L:	linux-input@vger.kernel.org
S:	Maintained
F:	drivers/hid/hid-logitech-hidpp.c
HID PLAYSTATION DRIVER
M:	Roderick Colenbrander <roderick.colenbrander@sony.com>
L:	linux-input@vger.kernel.org
+1 −0
Original line number Diff line number Diff line
@@ -825,6 +825,7 @@
#define USB_DEVICE_ID_LOGITECH_G510_USB_AUDIO	0xc22e
#define USB_DEVICE_ID_LOGITECH_G29_WHEEL	0xc24f
#define USB_DEVICE_ID_LOGITECH_G920_WHEEL	0xc262
#define USB_DEVICE_ID_LOGITECH_G923_XBOX_WHEEL	0xc26e
#define USB_DEVICE_ID_LOGITECH_WINGMAN_F3D	0xc283
#define USB_DEVICE_ID_LOGITECH_FORCE3D_PRO	0xc286
#define USB_DEVICE_ID_LOGITECH_FLIGHT_SYSTEM_G940	0xc287
+91 −61
Original line number Diff line number Diff line
@@ -30,11 +30,7 @@
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Benjamin Tissoires <benjamin.tissoires@gmail.com>");
MODULE_AUTHOR("Nestor Lopez Casado <nlopezcasad@logitech.com>");

static bool disable_raw_mode;
module_param(disable_raw_mode, bool, 0644);
MODULE_PARM_DESC(disable_raw_mode,
	"Disable Raw mode reporting for touchpads and keep firmware gestures.");
MODULE_AUTHOR("Bastien Nocera <hadess@hadess.net>");

static bool disable_tap_to_click;
module_param(disable_tap_to_click, bool, 0644);
@@ -71,12 +67,13 @@ MODULE_PARM_DESC(disable_tap_to_click,
/* bits 2..20 are reserved for classes */
/* #define HIDPP_QUIRK_CONNECT_EVENTS		BIT(21) disabled */
#define HIDPP_QUIRK_WTP_PHYSICAL_BUTTONS	BIT(22)
#define HIDPP_QUIRK_NO_HIDINPUT			BIT(23)
#define HIDPP_QUIRK_DELAYED_INIT		BIT(23)
#define HIDPP_QUIRK_FORCE_OUTPUT_REPORTS	BIT(24)
#define HIDPP_QUIRK_UNIFYING			BIT(25)
#define HIDPP_QUIRK_HIDPP_WHEELS		BIT(26)
#define HIDPP_QUIRK_HIDPP_EXTRA_MOUSE_BTNS	BIT(27)
#define HIDPP_QUIRK_HIDPP_CONSUMER_VENDOR_KEYS	BIT(28)
#define HIDPP_QUIRK_HI_RES_SCROLL_1P0		BIT(29)

/* These are just aliases for now */
#define HIDPP_QUIRK_KBD_SCROLL_WHEEL HIDPP_QUIRK_HIDPP_WHEELS
@@ -87,8 +84,6 @@ MODULE_PARM_DESC(disable_tap_to_click,
					 HIDPP_CAPABILITY_HIDPP20_HI_RES_SCROLL | \
					 HIDPP_CAPABILITY_HIDPP20_HI_RES_WHEEL)

#define HIDPP_QUIRK_DELAYED_INIT		HIDPP_QUIRK_NO_HIDINPUT

#define HIDPP_CAPABILITY_HIDPP10_BATTERY	BIT(0)
#define HIDPP_CAPABILITY_HIDPP20_BATTERY	BIT(1)
#define HIDPP_CAPABILITY_BATTERY_MILEAGE	BIT(2)
@@ -225,6 +220,16 @@ struct hidpp_device {
#define HIDPP_ERROR_INVALID_PARAM_VALUE		0x0b
#define HIDPP_ERROR_WRONG_PIN_CODE		0x0c
/* HID++ 2.0 error codes */
#define HIDPP20_ERROR_NO_ERROR			0x00
#define HIDPP20_ERROR_UNKNOWN			0x01
#define HIDPP20_ERROR_INVALID_ARGS		0x02
#define HIDPP20_ERROR_OUT_OF_RANGE		0x03
#define HIDPP20_ERROR_HW_ERROR			0x04
#define HIDPP20_ERROR_LOGITECH_INTERNAL		0x05
#define HIDPP20_ERROR_INVALID_FEATURE_INDEX	0x06
#define HIDPP20_ERROR_INVALID_FUNCTION_ID	0x07
#define HIDPP20_ERROR_BUSY			0x08
#define HIDPP20_ERROR_UNSUPPORTED		0x09
#define HIDPP20_ERROR				0xff

static void hidpp_connect_event(struct hidpp_device *hidpp_dev);
@@ -279,6 +284,7 @@ static int hidpp_send_message_sync(struct hidpp_device *hidpp,
	struct hidpp_report *response)
{
	int ret;
	int max_retries = 3;

	mutex_lock(&hidpp->send_mutex);

@@ -291,6 +297,7 @@ static int hidpp_send_message_sync(struct hidpp_device *hidpp,
	 */
	*response = *message;

	for (; max_retries != 0; max_retries--) {
		ret = __hidpp_send_report(hidpp->hid_dev, message);

		if (ret) {
@@ -317,9 +324,13 @@ static int hidpp_send_message_sync(struct hidpp_device *hidpp,
		     response->report_id == REPORT_ID_HIDPP_VERY_LONG) &&
		    response->fap.feature_index == HIDPP20_ERROR) {
			ret = response->fap.params[1];
			if (ret != HIDPP20_ERROR_BUSY) {
				dbg_hid("%s:got hidpp 2.0 error %02X\n", __func__, ret);
				goto exit;
			}
			dbg_hid("%s:got busy hidpp 2.0 error %02X, retrying\n", __func__, ret);
		}
	}

exit:
	mutex_unlock(&hidpp->send_mutex);
@@ -334,8 +345,13 @@ static int hidpp_send_fap_command_sync(struct hidpp_device *hidpp,
	struct hidpp_report *message;
	int ret;

	if (param_count > sizeof(message->fap.params))
	if (param_count > sizeof(message->fap.params)) {
		hid_dbg(hidpp->hid_dev,
			"Invalid number of parameters passed to command (%d != %llu)\n",
			param_count,
			(unsigned long long) sizeof(message->fap.params));
		return -EINVAL;
	}

	message = kzalloc(sizeof(struct hidpp_report), GFP_KERNEL);
	if (!message)
@@ -3436,11 +3452,17 @@ static int hi_res_scroll_enable(struct hidpp_device *hidpp)
		ret = hidpp10_enable_scrolling_acceleration(hidpp);
		multiplier = 8;
	}
	if (ret)
	if (ret) {
		hid_dbg(hidpp->hid_dev,
			"Could not enable hi-res scrolling: %d\n", ret);
		return ret;
	}

	if (multiplier == 0)
	if (multiplier == 0) {
		hid_dbg(hidpp->hid_dev,
			"Invalid multiplier 0 from device, setting it to 1\n");
		multiplier = 1;
	}

	hidpp->vertical_wheel_counter.wheel_multiplier = multiplier;
	hid_dbg(hidpp->hid_dev, "wheel multiplier = %d\n", multiplier);
@@ -3472,14 +3494,8 @@ static int hidpp_initialize_hires_scroll(struct hidpp_device *hidpp)
			hid_dbg(hidpp->hid_dev, "Detected HID++ 2.0 hi-res scrolling\n");
		}
	} else {
		struct hidpp_report response;

		ret = hidpp_send_rap_command_sync(hidpp,
						  REPORT_ID_HIDPP_SHORT,
						  HIDPP_GET_REGISTER,
						  HIDPP_ENABLE_FAST_SCROLL,
						  NULL, 0, &response);
		if (!ret) {
		/* We cannot detect fast scrolling support on HID++ 1.0 devices */
		if (hidpp->quirks & HIDPP_QUIRK_HI_RES_SCROLL_1P0) {
			hidpp->capabilities |= HIDPP_CAPABILITY_HIDPP10_FAST_SCROLL;
			hid_dbg(hidpp->hid_dev, "Detected HID++ 1.0 fast scroll\n");
		}
@@ -4002,7 +4018,7 @@ static void hidpp_connect_event(struct hidpp_device *hidpp)
	if (hidpp->capabilities & HIDPP_CAPABILITY_HI_RES_SCROLL)
		hi_res_scroll_enable(hidpp);

	if (!(hidpp->quirks & HIDPP_QUIRK_NO_HIDINPUT) || hidpp->delayed_input)
	if (!(hidpp->quirks & HIDPP_QUIRK_DELAYED_INIT) || hidpp->delayed_input)
		/* if the input nodes are already created, we can stop now */
		return;

@@ -4107,6 +4123,7 @@ static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id)
	bool connected;
	unsigned int connect_mask = HID_CONNECT_DEFAULT;
	struct hidpp_ff_private_data data;
	bool will_restart = false;

	/* report_fixup needs drvdata to be set before we call hid_parse */
	hidpp = devm_kzalloc(&hdev->dev, sizeof(*hidpp), GFP_KERNEL);
@@ -4147,11 +4164,6 @@ static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id)
	    hidpp_application_equals(hdev, HID_GD_KEYBOARD))
		hidpp->quirks |= HIDPP_QUIRK_HIDPP_CONSUMER_VENDOR_KEYS;

	if (disable_raw_mode) {
		hidpp->quirks &= ~HIDPP_QUIRK_CLASS_WTP;
		hidpp->quirks &= ~HIDPP_QUIRK_NO_HIDINPUT;
	}

	if (hidpp->quirks & HIDPP_QUIRK_CLASS_WTP) {
		ret = wtp_allocate(hdev, id);
		if (ret)
@@ -4162,6 +4174,10 @@ static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id)
			return ret;
	}

	if (hidpp->quirks & HIDPP_QUIRK_DELAYED_INIT ||
	    hidpp->quirks & HIDPP_QUIRK_UNIFYING)
		will_restart = true;

	INIT_WORK(&hidpp->work, delayed_work_cb);
	mutex_init(&hidpp->send_mutex);
	init_waitqueue_head(&hidpp->wait);
@@ -4176,7 +4192,7 @@ static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id)
	 * Plain USB connections need to actually call start and open
	 * on the transport driver to allow incoming data.
	 */
	ret = hid_hw_start(hdev, 0);
	ret = hid_hw_start(hdev, will_restart ? 0 : connect_mask);
	if (ret) {
		hid_err(hdev, "hw start failed\n");
		goto hid_hw_start_fail;
@@ -4213,6 +4229,7 @@ static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id)
			hidpp->wireless_feature_index = 0;
		else if (ret)
			goto hid_hw_init_fail;
		ret = 0;
	}

	if (connected && (hidpp->quirks & HIDPP_QUIRK_CLASS_WTP)) {
@@ -4227,12 +4244,13 @@ static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id)

	hidpp_connect_event(hidpp);

	if (will_restart) {
		/* Reset the HID node state */
		hid_device_io_stop(hdev);
		hid_hw_close(hdev);
		hid_hw_stop(hdev);

	if (hidpp->quirks & HIDPP_QUIRK_NO_HIDINPUT)
		if (hidpp->quirks & HIDPP_QUIRK_DELAYED_INIT)
			connect_mask &= ~HID_CONNECT_HIDINPUT;

		/* Now export the actual inputs and hidraw nodes to the world */
@@ -4241,6 +4259,7 @@ static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id)
			hid_err(hdev, "%s:hid_hw_start returned error\n", __func__);
			goto hid_hw_start_fail;
		}
	}

	if (hidpp->quirks & HIDPP_QUIRK_CLASS_G920) {
		ret = hidpp_ff_init(hidpp, &data);
@@ -4297,9 +4316,15 @@ static const struct hid_device_id hidpp_devices[] = {
	  HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH,
		USB_DEVICE_ID_LOGITECH_T651),
	  .driver_data = HIDPP_QUIRK_CLASS_WTP },
	{ /* Mouse Logitech Anywhere MX */
	  LDJ_DEVICE(0x1017), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_1P0 },
	{ /* Mouse logitech M560 */
	  LDJ_DEVICE(0x402d),
	  .driver_data = HIDPP_QUIRK_DELAYED_INIT | HIDPP_QUIRK_CLASS_M560 },
	{ /* Mouse Logitech M705 (firmware RQM17) */
	  LDJ_DEVICE(0x101b), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_1P0 },
	{ /* Mouse Logitech Performance MX */
	  LDJ_DEVICE(0x101a), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_1P0 },
	{ /* Keyboard logitech K400 */
	  LDJ_DEVICE(0x4024),
	  .driver_data = HIDPP_QUIRK_CLASS_K400 },
@@ -4348,6 +4373,9 @@ static const struct hid_device_id hidpp_devices[] = {
	{ /* Logitech G920 Wheel over USB */
	  HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G920_WHEEL),
		.driver_data = HIDPP_QUIRK_CLASS_G920 | HIDPP_QUIRK_FORCE_OUTPUT_REPORTS},
	{ /* Logitech G923 Wheel (Xbox version) over USB */
	  HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G923_XBOX_WHEEL),
		.driver_data = HIDPP_QUIRK_CLASS_G920 | HIDPP_QUIRK_FORCE_OUTPUT_REPORTS },
	{ /* Logitech G Pro Gaming Mouse over USB */
	  HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, 0xC088) },

@@ -4367,6 +4395,8 @@ static const struct hid_device_id hidpp_devices[] = {
	{ /* MX Ergo trackball over Bluetooth */
	  HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb01d) },
	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb01e) },
	{ /* Signature M650 over Bluetooth */
	  HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb02a) },
	{ /* MX Master 3 mouse over Bluetooth */
	  HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb023) },
	{}