I am a USB flash drive for those Linux events (34) confused batch transmission (3)

Source: Internet
Author: User
Previous article: http://www.2cto.com/ OS /201511/114321.htmlin usb_stor_bulk_transport (), the first most important function called in this function is usb_stor_bulk_transfer_buf (). Still from drivers/usb/stroage/transport. c: previous: http://www.2cto.com/ OS /201112/114321.html

In usb_stor_Bulk_transport (), the first most important function called in this function is usb_stor_bulk_transfer_buf (). Still from drivers/usb/stroage/transport. c:
 
391 int usb_stor_bulk_transfer_buf (struct us_data * us, unsigned int pipe,
 
392 void * buf, unsigned int length, unsigned int * act_len)
 
393 {
 
394 int result;
 
395
 
396 US_DEBUGP ("% s: xfer % u Bytes \ n" ,__ FUNCTION __, length );
 
397
 
398/* fill and submit the URB */
 
399 usb_fill_bulk_urb (us-> current_urb, us-> pusb_dev, pipe, buf, length,
 
400 usb_stor_blocking_completion, NULL );
 
401 result = usb_stor _ msg_common (us, 0 );
 
402
 
403/* store the actual length of the datatransferred */
 
404 if (act_len)
 
405 * act_len = us-> current_urb-> actual_length;
 
406 return interpret_urb_result (us, pipe, length, result,
 
407 us-> current_urb-> actual_length );
 
408}
 
If the result is successfully submitted, the returned result is 0. Act_len records the actual transfer length. However, simply looking at these two functions, we have to look at the context. In other words, we need to combine the context of the call of usb_stor_bulk_transfer_buf in usb_bulk_transport () to compare the parameters and real parameters, so that we can truly understand and open up this thick fog.
 
Before carefully analyzing usb_stor_Bulk_transport (), let's look at this usb_fill_bulk_urb () function. This function is the first time we have seen that in the USB World, functions similar to this function include usb_fill_control_urb (). In addition, there is also a function called usb_fill_int_urb (). Needless to say, these functions are similar, except that they correspond to batch, control, and interruption in USB transmission mode respectively. The only difference from usb_fill_control_urb is that a setup_packet is not required for batch transmission. Specifically, usb_fill_bulk_urb () is defined in include/linux/usb. h:
 
1207 static inline void usb_fill_bulk_urb (structurb * urb,
 
1208 structusb_device * dev,
 
1209 unsignedint pipe,
 
1210 void * transfer_buffer,
 
1211 intbuffer_length,
 
1212 usb_complete_t complete_fn,
 
1213 void * context)
 
1214 {
 
1215 spin_lock_init (& urb-> lock );
 
1216 urb-> dev = dev;
 
1217 urb-> pipe = pipe;
 
1218 urb-> transfer_buffer = transfer_buffer;
 
1219 urb-> transfer_buffer_length = buffer_length;
 
1220 urb-> complete = complete_fn;
 
1221 urb-> context = context;
 
1222}
 
We call this function to fill in an urb, and then we can submit this urb to the USB Core layer. Obviously, it is to fill in an urb for a specific pipeline (the initial urb application is initialized to 0 ).
 
The following line is available in include/linux/usb. h.
 
961 typedef void (* usb_complete_t) (struct urb *);
 
Typedef is used to simplify the declaration. if you are not familiar with the typedef function, you can check that the strength of typedef makes the following two statements equally effective.
 
One function is:
 
Void (* func1) (struct urb *);
 
Void (* func2) (struct urb *);
 
Void (* func3) (struct urb *);
 
Another function is:
 
Typedef void (* usb_complete_t) (struct urb *);
 
Usb_complete_t func1;
 
Usb_complete_t func2;
 
Usb_complete_t func3;
 
As you can see, if you want to declare many function pointers, you can use typedef once and for all. it will be easy to declare them later. Therefore, we know that the complete in urb is a function pointer, which is set to point to the function usb_stor_blocking_completion (). Needless to say, this function will certainly be called later.
 
In row 3, the function usb_stor _ msg_common () is called. its function is that urb will be submitted, and then the core layer will schedule and execute it.
 
124 static int usb_stor _ msg_common (struct us_data * us, int timeout)
 
125 {
 
126 struct completion urb_done;
 
127 long timeleft;
 
128 int status;
 
129
 
130/* don't submit URBs during abort/disconnectprocessing */
 
131 if (us-> flags & ABORTING_OR_DISCONNECTING)
 
132 return-EIO;
 
133
 
134/* set up data structures for the wakeupsystem */
 
135 init_completion (& urb_done );
 
136
 
137/* fill the common fields in the URB */
 
138 us-> current_urb-> context = & urb_done;
 
139 us-> current_urb-> actual_length = 0;
 
140 us-> current_urb-> error_count = 0;
 
141 us-> current_urb-> status = 0;
 
142
 
143/* we assume that if transfer_buffer isn 'tus-> iobuf then it
 
144 * hasn't been mapped for DMA. Yes, this isclunky, but it's
 
145 * easier than always having the caller tell us whether
 
146 * transfer buffer has already been mapped .*/
 
147 us-> current_urb-> transfer_flags = URB_NO_SETUP_DMA_MAP;
 
148 if (us-> current_urb-> transfer_buffer = us-> iobuf)
 
149 us-> current_urb-> transfer_flags | = URB_NO_TRANSFER_DMA_MAP;
 
150 us-> current_urb-> transfer_dma = us-> iobuf_dma;
 
151 us-> current_urb-> setup_dma = us-> cr_dma;
 
152
 
153/* submit the URB */
 
154 status = usb_submit_urb (us-> current_urb, GFP_NOIO );
 
155 if (status ){
 
156/* something went wrong */
 
157 return status;
 
158}
 
159
 
160/* since the URB has been submittedsuccessfully, it's now okay
 
161 * tocancel it */
 
162 set_bit (us_f1_x_urb_active, & us-> flags );
 
163
 
164/* did an abort/disconnect occur during thesubmission? */
 
165 if (us-> flags & ABORTING_OR_DISCONNECTING ){
 
166
 
167/* cancel the URB, if it hasn't been cancelledalready */
 
168 if (test_and_clear_bit (us_f1_x_urb_active, & us-> flags )){
 
169 US_DEBUGP ("-- cancellingURB \ n ");
 
170 usb_unlink_urb (us-> current_urb );
 
171}
 
172}
 
173
 
174/* wait for the completion of the URB */
 
175 timeleft = wait_for_completion_interruptible_timeout (
 
176 & urb_done, timeout? : MAX_SCHEDULE_TIMEOUT );
 
177
 
178 clear_bit (us_f1_x_urb_active, & us-> flags );
 
179
 
180 if (timeleft <= 0 ){
 
181 US_DEBUGP ("% s -- cancellingURB \ n ",
 
182 timeleft = 0? "Timeout": "Signal ");
 
183 usb_kill_urb (us-> current_urb );
 
184}
 
185
 
186/* return the URB status */
 
187 return us-> current_urb-> status;
 
188}
 
Note that the usb_fill_bulk_urb function only fills several elements in urb, while struct urb contains many things, but some settings are common, so you need to use usb_stor_msg_common () you can see that there are only two parameters passed to this function: us and timeout (the value passed to this function in this case is 0 ), we will continue to go to this function to make it clear and clear.
 
First, let us-> flags and ABORTING_OR_DISCONNECTING and the ABORTING_OR_DISCONNECTING macro are defined in drivers/usb/storage/usb. h:
 
70/* Dynamic flag definitions: used in set_bit () etc .*/
 
71 # define us_f1_x_urb_active 18/* 0x00040000 current_urb is in use */
 
72 # define us_f1_x_sg_active 19/* 0x00080000 current_sg is in use */
 
73 # define us_f1_x_aborting 20/* 0x00100000 abort is in progress */
 
74 # define us_f1_x_disconnecting 21/* 0x00200000 disconnect in progress */
 
75 # define ABORTING_OR_DISCONNECTING (1UL <us_f1_x_aborting) | \
 
76 (1UL <us_fw.x_disconnecting ))
 
77 # define us_f1_x_resetting 22/* 0x00400000 device reset in progress */
 
78 # define us_f1_x_timed_out 23/* 0x00800000 SCSI midlayer timed out */
 
It is just a flag. we know that every USB Mass Storage device has a struct us_data data structure, namely, us. Therefore, throughout the probe process, it is equivalent to a "global" variable, so some flags can be used to mark some things. For example, for the urb submission function, it obviously does not want the device to be abandoned or disconnected at this time, because there is no need to submit urb.
 
The next function, init_completion (), is just a queue operation function, which is defined in include/linux/completion. h:
 
39 static inline void init_completion (structcompletion * x)
 
40 {
 
41 x-> done = 0;
 
42 init_waitqueue_head (& x-> wait );
 
43}
 
It only calls init_waitqueue_head to initialize a waiting queue. The definition of struct completion is also in the same file:
 
13 struct completion {
 
14 unsigned int done;
 
15 wait_queue_head_t wait;
 
16 };
 
We will describe the init_waitqueue_head in the following story.
 
Next, the current_urb structure of us is set. As shown in row 3, transfer_flags is set to writable, while URB_NO_SETUP_DMA_MAP indicates that if DMA is used for transmission, the setup_dma pointer in urb points to the DMA Buffer instead of the buffer pointed to by setup_packet. However, setup_packet is a concept unique to control transmission. this concept is not available for batch transmission, so we can ignore it completely.
 
Next, URB_NO_TRANSFER_DMA_MAP indicates that if urb has a DMA buffer to be transmitted, the buffer is the buffer to which the transfer_dma pointer points, rather than the buffer to which the transfer_buffer pointer points. In other words, if the two DMA flags are not set, the USB Core uses setup_packet (meaningful only for control transmission) and transfer_buffer as the buffer for data transmission, then, the following two rows grant us iobuf_dma and cr_dma to the transfer_dma and setup_dma of urb. Comments from rows 143 to 146 indicate that as long as transfer_buffer is assigned a value, assume that there is a DMA buffer that needs to be transferred, and then URB_NO_TRANSFER_DMA_MAP is set. The DMA section is difficult to understand, so let's say a few more words.
 
First, there are two DMA-Related flags: URB_NO_SETUP_DMA_MAP and URB_NO_TRANSFER_DMA_MAP. Note that the two are different. The first one is specially prepared for control transmission, because only the control transmission requires this Setup phase and a Setuppacket is required. Let's only look at the last one. regarding the relationship between transfer_buffer and transfer_dma, we applied for the memory of us-> iobuf in the same way as below:
 
466 us-> iobuf = usb_buffer_alloc (us-> pusb_dev, US_IOBUF_SIZE,
 
467 GFP_KERNEL, & us-> iobuf_dma );
 
468 if (! Us-> iobuf ){
 
469 US_DEBUGP ("I/O buffer allocation failed \ n ");
 
470 return-ENOMEM;
 
471}
 
Here we have two things: us-> iobuf and us-> iobuf_dma, but we noticed that when setting the flag of URB_NO_TRANSFER_DMA_MAP, we first make a judgment, determine whether us-> current_urb-> transfer_buffer is equal to us-> iobuf. what does this mean? Where did we assign a value to transfer_buffer? The answer is that in usb_fill_bulk_urb, we passed us-> iobuf and it was assigned to urb-> transfer_buffer. This means that we will use DMA transmission here, so this flag is set here. If we do not want to perform DMA transmission, it is very simple. we will not let urb-> transfer_buffer point to us-> iobuf before calling usb_stor _ msg_common, this is all set by ourselves. You need to know that transfer_buffer is actually used for data transmission in various transmission modes, while setup_packet only sends Setup packets in Control Transmission. besides the Setup phase, there will also be a data transmission phase, which still relies on transfer_buffer for data transmission. if DMA is used, transfer_dma is used.
 
Line 3 finally reached the urb submission step. usb_submit_urb was called. as a USB device driver, we don't need to know what this function is doing, as long as we know how to use it. It is defined in drivers/usb/core/urb. c. We need to know that it has two parameters: urb to be submitted, and flag to be applied for memory. Here we use GFP_NOIO, which means that I/O operations cannot be performed when the memory is applied. The principle is very simple. this is a storage device. calling usb_submit_urb is probably because we want to read some disks or USB disks. in this case, if the memory function is applied to read and write the disk again, then there is a problem. what is the problem? Nested. What is the function that applies for memory? Because the memory is not enough. It is not convenient to use a disk as a swap partition. Therefore, when applying for memory, it may need to exist on the disk, so you have to switch back. Isn't this enough to read and write the disk? Therefore, if we submit urb for reading and writing the hard disk, I/O operations cannot be performed again in this process. The purpose of this operation is to prevent nested endless loops.
 
So we can call 154 lines to go down, and the rest will be handled by the USB Core and USB host. As for the return value of this function itself, if everything is normal, the status will be 0. Therefore, if the status is not 0, an error occurs. In row 3, after a urb is submitted, we usually put us-> flags on a flag, us_f1_x_urb_active, so that we can record that the urb status is alive.
 
Row 3: Let's judge us-> flags again to see if the flag of aborting or disconnected is set. We will see who will set these flags later. Obviously, if we have already set these flags, we don't need to proceed. this urb can be canceled.
 
175 rows, lead time mechanism


From the Linux kernel column of fudan_abc
Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.