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", },