【转】Linux那些事儿之我是U盘(46)迷雾重重的Bulk传输(四)

时间:2022-04-05 14:34:09
在讲数据传输阶段之前 , 先解决刚才的历史遗留问题 . usb_stor_bulk_transfer_buf() ,429 , 有一个很有趣的函数 interpret_urb_result() 被调用 . 这个函数同样来自 drivers/usb/storage/transport.c:

277 /*
    278  * Interpret the results of a URB transfer
    279  *
    280  * This function prints appropriate debugging messages, clears halts on
    281  * non-control endpoints, and translates the status to the corresponding
    282  * USB_STOR_XFER_xxx return code.
    283  */
    284 static int interpret_urb_result(struct us_data *us, unsigned int pipe,
    285                 unsigned int length, int result, unsigned int partial)
    286 {
    287         US_DEBUGP("Status code %d; transferred %u/%u/n",
    288                         result, partial, length);
    289         switch (result) {
    290
    291         /* no error code; did we send all the data? */
    292         case 0:
    293                 if (partial != length) {
    294                         US_DEBUGP("-- short transfer/n");
    295                         return USB_STOR_XFER_SHORT;
    296                 }
    297
    298                 US_DEBUGP("-- transfer complete/n");
    299                 return USB_STOR_XFER_GOOD;
    300
    301         /* stalled */
    302         case -EPIPE:
    303                 /* for control endpoints, (used by CB[I]) a stall indicates
    304                  * a failed command */
    305                 if (usb_pipecontrol(pipe)) {
    306                         US_DEBUGP("-- stall on control pipe/n");
    307                         return USB_STOR_XFER_STALLED;
    308                 }
    309
    310                 /* for other sorts of endpoint, clear the stall */
    311                 US_DEBUGP("clearing endpoint halt for pipe 0x%x/n", pipe);
    312                 if (usb_stor_clear_halt(us, pipe) < 0)
    313                         return USB_STOR_XFER_ERROR;
    314                 return USB_STOR_XFER_STALLED;
    315
    316         /* timeout or excessively long NAK */
    317         case -ETIMEDOUT:
    318                 US_DEBUGP("-- timeout or NAK/n");
    319                 return USB_STOR_XFER_ERROR;
    320
    321         /* babble - the device tried to send more than we wanted to read */
    322         case -EOVERFLOW:
    323                 US_DEBUGP("-- babble/n");
    324                 return USB_STOR_XFER_LONG;
    325
    326         /* the transfer was cancelled by abort, disconnect, or timeout */
    327         case -ECONNRESET:
    328                 US_DEBUGP("-- transfer cancelled/n");
    329                 return USB_STOR_XFER_ERROR;
    330
    331         /* short scatter-gather read transfer */
    332         case -EREMOTEIO:
    333                 US_DEBUGP("-- short read transfer/n");
    334                 return USB_STOR_XFER_SHORT;
    335
    336         /* abort or disconnect in progress */
    337         case -EIO:
    338                 US_DEBUGP("-- abort or disconnect in progress/n");
    339                 return USB_STOR_XFER_ERROR;
    340
    341         /* the catch-all error case */
    342         default:
    343                 US_DEBUGP("-- unknown error/n");
    344                 return USB_STOR_XFER_ERROR;
    345         }
    346 }

应该说这个函数的作用是一目了然的.就是根据传进来的参数result进行判断,从而采取相应的行动.partial是实际传输的长度,length是期望传输的长度,传输结束了当然要比较这两者,因为有所期待,才会失望.resultusb_stor_msg_common()函数的返回值,其实就是状态代码,如果为0说明一切都很顺利,结果也是成功的,287这行,打印出result,同时打印出partiallength的比,注意两个%u中间那个”/”,就是除号,或者说分割分子和分母的符号.然后通过一个switch语句判断result,0,说明至少数据有传输,然后有两种情况,于是返回不同的值,一个是USB_STOR_XFER_SHORT,另一个是USB_STOR_XFER_GOOD.至于返回这些值之后会得到什么反应,让我们边走边看.目前只需要知道的是,对于真正传输完全令人满意的情况,返回值只能是USB_STOR_XFER_GOOD.返回其它值都说明有问题.而这里作为传递给switchresult,实际上是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,实在没话可说,USB_VENDOR_ID_GENESYS代表某公司,这公司的产品在命令阶段和数据阶段居然还得延时100微秒.没办法,谁要我们生活在一个宣扬个性的时代呢.体谅他们吧,没有哪一种胭脂能涂抹时间,没有哪一件服装能掩饰灵魂,没有哪一套古籍能装潢空虚,没有哪一家公司能说自己的产品是完美的,是没有缺陷的.

  992,transfer_length可能为0,因为有的命令她并不需要您传输数据,所以她没有数据阶段.而对于那些有数据阶段的情况,咱们进入if这一段.

  993,没什么可说的,就是根据数据传输方向确定用接收pipe还是发送pipe.

  然后,995,usb_stor_bulk_transfer_sg()这个函数是真正的执行bulk数据传输了.这个函数来自drivers/usb/storage/transport.c:

484 /*
    485  * Transfer an entire SCSI command's worth of data payload over the bulk
    486  * pipe.
    487  *
    488  * Note that this uses usb_stor_bulk_transfer_buf() and
    489  * usb_stor_bulk_transfer_sglist() to achieve its goals --
    490  * this function simply determines whether we're going to use
    491  * scatter-gather or not, and acts appropriately.
    492  */
    493 int usb_stor_bulk_transfer_sg(struct us_data* us, unsigned int pipe,
    494                 void *buf, unsigned int length_left, int use_sg, int *residual)
    495 {
    496         int result;
    497         unsigned int partial;
    498
    499         /* are we scatter-gathering? */
    500         if (use_sg) {
    501                 /* use the usb core scatter-gather primitives */
    502                 result = usb_stor_bulk_transfer_sglist(us, pipe,
    503                                 (struct scatterlist *) buf, use_sg,
    504                                 length_left, &partial);
    505                 length_left -= partial;
    506         } else {
    507                 /* no scatter-gather, just make the request */
    508                 result = usb_stor_bulk_transfer_buf(us, pipe, buf,
    509                                 length_left, &partial);
    510                 length_left -= partial;
    511         }
    512
    513         /* store the residual and return the error code */
    514         if (residual)
    515                 *residual = length_left;
    516         return result;
    517 }

注释说得很清楚,这个函数是一个壳,真正干活的是她所调用或者说利用的那两个函数.usb_stor_bulk_transfer_sglist()usb_stor_bulk_transfer_buf().后者咱们刚才已经遇到过了,而前者是专门为scatter-gather传输准备的函数,她也来自drivers/usb/storage/transport.c:

    433 /*
    434  * Transfer a scatter-gather list via bulk transfer
    435  *
    436  * This function does basically the same thing as usb_stor_bulk_transfer_buf()
    437  * above, but it uses the usbcore scatter-gather library.
    438  */
    439 int usb_stor_bulk_transfer_sglist(struct us_data *us, unsigned int pipe,
    440                 struct scatterlist *sg, int num_sg, unsigned int length,
    441                 unsigned int *act_len)
    442 {
    443         int result;
    444
    445         /* don't submit s-g requests during abort/disconnect processing */
    446         if (us->flags & ABORTING_OR_DISCONNECTING)
    447                 return USB_STOR_XFER_ERROR;
    448
    449         /* initialize the scatter-gather request block */
    450         US_DEBUGP("%s: xfer %u bytes, %d entries/n", __FUNCTION__,
    451                         length, num_sg);
    452         result = usb_sg_init(&us->current_sg, us->pusb_dev, pipe, 0,
    453                         sg, num_sg, length, SLAB_NOIO);
    454         if (result) {
    455                 US_DEBUGP("usb_sg_init returned %d/n", result);
    456                 return USB_STOR_XFER_ERROR;
    457         }
    458
    459         /* since the block has been initialized successfully, it's now
    460          * okay to cancel it */
    461         set_bit(US_FLIDX_SG_ACTIVE, &us->flags);
    462
    463         /* did an abort/disconnect occur during the submission? */
    464         if (us->flags & ABORTING_OR_DISCONNECTING) {
    465
    466                 /* cancel the request, if it hasn't been cancelled already */
    467                 if (test_and_clear_bit(US_FLIDX_SG_ACTIVE, &us->flags)) {
    468                         US_DEBUGP("-- cancelling sg request/n");
    469                         usb_sg_cancel(&us->current_sg);
    470                 }
    471         }
    472
    473         /* wait for the completion of the transfer */
    474         usb_sg_wait(&us->current_sg);
    475         clear_bit(US_FLIDX_SG_ACTIVE, &us->flags);
    476
    477         result = us->current_sg.status;
    478         if (act_len)
    479                 *act_len = us->current_sg.bytes;
    480         return interpret_urb_result(us, pipe, length, result,
    481                         us->current_sg.bytes);
    482 }
  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()函数被调用.我们来看这个函数.