XHCI 命令传输(构建Command TRB)_xjc命令

XHCI 命令传输(构建Command TRB)_xjc命令

编码文章call10242025-09-22 15:47:341A+A-
  • 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

点击这里复制本文地址 以上内容由文彬编程网整理呈现,请务必在转载分享时注明本文地址!如对内容有疑问,请联系我们,谢谢!
qrcode

文彬编程网 © All Rights Reserved.  蜀ICP备2024111239号-4