From nobody Tue Apr 7 09:05:26 2026 Received: from mail-pf1-f180.google.com (mail-pf1-f180.google.com [209.85.210.180]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id AD7C0261388 for ; Sat, 14 Mar 2026 07:51:28 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.210.180 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773474690; cv=none; b=jJ5FXuQhH9Ew+YnVeaW2w975atMMZPdBJnH/zQVMTM2ecQCNbvm8wz6HMs47K9dIhNorbZk53Lo+Xto1P7StFsEW1HWoK3eVlzWH2u4eFouyFhSYUBDPVlJwE+Y1bRmGV5EQohzFIq5WiykLJiSyni21tATLXxh2Tp0tKnskjPg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773474690; c=relaxed/simple; bh=2F8H55rYZ/j2cKInESmasrnF63FUKxVPCPnL+zkPMYc=; h=From:To:Cc:Subject:Date:Message-ID:MIME-Version; b=WWaFLYqAamhhSUwgFK7Fb7RuQD2pdHyPGL0u0aDzCkZHPS0f26axNDu0t6eITLdltp3o3rBj42NzfnBtGmeq373DoMsFnaE5iE+AGGqLk/xcqLoqJOQ7gCY5+T5rHgcQ4jghsPupDCd6kqEPHxlnZOFRFeVim4ze8nMwfRjBhnM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=l7X1rr1w; arc=none smtp.client-ip=209.85.210.180 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="l7X1rr1w" Received: by mail-pf1-f180.google.com with SMTP id d2e1a72fcca58-829b2018c94so1742258b3a.0 for ; Sat, 14 Mar 2026 00:51:28 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1773474688; x=1774079488; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:from:to:cc:subject:date:message-id:reply-to; bh=U45jrujbw5JJI0xF9tm4sefL6UUjJiPpRTs8obNU44E=; b=l7X1rr1wbB/KLWcjxdD+evIl38o0XfHBqrGtABhrPtMjWFexhNOMwfYPkIBijHVAVx PAfhpTNIiP5wjy7e522xKYBAbWQrtRxq5JPyk4rr7jLY2eBKe06MkFLNWE+PZocMquL/ 3ft/6KltiiPUGjgcLc8RD3YDQqSjS+XZiOsUzIPswa9eNAh/zvUBLmMrT/tZUD68vxM2 9fQ9GaLTkr6NyvlUaQb/C19f1BYE96HCJULPmCu5cPmXbpDQPcDdW76Sp0QSM4w2FE0x DcDQt07B/4pHxiTe3kSG6jgSX3LHWkJYoeCFuDaHFGcSMIB2vlzy5odhEIYxEivuV9MD Po/g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1773474688; x=1774079488; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:x-gm-gg:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to; bh=U45jrujbw5JJI0xF9tm4sefL6UUjJiPpRTs8obNU44E=; b=sZo9trd4WZe6bC8pWPe4WiScjCgZ2bfGdhNsEw6HPls2gwu0CGvsyCY3viercNYB3B 7srWVspqMuCSk8V7lprpco+NawV7usBYgHn+ZRs3tUowp/kVoYBPkoLPC7Zl+14BOf9Z ixvXGPo3OX8YkVmEdXKUYtmR20gFkCPsbPdzK+4AqOwMOmfUpo5E4nFnM99FwE5/Hv+Z RK8+58ABuIGTgLdaA8Re1jX/XyEIAbePIrdoKt891b7ABh+FoKolg3ZQOiOWyn70ar+a XhsV9XL6R7FsyuAivGLfXgmvPWNc4h/B90qaMo2eE0+MdAD/nZrhfN0zeVHApzebw4kL hh4g== X-Forwarded-Encrypted: i=1; AJvYcCUmDlyx6BoA8+ToL3LeV0H5c/wuHvLhvHFt99up8S+zpP6tQ674BdxFyr3neufhxH2jfIwfpzEkDk7Ij2M=@vger.kernel.org X-Gm-Message-State: AOJu0Yy4Jur7BQgSAts9wPI9M/BIrnAk8eBJyBBP8tYBBPlkTZVmZp+5 YbiLBGecI3vmMZPDag9frTQiZtM4sa+M9BmxZI1SKjAfTE+YR42EIsNc X-Gm-Gg: ATEYQzy+OI3Xy0f10Pjeu5Xi3FVZ38WKmL9nAfF3QNARVpxGsR4xShhjthvbGL0YHMz W8oSXgPOmIVd0N8FwgLlfvCUjtQlVNsasNkDUpmFzor06u8GpyWG7jM9mL1W0LmdKjtkk7YS2FV qZ/zEsGpbkTy+VyK5l+xiG79jXpGy6cvQbYrQT2c+8TMuX76GiTZ5nPAu/odXapAyiRyeQ1+L+q XOmDHTA1clHbtXYnplP8fMBHTQ15lXUro7UYUkReOHqVIQH+E+YNWMetG4oMt40HWCfrvefwPKt 34bTq/QKwASmDiexerxGlevyiUMi7JA8g60CdE1i5JqiitiKlxtTRnHuZ7Xokj7s+ur3CFUYV46 rjo56bRpdql5DBiP1V/dvlu92u4j1azqJM3MtgoVC65B5BXEQV8HzvF7c14C7iz8ZH3SwwqyuLx WQgYTPR5dDKabsoDt4RoPhox7bF/THi7IV0vXob08kqaZLMVLNU/qJf7SzIeJf1G7T5dDlcctYO +xG8nJf/JyoNZOC72BJFPnbtf28bUyS1j3sa6YAviQNwVB7s18VJ77Diq55CePB8Uw= X-Received: by 2002:a05:6a21:6f8b:b0:398:a440:e3bc with SMTP id adf61e73a8af0-398ecdfc03dmr5865315637.66.1773474687889; Sat, 14 Mar 2026 00:51:27 -0700 (PDT) Received: from sanjays-pc.govzhome.govindz.co.nz ([116.251.152.103]) by smtp.gmail.com with ESMTPSA id 41be03b00d2f7-c73ebb649a8sm3563670a12.18.2026.03.14.00.51.23 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 14 Mar 2026 00:51:27 -0700 (PDT) From: Sanjay Govind To: Dmitry Torokhov , Vicki Pfau , Nilton Perim Neto , Mario Limonciello , Sanjay Govind , "Pierre-Loup A. Griffais" Cc: Antheas Kapenekakis , linux-input@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH] xpad: Overhaul device data for wireless devices Date: Sat, 14 Mar 2026 20:50:32 +1300 Message-ID: <20260314075034.1488655-2-sanjay.govind9@gmail.com> X-Mailer: git-send-email 2.53.0 Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Xbox 360 wireless controllers expose information in the link and capabilities reports. Extract and use the vendor id for wireless controllers, and use the subtype to build a nicer device name and product id. Some xbox 360 controllers put a vid and pid into the stick capability data, so check if this was done, and pull the vid, pid and revision from there. Signed-off-by: Sanjay Govind --- drivers/input/joystick/xpad.c | 138 +++++++++++++++++++++++++++++++++- 1 file changed, 135 insertions(+), 3 deletions(-) diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c index bf4accf3f581..2490eb21a534 100644 --- a/drivers/input/joystick/xpad.c +++ b/drivers/input/joystick/xpad.c @@ -94,6 +94,22 @@ #define XTYPE_XBOXONE 3 #define XTYPE_UNKNOWN 4 =20 +#define FLAG_FORCE_FEEDBACK 0x01 + +#define SUBTYPE_GAMEPAD 0x01 +#define SUBTYPE_WHEEL 0x02 +#define SUBTYPE_ARCADE_STICK 0x03 +#define SUBTYPE_FLIGHT_SICK 0x04 +#define SUBTYPE_DANCE_PAD 0x05 +#define SUBTYPE_GUITAR 0x06 +#define SUBTYPE_GUITAR_ALTERNATE 0x07 +#define SUBTYPE_DRUM_KIT 0x08 +#define SUBTYPE_GUITAR_BASS 0x0B +#define SUBTYPE_RB_KEYBOARD 0x0F +#define SUBTYPE_ARCADE_PAD 0x13 +#define SUBTYPE_TURNTABLE 0x17 +#define SUBTYPE_PRO_GUITAR 0x19 + /* Send power-off packet to xpad360w after holding the mode button for thi= s many * seconds */ @@ -795,6 +811,9 @@ struct usb_xpad { int xtype; /* type of xbox device */ int packet_type; /* type of the extended packet */ int pad_nr; /* the order x360 pads were attached */ + u8 sub_type; + u16 flags; + u16 wireless_vid; const char *name; /* name of the device */ struct work_struct work; /* init/remove device from callback */ time64_t mode_btn_down_ts; @@ -807,6 +826,8 @@ static void xpad_deinit_input(struct usb_xpad *xpad); static int xpad_start_input(struct usb_xpad *xpad); static void xpadone_ack_mode_report(struct usb_xpad *xpad, u8 seq_num); static void xpad360w_poweroff_controller(struct usb_xpad *xpad); +static int xpad_inquiry_pad_capabilities(struct usb_xpad *xpad); + =20 /* * xpad_process_packet @@ -1026,12 +1047,46 @@ static void xpad360w_process_packet(struct usb_xpad= *xpad, u16 cmd, unsigned cha if (data[0] & 0x08) { present =3D (data[1] & 0x80) !=3D 0; =20 - if (xpad->pad_present !=3D present) { + /* delay prescence until after we get the link report */ + if (!present && xpad->pad_present) { xpad->pad_present =3D present; schedule_work(&xpad->work); } } =20 + /* Link report */ + if (data[0] =3D=3D 0x00 && data[1] =3D=3D 0x0F) { + xpad->sub_type =3D data[25] & 0x7f; + + /* Decode vendor id from link report */ + xpad->wireless_vid =3D ((data[0x16] & 0xf) | data[0x18] << 4) << 8 | dat= a[0x17]; + + if ((data[25] & 0x80) !=3D 0) + xpad->flags |=3D FLAG_FORCE_FEEDBACK; + + if (!xpad->pad_present) { + xpad->pad_present =3D true; + schedule_work(&xpad->work); + } + xpad_inquiry_pad_capabilities(xpad); + } + + /* Capabilities report */ + if (data[0] =3D=3D 0x00 && data[1] =3D=3D 0x05 && data[5] =3D=3D 0x12) { + xpad->flags |=3D data[20]; + /* + * A bunch of vendors started putting vids and pids + * into capabilities data because they can't be + * retrieved by xinput easliy. + * Not all of them do though, so check the vids match + * before extracting that info. + */ + if (((data[11] << 8) | data[10]) =3D=3D xpad->wireless_vid) { + xpad->dev->id.product =3D (data[13] << 8) | data[12]; + xpad->dev->id.version =3D (data[15] << 8) | data[14]; + } + } + /* Valid pad data */ if (data[1] !=3D 0x1) return; @@ -1495,6 +1550,31 @@ static int xpad_inquiry_pad_presence(struct usb_xpad= *xpad) return xpad_try_sending_next_out_packet(xpad); } =20 +static int xpad_inquiry_pad_capabilities(struct usb_xpad *xpad) +{ + struct xpad_output_packet *packet =3D + &xpad->out_packets[XPAD_OUT_CMD_IDX]; + + guard(spinlock_irqsave)(&xpad->odata_lock); + + packet->data[0] =3D 0x00; + packet->data[1] =3D 0x00; + packet->data[2] =3D 0x02; + packet->data[3] =3D 0x80; + packet->data[4] =3D 0x00; + packet->data[5] =3D 0x00; + packet->data[6] =3D 0x00; + packet->data[7] =3D 0x00; + packet->data[8] =3D 0x00; + packet->data[9] =3D 0x00; + packet->data[10] =3D 0x00; + packet->data[11] =3D 0x00; + packet->len =3D 12; + packet->pending =3D true; + + return xpad_try_sending_next_out_packet(xpad); +} + static int xpad_start_xbox_one(struct usb_xpad *xpad) { int error; @@ -1965,8 +2045,60 @@ static int xpad_init_input(struct usb_xpad *xpad) usb_to_input_id(xpad->udev, &input_dev->id); =20 if (xpad->xtype =3D=3D XTYPE_XBOX360W) { - /* x360w controllers and the receiver have different ids */ - input_dev->id.product =3D 0x02a1; + /* + * x360w controllers on windows put the subtype into the product + * for wheels and gamepads, but it makes sense to do it for all + * subtypes + */ + input_dev->id.product =3D 0x02a0 + xpad->sub_type; + /* If the Link report has provided a vid, it won't be set to 1 */ + if (xpad->wireless_vid !=3D 1) + input_dev->id.vendor =3D xpad->wireless_vid; + switch (xpad->sub_type) { + case SUBTYPE_GAMEPAD: + input_dev->name =3D "Xbox 360 Wireless Controller"; + break; + case SUBTYPE_WHEEL: + input_dev->name =3D "Xbox 360 Wireless Wheel"; + break; + case SUBTYPE_ARCADE_STICK: + input_dev->name =3D "Xbox 360 Wireless Arcade Stick"; + break; + case SUBTYPE_FLIGHT_SICK: + input_dev->name =3D "Xbox 360 Wireless Flight Stick"; + break; + case SUBTYPE_DANCE_PAD: + input_dev->name =3D "Xbox 360 Wireless Dance Pad"; + break; + case SUBTYPE_GUITAR: + input_dev->name =3D "Xbox 360 Wireless Guitar"; + break; + case SUBTYPE_GUITAR_ALTERNATE: + input_dev->name =3D "Xbox 360 Wireless Alternate Guitar"; + break; + case SUBTYPE_GUITAR_BASS: + input_dev->name =3D "Xbox 360 Wireless Bass Guitar"; + break; + case SUBTYPE_DRUM_KIT: + /* Vendors used force feedback flag to differentiate these */ + if (xpad->flags & FLAG_FORCE_FEEDBACK) + input_dev->name =3D "Xbox 360 Wireless Guitar Hero Drum Kit"; + else + input_dev->name =3D "Xbox 360 Wireless Rock Band Drum Kit"; + break; + case SUBTYPE_RB_KEYBOARD: + input_dev->name =3D "Xbox 360 Wireless Rock Band Keyboard"; + break; + case SUBTYPE_ARCADE_PAD: + input_dev->name =3D "Xbox 360 Wireless Arcade Pad"; + break; + case SUBTYPE_TURNTABLE: + input_dev->name =3D "Xbox 360 Wireless DJ Hero Turntable"; + break; + case SUBTYPE_PRO_GUITAR: + input_dev->name =3D "Xbox 360 Wireless Rock Band Pro Guitar"; + break; + } } =20 input_dev->dev.parent =3D &xpad->intf->dev; --=20 2.53.0