Someone asked, how can I write a driver for so long? Indeed, it is not easy for everyone to go all the way, but now that we have reached today, we can only stick to it. Usb_stor_acquire_resources () is used to obtain resources by name. What is a resource? I have not applied for a large number of applications...
Someone asked, how can I write a driver for so long?
Indeed, it is not easy for everyone to go all the way, but now that we have reached today, we can only stick to it.
Usb_stor_acquire_resources () is used to obtain resources by name. What is a resource? Didn't I apply for a large amount of memory? Why is it so troublesome to write a USB driver? Isn't a struct us_data struct specially designed for the USB Mass Storage device? Isn't it that the story has reached its climax?
If you think that you have a good understanding of the driver of the USB device and think that the following code does not need to be analyzed, I just want to say, god's plan to create the world may not include a USB device driver.
Indeed, there are not many codes for usb_stor_acquire_resources. each line has its own story. In this section, we will only talk about one line of code. Yes, it is a line of code, because we need to introduce a term, a well-known name, which is the legendary "urb ", USB RequestBlock. The USB device needs to communicate with each other. to transmit data, you need to use urb. Specifically, the USB device driver uses urb. In fact, as a USB device driver, it cannot directly manipulate data transmission. in the USB Grand Park, external devices will always be a secondary role. the true Core is USB Core, what is really responsible for scheduling is USB host control. This generally invisible USB host controller chip is the big manager in the USB visualization Park. To send information, a device driver must create an urb data structure and hand over the data structure to the core layer. The core layer schedules all devices in a unified manner, after the device submits the urb, it only needs to wait. Don't worry. let's take a while.
Row 3: A value assignment statement. The us-> current_urb on the left of the equal sign and the usb_alloc_urb () function on the right of the equal sign are called. If struct us_data is the main character in usb mass storage, struct urb will become the main character in the whole USB subsystem without dispute. All USB drivers in Linux must also use urb. So what exactly does urb look like? You can find it in include/linux/usb. h:
1126 struct urb
1127 {
1128/* private: usb core and hostcontroller only fields in the urb */
1129 struct kref;/* reference count of the URB */
1130 spinlock_t lock;/* lock for the URB */
1131 void * hcpriv;/* private data for host controller */
1132 atomic_tuse_count;/* concurrent submissions counter */
1133 u8 reject;/* submissions will fail */
1134
1135/* public: incluented fields inthe urb that can be used by drivers */
1136 struct list_head urb_list;/* list headfor use by the urb's
1137 * current owner */
1138 struct usb_device * dev;/* (in) pointer to associated device */
1139 unsignedint pipe;/* (in) pipe information */
1140 intstatus;/* (return) non-ISO status */
1141 unsigned int transfer_flags;/* (in) URB_SHORT_NOT_ OK | ...*/
1142 void * transfer_buffer;/* (in) associated data buffer */
1143 dma_addr_ttransfer_dma;/* (in) dma addr for transfer_buffer */
1144 int transfer_buffer_length;/* (in) data bufferlength */
1145 int actual_length;/* (return) actual transfer length */
1146 unsigned char * setup_packet;/* (in) setup packet (control only )*/
1147 dma_addr_tsetup_dma;/* (in) dma addr for setup_packet */
1148 intstart_frame;/* (modify) start frame (ISO )*/
1149 intnumber_of_packets;/* (in) number of ISO packets */
1150 intinterval;/* (modify) transfer interval
1151 * (INT/ISO )*/
1152 int error_count;/* (return) number of ISO errors */
1153 void * context;/* (in) context for completion */
1154 usb_complete_tcomplete;/* (in) completionroutine */
1155 struct usb_iso_packet_descriptoriso_frame_desc [0];
1156/* (in) iso only */
1157 };
We often complain that there are too few comments in the Linux kernel source code, so that we often don't understand what the code actually means. However, urb asked developers to write articles. The struct urb struct has only 30 lines, but the explanatory text has used more than 160 lines. See the status of urb. Of course, we post it here mainly to keep the original taste. on the other hand, this comment is also very clear and explained to every member, and we will inevitably use many members of urb.
At this moment, we do not care about the role of each element in this struct. we only need to know that an urb contains all the information required for USB transmission. As a driver, to communicate, you must create such a data structure and assign values. Obviously, for different types of transmission, you need to assign different values to urb and then submit her to the underlying layer, after the underlying USB Core is complete, the corresponding USB host controller will be found to implement data transmission. After the transmission is complete, the USB host controller notifies the device driver.
In short, we know that the first line is to call usb_alloc_urb () to apply for a struct urb struct. About usb_alloc_urb (), we don't want to talk about it. it is a function provided by USB Core, from drivers/usb/core/urb. c. The USB Developer did give urb a sufficient face to organize the code related to the data structure into such a file. We can find the declaration of this function in include/linux/usb. h:
1266 extern struct urb * usb_alloc_urb (intiso_packets, gfp_t mem_flags );
This function applies for memory for an urb struct. It has two parameters. The first iso_packets is used to specify the number of packets to be transmitted in the wait-time transmission mode. for non-equal-time mode, this parameter uses 0 directly. Another parameter, mem_flags, is a flag that indicates the method for applying for memory. this flag will be finally passed to the kmalloc function. here we pass GFP_KERNEL, which is the most commonly used in memory application, we also used it before when applying for memory for us. Usb_alloc_urb will eventually return an urb pointer, and the us member current_urb is also a pointer to struct urb, so it is assigned. However, remember that in addition to applying for memory, usb_alloc_urb also initializes the struct, and the struct urb is initialized to 0. Although the code of this function is not "pasted" here, but you must never think that the person who writes the code is similar to me. you can still forget to initialize the application variables. In addition, there is a reference count and a spin lock in struct urb, which is also initialized.
So next we will deal with us-> current_urb. If you are still confused about how to use urb, you can view the host controller driver code. If you don't want to see it, I can tell you in one of the most acceptable ways that USB is a bus and it requires communication. In our real life, we really want to use a device, but it is not enough to implement USB communication, so there is a USB host controller in the world, which is responsible for unified scheduling. This is like the traffic police in the city. what the city really needs is vehicles and pedestrians, while there are vehicles and pedestrians, and there is no traffic police, then the vehicles and pedestrians in the city will be chaotic. Therefore, the traffic police industry was born, and the traffic police stood at the intersection to manage and dispatch chaotic traffic. If vehicles and pedestrians can follow certain rules and come and go to every corner and intersection of the city, there is no need for the traffic police to exist. Similarly, if the device can transmit information completely and every packet can reach where it should go, then we do not need a host controller. However, there will always be people who do not follow the traffic rules. Similarly, in the world of USB, devices are always so unruly. we must design something to manage and control the communication between all USB devices. in this way, the host controller is born.
What is the division of labor between devices and host controllers? In terms of hardware implementation, we will not talk about it. Specifically, in Linux, the device driver only needs to prepare a urb struct variable for each request, fill it in (that is, assign the assigned value), and then it calls the function provided by USB Core to pass the urb to the host controller, the host controller will plan the urb submitted by each device driver to perform each operation. During this period, the driver of the USB device usually goes to sleep. Once the host controller finishes what urb has to do, it will call a function to wake up the driver of the USB device, then the driver of the USB device can proceed.
This is like the relationship between teachers and students in our school. During the exam, we just filled out the exam, and then handed it to the teacher. then the teacher took it to correct the exam. during this period, we had no choice but to wait for the teacher to finish the exam and told us the score, we continue our lives. The same is true for USB device drivers. if urb is submitted to the USB host but is not executed successfully, the life of the driver may end early. However, this is a post. now we only need to have a perceptual knowledge, and we will be able to have a deeper understanding later, this job division brings us great convenience in writing device drivers.
Continue the usb_stor_acquire_resources function.
Rows 785 to 788 indicate that the application was successful after urb applied. if the pointer is NULL, the request fails and-ENOMEM is returned directly.
Row 3, us-> unusual_dev-> What is initFunction? The unusual_devs.h file was analyzed for specific examples. some devices need some initialization functions, which are defined in the unusual_devs.h file, the UNUSUAL_DEV definition has granted these initialization functions to the initFunction pointer of us-> unusual_dev. So at this time, before the transmission starts, we can determine whether there is such a function, that is, whether the function pointer is null. if it is not empty, it is easy to execute this function. For example, the two devices we mentioned at the time had initialization functions, so we had to execute them. Of course, General devices certainly do not need such a function. As for the parameters passed to this function, when the struct us_unusual_dev struct is defined, it defines the parameters required by this function. what is needed is a struct us_data *, which is natural, the transfer is us.
So far, we have finally reached the 799th line in usb_stor_acquire_resources (), and will soon see this long-awaited kernel Genie