前言
一直以来对设备描述符这个概念云里雾里的:
- 什么是设备描述符?
- 设备描述符是个结构体还是结构体指针?
- 为什么要有设备描述符?
- 设备描述符的作用?
- 设备描述符是根据什么定义的?
启发
今天看《Linux那些事儿之我是USB》,书中的一句话拨开了我心中的迷雾:
/* USB_DT_DEVICE: Device descriptor */
struct usb_device_descriptor {
__u8 bLength;
__u8 bDescriptorType;
__le16 bcdUSB;
__u8 bDeviceClass;
__u8 bDeviceSubClass;
__u8 bDeviceProtocol;
__u8 bMaxPacketSize0;
__le16 idVendor;
__le16 idProduct;
__le16 bcdDevice;
__u8 iManufacturer;
__u8 iProduct;
__u8 iSerialNumber;
__u8 bNumConfigurations;
} __attribute__ ((packed));
哦,设备描述符就是个结构体,它是根据 Spec(或者 Chip Datasheet)定义的。
这时候我先没着急打开 Spec 去看 Table 9-8 长啥样,但是已经猜的八九不离十了,肯定是一组寄存器。
我先去想,如果让我去设计一颗 IC(比如说 USB_LED 控制芯片),我
- 如何让 CPU 知道我是一个 USB 设备呢?
- 如何让 CPU 知道我是一个 LED 设备呢?
- 如何让 CPU 知道我是哪个厂家的呢?
- 如何让 CPU 知道我有哪些属性(开、关、亮度、颜色、闪烁等)呢?
肯定得有一组寄存器(或者 e2prom)来存储以上信息,这样 CPU 就可以从我的寄存器中读取我的设备信息,进而知道我是一个什么设备,应该给我安装什么样的驱动,我具有哪些属性,后续可以对我进行哪些操作等等。
同时,CPU 也得有变量去存储我的设备信息,因为设备信息不止一个,同时它们又都有一个共性都是设备信息,所以就把这些变量统一放在一个结构体里面方便维护和使用,这个结构体就是设备描述符。
我画个图把脑海中的图像展现出来,如下:
USB Spec Table9-8
打开 USB2.0 Spec,看到了 Table 9-8 描述的设备信息,和内核代码中定义的 struct usb_device_descriptor
完全一致,就连变量名称都是完全使用 Spec 中的。
总结
外设有一组寄存器用来表示自身的设备信息,内核需要一个设备描述符用来存储外设的这一组设备信息。因此设备描述符中的每个成员变量对应一个寄存器,通常设备描述符这个 struct 会设置成字节对齐,以保证整个结构体大小和一组寄存器大小完全相等,且其中每个成员一一对应。