Commit 7601fef4 authored by Jiri Kosina's avatar Jiri Kosina
Browse files

Merge branch 'for-6.7/lenovo' into for-linus

- Suspend/Resume fix for USB Thinkpad Compact Keyboard (Jamie Lentin)
- firmware detection improvement for Lenovo cptkbd (Mikhail Khvainitski)
parents f5883ef1 2f2bd7cb
Loading
Loading
Loading
Loading
+79 −39
Original line number Diff line number Diff line
@@ -51,7 +51,12 @@ struct lenovo_drvdata {
	int select_right;
	int sensitivity;
	int press_speed;
	u8 middlebutton_state; /* 0:Up, 1:Down (undecided), 2:Scrolling */
	/* 0: Up
	 * 1: Down (undecided)
	 * 2: Scrolling
	 * 3: Patched firmware, disable workaround
	 */
	u8 middlebutton_state;
	bool fn_lock;
};

@@ -521,6 +526,19 @@ static void lenovo_features_set_cptkbd(struct hid_device *hdev)
	int ret;
	struct lenovo_drvdata *cptkbd_data = hid_get_drvdata(hdev);

	/*
	 * Tell the keyboard a driver understands it, and turn F7, F9, F11 into
	 * regular keys
	 */
	ret = lenovo_send_cmd_cptkbd(hdev, 0x01, 0x03);
	if (ret)
		hid_warn(hdev, "Failed to switch F7/9/11 mode: %d\n", ret);

	/* Switch middle button to native mode */
	ret = lenovo_send_cmd_cptkbd(hdev, 0x09, 0x01);
	if (ret)
		hid_warn(hdev, "Failed to switch middle button: %d\n", ret);

	ret = lenovo_send_cmd_cptkbd(hdev, 0x05, cptkbd_data->fn_lock);
	if (ret)
		hid_err(hdev, "Fn-lock setting failed: %d\n", ret);
@@ -668,6 +686,22 @@ static int lenovo_event_cptkbd(struct hid_device *hdev,
{
	struct lenovo_drvdata *cptkbd_data = hid_get_drvdata(hdev);

	if (cptkbd_data->middlebutton_state != 3) {
		/* REL_X and REL_Y events during middle button pressed
		 * are only possible on patched, bug-free firmware
		 * so set middlebutton_state to 3
		 * to never apply workaround anymore
		 */
		if (cptkbd_data->middlebutton_state == 1 &&
				usage->type == EV_REL &&
				(usage->code == REL_X || usage->code == REL_Y)) {
			cptkbd_data->middlebutton_state = 3;
			/* send middle button press which was hold before */
			input_event(field->hidinput->input,
				EV_KEY, BTN_MIDDLE, 1);
			input_sync(field->hidinput->input);
		}

		/* "wheel" scroll events */
		if (usage->type == EV_REL && (usage->code == REL_WHEEL ||
				usage->code == REL_HWHEEL)) {
@@ -694,6 +728,7 @@ static int lenovo_event_cptkbd(struct hid_device *hdev,
			}
			return 1;
		}
	}

	if (usage->type == EV_KEY && usage->code == KEY_FN_ESC && value == 1) {
		/*
@@ -1126,22 +1161,6 @@ static int lenovo_probe_cptkbd(struct hid_device *hdev)
	}
	hid_set_drvdata(hdev, cptkbd_data);

	/*
	 * Tell the keyboard a driver understands it, and turn F7, F9, F11 into
	 * regular keys (Compact only)
	 */
	if (hdev->product == USB_DEVICE_ID_LENOVO_CUSBKBD ||
	    hdev->product == USB_DEVICE_ID_LENOVO_CBTKBD) {
		ret = lenovo_send_cmd_cptkbd(hdev, 0x01, 0x03);
		if (ret)
			hid_warn(hdev, "Failed to switch F7/9/11 mode: %d\n", ret);
	}

	/* Switch middle button to native mode */
	ret = lenovo_send_cmd_cptkbd(hdev, 0x09, 0x01);
	if (ret)
		hid_warn(hdev, "Failed to switch middle button: %d\n", ret);

	/* Set keyboard settings to known state */
	cptkbd_data->middlebutton_state = 0;
	cptkbd_data->fn_lock = true;
@@ -1264,6 +1283,24 @@ static int lenovo_probe(struct hid_device *hdev,
	return ret;
}

#ifdef CONFIG_PM
static int lenovo_reset_resume(struct hid_device *hdev)
{
	switch (hdev->product) {
	case USB_DEVICE_ID_LENOVO_CUSBKBD:
	case USB_DEVICE_ID_LENOVO_TPIIUSBKBD:
		if (hdev->type == HID_TYPE_USBMOUSE)
			lenovo_features_set_cptkbd(hdev);

		break;
	default:
		break;
	}

	return 0;
}
#endif

static void lenovo_remove_tpkbd(struct hid_device *hdev)
{
	struct lenovo_drvdata *data_pointer = hid_get_drvdata(hdev);
@@ -1380,6 +1417,9 @@ static struct hid_driver lenovo_driver = {
	.raw_event = lenovo_raw_event,
	.event = lenovo_event,
	.report_fixup = lenovo_report_fixup,
#ifdef CONFIG_PM
	.reset_resume = lenovo_reset_resume,
#endif
};
module_hid_driver(lenovo_driver);