Overview of USB device model building process
The S3c2440 processor integrates a USB controller. The host controller is added to the kernel as a platform device s3c_device_usb. The device matches the driver ohci_hcd_s3c2410_driver and calls the function usb_hcd_s3c2410_probe. In the function usb_hcd_s3c2410_probe, hardware resources are obtained, memory is allocated for the USB host controller structure usb_hcd, and the function usb_add_hcd is called to fill usb_hcd. One host controller corresponds to one USB bus, and the bus is registered to the kernel usb_register_bus(&hcd->self) in the function usb_add_hcd. One host controller is bound to one root_hub. Root_hub, hub, and devices plugged into the hub port are all usb_device. Therefore, in the function usb_add_hcd, storage space usb_alloc_dev is allocated for the usb_device of the root_hub. In order to initialize the usb_device of root_hub and register it with the kernel, the function register_root_hub is called again. Whether it is root_hub, hub, or the device plugged into the hub port, they are all usb_device, so they all have device descriptors. In the function register_root_hub, the function usb_get_device_descriptor is called to obtain the device descriptor of the root_hub device. A new device needs to be configured accordingly before being added to the kernel. To complete this work, the function register_root_hub calls usb_new_device again.
Each USB device has one or more configurations; each configuration has one or more interfaces; an interface has one or more settings; a setting has one or more endpoints. In order to describe the configuration, interface, and endpoint, each USB device has a configuration descriptor, an interface descriptor, and an endpoint descriptor. In order to obtain and parse these descriptors, the function usb_configure_device is called in the function usb_new_device. Then the device is added to the kernel device_add(&udev->dev). Each USB device has a control endpoint. It is usually used to configure the device, obtain device information, send commands to the device, or obtain a status report of the device. It is needed in the process of device establishment. To make it work, it must be added to the kernel first. For this purpose, the function usb_create_ep_devs is called in the function usb_new_device.
The bus type of all USB devices is usb_bus_type and the device type is usb_device_type. When a USB device is added to the bus, it will look for its corresponding driver. For this purpose, the kernel creates a driver usb_generic_driver that can match all USB devices. When a usb_device is added to the kernel, it will match the driver usb_generic_driver and call the function generic_probe. In the function generic_probe, the function usb_choose_configuration will be called to select a reasonable configuration for the device. At this point, all descriptors under the selected configuration can be used to configure the device. The function usb_set_configuration completes this function. In the function usb_set_configuratio, all interfaces of the device are added to the kernel device_add(&intf->dev). The bus type of these interface devices is usb_bus_type and the device type is usb_if_device_type.
The USB interface is also added to the kernel as a device. It has its own bus usb_bus_type, so each interface has its corresponding driver. The interface is divided into HUB interface and USB device interface.
1. If it is a HUB interface:
HUB is different from devices. In addition to device descriptors, it also has its own unique HUB descriptor. There is a structure struct usb_hub to manage HUB. In order to configure HUB and fill in HUB structure usb_hub, the kernel creates HUB driver hub_driver. Once a new HUB is inserted, the driver hub_driver will match the interface of the new HUB, and then call the function hub_probe. In the function hub_probe, the memory usb_hub is allocated to the HUB structure, and the function hub_configure is called to obtain the HUB descriptor and configure the HUB. In the function hub_configure, the function get_hub_descriptor is called to obtain the HUB descriptor, and some parameters of the HUB are checked and configured for rationality. Then a URB is created and initialized as an interrupt URBusb_fill_int_urb(hub->urb, hdev, pipe, *hub->buffer, maxp, hub_irq,hub, endpoint->bInterval);, and the interrupt callback function is hub_irq. The role of this interrupt URB will be described later. Finally, the function hub_activate is called to activate the HUB. A HUB may have multiple ports for inserting USB devices. In the function hub_activate, the status of all ports on the HUB is detected and the changes on each port are marked hub->change_bits. Finally, the interrupt URB is submitted, usb_submit_urb(hub->urb, GFP_NOIO), to wake up the kernel thread kick_khubd(hub) (discussed below).
At this point, the USB host controller and root_hub have been added to the kernel, and the entire USB system is working normally, just waiting for the USB device to be plugged into the HUB port.
2. If it is the interface of the device:
A USB device may have multiple interfaces. One interface represents a basic function. Each USB driver controls one interface. The implementation of this driver is the main work of the driver writer. After the interface device matches the corresponding driver, the probe function is called to perform the corresponding initialization device model establishment and other work. . . . . .
At this point, a USB device inserted into the HUB can work normally.
About kernel threads:
When registering the HUB driver usb_register(&hub_driver), a kernel thread is also created.
khubd_task = kthread_run(hub_thread, NULL, "khubd"). The job of this thread is to wake up and process changes when there are changes on the HUB port. Under normal circumstances, this thread is in sleep mode. At this time, there is no HUB to be processed on the linked list hub_event_list. So when will the thread be woken up? When the HUB is created, an interrupt URB will be created in the function hub_configure, and the HUB will be submitted in the HUB activation function hub_activate. This URB will periodically obtain the status of the HUB. Once the status on the HUB port changes, the change will be marked in the URB callback function hub_irq hub->event_bits[0] = bits, and kick_khubd(hub) will be called to add the changed HUB structure to the linked list hub_event_list to wake up the kernel thread.
This change may be a reset, electromagnetic interference, a device plugged into or unplugged from the HUB port, etc. What we want to see is of course the change in the HUB port connection. To handle this change, the thread calls the function hub_events. In the function hub_events, call the function hub_port_status(hub, i,&portstatus, &portchange); to get the port status. Judge these changes, set the change flag, and then call the function hub_port_connect_change for processing. Determine the specific type of change in the function hub_port_connect_change and handle it accordingly. If a device is plugged into the HUB port, establish a device model for the device. Whether it is another HUB or a USB device plugged into the HUB port, there is a usb_device structure in the kernel, and the function usb_alloc_dev will be called to allocate storage space for the structure.
Call the function hub_port_init(hub, udev, port1, i) to reset the device and get its device descriptor. Then call the function usb_new_device(udev) to get the configuration descriptor, interface descriptor, endpoint descriptor, and add the device to the kernel. Then match the USB device driver usb_generic_driver to call the function generic_probe, configure the USB device, initialize the device interface and add it to the kernel. Next is the matching of each interface of the USB device with its corresponding driver. If the USB device is a HUB, match the driver hub_driver, call the function hub_probe, and establish the HUB model. If it is a device, match its corresponding driver. These tasks have been discussed above.
Previous article:Kernel timer for keystroke processing
Next article:nandflash bare metal program analysis
- Popular Resources
- Popular amplifiers
Professor at Beihang University, dedicated to promoting microcontrollers and embedded systems for over 20 years.
- LED chemical incompatibility test to see which chemicals LEDs can be used with
- Application of ARM9 hardware coprocessor on WinCE embedded motherboard
- What are the key points for selecting rotor flowmeter?
- LM317 high power charger circuit
- A brief analysis of Embest's application and development of embedded medical devices
- Single-phase RC protection circuit
- stm32 PVD programmable voltage monitor
- Introduction and measurement of edge trigger and level trigger of 51 single chip microcomputer
- Improved design of Linux system software shell protection technology
- What to do if the ABB robot protection device stops
- Huawei's Strategic Department Director Gai Gang: The cumulative installed base of open source Euler operating system exceeds 10 million sets
- Download from the Internet--ARM Getting Started Notes
- Learn ARM development(22)
- Learn ARM development(21)
- Learn ARM development(20)
- Learn ARM development(19)
- Learn ARM development(14)
- Learn ARM development(15)
- Analysis of the application of several common contact parts in high-voltage connectors of new energy vehicles
- Wiring harness durability test and contact voltage drop test method
- MSP430F149 I/O port control
- Xunwei-i.MX6ULL Development Board-Busybox transplant DHCP (Part 3)
- Free download of test solutions: R&SCMA180 - ideal test tool for analog and digital radio walkie-talkies
- Review summary: APM32E103VET6S MINI development board with the Polar Ocean M3 core
- Live broadcast at 13:15 this afternoon [Keysight World 2020|Telecom Infrastructure, Cloud and Artificial Intelligence Forum]
- Use of SN74LVC125AD
- [Zero-knowledge ESP8266 tutorial] Quick Start 17 Station mode creates a wifi hotspot
- If I need to control about 3,000 lights in a room, is BLE MESH or zigbee more suitable?
- Example of connecting CANOpen gateway to Inovance inverter
- Which Bluetooth microphone has a reference circuit? Post it and discuss it