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

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

一切都在发展变化,不断地向昨天告别,满怀信心地投入每一个崭新的今天。

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

相关文章:

你感兴趣的文章:

标签云: