S3C2440 USB bus driver analysis (XVIII)

Publisher:莫愁前路Latest update time:2020-07-17 Source: eefocusKeywords:S3C2440  USB Reading articles on mobile phones Scan QR code
Read articles on your mobile phone anytime, anywhere

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

[1] [2]
Keywords:S3C2440  USB Reference address:S3C2440 USB bus driver analysis (XVIII)

Previous article:S3C2440 USB mouse driver (19)
Next article:S3C2440 touch screen driver (Seventeen)

Recommended ReadingLatest update time:2024-11-16 10:30

S3C2440 OpenJtag
C:UsersAdministratorDesktop oflash.exe leds.bin +---------------------------------------------------------+ |   Flash Programmer v1.5.4 for OpenJTAG of www.100ask.net  | |   OpenJTAG is a USB to JTAG & RS232 tool based FT2232   | |   This programmer supports both of S3C24X0 & S3C6410    | |   Author: Email/MSN(thisw
[Microcontroller]
Linux 2.6.32 porting to arm9 (s3c2440) platform 2 -- Kconfig and Makefile (2) Linux
There is a Kconfig and Makefile in each directory of the Linux kernel source tree. The Kconfigs distributed to each directory constitute a distributed kernel configuration database. Each Kconfig describes the kernel configuration menu related to the source document of the directory to which it belongs. When executing
[Microcontroller]
STM32 USB virtual serial port
Serial port debugging is used more and more in projects, and the shortage of serial port resources has become particularly prominent. Many people who use notebooks have a deep understanding that they cannot develop without a USB to serial port tool. This chapter briefly outlines the transplantation of USB virtual seri
[Microcontroller]
STM32 USB virtual serial port
L-com has a variety of adapters in stock, fully matching USB, Ethernet and other interfaces
As an authorized distributor of L-com, Heilind can provide relevant product services and support to the market. In addition, it also supplies products from many of the world's top manufacturers, covering 25 different component categories, and focuses on all market segments. and all customers, constantly seeking a broa
[Network Communication]
L-com has a variety of adapters in stock, fully matching USB, Ethernet and other interfaces
Porting s3c2440 ads program to keil (Part 2) Preliminary completion
What if I change the parameter configuration? Then compile again to package errors As follows The error is as follows This error cannot be solved Finally, I checked the method of netizens on the Internet and it can be modified, but the nand file is introduced Finally, I know that the 2440init.s file needs to be m
[Microcontroller]
Porting s3c2440 ads program to keil (Part 2) Preliminary completion
iTOP-4412 development board-QtE4.7-usb3G network card transplantation tutorial
The development board used is Xunwei's iTOP-4412 development board   Porting Huawei E261 WCDMA 12d1:1446USB network card to 4412 development board QtELinux system.   1 Kernel Configuration Configure the following kernel options           and         As shown below     Then compile the kernel and burn it to the de
[Microcontroller]
iTOP-4412 development board-QtE4.7-usb3G network card transplantation tutorial
Porting u-boot-2010.09 to S3C2440 (Part 3) - Assembly code to determine whether to boot from NAND or NOR
Reference document: nandflash boot of s3c2440 guess_flash: #define BWSCON 0x48000000 ldr r4, =BWSCON   ldr r6, ands r6, r6, #0x6 mov r6, r6, LSL#4 ldr r5, =GPBDAT str r6, bl guess_flash What these lines mean is:         Get the value of address 0X48000000, obtain its bits, and display its
[Microcontroller]
USB video capture based on mini2440
In embedded systems, video collection mainly uses two interfaces: one is the standard camera interface and the other is the USB interface (USB1.1). The standard camera interface has a complex interface but fast transmission speed and is suitable for high-quality video capture, while the USB interface has a simple inte
[Microcontroller]
Latest Microcontroller Articles
  • Download from the Internet--ARM Getting Started Notes
    A brief introduction: From today on, the ARM notebook of the rookie is open, and it can be regarded as a place to store these notes. Why publish it? Maybe you are interested in it. In fact, the reason for these notes is ...
  • Learn ARM development(22)
    Turning off and on interrupts Interrupts are an efficient dialogue mechanism, but sometimes you don't want to interrupt the program while it is running. For example, when you are printing something, the program suddenly interrupts and another ...
  • Learn ARM development(21)
    First, declare the task pointer, because it will be used later. Task pointer volatile TASK_TCB* volatile g_pCurrentTask = NULL;volatile TASK_TCB* vol ...
  • Learn ARM development(20)
    With the previous Tick interrupt, the basic task switching conditions are ready. However, this "easterly" is also difficult to understand. Only through continuous practice can we understand it. ...
  • Learn ARM development(19)
    After many days of hard work, I finally got the interrupt working. But in order to allow RTOS to use timer interrupts, what kind of interrupts can be implemented in S3C44B0? There are two methods in S3C44B0. ...
  • Learn ARM development(14)
  • Learn ARM development(15)
  • Learn ARM development(16)
  • Learn ARM development(17)
Change More Related Popular Components

EEWorld
subscription
account

EEWorld
service
account

Automotive
development
circle

About Us Customer Service Contact Information Datasheet Sitemap LatestNews


Room 1530, 15th Floor, Building B, No.18 Zhongguancun Street, Haidian District, Beijing, Postal Code: 100190 China Telephone: 008610 8235 0740

Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号