XHCI 命令传输(构建Command TRB)_xjc命令
- Command TRB是Command Ring的一个Work Item。XHCI支持的常用命令如下:
Name | Description | TRB ID |
No Op | 测试TRB Ring | 8 |
Enable Slot | 获取USB设备唯一Slot ID,USB设备从Disabled状态进入到Default状态 | 9 |
Disable Slot | USB设备从任何状态转换为Disabled状态,任何Pending的传输终止。设备Slot ID释放,可用。 | 10 |
Address Device | 使能USB设备的默认控制端点,USB设备进入到Addressed状态 | 11 |
Configure Endpoint | Enable/Disable 设备的特定端点 | 12 |
Evaluate Context | 通知XHCI,驱动已经修改了Context数据参数 | 13 |
Reset Endpoint | 重置特定端点。用来recovery 因错误停止的端点。 | 14 |
Stop Endpoint | 停止/放弃USB端点上的传输。 | 15 |
Set TR Dequeue Point | 更新端点Transfer Ring出队指针 | 16 |
Reset Device | 重置特定USB Device Slot。用来同步Device Slot状态 | 17 |
- 常用命令格式
No Op Command TRB ,Enable Slot Command TRB,Disable Slot Command TRB,
RsvdZ | |||
RsvdZ | |||
RsvdZ | |||
RsvdZ | TRB ID | RsvdZ | Cycle bit(C) |
Address Device Command TRB
Input Context Pointer Lo | RsvdZ | ||||
Input Context Pointer Lo | |||||
RsvdZ | |||||
Slot ID | RsvdZ | TRB ID | BSR | RsvdZ | Cycle bit(C) |
Configure Endpoint Command TRB
Input Context Pointer Lo | RsvdZ | ||||
Input Context Pointer Lo | |||||
RsvdZ | |||||
Slot ID | RsvdZ | TRB ID | DC | RsvdZ | Cycle bit(C) |
- 代码逻辑
构建 命令TRB
//TRB数据结构描述
struct XhciTrb {
UINT32 PtrLow; //word0
UINT32 PtrHign; //word1
UINT32 Status; //word2
UINT32 Control; //word3
}
填充TRB
static void XhciTrbFill (XhciRing TrbRing, void *Data, UINT32 DataLength,UINT32 CtrlFlag)
{
//根据Command Ring入队指针,获取如果指针对应的TRB,用来填充正确的数据
XhciTrb *DstTrb = &TrbRing->Ring[Ring->Eidx];
//如果是Immediate data,TRB中填入直接数据
if (CtrlFlags & TRB_TR_IDT) {
Memcpy(&DstTrb->PtrLow, Data, DataLength);
} else {
//否则TRB中的PtrLow字段是数据在内存中的地址
DstTrb->PtrLow = (UINT32)Data;
DstTrb->PtrHign = 0;
}
//写入命令数据参数长度
DstTrb->Status = DataLength;
//写入xHCI驱动维护的Produce Cycle State PCS到TRB的CS位置
//将flag写入TRB的dword[3]
DstTrb->Control = CtrlFlag | (TrbRing->Cs ? TRB_C : 0);
}
将TRB入队到队列Ring
XhciTrbQueue (XhciRing TrbRing,void *Data,UINT32 DataLength, UINT32 Flags)
{
//如果入队指针索引nidx大于TrbRing array size,构建link TRB,反转PCS,入队索引nidx回到第一个
if (TrbRing->Eidx >= ARRAY_SIZE(TrbRing->Ring) - 1) {
XhciTrbFill(TrbRing, TrbRing->Ring, 0, (TR_LINK << 10) | TRB_LK_TC);
TrbRing->Eidx = 0;
TrbRing->Cs ^= 1;
}
//填充TrbRing[Eidx]的TRB
XhciTrbFill(TrbRing, Data, DataLength, Flags);
//更新驱动软件维护的Ring的入队指针
TrbRing->Eidx++;
}
通知XHCI 有TRB Ring需要处理,也就是响门铃
void XhciDoorbell(UsbXhci *Xhci, UINT32 SlotId, UINT32 Value)
{
void *Addr = &Db[Slotid].Doorbell;
MmioWrite32(Addr, Value);
}
XHCI 包含256个32-bit Doorbell 寄存器,每个寄存器透过slotid索引。Doorbell register 0被xHCI占用,用做命令传输,Doorbell 1-255用做Device Context Doorbell寄存器。当xHCI驱动软件构建一个传输任务,插入TRB到相应的TRB ring后,Ring相应的Doorbell 寄存器通知xHC有TRB ring需要传输。
Door Bell寄存器格式如下:
DB Stream ID | RsvdZ | DB Target |