USB bus is a typical hot-swap bus standard. Because of its excellent performance, it has almost become the standard of current large and small devices.
USB drivers can be divided into three categories: the driver of SoC's USB controller, the driver of host USB device and the driver of USB Gadget on device. Usually, for the standardized device like USB, the driver of host controller has been written by the kernel. The driver of Gadget on device usually only runs firmware program instead of Linux, so the main task of driver engineer is to write host. USB device driver.
USB Subsystem Framework
The following chart shows the framework of the USB subsystem in Linux. Like i2c, the USB subsystem can be divided into three layers: ** Device Driver Layer - USB Core - Controller Driver Layer*
As a hot-swap bus, the biggest difference between USB and non-hot-swap bus is that the bus can not know the information of the device beforehand and when the device is inserted or pulled out, so it can not use any form to write the device information into the kernel beforehand.
In order to solve the problem of device identification caused by hot plug-in, USB bus acquires the device information of a USB device connected to the bus by enumeration, a device described step by step by step by device - > config - > interface - > endpoint. Based on the idea of separation, a set of structure is designed in the USB subsystem to describe the device information of these dimensions. In contrast, I2C bus only needs An i2c_client can describe a device.
All communication on the USB bus is initiated by the host, so in essence, USB is conducted by polling. USB bus will use polling method to continuously detect whether there is device access on the bus, and if there is device access to the corresponding D+D - there will be level changes. Then the bus will communicate with the device according to the Protocol stipulated by USB. The device will send the device information stored in itself to the host in turn. The host will organize the information according to the four-tier model. Reporting to the kernel, the USB subsystem in the kernel matches the corresponding driver. The USB device driver is oriented to the level of interface information.
As a highly standardized device, although USB itself is very complex, the kernel has done a lot of work for us. The following common device drivers have been implemented in the kernel. In many cases, the difficulty of driving depends not on the complexity of the device, but on the degree of standardization.
- Audio equipment class
- Communications Equipment Class
- HID device class
- Display Device Class
- mass storage class
- Power supply equipment category
- Printing Equipment Class
- Hub Equipment Class
A Brief Introduction to Core Structure and Method
Core structure
Based on the idea of separation, the USB subsystem also provides a structure for describing a USB device. However, based on the USB protocol, a complete description of a USB device information requires nine structures. Among these structures, the first four are used to describe the hardware information of a USB device, i.e. the information of the device itself, which is written to the device eeprom, and can be seen in any USB host. Information can be viewed by using lsusb-v command; the last five software information describing a USB device, that is, besides hardware information, Linux encapsulates some information in order to manage a USB device, which is OS-specific information; the relationship between hardware information and software information of USB device is similar to hardware interrupt and kernel interrupt in interrupt subsystem, but more complex.
- usb_device_descriptor describes device information of a USB device
- usb_config_descriptor describes the config information of a device
- usb_interface_descriptor describes the interface information of a config
usb_endpoint_descriptor describes the endpoint information of an interface
- Usb_device describes the software information of a USB device, including usb_device_descriptor
- urb_host_config describes the software information of a USB device config, including usb_config_descriptor
- usb_interface describes an interface information
- usb_host_interface describes the settings of an interface, including usb_interface_descriptor, for which we write drivers
usb_host_endpoint describes the endpoint information of an interface, including usb_endpoint_descriptor, which is the smallest unit of USB communication. We read and write a device for an endpoint.
- usb_driver describes a USB device driver, which is the core structure of USB device driver development.
- usb_driver_id is used to identify a USB device. Its instance id_table is a domain of usb_driver. Because of the complexity of describing a device in USB bus, there are many ways to construct such an object.
- urb (usb request block) is the data carrier in the process of USB communication, which is equivalent to i2c_msg in I2C subsystem and sk_buff in network device driver.
usb_hcd Describes a USB Controller Driver in SoC
Core method
- usb_fill_int_urb is the API of registering urb and the core data encapsulation of the whole USB communication.
Detailed description of core structure and methodology
First of all, the nine structures describing device information, in which the hardware information is independent, are defined in the kernel "include/uapi/linux/usbch9.h", so I will not paste the code.
usb_device_descriptor
//include/uapi/linux/usbch9.h 258 struct usb_device_descriptor { 259 __u8 bLength; 260 __u8 bDescriptorType; 262 __le16 bcdUSB; 263 __u8 bDeviceClass; 264 __u8 bDeviceSubClass; 265 __u8 bDeviceProtocol; 266 __u8 bMaxPacketSize0; 267 __le16 idVendor; 268 __le16 idProduct; 269 __le16 bcdDevice; 270 __u8 iManufacturer; 271 __u8 iProduct; 272 __u8 iSerialNumber; 273 __u8 bNumConfigurations; 274 } __attribute__ ((packed));
struct usb_device_descriptor
--263-->Equipment category
--264-->Device sub class
--265-->communication protocol
--267-->seller
--268-->product ID
--272-->serial number
usb_config_descriptor
//include/uapi/linux/usbch9.h 314 struct usb_config_descriptor { 315 __u8 bLength; 316 __u8 bDescriptorType; 317 318 __le16 wTotalLength; 319 __u8 bNumInterfaces; 320 __u8 bConfigurationValue; 321 __u8 iConfiguration; 322 __u8 bmAttributes; 323 __u8 bMaxPower; 324 } __attribute__ ((packed));
usb_interface_descriptor
//include/uapi/linux/usbch9.h 351 struct usb_interface_descriptor { 352 __u8 bLength; 353 __u8 bDescriptorType; 354 355 __u8 bInterfaceNumber; 356 __u8 bAlternateSetting; 357 __u8 bNumEndpoints; 358 __u8 bInterfaceClass; 359 __u8 bInterfaceSubClass; 360 __u8 bInterfaceProtocol; 361 __u8 iInterface; 362 } __attribute__ ((packed));
usb_endpoint_descriptor
//include/uapi/linux/usbch9.h 369 struct usb_endpoint_descriptor { 370 __u8 bLength; 371 __u8 bDescriptorType; 372 373 __u8 bEndpointAddress; 374 __u8 bmAttributes; 375 __le16 wMaxPacketSize; 376 __u8 bInterval; 377 378 /* NOTE: these two are _only_ in audio endpoints. */ 379 /* use USB_DT_ENDPOINT*_SIZE in bLength, not sizeof. */ 380 __u8 bRefresh; 381 __u8 bSynchAddress; 382 } __attribute__ ((packed));
usb_device
//include/linux/usb.h 510 struct usb_device { 511 int devnum; 512 char devpath[16]; 513 u32 route; 522 struct usb_device *parent; 523 struct usb_bus *bus; 524 struct usb_host_endpoint ep0; 526 struct device dev; 528 struct usb_device_descriptor descriptor; 529 struct usb_host_bos *bos; 530 struct usb_host_config *config; 532 struct usb_host_config *actconfig; 557 char *product; 558 char *manufacturer; 559 char *serial; 561 struct list_head filelist; 563 int maxchild; 568 unsigned long active_duration; 569 584 };
struct usb_device
--522-->The parent device of this device, Usually is usb The Last Node Equipment of Tower Structure
--523-->The bus that belongs to is usb Bus
--526-->This is a device, It will be linked to the corresponding linked list.
--528-->This software device Hardware included in the structure device object
--530-->Software device All software owned config object, Corresponding hardware device All the hardware you own config
--531-->The moment, this device In use config
--557-->Product name
--558-->Product Manufacturer
--559-->product ID
--561-->Opened on this device usbfs Link List Node of File
--563-->Maximum number of sub-devices
urb_host_config
//include/linux/usb.h 275 struct usb_host_config { 276 struct usb_config_descriptor desc; 278 char *string; /* iConfiguration string, if present */ 282 struct usb_interface_assoc_descriptor *intf_assoc[USB_MAXIADS]; 286 struct usb_interface *interface[USB_MAXINTERFACES]; 290 struct usb_interface_cache *intf_cache[USB_MAXINTERFACES]; 292 unsigned char *extra; /* Extra descriptors */ 293 int extralen; 294 };
struct usb_host_config
--276-->Software config Object contains hardware config object
--278-->config Name
--282-->this config Associated Interface Association Descriptor
--283-->this config Upper-related lower-level software interface array,
usb_interface
Here's a description that matches the driver directly.
160 struct usb_interface { 163 struct usb_host_interface *altsetting; 165 struct usb_host_interface *cur_altsetting; 167 unsigned num_altsetting; /* number of alternate settings */ 171 struct usb_interface_assoc_descriptor *intf_assoc; 173 int minor; 175 enum usb_interface_condition condition; /* state of binding */ 176 unsigned sysfs_files_created:1; /* the sysfs attributes exist */ 177 unsigned ep_devs_created:1; /* endpoint "devices" exist */ 178 unsigned unregistering:1; /* unregistration is in progress */ 179 unsigned needs_remote_wakeup:1; /* driver requires remote wakeup */ 180 unsigned needs_altsetting0:1; /* switch to altsetting 0 is pending */ 181 unsigned needs_binding:1; /* needs delayed unbind/rebind */ 182 unsigned reset_running:1; 183 unsigned resetting_device:1; /* true: bandwidth alloc after reset */ 185 struct device dev; /* interface specific device info */ 186 struct device *usb_dev; 187 atomic_t pm_usage_cnt; /* usage counter for autosuspend */ 188 struct work_struct reset_ws; /* for resets in atomic context */ 189 };
struct usb_interface
--163-->this interface All included setting
--164-->this interface Currently in use setting
--165-->If this interface Binding to a driver that uses the master device number, This field is interface Secondary Equipment Number of ___________; On the contrary, it's useless.. The driver should be in probe Set this parameter in
usb_host_interface
77 struct usb_host_interface { 78 struct usb_interface_descriptor desc; 80 int extralen; 81 unsigned char *extra; /* Extra descriptors */ 86 struct usb_host_endpoint *endpoint; 88 char *string; /* iInterface string, if present */ 89 };
struct usb_host_interface
--78-->this interface Corresponding hardware interface object
--86-->Owned Description Software endpoint Information usb_host_endpoint array
--88-->interface Name
usb_host_endpoint
endpoint is the basic unit of USB device IO
64 struct usb_host_endpoint { 65 struct usb_endpoint_descriptor desc; 66 struct usb_ss_ep_comp_descriptor ss_ep_comp; 67 struct list_head urb_list; 68 void *hcpriv; 69 struct ep_device *ep_dev; /* For sysfs info */ 71 unsigned char *extra; /* Extra descriptors */ 72 int extralen; 73 int enabled; 74 };
struct usb_host_endpoint
--65-->this usb_host_endpoint Corresponding hardware endpoint information
--67-->Read and write this endpoint Of usb linked list, from usb Core layer(drivers/usb/core/file.c)Maintain
--73-->this endpoint Is it enabled?
Every hardware information object is included in a software information object, and the software information object is included layer by layer. So although the driver is described by interface, we can easily find config and device descriptions upward by using "list_entry()", and endpoint descriptions can be easily found by using the domain. The structure of the nine descriptive devices is shown in the following figure:
urb
Unlike platform s or i2c buses, USB buses do not allow devices to initiate communication, so as device drivers, only the required "materials" are ready to be submitted to the USB controller driver via the core layer, allowing the controller driver to poll the device with these "materials" and bring the response back. These "materials" are urbs and corresponding registration parameters. When the usb_driver matches the USB device, we prepare a urb object to register to the bus through usb_fill_int_urb()/_bulk_/_control_and send the command of sending the urb object to the controller driver through usb_submit_urb at the appropriate time. After the bus controller driver receives our sending command, it will continuously send the matching device according to the cycle set at the time of registration. Send the request, if the sub-device responds to our request, the controller driver fills in our registered urb object and calls back our registration function.
For mass storage USB devices, if the device is to work properly, in addition to these processes, also need to add the management of the buffer, which we will talk about in the next part.
usb_fill_int_urb
Initialize and register an interrupt urb. The prototype of the function is as follows:
static inline void usb_fill_int_urb(struct urb *urb,struct usb_device *dev,unsigned int pipe, void *transfer_buffer,int buffer_length,usb_complete_t complete_fn,void *context,int interval)
This function has many parameters, urb represents the urb object we want to register, dev represents the destination device of the urb object, pipe represents the read and write pipeline, which is obtained by usb_sndintpipe() and usb_rcvintpipe(), transfer_buffer represents the first address of the buffer for transferring data, buffer_length indicates the length of the buffer, complete_fn indicates that if the urb we send out responds, we call back the function. context is a parameter of the callback function, which is defined by the user and is equivalent to void * dev in request_irq.
usb_alloc()
Like xxx, urb uses the kernel allocation function, which does some initialization work.
usb_fill_bulk_urb
Initialize and register a mass storage urb
usb_fill_control_urb
Initialize and register a control urb
usb_submit_urb
Notify the kernel to send urb objects
usb_driver
1048 struct usb_driver { 1049 const char *name; 1051 int (*probe) (struct usb_interface *intf, 1052 const struct usb_device_id *id); 1054 void (*disconnect) (struct usb_interface *intf); 1056 int (*unlocked_ioctl) (struct usb_interface *intf, unsigned int code, 1057 void *buf); 1059 int (*suspend) (struct usb_interface *intf, pm_message_t message); 1060 int (*resume) (struct usb_interface *intf); 1061 int (*reset_resume)(struct usb_interface *intf); 1063 int (*pre_reset)(struct usb_interface *intf); 1064 int (*post_reset)(struct usb_interface *intf); 1066 const struct usb_device_id *id_table; 1068 struct usb_dynids dynids; 1069 struct usbdrv_wrap drvwrap; 1070 unsigned int no_dynamic_id:1; 1071 unsigned int supports_autosuspend:1; 1072 unsigned int disable_hub_initiated_lpm:1; 1073 unsigned int soft_unbind:1; 1074 };
struct usb_driver
--1049-->usb Name of equipment
--1051-->Detection function, When usb_driver Of id_table and usb When the device information matches, it will be executed., The main job is to apply for resources., Initialization, Provide interface
--1054-->When the driver module is unloaded or the device is pulled out, it will be executed.
--1066-->Functions are still matched, just usb Equipment information is described by four dimensions, therefore id_table The content that can be filled in is also varied.
usb_register
Register a usb_driver to the kernel
usb_deregister
Log off a usb_driver
id_table
The kernel provides the following macros to construct a usb_device_id object. In fact, it fills in different domains of usb_device_id. Because of the differences of devices, different USB devices will report different device information, but whatever information they report, it must belong to the encapsulation of the following macros. You can use lsusb-v to view the hardware information of the device first, and then according to the information they provide. Hardware information determines id_table to write the corresponding driver
USB_DEVICE
811 #define USB_DEVICE(vend, prod) \ 812 .match_flags = USB_DEVICE_ID_MATCH_DEVICE, \ 813 .idVendor = (vend), \ 814 .idProduct = (prod)
USB_DEVICE_VER
825 #define USB_DEVICE_VER(vend, prod, lo, hi) \ 826 .match_flags = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION, \ 827 .idVendor = (vend), \ 828 .idProduct = (prod), \ 829 .bcdDevice_lo = (lo), \ 830 .bcdDevice_hi = (hi)
USB_DEVICE_INTERFACE_CLASS
841 #define USB_DEVICE_INTERFACE_CLASS(vend, prod, cl) \ 842 .match_flags = USB_DEVICE_ID_MATCH_DEVICE | \ 843 USB_DEVICE_ID_MATCH_INT_CLASS, \ 844 .idVendor = (vend), \ 845 .idProduct = (prod), \ 846 .bInterfaceClass = (cl)
USB_DEVICE_INTERFACE_PROTOCOL
857 #define USB_DEVICE_INTERFACE_PROTOCOL(vend, prod, pr) \ 858 .match_flags = USB_DEVICE_ID_MATCH_DEVICE | \ 859 USB_DEVICE_ID_MATCH_INT_PROTOCOL, \ 860 .idVendor = (vend), \ 861 .idProduct = (prod), \ 862 .bInterfaceProtocol = (pr)
USB_DEVICE_INTERFACE_NUMBER
873 #define USB_DEVICE_INTERFACE_NUMBER(vend, prod, num) \ 874 .match_flags = USB_DEVICE_ID_MATCH_DEVICE | \ 875 USB_DEVICE_ID_MATCH_INT_NUMBER, \ 876 .idVendor = (vend), \ 877 .idProduct = (prod), \ 878 .bInterfaceNumber = (num)
USB_DEVICE_INFO
889 #define USB_DEVICE_INFO(cl, sc, pr) \ 890 .match_flags = USB_DEVICE_ID_MATCH_DEV_INFO, \ 891 .bDeviceClass = (cl), \ 892 .bDeviceSubClass = (sc), \ 893 .bDeviceProtocol = (pr) 894
USB_INTERFACE_INFO
904 #define USB_INTERFACE_INFO(cl, sc, pr) \ 905 .match_flags = USB_DEVICE_ID_MATCH_INT_INFO, \ 906 .bInterfaceClass = (cl), \ 907 .bInterfaceSubClass = (sc), \ 908 .bInterfaceProtocol = (pr)
USB_DEVICE_AND_INTERFACE_INFO
924 #define USB_DEVICE_AND_INTERFACE_INFO(vend, prod, cl, sc, pr) \ 925 .match_flags = USB_DEVICE_ID_MATCH_INT_INFO \ 926 | USB_DEVICE_ID_MATCH_DEVICE, \ 927 .idVendor = (vend), \ 928 .idProduct = (prod), \ 929 .bInterfaceClass = (cl), \ 930 .bInterfaceSubClass = (sc), \ 931 .bInterfaceProtocol = (pr)
USB_VENDOR_AND_INTERFACE_INFO
946 #define USB_VENDOR_AND_INTERFACE_INFO(vend, cl, sc, pr) \ 947 .match_flags = USB_DEVICE_ID_MATCH_INT_INFO \ 948 | USB_DEVICE_ID_MATCH_VENDOR, \ 949 .idVendor = (vend), \ 950 .bInterfaceClass = (cl), \ 951 .bInterfaceSubClass = (sc), \ 952 .bInterfaceProtocol = (pr) 953
id_table instance
The following is the ib_table filling mode in the kernel "drdrivers/hid/usbhid/usbmouse.c". It can be seen that not only macros are used in the construction, but also the attribute values of USB mouse are identified by standard macros because it is a standard device.
230 static struct usb_device_id usb_mouse_id_table [] = { 231 { USB_INTERFACE_INFO(USB_INTERFACE_CLASS_HID, USB_INTERFACE_SUBCLASS_BOOT, 232 USB_INTERFACE_PROTOCOL_MOUSE) }, 233 { } /* Terminating entry */ 234 };
USB Mouse Example
The kernel "drivers/hid/usb hid/usbmouse.c" is a driver of USB mouse. Here I write one according to my own understanding. It adopts the framework of "usb interrupt device driver+input subsystem".
#define BUF_SIZE 8 MODULE_LICENSE("GPL"); //Object-oriented, encapsulating classes according to requirements struct xj_mouse { char name[128]; struct usb_device *dev; struct urb *msg; struct input_dev *input; signed char *buf; }; struct xj_mouse *mouse; static int usb_mouse_open(struct input_dev *dev) { struct xj_mouse *mouse = input_get_drvdata(dev); mouse->msg->dev = mouse->dev; if (usb_submit_urb(mouse->msg, GFP_KERNEL)) return -EIO; return 0; } static void usb_mouse_close(struct input_dev *dev) { struct xj_mouse *mouse = input_get_drvdata(dev); usb_kill_urb(mouse->msg); } static int init_input(struct usb_interface * intf) { int err=0; struct usb_device *dev = mouse->dev; struct input_dev *input_dev = mouse->input; input_dev->name = mouse->name; usb_to_input_id(dev, &input_dev->id); input_dev->dev.parent = &intf->dev; input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL); input_dev->keybit[BIT_WORD(BTN_MOUSE)] = BIT_MASK(BTN_LEFT) |BIT_MASK(BTN_RIGHT) | BIT_MASK(BTN_MIDDLE); input_dev->relbit[0] = BIT_MASK(REL_X) | BIT_MASK(REL_Y); input_dev->keybit[BIT_WORD(BTN_MOUSE)] |= BIT_MASK(BTN_SIDE) |BIT_MASK(BTN_EXTRA); input_dev->relbit[0] |= BIT_MASK(REL_WHEEL); input_set_drvdata(input_dev, mouse); input_dev->open = usb_mouse_open; input_dev->close = usb_mouse_close; err = input_register_device(mouse->input); return 0; } static void completion(struct urb * msg) { int status; signed char *buf = mouse->buf; struct input_dev *input = mouse->input; input_report_key(input, BTN_LEFT, buf[0] & 0x01); input_report_key(input, BTN_RIGHT, buf[0] & 0x02); input_report_key(input, BTN_MIDDLE, buf[0] & 0x04); input_report_key(input, BTN_SIDE, buf[0] & 0x08); input_report_key(input, BTN_EXTRA, buf[0] & 0x10); input_report_rel(input, REL_X, buf[1]); input_report_rel(input, REL_Y, buf[2]); input_report_rel(input, REL_WHEEL, buf[3]); input_sync(input); status = usb_submit_urb (msg, GFP_ATOMIC); } static int probe(struct usb_interface *intf, const struct usb_device_id *id) { int pipe; struct usb_host_interface *interface; struct usb_endpoint_descriptor *endpoint; //Distribution and Initialization of Personality Structure mouse = (struct xj_mouse *)kzalloc(sizeof(struct xj_mouse),GFP_KERNEL); mouse->dev=interface_to_usbdev(intf); mouse->msg=usb_alloc_urb(0,GFP_KERNEL); mouse->input=input_allocate_device(); mouse->buf=(void *)kzalloc(BUF_SIZE,GFP_KERNEL); if (mouse->dev->manufacturer){ strlcpy(mouse->name, mouse->dev->manufacturer, sizeof(mouse->name)); mouse->input->name = mouse->name; } //Initialize the input device init_input(intf); //Get pipe interface=intf->cur_altsetting; endpoint=&interface->endpoint[0].desc; /* Use dev and endpoint to get endpoint addresses */ pipe = usb_rcvintpipe(mouse->dev,endpoint->bEndpointAddress); //Register usb driver usb_fill_int_urb(mouse->msg,mouse->dev,pipe,mouse->buf,BUF_SIZE,completion,mouse->msg,endpoint->bInterval); return 0; } static void disconnect(struct usb_interface *intf) { struct xj_mouse *tmp_mouse = usb_get_intfdata (intf); usb_set_intfdata(intf, NULL); if (tmp_mouse) { usb_kill_urb(tmp_mouse->msg); input_unregister_device(tmp_mouse->input); usb_free_urb(tmp_mouse->msg); kfree(tmp_mouse->buf); kfree(tmp_mouse); } } static struct usb_device_id id_table [] ={ { USB_INTERFACE_INFO(USB_INTERFACE_CLASS_HID, USB_INTERFACE_SUBCLASS_BOOT,USB_INTERFACE_PROTOCOL_MOUSE) }, {}, }; struct usb_driver mouse_drv = { .name = "xj_mouse_drv", .probe = probe, .disconnect = disconnect, .id_table = id_table, }; module_usb_driver(mouse_drv);