diff mbox series

HID: Use SET_REPORT request on control endpoint in hid-rmi for Acer Switch 3 and 5 cover keyboards

Message ID 2931730.Pa2PyE0Qbt@tobias-tablet (mailing list archive)
State Mainlined
Commit 10235380d18e8f666446970078d1ee69b33ab643
Delegated to: Jiri Kosina
Headers show
Series HID: Use SET_REPORT request on control endpoint in hid-rmi for Acer Switch 3 and 5 cover keyboards | expand

Commit Message

Tobias Auerochs April 20, 2019, 7:19 p.m. UTC
The touchpad on the cover keyboard for the Acer Switch 3 and 5 does not
work as-is under Linux. Both devices have the same usb id for the cover
keyboard.

The kernel correctly assigns the hid-rmi driver to the device using usbhid
for transport.
Any attempts of hid-rmi to talk to the device using hid_hw_output_report
fail however as usbhid does not have a working urbout due to the lack of
any out endpoints.

Looking through Wireshark usbmon recordings from the Windows Synaptics
driver for this computer running inside of QEMU shows that it should be
using SET_REPORT requests instead.

This replaces the hid_hw_output_report in hid-rmi with a
hid_hw_raw_request for this device, which is at least enough to enable
the kernel to get working multi-touch input.

Signed-off-by: Tobias Auerochs <tobi291019@gmail.com>
---

Comments

Jiri Kosina May 9, 2019, 7:36 p.m. UTC | #1
On Sat, 20 Apr 2019, Tobias Auerochs wrote:

> The touchpad on the cover keyboard for the Acer Switch 3 and 5 does not
> work as-is under Linux. Both devices have the same usb id for the cover
> keyboard.
> 
> The kernel correctly assigns the hid-rmi driver to the device using usbhid
> for transport.
> Any attempts of hid-rmi to talk to the device using hid_hw_output_report
> fail however as usbhid does not have a working urbout due to the lack of
> any out endpoints.
> 
> Looking through Wireshark usbmon recordings from the Windows Synaptics
> driver for this computer running inside of QEMU shows that it should be
> using SET_REPORT requests instead.
> 
> This replaces the hid_hw_output_report in hid-rmi with a
> hid_hw_raw_request for this device, which is at least enough to enable
> the kernel to get working multi-touch input.

Applied, thanks.
diff mbox series

Patch

diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
index b6d93f4ad037..3fc369477d52 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -1083,6 +1083,7 @@ 
 #define USB_DEVICE_ID_SYNAPTICS_HD	0x0ac3
 #define USB_DEVICE_ID_SYNAPTICS_QUAD_HD	0x1ac3
 #define USB_DEVICE_ID_SYNAPTICS_TP_V103	0x5710
+#define USB_DEVICE_ID_SYNAPTICS_ACER_SWITCH5	0x81a7
 
 #define USB_VENDOR_ID_TEXAS_INSTRUMENTS	0x2047
 #define USB_DEVICE_ID_TEXAS_INSTRUMENTS_LENOVO_YOGA	0x0855
diff --git a/drivers/hid/hid-rmi.c b/drivers/hid/hid-rmi.c
index 9e33165250a3..34465a7c3713 100644
--- a/drivers/hid/hid-rmi.c
+++ b/drivers/hid/hid-rmi.c
@@ -39,6 +39,7 @@ 
 /* device flags */
 #define RMI_DEVICE			BIT(0)
 #define RMI_DEVICE_HAS_PHYS_BUTTONS	BIT(1)
+#define RMI_DEVICE_OUTPUT_SET_REPORT	BIT(2)
 
 /*
  * retrieve the ctrl registers
@@ -167,9 +168,19 @@  static int rmi_set_mode(struct hid_device *hdev, u8 mode)
 
 static int rmi_write_report(struct hid_device *hdev, u8 *report, int len)
 {
+	struct rmi_data *data = hid_get_drvdata(hdev);
 	int ret;
 
-	ret = hid_hw_output_report(hdev, (void *)report, len);
+	if (data->device_flags & RMI_DEVICE_OUTPUT_SET_REPORT) {
+		/*
+		 * Talk to device by using SET_REPORT requests instead.
+		 */
+		ret = hid_hw_raw_request(hdev, report[0], report,
+				len, HID_OUTPUT_REPORT, HID_REQ_SET_REPORT);
+	} else {
+		ret = hid_hw_output_report(hdev, (void *)report, len);
+	}
+
 	if (ret < 0) {
 		dev_err(&hdev->dev, "failed to write hid report (%d)\n", ret);
 		return ret;
@@ -751,6 +762,8 @@  static const struct hid_device_id rmi_id[] = {
 		.driver_data = RMI_DEVICE_HAS_PHYS_BUTTONS },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_X1_COVER) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_PRIMAX, USB_DEVICE_ID_PRIMAX_REZEL) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_ACER_SWITCH5),
+		.driver_data = RMI_DEVICE_OUTPUT_SET_REPORT },
 	{ HID_DEVICE(HID_BUS_ANY, HID_GROUP_RMI, HID_ANY_ID, HID_ANY_ID) },
 	{ }
 };