NAME
usbdi —
USB device drivers
interface
SYNOPSIS
#include <dev/usb/usb.h>
#include <dev/usb/usbdi.h>
#include <dev/usb/usbdi_util.h>
Functions offered by
usbdi.h
usbd_status
usbd_open_pipe(
struct
usbd_interface *iface,
uint8_t address,
uint8_t flags,
struct usbd_pipe **pipe);
usbd_status
usbd_close_pipe(
struct
usbd_pipe *pipe);
usbd_status
usbd_transfer(
struct
usbd_xfer *xfer);
struct usbd_xfer *
usbd_setup_xfer(
struct
usbd_xfer *xfer,
void
*priv,
void *buffer,
uint32_t length,
uint16_t flags,
uint32_t timeout,
usbd_callback);
void
usbd_setup_default_xfer(
struct
usbd_xfer *xfer,
struct
usbd_device *dev,
void
*priv,
uint32_t
timeout,
usb_device_request_t *req,
void *buffer,
uint32_t length,
uint16_t flags,
usbd_callback);
void
usbd_setup_isoc_xfer(
struct
usbd_xfer *xfer,
void
*priv,
uint16_t
*frlengths,
uint32_t
nframes,
uint16_t
flags,
usbd_callback);
void
usbd_get_xfer_status(
struct
usbd_xfer *xfer,
void
**priv,
void
**buffer,
uint32_t
*count,
usbd_status
*status);
usb_endpoint_descriptor_t *
usbd_interface2endpoint_descriptor(
struct
usbd_interface *iface,
uint8_t address);
usbd_status
usbd_abort_pipe(
struct
usbd_pipe *pipe);
usbd_status
usbd_abort_default_pipe(
struct
usbd_device *dev);
usbd_status
usbd_clear_endpoint_stall(
struct
usbd_pipe *pipe);
usbd_status
usbd_clear_endpoint_stall_async(
struct
usbd_pipe *pipe);
void
usbd_clear_endpoint_toggle(
struct
usbd_pipe *pipe);
usbd_status
usbd_endpoint_count(
struct
usbd_interface *dev,
uint8_t *count);
usbd_status
usbd_interface_count(
struct
usbd_device *dev,
uint8_t
*count);
usbd_status
usbd_interface2device_handle(
struct
usbd_interface *iface,
struct usbd_device **dev);
usbd_status
usbd_device2interface_handle(
struct
usbd_device *dev,
uint8_t
ifaceno,
struct
usbd_interface **iface);
struct usbd_device *
usbd_pipe2device_handle(
struct
usbd_pipe *pipe);
int
usbd_create_xfer(
struct
usbd_pipe *pipe,
size_t
len,
unsigned int
flags,
unsigned int
nframes,
struct usbd_xfer
**xp);
void
usbd_destroy_xfer(
struct
usbd_xfer *xfer);
void *
usbd_get_buffer(
struct
usbd_xfer *xfer);
usbd_status
usbd_sync_transfer(
struct
usbd_xfer *req);
usbd_status
usbd_sync_transfer_sig(
struct
usbd_xfer *req);
usbd_status
usbd_open_pipe_intr(
struct
usbd_interface *iface,
uint8_t address,
uint8_t flags,
struct usbd_pipe **pipe,
void *priv,
void *buffer,
uint32_t length,
usbd_callback callback,
int interval);
usbd_status
usbd_do_request(
struct
usbd_device *dev,
usb_device_request_t *req,
void *data);
usbd_status
usbd_do_request_flags(
struct
usbd_device *dev,
usb_device_request_t *req,
void *data,
uint16_t flags,
int *actlen,
uint32_t timo);
usb_interface_descriptor_t *
usbd_get_interface_descriptor(
struct
usbd_interface *iface);
usb_config_descriptor_t *
usbd_get_config_descriptor(
struct
usbd_device *dev);
usb_device_descriptor_t *
usbd_get_device_descriptor(
struct
usbd_device *dev);
usbd_status
usbd_set_interface(
struct
usbd_interface *iface,
int
altidx);
int
usbd_get_no_alts(
usb_config_descriptor_t
*iface,
int ifaceno);
usbd_status
usbd_fill_deviceinfo(
struct
usbd_device *dev,
struct
usb_device_info *di);
int
usbd_get_interface_altindex(
struct
usbd_interface *iface);
usb_endpoint_descriptor_t *
usbd_get_endpoint_descriptor(
struct
usbd_interface *dev,
uint8_t address);
usb_interface_descriptor_t *
usbd_find_idesc(
usb_config_descriptor_t
*cd,
int iindex,
int ano);
usb_endpoint_descriptor_t *
usbd_find_edesc(
usb_config_descriptor_t
*cd,
int ifaceidx,
int altidx,
int endptidx);
void
usbd_dopoll(
struct
usbd_interface *iface);
void
usbd_set_polling(
struct
usbd_device *iface,
int
val);
const char *
usbd_errstr(
usbd_status
err);
void
usbd_add_dev_event(
int
type,
struct usbd_device
*iface);
void
usbd_add_drv_event(
int
type,
struct usbd_device
*iface,
device_t dv);
char *
usbd_devinfo_alloc(
struct
usbd_device *iface,
int
showclass);
void
usbd_devinfo_free(
char
*str);
const struct usbd_quirks *
usbd_get_quirks(
struct
usbd_device *iface);
usbd_status
usbd_reload_device_desc(
struct
usbd_device *iface);
int
usbd_ratecheck(
struct
timeval *tv);
usbd_status
usbd_get_string(
struct
usbd_device *iface,
int
si,
char *buf);
usbd_status
usbd_get_string0(
struct
usbd_device *iface,
int
si,
char *buf,
int unicode);
void
usb_desc_iter_init(
struct
usbd_device *iface,
usbd_desc_iter_t *iter);
const usb_descriptor_t *
usb_desc_iter_next(
usbd_desc_iter_t
*iter);
void
usb_add_task(
struct
usbd_device *iface,
struct
usb_task *task,
int
queue);
void
usb_rem_task(
struct
usbd_device *iface,
struct
usb_task *task);
void
usb_init_task(
struct
usb_task *task,
void
(*func)(void *),
void
*arg,
uint8_t,
flags);
const struct usb_devno *
usb_lookup(
const
struct usb_devno *tbl,
uint16_t vendor,
uint16_t product);
Obsolete functions
The following functions have been obsoleted from
usbdi.h
.
void *
usbd_alloc_buffer(
struct
usbd_xfer *xfer,
uint32_t
size);
void
usbd_free_buffer(
struct
usbd_xfer *xfer);
Utilities from usbdi_util.h
Based on the routines in
usbdi.h
a number of utility
functions have been defined that are accessible through
usbdi_util.h
.
usbd_status
usbd_get_desc(
struct
usbd_device *dev,
int
type,
int index,
int len,
void *desc);
usbd_status
usbd_get_config_desc(
struct
usbd_device *dev,
int
confidx,
usb_config_descriptor_t
*d);
usbd_status
usbd_get_config_desc_full(
struct
usbd_device *,
int
dev,
void *d,
int size);
usbd_status
usbd_get_device_desc(
struct
usbd_device *dev,
usb_device_descriptor_t
*d);
usbd_status
usbd_set_address(
struct
usbd_device *dev,
int
addr);
usbd_status
usbd_get_port_status(
struct
usbd_device *dev,
int
port,
usb_port_status_t
*ps);
usbd_status
usbd_set_hub_feature(
struct
usbd_device *dev,
int
sel);
usbd_status
usbd_clear_hub_feature(
struct
usbd_device *dev,
int
sel);
usbd_status
usbd_set_port_feature(
struct
usbd_device *dev,
int
port,
int sel);
usbd_status
usbd_clear_port_feature(
struct
usbd_device *dev,
int
port,
int sel);
usbd_status
usbd_get_device_status(
struct
usbd_device *dev,
usb_status_t *st);
usbd_status
usbd_get_hub_status(
struct
usbd_device *dev,
usb_hub_status_t *st);
usbd_status
usbd_set_protocol(
struct
usbd_interface *dev,
int
report);
usbd_status
usbd_get_report_descriptor(
struct
usbd_device *dev,
int
ifcno,
int repid,
int size,
void *d);
struct usb_hid_descriptor *
usbd_get_hid_descriptor(
struct
usbd_interface *ifc);
usbd_status
usbd_set_report(
struct
usbd_interface *iface,
int
type,
int id,
void *data,
int len);
usbd_status
usbd_set_report_async(
struct
usbd_interface *iface,
int
type,
int id,
void *data,
int len);
usbd_status
usbd_get_report(
struct
usbd_interface *iface,
int
type,
int id,
void *data,
int len);
usbd_status
usbd_set_idle(
struct
usbd_interface *iface,
int
duration,
int id);
usbd_status
usbd_alloc_report_desc(
struct
usbd_interface *ifc,
void
**descp,
int *sizep,
int mem);
usbd_status
usbd_get_string_desc(
struct
usbd_device *dev,
int
sindex,
int langid,
usb_string_descriptor_t
*sdesc);
void
usbd_delay_ms(
struct
usbd_device *dev,
u_int
ms);
usbd_status
usbd_set_config_no(
struct
usbd_device *dev,
int
no,
int msg);
usbd_status
usbd_set_config_index(
struct
usbd_device *dev,
int
index,
int msg);
usbd_status
usbd_bulk_transfer(
struct
usbd_xfer *xfer,
struct
usbd_pipe *pipe,
uint16_t
flags,
uint32_t
timeout,
void *buf,
uint32_t *size);
usbd_status
usbd_intr_transfer(
struct
usbd_xfer *xfer,
struct
usbd_pipe *pipe,
uint16_t
flags,
uint32_t
timeout,
void *buf,
uint32_t *size);
void
usb_detach_waitold(
device_t
dv);
void
usb_detach_wakeupold(
device_t
dv);
void
usb_detach_wait(
device_t
dv,
kcondvar_t *cv,
kmutex_t *lk);
void
usb_detach_broadcast(
device_t
dv,
kcondvar_t *cv);
DESCRIPTION
Device driver access to the USB bus centers around transfers. A transfer
describes a communication with a USB device. A transfer is an abstract concept
that can result in several physical packets being transferred to or from a
device. A transfer is described by the
struct usbd_xfer
* cookie. A pipe is a logical connection to a USB device. It is
described by the
struct usbd_pipe * cookie. See the
TRANSFERS and
PIPES sections for more details.
There are a number of functions to obtain a handle, descriptor of resource
count:
-
-
- usbd_device2interface_handle(dev,
ifaceno, iface)
- Fills in iface with the
struct usbd_interface * for the USB device
dev on interface number
ifaceno.
-
-
- usbd_interface2device_handle(iface,
dev)
- Fills in dev with the
struct usbd_device * pointer for interface
iface.
-
-
- usbd_pipe2device_handle(pipe)
- Returns the struct usbd_device *
associated with pipe.
-
-
- usbd_interface2endpoint_descriptor(iface,
address)
- Returns the usb_endpoint_descriptor_t
* for the particular interface iface at
address address.
-
-
- usbd_endpoint_count(dev,
count)
-
- usbd_interface_count(dev,
count)
- Fills in count with the number of
endpoint or interfaces the USB device dev has.
Error handling and other return values are described in
usbd_status(9).
Additional comments on particular functions:
-
-
- usbd_errstr(err)
- Returns the string associated with
err.
-
-
- usbd_add_dev_event(type,
iface)
- The type must be one of
USB_EVENT_CTRLR_ATTACH
,
USB_EVENT_CTRLR_DETACH
,
USB_EVENT_DEVICE_ATTACH
and
USB_EVENT_DEVICE_DETACH
.
-
-
- usbd_add_drv_event(type,
iface, dv)
- The type must be one of
USB_EVENT_DRIVER_ATTACH
and
USB_EVENT_DRIVER_DETACH
. The
dv corresponds with the
device_t associated with the device attached or
detached.
-
-
- usb_lookup(tbl,
vendor, product)
- Lookup a USB device. The returned struct
usb_devno pointer has these members:
- uint16_t
ud_vendor;
- uint16_t
ud_product;
The USB_PRODUCT_ANY
macro can be used to match any
USB product by a particular vendor.
PIPES
Pipes are created and destroyed by using the
usbd_open_pipe(),
usbd_open_pipe_intr() and
usbd_close_pipe() functions. The open functions take the
interface handle
iface, the
address of this pipe and
flags for
this pipe which currently may be 0, or a combination of
USBD_EXCLUSIVE_USE
, to enable exclusive access to this
interface and address, and
USBD_MPSAFE
, to allow
running transfer callbacks on this pipe without first acquiring
kernel_lock
. The
usbd_open_pipe_intr() takes additional arguments
priv to set the default private handle.
buffer and
len to describe the
buffer to be used,
callback for the function to call at
interrupt time, and finally the
interval for interrupts
to be delivered in milliseconds. The
interval may be set
to
USBD_DEFAULT_INTERVAL
use the default interval,
specified by the ep. description. It is common to have more than one pipe per
device.
TRANSFERS
Transfers are created and destroyed with
usbd_create_xfer()
and
usbd_destroy_xfer(), respectively, and are associated
with a pipe at their creation time. The create function takes the pipe handle
pipe, the length of the largest transfer possible
len, possible transfer flags
flags, the number of isochronous frames (or 0) in
nframes.
The data describing the transfer is filled by either
usbd_setup_default_xfer() for control pipe transfers, by
usbd_setup_xfer() for bulk and interrupt transfers, and by
usbd_setup_isoc_xfer() for isochronous transfers. Private
data may be passed between setup and completion or status calls using the
void *priv argument.
Arguments to the setup functions include the newly allocated
xfer, the private data
priv, the
timeout in milliseconds, for control, bulk and interrupt
transfers
buffer the data to transfer and its
length and for isochronous transfers the frame length
frlengths and number of frames
nframes, and for default transfers a USB request
structure
req must be presented. See the
INITIALISING USB REQUESTS
section for more details on USB requests.
The transfer specific
flags that can be set are:
-
-
USBD_SYNCHRONOUS
- Wait for completion
-
-
USBD_SYNCHRONOUS_SIG
- When waiting for completion, allow signals to trigger wake
up.
-
-
USBD_SHORT_XFER_OK
- Short reads are not an error
-
-
USBD_FORCE_SHORT_XFER
- Force last short packet on write
The
usbd_get_buffer() function returns the current kernel
address for the buffer suitable for transfer in
xfer.
The
usbd_open_pipe(),
usbd_open_pipe_intr(),
usbd_close_pipe(),
usbd_alloc_xfer(), and
usbd_free_xfer() can all sleep and should not be called from
interrupt context as a result.
Upon completion the
callback function is called, which
takes the completed
xfer, the private data
priv originally assocated with this transfer, and
status the status of this transfer.
Transfers are initiated by calling
usbd_transfer(), and their
results made be later obtained by calling
usbd_get_xfer_status, which fills in the private data
priv, original buffer location
buffer, the length
length, and the
status of this request.
The
usbd_bulk_transfer() and
usbd_intr_transfer() functions are used to transfer data in
either an interrupt or bulk fashion, and are front-ends to the
usbd_setup_xfer(),
usbd_transfer() and
usbd_get_xfer_status(), as well as associated error
handling. The
usbd_sync_transfer() is identical to
usbd_transfer() with the
USBD_SYNCHRONOUS
flag set. The
usbd_sync_transfer_sig() is identical to
usbd_transfer() with the
USBD_SYNCHRONOUS
and
USBD_SYNCHRONOUS_SIG
flags set.
Transfers are aborted via this pipe with
usbd_abort_pipe() and
usbd_abort_default_pipe().
The
usbd_clear_endpoint_stall() and
usbd_clear_endpoint_stall_async() functions are used to
clear endpoint halt in either a synchronous or asynchronous fashion. To clear
the toggle state of an endpoint the
usbd_clear_endpoint_toggle() function should be used.
A request is described by a
usb_device_request_t which
must be initialised as necessary before calling either
usbd_do_request() or
usbd_do_request_flags() to submit the request. For both
these functions
dev is the handle of the USB device the
request is for,
req is the USB request, as described in
the
INITIALISING USB
REQUESTS section, and then
data is a buffer
containing the data for the request. For the
usbd_do_request_flags() function there are additional
flags passed to the
usbd_setup
function,
actlen a pointer to fill in with the actual
length of this request, and
timo, the number of
milliseconds to wait before timing out this request.
INITIALISING USB REQUESTS
There are 5 members of a
usb_device_request_t that must be
initialised:
- uByte
bmRequestType;
- uByte
bRequest;
- uWord
wValue;
- uWord
wIndex;
- uWord
wLength;
The first two are normal byte values that may be simply assigned, but the last
three must be initialised with the
USETW() macro.
The
bmRequestType holds the request type of this USB
request, which describes the indended recipient of the request.
This may be one of:
with one of:
UT_STANDARD
-
UT_CLASS
-
UT_VENDOR
-
and with one of:
UT_DEVICE
-
UT_INTERFACE
-
UT_ENDPOINT
-
UT_OTHER
-
These are also in combinations as:
UT_READ_DEVICE
-
UT_READ_INTERFACE
-
UT_READ_ENDPOINT
-
UT_WRITE_DEVICE
-
UT_WRITE_INTERFACE
-
UT_WRITE_ENDPOINT
-
UT_READ_CLASS_DEVICE
-
UT_READ_CLASS_INTERFACE
-
UT_READ_CLASS_OTHER
-
UT_READ_CLASS_ENDPOINT
-
UT_WRITE_CLASS_DEVICE
-
UT_WRITE_CLASS_INTERFACE
-
UT_WRITE_CLASS_OTHER
-
UT_WRITE_CLASS_ENDPOINT
-
UT_READ_VENDOR_DEVICE
-
UT_READ_VENDOR_INTERFACE
-
UT_READ_VENDOR_OTHER
-
UT_READ_VENDOR_ENDPOINT
-
UT_WRITE_VENDOR_DEVICE
-
UT_WRITE_VENDOR_INTERFACE
-
UT_WRITE_VENDOR_OTHER
-
UT_WRITE_VENDOR_ENDPOINT
-
The
bRequest describes which request is being made. The
available values are:
UR_GET_STATUS
-
UR_CLEAR_FEATURE
-
UR_SET_FEATURE
-
UR_SET_ADDRESS
-
UR_GET_DESCRIPTOR
-
UR_SET_DESCRIPTOR
-
The
wValue,
wIndex and
wLength are device-specific values and must be
initialised with the
USETW() macro.
USB REQUEST TYPES AND
STRUCTURES
The
UR_GET_STATUS
request operates on a
usb_status_t structure, which has this member:
For device status requests the
wStatus member may have
either of these bit flags set:
UDS_SELF_POWERED
-
UDS_REMOTE_WAKEUP
-
For endpoint status requests the
wStatus member may have
this bit flag set:
The
UR_CLEAR_FEATURE
and
UR_SET_FEATURE
requests clear or set special features
on USB devices. The values for
wValue,
wIndex and
wLength depend upon the
device and device type.
The
UR_SET_ADDRESS
request sets the virtual USB address
of a port using the
wValue.
The
UR_GET_DESCRIPTOR
and
UR_SET_DESCRIPTOR
requests operate on a
usb_descriptor_t structure, which has these members:
- uByte
bLength;
- uByte
bDescriptorType;
The
bDescriptorType member may be one of the following
values:
UDESC_DEVICE
-
UDESC_CONFIG
-
UDESC_STRING
-
UDESC_INTERFACE
-
UDESC_ENDPOINT
-
UDESC_DEVICE_QUALIFIER
-
UDESC_OTHER_SPEED_CONFIGURATION
-
UDESC_INTERFACE_POWER
-
UDESC_OTG
-
UDESC_DEBUG
-
UDESC_INTERFACE_ASSOC
-
UDESC_CS_DEVICE
-
UDESC_CS_CONFIG
-
UDESC_CS_STRING
-
UDESC_CS_INTERFACE
-
UDESC_CS_ENDPOINT
-
UDESC_HUB
-
The
usbd_set_interface() function can be used to change the
index used for transfers on this interface as obtained via
usbd_device2interface_handle().
USB DEVICE DETACHMENT
There are two functions available to ease the detach of active devices.
Typically a reference count is maintained on syscall activity. When a USB
device is to be detached, the reference count should be decremented and if it
is greater or equal to zero,
usb_detach_wait() should be
called on the
dv associated with this USB device and,
typically, a device-specific condition variable
cv. and
mutex
lk protecting this reference count state. At the
end of each syscall function, if the reference count is decremented to less
than zero, then
usb_detach_broadcast() must be called on the
dv and
cv that is being waited on
with
usb_detach_wait().
The are another pair of functions with similar functionality that do not use a
condition variable or mutex and should be avoided in new code. The
usb_detach_waitold() function works like
usb_detach_wait(), and the
usb_detach_wakeupold() function works like
usb_detach_broadcast().
USB TASK MANAGEMENT
The USB stack provides a task management framework to execute tasks in a thread
context at the soonest opportunity. Typically this is used by network drivers
to handle periodic updates or status change requests, or other operations that
need to run in a normal context.
The
usb_init_task() function takes a pointer to a
struct usb_task that will be initalised, a function to
call for this task
func, the argument to pass to
func,
arg, and the task flags
flags. If the
flags argument is
USB_TASKQ_MPSAFE
, the
func
function will be called without first acquiring
kernel_lock
.
To invoke the task callback the
usb_add_task() function should
be called with the
iface associated with this device,
the task structure
task, and the
queue to run against, either
USB_TASKQ_HC
for operations initiated by host
controllers or
USB_TASKQ_DRIVER
for operations
initiated by USB drivers.
To deschedule a potentially running task the
usb_rem_task()
function should be called.
The driver using these facilities is expected to provide the necessary
serialisation between
usb_init_task(),
usb_add_task() and
usb_rem_task() for each
specific
struct usb_task.
SEE ALSO
usb(4),
usbd_status(9)
HISTORY
This
usbdi interface first appeared in
NetBSD
1.4. The interface is based on an early definition from the OpenUSBDI
group within the USB organisation. Right after this definition the OpenUSBDI
development got closed for open source developers, so this interface has not
followed the further changes. The OpenUSBDI specification is now available
again, but looks different.
BUGS
This manual is under development, so its biggest shortcoming is
incompleteness.