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

Reply via email to