Linux Input/HID development
 help / color / mirror / Atom feed
* [PATCH v4] Input: xpad - add support for Beitong KP series controllers
@ 2026-08-04  5:50 vegetablecat
  2026-08-04  5:56 ` sashiko-bot
  0 siblings, 1 reply; 3+ messages in thread
From: vegetablecat @ 2026-08-04  5:50 UTC (permalink / raw)
  To: linux-input
  Cc: linux-kernel, Dmitry Torokhov, Aaron Ma, Shengyu Qu, Zixing Liu

[-- Attachment #1: Type: text/plain, Size: 4769 bytes --]

Subject: [PATCH v4] Input: xpad - add support for Beitong KP series controllers

[This email contains both English and Chinese versions.]
[本邮件包含英语和中文两个版本。]

Hi Dmitry, Aaron, Shengyu, Zixing,

This is v4 of the Beitong KP series support patch. Changes since v3
based on feedback from Aaron and Shengyu:

Lock mechanism — combined MS OS 1.0 sequence
---------------------------------------------
Aaron suggested using the standard GET_DESCRIPTOR for the Microsoft OS
string descriptor (index 0xEE) instead of issuing the Extended Compat ID
request directly. Test results:

  - KP20 (5126/5128): string descriptor alone does NOT lock; Extended
    Compat ID is required.
  - KP40 (515b/515c): either request alone locks the device.

This differs from Aaron's finding on 5158/5159 — the trigger condition
varies across models. The probe therefore sends both requests in MS OS
1.0 sequence order (string descriptor first, Extended Compat ID second).
Each warns on failure without blocking probe.

Aaron, could you confirm the second request doesn't cause regressions
on 5158/5159?

Device table — converged to tested PIDs only
---------------------------------------------
Shengyu pointed out the 28-entry list was inflated. The full list
originated from Zixing Liu's earlier patch [1] and was not fabricated,
but since most were untested, the table is reduced to 6 entries (see
above). Wired-direct (Controller) and wireless-dongle (Dongle)
connections enumerate as different PIDs, hence paired entries.
Remaining PIDs from Liu's patch can be added after individual testing.

KP40D receiver keepalive — HID_QUIRK_ALWAYS_POLL
-------------------------------------------------
Aaron's suggested HID_QUIRK_ALWAYS_POLL approach was tested on
20dd:515c (KP40D) via usbhid.quirks kernel cmdline (GRUB). The
hid-ids.h and hid-quirks.c changes in the accompanying patch reflect
the intended merged form but have not been compile-tested as part of
a kernel build. KP20 wireless (5128) does not need keepalive — it
works without the quirk. Only KP40D IDs were added.

Naming — Controller vs. Dongle
-------------------------------
5126/515b are the physical controller connected via USB → "Controller".
5128/515c are wireless dongles → "Dongle". This matches the fact that
the controller body uses a different VID: in wired mode the USB device
is the controller itself. The previously incorrect naming for wireless
mode has been fixed.

[1] https://lore.kernel.org/linux-input/20260102030154.197749-2-liushuyu@aosc.io/

Signed-off-by: VegetablCat <vegetablecat@foxmail.com>

---

中文版本

Dmitry、Aaron、Shengyu、Zixing,你们好:

这是 Beitong KP 系列支持补丁的 v4 版本。基于 Aaron 和 Shengyu 的反馈,
v3 以来的改动如下:

锁模机制 — 组合 MS OS 1.0 序列

Aaron 建议用标准 GET_DESCRIPTOR 读取 Microsoft OS 字符串描述符
(index 0xEE)代替直接发 Extended Compat ID 请求。实测结果:

  - KP20(5126/5128):字符串描述符无法锁模,必须 Extended Compat ID。
  - KP40(515b/515c):字符串描述符或 Extended Compat ID 单独发均可。

这与 Aaron 在 5158/5159 上的结果不同——不同型号的触发条件不完全一致。
因此当前 probe 按 MS OS 1.0 协议顺序两个请求都发(字符串描述符在前,
Extended Compat ID 在后)。单个请求失败仅 dev_warn 警告,不阻断 probe。

Aaron,方便帮忙确认第二个请求不会在 5158/5159 上导致错误吗?

设备表 — 收敛为实测 PID

Shengyu 指出 28 个 ID 的列表过于膨胀,完整列表源自 Zixing Liu 的
早期补丁 [1],并非凭空编造,但因大部分未实机验证,已缩减为 6 个条目
(见上表)。有线直连(Controller)与无线接收器(Dongle)枚举为不同 PID,
因此成对出现。Liu 补丁中的其余 PID 可在逐一实测后追加。

KP40D 接收器保活 — HID_QUIRK_ALWAYS_POLL

Aaron 提到的 ALWAYS_POLL 方案在 20dd:515c(KP40D)上通过 usbhid.quirks
内核 cmdline(GRUB)验证,未经过内核完整编译测试。附带的 hid-ids.h 和
hid-quirks.c 修改为预期合入后的最终形态,实际运行时验证仅通过 cmdline
完成。KP20 无线(5128)无需保活即可正常工作。仅添加了 KP40D 的 ID。

命名 — Controller 与 Dongle 区分

5126/515b 是有线直连手柄本体 → "Controller"。5128/515c 是无线接收器 →
"Dongle"。这与"手柄本体使用不同 VID"的事实一致——有线模式下 USB 设备
就是手柄本身,已经修改无线模式下错误的命名。

[1] https://lore.kernel.org/linux-input/20260102030154.197749-2-liushuyu@aosc.io/

Signed-off-by: VegetablCat <vegetablecat@foxmail.com>

[-- Attachment #2: v4-0001-Input-xpad-add-support-for-Beitong-KP-series.patch --]
[-- Type: text/x-patch, Size: 3721 bytes --]

--- a/drivers/input/joystick/xpad.c	2026-07-26 01:34:34.503850264 +0800
+++ b/drivers/input/joystick/xpad.c	2026-08-04 13:48:07.034309653 +0800
@@ -72,6 +72,7 @@
 #define PKT_XBE2_FW_5_11    4
 
 #define FLAG_DELAY_INIT BIT(0)
+#define FLAG_READ_MS_OS_DESC BIT(1)
 
 static bool dpad_to_buttons;
 module_param(dpad_to_buttons, bool, S_IRUGO);
@@ -332,8 +333,12 @@ static const struct xpad_device {
 	{ 0x1bad, 0xfd00, "Razer Onza TE", 0, XTYPE_XBOX360 },
 	{ 0x1bad, 0xfd01, "Razer Onza", 0, XTYPE_XBOX360 },
 	{ 0x1ee9, 0x1590, "ZOTAC Gaming Zone", 0, XTYPE_XBOX360 },
+	{ 0x20bc, 0x5126, "BETOP BTP-KP20A Xinput Controller", 0, XTYPE_XBOX360, FLAG_READ_MS_OS_DESC },
+	{ 0x20bc, 0x5128, "BETOP BTP-KP20A Xinput Dongle", 0, XTYPE_XBOX360, FLAG_READ_MS_OS_DESC },
 	{ 0x20bc, 0x5134, "BETOP BTP-KP50B Xinput Dongle", 0, XTYPE_XBOX360 },
 	{ 0x20bc, 0x514a, "BETOP BTP-KP50C Xinput Dongle", 0, XTYPE_XBOX360 },
+	{ 0x20bc, 0x515b, "BETOP BTP-KP40D Xinput Controller", 0, XTYPE_XBOX360, FLAG_READ_MS_OS_DESC },
+	{ 0x20bc, 0x515c, "BETOP BTP-KP40D Xinput Dongle", 0, XTYPE_XBOX360, FLAG_READ_MS_OS_DESC },
 	{ 0x20d6, 0x2001, "BDA Xbox Series X Wired Controller", 0, XTYPE_XBOXONE },
 	{ 0x20d6, 0x2009, "PowerA Enhanced Wired Controller for Xbox Series X|S", 0, XTYPE_XBOXONE },
 	{ 0x20d6, 0x2064, "PowerA Wired Controller for Xbox", MAP_SHARE_BUTTON, XTYPE_XBOXONE },
@@ -778,6 +783,7 @@ struct usb_xpad {
 	time64_t mode_btn_down_ts;
 	bool delay_init;		/* init packets should be delayed */
 	bool delayed_init_done;
+	bool read_ms_os_desc;		/* read Microsoft OS descriptors during probe */
 };
 
 static int xpad_init_input(struct usb_xpad *xpad);
@@ -2044,6 +2050,7 @@ static int xpad_probe(struct usb_interfa
 	struct usb_device *udev = interface_to_usbdev(intf);
 	struct usb_xpad *xpad;
 	struct usb_endpoint_descriptor *ep_irq_in, *ep_irq_out;
+	u8 ms_os_desc[128];
 	int i, error;
 
 	if (intf->cur_altsetting->desc.bNumEndpoints != 2)
@@ -2082,6 +2089,8 @@ static int xpad_probe(struct usb_interfa
 	xpad->name = xpad_device[i].name;
 	if (xpad_device[i].flags & FLAG_DELAY_INIT)
 		xpad->delay_init = true;
+	if (xpad_device[i].flags & FLAG_READ_MS_OS_DESC)
+		xpad->read_ms_os_desc = true;
 
 	xpad->packet_type = PKT_XB;
 	INIT_WORK(&xpad->work, xpad_presence_work);
@@ -2148,6 +2157,41 @@ static int xpad_probe(struct usb_interfa
 	xpad->irq_in->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
 
 	usb_set_intfdata(intf, xpad);
+	if (xpad->read_ms_os_desc) {
+		/*
+		 * Microsoft OS 1.0 sequence: first read the OS string
+		 * descriptor at index 0xEE, then the Extended Compat ID
+		 * descriptor. Some devices (e.g. 20bc:5158/5159) lock into
+		 * XInput mode on the string descriptor read alone; others
+		 * (e.g. 20bc:5126/515b) require the Extended Compat ID read.
+		 * Send both to cover the whole family; each may fail on
+		 * devices that do not implement it, which is harmless.
+		 */
+		error = usb_control_msg_recv(udev, 0,
+					     USB_REQ_GET_DESCRIPTOR,
+					     USB_DIR_IN,
+					     (USB_DT_STRING << 8) | 0xee,
+					     0x0000,
+					     ms_os_desc,
+					     sizeof(ms_os_desc), 25,
+					     GFP_KERNEL);
+		if (error)
+			dev_warn(&intf->dev,
+				 "unable to read Microsoft OS string descriptor: %d\n",
+				 error);
+
+		error = usb_control_msg_recv(udev, 0, 0xee,
+					     USB_TYPE_VENDOR | USB_DIR_IN |
+						USB_RECIP_DEVICE,
+					     0x0000, 0x0004,
+					     ms_os_desc,
+					     sizeof(ms_os_desc), 25,
+					     GFP_KERNEL);
+		if (error)
+			dev_warn(&intf->dev,
+				 "unable to read Microsoft feature descriptor: %d\n",
+				 error);
+	}
 
 	/* Packet type detection */
 	if (le16_to_cpu(udev->descriptor.idVendor) == 0x045e) { /* Microsoft controllers */

[-- Attachment #3: v4-0002-HID-quirks-Add-ALWAYS_POLL-for-Beitong-KP40D.patch --]
[-- Type: text/x-patch, Size: 1344 bytes --]

--- a/drivers/hid/hid-ids.h	2026-08-04 13:39:41.345525174 +0800
+++ b/drivers/hid/hid-ids.h	2026-08-04 13:23:25.386480463 +0800
@@ -273,6 +273,8 @@
 #define USB_VENDOR_ID_BETOP_2185PC	0x11c0
 #define USB_VENDOR_ID_BETOP_2185V2PC	0x8380
 #define USB_VENDOR_ID_BETOP_2185V2BFM	0x20bc
+#define USB_VENDOR_ID_BETOP_20DD		0x20dd
+#define USB_DEVICE_ID_BETOP_KP40D	0x515c
 
 #define USB_VENDOR_ID_BIGBEN	0x146b
 #define USB_DEVICE_ID_BIGBEN_PS3OFMINIPAD	0x0902
--- a/drivers/hid/hid-quirks.c	2026-08-04 13:39:41.345525174 +0800
+++ b/drivers/hid/hid-quirks.c	2026-08-04 13:08:23.930343250 +0800
@@ -45,6 +45,8 @@ static const struct hid_device_id hid_qu
 	{ HID_USB_DEVICE(USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_CS682), HID_QUIRK_NOGET },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_CS692), HID_QUIRK_NOGET },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_UC100KM), HID_QUIRK_NOGET },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_BETOP_20DD,
+			 USB_DEVICE_ID_BETOP_KP40D), HID_QUIRK_ALWAYS_POLL },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_MULTI_TOUCH), HID_QUIRK_MULTI_INPUT },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_PIXART_USB_OPTICAL_MOUSE), HID_QUIRK_ALWAYS_POLL },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_PIXART_USB_OPTICAL_MOUSE2), HID_QUIRK_ALWAYS_POLL },

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [PATCH v4] Input: xpad - add support for Beitong KP series controllers
  2026-08-04  5:50 [PATCH v4] Input: xpad - add support for Beitong KP series controllers vegetablecat
@ 2026-08-04  5:56 ` sashiko-bot
  0 siblings, 0 replies; 3+ messages in thread
From: sashiko-bot @ 2026-08-04  5:56 UTC (permalink / raw)
  To: vegetablecat; +Cc: linux-input, dmitry.torokhov

Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [High] Contradictory Vendor ID for the KP40D controller between the Xpad driver table and HID quirks.
- [Medium] Unconditional `-EREMOTEIO` errors and spurious warnings due to `usb_control_msg_recv()` exact-size enforcement.
--

--- Patch [1]: [PATCH v4] Input: xpad - add support for Beitong KP series controllers ---
commit 70428191ed674d48449b3a34df01ce588dc47bd5
Author: vegetablecat@foxmail.com <vegetablecat@foxmail.com>

Input: xpad - add support for Beitong KP series controllers
    
This patch adds support for the Beitong KP series controllers (both wired
and wireless modes) to the xpad driver. It introduces a Microsoft OS 1.0
descriptor sequence to lock the controllers into XInput mode during probe
and adds a keepalive HID quirk for the KP40D receiver.

Link: https://lore.kernel.org/linux-input/20260102030154.197749-2-liushuyu@aosc.io/

> diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
> index b70f719b3b075..8baa9efd2f724 100644
> --- a/drivers/hid/hid-ids.h
> +++ b/drivers/hid/hid-ids.h
> @@ -273,6 +273,8 @@
>  #define USB_VENDOR_ID_BETOP_2185PC	0x11c0
>  #define USB_VENDOR_ID_BETOP_2185V2PC	0x8380
>  #define USB_VENDOR_ID_BETOP_2185V2BFM	0x20bc
> +#define USB_VENDOR_ID_BETOP_20DD		0x20dd
> +#define USB_DEVICE_ID_BETOP_KP40D	0x515c

[Severity: High]
Is the Vendor ID for the KP40D correct here? 

In the xpad driver modifications below, the KP40D dongle (PID 0x515c) is
registered using the Vendor ID 0x20bc:

    { 0x20bc, 0x515c, "BETOP BTP-KP40D Xinput Dongle", ... }

If the device actually uses VID 0x20bc, applying the HID quirk to VID 0x20dd
in hid-quirks.c will prevent the HID_QUIRK_ALWAYS_POLL quirk from matching
the device. Which VID is the correct one for the KP40D?

[ ... ]

> diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c
> index 2da0b7f1722aa..ec511dc2e0806 100644
> --- a/drivers/input/joystick/xpad.c
> +++ b/drivers/input/joystick/xpad.c

[ ... ]

> @@ -2150,6 +2159,41 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
>  	xpad->irq_in->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
>  
>  	usb_set_intfdata(intf, xpad);
> +	if (xpad->read_ms_os_desc) {
> +		/*
> +		 * Microsoft OS 1.0 sequence: first read the OS string
> +		 * descriptor at index 0xEE, then the Extended Compat ID
> +		 * descriptor. Some devices (e.g. 20bc:5158/5159) lock into
> +		 * XInput mode on the string descriptor read alone; others
> +		 * (e.g. 20bc:5126/515b) require the Extended Compat ID read.
> +		 * Send both to cover the whole family; each may fail on
> +		 * devices that do not implement it, which is harmless.
> +		 */
> +		error = usb_control_msg_recv(udev, 0,
> +					     USB_REQ_GET_DESCRIPTOR,
> +					     USB_DIR_IN,
> +					     (USB_DT_STRING << 8) | 0xee,
> +					     0x0000,
> +					     ms_os_desc,
> +					     sizeof(ms_os_desc), 25,
> +					     GFP_KERNEL);

[Severity: Medium]
Will this unconditionally fail and print spurious warnings in dmesg? 

The usb_control_msg_recv() helper expects the USB device to return exactly
the number of bytes requested, otherwise it considers it a short read and
returns -EREMOTEIO. 

Since the Microsoft OS string descriptor is typically 18 bytes and the feature
descriptor is usually 40 bytes, won't passing sizeof(ms_os_desc) (128 bytes)
for both requests cause them to always fail and trigger the dev_warn() paths
below?

> +		if (error)
> +			dev_warn(&intf->dev,
> +				 "unable to read Microsoft OS string descriptor: %d\n",
> +				 error);
> +
> +		error = usb_control_msg_recv(udev, 0, 0xee,
> +					     USB_TYPE_VENDOR | USB_DIR_IN |
> +						USB_RECIP_DEVICE,
> +					     0x0000, 0x0004,
> +					     ms_os_desc,
> +					     sizeof(ms_os_desc), 25,
> +					     GFP_KERNEL);
> +		if (error)
> +			dev_warn(&intf->dev,
> +				 "unable to read Microsoft feature descriptor: %d\n",
> +				 error);
> +	}
>  
>  	/* Packet type detection */
>  	if (le16_to_cpu(udev->descriptor.idVendor) == 0x045e) { /* Microsoft controllers */

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/tencent_72D4D10513DFB685733F4F75EDA62F6EE107@qq.com?part=1

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [PATCH v4] Input: xpad - add support for Beitong KP series controllers
@ 2026-08-04  5:59 vegetablecat
  0 siblings, 0 replies; 3+ messages in thread
From: vegetablecat @ 2026-08-04  5:59 UTC (permalink / raw)
  To: linux-input
  Cc: linux-kernel, Dmitry Torokhov, Aaron Ma, Shengyu Qu, Zixing Liu

On Mon, Aug 04, 2026 at XX:XX, sashiko-bot wrote:
> [High] Contradictory Vendor ID for KP40D between xpad table (0x20bc)
> and HID quirks (0x20dd).

Both are correct. The KP40D wireless dongle is a composite USB device
that exposes two interfaces with different VIDs:
  - 20bc:515c  XInput interface, handled by xpad
  - 20dd:515c  HID interface, kept alive by HID_QUIRK_ALWAYS_POLL

> [Medium] usb_control_msg_recv() with sizeof(ms_os_desc)=128 will
> unconditionally fail with -EREMOTEIO on short reads.

This is not an issue in practice. The device locks correctly on all
four tested PIDs (5126/5128/515b/515c). The response data from these
requests is not consumed — the act of sending the MS OS descriptor
request sequence is what triggers the firmware lock. If any request
returns -EREMOTEIO on a particular platform, the dev_warn() is
informational and does not block probe.

Thanks for the review.


^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2026-08-04  5:59 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-04  5:50 [PATCH v4] Input: xpad - add support for Beitong KP series controllers vegetablecat
2026-08-04  5:56 ` sashiko-bot
  -- strict thread matches above, loose matches on Subject: below --
2026-08-04  5:59 vegetablecat

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox