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

在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 };

这两个数据结构对应于江湖中传说的CBW和CSW,即command block wrapper和command 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的格式,

这是CBW,

而这,就是CSW.

959行, bcb->Signature=cpu_to_le32(US_BULK_CB_SIGN),Signature对应usb mass storage spec中CBW的前四个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咱们前面讲过,表示数据是从设备传向主存.而bmCBWFlags是8位的,其中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的意义在于,host会send出去,而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->Lun和CBW中的bCBWLUN并不完全对应,bCBWLUN只有4个bit,而咱们这里定义的时候,Lun是有8位的,低四位用来对应bCBWLUN,而高四位实际上是用来表征target id的.所以接下来判断us->flags里边设了US_FL_SCM_MULT_TARG这个标志没有,如果有,说明是支持多个target的,于是就要记录下是哪个target.

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

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

95 #define US_BULK_CB_WRAP_LEN 3131就是CBW的长度,CBW正是31个bytes.而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盘(45)迷雾重重的Bulk传输(三) – fudan

相关文章:

你感兴趣的文章:

标签云: