您的位置:首页 > 运维架构 > Linux

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

2007-07-31 02:21 621 查看
在讲数据传输阶段之前,先解决刚才的历史遗留问题. 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是期望传输的长度,传输结束了当然要比较这两者,因为有所期待,才会失望.result是usb_stor_msg_common()函数的返回值,其实就是状态代码,如果为0说明一切都很顺利,结果也是成功的,287这行,打印出result来,同时打印出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行,实在没话可说,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()函数被调用.我们来看这个函数.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐