USB Series Two: Read the descriptor of the USB device

Source: Internet
Author: User

In the previous article, we have given the link address of the USB protocol, from this article, we will involve a lot of USB 1.1 content, our guiding ideology is to start with the familiar USB 1.1 protocol, first use off-the-shelf HCD and USBD, directly face the client driver programming, see the results as soon as possible, So that readers have confidence in the development of USB, and then study the programming methods of USBD and HCD. Readers should read the agreement themselves, the details of the agreement in the article, because it will involve a lot of text, can not be explained too much.
1, USB system host side of the software structure
Generally speaking, the textbook or protocol will be the USB host side of the software is said to have three layers, the first layer called the host controller Driver HCD (Driver), the second layer called the USB driver USBD (USB Driver), the third layer is called the client driver ( Client Driver); in fact, what we actually see, often HCD and USBD is done by a program, such as Windows provides HCD and USBD, if you develop a USB device yourself, Only need to develop a client driver on HCD and USBD, Linux is also the same, Linux kernel has provided HCD and USBD, so under Windows and Linux we basically did not develop HCD and USBD necessary, and Linux also provides source code But DOS is not the same, DOS itself does not have any support for USB, so in order to thoroughly play USB under DOS, you need to study HCD, USBD and client drivers.
2, Dosusb introduction
Obviously, HCD and USBD are a little bit more basic, and there are more things to understand, and if we can get around HCD and USBD, it will be much easier to start directly from the client driver. Fortunately we can find a free dos under the USB driver, called DOSUSB, which implements most of the HCD and USBD functions, making us a good helper for USB programming.
DOSUSB has not yet implemented the EHIC driver, which means that USB2.0 is not supported, which is one of the reasons we started with USB 1.1, on the other hand, Since USB2.0 is compatible with USB1.1, you can still use the USB1.1 driver even if you are under USB2.0, but you cannot deliver 480mb/seconds.
Let's introduce Dosusb. Dosusb's official website is as follows:
Http://www.usbdos.net

The latest version of DOGUSB can be downloaded from its official website, and the current version is 1.1.1. or download this version of DOSUSB below at the following URL.

Http://blog.hengch.com/software/dosusb/dosusb.zip

Dosusb can be used free of charge in non-commercial areas, if willing to spend money, can purchase to source code, from its official website of the Forum to see, in September 2006 the author source code price is 1000 euros.

DOSUSB installation is very simple, only need to extract to a certain directory, such as in the C:\DOSUSB directory, please read DOSUSB's own documentation, use is very simple, at the DOS prompt type Dosusb execution.

C:\dosusb>dosusb

By default, DOSUSB uses int 65h as its driving soft interrupt, and if there is a conflict with your system, you can add the parameter/I when running DOSUSB, please read the DOSUSB documentation yourself.

DOSUSB communicates with the client driver via a data structure called URB (USB Request Block), which is very similar to Linux, and the authors refer to the source code under Linux, which is defined in the DOSUSB document as follows:

    struct{BYTE transaction_type; //SET Transaction (Control Transfer) (2DH), input transaction (69h) output transaction (E1H)BYTE Chain_end_flag;//SpareBYTE Dev_add;//Device AddressBYTE End_point;//Endpoint NumberBYTE Error_code;//wrong?BYTE status;//Device StatusWORD Transaction_flags;//SpareWORD Buffer_off;//receive/Send buffer offset addressWORD buffer_seg;//Receive/Send buffer segment addressWORD buffer_length;//receive/Send buffer lengthWORD actual_length;//Maximum length per packet when receiving/sendingWORD Setup_buffer_off;//offset address of the setup_request structureWORD setup_buffer_seg;//segment Address of the SETUP_REQUEST structureWORD Start_frame;//SpareWORD nr_of_packets;//Real-time transfer is initiated when >0WORD Int_interval;//SpareWORD Error_count;//Number of retriesWORD timeout;//SpareWORD Next_urb_off;//SpareWORD next_urb_seg;//Spare} URB//32 bytes

This structure is listed because we will use this structure to interact with the USBD. The definitions of the fields in the structure are described in detail in the DOSUSB documentation. In addition to the alternate fields do not need to fill out, Error_code and status returned by Dosusb, so fill 0 can be, the following will introduce more detailed methods of filling.

In Dosusb's release package, there is a sample directory with many examples, but most of it is written in power Basic, but it still has a good reference value.

3. Some contents of USB 1.1 protocol

The USB protocol defines a set of descriptors for USB devices that describe the intrinsic structure of the device's capabilities and attributes, including standard descriptors (device descriptors, configuration descriptors, interface descriptors, endpoint descriptors, and string descriptors), as well as non-standard descriptors such as class descriptors. According to the protocol, the device descriptor can have a number of configuration descriptors, each configuration descriptor can have several interface descriptors, each interface descriptor can have a number of endpoint descriptors, string descriptors are mainly used to describe some text information, such as the manufacturer name, product name and so on. The purpose of this article is to read out these descriptors.

In fact, the so-called descriptor is a data structure, no matter what descriptor, its first two bytes meaning is the same, the first byte is the length of the descriptor, the second byte is the type of the descriptor.

    • Device Descriptor:
   struct{BYTE blength; //the length of the descriptor, in bytesBYTE bDescriptorType;//Device Descriptor type, 0x01WORD Bcdusb;//USB protocol version supported by the device, BCD codeBYTE Bdeviceclass;//device Class code (assigned by USB-IF)BYTE Bdevicesubclass;//sub-class codeBYTE Bdeviceprotocol;//Protocol CodeBYTE bMaxPacketSize0;//Maximum packet length for endpoint 0 (8,16,32,64 only)WORD Idvendor;//Vendor ID (assigned by usb-if)WORD idproduct;//Product ID (defined by manufacturer)WORD Bcddevice;//Device Release number (BCD code)BYTE imanufacture;//index value of the string descriptor that describes the vendor informationBYTE iproduct;//index value of the string descriptor that describes the product informationBYTE Iserialnumber;//the index value of the string descriptor that describes the device serial number informationBYTE bnumconfigurations;//The number of possible configuration descriptors} device_descriptor
    • Config descriptor (configuration descriptor)
  struct{BYTE blength; //the length of the descriptor, in bytesBYTE bDescriptorType;//configuration descriptor type, 0x02WORD wtotallength;//The total length of the configuration informationBYTE bnuminterfaces;//The number of interfaces supported by this configurationBYTE Bconfigurationvalue;//selected by the setcongiguration () request as a parameterBYTE bconfiguration;//The index value that describes the string descriptor for the configurationBYTE bmattributes;//Configuration FeaturesBYTE Maxpower;//The bus power consumption in this configuration is a unit of 2mA}configuration_descriptor;

Bmattributes:b7: Standby, B6: Self-powered, B5: Remote wake-up, b4--b0: Standby

In addition, all descriptors under this configuration can be read out when the configuration descriptor is read, the total length of these descriptors is the value of the Wtotallength field, and after all the descriptors are read out, they are split in one place.

    • Interface Descriptor (Interface descriptor):
    struct{BYTE blength; //the length of the descriptor, in bytesBYTE bDescriptorType;//interface Descriptor type, 0x04BYTE Binterfacenumber;//connection number, starting from 0BYTE balternatesetting;//the index value of the optional setting.BYTE bnumendpoints;//the number of endpoints for this interface. BYTE Binterfaceclass;//Interface class encoding (assigned by USB-IF)BYTE Binterfacesubclass;//Interface Subclass encoding (assigned by USB-IF)BYTE Binterfaceprotocol;//Protocol code (assigned by USB-IF)BYTE IInterface;//The index value that describes the string descriptor for the interface}interface_descriptor;

The BINTERFACECLASS:USB protocol divides different interfaces into different classes according to functions, as follows:

1: Audio class, 2:CDC control class, 3: Man-Machine Interface Class (HID), 5: Physical class, 6: Image class, 7: Printer class, 8: Big Data storage class, 9: Hub class, 10:CDC data class, 11: Smart card class, 13: Security class, 220: Diagnostic device class, 224: Wireless Control class, 254: Specific application class, 255 manufacturer-defined device.

    • Endpoint Descriptor (Endpoint descriptor):
 struct   {BYTE blength;  //  byte bdescripto    Rtype; //       end descriptor type, 0x05    BYTE bendpointaddress; //       endpoint address        BYTE bmattributes; //           WORD wmaxpacketsize; //       The maximum datagram length received/sent.           BYTE Binterval; //     }endpoint_descriptor; 

Bmattributes:bit 1:0--Transfer Type, 00 = Control transmission, 01= real-time transmission, 10 = bulk transfer, 11 = interrupt transfer; all other bits are reserved.

    • string descriptors (String descriptor):
    struct {      BYTE    blength;             // the length of the descriptor, in bytes      BYTE    bDescriptorType;    // string Descriptor type, 0x03      Char    Bstring[];          // Unicode-encoded string    } String_descriptor;
    • USB command Requests (USB DEVICE request)

In order to better coordinate the data communication between the USB host and the device, the USB specification defines a set of command requests to complete the unified control of all USB devices on the bus by the host, and the USB command request is made in a uniform format with the following structure:

    struct {      BYTE  bmrequesttype;   // Request Type      BYTE  brequest;       // Encoding of the command request      WORD  Wvalue;         // Different commands, different meanings      WORD  Windex;         //       WORD  wlength;        // If there is a data stage, this field is the number of bytes of data    } Setup_request;

This is the structure behind the instructions we make to the device. As a command request to read the USB device descriptor that we are going to use in this article, the fields of this structure are filled in as follows.

bmrequesttype:b7--data transmission direction, 0 = host to device, 1 = device to host, type of b6:5--command, 0= standard command, 1 = Class command, 2= vendor-supplied command, 3 = reserved; b4:0--Receive object, 0 = device, 1= interface, 2 = endpoint, 3 = Other. We send out the command to get the descriptor, the data transmission direction is the device to the host, the standard command, the receiving object is the device, so the field is filled 0x80.

Brequest: The standard command is encoded as follows,

get_status=0; clear_feature=1; set_feature=3; set_address=5;get_descriptor=6; set_descriptor=7; get_configuration=8; set_configuration=9; get_interface=10; set_interface=11; Synch_frame=12. Our order is get_descriptor, so we should fill in 6.

Wvalue: High byte representation descriptor type, 0x01= device descriptor, 0x02= configuration descriptor, 0x03= string descriptor, 0x04= interface descriptor, 0x05= endpoint descriptor, 0x29= Hub class descriptor, 0x21= Human Interface class descriptor, 0xff= A vendor-defined descriptor.

A low-byte representation of the index value that represents the descriptor. Therefore, when the device descriptor is read, the field value is 0x100, and when the read configuration descriptor is, it should be 0x03yy, where yy is the index value of the descriptor.

Windex: When reading the string descriptor, fill in the 0x0409, indicate that you want to get the English string, and other cases 0.

Wlength: Data length, generally should be filled in, the first byte of the descriptor, blength. Since we do not know the actual length of the descriptor when we read it, it is common practice to read 8 bytes First and then reread the complete descriptor again based on the value of the first byte blength; Note that when the configuration descriptor is read 8 bytes of money, You should use the value of the Wtotallength field as the length to read all the descriptors associated with the configuration.

4. Read the Device Descriptor sample program

According to the custom of our article, almost every article has an example program, this article is no exception, the sample program of this article please download at the following address:

Http://blog.hengch.com/source/usbview.zip

The program is written in C + +, compiled under DJGPP, so is the code in the 32-bit protection mode, it is important to note that the DOSUSB is the driver in real mode, so in the application of memory block to apply 1M Real mode can read memory, otherwise, the use of int 65h when calling Dosusb, there must be a problem.

With 4 header files, public.h defines some handy data types, such as Byte char,word for short int and so on, so you don't have to pay much attention to it. The functions and data structures required to invoke DOS interrupts are defined in x86int.h, until they are used; a DOS_MEM class is defined in dosmem.h, primarily to make it easier to request and use DOS memory blocks in protected mode, and to know how to do so. To be able to understand the meaning of the program. Usb.h defines all the constants associated with the USB protocol, which correspond to the various data structures described earlier, and because we are using DOS memory in protected mode, it is a bit of a hassle to map a block of memory to a data structure, and reading the individual fields depends primarily on the constants defined in Usb.h.

Main procedures in the usbview.cc, the main ideas are as follows:

    • The address of the USB device is from 1--127, so we do a loop from 1--127 and read the USB device descriptor one at a-until the "illegal address" appears.
    • Each USB device has only one device descriptor, so we start by reading the device descriptor under an address.
    • At first we didn't know the length of the device descriptor, even though we knew it was 18 characters long, but we still don't know the length of the packet allowed by endpoint 0 (the BMaxPacketSize0 field in the device descriptor), but we know that the minimum value of the packet length is 8, so we first read the 8-byte device descriptor.
    • After we get the 8-character device descriptor, we can get the length of the descriptor and the packet length of endpoint 0, and in all subsequent commands, this value is always filled in the Actual_length field of the URB structure.
    • Buffer is used to store the descriptor returned by the USBD, and it is recommended to initialize it before use, all clear 0.
    • To issue a command request to the device, you need to fill in the setup_request structure, as mentioned before, Bmrequesttype=0x80,brequest=6, the two fields are always the same; we are now reading the device descriptor, so wvalue= 0x100,windex=0,wlength fills 8 on the first call and fills in the Returned Blength field (which should be 18) when the second call is made.
    • After the buffer and setup_request are ready, we need to fill in URB and interact with DOSUSB; The read descriptor is a control transmission, so transaction=0x2d (followed by 0x2D); Dev_add fill in the loop variable mentioned above; end_ Point=0, because we are always on endpoint 0 (see USB protocol), Buffer_off and buffer_seg respectively fill in the buffer of the cheap address and segment address; Setup_buffer_off and setup_buffer_seg respectively fill in the front setup_ The offset address and segment address of the request structure, and the wlength in the same setup_request structure can also be set between the maximum length of wlength and Buferr, if the maximum length of the buffer is less than wlength, buffer_length We can only fill in the maximum length of the buffer, but in this case we will not get the full descriptor; Actual_length fills 8 on the first call, and then fills in the Returned BMaxPacketsize0 field, and the other fields are 0.
    • Let Ds:dx point to the URB structure just completed, call the soft interrupt 65H,DOSUSB will handle the following things for you.
    • If normal, Error_code should return 0, if not 0, meaning the following:
      The illegal device address, 2--internal error, 3--illegal transation_type field, 4--illegal buffer length.
    • If normal, the Status field should be 0, the field is the state byte returned by the USB controller, and different controllers (OHCI or UHCI) return different values.
    • When we get the device descriptor, if the Imanufacturer field in the device descriptor is not 0, we can get the corresponding string descriptor based on this value, which shows the factory information, note that the string descriptor is Unicode encoding, for ASCII, It is a asscii code with an ASCII 0 composition, the same as we can get product information and serial number information.
    • When we get the device descriptor, we can know how many configurations are on the device (bnumconfigurations in the device descriptor), and then get all the configuration descriptors and all the descriptors under their configuration through a loop.
    • The method of reading the configuration descriptor is much the same as reading the device descriptor, which is to read 8 bytes First, then read all the descriptor contents according to the contents of the return, to be aware that, in fact, we cannot get the interface descriptor and the endpoint descriptor separately, the only way is to read the descriptor of a configuration, So the Wlength field in the setup_request structure must be consistent with the Wtotallength value returned in the configuration descriptor.
    • The rest of the story is how to show the descriptors we get, which I think is not a difficult thing for every reader.

USB Series Two: Read the descriptor of the USB device

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.