Difference between revisions of "/dev/usb/oh0"

From WiiBrew
< /dev‎ | usb
Jump to navigation Jump to search
(→‎Known Devices: add Logitech mic)
(tueidj: Thanks. Do you know in what IOS version it is implemented? It doesn't seem to be in IOS36.)
 
(59 intermediate revisions by 2 users not shown)
Line 1: Line 1:
==Description==
+
/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 the external USB bus in the Wii
 
  
This interface is very similar to OH1.
+
== /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).
  
== Host device (/dev/usb/oh0) ==
 
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
Line 10: Line 14:
 
! Notes
 
! Notes
 
|-
 
|-
| 12 (ioctlv) || [https://github.com/devkitPro/libogc/blob/b8c0882a73de7833467a844e9adebb9ff8768ba5/libogc/usb.c#L1370 USBV0_IOCTL_GETDEVLIST] || 2 || 2
+
| 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.
 +
 
 +
{| class="wikitable"
 +
|-
 +
! 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.
 +
 +
<source lang="c">
 +
struct Descriptor
 +
{
 +
  u32 unknown;
 +
  u16 vid;
 +
  u16 pid;
 +
};
 +
// sizeof(Descriptor) = 8
 +
</source>
 +
 
* in 0: u8 - number of descriptors to return
 
* in 0: u8 - number of descriptors to return
 
* in 1: u8 - interface class
 
* in 1: u8 - interface class
* out 0: u8 - number of devices
+
* io 0: u8 - number of devices
* out 1: u32* of size num_descriptors * 8 - device list
+
* 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
  
 
|-
 
|-
| 27 (ioctlv) || USBV0_IOCTL_DEVINSERTHOOK || 2 || 0
+
| 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.
 
Returns when a device with the requested VID/PID is plugged in, or immediately if the device is already inserted.
Line 25: Line 102:
  
 
|-
 
|-
| 30 (ioctlv) || ? || 3 || 1
+
| 28 (ioctlv) || USBV0_IOCTLV_DEVICECLASSCHANGE || 1 || 0 || OH0
 
|
 
|
Unknown.
+
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 0: u16 - VID
 
* in 1: u16 - PID
 
* in 1: u16 - PID
* in 2: u8 - Unknown (00)
+
* in 2:  u8 - If falsy, return immediately if the device is already plugged in
* out 0: u8* of size 4 - Unknown (00 a3 f4 c0 -- for 046d:0a03)
+
* 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 <code>IOS_ResourceReply(ioctlv_30_request, -7022)</code> 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.
 +
 
 +
{| class="wikitable"
 +
|-
 +
! 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).
 
|}
 
|}
  

Latest revision as of 22: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