blob: 65523c6950bbfe48e14c34709e38928372e90880 [file]
==========================
USB (Universal Serial Bus)
==========================
NAKing USB OUT/IN Tokens
------------------------
USB supports a NAKing mechanism to pace incoming OUT data from the USB host.
The USB device class driver can control this NAKing only indirectly
by the manner in which it manages read requests.
Similarly, USB will refuse to perform the USB host's requests for IN data
by NAKing the host's IN tokens.
.. note:: USB direction naming is host-centric. This makes life difficult for
people working USB device drivers:
IN refers to data coming from the device INto the host.
But for the device, this is a write operation (write being
peripheral-centric: from-memory-to-peripheral).
OUT refers to data sent from the host OUT to the device.
For the device this is a read (peripheral-to-memory) operation.
NAKing USB OUT Tokens
^^^^^^^^^^^^^^^^^^^^^
Below is how the NAKing is implemented in the interaction between the USB
device class driver and USB Device Controller Drivers (DCDs):
1. At initialization time when the USB device class driver is enumerated
by the host, the class driver will allocates a number of read requests
(which contain request buffers).
2. The USB device class driver sends each allocated read request to the device
DCD via ``DRVR_EPSUBMIT()``.
3. Upon receipt, the DCD will keep all of these empty read requests in a list.
4. When the OUT token is received what happens next depends upon the state
of the list of empty read requests:
4a. If there are no requests in the list of empty read requests, the DCD
will have configured the endpoint to NAK the OUT token. This NAKing
will continue until the list of read requests is non-empty and the DCD
disables the NAKing to signal that it can accept the OUT packet data.
4b. If the list of read requests is not empty, the DCD will remove the next
read request from the list, receive the DATA accompanying the OUT
token, copy the received packet data into the read request's buffer,
and return the filled reqd request to the USB device class driver.
The data is returned using a callback function pointer that is
contained inside of the read request.
5. When the filled read request if returned, the USB device class driver will
add the newly filled read request to the TAIL of a list of filled read
requests. This will then be available to the the driver read logic when
the application requests more data.
This step will also wake up read logic that has been suspended waiting
for the availability of incoming data.
6. The receive logic starts when the application requests data (or it is
resumed after the receipt of new data) it will look at the read request
at the HEAD of the list of filled read requests. If will return the data
payload to the application by copying it from the read request's buffer
into the application-provided receive buffer:
6a. If the application's receive buffer becomes full and it cannot accept
more data, the receive logic will save the offset in the data buffer
where it left off. If the application asks for more data, it will
resume transferring at the point where it left off.
6b. If the receive logic transfers all of the data from the receive
buffer. It will remove the read request from the HEAD of the list
of filled read requests and return the receive buffer to the driver
via ``DRVR_EPSUBMIT()`` (See step 3).
The receive logic will then continue at step 6.
6c. If the receive logic needs more data in order to complete
the application read operation, it will wait until it is awakened
by the receipt of a newly filled.
CDC/ACM driver
~~~~~~~~~~~~~~
The CDC/ACM driver differs from all other drivers because it is REQUIRED
to discard data if there is no application ready to receive the data.
This is how a serial device works. So there is nothing like step 5
in the CDC/ACM driver and in step 6 the CDC/ACM driver will not remember
the point where it left off; if the application cannot accept any further
data, it will return the partially emptied read request to the DCD
immediately to be filled – dropping an untransferred data into the bit bucket.
This is not an error or an oversight in the CDC/ACM. This is the intentional
design. This is the CORRECT behavior of the CDC/ACM driver. Data overrun can
only be prevented on a serial connection by using either XON/XOFF software
flow control or hardware flow control. A special endpoint 0 control request
is reserved for the CDC/ACM implementation.
.. note:: As of this writing, the logic that implements the CDC/ACM
_hardware flow control has not been implemented.
There is a place holder for such logic, but the implementation
is missing._
NAKing USB IN Tokens
^^^^^^^^^^^^^^^^^^^^
The DCD will NAK IN tokens whenever it has nothing to send to the host PC.
Without going into as much detail, suffice it to say that the logic flow
is very similar to the case off OUT tokens with the following differences:
1. The list of empty write requests are not provided to the DCD at
initialization time, but are instead are retained in a list of empty write
requests in the USB device class driver.
2. When the USB class driver has data to send, it will remove a write request
from this list, copy the outgoing application data into the write buffer,
and send the filled write request to the DCD via ``DRVR_EPSUBMIT()``.
If there are no available write requests, the application thread may block
waiting for the next write request to be returned from the DCD.
3. The DCD will keep a list of filled write requests for each endpoint.
When that list becomes non-empty, the DCD will disable the NAKing and
set up to transfer data to the host. Normally this involves copying
the IN data into an outgoing FIFO or setting up some write DMA transfers:
3a. After the data has been transferred to the USB device hardware,
the emptied write request will be returned to the USB device class driver.
This is done through a callback function pointer within the write request.
3b. If the DCD's list of write requests becomes empty, it will set up
the endpoint to NAK any further IN tokens (after the final IN transfer
completes).
4. When the USB device class driver receives the emptied write request from
the DCD, it will return the write request to its list of empty write
request and may, perhaps, wake up any thread that was waiting
for an available write request to send more data.
So the fundamental different between IN and OUT processing is that for
IN transfers, empty write requests are saved in the USB device class driver
and then given to the DCD when they are filled with outgoing data.
For OUT transfers empty read requests are retained in the DCD and returned
to the USB device class driver when they filled with incoming data.
Similarly, filled read requests are queued for application read processing
in the USB device class driver; filled write requests are queued for transfer
to the host in the DCD.
But in either case, NAKing occurs when associated DCD request queue is empty.