Difference between revisions of "/dev/usb/oh0"
(tueidj: Thanks. Do you know in what IOS version it is implemented? It doesn't seem to be in IOS36.) |
|||
(64 intermediate revisions by 4 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 the external USB bus | ||
− | + | == /dev/usb/oh0 (IOS57, 58 and 59) == | |
− | |||
− | |||
− | ==Errors== | + | 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). | ||
+ | |||
+ | {| class="wikitable" | ||
+ | |- | ||
+ | ! 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. | ||
+ | |||
+ | {| 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 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 <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). | ||
+ | |} | ||
+ | |||
+ | == 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 | ||
− | |||
− | |||
− | |||
− | |||
− | |||
[[Category:Wii Filesystem]] | [[Category:Wii Filesystem]] |
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
|
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]
|
25 (ioctlv) | USBV0_IOCTLV_SETRHPORTSTATUS | 2 | 0 | OH0 | Supposedly used for setting the root hub's port status. (internal name: SetRhPortStatus) [check]
|
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.
|
28 (ioctlv) | USBV0_IOCTLV_DEVICECLASSCHANGE | 1 | 0 | OH0 |
Has to do with device insertion hooks. Triggered on device class change (?) [check]
|
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.
|
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 |
/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.
|
1 (ioctlv) | USBV0_IOCTLV_BLKMSG | 2 | 1 | Both |
Submits a bulk transfer.
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.
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.
|
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.
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