梳理USB port口检测设备
首先梳理一下usb设备的检测过程:
当usb设备接到port时,控制器会监测到该port电平状态发生改变,继而产生中断
port状态中断函数:handle_port_status
中断函数做了两件事:
第一件处理当前中断
第二件继续轮询该port状态
第一件事:使用tasklet中断下半部处理,然后使用工作队列创建出设备
else if (high_prio_bh) // 同步传输或中断传输
tasklet_hi_schedule(&bh->bh);
else
tasklet_schedule(&bh->bh); // 控制传输或批量传输
tasklet执行usb_giveback_urb_bh,继而会执行urb的complete_fn。对于hub,complete_fn为hub_irq
hub_irq会执行唤醒工作队列hub_wq queue_work(hub_wq, &hub->events)
执行hub_event,然后故事就开始了。
第二件事:唤起定时器函数hcd->rh_timer - rh_timer_func - usb_hcd_poll_rh_status
插入鼠标获取usbmon
第一部分port相关包
ffffffa0e8a9af00 2329250566 S Ci:3:001:0 s a3 00 0000 0001 0004 4 < USB_RT_PORT | IN
ffffffa0e8a9af00 2329250601 C Ci:3:001:0 0 4 = 01010100
ffffffa0e8a9af00 2329250614 S Co:3:001:0 s 23 01 0010 0001 0000 0
ffffffa0e8a9af00 2329250643 C Co:3:001:0 0 0
ffffffa0e8a9af00 2329250685 S Ci:3:001:0 s a3 00 0000 0001 0004 4 <
ffffffa0e8a9af00 2329250709 C Ci:3:001:0 0 4 = 01010000
ffffffa0e8a9af00 2329284024 S Ci:3:001:0 s a3 00 0000 0001 0004 4 <
ffffffa0e8a9af00 2329284053 C Ci:3:001:0 0 4 = 01010000
ffffffa0e8a9af00 2329320017 S Ci:3:001:0 s a3 00 0000 0001 0004 4 <
ffffffa0e8a9af00 2329320044 C Ci:3:001:0 0 4 = 01010000
ffffffa0e8a9af00 2329356036 S Ci:3:001:0 s a3 00 0000 0001 0004 4 <
ffffffa0e8a9af00 2329356079 C Ci:3:001:0 0 4 = 01010000
ffffffa0e8a9af00 2329392022 S Ci:3:001:0 s a3 00 0000 0001 0004 4 <
ffffffa0e8a9af00 2329392054 C Ci:3:001:0 0 4 = 01010000
ffffffa0e8a9af00 2329392417 S Co:3:001:0 s 23 03 0004 0001 0000 0
ffffffa0e8a9af00 2329392446 C Co:3:001:0 0 0
ffffffa0e8a9b000 2329460039 S Ci:3:001:0 s a3 00 0000 0001 0004 4 <
ffffffa0e8a9b000 2329460080 C Ci:3:001:0 0 4 = 03031000
ffffffa0e8a9b000 2329460108 S Co:3:001:0 s 23 01 0014 0001 0000 0
ffffffa0e8a9b000 2329460134 C Co:3:001:0 0 0
ffffffa0e8a9af00 2329520737 S Ci:3:000:0 s 80 06 0100 0000 0040 64 <
ffffffa0e8a9af00 2329524946 C Ci:3:000:0 0 18 = 12011001 00000008 3a091025 00010102 0001 // 鼠标设备描述符
ffffffa0e8a9af00 2329524971 S Co:3:001:0 s 23 03 0004 0001 0000 0
ffffffa0e8a9af00 2329525005 C Co:3:001:0 0 0
ffffffa0e8a9af00 2329592022 S Ci:3:001:0 s a3 00 0000 0001 0004 4 <
ffffffa0e8a9af00 2329592071 C Ci:3:001:0 0 4 = 03031000
ffffffa0e8a9af00 2329592081 S Co:3:001:0 s 23 01 0014 0001 0000 0
ffffffa0e8a9af00 2329592101 C Co:3:001:0 0 0
X3 为port操作
struct usb_ctrlrequest {
__u8 bRequestType; 方向 in:80 / out:0
#define USB_DIR_OUT 0 /* to device */
#define USB_DIR_IN 0x80 /* to host */
#define USB_RT_PORT (USB_TYPE_CLASS | USB_RECIP_OTHER)
#define USB_TYPE_CLASS (0x01 << 5)
#define USB_RECIP_OTHER 0x03
__u8 bRequest; 描述符操作
#define USB_REQ_GET_STATUS 0x00
#define USB_REQ_CLEAR_FEATURE 0x01
#define USB_REQ_SET_FEATURE 0x03
__le16 wValue; 描述符类型
#define HUB_PORT_STATUS 0
#define HUB_PORT_PD_STATUS 1
#define HUB_EXT_PORT_STATUS 2
__le16 wIndex; // port号
__le16 wLength;
} __attribute__ ((packed));
上述包来自hub_port_init中的hub_port_reset。
usb_control_msg 中会做如下填充
struct usb_ctrlrequest *dr;
dr->bRequestType = requesttype;
dr->bRequest = request;
dr->wValue = cpu_to_le16(value);
dr->wIndex = cpu_to_le16(index);
dr->wLength = cpu_to_le16(size);
其中value的组成:(type << 8) + index,index为port index号
第二部分鼠标相关包
010devnum为鼠标 :鼠标读取配置部分
ffffffa0e8a9ae00 2329672054 S Ci:3:010:0 s 80 06 0100 0000 0012 18 <
ffffffa0e8a9ae00 2329676947 C Ci:3:010:0 0 18 = 12011001 00000008 3a091025 00010102 0001
ffffffa0e8a9ae00 2329676984 S Ci:3:010:0 s 80 06 0200 0000 0009 9 <
ffffffa0e8a9ae00 2329680943 C Ci:3:010:0 0 9 = 09022200 010100a0 32
ffffffa0e8a9ae00 2329680966 S Ci:3:010:0 s 80 06 0200 0000 0022 34 <
ffffffa0e8a9ae00 2329687944 C Ci:3:010:0 0 34 = 09022200 010100a0 32090400 00010301 02000921 11010001 22340007 05810304
ffffffa0e8a9bc00 2329687999 S Ci:3:010:0 s 80 06 0300 0000 00ff 255 <
ffffffa0e8a9bc00 2329690944 C Ci:3:010:0 0 4 = 04030904
ffffffa0e8a9bc00 2329690978 S Ci:3:010:0 s 80 06 0302 0409 00ff 255 <
ffffffa0e8a9bc00 2329697943 C Ci:3:010:0 0 36 = 24035500 53004200 20004f00 70007400 69006300 61006c00 20004d00 6f007500
ffffffa0e8a9bc00 2329697979 S Ci:3:010:0 s 80 06 0301 0409 00ff 255 <
ffffffa0e8a9bc00 2329701944 C Ci:3:010:0 0 14 = 0e035000 69007800 41007200 7400
鼠标设置部分
ffffffa0e8a9bc00 2329705350 S Co:3:010:0 s 00 09 0001 0000 0000 0
ffffffa0e8a9bc00 2329706934 C Co:3:010:0 0 0
ffffffa0e8a9af00 2329707250 S Co:3:010:0 s 21 0a 0000 0000 0000 0
ffffffa0e8a9af00 2329708983 C Co:3:010:0 -32 0
ffffffa0e8a9af00 2329709023 S Ci:3:010:0 s 81 06 2200 0000 0034 52 <
ffffffa0e8a9af00 2329718945 C Ci:3:010:0 0 52 = 05010902 a1010901 a1000509 19012903 15002501 75019503 81027505 95018101
ffffffa0e8a9bf00 2329719592 S Ii:3:010:1 -115:8 4 <
知识点010为devnum,动态分配的,但是hub dev的devnum是固定的,hub为1
xhc有两个hub一个2.0,一个3.0,devnum都为1。不信?lsusb -tv
至于devnum为0,没研究过lsusb代码,个人猜测为xhc dev
struct usb_ctrlrequest {
__u8 bRequestType; 方向 in:80 / out:0
#define USB_DIR_OUT 0 /* to device */
#define USB_DIR_IN 0x80 /* to host */
__u8 bRequest; 描述符操作
#define USB_REQ_SET_ADDRESS 0x05
#define USB_REQ_GET_DESCRIPTOR 0x06
#define USB_REQ_SET_DESCRIPTOR 0x07
#define USB_REQ_GET_CONFIGURATION 0x08
#define USB_REQ_SET_CONFIGURATION 0x09
#define USB_REQ_GET_INTERFACE 0x0A
#define USB_REQ_SET_INTERFACE 0x0B
__le16 wValue; 描述符类型
#define USB_DT_DEVICE 0x01
#define USB_DT_CONFIG 0x02
#define USB_DT_STRING 0x03
#define USB_DT_INTERFACE 0x04
#define USB_DT_ENDPOINT 0x05
__le16 wIndex; ep号
__le16 wLength;
} __attribute__ ((packed));
usb_control_msg 中会做如下填充
struct usb_ctrlrequest *dr;
dr->bRequestType = requesttype;
dr->bRequest = request;
dr->wValue = cpu_to_le16(value);
dr->wIndex = cpu_to_le16(index);
dr->wLength = cpu_to_le16(size);
其中value的组成:(type << 8) + index,index为ep index号
第一个包 18byte 是读取usb_device_descriptor
80 06 0100 0000 0012
第二个包 9byte 是读取usb_config_descriptor
80 06 0200 0000 0009
第三个包 32byte 是读取所有的配置信息
80 06 0200 0000 0022
第四 五 六个包 255byte,读取string,ep0,ep1_in,ep2_in,三个ep
80 06 0300 0000 00ff
80 06 0302 0409 00ff
80 06 0301 0409 00ff
第七个包 是设置ep1_out配置
00 09 0001 0000 0000
第八个包
21 0a 0000 0000 0000
第九个包
81 06 2200 0000 0034
上述包都为setup包
hub_port_init 中实现了DEVICE包的发送,发送位置为
usb_get_device_descriptor(udev, USB_DT_DEVICE_SIZE);
usb_enumerate_device实现CONFIG和STRING包发送。
usb_get_configuratio(udev)
usb_cache_string(udev, udev->descriptor.iProduct);
usb_cache_string(udev, udev->descriptor.iManufacturer);
usb_cache_string(udev, udev->descriptor.iSerialNumber);
来来来对比一下:
lsusb -s 003:005 -v
Device Descriptor:
bLength 18
bDescriptorType 1
bcdUSB 1.10
bDeviceClass 0
bDeviceSubClass 0
bDeviceProtocol 0
bMaxPacketSize0 8
idVendor 0x093a Pixart Imaging, Inc.
idProduct 0x2510 Optical Mouse
bcdDevice 1.00
iManufacturer 1 PixArt
iProduct 2 USB Optical Mouse
iSerial 0
bNumConfigurations 1
对比一下返回
12011001 00000008 3a091025 00010102 0001
Configuration Descriptor:
bLength 9
bDescriptorType 2
wTotalLength 0x0022
bNumInterfaces 1
bConfigurationValue 1
iConfiguration 0
bmAttributes 0xa0
对比一下返回
09022200 010100a0
协议包中数据以大端形式返回