在讲数据传输阶段之前,先解决刚才的历史遗留问题。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()函数被调用。我们来看这个函数。

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

  1. 《Linux那些事儿之我是USB》我是U盘(37)迷雾重重的批量传输(六)

    usb_stor_bulk_transfer_sglist()函数有一定的"蛊惑性",我们前面说过,之所以采用sglist,就是为了提高传输效率.我们更知道,sg的目的就是让一堆不 ...

  2. 《Linux那些事儿之我是USB》我是U盘(34)迷雾重重的批量传输(三)

    在usb_stor_Bulk_transport()中,这个函数中调用的第一个最重要的函数,那就是usb_stor_bulk_transfer_buf().仍然是来自drivers/usb/stroa ...

  3. 《Linux那些事儿之我是USB》我是U盘(33)迷雾重重的批量传输(二)

    其实故事已经讲了很久,但如果你觉得到这里你已经把故事都看明白了,那么你错了.不仅仅是错了.不信,我们就继续看,先看512行,us->transport(),这个函数指针同样是在storage_p ...

  4. 《Linux那些事儿之我是USB》我是U盘(35)迷雾重重的批量传输(四)

    有时候我也被这个问题所困扰,我不知道是我不明白,还是这世界变化太快.连Linux中都引入了过期这么一个概念.设置一个时间,如果时间到了该做的事情还没有做完,那么某些事情就会发生. 比如需要烤蛋糕,现在 ...

  5. 《Linux那些事儿之我是USB》我是U盘(32)迷雾重重的批量传输(一)

    374行,us->proto_handler()其实是一个函数指针,知道它指向什么吗?我们早在storage_probe()中,确切地说,在get_protocol()就赋了值,当时只知道是ge ...

  6. Linux那些事儿 之 戏说USB(3)我是一棵树

    从拓扑上来看,USB子系统并不以总线的方式来部署,它是一颗由几个点对点的连接构成的树. 它主要包括了USB连接.USB host controller和USB device三个部分.而USB devi ...

  7. Linux那些事儿 之 戏说USB(22)设备的生命线(五)

    下面接着看那三个基本点. 第一个基本点,usb_alloc_urb函数,创建urb的专用函数,为一个urb申请内存并做初始化,在drviers/usb/core/urb.c里定义. struct ur ...

  8. Linux那些事儿 之 戏说USB(15)设备

    struct usb_device结构冗长而又杂乱 include/linux/usb.h struct usb_device {int devnum;char devpath[16];u32 rou ...

  9. Linux那些事儿 之 戏说USB(25)设备的生命线(四)

    转载地址:http://blog.csdn.net/fudan_abc/article/details/1819919 洗澡是屁股享福,脑袋吃苦:看电影是脑袋享福,屁股吃苦:看内核代码是脑袋.屁股都吃 ...

最新文章

  1. matlab两个多项式相除,C++和MATLAB混合编程求解多项式系数(矩阵相除)
  2. 【软考】信息系统项目管理师--知识点
  3. notepad++默认的快捷键整理
  4. Java基础篇:static关键字
  5. 我的LINUX学习之路之二十一之web服务器简单搭建
  6. linux携带密码登录其他远程机
  7. 学习Unix其实就这样简单
  8. 怎么判断子元素距离父元素顶部位置_css子元素如何相对父元素定位?
  9. 再见, VS Code !你好,GitHub!
  10. 史上最详细的宝塔部署java项目流程
  11. 腾讯管家中的壁纸无下载按钮,如何保存?
  12. RNA甲基化修饰种类
  13. EXIF 方向参数 Orientation
  14. Windows11图片密码的设置方法(用喜欢的图片作为开机密码)
  15. Mysql事务隔离与Spring
  16. LMG3410R050功率放大级解决方案
  17. 软考高项必考的PV、EV、AC、SV、CV、SPI、CPI看这就够了
  18. 18.鸡尾酒疗法C语言
  19. 修改linux服务器nls_lang,Oracle下服务端字符集修改
  20. 计算机毕业设计(81)php小程序毕设作品之校园跑腿小程序系统

热门文章

  1. 维也纳国际酒店11家门店陆续开业,加速布局中高端酒店市场
  2. 萌宠大作战服务器维护,萌宠大作战
  3. qt客户端显示服务器发送的图片,c++ - Qt客户端服务器应用程序“发送图像”出现问题 - 堆栈内存溢出...
  4. 03. Vuepress1.x 设置 favicon.ico 图标
  5. 机油MEMS压力传感器助力汽车产业智能化升级
  6. 足球世界中最明亮的一颗星——C罗
  7. Cadence如何导出PDF文件?Cadence导出PDF文件流程
  8. 1069 微博转发抽奖 (20分)
  9. 2022年G3锅炉水处理考试及G3锅炉水处理考试资料
  10. 多数据源和es版本问题