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

/dev/uhs

From WiiUBrew
< /dev
Revision as of 09:58, 22 May 2016 by Datalogger (talk | contribs) (Changed format of table)
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

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.

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.

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.

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.

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;


List of Functions (Ioctl/Ioctlv/IoctlAsync)

Command Function Ioctl Ioctlv IoctlAsync Notes
0x01 FSMount      X
0x01 FSAMount      X
0x01 FSMountAsync      X
0x01 FSBindMount      X
0x02 FSUnmount      X
0x02 FSAUnmount      X
0x02 FSUnmountAsync      X
0x02 FSBindUnmount      X
0x02 FSBindUnmountAsync      X      X
0x03 FSGetVolumeInfo      X
0x03 FSAGetVolumeInfo      X
0x03 FSGetVolumeInfoAsync      X
0x04 FSInit         X
0x04 FSAInit         X
0x05 FSChangeDir      X
0x05 FSAChangeDir      X
0x05 FSChangeDirAsync      X
0x06 FSGetCwd      X
0x06 FSAGetCwd      X
0x06 FSGetCwd Async      X
0x07 FSMakeDir      X      X
0x08 FSRemove      X      X
0x09 FSRename      X
0x0A FSOpenDir      X      X
0x0B FSReadDir      X
0x0C FSRewindDir      X
0x0D FSCloseDir      X
0x0E FSOpenFile      X
0x0E FSOpenFileEx      X
0x0F FSReadFile      X
0x0F FSReadFileWith Pos      X
0x10 FSWriteFile      X
0x10 FSWriteFileWithPos      X
0x11 FSGetPosFile      X
0x12 FSSetPosFile      X
0x13 FSIsEof      X
0x14 FSGetStatFile      X
0x15 FSCloseFile      X
0x16 FSAGetError      X
0x17 FSFlushFile      X
0x18 FSGetStat      X      X
0x18 FSGetFreeSpaceSize      X      X
0x18 FSGetEntryNum      X      X
0x18 FSGetFileSystemInfo      X      X
0x19 FSAppendFile      X
0x19 FSAppendFileEx      X
0x1A FSTruncateFile      X
0x1B FSAFlushVolume      X      X
0x1C FSARollbackVolume      X      X
0x1D FSMakeQuota      X      X
0x1E FSFlushQuota      X      X
0x1F FSRollbackQuota      X      X
0x1F FSARollbackQuotaForce      X      X
0x20 FSChangeMode      X      X
0x21 FSOpenFileByStat      X
0x22 FSRegisterFlushQuota      X      X
0x23 FSFlushMultiQuota      X      X
0x25 FSGetFileBlockAddress      X
0x6E Unknowm      X
0x6F Unknown      X
0x72 FSRemoveQuota      X      X
0x75 FSMakeLinkAsync      X      X
0x76 HIOInit      ?      ?         ? Not FS Command?
0x?? FSAddClientEx         X Used with 0x01 and 0x02