Analysis of several important structural bodies of USB device driver development

Source: Internet
Author: User
Tags bitmask commit time interval port number

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

  

This part of all the structure of the Declaration can be found in the kernel source file usb.h, interested friends can read the source code.

USB devices are complex, but the Linux kernel provides a subsystem called USB core to handle most of the complex work, so this is what is described here as the interface between the driver and the USB core.

In the USB device organization structure, there are four levels of device, configuration (config), interface (interface), and endpoint (endpoint) from top to bottom.
A brief description of these four levels is as follows:
Devices typically have one or more configurations
Configuration often has one or more interfaces
Interfaces typically have one or more settings
The interface does not have or has more than one endpoint


Equipment
It is obvious that an inserted USB device is represented in the kernel using the data structure struct Usb_device to describe the entire USB device. (include/linux/usb.h)

struct Usb_device {
int devnum; Device number, which is the address on the USB bus
Char Devpath [16]; The device ID string used for the message
Enum Usb_device_state State; Device status: Configured, not connected, and so on
Enum Usb_device_speed speed; Device speed: High speed, full speed, low speed, or error
  
struct USB_TT *tt; Processing of transmission information; for low speed, full speed devices and high speed hubs
int ttport; Device port at TT hub
  
unsigned int toggle[2]; One bit for each endpoint, indicating the direction of the end point ([0] = in, [1] = out)
struct Usb_device *parent; Top level Hub pointer
struct Usb_bus *bus; Bus pointer
struct Usb_host_endpoint ep0; Endpoint 0 Data

struct device dev; General Device Interface Data structure
 
struct Usb_device_descriptor descriptor; USB Device Descriptor
struct Usb_host_config *config; All configurations of the device

struct Usb_host_config *actconfig; Device configuration that is activated
struct Usb_host_endpoint *ep_in[16]; Input end Points Group
struct Usb_host_endpoint *ep_out[16]; Output End points Group
  
Char **rawdescriptors; Raw descriptors for each configuration
  
unsigned short bus_ma; Bus current available for use


U8 Portnum; Parent port number
U8 level; Number of layers in the USB hub
  
unsigned can_submit:1; URB can be submitted flag
unsigned discon_suspended:1; Break flag when paused
unsigned persist_enabled:1; Usb_persist Enable flag
unsigned have_langid:1; String_langid Presence Flag
unsigned authorized:1;
unsigned authenticated:1;
unsigned wusb:1; Wireless USB Flag

int string_langid; String Language ID

  
/* static string strings from the device *//devices
Char *product; Product Name
Char *manufacturer; Manufacturer name
Char *serial; Product serial Number
  
struct List_head filelist; The Usbfs file that this device opens

#ifdef Config_usb_device_class
struct device *usb_classdev; USB-Class devices created for USBFS devices accessed by user space
#endif
#ifdef Config_usb_devicefs
struct Dentry *usbfs_dentry; USBFS entrance of the equipment
#endif
  
int maxchild; (if hub) the number of interfaces
struct Usb_device *children[usb_maxchildren];//connected to a sub-device on this hub
int pm_usage_cnt; Auto-pending usage count
U32 quirks;
atomic_t Urbnum; The URB count submitted by this device
  
unsigned long active_duration; Use timings after activation


#ifdef CONFIG_PM//power Management related
struct Delayed_work autosuspend; Auto-suspend delay
struct Work_struct autoresume; (interrupted) automatic wake-up demand
struct Mutex Pm_mutex; PM Mutual Exclusion Lock

 
unsigned long last_busy; Last-Used time
int autosuspend_delay;
unsigned long connect_time; Time of first connection
  
unsigned auto_pm:1; Automatic Suspend/Wake
unsigned do_remote_wakeup:1; Remote wake-up
unsigned reset_resume:1; Use Reset to replace wakeup
unsigned autosuspend_disabled:1; Pending close
unsigned autoresume_disabled:1; Wake-up shutdown
unsigned skip_sys_resume:1; Skip Next system Wake up
#endif
struct Wusb_dev *wusb_dev; (if wireless USB) is connected to a WUSB specific data structure

};


Configuration
A USB device can have multiple configurations and can be converted between them to change the state of the device. For example, a device can download firmware (firmware) to change the state of the device (I feel similar to FPGA or CPLD), then the USB device will switch configuration to complete the work. Only one configuration can be activated at a time. Linux uses struct struct usb_host_config to describe the USB configuration. The USB device drivers We write typically do not need to read or write any values for these structures. You can find descriptions of them in the kernel source file include/linux/usb.h.
struct Usb_host_config {
struct Usb_config_descriptor desc; Configuration descriptor

Char *string; /* string pointer configured (if present) */
struct Usb_interface_assoc_descriptor *intf_assoc[usb_maxiads]; Configuring the interface Joint Description Fu Chinqu
struct Usb_interface *interface[usb_maxinterfaces]; Interface Description Fu Chinqu
struct Usb_interface_cache *intf_cache[usb_maxinterfaces];
unsigned char *extra; /* Additional descriptors */
int Extralen;
};


Interface
The USB endpoint is tied to an interface, and the USB interface handles only one USB logical connection. A USB interface represents a basic function, each USB driver controls an interface. Therefore, a physical hardware device may require more than one driver. This can be seen in the "Halo to Death fart" system, sometimes after inserting a USB device, the system will recognize multiple devices, and install the corresponding multiple drivers.
USB interface can have other settings, it is a different choice of interface parameters. The state of the initialization of the interface is the first setting, with a number of 0. Other settings can control separate endpoints in different ways.

The USB interface is described using the struct usb_interface in the kernel. The USB core transmits it to the USB drive and is controlled by the USB drive for subsequent control.
struct Usb_interface {
struct Usb_host_interface *altsetting; /* contains an array of interface structures for all optional settings available for this interface. Each struct usb_host_interface contains a set of endpoint configurations (that is, the endpoint configuration defined by the struct usb_host_endpoint structure). These interface structures do not have a particular order. */

struct Usb_host_interface *cur_altsetting; /* Pointer to the internal altsetting, indicating the currently active interface configuration */
unsigned num_altsetting; /* Number of selectable settings */

/* If There is a interface association descriptor then it'll list the associated interfaces */
struct Usb_interface_assoc_descriptor *intf_assoc;

    int minor;/* If the USB drive that is bound to this interface uses the USB main device number, this variable contains the secondary device number assigned to the interface by the USB core. This only works after a successful call to Usb_register_dev. Effect. */
   /* The following data is not considered in the driver we write, the system will automatically set the */
    enum usb_interface_condition Condition /* State of the binding */
    unsigned is_active:1;/* The interface are not suspended */
  &NB Sp unsigned sysfs_files_created:1; /* The SYSFS attributes exist */
    unsigned ep_devs_created:1;/* endpoint "devices" exist */
&NBSP ;   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 */
    Unsi Gned 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; /* Union array of all endpoint structures for this interface */
Char *string; /* Interface Description String */
unsigned char *extra; /* Additional descriptors */
int Extralen;
};

Endpoint
The most basic form of USB communication is through a thing called an endpoint. A USB endpoint can transmit data in one direction only (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 viewed as a one-way pipe.

There are 4 different types of USB endpoints, each with different data transfer modes:

Controlling control
Control endpoints are used to control access to different parts of the USB device. Typically used as a configuration device, get device information, send a command to a device, or get a Device status report. These endpoints are usually smaller. Each USB device has a control endpoint called "Endpoint 0", which is used by the USB core to configure the device at plug-in. The USB protocol guarantees that there is always enough bandwidth left to the control endpoint to transmit data to the device.

Interrupt Interrupt
Each time the USB host requests data from the device, the interrupt endpoint transmits a small amount of data at a fixed rate. This is the primary data transfer method for USB keyboards and mice. It also transmits data to the USB device to control the device. It is not usually necessary to transmit large amounts of data. The USB protocol guarantees that there is always enough bandwidth left to the interrupt endpoint to transmit data to the device.

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

Wait-time isochronous
The endpoint also transmits large amounts of data in bulk, but this data is not guaranteed to be delivered. These endpoints are used in devices that can handle data loss and rely more on persisting data flow. such as audio and video devices, and so on.

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

The endpoint is described in the kernel using struct struct usb_host_endpoint, which contains the real endpoint information in another structure: the struct usb_endpoint_descriptor (the endpoint descriptor, which contains all the USB-specific data).
struct Usb_host_endpoint {
struct Usb_endpoint_descriptor desc; Endpoint Descriptor
struct List_head urb_list; Urb to columns 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 for this particular endpoint, this 8-bit data contains the direction of the endpoint, combined with bitmask usb_dir_out and usb_dir_in, to determine the data direction of the endpoint. */

__u8 bmattributes; This is the type of endpoint, the bitmask is as follows

__le16 wmaxpacketsize; /* The maximum number of bytes that the endpoint can process at one time. The driver can send data that is larger than this value to the endpoint, but when it is actually transferred to the device, the data is divided into chunks of wmaxpakcetsize size. For high-speed devices, a high-bandwidth mode can be used to support endpoints by using several additional bits of the high-level portion. */
__u8 Binterval; If the endpoint is a break type, the value is the interval setting for the endpoint, that is, the interval between interrupt requests for the endpoint, in milliseconds

/* Note:these _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 */

Bitmask of #define USB_ENDPOINT_XFERTYPE_MASK 0x03/* bmattributes */
#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 device's representation in SYSFS is also very complex. Physical USB devices (represented by struct usb_device) and a single USB interface (represented by struct usb_interface) are present 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 (representing Usb_device structure)
.
|--3-1:1.0 (mouse corresponding to the usb_interface)
| |--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 uses 2.6.29.4

The USB device driver code communicates via URB and all USB devices. URB with struct URB structure description (include/linux/usb.h).
URB sends or accepts data in an asynchronous manner to a specific endpoint of a particular USB device. A USB device driver can assign multiple URB to an endpoint or reuse a single urb to multiple different endpoints, depending on the needs of the driver. Each endpoint in the device processes a URB queue, so multiple URB can be sent to the same endpoint before the queue is emptied.

A typical life cycle of a URB is as follows:
(1) was created;
(2) A specific endpoint assigned to a particular USB device;
(3) is presented to the USB core;
(4) The USB core is submitted to a specific device specific USB host controller driver;
(5) by the USB host Controller driver processing, and transmission to the device;
(6) After the operation is completed, the USB host controller driver notifies the USB device driver.

URB can also be submitted for its drive to be canceled at any time, and if the device is removed, URB can be canceled by the USB core. URB is dynamically created and contains an internal reference count that allows them to be freed automatically when the last user releases them.

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

struct URB

struct URB {
/* PRIVATE:USB core and host controller only in the URB */
struct Kref kref; /* URB Reference count */
void *hcpriv; /* Private data for host controller */
atomic_t Use_count; /* Current COMMIT count */
Atomic_t reject; /* Commit failure count */
int unlinked; /* Connection Failure code */

/* public:documented fields in the URB so 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 anchored */
struct Usb_anchor *anchor;
struct Usb_device *dev; /* Pointer to the target struct usb_device that the URB will send, which must be initialized by the USB drive 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 to which the URB is to be sent, which must be initialized by the USB drive before the URB is sent to the USB core. Must be generated by the following function */
int status; /* When URB begins processing or processing by the USB core, this variable is set to the current state of Urb. The only time the USB driver can safely access this variable is in the URB end processing routine function. This restriction is to prevent race. For the URB, the success value (0) In this variable only indicates whether the URB has been chained. To obtain the detailed state of the URB, the ISO_FRAME_DESC variable should be checked. */
unsigned int transfer_flags; /* Transfer Settings */
void *transfer_buffer; /* points to 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 properly access this buffer, it must be created using Kmalloc, not in the stack or in static memory. For the control endpoint, this buffer is used for data relay */
dma_addr_t TRANSFER_DMA; /* Buffer for DMA transfer of data to USB devices */
int transfer_buffer_length; /* Transfer_buffer or TRANSFER_DMA variable points to the buffer size. If this is 0, the transmit buffer is not used by the USB core. For an out endpoint, if the endpoint size is smaller than the value specified by this variable, the transmission of the USB device is divided into smaller chunks to properly transmit the data. This large transmission is performed with a continuous USB frame. A large chunk of data is submitted in a URB, and the USB host controller is divided into smaller chunks, which is much faster than sending the small buffers in sequential order */
int actual_length; /* When this URB is complete, the variable is set to the true length of the URB (for out URB) to be sent or (for in URB) to accept the data. This variable must be used instead of URB for in Transfer_buffer_length, because the data received may be more than The whole buffer is small */
unsigned char *setup_packet; /* Pointer to the set packet that controls URB. It is transmitted before the data in the buffer is transmitted (for controlling URB) */
dma_addr_t SETUP_DMA; /* Control URB is used to set the DMA buffer address of the packet, which is transmitted before the data in the normal buffer is transmitted (for controlling URB) */
int start_frame; /* Set or return the initial number of frames (for URB) */
int number_of_packets; /* Specifies the number of equal-time transmit buffers processed by URB (for URB, which must be set before URB is sent to the USB core) */
int interval; The time interval at which the/*urb is polled. Only valid for interrupts or URB. The units of this value vary depending on the speed of the device. For low speed and high speed devices, the unit is a frame, which is equivalent to milliseconds. For other devices, the unit is a micro-frame, which is equivalent to 1/8 milliseconds. This value must be set before the URB is sent to the USB core. */
int error_count; /* URB error count, set by USB core */
void *context; /* Point to a block of data that can be set by the USB drive module. When URB is returned to the drive, it can be used in the end processing routine. */
usb_complete_t complete; /* Ends the processing routine function pointer, which is called by the USB core when the URB is fully transmitted or an error occurs. This function checks this urb and decides to release it or re-submit it to another transmission in the */
struct Usb_iso_packet_descriptor iso_frame_desc[0];
/* (for URB only) The Usb_iso_packet_descriptor struct allows a single urb to define many time-of-day transmissions at once, which is used to collect each individual transmission state */
};

struct Usb_iso_packet_descriptor {
unsigned int offset; /* The packet's data is offset in the transmit buffer (the first byte is 0) */
unsigned int length; /* The packet's transmit buffer size */
unsigned int actual_length; /* Time packet received data length in the transmit buffer */
int status; /* A single, equal-time transfer state of the packet. It can use the same return value as the state variable of the main struct URB struct */
};

This article from 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.