Linux那些事儿 之 戏说USB(17)接口是设备的接口(二)

  • Post author:
  • Post category:linux



最近看了一些韩国的反转剧,什么是反转剧?就是影片儿演到一半时如果让你猜最后的结局,十有八九都会出乎你的预料。虽然每片只有短短20多分钟,但论故事情节,比咱们的帘子幽梦之类的梦了几十集还不知道做啥的精彩的多。


咱们在生活中是不会有这般戏剧性的反转和悬念的,有的只是吃饭的人生,上班的人生,睡觉的人生。思源湖边做了多少次的白日梦毕业时就被扔到了湖水里,然后我们从平淡走向平庸。

不过这里还是有点小悬念的,前面struct usb_interface里表示接口设置的struct usb_host_interface就被有意无意的飘过了,咱们在这里看看它的真面目,同样在include/linux/usb.h文件里定义。




69




/* host-side wrapper for one interface setting’s parsed descriptors */





73




/* array of desc.bNumEndpoint endpoints associated with this





74




* interface setting. these will be in no particular order.





75




*/





76




struct




usb_host_endpoint




*endpoint;





78




char *




string




;           /* iInterface string, if present */





79




unsigned char *extra;   /* Extra descriptors */





80




int extralen;





81




};


71行,desc,接口的描述符。什么叫描述符?我们的生活就是一个不断的遇到人认识人的过程,有些人注定只是擦肩而过,有些人却深深的留在我们的内心里,比如USB的描述符。实际上,usb的描述符是一个带有预定义格式的数据结构,里面保存了usb设备的各种属性还有相关信息,姓甚名谁啊,哪儿生产的啊等等,我们可以通过向设备请求获得它们的内容来深刻的了解感知一个usb设备。主要有四种usb描述符,设备描述符,配置描述符,接口描述符和端点描述符,协议里规定一个usb设备是必须支持这四大描述符的,当然也有其它一些描述符来让设备可以显得个性些,但这四大描述符是一个都不能少的。

这些描述符放哪儿?当然是在设备里。就好像你要把身份证放自己身上以免在哪里心情舒畅的散步时被新时代最可爱的人警察叔叔查到一样,你不会直接放他们那儿吧,然后在他们亲切慈祥的向你招手时,告诉他们说不就在你那儿么,那样的话等待你又是个什么样的结果,我不知道,我想你也不会想知道。咱们的描述符就在设备里,等着主机去拿。具体在哪儿?usb设备里都会有一个叫EEPROM的东东,没错,就是放在它那儿,它就是用来存储设备本身信息的。如果你的脑海里还残存着一些大学里的美好时光的话,应该还会记得EEPROM就是电可擦写的可编程ROM,它与Flash虽说都是要电擦除的,但它可以按字节擦除,Flash只能一次擦除一个block,所以如果要改动比较少的数据的话,使用它还是比较合适的,但是世界上没有完美的东西,此物成本相对Flash比较高,所以一般来说usb设备里只拿它来存储一些本身特有的信息,要想存储数据,还是用Flash吧。

具体到接口描述符,它当然就是描述接口本身的信息的。一个接口可以有多个设置,使用不同的设置,描述接口的信息会有些不同,所以接口描述符并没有放在struct usb_interface结构里,而是放在表示接口设置的struct usb_host_interface结构里。定义在include/linux/usb/ch9.h文件里



294





/* USB_DT_INTERFACE: Interface descriptor */




296









__u8




bLength;




297









__u8




bDescriptorType;




299









__u8




bInterfaceNumber;




300









__u8




bAlternateSetting;




301









__u8




bNumEndpoints;




302









__u8




bInterfaceClass;




303









__u8




bInterfaceSubClass;




304









__u8




bInterfaceProtocol;




305









__u8




iInterface;


又看到了



__attribute__



,不过这里改头换面成了



__attribute__



,意思就是告诉编译器,这个结构的元素都是1字节对齐的,不要再添加填充位了。因为这个结构和spec里的Table 9.12是完全一致的,包括字段的长度,如果不给编译器这么个暗示,编译器就会依据你平台的类型在结构的每个元素之间添加一定的填充位,如果你拿这个添加了填充位的结构去向设备请求描述符,你想想会是什么结果。

296行,bLength,描述符的字节长度。协议里规定,每个描述符必须以一个字节打头来表明描述符的长度。那可以扳着指头数一下,接口描述符的bLength应该是9,两个巴掌就数完了,没错,ch9.h文件里紧挨着接口描述符的定义就定义了这个长度


308




#define



USB_DT_INTERFACE_SIZE



9


297行,bDescriptorType,描述符的类型。各种描述符的类型都在ch9.h文件里有定义,对应spec Table 9.5。对于接口描述符来说,值为



USB_DT_INTERFACE



,也就是0x04。




299



行,


bInterfaceNumber


,接口号。每个配置可以包含多个接口,这个值就是它们的索引值。






300



行,


bAlternateSetting


,接口使用的是哪个可选设置。协议里规定,接口默认使用的设置总为


0


号设置。






301



行,


bNumEndpoints


,接口拥有的端点数量。这里并不包括端点


0


,端点


0


是所有的设备都必须提供的,所以这里就没必要多此一举的包括它了。






302



行,


bInterfaceClass





303





bInterfaceSubClass





304





bInterfaceProtocol


。这个世界上有许许多多的


usb


设备,它们各有各的特点,为了区分它们,


usb


规范,或者说


usb


协议,把


usb


设备分成了很多类,然而每个类又分成子类,这很好理解,我们一个大学也是如此,先是分成很多个学院,然后每个学院又被分为很多个系,然后可能每个系下边又分了各个专业,


usb


协议也是这样干的,首先每个


Device





Interface


属于一个


Class


,然后


Class


下面又分了


SubClass


,完了


SubClass


下面又按各种设备所遵循的不同的通信协议继续细分。


usb


协议里边为每一种


Class


,每一种


SubClass


,每一种


Protocol


定义一个数值,比如


mass storage





Class


就是


0x08





hub





Class


就是


0x09









305



行,


iInterface


,接口对应的字符串描述符的索引值。疑?这里怎么又跳出来一个叫字符串描述符的东东?你没看错我也没说错,除了前面提到的四大描述符,是还有字符串描述符,不过那四大描述符是每个设备必须支持的,这个字符串描述符却是可有可无的,有了你欢喜我也欢喜,没有也不是什么问题。使用


lsusb


命令看一下







localhost:/usr/src/linux/drivers/usb/core # lsusb





Bus 001 Device 013: ID 04b4:1081 Cypress Semiconductor Corp.





Bus 001 Device 001: ID 0000:0000





第一行里显示的是我手边儿的


Cypress USB


开发板,看里面的


Cypress Semiconductor Corp.


,这么一长串的东东从哪里来?是不是应该从设备里来?设备的那几个标准描述符,整个描述符的大小也不一定放得下这么一长串,所以,一些设备专门准备了一些字符串描述符(


string descriptor


),就用来记这些长串的东西。字符串描述符主要就是提供一些设备接口相关的描述性信息,比如厂商的名字,产品序列号等等。字符串描述符当然可以有多个,这里的索引值就是用来区分它们的。







说过了接口描述符,回到


struct


usb_host_interface







76


行,


endpoint


,一个数组,表示这个设置所使用到端点。至于端点的结构


struct usb_host_endpoint


,天这么热,让它先一边儿凉快凉快吧,不怕春光乍泄的话,可以去思源湖冲个凉,咱们先看完


struct


usb_host_interface




再去说它。






78



行,


string


,用来保存从设备里取出来的字符串描述符信息的,既然字符串描述符可有可无,那这里的指针也有可能为空了。






79



行,


extra





80





extralen


,关于额外的描述符。除了前面提到的四大描述符还有字符串描述符外,还有为一组设备也就是一类设备定义的描述符,和厂商为设备特别定义的描述符,


extra


指的就是它们,


extralen


表示它们的长度。比如上海规定了,社保必须得交多少多少,公积金多少多少,有个最低的比例,有地儿觉得太少,给你多交些,叫补充什么金的,还有些地儿,觉得补充都不过瘾,像公务员这种特殊行业特别劳心劳力的,再加些特殊行业补贴等什么的,既规定了必须实现的,也给你特殊行业发挥的空间,当然怎么发挥就不是咱说了算了,不操那份儿心了。






版权声明:本文为fudan_abc原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。