devnum = find_next_zero_bit(bus->devmap.devicemap, 128, 1);
bus->devnum_next = ( devnum >= 127 ? 1 : devnum + 1); //Set the next addressing interval + 1
if (devnum < 128) {
set_bit(devnum, bus->devmap.devicemap); //Set bit
udev->devnum = devnum;
}
}
From the above code, we can see that the address number is added continuously each time. The USB interface can connect up to 127 devices. We plug and unplug the USB keyboard twice in succession, as shown in the following figure:
7. Let's take a look at how the hub_port_connect_chage()->hub_port_init() function connects to the USB device.
static int hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
int retry_counter)
{...
for (j = 0; j < SET_ADDRESS_TRIES; ++j)
{
retval = hub_set_address(udev); //(1)Set the address and tell the USB device the new address number
if (retval >= 0)
break;
msleep(200);
}
...
retval = usb_get_device_descriptor(udev, 8); //(2) Get the first 8 bytes of the USB device descriptor
...
retval = usb_get_device_descriptor(udev, USB_DT_DEVICE_SIZE); //Re-obtain device descriptor information
}
(1) The hub_set_address() function is mainly used to tell the USB device the new address number.
The hub_set_address() function is as follows:
static int hub_set_address(struct usb_device *udev)
{
int retval;
retval = usb_control_msg(udev, usb_sndaddr0pipe(), //(1)
USB_REQ_SET_ADDRESS, 0, udev->devnum, 0,
NULL, 0, USB_CTRL_SET_TIMEOUT);
if (retval == 0) {//Set new address, transfer completed, return 0
usb_set_device_state(udev, USB_STATE_ADDRESS); //Set the status flag
ep0_reinit(udev);
}
return retval;
}
The usb_control_msg() function is used to let the USB host controller send a control message to the USB device. If the transmission is completed, it returns 0. The parameter udev represents the target device. The pipe used is usb_sndaddr0pipe(), which is the default address 0 plus the control endpoint number 0. USB_REQ_SET_ADDRESS represents the command code, which sets the address. udev->devnum represents setting the device number of the target device. The time allowed to wait for the transmission to complete is 5 seconds, because USB_CTRL_SET_TIMEOUT is defined as 5000.
(2) The usb_get_device_descriptor() function mainly obtains the first 8 bytes of the target device descriptor. Why does it only read the first 8 bytes? Because at the beginning, we don’t know the packet capacity supported by the other party. These 8 bytes are available to every device. Later, according to the device data, the device description structure of the target device is reread through usb_get_device_descriptor().
The USB device descriptor structure is as follows:
/* USB_DT_DEVICE: Device descriptor */
struct usb_device_descriptor {
__u8 bLength; //The size of this descriptor
__u8 bDescriptorType; //descriptor type, here is the device descriptor DEVICE
__le16 bcdUSB; //Specify the USB version, such as USB2.0
__u8 bDeviceClass; //Class
__u8 bDeviceSubClass; //Subclass
__u8 bDeviceProtocol; //Specify the protocol
__u8 bMaxPacketSize0; //The maximum packet size corresponding to endpoint 0
__le16 idVendor; //Manufacturer ID
__le16 idProduct; //Product ID
__le16 bcdDevice; //Device release number
__u8 iManufacturer; //Index of manufacturer ID in string descriptor
__u8 iProduct; //Index of product ID in string descriptor
__u8 iSerialNumber; //Index of the device serial number in the string descriptor
__u8 bNumConfigurations; // possible configuration trees
} __attribute__ ((packed));
8. Let's see how the hub_port_connect_change()->usb_new_device() function creates a USB device
int usb_new_device(struct usb_device *udev)
{
...
err = usb_get_configuration(udev); //(1)Get the configuration description block
...
err = device_add(&udev->dev); //(2) Put the device into the dev list of the bus and find the corresponding device driver
...
}
(1) The usb_get_configuration() function is as follows, which is to obtain each configuration
int usb_get_configuration(struct usb_device *dev)
{
//USB_MAXCONFIG is defined as 8, indicating that there can be no more than 8 configuration description blocks under the device description block
if (ncfg > USB_MAXCONFIG) {//nfs indicates how many configuration description blocks are under the device description block
dev_warn(ddev, "too many configurations: %d, "
"using maximum allowed: %dn", ncfg, USB_MAXCONFIG);
dev->descriptor.bNumConfigurations = ncfg = USB_MAXCONFIG;
}
for (cfgno = 0; cfgno < ncfg; cfgno++) //for loop, read all configuration description blocks from the USB device at once
{
length = max((int) le16_to_cpu(desc->wTotalLength),
USB_DT_CONFIG_SIZE); //Use wTotalLength to know the actual data size
bigbuffer = kmalloc(length, GFP_KERNEL); //Then allocate enough space
...
result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno,
bigbuffer, length); //Call usb_get_descriptor once, read the entire configuration description block and put it in bifbuffer
...
dev->rawdescriptors[cfgno] = bigbuffer; //Put the bifbuffer address in the pointer array pointed to by ramdescriptor
result = usb_parse_configuration(&dev->dev, cfgno,
&dev->config[cfgno], bigbuffer, length); //Finally parse each configuration block
}
}
(2) The device_add() function is as follows:
int device_add(struct device *dev)
{
...
dev = get_device(dev); // Make dev equal to the device member under usb_device
...
if ((error = bus_add_device(dev)))//Add this device to the device table with dev->bus
goto BusError;
...
bus_attach_device(dev); //To match the corresponding driver
}
When the bus_attach_device() function matches successfully, the driver's probe function is called
9. Let's take a look at the usb_device_match function of the usb_bus_type member to see how it matches.
The usb_device_match function is shown below:
static int usb_device_match(struct device *dev, struct device_driver *drv)
{
if (is_usb_device(dev)) {//Judge whether it is a USB device
if (!is_usb_device_driver(drv))
return 0;
return 1;
} else { //Otherwise it is the interface of USB driver or USB device
struct usb_interface *intf;
struct usb_driver *usb_drv;
const struct usb_device_id *id;
if (is_usb_device_driver(drv)) //If it is a USB driver, no matching is required, just return directly
return 0;
intf = to_usb_interface(dev); //Get the interface of USB device
usb_drv = to_usb_driver(drv); //Get USB driver
id = usb_match_id(intf, usb_drv->id_table); //match the member id_table of USB driver
if (id)
return 1;
id = usb_match_dynamic_id(intf, usb_drv);
if (id)
return 1;
}
return 0;
}
Obviously it matches the id_table of the USB driver
10. So how should the id_table of the USB driver be defined?
The structure of id_table is usb_device_id, as shown below:
struct usb_device_id {
__u16 match_flags; //Which type does it match with the USB device? The macros for comparing types are as follows:
//USB_DEVICE_ID_MATCH_INT_INFO: 3 members of the interface descriptor used to match the device
//USB_DEVICE_ID_MATCH_DEV_INFO: 3 members used to match the device descriptor
//USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION: 4 members used to match a specific USB device
//USB_DEVICE_ID_MATCH_DEVICE: 2 members (idVendor and idProduct) used to match a specific USB device
/* The following 4 are used to match the description of a specific USB device */
__u16 idVendor; //Manufacturer ID
__u16 idProduct; //Product ID
__u16 bcdDevice_lo; //Low version number of the device
__u16 bcdDevice_hi; //High version number of the device
/* The following 3 are used to compare device descriptors*/
__u8 bDeviceClass; //Device class
__u8 bDeviceSubClass; //Device subclass
__u8 bDeviceProtocol; //Device protocol
/* The following 3 are used to compare the interface descriptors of the device*/
__u8 bInterfaceClass; //Interface type
__u8 bInterfaceSubClass; //Interface subclass
__u8 bInterfaceProtocol; //The protocol followed by the interface
/* not matched against */
kernel_ulong_t driver_info;
}
(Device descriptor interface descriptor structure reference: https://mp.csdn.net/postedit/81025137)
We refer to /drivers/hid/usbhid/usbmouse.c (the USB mouse driver that comes with the kernel) to see how it is used, as shown in the following figure:
It is found that it is defined by the USB_INTERFACE_INFO macro, which is as follows:
#define USB_INTERFACE_INFO(cl,sc,pr)
.match_flags = USB_DEVICE_ID_MATCH_INT_INFO, //Set the match_flags member of id_table
.bInterfaceClass = (cl),
.bInterfaceSubClass = (sc), .bInterfaceProtocol = (pr) //Set the 3 members of id_table to match the 3 members of the USB device
Then substitute the three values in the usb_mouse_id_table[] in the above figure into the macro
In USB_INTERFACE_INFO(cl,sc,pr):
.bInterfaceClass =USB_INTERFACE_CLASS_HID;
//Set the interface type to match USB to HID class, because USB_INTERFACE_CLASS_HID=0x03
//HID class is a device for human-computer interaction, such as USB keyboard, USB mouse, USB touchpad, USB game joystick, etc., all need to be filled in 0X03
.bInterfaceSubClass =USB_INTERFACE_SUBCLASS_BOOT;
//Set the interface subtype matching USB to boot device
.bInterfaceProtocol=USB_INTERFACE_PROTOCOL_MOUSE;
//Set the matching USB interface protocol to the USB mouse protocol, equal to 2
//When .bInterfaceProtocol=1, that is, USB_INTERFACE_PROTOCOL_KEYBOARD, it indicates the protocol of the USB keyboard
As shown in the figure below, we can also find the mouse protocol number under Windows, which is 1 (Col01):
VID: indicates the manufacturer (vendor) ID
PID: Product ID
Summary: When we plug in a USB device, the system will obtain the configuration, interface, endpoint data of the USB device and create the device, so our driver needs to write id_table to match the USB device
Previous article:S3C2440 USB mouse driver (19)
Next article:S3C2440 touch screen driver (Seventeen)
Recommended ReadingLatest update time:2024-11-16 10:30
- Popular Resources
- Popular amplifiers
- Virtualization Technology Practice Guide - High-efficiency and low-cost solutions for small and medium-sized enterprises (Wang Chunhai)
- usb_host_device_code
- Image acquisition and processing system for panoramic map applications
- Teach you to learn 51 single chip microcomputer-C language version (Second Edition) (Song Xuefeng)
Professor at Beihang University, dedicated to promoting microcontrollers and embedded systems for over 20 years.
- Innolux's intelligent steer-by-wire solution makes cars smarter and safer
- 8051 MCU - Parity Check
- How to efficiently balance the sensitivity of tactile sensing interfaces
- What should I do if the servo motor shakes? What causes the servo motor to shake quickly?
- 【Brushless Motor】Analysis of three-phase BLDC motor and sharing of two popular development boards
- Midea Industrial Technology's subsidiaries Clou Electronics and Hekang New Energy jointly appeared at the Munich Battery Energy Storage Exhibition and Solar Energy Exhibition
- Guoxin Sichen | Application of ferroelectric memory PB85RS2MC in power battery management, with a capacity of 2M
- Analysis of common faults of frequency converter
- In a head-on competition with Qualcomm, what kind of cockpit products has Intel come up with?
- Dalian Rongke's all-vanadium liquid flow battery energy storage equipment industrialization project has entered the sprint stage before production
- Allegro MicroSystems Introduces Advanced Magnetic and Inductive Position Sensing Solutions at Electronica 2024
- Car key in the left hand, liveness detection radar in the right hand, UWB is imperative for cars!
- After a decade of rapid development, domestic CIS has entered the market
- Aegis Dagger Battery + Thor EM-i Super Hybrid, Geely New Energy has thrown out two "king bombs"
- A brief discussion on functional safety - fault, error, and failure
- In the smart car 2.0 cycle, these core industry chains are facing major opportunities!
- The United States and Japan are developing new batteries. CATL faces challenges? How should China's new energy battery industry respond?
- Murata launches high-precision 6-axis inertial sensor for automobiles
- Ford patents pre-charge alarm to help save costs and respond to emergencies
- New real-time microcontroller system from Texas Instruments enables smarter processing in automotive and industrial applications
- The ADC example of the underlying driver code of esp32 is added to my own project and compiled unsuccessfully
- Read the good book "Electronic Engineer Self-study Handbook" - First Look
- Can anyone confirm what device this is? Thanks!
- Renesas RL78 D1A has an error when assigning an unsigned short type variable to a floating point number
- Source code of FFT transform IP core.zip
- Competition Sharing 3: RSL10 Bluetooth SoC BMM150 Geomagnetic Sensor Data Collection
- Understanding TMS320C6000 gel files
- NASA is going to build Wi-Fi on the moon? What do you think?
- Does anyone know linear system theory? Urgent! ! ! ! ! Thanks! ! ! !
- I have a question, STM32 drives a three-phase DC brushless controller to drive a DC brushless motor with Hall