In memory of Ben “bushing” Byer, who passed away on Monday, February 8th, 2016.

/dev/usb/oh0: Difference between revisions

From WiiBrew
< /dev | usb
Jump to navigation Jump to search
Leoetlino (talk | contribs)
Leoetlino (talk | contribs)
tueidj: Thanks. Do you know in what IOS version it is implemented? It doesn't seem to be in IOS36.
 
(14 intermediate revisions by 2 users not shown)
Line 1: Line 1:
/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 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 and newer) ==
== /dev/usb/oh0 (IOS57, 58 and 59) ==


In recent versions of IOS (after IOS 57), the OHCI0 module appears to implement a different interface and seems to only register this new interface of /dev/usb/oh0.
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).
Only IOS_OPEN, IOS_CLOSE and IOS_IOCTL are valid commands. The other commands immediately return IPC_EINVAL (-4).
Line 49: Line 49:


== /dev/usb/oh0 ==
== /dev/usb/oh0 ==
The OH1 module appears to be able to register itself as /dev/usb/oh0 and implements a similar set of requests.
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.
 
{| class="wikitable"
{| class="wikitable"
|-
|-
Line 57: Line 59:


|-
|-
| 12 (ioctlv) || USBV0_IOCTL_GETDEVLIST || 2 || 2 || Both
| 12 (ioctlv) || USBV0_IOCTLV_GETDEVLIST || 2 || 2 || Both
|
|
Returns a list of connected devices matching an interface class.
Returns a list of connected devices matching an interface class.
Line 78: Line 80:
|-
|-
| 15 (ioctl) || ? (USB_GetRhDesca) || - || 4 bytes || Both
| 15 (ioctl) || ? (USB_GetRhDesca) || - || 4 bytes || Both
| Unknown. Appears to return 02 00 03 02 regardless of the number of plugged in devices.
| 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) || ? (GetRhPortStatus) || ? || ? || OH0
| 20 (ioctlv) || USBV0_IOCTLV_GETRHPORTSTATUS|| 1 || 1 || OH0
| Supposedly used for getting the root hub's port status. {{check}}
| 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) || ? (SetRhPortStatus) || ? || ? || OH0
| 25 (ioctlv) || USBV0_IOCTLV_SETRHPORTSTATUS || 2 || 0 || OH0
| Supposedly used for setting the root hub's port status. {{check}}
| 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_IOCTL_DEVINSERTHOOK || 2 || 0 || OH0
| 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.
Returns when a device with the requested VID/PID is plugged in, or immediately if the device is already inserted.
Line 96: Line 102:


|-
|-
| 30 (ioctlv) || USBV0_IOCTL_DEVINSERTHOOKID (RegisterInsertionNotifyWithId) || 3 || 1 || OH0
| 28 (ioctlv) || USBV0_IOCTLV_DEVICECLASSCHANGE || 1 || 0 || OH0
|
|
Returns when a device with the requested VID/PID is plugged in, or immediately if the device is already inserted.
Has to do with device insertion hooks. Triggered on device class change (?) {{check}}
 
* in 0: u8 - Device class (can be zero)


It is similar to USBV0_IOCTL_DEVINSERTHOOK, but it has an additional in vector + io vector, possibly used for passing an "ID" (according the official name). Its purpose is unknown.
|-
| 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 0: u16 - VID
* in 1: u16 - PID
* in 1: u16 - PID
* in 2: u8 - Unknown (00); some sort of ID?
* in 2: u8 - If falsy, return immediately if the device is already plugged in
* io 0: u8* of size 4 - Unknown; some sort of ID?
* io 0: u32 - Overwritten with an ID to use with ioctl 31 for cancelling this insertion hook


|-
|-
| 31 (ioctl) || USBV0_IOCTL_CANCEL_DEVINSERTHOOK || 4 bytes || - || OH0
| 31 (ioctl) || USBV0_IOCTL_CANCEL_INSERT_HOOK || 4 bytes || - || OH0
| Internal names: IUSB_CancelInsertionNotify / __ohciCancelNotifyInsertion
| 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 probably used to specify the VID/PID.
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;
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 <code>IOS_ResourceReply(pending_hook, -7022)</code> is used.
if there was a pending hook, the return value of <code>IOS_ResourceReply(ioctlv_30_request, -7022)</code> is used.


|}
|}
Line 131: Line 142:


|-
|-
| 0 (ioctlv) || USBV0_IOCTL_CTRLMSG || 6 || 1 || Both
| 0 (ioctlv) || USBV0_IOCTLV_CTRLMSG || 6 || 1 || Both
|
|
Submits a control transfer.
Submits a control transfer.
Line 143: Line 154:


|-
|-
| 1 (ioctlv) || USBV0_IOCTL_BLKMSG || 2 || 1 || Both
| 1 (ioctlv) || USBV0_IOCTLV_BLKMSG || 2 || 1 || Both
|
|
Submits a bulk transfer.
Submits a bulk transfer.
Line 153: Line 164:


|-
|-
| 2 (ioctlv) || USBV0_IOCTL_INTRMSG || 2 || 1 || Both
| 2 (ioctlv) || USBV0_IOCTLV_INTRMSG || 2 || 1 || Both
|
|
Submits an interrupt transfer.
Submits an interrupt transfer.
Line 173: Line 184:


|-
|-
| 9 (ioctlv) || USBV0_IOCTL_ISOMSG || 3 || 2 || OH0
| 9 (ioctlv) || USBV0_IOCTLV_ISOMSG || 3 || 2 || OH0
|
|
Submits an isochronous transfer.
Submits an isochronous transfer.
Line 183: Line 194:


|-
|-
| 10 (ioctlv) || ? || 2 || 1 || OH0
| 10 (ioctlv) || USBV0_IOCTLV_LBLKMSG || 2 || 1 || OH0
|
|
Submits a transfer. (Which type?) {{check}}
Submits a bulk transfer. This is the same as ioctlv 1, except that this takes a u32 for the length instead of a u16.


Handled by the same function as for bulk and interrupt transfers.
* in 0: u8 - Endpoint
* in 0: u8 - Endpoint
* in 1: u32 - Length (?)
* in 1: u32 - Length
* io 0: array of length in_vectors[1] - Payload data
* io 0: array of length in_vectors[1] - Payload data


Line 197: Line 207:
| 26 (ioctl) || USBV0_IOCTL_DEVREMOVALHOOK || - || - || Both
| 26 (ioctl) || USBV0_IOCTL_DEVREMOVALHOOK || - || - || Both
|
|
Returns when the device is unplugged or reset, or on device close.
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.
Only one hook is allowed at the same time. Further ioctls to set up another hook before it is triggered result in IPC_EEXIST.
Line 208: Line 218:
|-
|-
| 32 (ioctlv) || ? || ? || ? || OH0
| 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).
|}
|}



Latest revision as of 23:13, 27 December 2016

/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