/dev/usb/oh0

From WiiBrew
< /dev‎ | usb
Jump to navigation Jump to search

/dev/usb/oh0 is used to interact with the Wii's external USB bus. This interface is very similar to /dev/usb/oh1 and has two parts: the "root" or host device, and individual devices on which USB requests can be submitted.

/dev/usb/oh0 (IOS57, 58 and 59)

In IOS57, 58 and 59, the OHCI0 module appears to implement a different interface and seems to only register this new interface of /dev/usb/oh0.

Only IOS_OPEN, IOS_CLOSE and IOS_IOCTL are valid commands. The other commands immediately return IPC_EINVAL (-4).

Additionally, /dev/usb/oh0 can only be opened from UID 0x11. Attempts to open OH0 with other UIDs will result in IPC_EACCES (-1).

Ioctl Name Input Output Notes
0 USBV2_IOCTL_GET_VERSION - 0x20 bytes Writes the version 0x20001 to the output buffer. This is very similar to the IOS58 version of /dev/usb/hid, which writes 0x50001 to the output buffer instead. It is also reminiscent of /dev/usb/ehc which does the same thing (but with an ioctlv).
1 ? ? ? ?
2 ? ? ? ?
3 ? 0x20 bytes ? ?
4 ? 0x20 bytes ? ?
5 ? 0x20 bytes ? ?
16 ? 0x20 bytes ? ?
17 ? 0x20 bytes ? ?
18 ? 0x20 bytes ? Handled by the same function as for ioctl 20.
19 ? 0x20 bytes ? ?
20 ? 0x20 bytes ? Handled by the same function as for ioctl 18.

/dev/usb/oh0

The OH1 module appears to be able to register itself as /dev/usb/oh0 and implements a similar set (subset?) of requests.

This list of requests is based on IOS36.

Request Name Input Output OH0/OH1 Notes
12 (ioctlv) USBV0_IOCTLV_GETDEVLIST 2 2 Both

Returns a list of connected devices matching an interface class.

struct Descriptor 
{
  u32 unknown;
  u16 vid;
  u16 pid;
};
// sizeof(Descriptor) = 8
  • in 0: u8 - number of descriptors to return
  • in 1: u8 - interface class
  • io 0: u8 - number of devices
  • io 1: u32* of size num_descriptors * 8 - device list
15 (ioctl) ? (USB_GetRhDesca) - 4 bytes Both Unknown; something to do with the root hub (Desc = description?). Appears to return 02 00 03 02 regardless of the number of plugged in devices. [check]
20 (ioctlv) USBV0_IOCTLV_GETRHPORTSTATUS 1 1 OH0 Supposedly used for getting the root hub's port status. (internal name: GetRhPortStatus) [check]
  • in 0: u8 - ?
  • io 0: u32 - Presumably the port status
25 (ioctlv) USBV0_IOCTLV_SETRHPORTSTATUS 2 0 OH0 Supposedly used for setting the root hub's port status. (internal name: SetRhPortStatus) [check]
  • in 0: u8 - ?
  • in 1: u32 - Presumably the port status
27 (ioctlv) USBV0_IOCTLV_DEVINSERTHOOK 2 0 OH0

Returns when a device with the requested VID/PID is plugged in, or immediately if the device is already inserted.

  • in 0: u16 - VID
  • in 1: u16 - PID
28 (ioctlv) USBV0_IOCTLV_DEVICECLASSCHANGE 1 0 OH0

Has to do with device insertion hooks. Triggered on device class change (?) [check]

  • in 0: u8 - Device class (can be zero)
30 (ioctlv) USBV0_IOCTLV_DEVINSERTHOOKID (RegisterInsertionNotifyWithId) 3 1 OH0

Returns when a device with the requested VID/PID is plugged in. Similar to ioctlv 27, but with additional parameters.

  • in 0: u16 - VID
  • in 1: u16 - PID
  • in 2: u8 - If falsy, return immediately if the device is already plugged in
  • io 0: u32 - Overwritten with an ID to use with ioctl 31 for cancelling this insertion hook
31 (ioctl) USBV0_IOCTL_CANCEL_INSERT_HOOK 4 bytes - OH0 Internal names: IUSB_CancelInsertionNotify / __ohciCancelNotifyInsertion

Cancels a device insertion hook (the hook request will be replied to with return value -7022). The input buffer is the ID given in the unique output vector of ioctlv 30.

Returns IPC_EINVAL if input buffer was nullptr. Otherwise, IPC_SUCCESS is returned if there was no hook; if there was a pending hook, the return value of IOS_ResourceReply(ioctlv_30_request, -7022) is used.

/dev/usb/oh0/%x/%x

These devices represent an individual USB device, based on its vendor ID and product ID (in hexadecimal format without leading zeroes). It is unclear how devices with the same VID/PID can be used at the same time.

Only one device handle can be opened at the same time. Attempting to open more than one results in IPC_EEXIST (-2).

This list is based on IOS36.

Request Name Input Output OH0/OH1 Notes
0 (ioctlv) USBV0_IOCTLV_CTRLMSG 6 1 Both

Submits a control transfer.

  • in 0: u8 - bmRequestType
  • in 1: u8 - bmRequest
  • in 2: u16 - wValue (swapped)
  • in 3: u16 - wIndex (swapped)
  • in 4: u16 - wLength (swapped)
  • in 5: u8 - Unknown (00)
  • io 0: array of length wLength - Request data
1 (ioctlv) USBV0_IOCTLV_BLKMSG 2 1 Both

Submits a bulk transfer.

  • in 0: u8 - Endpoint
  • in 1: u16 - Length
  • io 0: array of length in[1] - Payload data

If io_vectors[0].size and the length don't match, returns IPC_EINVAL.

2 (ioctlv) USBV0_IOCTLV_INTRMSG 2 1 Both

Submits an interrupt transfer.

  • in 0: u8 - Endpoint
  • in 1: u16 - Length
  • io 0: array of length in[1] - Payload data

If io_vectors[0].size and the length don't match, returns IPC_EINVAL.

5 (ioctl) USBV0_IOCTL_SUSPENDDEV - - Both

Used to suspend a device.

6 (ioctl) USBV0_IOCTL_RESUMEDEV - - Both

Used to resume a device.

9 (ioctlv) USBV0_IOCTLV_ISOMSG 3 2 OH0

Submits an isochronous transfer.

  • in 0: u8 - Endpoint
  • in 1: u16 - Length
  • in 2: u8 - Number of isochronous packets
  • io 0: u16* of size in[2] - Sizes of the isochronous packets
  • io 1: array of length in[1] - Payload data
10 (ioctlv) USBV0_IOCTLV_LBLKMSG 2 1 OH0

Submits a bulk transfer. This is the same as ioctlv 1, except that this takes a u32 for the length instead of a u16.

  • in 0: u8 - Endpoint
  • in 1: u32 - Length
  • io 0: array of length in_vectors[1] - Payload data

If io_vectors[0].size and the length don't match, returns IPC_EINVAL.

26 (ioctl) USBV0_IOCTL_DEVREMOVALHOOK - - Both

Returns when the device is unplugged or reset (in which cases the return value is IPC_SUCCESS / IPC_OK), or when the child device (/dev/usb/oh0/%x/%x) is closed (IPC_ENOENT).

Only one hook is allowed at the same time. Further ioctls to set up another hook before it is triggered result in IPC_EEXIST.

29 (ioctl) USBV0_IOCTL_RESET_DEVICE - - OH0

Triggers the associated removal hook before resetting the USB device.

32 (ioctlv) ? ? ? OH0 Unknown. [check]


33 (ioctlv) USBV0_IOCTLV_SETISOALT ? ? OH0

Select an alternative interface configuration (for devices with isochronous endpoints, the active interface determines if usb bandwidth is reserved for iso transfers). This is an alternative method to using a control message to achieve the same effect.

This ioctlv does not seem to be present in all IOS versions (not in IOS36 at least).

Known Devices

  • /dev/usb/oh0/0b95/7720: ASIX AX88772 USB2.0 to Fast Ethernet Adapter (referenced in IOS eth driver)
  • /dev/usb/oh0/57e/308: Nintendo Wii Speak (microphone)
  • /dev/usb/oh0/46d/a03: Logitech microphone

Errors

-4 (IPC_EINVAL): might be caused by an invalid device fd

-7003: STALL (according to gc-linux)

-7004: STALL (according to gc-linux)

-7005: NAK (according to gc-linux)

-7008

-7022