Re: Understanding USB callback events and sequence

From: Hans Petter Selasky <>
Date: Wed, 23 Mar 2022 09:35:24 UTC

On 3/22/22 22:43, Farhan Khan wrote:
> On Tue, Mar 22, 2022, at 2:28 PM, Hans Petter Selasky wrote:
>> This just means that the driver wants to check if it can send more
>> packets after the current job completed (USB_ST_TRANSFERRED).
> So it "double-dips" in case there are any other packets while it has the CPU without having to call us usb_transfer_start() again. Cool!
>>> Finally, I have been looking at USB traffic under wireshark (interpreted from usbdump -w file.pcap) and I see that every USB packet has a response from the device. Is this response packet handled by one of the RX callbacks? Or is this the same as TX's USB_ST_TRANSFERRED?

The response packet is handled after USB_ST_TRANSFERRED or 
USB_ST_CANCELLED / default, if something went wrong.

>> The "DONE" callback is either USB_ST_TRANSFERRED or USB_ST_CANCELLED /
>> default.
> Why is this necessary? Meaning, why not have the driver just process its "Done" step without the need for another callback?

Because it avoids races and additional state keeping in the driver. Many 
USB driver developers don't think about corner cases. For example what 
do you do if there is a USB transaction error. In other USB stacks like 
Linux and Windows, writing up the code to reset the USB endpoint is 
usually never done, because it requires a bunch of code and state 
keeping. In FreeBSD this piece comes for free and allows for continuous 
operation of your device, also if something should go wrong, which many 
developers simply don't think about. Just follow the existing examples 
in the FreeBSD kernel and you will be cool :-)

Consider the callback function a serialized event callback where you may 
re-fill and setup the next USB transfer.

> Regarding Wireshark, are the reply USB packets from the device processed by a handler in any way? I ask because I am currently porting over some code and I do not seem to have my RX interrupt callback triggering and trying to determine why not. Perhaps something is wrong in my `usb_config`?

Is the RX xfer NULL?

If yes, there is something wrong in the usb_config.

If no, then maybe you didn't call usbd_transfer_start()

> I wonder if it has anything to do with the endpoint address being a specific address rather than `UE_ADDR_ANY`? Curious why that value even exists rather than the exact address?

Because when you work with class devices, the endpoint number may change 
and you don't want each and every driver to go and parse the descriptors 
to figure this out.