USB: Question about usb_write() API

Sundar Subramaniyan


While developing a USB device controller driver for the Nordic nRF52840 SoC,
I ran into the problem of handling chunked/partial write() while coding the usb_dc_ep_write() function.

From what I could gather, the usb_write() API documentation states that the application calling
this function may choose to write all the data buffer at once even if it is larger than the maximum
packet size supported by the USB endpoint to which we're writing to.
Let's call this method "write all at once".

If the application or the class driver can manage to write in parts, then it must use the "bytes_ret" argument
to know how much data is written on the bus so as to know if there's anymore data remaining to be written in
the subsequent call. Let's call this method "write in parts".

In my case, I'm using bt_usb and it tries to write all at once - i.e. there's no handling of remaining data.
This mandates the USB device controller driver to take care of the writing in parts within the driver itself.
While this can be done in a simple loop if the driver talks synchronously to the USBD HW and do a poll and
a yield or use a semaphore till the HW completes the DMA and there's room to write more.

Here's what bt_usb does:

When I looked at other drivers to see how they are implemented, the designware USB driver seems to assume
the application/class drivers always support the "write in parts" method. I'm not blaming the driver or it's
implementation but I just wanted to point out that there are drivers which do not support handling chunked
write within them.

Here's the DW driver implementation:

Another class driver, netusb does it a little differently by writing in parts, but this too assumes the usb_write()
to be synchronous.

Here's what it does:

One more thing to consider is the write callbacks. In most cases, the application/class driver is the one that registers
the Bulk/Interrupt endpoint callbacks and the device stack has no way of knowing when to perform the next write, even
if it wants to handle this in the USB device stack.

My question now is, what is the ideal place to take care of truncation and chunk handling as per the USB device stack design?
Why the driver needs to handle the multi-part write and synchronization?

I understand that there are not going to be multiple USBD controllers on a given chip and taking care of this in the
driver won't cost much from memory/CPU cycles point of view but from USB DC driver implementation perspective
this might save a lot of time if the stack can abstract them.

Please let me know your opinions.


Join to automatically receive all group messages.