首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

Linux那些事儿之我是Hub(9)While You Were Sleeping(二)

Linux那些事儿之我是Hub(9)While You Were Sleeping(二)

老实说,从函数一个开始的598行直到627行都没有什么可说的.其中需要一提的是,606,调用usb_buffer_alloc()申请内存,赋给hub->buffer.614,调用kmalloc()申请内存,赋给hub->status.622,调用kmalloc()申请内存,赋给hub->descriptor.当然也别忘了这中间的某行,初始化一把互斥锁,hub->status_mutex.以后咱们会用得着的,到时候我们就会看到mutex_lock/mutex_unlock()这么一对函数来获得互斥锁/释放互斥锁.不过这把锁用得不多,总共也就两个函数里调用了.咱们走着瞧.
633,get_hub_descriptor().应该说,从这一刻起,我们将跨入一个新的时代,这一行是里程碑的一行,其意义就好比1992年有一位老人在中国的南海边画了一个圈,其重要性是不言而喻的.这一行,带领我们步入了hub协议.从此摆在我们面前的将不仅仅是usb协议本身了,又加了另一座大山,那就是hub协议,其实hub协议也算usb协议,但是由于hub作为一种特殊的usb设备,usb spec,专门有一章是关于hub,而这一章有150多页.这就是usb spec 2.0中的第十一章.简明起见,下面我将把这一章称作hub协议.而接下来我们的一言一行,都必须遵守hub协议了.,先看get_hub_descriptor,这就是发送一个request,或者说一个控制传输的控制请求,以获得hub的描述符.基本上hub驱动的这些函数,大多都是来自drivers/usb/core/hub.c:
    137 /* USB 2.0 spec Section 11.24.4.5 */
    138 static int get_hub_descriptor(struct usb_device *hdev, void *data, int size)

139 {

    140         int i, ret;
    141
    142         for (i = 0; i < 3; i++) {
    143                 ret = usb_control_msg(hdev, usb_rcvctrlpipe(hdev, 0),

144                         USB_REQ_GET_DESCRIPTOR, USB_DIR_IN | USB_RT_HUB,

    145                         USB_DT_HUB << 8, 0, data, size,
    146                         USB_CTRL_GET_TIMEOUT);
    147                 if (ret >= (USB_DT_HUB_NONVAR_SIZE + 2))
    148                         return ret;
    149         }
    150         return -EINVAL;
151 }
看过usb-storage的你,一定能看懂这个函数,不过有一点我说出来一定会让你吃惊,usb_control_msg()是我们第一次遇到,不信的话可以回去查一下,usb-storage里面根本没有用到这个函数,事实上usb-storage里面自己写了这么一个函数,叫做usb_stor_control_msg().理由是,usb_control_msg()不允许你在调用这个函数的时候取消一个request,而在usb-storage里我们经常做这样的事情,或者说我们有这样的需求,那么我们当然就得自己写一个函数了.不过hub里面没这么多乱七八糟的需求,插拔U盘是一件很正常的事情,可是你说谁没事总是插拔hub?吃多了哈药六厂的新盖中盖吗?
不过有一个好消息,usb_control_msg和我们讲过的usb_stor_control_msg的参数是一模一样的,所以我们无需再多说.每一个request怎么设置都是在spec里边规定的.对于GET_DESCRIPTOR这个request,如图所示:

hub spec规定, bmRequestType必须是10100000B,normally,GET_DESCRIPTOR的时候,bmRequestType应该等于10000000B.D7为方向位,1就说明时Device-to-host,IN,D6…5这两位表示Request的类型,可以是标准的类型,或者是Class特定的,或者是Vendor特定的,01就表示Class特定的.D4…0表示接受者,可以是设备,可以是接口,可以是端点.这里为0表示接收者是设备.(这里就体现了相同的request,不同的requesttype的意义了.)
USB_DT_HUB等于29,hub spec规定GET_DESCRIPTOR这个请求的wValue就该是Descriptor TypeDescriptor Index,wValue作为一个word,16,所以高8位放Descriptor Type,而低8位放Descriptor Index,usb 2.0 spec 11.24.2.10里规定了,hub descriptordescriptor index必须为0.而实际上,usb spec 9.4.3里也规定了,对于非configuration descriptorstring descriptor的其他几种标准descriptor,descriptor index必须为0.而对于configuration descriptorstring descriptor来说,这个descriptor index用来表征他们的编号,比如一个设备可以有多个configuration descriptor.编号从0开始.所以对于hub descriptor来说,wValue就是高8位表示Descriptor Type,而低8位设成0就可以了.这就是为什么”<<8”,Descriptor Type,specTable 9-5定义了各种Descriptortype,如图:

比如Device1,Configuration2,hub这里规定了,它的Descriptor type29h.USB_DT_HUB=(USB_TYPE_CLASS|0x09),USB_TYPE_CLASS就是0x01<<5.所以这里USB_DT_HUB就是0x29,29h,至于他为什么不直接写成29h那就只有天知道了.也许写代码的人想故意迷惑一下读代码的人吧,因为事实上usb 2.0 spec里边很清楚地直接用29h来表示hubdescriptor type,根本不存在两个咚咚的组合.这样写代码完全是对广大观众的不负责,你说我们是不是该鄙视一下这些写代码的同志.
USB_CTRL_GET_TIMEOUT是一个宏,值为5000,即表示5秒超时.
USB_DT_HUB_NONVAR_SIZE也是一个宏,值为7,为啥为7?首先请你明白,我们这里要获得的是hub descriptor,这是只有hub才有的一个descriptor,就是说对于hub来说,除了通常的usb设备有的那些设备描述符,接口描述符,端点描述符以外,hub spec自己也定义了一个描述符,这就叫hub描述符.hub描述符的前7个字节是固定的,表示什么意思也是确定的,但从第八个字节开始,一切就都充满了变数.所以前7个字节被称为非变量,NON-Variable,而从第7个开始以后的被称为变量,Variable.这些变量取决于hub上面端口的个数.所谓的变量不是说字节的内容本身是变化的,而是说descriptor具体有几个字节是变化的,比如hub上面有两个端口,那么这个hubdescriptor的字节数和hub上面有4个端口的情况就是不一样的,显然,有四个端口就要纪录更多的信息,当然描述符里的内容就多一些,从而描述符的字节长度也不一样,这超好理解.usb_control_msg()如果执行成功,那么返回值将是成功传输的字节长度,对这里来说,就是传输的hub描述符的字节长度.结合hub spec来看,这个长度至少应该是9,所以这里判断如果大于等于9,那就返回.当然你要问为什么这里要循环三次,这是为了防止通信错误.hub驱动中很多地方都这样做了,主要是因为很多设备在发送它们的描述符的时候总是出错.所以咱们没辙了,多试几次呗.
返回列表