Author Topic: USB Communication protocol  (Read 18882 times)

Limited_Atonement

  • Member
  • ***
  • Posts: 10
USB Communication protocol
« on: February 19, 2011, 03:13:37 pm »
I read much of the chapter 9 standard, and I thought I got it, but some well-respected code I also read seems to disagree with what I see in the standard.  In Table 9-2 (p248 in section 9.3), we see bmRequestType which specifies (among other things) Host-to-device or Device-to-host.  Furthermore, bRequest is a particular request being made of a device "when the [bmRequestType (they really should add this to the standard)] bits are reset to zero".

The code I read recently is the WinUSB firmware and Windows code at http://www.lvr.com/winusb.htm.  It is in cahoots with the USB code from Microchip.  The former seems to use the bRequest field to designate device-to-host or vice versa.  In the firmware, concerning bmRequestType, vide
"usb_device.c" line 1314
"usb_ch9.h" lines 391-392
    et allii...
and for bRequest, see
"main.c" lines 1356-1375
In the host-side application (C#), see
"winusbdevice.cs" line 85 and line 157
(I think that's right...I may have modified this file and got the line numbers off, anyway, it's in the methods "Do_Control_Write_Transfer();" and "Do_Control_Read_Transfer();" and the code says, "setupPacket.Request = 2;" and "setupPacket.Request = 1;".


Please let me know what you think, or if I'm reading this wrong.  What I would like to do is define some custom commands using the bRequest (say, request some action from the device using this parameter), and use the wValue and wIndex as four more bytes of parameter.  If bRequest is the way to get the device to send data vs expect data, then what does the upper bit of bmRequestType mean?  How can I use more than the bottom two bits of bRequest?  Should I just divide the thing in half, and have the first 128 commands be various read commands, and the second 128 be various write commands or something like that?

Thanks for your time.

Jan Axelson

  • Administrator
  • Frequent Contributor
  • *****
  • Posts: 3033
    • Lakeview Research
Re: USB Communication protocol
« Reply #1 on: February 19, 2011, 09:15:37 pm »
Bit 7 of bmRequest specifies the direction of the Data stage's data packet.

bRequest identifies the request.

Typically, the direction of a request's Data stage is always IN or always OUT. So once the device has identified the request, it knows the direction of the Data stage. bmRequest is a way to provide this information without having to know what the request is. For example, if a device ACKs a Setup packet and then determines that the request isn't supported, bmRequest tells the device whether to expect an IN or OUT Data packet to STALL.

For vendor-defined control requests, you can assign any bRequest value to any request you define and you can define wIndex and wValue for the request any way you want.

Jan

Limited_Atonement

  • Member
  • ***
  • Posts: 10
Re: USB Communication protocol
« Reply #2 on: February 22, 2011, 12:49:49 pm »
So, in the example that I cited, bRequest is being used redundantly in the custom protocol?  Rather than using bRequest == 1 means device-to-host (or vice versa), it is equally valid (perhaps more valid) to just check bit seven of bmRequestType, right?

Thanks for your answer.

Jan Axelson

  • Administrator
  • Frequent Contributor
  • *****
  • Posts: 3033
    • Lakeview Research
Re: USB Communication protocol
« Reply #3 on: February 22, 2011, 02:31:23 pm »
bRequest = 1 means the host is sending control request #1 as defined by the USB spec or a class or vendor driver, depending on where the request is directed. If request #1 has a defined direction, device firmware might not bother checking the direction bit in bmRequestType.

If a driver supports only two requests, one in each direction, I suppose device firmware could check only bmRequest to find out which request the host has sent. That would cause problems if the software is ever updated to support more requests, however.

Jan

Bret

  • Frequent Contributor
  • ****
  • Posts: 68
Re: USB Communication protocol
« Reply #4 on: February 22, 2011, 10:46:44 pm »
There are a couple of different "levels" of concern here.  One is how the device responds to a control request, and the other is how the request is issued from the software that is controlling the device to the host driver, which is responsible for processing the transaction.

The host driver needs to know whether the control request has a data stage or not, and if so, which direction and how many bytes the data stage is supposed to have.  Particularly with a vendor-specific control request, there is no way the host driver will know this "automatically".  Either there must be an external protocol that defines the direction and size of the data stage to the host driver (in addition to the memory address where the data is to be stored or retrieved), or bmRequestType AND wLength MUST be complete and correct in the request, even if the device itself doesn't care (because it can determine what it needs solely from bRequest).  A custom device/protocol can do pretty much anything it wants to with bRequest, wValue, and wIndex, but bmRequestType and wLength have to work just like the specs say or you'll get yourself into trouble.

Limited_Atonement

  • Member
  • ***
  • Posts: 10
Re: USB Communication protocol
« Reply #5 on: February 23, 2011, 12:45:06 pm »
Okay, I think all is well and I understand.

Quote
device firmware might not bother checking the direction bit in bmRequestType

I suppose I'm just quibbling about custom protocol practice now, but if the control type defines a direction, you're forfeiting requests.  In the case that you want lots of request types, and you want to pass the two parameters vValue and wIndex, all you have is a BYTE for bmRequestType and a BYTE for bRequest.  You can double the amount of messages you can sent if you rely on bmRequestType bit 7 (direction) so that bRequest 0x00 is a particular request with device-to-host, and a completely different request if bmRequestType specifies host-to-device.

Is this a violation of the conventions?  As I'm writing this, I see that there is almost no way that you could run short on message types (especially since with parameter-less requests, you could specify another two WORDs-worth of different commands, and one WORD with single-parameter requests!).

Thanks again for your time.

Jan Axelson

  • Administrator
  • Frequent Contributor
  • *****
  • Posts: 3033
    • Lakeview Research
Re: USB Communication protocol
« Reply #6 on: February 23, 2011, 12:57:47 pm »
9.3.1 in the USB 2.0 spec says

bmRequestType
This bitmapped field identifies the characteristics of the specific request. In particular, this field identifies
the direction of data transfer in the second phase of the control transfer.

To me that suggests that each request has a single direction for the Data stage.

I don't recall ever seeing a bRequest that supports both directions depending on bmRequestType. The USB spec has Get_Descriptor and Set_Descriptor, Get_Configuration and Set_Configuration, Get_Interface and Set_Interface. HIDs have Get_Report and Set_Report.

Classes that support many different requests tend to use a different transfer type. For example, mass storage uses bulk transfers to send SCSI commands.

Jan

Bret

  • Frequent Contributor
  • ****
  • Posts: 68
Re: USB Communication protocol
« Reply #7 on: February 23, 2011, 03:57:48 pm »
Quote
I don't recall ever seeing a bRequest that supports both directions depending on bmRequestType. The USB spec has Get_Descriptor and Set_Descriptor, Get_Configuration and Set_Configuration, Get_Interface and Set_Interface. HIDs have Get_Report and Set_Report.

I don't recall seeing a real device that ever did that either, and certainly the standard requests separate even pairs of "related" IN's and OUT's with distinct bRequests.  But, I don't think it's a violation of the spec to "reuse" a bRequest number for multiple purposes.  In fact, the design appears to have the intent of requiring the total combination of bmRequestType and bRequest to determine the request, not just one or the other.

Quote
Classes that support many different requests tend to use a different transfer type. For example, mass storage uses bulk transfers to send SCSI commands.

Absolutely correct.  If you're trying to control a device that requires lots of different types/combinations/sizes of data to be sent back and forth, USB control requests would probably be a poor choice, for a number of reasons.