知识屋:更实用的电脑技术知识网站
所在位置:首页 > 操作系统 > linux

《Linux那些事儿之我是USB》我是U盘(36)迷雾重重的批量传输(五)

发布时间:2014-09-05 16:27:17作者:知识屋

在讲数据传输阶段之前,先解决刚才的历史遗留问题。usb_stor_bulk_transfer_buf()中,406行,有一个很有趣的函数interpret_urb_result()被调用。这个函数同样来自drivers/usb/storage/transport.c中:
 
265 static int interpret_urb_result(struct us_data*us, unsigned int pipe,
 
266                unsigned int length, int result, unsigned int partial)
 
267 {
 
268      US_DEBUGP("Status code %d; transferred%u/%u/n",
 
269                         result, partial,length);
 
270      switch (result) {
 
271
 
272      /* no error code; did we send all the data? */
 
273      case 0:
 
274           if (partial != length) {
 
275               US_DEBUGP("-- shorttransfer/n");
 
276                return USB_STOR_XFER_SHORT;
 
277            }
 
278
 
279           US_DEBUGP("-- transfer complete/n");
 
280           return USB_STOR_XFER_GOOD;
 
281
 
282     /* stalled */
 
283     case -EPIPE:
 
284           /* for control endpoints, (used by CB[I]) astall indicates
 
285            * afailed command */
 
286           if (usb_pipecontrol(pipe)) {
 
287               US_DEBUGP("-- stall oncontrol pipe/n");
 
288                return USB_STOR_XFER_STALLED;
 
289           }
 
290
 
291           /* for other sorts of endpoint, clear thestall */
 
292           US_DEBUGP("clearing endpoint halt forpipe 0x%x/n", pipe);
 
293           if (usb_stor_clear_halt(us, pipe) < 0)
 
294                return USB_STOR_XFER_ERROR;
 
295           return USB_STOR_XFER_STALLED;
 
296
 
297      /* babble - the device tried to send morethan we wanted to read */
 
298      case -EOVERFLOW:
 
299           US_DEBUGP("-- babble/n");
 
300           return USB_STOR_XFER_LONG;
 
301
 
302      /* the transfer was cancelled by abort, disconnect,or timeout */
 
303      case -ECONNRESET:
 
304           US_DEBUGP("-- transfercancelled/n");
 
305           return USB_STOR_XFER_ERROR;
 
306
 
307      /* short scatter-gather read transfer */
 
308      case -EREMOTEIO:
 
309           US_DEBUGP("-- short readtransfer/n");
 
310           return USB_STOR_XFER_SHORT;
 
311
 
312      /* abort or disconnect in progress */
 
313      case -EIO:
 
314           US_DEBUGP("-- abort or disconnect inprogress/n");
 
315           return USB_STOR_XFER_ERROR;
 
316
 
317      /* the catch-all error case */
 
318      default:
 
319           US_DEBUGP("-- unknown error/n");
 
320           return USB_STOR_XFER_ERROR;
 
321      }
 
322 }
 
应该说这个函数的作用是一目了然,就是根据传进来的参数result进行判断,从而采取相应的行动。partial是实际传输的长度,而length是期望传输的长度,传输结束了当然要比较这两者,因为有所期待,才会失望。result是usb_stor_ msg_common()函数的返回值,其实就是状态代码。如果为0说明一切都很顺利,结果也是成功的。268这行,打印结果,同时打印出partial和length的比,注意两个%u中间那个“/”,就是除号,或者说分割分子和分母的符号。
 
然后通过一个switch语句判断result,为0,说明至少数据有传输。然后有两种情况,于是返回不同的值,USB_STOR_XFER_SHORT和USB_STOR_XFER_GOOD。至于返回这些值之后会得到什么反应,让我们边走边看。目前只需要知道的是,对于真正传输完全令人满意的情况,返回值只能是USB_STOR_XFER_GOOD。返回其他值都说明有问题。而这里作为传递给switch的result,实际上是USB Core那一层传过来的值。
 
而我们注意到,interpret_urb_result这个函数整个是被作为一个返回值出现在usb_stor_bulk_transfer_buf()中的。换而言之,前者返回之后,后者也马上就返回了,即再次返回到了usb_stor_Bulk_transport()中。因此,我们把视线拉回usb_stor_Bulk_transport(),981行,如果result不为USB_STOR_XFER_GOOD,就说明有一些问题,于是索性usb_stor_Bulk_transport()也返回,没必要再进行下一阶段的传输了。否则,才可以进行下一阶段。
 
下一个阶段是所谓的Bulk-only传输,总共就是三个阶段,即命令传输阶段、数据传输阶段、状态传输阶段。很显然,真正最有意义的阶段就是数据传输阶段,而在此之前,我们已经讲了第一阶段,即命令传输阶段。下面我们可以来看一下数据阶段。
 
989行,990行,实在没话可说,某些公司的产品在命令阶段和数据阶段居然还得延时100μs,最早时只发现了Genesys Logic公司的产品有这个问题,后来又发现更多的产品也有同样的问题。所以使用了US_FL_GO_SLOW这个flag,如果你有兴趣看一下早期的Linux Kernel,你会发现那时候其实没有这个flag,那时候定义了一个USB_VENDOR_ID_GENESYS,直接比较这个产品是不是Genesys Logic公司的,如果是的,那就考虑这个延时,否则就不用。
 
993行,transfer_length可能为0,因为有的命令并不需要您传输数据,所以它没有数据阶段。而对于那些有数据阶段的情况,我们进入if这一段。
 
994行,没什么可说的,就是根据数据传输方向确定用接收管道还是发送管道。
 
然后,996行,usb_stor_bulk_transfer_sg()函数真正地执行批量数据传输。这个函数来自drivers/usb/storage/transport.c中:
 
470 int usb_stor_bulk_transfer_sg(struct us_data*us, unsigned int pipe,
 
471                void *buf, unsigned int length_left, int use_sg, int *residual)
 
472 {
 
473     int result;
 
474     unsigned int partial;
 
475
 
476      /* are we scatter-gathering? */
 
477     if (use_sg) {
 
478           /* use the usb core scatter-gather primitives*/
 
479           result = usb_stor_bulk_transfer_sglist(us,pipe,
 
480                                 (structscatterlist *) buf, use_sg,
 
481                                 length_left,&partial);
 
482           length_left -= partial;
 
483      } else {
 
484           /* no scatter-gather, just make the request */
 
485           result = usb_stor_bulk_transfer_buf(us, pipe,buf,
 
486                                 length_left,&partial);
 
487           length_left -= partial;
 
488      }
 
489
 
490      /* store the residual and return the error code*/
 
491      if (residual)
 
492           *residual = length_left;
 
493      return result;
 
494 }
 
注释说得很清楚,这个函数是一个壳,真正干活的是它所调用或者说利用的那两个函数:usb_stor_bulk_transfer_sglist()和usb_stor_bulk_transfer_buf()。后者刚才已经遇到过了,而前者是专门为scatter-gather传输准备的函数,它也来自drivers/usb/storage/transport.c中:
 
416 static int usb_stor_bulk_transfer_sglist(structus_data *us, unsigned int pipe,
 
417                struct scatterlist *sg, int num_sg, unsigned int length,
 
418                unsigned int *act_len)
 
419 {
 
420      int result;
 
421
 
422      /*don't submit s-g requests during abort/disconnect processing */
 
423      if (us->flags &ABORTING_OR_DISCONNECTING)
 
424           return USB_STOR_XFER_ERROR;
 
425
 
426      /* initialize the scatter-gather request block*/
 
427      US_DEBUGP("%s: xfer %u Bytes, %dentries/n", __FUNCTION__,
 
428                         length, num_sg);
 
429      result = usb_sg_init(&us->current_sg,us->pusb_dev, pipe, 0,
 
430                         sg, num_sg, length,GFP_NOIO);
 
431      if (result) {
 
432           US_DEBUGP("usb_sg_init returned%d/n", result);
 
433           return USB_STOR_XFER_ERROR;
 
434      }
 
435
 
436      /* since the block has been initializedsuccessfully, it's now
 
437       * okayto cancel it */
 
438      set_bit(US_FLIDX_SG_ACTIVE,&us->flags);
 
439
 
440      /* did an abort/disconnect occur during thesubmission? */
 
441      if (us->flags &ABORTING_OR_DISCONNECTING) {
 
442
 
443           /* cancel the request, if it hasn't beencancelled already */
 
444           if (test_and_clear_bit(US_FLIDX_SG_ACTIVE,&us->flags)) {
 
445                US_DEBUGP("--cancelling sg request/n");
 
446                usb_sg_cancel(&us->current_sg);
 
447           }
 
448      }
 
449
 
450      /* wait for the completion of the transfer */
 
451      usb_sg_wait(&us->current_sg);
 
452      clear_bit(US_FLIDX_SG_ACTIVE, &us->flags);
 
453
 
454      result = us->current_sg.status;
 
455      if (act_len)
 
456           *act_len = us->current_sg.Bytes;
 
457      return interpret_urb_result(us, pipe, length,result,
 
458                         us->current_sg.Bytes);
 
459 }
 
在usb_stor_bulk_transfer_sg()函数中,判断use_sg是否为0,从而确定是否用scatter-gather。对于use_sg等于0的情况,表示不用scatter-gather,那么调用usb_stor_bulk_transfer_buf()发送scsi命令。实际传递的数据长度用partial记录,然后length_left就记录还剩下多少没传递,初值当然就是期望传递的那个长度。每次减去实际传递的长度即可。对于use_sg不等于0的情况,usb_stor_bulk_transfer_sglist()函数被调用。我们来看这个函数
(免责声明:文章内容如涉及作品内容、版权和其它问题,请及时与我们联系,我们将在第一时间删除内容,文章内容仅供参考)
收藏
  • 人气文章
  • 最新文章
  • 下载排行榜
  • 热门排行榜