bb_usb.3 5.42 KB
.TH bb_usb 3 "March 2003"
.SH NAME
osUsbInit, osUsbDevQuery, osUsbDevGetHandle, osUsbDevRead, osUsbDevWrite \- USB device API for BB Player OS
.SH SYNOPSIS
.nf
.B #include <ultra64.h>
.LP
.B s32 osUsbInit()
.LP
.B s32 osUsbDevQuery(s32 ctlr, OSUsbInfo *attrp, s32 nattr)
.LP
.B s32 osUsbDevGetHandle(s32 ctlr, OSUsbInfo *attrp, OSUsbHandle *handlep)
.LP
.B s32 osUsbDevRead(OSUsbHandle *handlep, u8 *buf, s32 len, u64 offset)
.LP
.B s32 osUsbDevWrite(OSUsbHandle *handlep, u8 *buf, s32 len, u64 offset)
.LP
.SH DATA STRUCTURES
.LP
The attributes of a USB device are represented by the following data structure:
.LP
.nf
.ft B
typedef struct {
	u8	ua_class;	/* device class */
	u8	ua_subclass;	/* subclass */
	u8	ua_protocol;	/* protocol */
	u16	ua_vendor;	/* vendor */
	u16	ua_product;	/* product */
	u8	ua_cfgs;	/* number of configurations */
	u8	ua_ifcs;	/* number of interfaces */
	u8	ua_eps;		/* number of endpoints */
	u8	ua_canblk;	/* read can block */
	OSMesgQueue	*ua_mq;	/* message queue of manager thread */
} OSUsbInfo;
.ft R
.fi
.LP
In order to access a specific USB device, the application must call
.BR osUsbDevGetHandle()
in order to get a USB device handle, which is described by this structure:
.LP
.nf
.ft B
typedef struct {
	OSMesgQueue	*uh_mq;	/* message queue of manager thread */
	u32	uh_devcookie;	/* opaque device cookie */
} OSUsbHandle;
.ft R
.fi
.SH DESCRIPTION
.PP
The calls on this page give the
.I libultra
program access to the USB subsystem of the BB Player.
There are two USB controllers in a standard BB Player, one of which
is always a USB Host and one which can be either a host or a device.
The USB subsystem uses a manager thread for each USB controller, which
sequences IO requests for other program threads and interacts with
the USB hardware and handles interrupts from the USB devices.
The programming model provided by
.I libultra
hides the
lower level details of the USB bus and devices and presents
a device independent IO interface that is similar to the
.B pread
and
.B pwrite
interface provided by the standard UNIX
.IR libc .
Each IO call specifies the position or offset into the device
at which the IO should be done, so that there is no need
for a separate device positioning call (e.g. \fBlseek\fR).
Note also that only synchronous IO calls are provided.
When dealing with a human interface device, for example,
the program can manage blocking read calls by creating
a separate IO thread, so that the rest of the program can
make progress while waiting for user input.
Sizes and offsets of all IO operations are expressed in terms of
bytes or characters, although specific devices may have
requirements on the size and alignment of IO operations. 
.PP
If a program never calls
.B osUsbInit
then the USB subsystem is disabled and will generate no interrupts,
even if a USB device is plugged into the system or removed from
the system.  The
.B Examples
section below gives the standard initialization sequence for the
USB subsystem.
Note that since USB is a Plug-and-Play interface, devices may
be added or removed at any point during the execution of a
program.
The initialization call
.B osUsbInit
should be made only once at program startup time.
.B osUsbDevQuery
can be called at any time to make sure that the program has
current information about the devices present on the USB
bus.
.SH RETURN VALUE
.B osUsbInit
returns the number of USB controllers found in the hardware.  Should
be 2.
.PP
.B osUsbDevQuery
returns the number of devices found on the particular USB controller.
.PP
.B osUsbDevGetHandle
returns 0 if successful.
Possible errors are:
.TP 15
ERR_OSUSBNODEV
Unable to find a device matching the specified attributes.
Call
.B osUsbDevQuery
to refresh USB device information.
.PP
.B osUsbDevRead
and
.B osUsbDevWrite
return the number of characters successfully transferred.
Possible errors are:
.TP 15
ERR_OSUSBNODEV
Invalid device handle.  Call
.B osUsbDevQuery
to refresh USB device information.
.TP 15
ERR_OSUSBALIGN
Size, alignment or offset of requested IO operation is illegal for the
specified device.  For example, beyond EOD or 
not a multiple of sectors for a mass storage device.
.PP
.SH EXAMPLES
An application that intends to use USB devices must initialize the
USB subsystem in a canonical way.
Here is some sample code:
.LP
.nf
.ft B
#define	MAX_USB_CONTROLLERS	2
#define MAX_USB_DEVS		2

int ctlr, num_controllers, dev, num_devs;
OSUsbInfo	usbdevattr[MAX_USB_DEVS];
OSUsbHandle	msd_handle;

osInitialize();
num_controllers = osUsbInit();
if (num_controllers > MAX_USB_CONTROLLERS) {
	panic("USB initialization failed: too many controllers in HW");
}

/*
 * Initialize each controller and start manager threads
 */
for (ctlr = 0, num_devs = 0; ctlr < num_controllers; ctlr++) {
	/*
	 * Enumerate the devices on the bus and retrieve their attributes
	 */
	num_devs += osUsbDevQuery(ctlr, &usbdevattr[num_devs],
		 MAX_USB_DEVS - num_devs);
}

/*
 * Find the device we want
 */
for (dev = 0; dev < num_devs; dev++) {
	OSUsbInfo *ap = &usbdevattr[dev];

	if (ap->ua_class == USB_MASS_STORAGE &&
	    ap->ua_subclass == 0 &&
	    ap->ua_vendor == 0x0676) {

		/*
		 * Found the mass storage device, get a handle
		 * and start the IO thread for that device.
		 */
		if (osUsbDevGetHandle(ap->ua_mq, ap, &msd_handle) < 0) {
			panic("Open of USB mass storage device failed");
			/* no return */
		}

		start_io_thread(&msd_handle);
		/* no return */
	}

	panic("No USB mass storage device found");
	/* no return */
}

.ft R
.fi
.SH SEE ALSO
Nintendo 64 Programming Guide