Re: USB: Question about usb_write() API


Andrei
 

Hi,

On Tue, Jan 30, 2018 at 02:31:46PM +0000, Cufi, Carles wrote:
+ Andrei

 

Carles

 

From: zephyr-devel-bounces@...
[mailto:zephyr-devel-bounces@...] On Behalf Of Sundar
Subramaniyan
Sent: 30 January 2018 13:18
To: zephyr-devel@...
Subject: [Zephyr-devel] USB: Question about usb_write() API

 

Hi,

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".
I think API states it supports both methods:
https://github.com/zephyrproject-rtos/zephyr/blob/master/include/usb/usb_device.h#L209


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:
[1]https://github.com/zephyrproject-rtos/zephyr/blob/master/samples/bluetooth/hci_usb/src/main.c#L665

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:
[2]https://github.com/zephyrproject-rtos/zephyr/blob/master/drivers/usb/device/usb_dc_dw.c#L1004
[3]https://github.com/zephyrproject-rtos/zephyr/blob/master/drivers/usb/device/usb_dc_dw.c#L423

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:
[4]https://github.com/zephyrproject-rtos/zephyr/blob/master/subsys/usb/class/netusb/netusb.c#L189
Fragmentation to USB packets is done on a higher level, in function_ecm
and finction_rndis files.

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 also look to usb_dc_ep_transfer() implemented for DW and STM32:

https://github.com/zephyrproject-rtos/zephyr/pull/5231

https://github.com/zephyrproject-rtos/zephyr/pull/5214

Best regards
Andrei Emeltchenko

Join {devel@lists.zephyrproject.org to automatically receive all group messages.