Hi,
I want to make my Xbox 360 wireless controller work. Although
it is "wireless", it actually communicates through usb(4) to a
dongle receiver[1] that connects with up to 4 controllers.
For that, I recompiled the kernel with the attached patch, and
booted into it. When plugging the receiver, I get this output
from usbdevs(8) and dmesg(8):
| $ usbdevs -v
| Controller /dev/usb0:
| [...]
| addr 02: 045e:0719 \M-)Microsoft, Xbox 360 Wireless Receiver for Windows
| full speed, power 260 mA, config 1, rev 1.00, iSerial FF4CC9A0
| driver: uhidev1
| driver: uhidev2
| driver: uhidev3
| driver: uhidev4
| [...]
|
| $ dmesg
| [...]
| uhidev0 at uhub0 port 1 configuration 1 interface 0 "\M-)Microsoft Xbox 360
Wireless Receiver for Windows" rev 2.00/1.00 addr 2
| uhidev0: iclass 255/93
| ujoy0 at uhidev0: input=20, output=0, feature=0
| uhidev1 at uhub0 port 1 configuration 1 interface 2 "\M-)Microsoft Xbox 360
Wireless Receiver for Windows" rev 2.00/1.00 addr 2
| uhidev1: iclass 255/93
| ujoy1 at uhidev1: input=20, output=0, feature=0
| uhidev2 at uhub0 port 1 configuration 1 interface 4 "\M-)Microsoft Xbox 360
Wireless Receiver for Windows" rev 2.00/1.00 addr 2
| uhidev2: iclass 255/93
| ujoy2 at uhidev2: input=20, output=0, feature=0
| uhidev3 at uhub0 port 1 configuration 1 interface 6 "\M-)Microsoft Xbox 360
Wireless Receiver for Windows" rev 2.00/1.00 addr 2
| uhidev3: iclass 255/93
| ujoy3 at uhidev3: input=20, output=0, feature=0
| ugen2 at uhub0 port 1 configuration 1 "\M-)Microsoft Xbox 360 Wireless
Receiver for Windows" rev 2.00/1.00 addr 2
Four ujoy(4) drivers are automatically attached after plugging
the receiver. And the controllers are listed on SuperTuxKart,
for example. But when I pair the controller with the receiver
(both have a button I need to press at the same time for that)
the controller does not see itself as paired.
I think that some kind of communication between the driver and
the receiver needs to be performed. I checked the code of the
xbox gamepad driver in the Linux kernel (see xpad.c[2]), and I
could identify two things:
First, Linux driver calls xpad360w_start_input() when a device
is plugged to send it an HID output request. Here's a comment
from that function:
> Send presence packet.
> This will force the controller to resend connection packets.
> This is useful in the case we activate the module after the
> adapter has been plugged in, as it won't automatically
> send us info about the controllers.
On OpenBSD, I fixed uhidev_use_rdesc() in sys/dev/usb/uhidev.c
to make the driver send the same packets that Linux does. But
I do not think the device ever receives them, as dmesg(8) says
that the size of the output report is zero. Also, I found the
following comment in the wired controller's report descriptor,
which the wireless controller also uses (more on that bellow),
in sys/dev/usb/uhid_rdesc.h:
> The descriptor has no output report format, thus preventing
> you from controlling the LEDs and the built-in rumblers.
I do not know how to expand the report descriptor to include a
format for output report (nor whether that is feasible).
Second, the Linux driver converts input requests into requests
for the regular wired controller report descriptor. It parses
the first 4 byts of the report data (with info about whether a
controller has been connected/disconnected), then it processes
the remaining data (&data[4]) as if it was read from a regular
wired controller. See xpad360w_process_packets() in the Linux
file.
Again, I do not know how I can expand the existing xbox report
descriptor (or write a new one for the wireless controller) to
ignore the first four bytes.
So I am stuck now.
I ask for help on how I can continue hacking the driver to add
support for this controller.
Thank you,
-- Lucas de Sena
[1]: https://commons.wikimedia.org/wiki/File:Xbox_360_Wireless_Receiver.png
[2]:
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/plain/drivers/input/joystick/xpad.c
diff /usr/src
commit - b87515de6c2d632ea9e8c74e8b0ceb61cc0773ae
path + /usr/src
blob - c0664fbf239386b0aaf5191c0663db387aea27f5
file + sys/dev/usb/uhidev.c
--- sys/dev/usb/uhidev.c
+++ sys/dev/usb/uhidev.c
@@ -65,6 +65,8 @@ int uhidev_use_rdesc(struct uhidev_softc *, usb_interf
int, int, void **, int *);
#define UISUBCLASS_XBOX360_CONTROLLER 0x5d
#define UIPROTO_XBOX360_GAMEPAD 0x01
+#define UISUBCLASS_XBOX360W_CONTROLLER 0x5d
+#define UIPROTO_XBOX360W_GAMEPAD 0x81
#define UISUBCLASS_XBOXONE_CONTROLLER 0x47
#define UIPROTO_XBOXONE_GAMEPAD 0xd0
#endif /* !SMALL_KERNEL */
@@ -126,6 +128,10 @@ uhidev_match(struct device *parent, void *match, void
id->bInterfaceProtocol == UIPROTO_XBOX360_GAMEPAD)
return (UMATCH_IFACECLASS_IFACESUBCLASS_IFACEPROTO);
if (id->bInterfaceClass == UICLASS_VENDOR &&
+ id->bInterfaceSubClass == UISUBCLASS_XBOX360W_CONTROLLER &&
+ id->bInterfaceProtocol == UIPROTO_XBOX360W_GAMEPAD)
+ return (UMATCH_IFACECLASS_IFACESUBCLASS_IFACEPROTO);
+ if (id->bInterfaceClass == UICLASS_VENDOR &&
id->bInterfaceSubClass == UISUBCLASS_XBOXONE_CONTROLLER &&
id->bInterfaceProtocol == UIPROTO_XBOXONE_GAMEPAD) {
return (UMATCH_IFACECLASS_IFACESUBCLASS_IFACEPROTO);
@@ -373,6 +379,12 @@ uhidev_use_rdesc(struct uhidev_softc *sc, usb_interfac
size = sizeof(uhid_xb360gp_report_descr);
descptr = uhid_xb360gp_report_descr;
} else if ((id->bInterfaceClass == UICLASS_VENDOR &&
+ id->bInterfaceSubClass == UISUBCLASS_XBOX360W_CONTROLLER &&
+ id->bInterfaceProtocol == UIPROTO_XBOX360W_GAMEPAD)) {
+ /* The Xbox 360 wireless gamepad has no report descriptor. */
+ size = sizeof(uhid_xb360gp_report_descr);
+ descptr = uhid_xb360gp_report_descr;
+ } else if ((id->bInterfaceClass == UICLASS_VENDOR &&
id->bInterfaceSubClass == UISUBCLASS_XBOXONE_CONTROLLER &&
id->bInterfaceProtocol == UIPROTO_XBOXONE_GAMEPAD)) {
sc->sc_flags |= UHIDEV_F_XB1;
blob - 40346863f84113407ac0b674c81050ea69bedcbc
file + sys/dev/usb/usbdevs
--- sys/dev/usb/usbdevs
+++ sys/dev/usb/usbdevs
@@ -3146,6 +3146,7 @@ product MICROSOFT WLNOTEBOOK3 0x00d2 Wireless
Optical
product MICROSOFT WLNOTEBOOK2 0x00e1 Wireless Optical Mouse 3000 (Model 1056)
product MICROSOFT XBOX360_CONTROLLER 0x028e XBOX 360 Controller
product MICROSOFT XBOX360 0x0292 XBOX 360 WLAN
+product MICROSOFT XBOX360_WIRELESS_RECEIVER 0x0719 XBOX 360 Wireless Receiver
product MICROSOFT WLMOBILEMOUSE3500 0x0745 Wireless Mobile Mouse 3500
product MICROSOFT LIFECAM 0x074a Microsoft LifeCam
product MICROSOFT WLARCMOUSE 0x074f Wireless Arc Mouse (Model 1350)
blob - 9a7e68f213bb73fa1c2300bd85ec7a20cfd807f9
file + sys/dev/usb/usbdevs.h
--- sys/dev/usb/usbdevs.h
+++ sys/dev/usb/usbdevs.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: usbdevs.h,v 1.772 2023/11/27 20:04:07 miod Exp $ */
+/* $OpenBSD$ */
/*
* THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT.
@@ -3153,6 +3153,7 @@
#define USB_PRODUCT_MICROSOFT_WLNOTEBOOK2 0x00e1 /*
Wireless Optical Mouse 3000 (Model 1056) */
#define USB_PRODUCT_MICROSOFT_XBOX360_CONTROLLER 0x028e
/* XBOX 360 Controller */
#define USB_PRODUCT_MICROSOFT_XBOX360 0x0292 /* XBOX 360
WLAN */
+#define USB_PRODUCT_MICROSOFT_XBOX360_WIRELESS_RECEIVER 0x0719
/* XBOX 360 Wireless Receiver */
#define USB_PRODUCT_MICROSOFT_WLMOBILEMOUSE3500 0x0745 /*
Wireless Mobile Mouse 3500 */
#define USB_PRODUCT_MICROSOFT_LIFECAM 0x074a /* Microsoft
LifeCam */
#define USB_PRODUCT_MICROSOFT_WLARCMOUSE 0x074f /*
Wireless Arc Mouse (Model 1350) */
blob - 3cf210c7e8d550ed525068c6b8a40f2937fb72db
file + sys/dev/usb/usbdevs_data.h
--- sys/dev/usb/usbdevs_data.h
+++ sys/dev/usb/usbdevs_data.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: usbdevs_data.h,v 1.766 2023/11/27 20:04:07 miod Exp $ */
+/* $OpenBSD$ */
/*
* THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT.
@@ -7634,6 +7634,10 @@ const struct usb_known_product usb_known_products[] =
"XBOX 360 WLAN",
},
{
+ USB_VENDOR_MICROSOFT,
USB_PRODUCT_MICROSOFT_XBOX360_WIRELESS_RECEIVER,
+ "XBOX 360 Wireless Receiver",
+ },
+ {
USB_VENDOR_MICROSOFT, USB_PRODUCT_MICROSOFT_WLMOBILEMOUSE3500,
"Wireless Mobile Mouse 3500",
},