DESCRIPTION

The Universal Serial Bus (USB) driver programming interface provides USB
peripheral drivers with a host controller independent API for controlling
and communicating with USB peripherals.
Typically, drivers will first use some combination of the functions
usbd_set_config_no(), usbd_get_config_descriptor(), usbd_set_interface(),
usbd_get_interface_descriptor(), usbd_device2interface_handle(),
usbd_endpoint_count() and usbd_interface2endpoint_descriptor() to query
the device’s properties and prepare it for use. Drivers can then perform
requests on the USB control pipe using usbd_do_request(), they can open
pipes using the functions usbd_open_pipe() and usbd_open_pipe_intr(), and
perform transfers over these pipes using usbd_alloc_xfer(),
usbd_setup_xfer() and usbd_transfer(). Finally, the functions
usbd_abort_pipe(), usbd_close_pipe() and usbd_free_xfer() are used to
cancel outstanding transfers, close open pipes and deallocate transfer
structures.
The usbd_get_device_descriptor() function returns a pointer to the USB
device descriptor for dev. See USBDescriptors below for information
about the USB device descriptor.
The usbd_get_config_desc() function retrieves the specified configuration
descriptor from the device. The confidx parameter specifies the
configuration descriptor index, which must be less than the
bNumConfigurations value in the device descriptor. The function
usbd_get_config_desc_full() retrieves a full configuration descriptor,
which has all related interface and endpoint descriptors appended to a
normal configuration descriptor. The parameter d should point to memory
that is at least size bytes in length, and this should be at least as
long as the wTotalLength value from the configuration descriptor. See
USBDescriptors below for information about the USB configuration
descriptor.
The usbd_get_config() function retrieves the current configuration number
from the device, i.e. the bConfigurationValue value from the
configuration that is active. If the device is unconfigured then
USB_UNCONFIG_NO is returned. The current configuration can be changed by
calling either usbd_set_config_index() or usbd_set_config_no(). The
difference between these functions is that usbd_set_config_index()
accepts a configuration index number that is less than the
bNumConfigurations value from the device descriptor, whereas
usbd_set_config_no() requires the bConfigurationValue value of the
desired configuration to be provided instead. To unconfigure the device,
supply a configuration index of USB_UNCONFIG_INDEX to
usbd_set_config_index(), or else specify a configuration number of
USB_UNCONFIG_NO to usbd_set_config_no().
The usbd_get_config_descriptor() function returns a pointer to an in-
memory copy of the full configuration descriptor of the configuration
that is currently active. The returned pointer remains valid until the
device configuration is changed using usbd_set_config_index() or
usbd_set_config_no(). If the device is unconfigured then NULL is
returned instead.
The function usbd_interface_count() returns the number of interfaces
available in the current device configuration. The usbd_get_no_alts()
function determines the number of alternate interfaces in a full
configuration descriptor by counting the interface descriptors with
bInterfaceNumber equal to ifaceno (the count includes alternate index
zero). The usbd_find_idesc() function locates an interface descriptor
within a full configuration descriptor. The ifaceidx parameter specifies
the interface index number, which should be less than the number of
interfaces in the configuration descriptor (i.e. the value returned by
usbd_interface_count() or the bNumInterface field from the configuration
descriptor). An alternate interface can be specified using a non-zero
altidx, which should be less than the value returned by
usbd_get_no_alts(). The return value is a pointer to the requested
interface descriptor within the full configuration descriptor, or NULL if
the specified interface descriptor does not exist. Note that the altidx
parameter specifies the alternate setting by index number starting at
zero; it is not the alternate setting number defined in the interface
descriptor.
The function usbd_find_edesc() locates an endpoint descriptor within a
full configuration descriptor. The ifaceidx and altidx parameters are
the same as described for usbd_find_idesc(), and the endptidx parameter
is an endpoint index number that should be less than the bNumEndpoints
field in the interface descriptor. The return value is a pointer to the
requested endpoint descriptor within the full configuration descriptor,
or NULL if the specified endpoint descriptor does not exist. Note that
the altidx and endptidx parameters are index numbers starting at zero;
they are not the alternate setting and endpoint address defined in the
descriptors.
The usbd_get_speed() function returns the device speed. This can be
USB_SPEED_LOW, USB_SPEED_FULL or USB_SPEED_HIGH.
USB devices optionally support string descriptors, which can be retrieved
using the usbd_get_string() or usbd_get_string_desc() functions. Device,
configuration and interface descriptors reference strings by an index
number that can be supplied to these functions. The usbd_get_string()
function should be used unless a non-default language is required. It
requires that buf points to a buffer of at least USB_MAX_STRING_LEN bytes
in size. The si parameter specified which string to retrieve.
The usb_find_desc() function searches through the in-memory full
configuration descriptor for the active configuration and finds the first
descriptor that has a bDescriptorType equal to type, and if subtype is
not equal to USBD_SUBTYPE_ANY, the descriptor must also have a
bDescriptorSubtype equal to subtype. If found, then a pointer to the
descriptor is returned. Otherwise, usb_find_desc() returns NULL. The
returned pointer is valid until the device configuration is changed using
usbd_set_config_index() or usbd_set_config_no().
The USB driver interface uses opaque interface handles to refer to
configuration interfaces. These handles remain valid until the device
configuration is changed using usbd_set_config_index() or
usbd_set_config_no(). The usbd_device2interface_handle() function
retrieves an interface handle. The ifaceno parameter is an interface
index number starting at zero. If the device is configured and the
specified interface exists, then USBD_NORMAL_COMPLETION is returned and
the interface handle is stored in *iface. Otherwise an error code is
returned and *iface is not changed. The usbd_interface2device_handle()
function retrieves the device handle from an interface handle. This is
just for convenience to save passing around the device handle as well as
the interface handle. The usbd_set_interface() function changes the
alternate setting number for an interface to the alternate setting
identified by the zero-based index number altidx. This operation
invalidates any existing endpoints on this interface and their
descriptors. The usbd_get_interface_altindex() function returns the
current alternative setting index as was specified when calling
usbd_set_interface(). The usbd_endpoint_count() function retrieves the
number of endpoints associated with the specified interface. The
usbd_interface2endpoint_descriptor() function returns a pointer to an in-
memory endpoint descriptor for the endpoint that has an index number of
index. This pointer remains valid until the configuration or alternate
setting number are changed. The function usbd_get_endpoint_descriptor()
is like usbd_interface2endpoint_descriptor() but it accepts a
bEndpointAddress address value instead of an index.
The usbd_fill_deviceinfo() function fills out a usb_device_info structure
with information about the device. The vendor and product names come
from the device itself, falling back to a table lookup or just providing
the IDs in hexadecimal. If usedev is zero then usbd_fill_deviceinfo()
will not attempt to retrieve the vendor and product names from the
device. The usb_device_info structure is defined in #include<dev/usb/usb.h>
as follows:
struct usb_device_info {
u_int8_t udi_bus;
u_int8_t udi_addr; /* device address */
usb_event_cookie_t udi_cookie;
char udi_product[USB_MAX_STRING_LEN];
char udi_vendor[USB_MAX_STRING_LEN];
char udi_release[8];
u_int16_t udi_productNo;
u_int16_t udi_vendorNo;
u_int16_t udi_releaseNo;
u_int8_t udi_class;
u_int8_t udi_subclass;
u_int8_t udi_protocol;
u_int8_t udi_config;
u_int8_t udi_speed;
#define USB_SPEED_LOW 1
#define USB_SPEED_FULL 2
#define USB_SPEED_HIGH 3
int udi_power; /* power consumption in mA */
int udi_nports;
char udi_devnames[USB_MAX_DEVNAMES][USB_MAX_DEVNAMELEN];
/* hub only: addresses of devices on ports */
u_int8_t udi_ports[16];
#define USB_PORT_ENABLED 0xff
#define USB_PORT_SUSPENDED 0xfe
#define USB_PORT_POWERED 0xfd
}
The usbd_devinfo() function generates a string description of the USB
device. The cp argument should point to a 1024-byte buffer (XXX the
maximum length is approximately 320 chars, but there is no sanity
checking and everything uses 1024-character buffers). Device class
information is included if the showclass parameter is non-zero.
The usbd_get_quirks() function returns information from a table of
devices that require special workarounds in order to function correctly.
The returned structure is defined in #include<dev/usb/usb_quirks.h>
as follows:
struct usbd_quirks {
u_int32_t uq_flags; /* Device problems */
};
See #include<dev/usb/usb_quirks.h>
for a list of all currently defined quirks.
USB control requests are performed via usb_device_request_t structures,
defined in #include<dev/usb/usb.h>
as follows:
typedef struct {
uByte bmRequestType;
uByte bRequest;
uWord wValue;
uWord wIndex;
uWord wLength;
} UPACKED usb_device_request_t;
The usbd_do_request() function performs a single request synchronously.
The req parameter should point to a properly initialized
usb_device_request_t, and when the wLength field is non-zero, data should
point at a buffer that is at least wLength bytes in length. The request
timeout is set to 5 seconds, so the operation will fail with USBD_TIMEOUT
if the device does not respond within that time. The
usbd_do_request_async() function is like usbd_do_request(), but it does
not wait for the request to complete before returning. This routine does
not block so it can be used from contexts where sleeping is not allowed.
Note that there is no notification mechanism to report when the operation
completed nor is there a way to determine whether the request succeeded,
so this function is of limited use. See usbd_setup_default_xfer() and
usbd_transfer() for a way to invoke an asynchronous callback upon
completion of a control request. The usbd_do_request_flags() function is
like usbd_do_request(), but additional flags can be specified, the
timeout is configurable, and the actual number of bytes transferred is
made available to the caller. The usbd_do_request_flags_pipe() function
uses a specified pipe instead of the default pipe.
The function usbd_open_pipe() creates a pipe connected to a specified
endpoint on a specified interface. The parameter address should be the
bEndpointAddress value from one of this interface’s endpoint descriptors.
If flags contains USBD_EXCLUSIVE_USE then the operation will only succeed
if there are no open pipes already connected to the specified endpoint.
The usbd_open_pipe_intr() function creates an interrupt pipe connected to
the specified endpoint. The parameter address should be the
bEndpointAddress value from one of this interface’s endpoint descriptors.
The flags parameter is passed to usbd_setup_xfer(). The buffer and len
parameters define a buffer that is to be used for the interrupt
transfers. The callback to be invoked each time a transfer completes is
specified by cb, and priv is an argument to be passed to the callback
function. The ival parameter specifies the maximum acceptable interval
between transfers; in practice the transfers may occur more frequently.
The function usbd_pipe2device_handle() returns the device associated with
the specified pipe.
The usbd_abort_pipe() function aborts all active or waiting transfers on
the specified pipe. Each transfer is aborted with a USBD_CANCELLED
status; callback routines must detect this error code to ensure that they
do not attempt to initiate a new transfer in response to one being
aborted. This routine blocks while it is waiting for the hardware to
complete processing of aborted transfers, so it is only safe to call it
in contexts where sleeping is allowed. The function
usbd_abort_default_pipe() aborts all active or waiting transfers on the
default pipe. Like usbd_abort_pipe(), it blocks waiting for the hardware
processing to complete.
When a pipe has no active or waiting transfers, the pipe may be closed
using the usbd_close_pipe() function. Once a pipe is closed, its pipe
handle becomes invalid and may no longer be used.
USB transfer handles are allocated using the function usbd_alloc_xfer()
and may be freed using usbd_free_xfer().
The function usbd_setup_xfer() initializes a transfer handle with the
details of a transfer to or from a USB device. The xfer parameter
specifies the transfer handle to initialize, pipe specifies the pipe on
which the transfer is to take place, and priv is an argument that will be
passed to callback function. The arguments buffer and length define the
data buffer for the transfer. If length is zero then the buffer may be
NULL. The flags parameter may contain the following flags:
USBD_NO_COPY This is used in association with
usbd_alloc_buffer() and usbd_free_buffer() to use
a dedicated DMA-capable buffer for the transfer.
USBD_SYNCHRONOUS Wait for the transfer to compete in
usbd_transfer().
USBD_SHORT_XFER_OK Permit transfers shorter than the requested data
length.
USBD_FORCE_SHORT_XFER Force a short transfer at the end of a write
operation to let the device know that the transfer
has ended.
The timeout parameter specifies a timeout for the transfer in
milliseconds. A value of USBD_NO_TIMEOUT indicates that no timeout
should be configured. The parameter callback specifies the function to
call when the transfer completes. Note that usbd_setup_xfer() does not
actually initiate the transfer. The usbd_setup_default_xfer()
initializes a control transfer for the default pipe. The req parameter
should point at a completed usb_device_request_t structure. The function
usbd_setup_isoc_xfer initializes a transfer for an isochronous pipe.
The function usbd_transfer() initiates a transfer. Normally it returns
USBD_IN_PROGRESS to indicate that the transfer has been queued. If the
USB stack is operating in polling mode, or if the transfer is
synchronous, then USBD_NORMAL_COMPLETION may be returned. Other return
values indicate that the transfer could not be initiated due to an error.
The usbd_sync_transfer() function executes a transfer synchronously. It
will sleep waiting for the transfer to complete and then return the
transfer status. Note that if the transfer has a callback routine, this
will be invoked before usbd_sync_transfer() returns.
The usbd_intr_transfer() and usbd_bulk_transfer() functions set up a
transfer and wait synchronously for it to complete but they allows
signals to interrupt the wait. They returns USBD_INTERRUPTED if the
transfer was interrupted by a signal. XXX these two functions are
identical apart from their names.
The function usbd_get_xfer_status() retrieves various information from a
completed transfer. If the priv parameter is not NULL then the callback
private argument is stored in *priv. If buffer is not NULL then the
transfer buffer pointer is stored in *buffer. The actual number of bytes
transferred is stored in *count if countisnotNULL. Finally, the
transfer status is stored in *status if status is not NULL.
The usbd_clear_endpoint_stall() function clears an endpoint stall
condition synchronously, i.e. it sleeps waiting for the stall clear
request to complete. The function usbd_clear_endpoint_stall_async()
performs the same function asynchronously, but it provides no way to
determine when the request completed, or whether it was successful. The
usbd_clear_endpoint_toggle() function instructs the host controller
driver to reset the toggle bit on a pipe. This is used when manually
clearing an endpoint stall using a control pipe request, in order to
ensure that the host controller driver and the USB device restart with
the same toggle value.
Normally the USB subsystem maps and copies data to and from DMA-capable
memory each time a transfer is performed. The function
usbd_alloc_buffer() allocates a permanent DMA-capable buffer associated
with the transfer to avoid this overhead. The return value is the
virtual address of the buffer. Any time that usbd_setup_xfer() is called
on the transfer with the USBD_NO_COPY flag enabled, the allocated buffer
will be used directly and the buffer argument passed to usbd_setup_xfer()
will be ignored. The usbd_get_buffer() function returns a pointer to the
virtual address of a buffer previously allocated by usbd_alloc_buffer().
Finally, usbd_free_buffer() deallocates the buffer.
The usbd_errstr() function converts a status code into a string for
display.
The function usbd_set_polling() enables or disables polling mode. In
polling mode, all operations will busy-wait for the device to respond, so
its use is effectively limited to boot time and kernel debuggers. It is
important to match up calls that enable and disable polling mode, because
the implementation just increments a polling reference count when on is
non-zero and decrements it when on is zero. The usbd_dopoll() causes the
host controller driver to poll for any activity. This should only be
used when polling mode is enabled.
The usbd_ratecheck() function is used to limit the rate at which error
messages are printed to approximately once per second. The last argument
should point at a persistent structtimeval. A value of 1 will be
returned if a message should be printed, but if usbd_ratecheck() has
already been called with the same structtimeval parameter in the last
second then 0 is returned and the error message should be suppressed.
The functions usb_detach_wait() and usb_detach_wakeup() are used to wait
for references to drain before completing the detachment of a device.
The usb_detach_wait() function will wait up to 60 seconds to receive a
signal from usb_detach_wait().
USBDescriptors
The USB specification defines a number of standard descriptors by which
USB devices report their attributes. These descriptors are fixed-format
structures that all USB devices make available through USB control pipe
requests.
Every USB device has exactly one USB device descriptor. The USB
subsystem retrieves this automatically when a device is attached, and a
copy of the descriptor is kept in memory. The
usbd_get_device_descriptor() function returns a pointer to the
descriptor. The device descriptor structure is defined in #include<dev/usb/usb.h>
as follows:
typedef struct {
uByte bLength;
uByte bDescriptorType;
uWord bcdUSB;
#define UD_USB_2_0 0x0200
#define UD_IS_USB2(d) (UGETW((d)->bcdUSB) >= UD_USB_2_0)
uByte bDeviceClass;
uByte bDeviceSubClass;
uByte bDeviceProtocol;
uByte bMaxPacketSize;
/* The fields below are not part of the initial descriptor. */
uWord idVendor;
uWord idProduct;
uWord bcdDevice;
uByte iManufacturer;
uByte iProduct;
uByte iSerialNumber;
uByte bNumConfigurations;
} UPACKED usb_device_descriptor_t;
#define USB_DEVICE_DESCRIPTOR_SIZE 18
USB devices have at least one configuration descriptor. The
bNumConfigurations field of the device descriptor specifies the number of
configuration descriptors that a device supports. The
usbd_get_config_desc() function retrieves a particular configuration
descriptor from the device and the usbd_get_config_desc_full() function
retrieves a full wTotalLength length configuration descriptor, which
includes all related interface and endpoint descriptors. Only one
configuration may be active at a time. The usbd_set_config_index()
function activates a specified configuration. The configuration
descriptor structure is defined in #include<dev/usb/usb.h>
as follows:
typedef struct {
uByte bLength;
uByte bDescriptorType;
uWord wTotalLength;
uByte bNumInterface;
uByte bConfigurationValue;
uByte iConfiguration;
uByte bmAttributes;
#define UC_BUS_POWERED 0x80
#define UC_SELF_POWERED 0x40
#define UC_REMOTE_WAKEUP 0x20
uByte bMaxPower; /* max current in 2 mA units */
#define UC_POWER_FACTOR 2
} UPACKED usb_config_descriptor_t;
#define USB_CONFIG_DESCRIPTOR_SIZE 9
Each device configuration provides one or more interfaces. The
bNumInterface field of the configuration descriptor specifies the number
of interfaces associated with a device configuration. Interfaces are
described by an interface descriptor, which is defined in #include<dev/usb/usb.h>
as follows:
typedef struct {
uByte bLength;
uByte bDescriptorType;
uByte bInterfaceNumber;
uByte bAlternateSetting;
uByte bNumEndpoints;
uByte bInterfaceClass;
uByte bInterfaceSubClass;
uByte bInterfaceProtocol;
uByte iInterface;
} UPACKED usb_interface_descriptor_t;
#define USB_INTERFACE_DESCRIPTOR_SIZE 9
Configurations may also have alternate interfaces with the same
bInterfaceNumber but different bAlternateSetting values. These alternate
interface settings may be selected by passing a non-zero altidx parameter
to usbd_set_interface().
Interfaces have zero or more endpoints, and each endpoint has an endpoint
descriptor. Note that endpoint zero, which is always present, does not
have an endpoint descriptor, and it is never included in the
bNumEndpoints count of endpoints. The endpoint descriptor is defined in
#include<dev/usb/usb.h>
as follows:
typedef struct {
uByte bLength;
uByte bDescriptorType;
uByte bEndpointAddress;
#define UE_GET_DIR(a) ((a) & 0x80)
#define UE_SET_DIR(a,d) ((a) | (((d)&1) << 7))
#define UE_DIR_IN 0x80
#define UE_DIR_OUT 0x00
#define UE_ADDR 0x0f
#define UE_GET_ADDR(a) ((a) & UE_ADDR)
uByte bmAttributes;
#define UE_XFERTYPE 0x03
#define UE_CONTROL 0x00
#define UE_ISOCHRONOUS 0x01
#define UE_BULK 0x02
#define UE_INTERRUPT 0x03
#define UE_GET_XFERTYPE(a) ((a) & UE_XFERTYPE)
#define UE_ISO_TYPE 0x0c
#define UE_ISO_ASYNC 0x04
#define UE_ISO_ADAPT 0x08
#define UE_ISO_SYNC 0x0c
#define UE_GET_ISO_TYPE(a) ((a) & UE_ISO_TYPE)
uWord wMaxPacketSize;
uByte bInterval;
} UPACKED usb_endpoint_descriptor_t;
#define USB_ENDPOINT_DESCRIPTOR_SIZE 7

RETURNVALUES

Many functions return a usbd_status type to indicate the outcome of the
operation. If the operation completed successfully then
USBD_NORMAL_COMPLETION is returned. Operations that have been started
but not yet completed will return USBD_IN_PROGRESS. Other errors usually
indicate a problem. Error codes can be converted to strings using
usbd_errstr().

ERRORS

[USBD_PENDING_REQUESTS]
A pipe could not be closed because there are
active requests.
[USBD_NOT_STARTED] The transfer has not yet been started.
[USBD_INVAL] An invalid value was supplied.
[USBD_NOMEM] An attempt to allocate memory failed.
[USBD_CANCELLED] The transfer was aborted.
[USBD_BAD_ADDRESS] The specified endpoint address was not found.
[USBD_IN_USE] The endpoint is already in use, or the
configuration cannot be changed because some of
its endpoints are in use.
[USBD_NO_ADDR] No free USB devices addresses were found to assign
to the device.
[USBD_SET_ADDR_FAILED]
The device address could not be set.
[USBD_NO_POWER] Insufficient power was available for the device.
[USBD_TOO_DEEP] Too many levels of chained hubs were found.
[USBD_IOERROR] There was an error communicating with the device.
[USBD_NOT_CONFIGURED] An operation that requires an active configuration
was attempted while the device was in an
unconfigured state.
[USBD_TIMEOUT] A transfer timed out.
[USBD_SHORT_XFER] A transfer that disallowed short data lengths
completed with less than the requested length
transferred.
[USBD_STALLED] A transfer failed because the pipe is stalled.
[USBD_INTERRUPTED] An interruptible operation caught a signal.