`
dato0123
  • 浏览: 913701 次
文章分类
社区版块
存档分类
最新评论

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

 
阅读更多

usb_stor_Bulk_transport(), 古人一针见血的为我们指出了这个函数中调用的第一个最重要的函数,那就是usb_stor_bulk_transfer_buf().仍然是来自drivers/usb/stroage/transport.c.

409 /*
410 * Transfer one buffer via bulk pipe, without timeouts, but allowing early
411 * termination. Return codes are USB_STOR_XFER_xxx. If the bulk pipe
412 * stalls during the transfer, the halt is automatically cleared.
413 */
414 int usb_stor_bulk_transfer_buf(struct us_data *us, unsigned int pipe,
415 void *buf, unsigned int length, unsigned int *act_len)
416 {
417 int result;
418
419 US_DEBUGP("%s: xfer %u bytes/n", __FUNCTION__, length);
420
421 /* fill and submit the URB */
422 usb_fill_bulk_urb(us->current_urb, us->pusb_dev, pipe, buf, length,
423 usb_stor_blocking_completion, NULL);
424 result = usb_stor_msg_common(us, 0);
425
426 /* store the actual length of the data transferred */
427 if (act_len)
428 *act_len = us->current_urb->actual_length;
429 return interpret_urb_result(us, pipe, length, result,
430 us->current_urb->actual_length);
431 }
一路走来的同志们不会对这里这个usb_fill_bulk_urb()完全陌生.我们的确是第一次见这个函数,但是此前我们有见过usb_fill_control_urb(),除此之外还有一个叫做usb_fill_int_urb()的函数,不用说,这几个函数是差不多的,只不过她们分别对应usb传输模式中的bulk,control,interrupt.唯一一处和usb_fill_control_urb不同的便是bulk传输不需要有一个setup_packet.具体来看,usb_fill_bulk_urb()定义于include/linux/usb.h:

845 /**
846 * usb_fill_bulk_urb - macro to help initialize a bulk urb
847 * @urb: pointer to the urb to initialize.
848 * @dev: pointer to the struct usb_device for this urb.
849 * @pipe: the endpoint pipe
850 * @transfer_buffer: pointer to the transfer buffer
851 * @buffer_length: length of the transfer buffer
852 * @complete: pointer to the usb_complete_t function
853 * @context: what to set the urb context to.
854 *
855 * Initializes a bulk urb with the proper information needed to submit it
856 * to a device.
857 */
858 static inline void usb_fill_bulk_urb (struct urb *urb,
859 struct usb_device *dev,
860 unsigned int pipe,
861 void *transfer_buffer,
862 int buffer_length,
863 usb_complete_t complete,
864 void *context)
865 {
866 spin_lock_init(&urb->lock);
867 urb->dev = dev;
868 urb->pipe = pipe;
869 urb->transfer_buffer = transfer_buffer;
870 urb->transfer_buffer_length = buffer_length;
871 urb->complete = complete;
872 urb->context = context;
873 }

看过了那个usb_fill_control_urb之后看这个函数应该是很简单的了.结合上面调用这个函数的代码,可知,urb->complete被赋值为usb_stor_blocking_completion,不用说,这个函数之后肯定会被调用.正如上次控制传输中所讲的那样.

424,usb_stor_msg_common()这个函数再一次被调用,年年岁岁花相似,岁岁年年人不同,urb还像上次那样被被提交,然后核心层去调度,去执行她.如果结果是提交成功了,那么返回值result将是0.act_len将记录实际传输的长度.不过光看这两个函数其实看不出什么,我们必须结合上下文来看.换句话说,我们需要结合usb_stor_Bulk_transport()usb_stor_bulk_transfer_buf被调用的上下文,对比形参和实参来看,才能真的明白,才能拨开这浓浓的迷雾.

usb_stor_Bulk_transport()函数中,978,usb_stor_bulk_transfer_buf()函数得到调用.第一个参数,us,无需多说,第二个参数,us->send_bulk_pipe,作为u盘来说,她除了有一个控制管道以外,还会有两个bulk管道,一个是In,一个是Out,经历过此前的风风雨雨,咱们已经对usb中那些名词不再有神秘感,所谓管道无非就是一个unsigned int类型的数.us->send_bulk_pipe和接下来我们立刻会邂逅的us->recv_bulk_pipe都是在曾经那个令人回味的storage_probe()中调用get_pipes()函数获得的.然后第三个参数bcb,这是什么玩艺?嘿嘿,看仔细了.

950,定义了这么一个指针bcb,struct bulk_cb_wrap结构体的指针,这是一个专门为bulk only协议特别准备的数据结构,来自drivers/usb/storage/transport.h:

80 /*
81 * Bulk only data structures
82 */
83
84 /* command block wrapper */
85 struct bulk_cb_wrap {
86 __le32 Signature; /* contains 'USBC' */
87 __u32 Tag; /* unique per command id */
88 __le32 DataTransferLength; /* size of data */
89 __u8 Flags; /* direction in bit 0 */
90 __u8 Lun; /* LUN normally 0 */
91 __u8 Length; /* of of the CDB */
92 __u8 CDB[16]; /* max command */
93 };

眼疾手快的同志们一定已经看到,同一文件中还定义了另一个数据结构,struct bulk_cs_wrap,

100 /* command status wrapper */
101 struct bulk_cs_wrap {
102 __le32 Signature; /* should = 'USBS' */
103 __u32 Tag; /* same as original command */
104 __le32 Residue; /* amount not transferred */
105 __u8 Status; /* see below */
106 __u8 Filler[18];
107 };

这两个数据结构对应于江湖中传说的CBWCSW,command block wrappercommand status wrapper.事到如今,咱们需要关注一下usb mass storage bulk only transport协议了,因为u盘是按照这个协议规定的方式去传输数据的,Bulk only传输方式是这样进行的,首先由host给设备发送一个CBW,然后device接收到了CBW,她会进行解释,然后按照CBW里定义的那样去执行她该做的事情,然后她会给host返回一个CSW.CBW实际上是命令的封装包,CSW实际上是状态的封装包.(命令执行后的状态,成功,失败,浪里看不出有未有...所以需要使用这么一个状态包). 至于你说为啥要把命令以及反映命令执行成功与否的状态包装起来,那很简单, 包装是房子富丽堂皇的外壳,包装是丑妇手上绚丽的太阳伞,包装是模特在舞台上走出的一字猫步.爱美之心人皆有之,设计spec的人也不例外.

这时候我们就可以看看usb_stor_Bulk_transport()函数中,调用usb_stor_bulk_transfer_buf()之前的那几行究竟在干嘛了.很明显,这些行都是在为usb_stor_bulk_transfer_buf()这个函数调用做准备,对应于那些三级片中的前戏,真正精彩的部分还是在usb_stor_bulk_transfer_buf(),但前戏的存在必然是合理的,毕竟,子曾经曰过:没有激情的拥吻,何来床上的翻滚.所以我们来具体看看这部分前戏.(,沦为今天这样一个优秀的大学生,不能怪复旦,主要是自己没有坚强的意志品质啊!)

950,struct bulk_cb_wrap *bcb,赋值为(struct bulk_cb_wrap *) us->iobuf,951,struct bulk_cs_wrap *bcs,也赋值为(struct bulk_cb_wrap *) us->iobuf,然后定义一个unsigned int的变量transfer_length,赋值为srb->request_bufflen.然后接下来就开始为bcb的各成员赋值了.我们不妨看一下usb mass storage spec中的两张图片,一张是CBW的格式,一张是CSW的格式,

<shapetype id="_x0000_t75" stroked="f" filled="f" path="m@4@5l@4@11@9@11@9@5xe" o:preferrelative="t" o:spt="75" coordsize="21600,21600"><stroke joinstyle="miter"></stroke><formulas><f eqn="if lineDrawn pixelLineWidth 0"></f><f eqn="sum @0 1 0"></f><f eqn="sum 0 0 @1"></f><f eqn="prod @2 1 2"></f><f eqn="prod @3 21600 pixelWidth"></f><f eqn="prod @3 21600 pixelHeight"></f><f eqn="sum @0 0 1"></f><f eqn="prod @6 1 2"></f><f eqn="prod @7 21600 pixelWidth"></f><f eqn="sum @8 21600 0"></f><f eqn="prod @7 21600 pixelHeight"></f><f eqn="sum @10 21600 0"></f></formulas><path o:connecttype="rect" gradientshapeok="t" o:extrusionok="f"></path><lock aspectratio="t" v:ext="edit"></lock></shapetype><shape id="_x0000_i1025" style="WIDTH: 415.2pt; HEIGHT: 198pt" type="#_x0000_t75"><imagedata o:title="" src="file:///C:/DOCUME~1/JASON_~1/LOCALS~1/Temp/msohtml1/02/clip_image001.emz"></imagedata></shape>

这是CBW,

<shape id="_x0000_i1026" style="WIDTH: 414.6pt; HEIGHT: 159pt" type="#_x0000_t75"><imagedata o:title="" src="file:///C:/DOCUME~1/JASON_~1/LOCALS~1/Temp/msohtml1/02/clip_image003.emz"></imagedata></shape>

而这,就是CSW.

959, bcb->Signature=cpu_to_le32(US_BULK_CB_SIGN),Signature对应usb mass storage specCBW的前四个bytes,dCBWSignature,US_BULK_CB_SIGN这个宏定义于drivers/usb/storage/transport.h,

96 #define US_BULK_CB_SIGN 0x43425355 /*spells out USBC */

也不知道是哪个傻X规定的,只有把dCBWSignature里边写上43425355h才能标志着个数据包是一个CBW.另外,CBW的传输全是遵守little endian,所以cpu_to_le32()这个宏需要使用,来转换数据格式.

然后bcb->DataTransferLength对应CBW中的dCBWDataTransferLength.这个就是标志host希望这个endpoint传输多少个bytes的数据.这里把cpu_to_le32(transfer_length)赋给了她.transfer_length刚才已经说了,就是srb->request_bufflen. 其实这几个变量名换来换去最重要记录的还是同一样东西.

bcb->Flags,对应于CBW中的bmCBWFlags,bcb->Flags = srb->sc_data_direction == DMA_FROM_DEVICE ? 1 << 7 : 0;这个表明的是数据传输的方向,DMA_FROM_DEVICE咱们前面讲过,表示数据是从设备传向主存.bmCBWFlags8位的,其中bit7表示方向,0表示Data-Out,from host to the device,1表示Data-in,from the device to the host.所以这里如果是1的话要左移7.

bcb->Tag = srb->serial_number,这个Tag对应CBW中的dCBWTag,这个dCBWTag的意义在于,hostsend出去,device将会把这个Tag的内容给打印出来,确切的说,device会回送一个CSW回来,而在CSW中会有一个dCSWTag,她的内容和这个dCBWTag是一样的,所以实际上这就跟接头暗号似的.每一个scsi命令都会被赋上一个serial_number,这里把她用在了Tag.

bcb->Lun = srb->device->lun,很简单,对应CBW中的bCBWLUN,就是表征这个命令是发给哪个LUN,我们知道一个设备如果支持多个LUN,那么显然每个LUN会有一个编号.比如咱们要读写u盘上的某个分区,那么当然得指明是哪个分区了.如果设备不支持多个lun,那么这儿会被设置为0.不过需要注意,这里bcb->LunCBW中的bCBWLUN并不完全对应,bCBWLUN只有4bit,而咱们这里定义的时候,Lun是有8位的,低四位用来对应bCBWLUN,而高四位实际上是用来表征target id.所以接下来判断us->flags里边设了US_FL_SCM_MULT_TARG这个标志没有,如果有,说明是支持多个target,于是就要记录下是哪个target.

bcb->Length = srb->cmd_len,这个对应于CBW中的bCBWCBLength,即命令的有效长度,单位是bytes. scsi命令的有效长度只能是116之间.接下来有个CDB数组,数组共16个元素,理由咱们刚才讲struct scsi_cmnd中的cmnd就已经说过了.969,970行正是把命令srb->cmnd数组的内容copybcb->CDB.

这时候,前戏结束了,usb_stor_bulk_transfer_buf正式被调用了.传递给她的第三个参数正是bcb,而第四个参数是US_BULK_CB_WRAP_LEN,她也是定义于drivers/usb/storage/transport.h,

95 #define US_BULK_CB_WRAP_LEN 31
31就是CBW的长度,CBW正是31bytes.usb_stor_bulk_transfer_buf的所作所为咱们是非常清楚地,无非就是提交这么一个urb,然后就不用管事了,就等结果呗.而最终的result是由interpret_urb_result()返回的,传输正确那么会返回USB_STOR_XFER_GOOD,而如果不正确,那么usb_stor_Bulk_transport()中就直接返回了,返回值是USB_STOR_TRANSPORT_ERROR.如果正确,那么继续往下走,这才到真正的数据传输阶段. 在真正开始将数据传输阶段之前,我们先来看看interpret_urb_result()函数.

分享到:
评论

相关推荐

    Linux那些事儿之我是U盘

    Linux那些事儿之我是U盘

    Linux那些事儿之我是U盘.pdf

    Linux那些事儿之我是U盘-有书签版.pdf

    Linux那些事儿

    Linux那些事儿之我是U盘 Linux那些事儿之我是Hub Linux那些事儿之我是USB Core Linux那些事儿之我是UHCI Linux那些事儿之我是EHCI控制器 Linux那些事儿之我是PCI Linux那些事儿之我是SCSI硬盘 Linux那些事儿之我是...

    Linux那些事儿1-9合集

    读过《linux那些事儿之我是U盘》的人,都知道其风格,我就不多说了。 导读: linux那些事儿之我是U盘 linux那些事儿之我是HUB linux那些事儿之我是USB Core linux那些事儿之我是UHCI Linux那些事儿之我是EHCI主机控制...

    Linux那些事儿之全集

    导读.doc Linux那些事儿之我是Block层.pdf Linux那些事儿之我是EHCI主机控制器.pdf Linux那些事儿之我是Hub.pdf Linux那些事儿之我是USB_core.pdf Linux那些事儿之我是U盘.pdf等等 Linux那些事儿系列全在这里了

    Linux那些事儿系列.rar

    》包括《Linux那些事儿之我是Hub》、《Linux那些事儿之我是Sysfs》《Linux那些事儿之我是UHCI》、《Linux那些事儿之我是USB core》、《Linux那些事儿之我是U盘》,令人叹为观止的一个linux系列书籍。只能说,江山代...

    Linux那些事儿(linux内核写的很详细)

    Linux那些事儿 Linux那些事儿之我是Block层 Linux那些事儿之我是Sysfs Linux那些事儿之我是U盘

    Linux那些事儿之我是USB(第2版).pdf

    本书基于2.6.22内核,对USB子系统的大部分源代码逐行进行分析,系统地阐释了Linux内核中USB子系统是如何运转的,子系统内部的各个模块之间是如何互相协作、配合的。本次改版修改了第1版中出现的错误,增加了一个附录...

    Linux那些事儿之我是Hub

    Linux那些事儿之我是Hub,是前面Linux那些事之我是U盘,usb等的姐妹篇

    linux那些事儿之我是U盘

    深入浅出学linux,linux那些事儿系列之我是U盘

    linux的那些事儿全集

    Linux那些事儿之我是Block层 Linux那些事儿之我是EHCI主机控制器 Linux那些事儿之我是Hub Linux那些事儿之我是PCI Linux那些事儿之我是SCSI硬盘 Linux那些事儿之我是Sysfs ...Linux那些事儿之我是U盘

    linux那些事全集

    Linux那些事儿之我是U盘 Linux那些事儿之我是USB_core Linux那些事儿之我是UHCI Linux那些事儿之我是Sysfs Linux那些事儿之我是SCSI硬盘 Linux那些事儿之我是PCI Linux那些事儿之我是Hub Linux那些事儿之我是EHCI...

    Linux那些事儿之我是XXX全集.rar

    Linux那些事儿之我是XXX全集 包含USB core U盘 UHCI PCI SCSI硬盘 Block Hub EHCI 。 想学驱动的童鞋,不妨看看。该书主要是进行源代码的分析

    Linux那些事儿 系列之2 Block+EHCI+PCI+SCSI

    Linux那些事儿之我是Block层.pdf Linux那些事儿之我是EHCI主机控制器.pdf Linux那些事儿之我是PCI.pdf Linux那些事儿之我是SCSI硬盘.pdf 注: 之前有人已经上传了《Linux那些事儿 系列》,其已经包含了:hub,sysfs...

Global site tag (gtag.js) - Google Analytics