Linux USB设备结构中的配置、接口、设置、端点
内核版本:linux-3.4.2
## 1.描述符数据结构 ##
描述符存储在USB设备结构体中,USB设备结构中与描述符相关的成员如下:
struct usb_device {
struct usb_host_endpoint ep0;
struct usb_device_descriptor descriptor; /* SPEC中定义的设备描述符 */
struct usb_host_bos *bos;
struct usb_host_config *config; /* 配置描述符 */
struct usb_host_config *actconfig;
struct usb_host_endpoint *ep_in[16];
struct usb_host_endpoint *ep_out[16];
char **rawdescriptors;
};
从上面的成员的类型可以看出,struct usb_device_descriptor
对应的是USB规范中的设备描述符,而struct usb_host_config
并没有对应USB规范中的配置描述符,一般名字为usb_xxx_descriptor
的结构体对应的是USB规范中的描述符,而名字为usb_host_xxx
的结构体则代表主机侧的一个描述符,而具体的USB规范中的描述符则是一个usb_host_xxx
结构体中的成员。
可以预见的是:
struct usb_config_descriptor
对应SPEC中的配置描述符
struct usb_interface_descriptor
对应SPEC中的接口描述符
struct usb_endpoint_descriptor
对应SPEC中的端点描述符
struct usb_host_config
对应主机侧的一个配置
struct usb_host_interface
对应主机侧的一个接口
struct usb_host_endpoint
对应主机侧的一个端点
那么这些描述符是怎么存储的,config和actconfig有什么区别,这得看从设备枚举的时候读取设备描述符开始到USB接口设备匹配到接口驱动为止的代码来看struct usb_device
结构体中成员的变化。
## 2. 读取设备描述符,设置设备 ##
读取设备描述符是在hub_port_connect_change
函数中,大概过程如下:
static void hub_port_connect_change(struct usb_hub *hub, int port1, u16 portstatus, u16 portchange)
{
for (i = 0; i < SET_CONFIG_TRIES; i++) {
udev = usb_alloc_dev(hdev, hdev->bus, port1); /* 分配一个usb_device,此时设备的状态是 USB_STATE_ATTACHED */
...
choose_devnum(udev); /* 选择设备编号 */
hub_port_init(hub, udev, port1, i); /* hub端口的初始化 */
...
usb_new_device(udev); /* 向系统添加新的USB设备 */
}
}
### 2.1 分配初始化USB设备对象 ###
首先看设备是怎么分配的:
parent:这个参数指向了设备插入的hub的设备结构体
bus:这个参数指向了物理上的一个usb总线
port1:这个参数指设备插入的hub的端口号
struct usb_device *usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port1)
{
dev = kzalloc(sizeof(*dev), GFP_KERNEL); /* 这里分配了一个usb_device结构体,代表了一个USB设备 */
...
dev->state = USB_STATE_ATTACHED; /* 设备的状态为ATTACHED */
...
dev->ep0.desc.bLength = USB_DT_ENDPOINT_SIZE; /* 设置端点0的描述符的长度 */
dev->ep0.desc.bDescriptorType = USB_DT_ENDPOINT; /* 设置端点0的描述符的类型 */
}
此时的usb_device
里的成员是这样的情况:
图1
### 2.2 读取设备描述符 ###
分配了usb_device
之后,就会进入hub_port_init
函数读取设备描述符:
static int hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1, int retry_counter)
{
int devnum = udev->devnum;
for (i = 0; i < GET_DESCRIPTOR_TRIES; (++i, msleep(100))) { //如果第一次就成功了,那就退出循环了
if (USE_NEW_SCHEME(retry_counter) && !(hcd->driver->flags & HCD_USB3)) {
#define GET_DESCRIPTOR_BUFSIZE 64
buf = kmalloc(GET_DESCRIPTOR_BUFSIZE, GFP_NOIO); /* 首先分配64字节的空间 */
buf->bMaxPacketSize0 = 0;
usb_control_msg(udev, usb_rcvaddr0pipe(),
USB_REQ_GET_DESCRIPTOR, USB_DIR_IN,
USB_DT_DEVICE << 8, 0,
buf, GET_DESCRIPTOR_BUFSIZE,
initial_descriptor_timeout); /* 发送一个控制传输请求,请求64字节的数据 */
udev->descriptor.bMaxPacketSize0 = buf->bMaxPacketSize0; /* 记录端点