Introduction to basic concepts and protocols of Linux USB

Posted by nutstretch on Fri, 24 Dec 2021 19:34:19 +0100

introduction

   because it is necessary to use the development board equipped with Linux system as a USB slave device (virtual serial port), it is very necessary to popularize the basic concept of USB before using the Gadget driver in Linux kernel. In addition, in the process of USB device driver development, it is also necessary to capture packets of USB devices with the help of BUS Hound tools and analyze the protocol frames received by USB devices.


Basic concepts

1. USB is a master-slave structure:
   a. all USB transmissions are initiated from the USB host;
   B. the USB device does not have the ability to "actively" notify the USB host.
Example: the USB mouse swipes to generate data immediately, but it has no ability to notify the PC to read the data. It can only passively wait for the PC to read it.

2. There are four USB transmission types:
   a. control transmission: reliable and time guaranteed, such as the identification process of USB device
   b. batch transmission: reliable, time is not guaranteed, such as U SB flash disk
   c. interrupt transmission: reliable and real-time, such as USB mouse
   d. real time transmission: unreliable, real-time, such as USB camera

3. USB transmission object: endpoint
   a. we say "read USB flash disk" and "write USB flash disk", which can be subdivided into: write data to endpoint 1 of USB flash disk and read data from endpoint 2 of USB flash disk
   b. except endpoint 0, each endpoint only supports data transmission in one direction;
   c. endpoint 0 is used to control transmission, which can be output or input;
   d. each endpoint has a transmission type and transmission direction;
   e. the endpoint is the basic unit of USB device communication, and all communications are initiated from the endpoint.

4. The input (IN) and output (OUT) in the program are all based on the position of USB host.
Example: for example, the data of the mouse is transferred from the mouse to the PC, and the corresponding endpoint is called "input endpoint"

5. According to the hierarchy of USB protocol stack:
   a. a Host may have one or more devices;
   b. a Device may have one or more interfaces;
  c. an Interface may have one or more endpoints.

6. Main USB controller standards:
  a. OHCI(Open Host Controller Interface)
  b. UHCI(Universal Host Controller Interface)
  c. EHCI( Enhanced Host Controller Interface)
  d. xHCI (eXtensible Host Controller Interface). xHCI supports USB devices of all speeds. The purpose of xHCI is to replace the first three.


Protocol introduction

1. Five common structures for USB Driver Development:
   ① device descriptor is used to describe the general information of USB device. USB device has only one device descriptor. The device descriptor records the USB version number, device type, vid (manufacturer ID), PID (product ID), device serial number, etc.

struct usb_device_descriptor {
  			__u8  bLength;									//  This device descriptor is 18 bytes long
  			__u8  bDescriptorType;				// Descriptor type, 0X01
  			__u16 bcdUSB;									// USB version number, BCD code
  			__u8  bDeviceClass;						// Equipment class
  			__u8  bDeviceSubClass;				// Equipment subclass
  			__u8  bDeviceProtocol;				// Equipment protocol
  			__u8  bMaxPacketSize0;				// Maximum packet length for endpoint 0
  			__u16 idVendor;								// Vendor ID
  			__u16 idProduct;								// Product ID
  			__u16 bcdDevice;							// Equipment version number
  			__u8  iManufacturer;						// Vendor information string descriptor index value
  			__u8  iProduct;									// Product information string descriptor index value
  			__u8  iSerialNumber;					// Product serial number string descriptor index value
  			__u8  bNumConfigurations;		// Number of possible configuration descriptors
} __attribute__ ((packed));

   ② the bNumConfigurations field of the device descriptor defines the number of configuration descriptors of a USB device, and a USB device has at least one configuration descriptor. The configuration descriptor describes the number of interfaces that the device can provide, configuration number, power supply information, etc.

struct usb_config_descriptor {
  			__u8  bLength;							 		// This configuration descriptor is 9 bytes long
  			__u8  bDescriptorType;				// Configuration descriptor type: 0X02
  		
  			__le16 wTotalLength;					// Total length of the entire configuration information (including configuration, interface, endpoint, device class and manufacturer defined descriptor)
  			__u8  bNumInterfaces;					// The number of interfaces supported by this configuration
  			__u8  bConfigurationValue;		// The value of the configuration. A device supports multiple configurations. Different configurations are distinguished by the configuration value.
  			__u8  iConfiguration;						// String index describing this configuration
  			__u8  bmAttributes;						// Properties of this device: 	 D7: reserved 	 D6: self contained power supply 	 D5: remote wake-up 	 D4:0: reserved
  			__u8  bMaxPower;							// Bus current required in this configuration (unit: 2mA)
} __attribute__ ((packed));

   ③ string descriptor is optional. String descriptor is used to describe some information convenient for people to read, such as manufacturer and equipment name. If a device does not have a string descriptor, the index value related to the string in other descriptors must be 0.

struct usb_string_descriptor {
  			__u8  bLength;									// Length of this string descriptor
  			__u8  bDescriptorType;				// String descriptor type, 0X03
  		
  			__le16 wData[1];								/* UTF-16LE encoded */
} __attribute__ ((packed));

④. The configuration descriptor specifies the number of interfaces under the configuration. The configuration can provide one or more interfaces, and the interface descriptor is used to describe the interface properties. The interface descriptor generally records the interface number, the number of endpoints corresponding to the interface, the class described by the interface, etc.

struct usb_interface_descriptor {
			__u8  bLength;									// Length of this interface descriptor, 9 bytes
			__u8  bDescriptorType;				// Descriptor type, 0X04
			
			__u8  bInterfaceNumber;			// Current interface number, starting from 0
			__u8  bAlternateSetting;				// Current interface alternate number
			__u8  bNumEndpoints;				// Number of endpoints for the current interface
			__u8  bInterfaceClass;					// The class to which the current interface belongs
			__u8  bInterfaceSubClass;			// Subclass of the current interface
			__u8  bInterfaceProtocol;			// The protocol used by the current interface
			__u8  iInterface;								// Index value of the current interface string
} __attribute__ ((packed));

⑤. The interface descriptor defines the number of endpoints. The endpoint is the logical interface for data transmission between the device and the host. Except that endpoint 0 is a bidirectional port, other ports are unidirectional. The endpoint descriptor describes the tree transmission type, direction, packet size, endpoint number and other information.

struct usb_endpoint_descriptor {
			__u8  bLength;									// Length of this endpoint descriptor, 7 bytes
			__u8  bDescriptorType;				// Descriptor type, 0X05
		
			__u8  bEndpointAddress;			// Endpoint address and direction: 		 bit3:0: endpoint number 		 bit6:4: reserved, zero. 		 bit7: direction, 0 output endpoint (host to device), 1 input endpoint (device to host)
			__u8  bmAttributes;						// Endpoint attribute, bit1:0 indicates the transmission type: 		 00: control transmission 		 01: synchronous transmission 		 10: Batch transmission 		 11: Interrupt transmission 		 Other bits reserved
			__le16 wMaxPacketSize;				// The maximum packet length that an endpoint can send or receive
			__u8  bInterval;								// Cycle time gap value in endpoint data transmission. This field is invalid for batch transmission and control transmission. For synchronous transmission, this field must be 1ms. For interrupted transmission, this field can be set to 1ms~255ms.
		
			/* NOTE:  these two are _only_ in audio endpoints. */
			/* use USB_DT_ENDPOINT*_SIZE in bLength, not sizeof. */
			__u8  bRefresh;								
			__u8  bSynchAddress;					
} __attribute__ ((packed));

2. USB enumeration:
   after the USB device is connected with the USB host, the host will enumerate the USB device and obtain the descriptor information of the device through enumeration. After obtaining this information, the host will know what kind of driver to load and how to communicate. The USB enumeration process is as follows:
   ① in the first round, when the USB host detects that the USB device is inserted, it will send a bus reset signal to reset the device. After the USB device is reset, the address is 0, and the host sends data to the endpoint 0 of address 0 to request the descriptor of the device. After receiving the request, the device will send the device descriptor to the host according to the requirements of the host. After the host obtains the device descriptor sent by the device, if it is confirmed to be correct, it will return an acknowledgement packet (ACK) to the device.
   ② in the second round, the host resets the device again and enters the address setting stage. The host sends an address setting request packet to the endpoint 0 of address 0. The new device address is included in this packet, so there is no data process. The device enters the status process and waits for the host to request the status to return. After receiving it, the device will send a 0-byte status data packet to the host, indicating that the device has set the address. After receiving the 0-byte status data packet, the host will return an acknowledgement packet (ACK). After receiving the ACK packet sent by the host, the device will use the new device address, and the device will get a unique address.
   ③ in the third round, the host sends a request device descriptor packet to the new device address endpoint 0. This time, the host needs to obtain the whole device descriptor, a total of 18 bytes.
   ④ and are similar to step ③. Next, obtain the configuration descriptor, configuration set, string descriptor, etc.


USB packet capture tool (BUS Hound)

  a convenient USB frame grabbing tool allows us to get twice the result with half the effort in the process of USB driver development. The following is the interface for BUS Hound to grab data frames: