Buffer management – Comtrol eCos User Manual

Page 707

Advertising
background image

Control Endpoints

Non-standard control messages always have to be processed by higher-level code. This could be class-specific
packages. For example, the USB-ethernet package will handle requests for getting the MAC address and for en-
abling or disabling promiscuous mode. In all cases the device driver will store the initial request in the

con-

trol_buffer

field, check for an appropriate handler, and invoke it with details of the control endpoint and

any handler-specific data that has been installed alongside the handler itself. The handler should return either

USBS_CONTROL_RETURN_HANDLED

to report success or

USBS_CONTROL_RETURN_STALL

to report failure. The de-

vice driver will report this to the host.

If there are multiple parties interested in a particular type of control messages, it is the responsibility of application
code to install an appropriate handler and process the requests appropriately.

Buffer Management

typedef struct usbs_control_endpoint {

...

unsigned char*

buffer;

int

buffer_size;

void

(*fill_buffer_fn)(struct usbs_control_endpoint*);

void*

fill_data;

int

fill_index;

usbs_control_return (*complete_fn)(struct usbs_control_endpoint*, int);

...

} usbs_control_endpoint;

Many USB control messages involve transferring more data than just the initial eight-byte header. The header
indicates the direction of the transfer, OUT for host to peripheral or IN for peripheral to host. It also specifies a
length field, which is exact for an OUT transfer or an upper bound for an IN transfer. Control message handlers
can manipulate six fields within the control endpoint data structure to ensure that the transfer happens correctly.

For an OUT transfer, the handler should examine the length field in the header and provide a single buffer for all the
data. A class-specific protocol would typically impose an upper bound on the amount of data, allowing the buffer
to be allocated statically. The handler should update the

buffer

and

complete_fn

fields. When all the data has

been transferred the completion callback will be invoked, and its return value determines the response sent back to
the host. The USB standard allows for a new control message to be sent before the current transfer has completed,
effectively cancelling the current operation. When this happens the completion function will also be invoked. The
second argument to the completion function specifies what has happened, with a value of 0 indicating success and
an error code such as

-EPIPE

or

-EIO

indicating that the current transfer has been cancelled.

IN transfers are a little bit more complicated. The required information, for example the enumeration data, may not
be in a single contiguous buffer. Instead a mechanism is provided by which the buffer can be refilled, thus allowing
the transfer to move from one record to the next. Essentially, the transfer operates as follows:

1. When the host requests another chunk of data (typically eight bytes), the USB device driver will exam-

ine the

buffer_size

field. If non-zero then

buffer

contains at least one more byte of data, and then

buffer_size

is decremented.

2. When

buffer_size

has dropped to 0, the

fill_buffer_fn

field will be examined. If non-null it will

be invoked to refill the buffer.

3. The

fill_data

and

fill_index

fields are not used by the device driver. Instead these fields are available

to the refill function to keep track of the current state of the transfer.

603

Advertising