diff --git a/kernel/common/kprint.h b/kernel/common/kprint.h index 25100c5b..588ead27 100644 --- a/kernel/common/kprint.h +++ b/kernel/common/kprint.h @@ -35,7 +35,7 @@ printk("[ DEBUG ] (%s:%d)\t", __FILE__, __LINE__); \ printk(__VA_ARGS__); \ printk("\n"); \ - } while (0); + } while (0) #define kwarn(...) \ do \ diff --git a/kernel/driver/usb/xhci/xhci.c b/kernel/driver/usb/xhci/xhci.c index 22358007..22000c4d 100644 --- a/kernel/driver/usb/xhci/xhci.c +++ b/kernel/driver/usb/xhci/xhci.c @@ -46,6 +46,18 @@ 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 cid 主机控制器id + * @param pid 端口id + */ +#define XHCI_PORT_IS_USB2(cid, pid) ((xhci_hc[cid].ports[pid].flags & XHCI_PROTOCOL_INFO) == XHCI_PROTOCOL_USB2) +#define XHCI_PORT_IS_USB3(cid, pid) ((xhci_hc[cid].ports[pid].flags & XHCI_PROTOCOL_INFO) == XHCI_PROTOCOL_USB3) + +#define XHCI_PORT_IS_USB2_HSO(cid, pid) ((xhci_hc[cid].ports[pid].flags & XHCI_PROTOCOL_HSO) == XHCI_PROTOCOL_HSO) +#define XHCI_PORT_HAS_PAIR(cid, pid) ((xhci_hc[cid].ports[pid].flags & XHCI_PROTOCOL_HAS_PAIR) == XHCI_PROTOCOL_HAS_PAIR) +#define XHCI_PORT_IS_ACTIVE(cid, pid) ((xhci_hc[cid].ports[pid].flags & XHCI_PROTOCOL_ACTIVE) == XHCI_PROTOCOL_ACTIVE) + #define FAIL_ON(value, to) \ do \ { \ @@ -172,6 +184,53 @@ static int xhci_hc_stop_legacy(int id) return 0; } +/** + * @brief + * + * @return uint32_t + */ + +/** + * @brief 在Ex capability list中寻找符合指定的协议号的寄存器offset、count、flag信息 + * + * @param id 主机控制器id + * @param list_off 列表项位置距离控制器虚拟基地址的偏移量 + * @param version 要寻找的端口版本号(2或3) + * @param offset 返回的 Compatible Port Offset + * @param count 返回的 Compatible Port Count + * @param protocol_flag 返回的与协议相关的flag + * @return uint32_t 下一个列表项的偏移量 + */ +static uint32_t xhci_hc_get_protocol_offset(int id, uint32_t list_off, const int version, uint32_t *offset, uint32_t *count, uint16_t *protocol_flag) +{ + if (count) + *count = 0; + + do + { + uint32_t dw0 = xhci_read_cap_reg32(id, list_off); + uint32_t next_list_off = (dw0 >> 8) & 0xff; + next_list_off = next_list_off ? (list_off + (next_list_off << 2)) : 0; + + if ((dw0 & 0xff) == XHCI_XECP_ID_PROTOCOL && ((dw0 & 0xff000000) >> 24) == version) + { + uint32_t dw2 = xhci_read_cap_reg32(id, list_off + 8); + + if (offset != NULL) + *offset = (uint32_t)(dw2 & 0xff); + if (count != NULL) + *count = (uint32_t)((dw2 & 0xff00) >> 8); + if (protocol_flag != NULL) + *protocol_flag = (uint16_t)((dw2 >> 16) & 0xffff); + + return next_list_off; + } + + list_off = next_list_off; + } while (list_off); + + return 0; +} /** * @brief 配对xhci主机控制器的usb2、usb3端口 * @@ -192,10 +251,102 @@ static int xhci_hc_pair_ports(int id) // 从hcs1获取端口数量 xhci_hc[id].port_num = hcs1.max_ports; - kinfo("Found %d ports on xhci root hub.", hcs1.max_ports); // 找到所有的端口并标记其端口信息 + xhci_hc[id].port_num_u2 = 0; + xhci_hc[id].port_num_u3 = 0; + + uint32_t next_off = xhci_hc[id].ext_caps_off; + uint32_t offset, cnt; + uint16_t protocol_flags; + + // 寻找所有的usb2端口 + while (next_off) + { + next_off = xhci_hc_get_protocol_offset(id, next_off, 2, &offset, &cnt, &protocol_flags); + + if (cnt) + { + for (int i = 0; i < cnt; ++i) + { + xhci_hc[id].ports[offset + i].offset = ++xhci_hc[id].port_num_u2; + xhci_hc[id].ports[offset + i].flags = XHCI_PROTOCOL_USB2; + + // usb2 high speed only + if (protocol_flags & 2) + xhci_hc[id].ports[offset + i].flags |= XHCI_PROTOCOL_HSO; + } + } + } + + // 寻找所有的usb3端口 + next_off = xhci_hc[id].ext_caps_off; + while (next_off) + { + next_off = xhci_hc_get_protocol_offset(id, next_off, 3, &offset, &cnt, &protocol_flags); + + if (cnt) + { + for (int i = 0; i < cnt; ++i) + { + xhci_hc[id].ports[offset + i].offset = ++xhci_hc[id].port_num_u3; + xhci_hc[id].ports[offset + i].flags = XHCI_PROTOCOL_USB3; + } + } + } + + // 将对应的USB2端口和USB3端口进行配对 + for (int i = 1; i <= xhci_hc[id].port_num; ++i) + { + for (int j = i; j <= xhci_hc[id].port_num; ++j) + { + if (unlikely(i == j)) + continue; + + if ((xhci_hc[id].ports[i].offset == xhci_hc[id].ports[j].offset) && + ((xhci_hc[id].ports[i].flags & XHCI_PROTOCOL_INFO) != (xhci_hc[id].ports[j].flags & XHCI_PROTOCOL_INFO))) + { + xhci_hc[id].ports[i].paired_port_num = j; + xhci_hc[id].ports[i].flags |= XHCI_PROTOCOL_HAS_PAIR; + + xhci_hc[id].ports[j].paired_port_num = i; + xhci_hc[id].ports[j].flags |= XHCI_PROTOCOL_HAS_PAIR; + } + } + } + + // 标记所有的usb3端口为激活状态 + for (int i = 1; i <= xhci_hc[id].port_num; ++i) + { + if (XHCI_PORT_IS_USB3(id, i) || + (XHCI_PORT_IS_USB2(id, i) && (!XHCI_PORT_HAS_PAIR(id, i)))) + xhci_hc[id].ports[i].flags |= XHCI_PROTOCOL_ACTIVE; + } + kinfo("Found %d ports on root hub, usb2 ports:%d, usb3 ports:%d", xhci_hc[id].port_num, xhci_hc[id].port_num_u2, xhci_hc[id].port_num_u3); + + /* + // 打印配对结果 + for (int i = 1; i <= xhci_hc[id].port_num; ++i) + { + if (XHCI_PORT_IS_USB3(id, i)) + { + kdebug("USB3 port %d, offset=%d, pair with usb2 port %d, current port is %s", i, xhci_hc[id].ports[i].offset, + xhci_hc[id].ports[i].paired_port_num, XHCI_PORT_IS_ACTIVE(id, i) ? "active" : "inactive"); + } + else if (XHCI_PORT_IS_USB2(id, i) && (!XHCI_PORT_HAS_PAIR(id, i))) // 单独的2.0接口 + { + kdebug("Stand alone USB2 port %d, offset=%d, current port is %s", i, xhci_hc[id].ports[i].offset, + XHCI_PORT_IS_ACTIVE(id, i) ? "active" : "inactive"); + } + else if (XHCI_PORT_IS_USB2(id, i)) + { + kdebug("USB2 port %d, offset=%d, current port is %s, has pair=%s", i, xhci_hc[id].ports[i].offset, + XHCI_PORT_IS_ACTIVE(id, i) ? "active" : "inactive", XHCI_PORT_HAS_PAIR(id, i)?"true":"false"); + } + } + */ + return 0; } @@ -230,7 +381,7 @@ void xhci_init(struct pci_device_structure_general_device_t *dev_hdr) // 为当前控制器映射寄存器地址空间 xhci_hc[cid].vbase = SPECIAL_MEMOEY_MAPPING_VIRT_ADDR_BASE + XHCI_MAPPING_OFFSET + 65536 * xhci_hc[cid].controller_id; - kdebug("dev_hdr->BAR0 & (~0xf)=%#018lx", dev_hdr->BAR0 & (~0xf)); + // kdebug("dev_hdr->BAR0 & (~0xf)=%#018lx", dev_hdr->BAR0 & (~0xf)); mm_map_phys_addr(xhci_hc[cid].vbase, dev_hdr->BAR0 & (~0xf), 65536, PAGE_KERNEL_PAGE | PAGE_PWT | PAGE_PCD, true); // 读取xhci控制寄存器 diff --git a/kernel/driver/usb/xhci/xhci.h b/kernel/driver/usb/xhci/xhci.h index 3270e31e..f9e09dfb 100644 --- a/kernel/driver/usb/xhci/xhci.h +++ b/kernel/driver/usb/xhci/xhci.h @@ -2,8 +2,8 @@ #include #include -#define XHCI_MAX_HOST_CONTROLLERS 8 -#define XHCI_MAX_ROOT_HUB_PORTS 128 +#define XHCI_MAX_HOST_CONTROLLERS 4 // 本驱动程序最大支持4个xhci root hub controller +#define XHCI_MAX_ROOT_HUB_PORTS 128 // 本驱动程序最大支持127个root hub 端口(第0个保留) // xhci Capability Registers offset #define XHCI_CAPS_CAPLENGTH 0x00 // Cap 寄存器组的长度 @@ -141,7 +141,7 @@ struct xhci_ops_config_reg_t // ID 部分的含义定义 #define XHCI_XECP_ID_RESERVED 0 #define XHCI_XECP_ID_LEGACY 1 // USB Legacy Support -#define XHCI_XECP_ID_PROTOCAL 2 // Supported protocal +#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 @@ -154,6 +154,14 @@ struct xhci_ops_config_reg_t #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端口信息 * @@ -179,7 +187,7 @@ struct xhci_host_controller_t uint16_t port_num; // 总的端口数量 uint8_t port_num_u2; // usb 2.0端口数量 uint8_t port_num_u3; // usb 3端口数量 - struct xhci_port_info_t ports[XHCI_MAX_ROOT_HUB_PORTS]; // 指向端口信息数组的指针 + struct xhci_port_info_t ports[XHCI_MAX_ROOT_HUB_PORTS]; // 指向端口信息数组的指针(由于端口offset是从1开始的,因此该数组第0项为空) }; /** diff --git a/run.sh b/run.sh index f4e88707..193dd056 100644 --- a/run.sh +++ b/run.sh @@ -112,7 +112,7 @@ if [ $flag_can_run -eq 1 ]; then -device ahci,id=ahci \ -device ide-hd,drive=disk,bus=ahci.0 \ -usb \ - -device qemu-xhci,id=xhci + -device qemu-xhci,id=xhci,p2=8,p3=4 fi else