Name
Transfer Object — Structure and Interface
Synopsis
#include <cyg/io/usb.h>
usb_tfr *usb_device_tfr_alloc(
usb_device *dev)
;
usb_tfr *usb_target_tfr_alloc(
usb_target *tgt)
;
void usb_tfr_ref(
usb_tfr *tfr)
;
void usb_tfr_unref(
usb_tfr *tfr)
;
void usb_tfr_init(
usb_tfr *tfr, usb_uint8 endpoint, usb_uint8 attr, void *buffer, usb_uint32 size, usb_tfr_callback *callback, void *callback_data)
;
#define usb_request_init(
usb_request req, usb_uint8 request_type, usb_uint8 request, usb_uint16 value, usb_uint16 index, usb_uint16 length)
;
void usb_tfr_control(
usb_tfr *tfr, usb_uint8 endpoint, usb_request *req, void *buffer, usb_uint32 size, usb_tfr_callback *callback, void *callback_data)
;
usb_tfr *usb_control_tfr(
usb_device *dev, usb_uint8 request_type, usb_uint8 request, usb_uint16 value, usb_uint16 index, usb_tfr_callback *callback, void *callback_data)
;
void usb_tfr_bulk(
usb_tfr *tfr, usb_uint8 endpoint, usb_request *req, void *buffer, usb_uint32 size, usb_tfr_callback *callback, void *callback_data)
;
void usb_tfr_submit(
usb_tfr *tfr)
;
void usb_tfr_cancel(
usb_tfr *tfr)
;
Description
Most interaction between clients of the USB stack and the stack itself happens through the use of transfer objects (or just transfers). These data structures are allocated and initialized by the client and passed to the USB stack. When the transfer completes, the client is notified via a callback, following which it may release or reuse the object for another transfer.
Transfer Class Object
A transfer has the following structure:
struct usb_tfr { usb_node node; // List/queue node union { usb_device *dev; // Host device usb_target *tgt; // Target device }; usb_uint16 refcount; // Reference count usb_uint16 endpoint; // Endpoint address usb_uint8 attr; // Transfer type usb_uint8 flags; // Additional flags int status; // Current/returned status void *tfr_buffer; // Data buffer usb_uint16 tfr_size; // Size of transfer/buffer usb_uint16 tfr_actual; // Actual size transferred usb_tfr_callback *callback[2]; // Completion callback stack void *callback_data; // Callback data // The following fields are used by the HCD or PCD void *hcd_endpoint; // HCD endpoint private data usb_list hcd_list; // HCD transfer list // Per-transfer-type fields. union { struct { usb_uint8 setup[8]; // Setup packet } control; struct { } bulk; #ifdef USB_CONFIG_INTERRUPT struct { } interrupt; #endif #ifdef USB_CONFIG_ISOCHRONOUS struct { int start_frame; // Start frame int interval; // transfer interval int pkt_count; // Number of packets usb_iso_packet_desc *iso_packet; // packet descriptors } isochronous; #endif }; };
The fields of the transfer are as follows:
- node
-
A list node, which is used to link this transfer into internal
lists in the USB stack. It may also be used by the client when
the object is in its possession, but should be unlinked whenever
passed to
usb_tfr_submit()
. - dev
-
A pointer to the host device object on which this transfer will
operate. This is filled in when the transfer is allocated by
usb_device_tfr_alloc()
. This value should not be changed directly by the client since other fields in this object may depend on this field. The transfer also holds a reference to the device which may not be decremented properly if this field is changed. If the client needs to communicate with a different device, it should allocate a new transfer object. - dev
-
A pointer to the target object on which this transfer will
operate. This is filled in when the transfer is allocated by
usb_target_tfr_alloc()
. This value should not be changed directly by the client since other fields in this object may depend on this field. The transfer also holds a reference to the target which may not be decremented properly if this field is changed. - refcount
-
Transfer reference count. This controls the existence of this
transfer. It can be incremented with a call to
usb_tfr_ref()
and decremented with a callusb_tfr_unref()
. This field is set to 1 when the transfer is allocated, and the reference count on the associated device or target is also incremented. If the refcount is decremented to zero then the device or target reference is decremented, and the transfer returned to the free pool. - endpoint
-
This is the endpoint number and direction. This field has the
same format as the
bEndpointAddress
field of an endpoint descriptor and is initialized from the descriptor. - attr
-
This is the endpoint attributes; it mainly defines the type of
transfer: control, bulk, interrupt or isochronous. It may contain
other information for some transfer types. This field is
initialized from the
bmAttributes
field of an endpoint descriptor and has the same format. - flags
This field contains a number of flag bits that control the nature of the transfer. If
USB_TFR_FLAGS_TARGET
is set then this is a target mode transfer and thetgt
field is is valid, otherwise it is a host mode transfer and thedev
field is valid. The flagsUSB_TFR_FLAGS_START
andUSB_TFR_FLAGS_END
allow transfers to be chained together to provide a scatter/gather facility; this is currently not implemented. TheUSB_TFR_FLAGS_CALLBACK
flag indicates that this transfer's callback should be called when it is complete. TheUSB_TFR_FLAGS_SHORT_OK
flag indicates that a short transfer should be treated as a success and not a failure; this is currently not implemented for host transfers, but is for target OUT transfers.By default, a transfer is initialized with the
START
,END
andCALLBACK
flags set. Additionally a target mode transfer is initialized with theTARGET
flag set.- status
-
This field contains the transfer status. While it is in the
possession of the USB stack, this field may be used to record
internal state transitions. When it is returned to the client via
a callback, it will contain either
USB_OK
to indicate the transfer was successful, an error code, or a status code (e.g.USB_TFR_CANCELLED
). - tfr_buffer
- A pointer to a buffer containing the data to be transmitted, or where the received data should be places. There are no explicit alignment requirements on this buffer, but on some platforms this buffer may need to be synchronized to external memory or flushed from the data cache, so if it is not cache line aligned these operations may have a side-effect on other data.
- tfr_size
- The size of the data buffer, in bytes, and hence the size of the transfer. The transfer size is not limited by the maximum packet size of the addressed endpoint, the driver may split the transfer into a sequence of packets if necessary.
- tfr_actual
-
When the transfer is complete, this will contain the number of
bytes actually transferred. This should only differ from
tfr_size
if theSHORT_OK
flag is set. - callback
- When a transfer has completed, this is signalled to the client by calling a callback routine. Callbacks are managed as a stack, with the client callback as the lowest, last, callback. This mechanism allow the USB stack to interpose its own finalization processing for a transfer if required. This callback stacking is opaque to the client.
- callback_data
- This is a client-supplied data value that the client can supply to ensure continuity between the submitter and the callback; it is usually a pointer to some controlling data structure. The client's callback can retrieve this value from the transfer by accessing this field. While callbacks are stacked, the callback_data is not, internal callbacks only make use of the standard transfer fields.
- hcd_endpoint
- This field is for use by the HCD or PCD, and typically contains a pointer to the data structure in the driver that controls the endpoint to which this transfer is directed.
- hcd_list
- This field is for use by the HCD or PCD, and typically is the root of a chain of internal data structures that define the data transfer.
- control
-
This sub-structure is part of an anonymous union that defines
per-transfer-type fields consisting of this field and the
following
bulk
,interrupt
andisochronous
fields. This structure contains the contents of the setup packet. In host mode normally the setup packet is not assigned directly, but is copied here byusb_tfr_control()
after being initialized elsewhere withusb_request_init()
. - bulk
- This field contains bulk transfer control fields. It is currently empty.
- interrupt
- This field contains interrupt transfer control fields. It is currently empty and is only defined if interrupt transfer support is configured. It's contents may change significantly when interrupt transfer support is implemented.
- isochronous
- This field contains isochronous transfer control fields. It is currently empty and is only defined if isochronous transfer support is configured. At present isochronous transfers are not supported. It's contents may change significantly when isochronous transfer support is implemented.
API
There are a number of API functions associated with the management of transfer objects.
Host mode clients should allocate a transfer by calling
usb_device_tfr_alloc()
. The result will be a pointer
to a transfer which has been zeroed except that the
node
field will be initialized, the
dev
field will be set to the supplied
device pointer and the refcount
will be
set to 1. Additionally, usb_device_ref()
will
have been called on the device. This function will return a NULL
pointer if there are no transfers available for allocation.
Target mode clients should allocate a transfer by calling
usb_target_tfr_alloc()
. The result will be a
pointer to a transfer which has been zeroed except that the
node
field will be initialized, the
tgt
field will be set to the supplied
target pointer, the refcount
will be set
to 1 and usb_target_ref()
will have been
called on the target. The flags
field
will be initialized with the
USB_TFR_FLAGS_TARGET
flag. This function will
return a NULL pointer if there are no transfers available for
allocation.
If a client needs to take further reference to the transfer it can
call usb_tfr_ref()
. References are released by
calling usb_tfr_unref()
. When a client is
finished with a transfer it should call
usb_tfr_unref()
a last time to release the
initial reference. This may have the side-effect of calling
usb_device_unref()
or
usb_target_unref()
which may result in the
device object being freed.
In general, a transfer is initialized by one of several routines to
create a specific type of transfer. The most general initialization
routine is usb_tfr_init()
which sets up the
transfer with the endpoint address and attributes, a data buffer,
and a callback. This is the only initialization function that
should be applied to target mode transfers, the remaining
initialization functions only apply to host mode transfers.
Control transfer initialization is supported by a number of
functions. The function usb_tfr_control()
initializes a general control transfer. The
endpoint
argument is used to look up the
endpoint in the device and initialize the
endpoint
and
attr
fields in the transfer. The
req
argument points to a completed USB
request that will be copied into the
setup
buffer. The data buffer and
callback are initialized too. The USB request can be initialized
using the usb_request_init()
macro. The first
argument to this is the name of the request to initialize, not a
pointer. The remaining arguments give values for the various
fields; the 16 bit fields will potentially be byte swapped into
little endian order.
The function usb_control_tfr()
provided a
higher level interface to create control transfers that do not
transfer additional data. This is given the destination device plus
values for the request type, request code, value and index field
(but not the length), and the callback. Using these parameters, a
transfer is allocated, a request buffer created and the transfer
initialized with an endpoint address of zero. If a transfer cannot
be allocated, a NULL pointer is returned.
A bulk transfer can be initialized using
usb_tfr_bulk()
. The
endpoint
argument is used to look up the
endpoint in the device and initialize the
endpoint
and
attr
fields in the transfer. The buffer
and callback are also initialized.
Interrupt and Isochronous transfers are not currently supported, but when they are similar functions to initialize those will be available.
A transfer is submitted to the USB stack by calling
usb_submit()
. This function performs some
simple checks before passing the transfer on to the appropriate
driver. If this function is passed a NULL transfer, it will return
USB_ERR_TFR_ALLOC
. The transfer initialization
routines also return if a NULL transfer is passed to them. This
allows detection and handling of transfer allocation failures in
most cases to be deferred until this call, keeping error handling
simpler.
A transfer can be cancelled by calling
usb_cancel()
. This may simply mark the
transfer for cancellation, the transfer may not actually be
cancelled until some time after this function returns. When the
transfer is actually cancelled, its callback will be called with a
status of USB_TFR_CANCELLED
. However, if the
transfer was already finished, or caused an error, the callback
status may be USB_OK
or an error code. Thus
client code cannot rely on the transfer completing with a CANCELLED
status; this call just ensures that the transfer will be returned
to the client in some way. Note that it is not very useful to
cancel host mode control or bulk transfers since they will usually
be processed as soon as submitted and will be returned quickly; the
client is unlikely to catch them in time.
2024-03-18 | eCosPro Non-Commercial Public License |