diff --git a/kernel/driver/usb/xhci/xhci.c b/kernel/driver/usb/xhci/xhci.c index efea0cf2..c23def95 100644 --- a/kernel/driver/usb/xhci/xhci.c +++ b/kernel/driver/usb/xhci/xhci.c @@ -6,6 +6,8 @@ #include #include #include +#include +#include spinlock_t xhci_controller_init_lock; // xhci控制器初始化锁(在usb_init中被初始化) @@ -13,6 +15,20 @@ static int xhci_ctrl_count = 0; // xhci控制器计数 static struct xhci_host_controller_t xhci_hc[XHCI_MAX_HOST_CONTROLLERS] = {0}; +void xhci_hc_irq_enable(uint64_t irq_num); +void xhci_hc_irq_disable(uint64_t irq_num); +uint64_t xhci_hc_irq_install(uint64_t irq_num, void *arg); +void xhci_hc_irq_uninstall(uint64_t irq_num); + +hardware_intr_controller xhci_hc_intr_controller = + { + .enable = xhci_hc_irq_enable, + .disable = xhci_hc_irq_disable, + .install = xhci_hc_irq_install, + .uninstall = xhci_hc_irq_uninstall, + .ack = apic_local_apic_edge_ack, +}; + /* 注意!!! @@ -47,6 +63,23 @@ static struct xhci_host_controller_t xhci_hc[XHCI_MAX_HOST_CONTROLLERS] = {0}; #define xhci_get_ptr_op_reg64(id, offset) ((uint64_t *)(xhci_hc[id].vbase_op + offset)) #define xhci_write_op_reg64(id, offset, value) (*(uint64_t *)(xhci_hc[id].vbase_op + offset) = (uint64_t)value) +/** + * @brief 计算中断寄存器组虚拟地址 + * @param id 主机控制器id + * @param num xhci中断寄存器组号 + */ +#define xhci_calc_intr_vaddr(id, num) (xhci_hc[id].vbase + xhci_hc[id].rts_offset + XHCI_RT_IR0 + num * XHCI_IR_SIZE) +/** + * @brief 读取/写入中断寄存器 + * @param id 主机控制器id + * @param num xhci中断寄存器组号 + * @param intr_offset 寄存器在当前寄存器组中的偏移量 + */ +#define xhci_read_intr_reg32(id, num, intr_offset) (*(uint32_t *)(xhci_calc_intr_vaddr(id, num) + intr_offset)) +#define xhci_write_intr_reg32(id, num, intr_offset, value) (*(uint32_t *)(xhci_calc_intr_vaddr(id, num) + intr_offset) = value) +#define xhci_read_intr_reg64(id, num, intr_offset) (*(uint64_t *)(xhci_calc_intr_vaddr(id, num) + intr_offset)) +#define xhci_write_intr_reg64(id, num, intr_offset, value) (*(uint64_t *)(xhci_calc_intr_vaddr(id, num) + intr_offset) = value) + #define xhci_is_aligned64(addr) ((addr & 0x3f) == 0) // 是否64bytes对齐 /** @@ -243,6 +276,28 @@ static int xhci_hc_stop_legacy(int id) return 0; } +/** + * @brief 启用指定xhci控制器的调度 + * + * @param id 控制器id + * @return int + */ +static int xhci_hc_start_sched(int id) +{ + xhci_write_op_reg32(id, XHCI_OPS_USBCMD, (1 << 0) | (1 >> 2) | (1 << 3)); +} + +/** + * @brief 停止指定xhci控制器的调度 + * + * @param id 控制器id + * @return int + */ +static int xhci_hc_stop_sched(int id) +{ + xhci_write_op_reg32(id, XHCI_OPS_USBCMD, 0x00); +} + /** * @brief * @@ -300,7 +355,7 @@ static int xhci_hc_pair_ports(int id) { struct xhci_caps_HCSPARAMS1_reg_t hcs1; - memcpy(&hcs1, xhci_get_ptr_cap_reg32(id, XHCI_CAPS_HCSPARAMS1), sizeof(struct xhci_caps_HCCPARAMS1_reg_t)); + memcpy(&hcs1, xhci_get_ptr_cap_reg32(id, XHCI_CAPS_HCSPARAMS1), sizeof(struct xhci_caps_HCSPARAMS1_reg_t)); // 从hcs1获取端口数量 xhci_hc[id].port_num = hcs1.max_ports; @@ -407,13 +462,13 @@ static int xhci_hc_pair_ports(int id) * @brief 创建ring,并将最后一个trb指向头一个trb * * @param trbs 要创建的trb数量 - * @return uint64_t + * @return uint64_t trb数组的起始虚拟地址 */ static uint64_t xhci_create_ring(int trbs) { int total_size = trbs * sizeof(struct xhci_TRB_t); const uint64_t vaddr = (uint64_t)kmalloc(total_size, 0); - memset(vaddr, 0, total_size); + memset((void *)vaddr, 0, total_size); // 设置最后一个trb为link trb xhci_TRB_set_link_cmd(vaddr + total_size - sizeof(sizeof(struct xhci_TRB_t))); @@ -421,6 +476,150 @@ static uint64_t xhci_create_ring(int trbs) return vaddr; } +/** + * @brief 创建新的event ring table和对应的ring segment + * + * @param trbs 包含的trb的数量 + * @param ret_ring_addr 返回的第一个event ring segment的基地址(虚拟) + * @return uint64_t trb table的虚拟地址 + */ +static uint64_t xhci_create_event_ring(int trbs, uint64_t *ret_ring_addr) +{ + const uint64_t table_vaddr = (const uint64_t)kmalloc(64, 0); // table支持8个segment + if (unlikely(table_vaddr == NULL)) + return -ENOMEM; + memset((void *)table_vaddr, 0, 64); + + // 暂时只创建1个segment + const uint64_t seg_vaddr = (const uint64_t)kmalloc(trbs * sizeof(struct xhci_TRB_t), 0); + + if (unlikely(seg_vaddr == NULL)) + return -ENOMEM; + + memset((void *)seg_vaddr, 0, trbs * sizeof(struct xhci_TRB_t)); + + // 将segment地址和大小写入table + *(uint64_t *)(table_vaddr) = virt_2_phys(seg_vaddr); + *(uint64_t *)(table_vaddr + 8) = trbs; + + *ret_ring_addr = seg_vaddr; + return table_vaddr; +} + +void xhci_hc_irq_enable(uint64_t irq_num) +{ + int cid = xhci_find_hcid_by_irq_num(irq_num); + if (WARN_ON(cid == -1)) + return; + pci_start_msi(xhci_hc[cid].pci_dev_hdr); + + xhci_hc_start_sched(cid); +} + +void xhci_hc_irq_disable(uint64_t irq_num) +{ + int cid = xhci_find_hcid_by_irq_num(irq_num); + if (WARN_ON(cid == -1)) + return; + + xhci_hc_stop_sched(cid); + pci_disable_msi(xhci_hc[cid].pci_dev_hdr); +} + +uint64_t xhci_hc_irq_install(uint64_t irq_num, void *arg) +{ + int cid = xhci_find_hcid_by_irq_num(irq_num); + if (WARN_ON(cid == -1)) + return -EINVAL; + + struct xhci_hc_irq_install_info_t *info = (struct xhci_hc_irq_install_info_t *)arg; + + pci_enable_msi(xhci_hc[cid].pci_dev_hdr, irq_num, info->processor, info->edge_trigger, info->assert); + return 0; +} + +void xhci_hc_irq_uninstall(uint64_t irq_num) +{ + // todo + int cid = xhci_find_hcid_by_irq_num(irq_num); + if (WARN_ON(cid == -1)) + return; + xhci_hc_stop(cid); +} +/** + * @brief xhci主机控制器的中断处理函数 + * + * @param irq_num 中断向量号 + * @param cid 控制器号 + * @param regs 寄存器值 + */ +void xhci_hc_irq_handler(uint64_t irq_num, uint64_t cid, struct pt_regs *regs) +{ + // todo: handle irq + kdebug("USB irq received."); +} + +/** + * @brief 初始化xhci主机控制器的中断控制 + * + * @param id 主机控制器id + * @return int 返回码 + */ +static int xhci_hc_init_intr(int id) +{ + uint64_t retval = 0; + + struct xhci_caps_HCSPARAMS1_reg_t hcs1; + struct xhci_caps_HCSPARAMS2_reg_t hcs2; + memcpy(&hcs1, xhci_get_ptr_cap_reg32(id, XHCI_CAPS_HCSPARAMS1), sizeof(struct xhci_caps_HCSPARAMS1_reg_t)); + memcpy(&hcs2, xhci_get_ptr_cap_reg32(id, XHCI_CAPS_HCSPARAMS2), sizeof(struct xhci_caps_HCSPARAMS2_reg_t)); + + uint32_t max_segs = (1 << (uint32_t)(hcs2.ERST_Max)); + uint32_t max_interrupters = hcs1.max_intrs; + + // 创建 event ring + retval = xhci_create_event_ring(4096, &xhci_hc[id].event_ring_vaddr); + if (unlikely((int64_t)(retval) == -ENOMEM)) + return -ENOMEM; + xhci_hc[id].event_ring_table_vaddr = retval; + retval = 0; + + xhci_hc[id].current_event_ring_cycle = 1; + + // 写入第0个中断寄存器组 + xhci_write_intr_reg32(id, 0, XHCI_IR_MAN, 0x3); // 使能中断并清除pending位(这个pending位是写入1就清0的) + xhci_write_intr_reg32(id, 0, XHCI_IR_MOD, 0); // 关闭中断管制 + xhci_write_intr_reg32(id, 0, XHCI_IR_TABLE_SIZE, 1); // 当前只有1个segment + xhci_write_intr_reg64(id, 0, XHCI_IR_DEQUEUE, virt_2_phys(xhci_hc[id].event_ring_vaddr) | (1 << 3)); // 写入dequeue寄存器,并清除busy位(写1就会清除) + xhci_write_intr_reg64(id, 0, XHCI_IR_TABLE_ADDR, virt_2_phys(xhci_hc[id].event_ring_table_vaddr)); // 写入table地址 + + // 清除状态位 + struct xhci_ops_usbsts_reg_t sts = {0}; + sts.hse = 1; + sts.eint = 1; + sts.pcd = 1; + sts.sre = 1; + kdebug("new_sts=%#010lx", *(uint32_t *)(&sts)); + xhci_write_op_reg32(id, XHCI_OPS_USBSTS, *(uint32_t *)(&sts)); + + // 开启usb中断 + // 注册中断处理程序 + struct xhci_hc_irq_install_info_t install_info; + install_info.assert = 0; + install_info.edge_trigger = 1; + install_info.processor = 0; // 投递到bsp + + char *buf = (char *)kmalloc(16, 0); + memset(buf, 0, 16); + sprintk(buf, "xHCI HC%d", id); + irq_register(xhci_controller_irq_num[id], &install_info, &xhci_hc_irq_handler, id, &xhci_hc_intr_controller, buf); + kfree(buf); + + kdebug("xhci host controller %d: interrupt registered. irq num=%d", id, xhci_controller_irq_num[id]); + + return 0; +} + /** * @brief 初始化xhci控制器 * @@ -464,9 +663,9 @@ void xhci_init(struct pci_device_structure_general_device_t *dev_hdr) struct xhci_caps_HCSPARAMS1_reg_t hcs1; struct xhci_caps_HCSPARAMS2_reg_t hcs2; memcpy(&hcc1, xhci_get_ptr_cap_reg32(cid, XHCI_CAPS_HCCPARAMS1), sizeof(struct xhci_caps_HCCPARAMS1_reg_t)); - memcpy(&hcc2, xhci_get_ptr_cap_reg32(cid, XHCI_CAPS_HCCPARAMS2), sizeof(struct xhci_caps_HCCPARAMS1_reg_t)); - memcpy(&hcs1, xhci_get_ptr_cap_reg32(cid, XHCI_CAPS_HCSPARAMS1), sizeof(struct xhci_caps_HCCPARAMS1_reg_t)); - memcpy(&hcs2, xhci_get_ptr_cap_reg32(cid, XHCI_CAPS_HCSPARAMS2), sizeof(struct xhci_caps_HCCPARAMS1_reg_t)); + memcpy(&hcc2, xhci_get_ptr_cap_reg32(cid, XHCI_CAPS_HCCPARAMS2), sizeof(struct xhci_caps_HCCPARAMS2_reg_t)); + memcpy(&hcs1, xhci_get_ptr_cap_reg32(cid, XHCI_CAPS_HCSPARAMS1), sizeof(struct xhci_caps_HCSPARAMS1_reg_t)); + memcpy(&hcs2, xhci_get_ptr_cap_reg32(cid, XHCI_CAPS_HCSPARAMS2), sizeof(struct xhci_caps_HCSPARAMS2_reg_t)); // kdebug("hcc1.xECP=%#010lx", hcc1.xECP); // 计算operational registers的地址 @@ -500,13 +699,14 @@ void xhci_init(struct pci_device_structure_general_device_t *dev_hdr) // 端口配对 FAIL_ON(xhci_hc_pair_ports(cid), failed); + // ========== 设置USB host controller ========= // 获取页面大小 xhci_hc[cid].page_size = (xhci_read_op_reg32(cid, XHCI_OPS_PAGESIZE) & 0xffff) << 12; - kdebug("pg size=%d", xhci_hc[cid].page_size); + kdebug("page size=%d", xhci_hc[cid].page_size); // 获取设备上下文空间 xhci_hc[cid].dcbaap_vaddr = (uint64_t)kmalloc(2048, 0); // 分配2KB的设备上下文地址数组空间 - memset(xhci_hc[cid].dcbaap_vaddr, 0, 2048); + memset((void *)xhci_hc[cid].dcbaap_vaddr, 0, 2048); kdebug("dcbaap_vaddr=%#018lx", xhci_hc[cid].dcbaap_vaddr); if (unlikely(!xhci_is_aligned64(xhci_hc[cid].dcbaap_vaddr))) // 地址不是按照64byte对齐 @@ -516,14 +716,42 @@ void xhci_init(struct pci_device_structure_general_device_t *dev_hdr) } // 写入dcbaap xhci_write_cap_reg64(cid, XHCI_OPS_DCBAAP, virt_2_phys(xhci_hc[cid].dcbaap_vaddr)); + + // 创建command ring xhci_hc[cid].cmd_ring_vaddr = xhci_create_ring(XHCI_CMND_RING_TRBS); + if (unlikely(!xhci_is_aligned64(xhci_hc[cid].cmd_ring_vaddr))) // 地址不是按照64byte对齐 + { + kerror("cmd ring isn't 64 byte aligned."); + goto failed_free_dyn; + } + + // 设置初始cycle bit为1 + xhci_hc[cid].cmd_trb_cycle = XHCI_TRB_CYCLE_ON; + + // 写入command ring控制寄存器 + xhci_write_op_reg64(cid, XHCI_OPS_CRCR, virt_2_phys(xhci_hc[cid].cmd_ring_vaddr) | xhci_hc[cid].cmd_trb_cycle); + // 写入配置寄存器 + xhci_write_op_reg32(cid, XHCI_OPS_CONFIG, hcs1.max_slots); + // 写入设备通知控制寄存器 + xhci_write_op_reg32(cid, XHCI_OPS_DNCTRL, (1 << 1)); // 目前只有N1被支持 + + FAIL_ON(xhci_hc_init_intr(cid), failed_free_dyn); ++xhci_ctrl_count; spin_unlock(&xhci_controller_init_lock); return; failed_free_dyn:; // 释放动态申请的内存 if (xhci_hc[cid].dcbaap_vaddr) - kfree(xhci_hc[cid].dcbaap_vaddr); + kfree((void *)xhci_hc[cid].dcbaap_vaddr); + + if (xhci_hc[cid].cmd_ring_vaddr) + kfree((void *)xhci_hc[cid].cmd_ring_vaddr); + + if (xhci_hc[cid].event_ring_table_vaddr) + kfree((void *)xhci_hc[cid].event_ring_table_vaddr); + + if (xhci_hc[cid].event_ring_vaddr) + kfree((void *)xhci_hc[cid].event_ring_vaddr); failed:; // 取消地址映射 diff --git a/kernel/driver/usb/xhci/xhci.h b/kernel/driver/usb/xhci/xhci.h index fa472952..4481a211 100644 --- a/kernel/driver/usb/xhci/xhci.h +++ b/kernel/driver/usb/xhci/xhci.h @@ -5,6 +5,35 @@ #define XHCI_MAX_HOST_CONTROLLERS 4 // 本驱动程序最大支持4个xhci root hub controller #define XHCI_MAX_ROOT_HUB_PORTS 128 // 本驱动程序最大支持127个root hub 端口(第0个保留) +// ========== irq BEGIN =========== +/** + * @brief 每个xhci控制器的中断向量号 + * + */ +const uint8_t xhci_controller_irq_num[XHCI_MAX_HOST_CONTROLLERS] = {157, 158, 159, 160}; + +/** + * @brief 通过irq号寻找对应的主机控制器id + * + */ +#define xhci_find_hcid_by_irq_num(irq_num) ({ \ + int retval = -1; \ + for (int i = 0; i < XHCI_MAX_HOST_CONTROLLERS; ++i) \ + if (xhci_controller_irq_num[i] == irq_num) \ + retval = i; \ + retval; \ +}) + +struct xhci_hc_irq_install_info_t +{ + int processor; // 中断目标处理器 + int8_t edge_trigger; // 是否边缘触发 + int8_t assert; // 是否高电平触发 +}; +// ========== irq END =========== + +// ======== Capability Register Set BEGIN ============ + // xhci Capability Registers offset #define XHCI_CAPS_CAPLENGTH 0x00 // Cap 寄存器组的长度 #define XHCI_CAPS_RESERVED 0x01 @@ -28,7 +57,7 @@ struct xhci_caps_HCSPARAMS1_reg_t struct xhci_caps_HCSPARAMS2_reg_t { unsigned ist : 4; // 同步调度阈值 - unsigned ERST_Max : 4; // Event Ring Segment Table Max + unsigned ERST_Max : 4; // Event Ring Segment Table: Max segs unsigned Reserved : 13; unsigned max_scratchpad_buf_HI5 : 5; // 草稿行buffer地址(高5bit) unsigned spr : 1; // scratchpad restore @@ -73,6 +102,9 @@ struct xhci_caps_HCCPARAMS2_reg_t unsigned cic : 1; // configuration information capability unsigned Reserved : 26; } __attribute__((packed)); +// ======== Capability Register Set END ============ + +// ======== Operational Register Set BEGIN ========= // xhci operational registers offset #define XHCI_OPS_USBCMD 0x00 // USB Command @@ -137,30 +169,8 @@ struct xhci_ops_config_reg_t unsigned rsvd_psvd : 22; // Reserved and Preserved } __attribute__((packed)); -// xhci Extended Capabilities List ID -// ID 部分的含义定义 -#define XHCI_XECP_ID_RESERVED 0 -#define XHCI_XECP_ID_LEGACY 1 // USB Legacy Support -#define XHCI_XECP_ID_PROTOCOL 2 // Supported protocol -#define XHCI_XECP_ID_POWER 3 // Extended power management -#define XHCI_XECP_ID_IOVIRT 4 // I/0 virtualization -#define XHCI_XECP_ID_MSG 5 // Message interrupt -#define XHCI_XECP_ID_LOCAL_MEM 6 // local memory -#define XHCI_XECP_ID_DEBUG 10 // USB Debug capability -#define XHCI_XECP_ID_EXTMSG 17 // Extended message interrupt - -#define XHCI_XECP_LEGACY_TIMEOUT 10 // 设置legacy状态的等待时间 -#define XHCI_XECP_LEGACY_BIOS_OWNED (1 << 16) // 当bios控制着该hc时,该位被置位 -#define XHCI_XECP_LEGACY_OS_OWNED (1 << 24) // 当系统控制着该hc时,该位被置位 -#define XHCI_XECP_LEGACY_OWNING_MASK (XHCI_XECP_LEGACY_BIOS_OWNED | XHCI_XECP_LEGACY_OS_OWNED) - -// 端口信息标志位 -#define XHCI_PROTOCOL_USB2 0 -#define XHCI_PROTOCOL_USB3 1 -#define XHCI_PROTOCOL_INFO (1 << 0) // 1->usb3, 0->usb2 -#define XHCI_PROTOCOL_HSO (1 << 1) // 1-> usb2 high speed only -#define XHCI_PROTOCOL_HAS_PAIR (1 << 2) // 当前位被置位,意味着当前端口具有一个与之配对的端口 -#define XHCI_PROTOCOL_ACTIVE (1 << 3) // 当前端口是这个配对中,被激活的端口 +// ======== Operational Register Set END ========= +// ========= TRB begin =========== // TRB的Transfer Type可用值定义 #define XHCI_TRB_TRT_NO_DATA 0 @@ -172,6 +182,9 @@ struct xhci_ops_config_reg_t #define XHCI_TRBS_PER_RING 256 +#define XHCI_TRB_CYCLE_OFF 0 +#define XHCI_TRB_CYCLE_ON 1 + /** * @brief xhci通用TRB结构 * @@ -285,6 +298,56 @@ struct xhci_TRB_cmd_complete_t uint8_t slot_id; // the id of the slot associated with the // command that generated the event } __attribute__((packed)); +// ========= TRB end =========== + +// ======== Runtime Register Set Begin ========= + +#define XHCI_RT_IR0 0x20 // 中断寄存器组0距离runtime Register set起始位置的偏移量 +#define XHCI_IR_SIZE 32 // 中断寄存器组大小 + +// 中断寄存器组内的偏移量 +#define XHCI_IR_MAN 0x00 // Interrupter Management Register +#define XHCI_IR_MOD 0x04 // Interrupter Moderation +#define XHCI_IR_TABLE_SIZE 0x08 // Event Ring Segment Table size (count of segments) +#define XHCI_IR_TABLE_ADDR 0x10 // Event Ring Segment Table Base Address +#define XHCI_IR_DEQUEUE 0x18 // Event Ring Dequeue Pointer + +// MAN寄存器内的bit的含义 +#define XHCI_IR_IMR_PENDING (1 << 0) // Interrupt pending bit in Management Register +#define XHCI_IR_IMR_ENABLE (1 << 1) // Interrupt enable bit in Management Register + +struct xhci_intr_moderation_t +{ + uint16_t interval; // 产生一个中断的时间,是interval*250ns (wait before next interrupt) + uint16_t counter; +} __attribute__((packed)); +// ======== Runtime Register Set END ========= + +// ======= xhci Extended Capabilities List ======== + +// ID 部分的含义定义 +#define XHCI_XECP_ID_RESERVED 0 +#define XHCI_XECP_ID_LEGACY 1 // USB Legacy Support +#define XHCI_XECP_ID_PROTOCOL 2 // Supported protocol +#define XHCI_XECP_ID_POWER 3 // Extended power management +#define XHCI_XECP_ID_IOVIRT 4 // I/0 virtualization +#define XHCI_XECP_ID_MSG 5 // Message interrupt +#define XHCI_XECP_ID_LOCAL_MEM 6 // local memory +#define XHCI_XECP_ID_DEBUG 10 // USB Debug capability +#define XHCI_XECP_ID_EXTMSG 17 // Extended message interrupt + +#define XHCI_XECP_LEGACY_TIMEOUT 10 // 设置legacy状态的等待时间 +#define XHCI_XECP_LEGACY_BIOS_OWNED (1 << 16) // 当bios控制着该hc时,该位被置位 +#define XHCI_XECP_LEGACY_OS_OWNED (1 << 24) // 当系统控制着该hc时,该位被置位 +#define XHCI_XECP_LEGACY_OWNING_MASK (XHCI_XECP_LEGACY_BIOS_OWNED | XHCI_XECP_LEGACY_OS_OWNED) + +// 端口信息标志位 +#define XHCI_PROTOCOL_USB2 0 +#define XHCI_PROTOCOL_USB3 1 +#define XHCI_PROTOCOL_INFO (1 << 0) // 1->usb3, 0->usb2 +#define XHCI_PROTOCOL_HSO (1 << 1) // 1-> usb2 high speed only +#define XHCI_PROTOCOL_HAS_PAIR (1 << 2) // 当前位被置位,意味着当前端口具有一个与之配对的端口 +#define XHCI_PROTOCOL_ACTIVE (1 << 3) // 当前端口是这个配对中,被激活的端口 /** * @brief xhci端口信息 @@ -314,6 +377,10 @@ struct xhci_host_controller_t uint8_t page_size; // page size uint64_t dcbaap_vaddr; // Device Context Base Address Array Pointer的虚拟地址 uint64_t cmd_ring_vaddr; // command ring的虚拟地址 + uint64_t event_ring_vaddr; // event ring的虚拟地址 + uint64_t event_ring_table_vaddr; // event ring table的虚拟地址 + uint8_t cmd_trb_cycle; // 当前command ring cycle + uint8_t current_event_ring_cycle; // 当前event ring cycle struct xhci_port_info_t ports[XHCI_MAX_ROOT_HUB_PORTS]; // 指向端口信息数组的指针(由于端口offset是从1开始的,因此该数组第0项为空) };