/dev/uhs
/dev/uhs is the IOSU device node for the USB Host Stack (UHS). It provides an interface for low-level USB device access, which nsysuhs.rpl exposes to the Cafe OS userspace. The interface is opened through /dev/uhs/%d, where %d is an integer representing controller number. 0 is the controller for the external USB ports, and 1 is for internal USB devices (Bluetooth module and and DRH) only usable inside IOSU. Once opened, ioctl() requests can be issued to the interface, which are documented below.
ioctl() interface
0x00 - UhsQueryInterfaces()
0x01 - UhsClassDrvReg()
This function is used to register a USB class driver with UHS. Its input is a 24-byte buffer containing: a context pointer for a callback, the callback itself, and an interface filter buffer containing a series of parameters to filter the interfaces by, such as class, subclass, vendor ID, and product ID. When an interface matching the filter is added to UHS, it will trigger the callback, passing the context and an interface profile to it. The output is simply a 4-byte status code.
0x02 - UhsClassDrvUnReg()
0x04 - UhsAcquireInterface()
This function is used to acquire a USB device interface for use. Its input is a 12-byte buffer containing: a 32-bit interface handle, an unknown word, and a callback for when the acquire completes. No output is produced by IOSU.
0x05 - UhsReleaseInterface()
This function is used to release a currently-acquired USB interface once the client is done using it. Its input is a 12-byte buffer containing: a 32-bit interface handle, a 32-bit boolean for whether clients should be barred from re-acquiring the interface later, and 0. No output is produced by IOSU.
0x06 - UhsSetInterface()
0x07 - UhsGetInterface()
0x08 - UhsGetAlternateInterface()
0x09 - UhsGetDescriptorString()
0x0A - UhsGetFullConfigDescriptor()
0x0B - UhsAdministerEndpoint() / UhsAdministerEndpointOpt
0x0C - UhsAdministerDevice()
0x10 - UhsGetCurrentFrame()
0x11 - UhsQueryInterfaces()
This function is used to determine which USB device interfaces are plugged in and available. Its input is an interface filter buffer containing a series of parameters to filter the interfaces by, such as class, subclass, vendor ID, and product ID. The output is an array of interface profiles, one for each interface being read. IOS_Ioctl() with this function returns the number of attached USB interfaces permitted by the filter.
0x12 - UhsAdministerDevice()
This function's purpose is currently unknown, but usb_mic.rpl uses it during device initialization. Its input is a 12-byte buffer containing: a 32-bit unknown word (1-5 inclusive), a 32-bit interface handle, and a 16-bit unknown word. No output is produced by IOSU. usb_mic.rpl seems to pass 2 and 0 as the two unknown words when initializing a USB microphone.
0x14 - UhsServerAddHc()
Used internally to add a host controller to UHS. Its input is a 8 byte buffer containing the number of the root hub and an options parameter.
0x15 - UhsServerRemoveHc()
See UhsServerAddHc.
ioctlv() interface
0x0C - UhsSubmitControlRequest()
This function is used to send a control request to a USB device interface. It takes two buffers through the ioctlv interface: a control request block and the actual data buffer, in that order. If the direction of the request is out to the device, there are 0 inputs and 2 outputs; if the direction is in to the host, there is 1 input and 1 output.
0x0D - UhsSubmitInterruptRequest()
0x0F - UhsSubmitIsocRequest()
0x0E - UhsSubmitBulkRequest()
This function is used to send a bulk request to a USB device interface. It takes two buffers through the ioctlv interface: a bulk request block and the actual data buffer, in that order. If the direction of the request is out to the device, there are 0 inputs and 2 outputs; if the direction is in to the host, there is 1 input and 1 output.
Structures
Interface Filter
This structure is passed to several functions to determine which interface profiles to return or handle.
/* Determines which parameters to check */
#define MATCH_ANY 0x000
#define MATCH_DEV_VID 0x001
#define MATCH_DEV_PID 0x002
#define MATCH_DEV_CLASS 0x010
#define MATCH_DEV_SUBCLASS 0x020
#define MATCH_DEV_PROTOCOL 0x040
#define MATCH_IF_CLASS 0x080
#define MATCH_IF_SUBCLASS 0x100
#define MATCH_IF_PROTOCOL 0x200
/* Interface filter */
typedef struct
{
uint16_t match_params; /* Bitmask of above flags */
uint16_t vid, pid; /* Vendor ID and product ID */
char unknown6[0xa - 0x6];
uint8_t dev_class; /* Device class */
uint8_t dev_subclass; /* Device subclass */
uint8_t dev_protocol; /* Device protocol */
uint8_t if_class; /* Interface class */
uint8_t if_subclass; /* Interface subclass */
uint8_t if_protocol; /* Interface protocol */
} UhsInterfaceFilter;
USB Descriptors
These are device, configuration, and interface descriptors defined by the USB specification.[1]
/* USB device descriptor */
typedef struct
{
uint8_t bLength;
uint8_t bDescriptorType;
uint16_t bcdUsb;
uint8_t bDeviceClass;
uint8_t bDeviceSubclass;
uint8_t bDeviceProtocol;
uint8_t bMaxPacketSize;
uint16_t idVendor;
uint16_t idProduct;
uint16_t bcdDevice;
uint8_t iManufacturer;
uint8_t iProduct;
uint8_t iSerialNumber;
uint8_t bNumConfigurations;
} UhsDeviceDescriptor;
/* USB configuration descriptor */
typedef struct
{
uint8_t bLength;
uint8_t bDescriptorType;
uint16_t wTotalLength;
uint8_t bNumInterfaces;
uint8_t bConfigurationValue;
uint8_t iConfiguration;
uint8_t bmAttributes;
uint8_t bMaxPower;
} UhsConfigDescriptor;
/* USB interface descriptor */
typedef struct
{
uint8_t bLength;
uint8_t bDescriptorType;
uint8_t bInterfaceNumber;
uint8_t bAlternateSetting;
uint8_t bNumEndpoints;
uint8_t bInterfaceClass;
uint8_t bInterfaceSubClass;
uint8_t bInterfaceProtocol;
uint8_t iInterface;
} UhsInterfaceDescriptor;
Interface Profile
This structure is used to represent an available device interface attached to the Wii U.
/* Interface profile */
typedef struct
{
uint32_t if_handle;
char unknown4[0x28 - 0x4];
UhsDeviceDescriptor dev_desc;
UhsConfigDescriptor cfg_desc;
UhsInterfaceDescriptor if_desc;
char in_endpoints[0xdc - 0x4c];
char out_endpoints[0x16c - 0xdc];
} UhsInterfaceProfile;
in_endpoints and out_endpoints are arrays of USB endpoint descriptors, but parsing them isn't exactly straightforward. The USB specification defines endpoint descriptors as 7-bytes, but UHS also supports 9-byte endpoints. Anyone programming with this API will have to iterate through the lists, applying casts as necessary. All USB endpoint descriptors start with a length, so check that first. If it's 0, assume the endpoint is empty and go 9-bytes forward for the next one. If it specifies a size, use that.
Request Blocks
The USB spec defines four types of requests: control, bulk, isochronous, and interrupt. UHS provides request buffers to invoke all of them.
/* Endpoint transfer directions */
#define ENDPOINT_TRANSFER_OUT 1
#define ENDPOINT_TRANSFER_IN 2
/* Control request block */
typedef struct
{
uint32_t if_handle;
uint8_t endpoint; // Usually (always?) 0 for default
uint32_t timeout;
uint32_t transfer_type; // 1=control
uint8_t bRequest, bmRequestType;
uint16_t wValue, wIndex, wLength;
} control_req_t;
/* Bulk request block */
typedef struct
{
uint32_t if_handle;
uint8_t endpoint;
uint32_t timeout;
uint32_t transfer_type; // 3=bulk
int direction; // 1=out, 2=in as per above
int length;
} bulk_req_t;
Tables
List of Functions (Ioctl/Ioctlv/IoctlAsync/IoctlvAsync)
Command | Function | Ioctl | Ioctlv | IoctlAsync | IoctlvAsync | Notes |
---|---|---|---|---|---|---|
0x01 | UhsClassDrvReg | X | ||||
0x02 | UhsClassDrvUnReg | X | ||||
0x03 | Unknown | X | ||||
0x04 | UhsAcquireInterface | X | ||||
0x05 | UhsReleaseInterface | X | ||||
0x06 | UhsSetInterface | X | ||||
0x07 | UhsGetInterface | X | ||||
0x08 | UhsGetAlternateInterface | X | ||||
0x09 | UhsGetDescriptorString | X | ||||
0x0A | UhsGetFullConfigDescriptor | X | ||||
0x0B | UhsAdministerEndpoint | X | ||||
0x0C | UhsSubmitControlRequest | X | X | |||
0x0D | UhsSubmitInterruptRequest | X | X | |||
0x0E | UhsSubmitBulkRequest | X | X | |||
0x0F | UhsSubmitIsocRequest | X | X | |||
0x10 | UhsGetCurrentFrame | X | ||||
0x11 | UhsQueryInterfaces | X | ||||
0x12 | UhsAdministerDevice | X | ||||
0x13 | X | |||||
0x14 | UhsServerAddHc | X | ||||
0x15 | UhsServerRemoveHc | X |