On Mon, Apr 23, 2012 at 12:27:57PM -0400, Alan Stern wrote: > On Mon, 23 Apr 2012, Thomas Knauth wrote: > > > >> Is this the intended behavior? Any writes/reads falling short of the > > >> gadget zero buffer length, cause testusb to hang (USB activity LED on > > >> the net3380 is on, during this time though). > > > > > > No it shouldn't hang, but I must say I don't like how g_zero works > > > today. It relies a lot on the peripheral controller being able to abort > > > a transfer which was started by mistake. If you look at how USB classes > > > are built, they all have some way to tell the other end transfer is > > > over. > > > > > > Either they will negotiate a transfer size (e.g. Mass Storage with CBW) > > > or they will use a ZLP to notify about the end of the transfer; but > > > g_zero/usbtest has neither. > > > > This may actually be the explanation. The driver cannot tell whether > > the request is finished or not if the size supplied to usbtest is a > > multiple of the maximum packet size. Using, e.g., -s 511, works for > > any value of -c. Using -s with g_zero buflen also works. Setting -s to > > anything less than g_zero buflen being a multiple of the maximum > > packet size, does not work. As far as I can tell from reading the > > code, the driver does not know whether there will be more data for > > this request, because req.actual < req.length (req.length defined by > > g_zero buflen, req.actual defined by -s parameter to usbtest) and it > > is not a short packet: > > > > is_short = (count == 0) || ((count % ep->ep.maxpacket) != 0); > > > > int retval = is_short || ((req->req.actual == req->req.length) && > > !req->req.zero); > > > > I'm still unsure who is at fault here: the driver or g_zero/usbtest > > and how best to fix this. Any suggestions? > > Why is this a problem? All that should happen is you transfer less > data than g_zero expects. Either way, the transfer should succeed. ok, let's say usbtest is sending at 1024 byte chunks 5 times and g_zero uses a 4096 byte buffer, this will mean UDC will start a 4k e.g. DMA transfer and that single DMA transfer will receive the first 4 chunks sent by usbtest. Now g_zero blindly starts another 4k transfer, UDC's DMA is kicked, but host only sends 1k. That transfer will never finish because 1024 is aligned to wMaxPacketSize (so, not a short packet) and is not the end of the transfer kicked to DMA (which was 4k). How do you make this work ? If you look at most UDC's code, you will see there's a DMA abort or some sort of transfer abort mechanism whenever actual == length, this is what makes it magically work, but IMHO, that's not how USB is supposed to be implemented. Look at all other classes, they have a way to negotiate size of transfer (Mass Storage's CBW, Ethernet's MTU, MTP's handling of ZLP and so on) so there will always be a way to finish the transfer. But g_zero is special, because it relies on the UDC aborting a transfer which was bigger than necessary. -- balbi
Attachment:
signature.asc
Description: Digital signature