host端USB枚举流程--2021-03-25

 

1. 主机集线器检测到新设备(热插拔检测)

  • USB主机端,集线器端口的DATA+和 DATA-差分线上都有下拉15K 的电阻。
  • 从机端,USB 设备端(鼠标键盘等),都有 1.5K 的上拉电阻。当 USB 接口空置的时候,集线器上检测到的 DATA+和 DATA-都是低电平,当 USB 设备插入的时候,就会被拉高,这个时候是产生低电平到高电平的变化。

USB主机集线器监视着每个端口的信号电压,当用USB线将PC和设备接通后,设备的上拉电阻使信号线的电位升高,因此被主机集线器检测到。反之,设备拔出,产生高电平到低电平的变化,集线器检测到设备拔出。

2. 主机发送Get_Status请求

每个集线器用中断传输来报告在集线器上的事件。当主机知道了这个事件,它给集线器发送一个Get_Status请求来了解更多的消息,返回的消息告诉主机一个设备是什么时候连接的。

3. 主机发送Set_Feature请求,集线器重启端口

当主机知道有一个新的设备时,主机给集线器发送一个Set_Feature请求,请求集线器来重启端口。集线器使得设备的USB数据线处于重启(RESET)状态至少10ms。 在重启device之前,host和hub通信,确认device存在。

4. 集线器在设备和主机之间建立一个信号通路

主机发送一个Get_Status请求来验证设备是否激起重启状态。返回的数据有一位表示设备仍然处于重启状态。当集线器释放了重启状态,设备就处于默认状态了,设备已经准备好通过Endpoint 0 的默认流程响应控制传输,即设备现在使用默认地址0x0与主机通信。

Endpoint 是指的端点,在 USB 通信中,我们知道是主从通信,通信的双方主体是主机端设备的端点和 USB 设备。由于一个 USB 口,可能不止一个端点,在 USB协议中规定,USB 接口中必须有端点 0,也就是 Endpoint 0。其中还有设备描述符、配置描述符、接口描述符、端点描述符四个部分。现在我们只需要知道,主机和从机通信是通过端点来进行,而端点 0 是任何一个 USB 设备都有的。

5. 集线器检测设备速度

集线器通过测定哪根信号线(D+或D-)在空闲时有更高的电压来检测设备是低速设备还是全速设备。(全速和高速设备D+有上拉电阻,低速设备D-有上拉电阻)。

这部分是由具体的 USB 设备生产商(鼠标键盘)设计决定的,一般高速设备都是兼容低速设备的,而且完全由集线器来检测。

前五个步中,主要工作是检测到 USB 设备、向主机报告在某个时间点有一个 USB 设备接入、集线器重启接入 USB的端口、集线器在主控制器和 USB 设备之间建立一个信号通路,最后集线器检测设备速度。

经过前面 5 个步骤,主控制器和 USB 设备之间建立了一个信号通路,而且主控制获取了设备是高速设备还是低速设备的信息。

在所有的 USB 设备中(不管是鼠标、键盘、蓝牙,还是网卡、U 盘等等),设备内部都有一个存储器,用于保存设备的信息。例如:生产厂商、产品的 ID 等等。存储器中还包含了一些具体的通信协议,在设备驱动中,需要根据USB 设备中的信息来进行配置初始化工作。

主机从 USB 设备中获取的信息,在 USB 协议中是有规定的,其中通过设备描述符、配置描述符、接口描述符、端点描述符来组织。

在 PC 上,我们接入一个 USB 设备之后,有时它会在右下角提醒,“发现新的 USB 设备XXX,已经可以使用”或者“发现新的 USB 设备 XXX,驱动无法加载”。我们可以判断出,USB 设备在接入之前,驱动是没有安装到内核中的,只有在 USB 设备被检测到,而且内核中有该设备对应的驱动,USB 设备的驱动才会被加载。

以下需要USB的firmware进行干预 。

6. 获取最大数据包长度

PC 向address 0发送USB协议规定的Get_Device_Descriptor命令,以取得缺省控制管道所支持的最大数据包长度,并在有限的时间内等待USB设备的响应。该长度包含在设备描述符的bMaxPacketSize0字段中,其地址偏移量为7,所以这时主机只需读取该描述符的前8个字节。注意,主机一次只能枚举一个USB设备,所以同一时刻只能有一个USB设备使用缺省地址0。 获取最大数据包长度是后面通信的基础。

以下操作雷同,不同操作系统设定时延是不一样的,比如说win2k大概是几毫秒,如果没有反应就再发送一次命令,重复三次。

7. 主机分配一个新的地址给设备

主机通过发送一个Set_Address请求来分配一个唯一的地址给设备。设备读取这个请求,返回一个确认,并保存新的地址。从此开始所有通信都使用这个新地址。

8. 主机重新发送Get_Device_Descriptor命令,读取完整设备描述符

主机向新地址重新发送Get_Device_Descriptor命令,此次读取其设备描述符的全部字段,以了解该设备的总体信息,如VID,PID。

9. 主机发送Get_Device_Configuration命令,获取完整配置信息

主机向设备循环发送Get_Device_Configuration命令,要求USB设备回答,以读取全部配置信息。

10. 主机发送Get_Device_String命令,获得描述字符集(unicode)

描述字符集包括了产商、产品描述、型号等信息。

11. 主机展示新设备信息

此时主机将会弹出窗口,展示发现新设备的信息,产商、产品描述、型号等。

12. PC判断能否提供该类USB的驱动

根据Device_Descriptor和Device_Configuration应答,PC判断是否能够提供USB的Driver,一般能提供几大类的设备,如游戏操作杆、存储、打印机、扫描仪等,操作就在后台运行。这一步中,加载的驱动就是设备驱动,也就是我们需要关注的驱动。

13. 主机发送Set_Configuration(x)命令,请求为设备选择一个配置

加载了USB设备驱动以后,主机发送Set_Configuration(x)命令请求为该设备选择一个合适的配置(x代表非0的配置值)。如果配置成功,USB设备进入“配置”状态,并可以和客户软件进行数据传输。

此时,常规的USB完成了其必须进行的配置和连接工作。查看注册表,能够发现相应的项目已经添加完毕,至此设备应当可以开始使用。不过,USB协议还提供了一些用户可选的协议,设备如果不应答,也不会出错,但是会影响到系统的功能。

kernel usb设备识别流程

 

usb_init()--usb.c

usb_hub_init()

hub_thread()

hub_events()

1.hub_port_status()--获得portchange,portstatus状态并设置connect_change变量;connect——change为1表示端口有变化

2.hub_port_connect_change()--处理枚举过程

1>hub_port_debounce_be_stable()--去抖动,

hub_port_debounce()

2>usb_alloc_dev()--为USB设备分配struct usb_device,并设置USB_STATE_ATTACHED

3>usb_set_device_state()--设置状态USB_STATE_POWERED

4>choose_devnum()--为USB设备分配编号-[ 220.836836] usb 2-1: new high-speed USB device number 4 using xxx-ehci

5>hub_port_init()

hub_port_reset()--复位设备,确定设备的速度(通过握手信号判断)

hub_port_finish_reset()--设置USB_STATE_DEFAULT状态

switch(udev->speed)语句,获取默认管道的最大包长度

dev_info(&udev->dev,"%s %s USB device number %d using %s\n",(udev->config) ? "reset" : "new", speed,devnum, udev->bus->controller->driver->name);

hub_set_address()--给设备分配一个新地址并设为USB_STATE_ADDRESS状态,之后用此地址通信

usb_get_device_descriptor()--获取设备描述符,此时状态还是USB_STATE_ADDRESS

6>usb_new_device()

usb_enumerate_device()--获取USB设备描述符

announce_device()--dev_info(&udev->dev, "New USB device found, idVendor=%04x, idProduct=%04x\n",le16_to_cpu(udev->descriptor.idVendor),le16_to_cpu(udev->descriptor.idProduct));

dev_info(&udev->dev, "New USB device strings: Mfr=%d, Product=%d, SerialNumber=%d\n",udev->descriptor.iManufacturer,udev->descriptor.iProduct,udev->descriptor.iSerialNumber);

device_add()--注册设备

3.usb_device_match()--检查新设备和预先加载的接口驱动是否匹配

4.usb_match_one_id_intf()--最终判断是否匹配

 

  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一个专注于USB的驱动工程师

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值