Comtrol eCos User Manual

Page 696

Advertising
background image

Receiving Data from the Host

between the host and the target has been broken, and

-EAGAIN

for when the endpoint has been

halted

. Specific

USB device drivers may specify additional error conditions.

The normal sequence of events is that the USB device driver will update the appropriate hardware registers. At
some point after that the host will attempt to send data by transmitting an OUT token followed by a data packet,
and since a receive operation is now in progress the data will be accepted and ACK’d. If there were no receive
operation then the peripheral would instead generate a NAK. The USB hardware will generate an interrupt once
the whole packet has been received, and the USB device driver will service this interrupt and arrange for a DSR
to be called. Isochronous and interrupt transfers involve just a single packet. However, bulk transfers may involve
multiple packets so the device driver has to check whether the packet was a full 64 bytes or whether it was a
terminating packet of less than this. When the device driver DSR detects a complete transfer it will inform higher-
level code by invoking the supplied completion function.

This means that the completion function will normally be invoked by a DSR and not in thread context - although
some USB device drivers may have a different implementation. Therefore the completion function is restricted in
what it can do. In particular it must not make any calls that will or may block such as locking a mutex or allocating
memory. The kernel documentation should be consulted for more details of DSR’s and interrupt handling generally.

It is possible that the completion function will be invoked before

usbs_start_rx_buffer

returns. Such an event

would be unusual because the transfer cannot happen until the next time the host tries to send data to this peripheral,
but it may happen if for example another interrupt happens and a higher priority thread is scheduled to run. Also, if
the endpoint is currently halted then the completion function will be invoked immediately with

-EAGAIN

: typically

this will happen in the current thread rather than in a separate DSR. The completion function is allowed to start
another transfer immediately by calling

usbs_start_rx_buffer

again.

USB device drivers are not expected to perform any locking. It is the responsibility of higher-level code to ensure
that there is only one receive operation for a given endpoint in progress at any one time. If there are concurrent
calls to

usbs_start_rx_buffer

then the resulting behaviour is undefined. For typical USB applications this does

not present any problems, because only one piece of code will access a given endpoint at any particular time.

The following code fragment illustrates a very simple use of

usbs_start_rx_buffer

to implement a blocking

receive, using a semaphore to synchronise between the foreground thread and the DSR. For a simple example like
this no completion data is needed.

static int error_code = 0;

static cyg_sem_t completion_wait;

static void

completion_fn(void* data, int result)

{

error_code = result;

cyg_semaphore_post(&completion_wait);

}

int

blocking_receive(usbs_rx_endpoint* ep, unsigned char* buf, int len)

{

error_code = 0;

usbs_start_rx_buffer(ep, buf, len, &completion_fn, NULL);

cyg_semaphore_wait(&completion_wait);

return error_code;

}

592

Advertising