xHCI
2023-09-14
-
- USB Driver(USBD): 总线驱动,用来枚举USB设备,给USB设备安装Protocol。
- Host Controller Driver(xHCD): xHC控制器驱动。
- Host Controller (xHC):USB控制器,是一个硬件设备。
- USB Device: 包括HUB和Function,比如鼠标、键盘。
XHCI介绍 #
-
xHCI包含三个空间
-
主机配置空间:一般是PCI配置空间。
-
MMIO空间:主要放一些寄存器(Capability Registers、Operational Registers、Runtime Registers和Doorbell Array)。
-
主机内存:主要放一些数据结构,比如Device Context Base Address Array, Device Contexts, Transfer Ring等。
-
-
xHCI支持的传输类型:Isochronous(等时传输)、Interrupt(中断传输)、Control(控制传输)、Bulk(批量传输)。
-
Capability Register:这些值作为Host Controller Driver的参数。
-
Runtime和Operational Registers指定主机控制器配置和运行变化状态。系统软件通过该寄存器来控制和监控主机控制器的Operational状态。
-
xHCI Extended Capabilities说明了xHC实现的一些可选特性。
-
Doorbell Array:最多支持256个Doorbell寄存器的数组,每个Doorbell寄存器都向系统软件提供了一种机制,用于通知xHC是否有域槽位或者Endpoint相关的工作要执行。Doorbell寄存器的DB Target字段表示按下门铃的原因。Doorbell寄存器0被主机控制器用域Command Ring管理。
-
Device Slot 表示USB设备的多个XHCI数据结构。每个设备由Device Context BaseAddress Array中的一个元素、Doorbell Array register中的一个寄存器和设备的Device Context组成。Slot ID用于标识特定的Device Slot。
-
Command Ring:软件使用Command Ring将Command传递给xHC。
-
Event Ring:xHC使用Event Ring将Command Completion和Asynchronous event传递给软件。
-
Transfer Ring:软件使用Transfer Ring为Endpoint安排工作。Transfer Ring是一个循环队列(队列中每个元素都是是Transfer Descriptor(TD)),每个TD定义了一个或多个数据Buffer。
XHCI数据结构 #
Device Context Base Address Array #
- Device Context Base Address Array (DCBAA)是一个指针数组,数组的每个元素都指向了一个Device Context数据结构。数组最多255个元素。
- DCBAA的数组下标就是SLOT ID。
- 当检测到插入了一个USB设备后:1. 软件初始化一个Device Context数据结构;2. 从xHC获取一个Slot ID;3. 将此Device Context的指针插入到DCBAA的SLOT ID的位置。
Device Context #
- Device Context用来记录设备的配置和状态信息。
- Device Context由32个数据结构组成,第一个数据结构是Slot Context,剩余的数据结构是Endpoint Context。
- 在枚举USB设备时,软件创建一个Device Context数据结构并初始化为0,在执行了Address Device命令后将该数据结构的所属权传递给xHC。在执行了Disable Slot命令后,xHC会失去该数据结构的所属权。
typedef struct _DEVICE_CONTEXT {
SLOT_CONTEXT Slot;
ENDPOINT_CONTEXT EP[31];
} DEVICE_CONTEXT;
Slot Context #
- Slot Context提供了control、state、addressing和电源管理。
typedef struct _SLOT_CONTEXT {
UINT32 RouteString : 20;
UINT32 Speed : 4;
UINT32 RsvdZ1 : 1;
UINT32 MTT : 1;
UINT32 Hub : 1;
UINT32 ContextEntries : 5;
UINT32 MaxExitLatency : 16;
UINT32 RootHubPortNum : 8;
UINT32 PortNum : 8;
UINT32 TTHubSlotId : 8;
UINT32 TTPortNum : 8;
UINT32 TTT : 2;
UINT32 RsvdZ2 : 4;
UINT32 InterTarget : 10;
UINT32 DeviceAddress : 8;
UINT32 RsvdZ3 : 19;
UINT32 SlotState : 5;
UINT32 RsvdZ4;
UINT32 RsvdZ5;
UINT32 RsvdZ6;
UINT32 RsvdZ7;
} SLOT_CONTEXT;
Endpoint Context #
- Endpoint Context数据结构定义了特定的USB Endpoint的配置和状态。Endpoint Context字段包含了Endpoint相关的type、control、state和带宽信息。这些信息由USB设备提供。Endpoint Context还定义了一个TR Dequeue 指定字段,通常提供了一个指向了与此pipe关联的Transfer Ring。
Rings #
- Ring是一个循环队列,xHC使用三种类型的Ring:
- Command Ring:(每个XHC一个)软件使用Command Ring将命令发送给xHC。
- Event Ring:(每个中断一个)xHC使用Event Ring将命令状态、结果传递给软件。
- Transfer Ring:(每个Endpoint或Stream一个)Transfer Ring被用来在内存和设备Endpoint之间传输数据。
Command接口 #
- 为了管理xHC和连接到xHC的设备,xHC提供了一个Command Ring接口,一个Command Ring上的项目被称为CD(Command Descriptor)。
- 所有命令都会在Event Ring上生成一个命令完成事件,该事件用于报告命令完成状态。
- xHCI 命令集合
命令 | 描述 |
---|---|
No Op | 测试TRB Ring机制 |
Enable Slot | 返回设备的Slot ID并将设备Slot状态从Disabled改为Default |
Disable Slot | 将Device Slot从其他任何状态改为Disabled状态 |
Address Device | 启用Default Control Endpoint,(可选)向USB设备发出SET_ADDRESS命令并将Device Slot设置为Addressed状态 |
Configure Endpoint | 启用或者禁用设备的Enpoint |
Evaluate Context | 告知xHC软件已经修改了选定的Context参数 |
Reset Endpoint | 复位Endpoint,该命令用于将一个halted endpoint恢复 |
Stop Endpoint | 停止Endpoint |
Set TR Dequeue Pointer | 更新一个启用的endpoint的Transfer Ring Dequeue |
Reset Device | 复位Device Slot,此命令用于在复位一个USB设备时同步Device Slot的状态 |
Endpoint #
- 一个USB设备支持最高31个Endpoints。
USB设备初始化 #
- 下面是一个连到ROOT HUB的USB设备初始化的流程:
- 当检测到一个USB设备连接后,xHC会将CCS和CSC置为1,并生成一个端口变更事件。
- 收到端口状态变更事件后,软件根据Port ID字段来确认是哪个Port生成的事件。
- 软件读取PORTSC寄存器。 USB3协议的Port尝试进入Enabled状态,连接的USB设备进入为Default状态。
- 软件通过Enable Slot命令来从xHC获取设备的slot,XHC会返回一个SLOT ID。Enable Slot执行成功后,Device Slot会进入Enabled状态。
- 获取到设备的slot后,软件初始化此slot关联的数据结构。
- 分配Input Context数据结构。
- 将Input Context中的Input Control Context的A0和A1标志位置为1。
- 初始化Input Slot Context数据结构,主要是设置Root Hub Port Number、Route String和Context Entries。
- 为Default Control Endpoint初始化Transfer Ring。
- 初始化Input Default Control Endpoint 0 Context,主要是设置EP type = Control、Max Packet Size等信息。
- 分配Output Device Context 数据结构,从Device Context Base Address Array中选择一个下标(Device Slot Id)用来指向Output Device Context数据结构。
- 软件使用Address Device命令来给设备分配地址,并启用其Default Control Endpoint。此命令会将Device Slot从Enabled状态置为Addressed状态,将USB设备从Default状态置为Address状态。
- 对于LS,HS, 和SS设备,其Default Control Endpoint允许的包大小是固定的,分别为8、64、512字节。对于FS设备,系统软件需要做一些操作来决定最大包大小(此处省略)。
- Default Control Endpoint配置完成后,系统软件可以获取到完整的Device Descriptor和Configuration Descriptor,以便将其交给适合的Class Drivers。(软件通过Endpoint 0的GET_DESCRIPTOR请求获取USB描述符)
- 软件会发出将Contxt Bit 0置为1的Evaluate Context命令,用来告知xHC最大退出延迟的值。此命令同样会修改Output Slot Context Interrupter部分字段的值。
- Class Driver会使用Configure EndPoint命令来配置Device Slot,并通过Default Control Endpoint发出USB SET_CONFIGURATION请求来设置USB设备。需要成功设置完这两项操作,才能将USB设备的状态从Address到Configured,并将Device SLot从Addressed变更为Configured。
- 如果需要,系统软件可能会配置Alternate Interface。
Resetting a Root Hub Port #
- 复位Root HUb port和连接上的USB设备。如果成功了,就会将PORT的状态设置为Enabled,并且可以获取到设备的Speed(位于PORTSC 的Port Speed)。
- 无论RESET是否执行成功,Port Reset Change(PRC)标志位都会置为1。如果PRC是从0变为1,则还会生成一个端口变更事件。
Device Slot Assignment #
- 当执行完RESET PORT后,软件会向XHC发出一个Enable Slot命令(通过Command Ring),
Device Slot Initialization #
- 一旦USB设备获得了Slot ID,软件会初始化SLOT对应的数据结构,流程如下:
- 初始化Input Context Data 数据结构,将所有字段初始化为0。
描述符 #
设备描述符 #
- 设备描述符用于表示USB设备的一般信息,如制造商ID、产品序列号等。
- 设备上电时,主机USB系统软件读取设备描述符的前8字节,得到endpoint所支持的最大数据包长度,后续控制传输就使用此值进行工作。
typedef struct {
UINT8 Length; //描述符字节长度0X12
UINT8 DescriptorType; //描述符的类型
UINT16 BcdUSB; //USB设备支持的协议版本号
UINT8 DeviceClass; //设备类代码
UINT8 DeviceSubClass; //子类代码
UINT8 DeviceProtocol; //协议码
UINT8 MaxPacketSize0; //断点0的最大包长度
UINT16 IdVendor; //厂商ID
UINT16 IdProduct; //产品ID
UINT16 BcdDevice; //设备发行号
UINT8 StrManufacturer; //厂商信息的字符串描述符索引值
UINT8 StrProduct; //产品信息的字符串描述符索引值
UINT8 StrSerialNumber; //设备序列号信息的字符串描述符索引值
UINT8 NumConfigurations; //配置描述符数目
} USB_DEVICE_DESCRIPTOR;
/*
案例
------------------------------------------
Device Descriptor
bLength : 0x0012
bDescriptorType : 0x0001
bcdUSB : 0x0320 - Spec# = 03.20
bDeviceClass : 0x00 - Defined at Interface level
bDeviceSubClass : 0x00
bDeviceProtocol : 0x00
bMaxEP0Size : 0x09 - 9 bytes
idVendor : 0x0B95 - "ASIX Electronics Corp."
idProduct : 0x1790 - "AX88179 Gigabit Ethernet"
bcdDevice : 0x0200 - Device# = 02.00
iManufacturer : 0x01 - "ASIX"
iProduct : 0x02 - "AX88179A"
iSerialNumber : 0x03 - "00F30573"
bNumConfigurations : 0x03
------------------------------------------
*/