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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值