/dev/uhs

From WiiUBrew
Jump to navigation Jump to search

/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