Analysis on several important structures of USB driver development

Source: Internet
Author: User

This article from the csdn blog, reproduced please indicate the source: http://blog.csdn.net/aaa6695798/archive/2009/11/06/4776202.aspx

  

All struct declarations can be found in the kernel source file USB. H. If you are interested, read the source code.

 

USB devices are actually complicated, but the Linux Kernel provides a subsystem called USB core to handle most of the complicated work. Therefore, the interface between the driver and USB core is described here.

In the USB device organization structure, there are four layers: device, config, interface, and endpoint.
A brief description of these four layers is as follows:
A device usually has one or more configurations.
Configuration often has one or more interfaces
An interface usually has one or more settings.
The interface does not have or has more than one endpoint

Device
It is obvious that a USB device is inserted, and the data structure struct usb_device is used in the kernel to describe the entire USB device. (Include/Linux/USB. h)

Struct usb_device {
Int devnum; // The device number, which is the address of the USB bus.
Char devpath [16]; // The device ID string used for the message
Enum usb_device_state state; // device status: configured, not connected, etc.
Enum usb_device_speed speed; // device speed: high speed, full speed, low speed, or incorrect
  
Struct usb_tt * tt; // process transmitter information; used for low-speed, full-speed devices, and high-speed hub
Int ttport; // The device port at the TT hub.
  
Unsigned int toggle [2]; // occupies one position for each endpoint, indicating the direction of the endpoint ([0] = In, [1] = out)
Struct usb_device * parent; // The upper-level hub pointer
Struct usb_bus * bus; // bus pointer
Struct usb_host_endpoint ep0; // endpoint 0 Data

Struct device dev; // data structure of common device Interfaces
 
Struct usb_device_descriptor descriptor; // USB device descriptor
Struct usb_host_config * config; // All configurations of the device

Struct usb_host_config * actconfig; // configure the activated device
Struct usb_host_endpoint * ep_in [16]; // input the endpoint Array
Struct usb_host_endpoint * ep_out [16]; // output endpoint Array
  
Char ** rawdescriptors; // raw descriptor for each configuration
  
Unsigned short bus_ma; // available bus current

U8 portnum; // The parent port number.
U8 level; // Number of USB hub Layers
  
Unsigned can_submit: 1; // the flag that can be submitted by urb.
Unsigned discon_suincluded: 1; // indicates the disconnection during suspension.
Unsigned persist_enabled: 1; // usb_persist enable flag
Unsigned have_langid: 1; // string_langid flag
Unsigned authorized: 1;
Unsigned authenticated: 1;
Unsigned WUSB: 1; // wireless USB flag

Int string_langid; // string language ID

  
/* Static strings from the device * // static string of the device
Char * product; // Product Name
Char * manufacturer; // vendor name
Char * serial; // product serial number
  
Struct list_head filelist; // The usbfs file opened by this device

# Ifdef config_usb_device_class
Struct device * usb_classdev; // a USB device created for the usb fs device accessed by the user space
# Endif
# Ifdef config_usb_devicefs
Struct dentry * usbfs_dentry; // usbfs entry of the device
# Endif
  
Int maxchild; // number of (if it is a hub) interfaces
Struct usb_device * Children [usb_maxchildren]; // The Sub-device connected to the hub.
Int pm_usage_cnt; // use count for automatic suspension
U32 quirks;
Atomic_t urbnum; // The urb count submitted by this device
  
Unsigned long active_duration; // use timing after activation

# Ifdef config_pm // related to power management
Struct delayed_work autosuspend; // automatic suspension Delay
Struct work_struct autoresume; // (interrupted) Automatic wake-up request
Struct mutex pm_mutex; // The mutex of the PM

 
Unsigned long last_busy; // The Last Time used.
Int autosuspend_delay;
Unsigned long connect_time; // time of the first connection
  
Unsigned auto_pm: 1; // automatic suspension/Wakeup
Unsigned do_remote_wakeup: 1; // remote Wakeup
Unsigned reset_resume: 1; // use reset to replace Wakeup
Unsigned autosuspend_disabled: 1; // suspend disabled
Unsigned autoresume_disabled: 1; // wake up disabled
Unsigned skip_sys_resume: 1; // skip the next system wake-up request
# Endif
Struct wusb_dev * wusb_dev; // (if it is a wireless USB) connect to the WUSB-specific data structure

};
 

Configuration
A USB device can have multiple configurations and can be switched between them to change the status of the device. For example, if a device can change the Usage Status of the device by downloading the firmware (firmware) (I think it is similar to FPGA or CPLD), the USB device must switch the configuration to complete this task. Only one configuration can be activated at a time. In Linux, the structure struct usb_host_config is used to describe the USB configuration. The USB driver we write usually does not need to read or write any value of these structures. You can find the descriptions in the kernel source code file include/Linux/USB. h.
Struct usb_host_config {
Struct usb_config_descriptor DESC; // configure the descriptor

Char * string;/* string pointer configured (if any )*/
Struct usb_interface_assoc_descriptor * intf_assoc [usb_maxiads]; // linked list of configured Interfaces
Struct usb_interface * interface [usb_maxinterfaces]; // interface descriptor linked list
Struct usb_interface_cache * intf_cache [usb_maxinterfaces];
Unsigned char * extra;/* extra descriptor */
Int extralen;
};
 

Interface
The USB endpoint is bound as an interface, and the USB interface only processes one type of USB logical connection. A usb interface represents a basic function, and each USB driver controls an interface. Therefore, a physical hardware device may need more than one driver. This can be seen in the "Dizzy fart" system. Sometimes, after a USB device is inserted, the system identifies multiple devices and installs multiple drivers.
The USB interface can have other settings, which are different options for interface parameters. The interface initialization status is the first setting, numbered 0. Other settings can control independent endpoints in different ways.

The USB interface is described using struct usb_interface in the kernel. The USB core transmits it to the USB driver, and the USB driver is responsible for subsequent control.
Struct usb_interface {
Struct usb_host_interface * altsetting;/* contains an array of all interface structures available for this interface. Each struct usb_host_interface contains an endpoint configuration defined by the struct usb_host_endpoint structure. These interface structures have no special order. */

Struct usb_host_interface * cur_altsetting;/* points to the internal pointer of altsetting, indicating the current interface configuration */
Unsigned num_altsetting;/* Number of optional settings */

/* If there is an interface Association descriptor then it will list the associated interfaces */
Struct usb_interface_assoc_descriptor * intf_assoc;

Int minor;/* If the USB driver bound to this interface uses the USB master device number, this variable contains the sub-device number allocated to the interface by the USB core. this is only valid after a successful call of usb_register_dev. */
/* The following data should not be considered in the driver we write. The system will automatically set */
Enum usb_interface_condition condition;/* state of binding */
Unsigned is_active: 1;/* the interface is not suincluded */
Unsigned sysfs_files_created: 1;/* The sysfs attributes exist */
Unsigned ep_devs_created: 1;/* endpoint "devices" exist */
Unsigned unregistering: 1;/* unregistration is in progress */
Unsigned needs_remote_wakeup: 1;/* driver requires remote wakeup */
Unsigned needs_altsetting0: 1;/* switch to altsetting 0 is pending */
Unsigned needs_binding: 1;/* Needs delayed unbind/rebind */
Unsigned reset_running: 1;

Struct device dev;/* interface-specific device information */
Struct device * usb_dev;
Int pm_usage_cnt;/* usage counter for autosuspend */
Struct work_struct reset_ws;/* For resets in atomic context */
};

Struct usb_host_interface {
Struct usb_interface_descriptor DESC; // interface Descriptor

Struct usb_host_endpoint * endpoint;/* the Union array of all endpoint struct of this interface */
Char * string;/* interface description string */
Unsigned char * extra;/* extra descriptor */
Int extralen;
};
 

 

Endpoint
The most basic form of USB communication is through something called an endpoint. A usb endpoint can only transmit data to one direction (from the host to the device (called the output endpoint) or from the device to the host (called the input endpoint )). An endpoint can be considered as a one-way pipeline.

A usb endpoint has four different types of data transmission methods:

Control
The control endpoint is used to control access to different parts of USB devices. It is usually used to configure devices, obtain device information, send commands to devices, or obtain device status reports. These endpoints are usually small. Each USB device has a control endpoint called "endpoint 0", which is used by the USB core to configure the device during insertion. The USB protocol ensures that there is always enough bandwidth for the control endpoint to transmit data to the device.

Interrupt interrupt
Each time a USB host requests data from a device, the interrupt endpoint transmits a small amount of data at a fixed rate. This is the main data transfer method for USB keyboard and mouse. It is also used to transmit data to USB devices to control devices. It is usually not used to transmit a large amount of data. The USB protocol ensures that there is always enough bandwidth left for the interrupt endpoint to transmit data to the device.

Bulk
Batch endpoints are used to transmit large amounts of data. These endpoints are often much larger than the interrupt endpoints. They are generally used to prevent any data loss. The USB protocol does not guarantee that the transmission is completed within a specific time range. If there is not enough space on the bus to send the entire bulk package, it is divided into multiple packages for transmission. These endpoints are generally used on printers, USB mass storage, and USB network devices.

Isochronous
The endpoint also transmits a large amount of data in batches, but this data cannot be delivered. These endpoints are used on devices that can process data loss and are more dependent on continuous data streams. Such as audio and video devices.

Control and batch endpoints are used for asynchronous data transmission, while interrupt and synchronization endpoints are periodic. This means that these endpoints are set to continuously transmit data at a fixed time, and the USB core reserves the corresponding bandwidth for them.

The endpoint is described in the kernel using the structure struct usb_host_endpoint. The actual endpoint information contained in the endpoint is in another structure: struct usb_endpoint_descriptor (the endpoint descriptor, containing all USB-specific data ).
Struct usb_host_endpoint {
Struct usb_endpoint_descriptor DESC; // endpoint Descriptor
Struct list_head urb_list; // The urb column of this endpoint, maintained by the USB core
Void * hcpriv;
Struct ep_device * ep_dev;/* For sysfs info */
Unsigned char * extra;/* extra descriptors */
Int extralen;
Int enabled;
};

/*-------------------------------------------------------------------------*/

/* Usb_dt_endpoint: endpoint descriptor */
Struct usb_endpoint_descriptor {
_ U8 blength;
_ U8 bdescriptortype;

_ U8 bendpointaddress;/* the USB address of the specific endpoint. The 8-bit data includes the direction of the endpoint. The data direction of the endpoint is determined based on the bmask usb_dir_out and usb_dir_in. */

_ U8 bmattributes; // This is the type of the endpoint. The bitmask is as follows:

_ Le16 wmaxpacketsize;/* Maximum number of bytes that the endpoint can process at a time. The driver can send data larger than this value to the endpoint, but when it is actually sent to the device, the data will be divided into wmaxpakcetsize blocks. For high-speed devices, several extra bits are used to support the high-bandwidth mode of the endpoint. */
_ U8 binterval; // If the endpoint is of the interrupt type, this value is the interval setting of the endpoint, that is, the interval between the interrupt requests of the endpoint, in milliseconds

/* Note: These two are _ only _ in audio endpoints .*/
/* Use usb_dt_endpoint * _ size in blength, not sizeof .*/
_ U8 brefresh;
_ U8 bsynchaddress;
} _ Attribute _ (packed ));

# Define usb_dt_endpoint_size 7
# Define usb_dt_endpoint_audio_size 9/* audio extension */

/*
* Endpoints
*/
# Define usb_endpoint_number_mask 0x0f/* In bendpointaddress endpoint USB Address Mask */
# Define usb_endpoint_dir_mask 0x80/* In bendpointaddress data direction mask */

# Define usb_dir_out 0/* To device */
# Define usb_dir_in 0x80/* to host */

# Define usb_endpoint_xfertype_mask 0x03/* bmattributes bit mask */
# Define usb_endpoint_xfer_control 0
# Define usb_endpoint_xfer_isoc 1
# Define usb_endpoint_xfer_bulk 2
# Define usb_endpoint_xfer_int 3
# Define usb_endpoint_max_adjustable 0x80
/*-------------------------------------------------------------------------*/
 

 

USB and sysfs
Because of the complexity of a single USB physical device, the representation of the device in sysfs is also very complex. Both the physical USB device (represented by struct usb_device) and a single USB interface (represented by struct usb_interface) appear in sysfs as a single device because both structures contain a struct device structure. The following is the directory tree of My USB mouse in sysfs:

/Sys/devices/pci0000: 00/0000: 00: 1A. 0/usb3/3-1 (indicating the usb_device structure)
.
| -- 3-. 0 (USB _ interface corresponding to the mouse)
| -- 0003: 046d: c018.0003
| -- Driver->.../../bus/HID/Drivers/generic-USB
| -- Power
| '-- Wakeup
| -- Subsystem->.../../bus/hid
| '-- Uevent
| -- Balternatesetting
| -- Binterfaceclass
| -- Binterfacenumber
| -- Binterfaceprotocol
| -- Binterfacesubclass
| -- Bnumendpoints
| -- Driver->.../../bus/USB/Drivers/usbhid
| -- Ep_81-

USB urb (USB request block)
Kernel 2.6.29.4

The USB device driver code communicates with all USB devices through urb. Urb uses the struct urb structure description (include/Linux/USB. h ).
Urb sends or receives data asynchronously from a specific endpoint of the same USB device. A USB device driver can allocate multiple URBS to one endpoint or reuse a single urb to multiple different endpoints Based on the driver's needs. Each endpoint in the device processes an urb queue, So multiple URBS can be sent to the same endpoint before the queue is cleared.

The typical lifecycle of an urb is as follows:
(1) created;
(2) is allocated to a specific endpoint of a specific USB device;
(3) submitted to the USB core;
(4) The driver is submitted by the USB core to a specific USB host controller of a specific device;
(5) processed by the USB Host Controller and transmitted to the device;
(6) After the above operations are completed, the USB host controller driver notifies the USB device driver.
 
Urb can also be canceled at any time by the submitted drive; if the device is removed, urb can be canceled by the USB core. Urb is dynamically created and contains an internal reference count so that they can be automatically released when the last user releases them.

--------------------------------------------------------------------------------

Struct urb
 
Struct urb {
/* Private: USB core and host controller only fields in the urb */
Struct kref;/* urb reference count */
Void * hcpriv;/* private data of the Host Controller */
Atomic_t use_count;/* Current submitted count */
Atomic_t reject;/* Submission failure count */
Int unlinked;/* connection failure code */

/* Public: incluented fields in the urb that can be used by drivers */
Struct list_head urb_list;/* List head for use by the urb's
* Current Owner */
Struct list_head anchor_list;/* The urb may be anchored */
Struct usb_anchor * anchor;
Struct usb_device * dev;/* pointer to the target struct usb_device sent by the urb. This variable must be initialized by the USB driver before the urb is sent to the USB core .*/
Struct usb_host_endpoint * EP;/* (internal) pointer to endpoint */
Unsigned int pipe;/* the endpoint message of the specific struct usb_device that the urb sends. This variable must be initialized by the USB driver before the urb is sent to the USB core. must be generated by the following function */
Int status;/* When urb starts processing or processing by the USB core, this variable is set to the current status of urb. the only time that the USB driver can safely access this variable is in the urb end processing routine function. this restriction is used to prevent competition. for a time-like urb, the success value (0) in this variable only indicates whether the urb has been dechained. to obtain the detailed status of the hour urb, check the iso_frame_desc variable. */
Unsigned int transfer_flags;/* transmission settings */
Void * transfer_buffer;/* indicates the buffer pointer used to send data to the device (Out urb) or receive data (in urb) from the device. In order for the host controller driver to correctly access this buffer, it must be created using the kmalloc call, not in the stack or static memory. For the control endpoint, this buffer is used for data transfer */
Dma_addr_t transfer_dma;/* used to transmit data to the buffer zone of the USB device in DMA mode */
Int transfer_buffer_length;/* the size of the buffer to which the transfer_buffer or transfer_dma variable points. If this is 0, the transfer buffer is not used by the USB core. For an out endpoint, if the size of this endpoint is smaller than the value specified by this variable, the transmission of this USB device will be divided into smaller blocks to transmit data correctly. This large transfer is performed with consecutive USB frames. Submit a large piece of data in an urb and divide the USB host controller into smaller blocks, which is much faster than sending small buffers in a sequential order */
Int actual_length;/* When the urb is complete, the variable is set to the actual length of the data sent by the urb (for out urb) or received (for in urb. for in urb, this variable must be used instead of transfer_buffer_length, because the received data may be smaller than the entire buffer */
Unsigned char * setup_packet;/* points to the set packet pointer that controls the urb. It is transmitted (used to control the urb) before the data in the Transfer Buffer )*/
Dma_addr_t setup_dma;/* urb is used to set the DMA buffer address of the data packet. It is transferred (used to control urb) before transmitting data in the common buffer )*/
Int start_frame;/* set or return the initial number of frames (used for equal hour urb )*/
Int number_of_packets;/* specify the number of transmission buffers when urb processes the same time (used for equal time urb, which must be set before urb is sent to the USB core )*/
Int interval;/* the time interval when urb is polling. valid only for the interrupted or equal hour urb. the unit of this value varies according to the device speed. for low-speed and high-speed devices, the unit is frame, which is equivalent to milliseconds. for other devices, the unit is microframe, equivalent to 1/8 milliseconds. this value must be set before urb is sent to the USB core. */
Int error_count;/* indicates the urb error count, which is set by the USB core */
Void * context;/* points to a data block that can be set by the USB driver module. When urb is returned to the driver, it can be used in the end processing routine .*/
Usb_complete_t complete;/* function pointer of the End Processing routine. When urb is completely transferred or an error occurs, it will be called by the USB core. this function checks this urb and decides to release it or resubmit it to another transmission */
Struct usb_iso_packet_descriptor iso_frame_desc [0];
/* (Only used for equal-time urb) The usb_iso_packet_descriptor struct allows a single urb to define multiple equal-time transmissions at a time. It is used to collect each individual transmission status */
};

Struct usb_iso_packet_descriptor {
Unsigned int offset;/* the offset of the data packet in the transmission buffer (the first byte is 0 )*/
Unsigned int length;/* the transmission buffer size of the data packet */
Unsigned int actual_length;/* When the packet receives the Data Length in the transmission buffer */
Int status;/* the transmission status of a single packet. It can take the same return value as the state variable of the main struct urb struct */
};

This article from the csdn blog, reproduced please indicate the source: http://blog.csdn.net/aaa6695798/archive/2009/11/06/4776202.aspx

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.