mirror of
https://github.com/DragonOS-Community/DragonOS.git
synced 2025-06-09 19:36:47 +00:00
bugfix: 解决了xhci驱动程序无法在真机上获取设备描述符的bug
This commit is contained in:
parent
2551e0a8c9
commit
94c960ae89
@ -17,7 +17,7 @@ static int usb_pdevs_count = 0;
|
|||||||
* @brief 初始化usb驱动程序
|
* @brief 初始化usb驱动程序
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
void usb_init()
|
int usb_init()
|
||||||
{
|
{
|
||||||
kinfo("Initializing usb driver...");
|
kinfo("Initializing usb driver...");
|
||||||
spin_init(&xhci_controller_init_lock);
|
spin_init(&xhci_controller_init_lock);
|
||||||
@ -30,7 +30,7 @@ void usb_init()
|
|||||||
kwarn("There is no usb hardware in this computer!");
|
kwarn("There is no usb hardware in this computer!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
kdebug("usb_pdevs_count=%d",usb_pdevs_count);
|
kdebug("usb_pdevs_count=%d", usb_pdevs_count);
|
||||||
// 初始化每个usb控制器
|
// 初始化每个usb控制器
|
||||||
for (volatile int i = 0; i < usb_pdevs_count; ++i)
|
for (volatile int i = 0; i < usb_pdevs_count; ++i)
|
||||||
{
|
{
|
||||||
@ -59,4 +59,5 @@ void usb_init()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
kinfo("Successfully initialized all usb host controllers!");
|
kinfo("Successfully initialized all usb host controllers!");
|
||||||
|
return 0;
|
||||||
}
|
}
|
@ -133,4 +133,4 @@ enum
|
|||||||
* @brief 初始化usb驱动程序
|
* @brief 初始化usb驱动程序
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
void usb_init();
|
int usb_init();
|
@ -47,9 +47,6 @@ static int xhci_data_stage(struct xhci_ep_ring_info_t *ep, uint64_t buf_vaddr, u
|
|||||||
static int xhci_status_stage(const int id, uint8_t direction, uint64_t status_buf_vaddr);
|
static int xhci_status_stage(const int id, uint8_t direction, uint64_t status_buf_vaddr);
|
||||||
static int xhci_wait_for_interrupt(const int id, uint64_t status_vaddr);
|
static int xhci_wait_for_interrupt(const int id, uint64_t status_vaddr);
|
||||||
|
|
||||||
static struct xhci_ep_context_t ep_ctx = {0};
|
|
||||||
struct xhci_slot_context_t slot_ctx = {0};
|
|
||||||
|
|
||||||
hardware_intr_controller xhci_hc_intr_controller =
|
hardware_intr_controller xhci_hc_intr_controller =
|
||||||
{
|
{
|
||||||
.enable = xhci_hc_irq_enable,
|
.enable = xhci_hc_irq_enable,
|
||||||
@ -732,7 +729,8 @@ void xhci_hc_irq_handler(uint64_t irq_num, uint64_t cid, struct pt_regs *regs)
|
|||||||
struct xhci_TRB_cmd_complete_t *event_trb_ptr = (struct xhci_TRB_cmd_complete_t *)&event_trb;
|
struct xhci_TRB_cmd_complete_t *event_trb_ptr = (struct xhci_TRB_cmd_complete_t *)&event_trb;
|
||||||
if ((event_trb.command & (1 << 2)) == 0) // 当前event trb不是由于short packet产生的
|
if ((event_trb.command & (1 << 2)) == 0) // 当前event trb不是由于short packet产生的
|
||||||
{
|
{
|
||||||
|
// kdebug("event_trb_ptr->code=%d", event_trb_ptr->code);
|
||||||
|
// kdebug("event_trb_ptr->TRB_type=%d", event_trb_ptr->TRB_type);
|
||||||
switch (event_trb_ptr->code) // 判断它的完成码
|
switch (event_trb_ptr->code) // 判断它的完成码
|
||||||
{
|
{
|
||||||
case TRB_COMP_TRB_SUCCESS: // trb执行成功,则将结果返回到对应的command ring的trb里面
|
case TRB_COMP_TRB_SUCCESS: // trb执行成功,则将结果返回到对应的command ring的trb里面
|
||||||
@ -813,9 +811,7 @@ static int xhci_reset_port(const int id, const int port)
|
|||||||
int retval = 0;
|
int retval = 0;
|
||||||
// 相对于op寄存器基地址的偏移量
|
// 相对于op寄存器基地址的偏移量
|
||||||
uint64_t port_status_offset = XHCI_OPS_PRS + port * 16;
|
uint64_t port_status_offset = XHCI_OPS_PRS + port * 16;
|
||||||
// kdebug("to reset %d, portsc=%#010lx", port, (xhci_read_op_reg32(id, port_status_offset + XHCI_PORT_PORTSC)));
|
|
||||||
// kdebug("to reset %d, usbcmd=%#010lx", port, xhci_read_op_reg32(id, XHCI_OPS_USBCMD));
|
|
||||||
// kdebug("to reset %d, usbsts=%#010lx", port, xhci_read_op_reg32(id, XHCI_OPS_USBSTS));
|
|
||||||
io_mfence();
|
io_mfence();
|
||||||
// 检查端口电源状态
|
// 检查端口电源状态
|
||||||
if ((xhci_read_op_reg32(id, port_status_offset + XHCI_PORT_PORTSC) & (1 << 9)) == 0)
|
if ((xhci_read_op_reg32(id, port_status_offset + XHCI_PORT_PORTSC) & (1 << 9)) == 0)
|
||||||
@ -847,20 +843,22 @@ static int xhci_reset_port(const int id, const int port)
|
|||||||
retval = -ETIMEDOUT;
|
retval = -ETIMEDOUT;
|
||||||
// kdebug("to wait reset timeout;");
|
// kdebug("to wait reset timeout;");
|
||||||
// 等待portsc的port reset change位被置位,说明reset完成
|
// 等待portsc的port reset change位被置位,说明reset完成
|
||||||
int timeout = 200;
|
int timeout = 100;
|
||||||
while (timeout)
|
while (timeout)
|
||||||
{
|
{
|
||||||
io_mfence();
|
io_mfence();
|
||||||
uint32_t val = xhci_read_op_reg32(id, port_status_offset + XHCI_PORT_PORTSC);
|
uint32_t val = xhci_read_op_reg32(id, port_status_offset + XHCI_PORT_PORTSC);
|
||||||
// kdebug("val=%#010lx", val);
|
|
||||||
io_mfence();
|
io_mfence();
|
||||||
|
if (val & (1 << 21))
|
||||||
|
break;
|
||||||
|
// QEMU对usb的模拟有bug,因此需要检测这里
|
||||||
|
#ifdef __QEMU_EMULATION__
|
||||||
|
|
||||||
if (XHCI_PORT_IS_USB3(id, port) && (val & (1 << 31)) == 0)
|
if (XHCI_PORT_IS_USB3(id, port) && (val & (1 << 31)) == 0)
|
||||||
break;
|
break;
|
||||||
else if (XHCI_PORT_IS_USB2(id, port) && (val & (1 << 4)) == 0)
|
else if (XHCI_PORT_IS_USB2(id, port) && (val & (1 << 4)) == 0)
|
||||||
break;
|
break;
|
||||||
else if (val & (1 << 21))
|
#endif
|
||||||
break;
|
|
||||||
|
|
||||||
--timeout;
|
--timeout;
|
||||||
usleep(500);
|
usleep(500);
|
||||||
}
|
}
|
||||||
@ -870,10 +868,11 @@ static int xhci_reset_port(const int id, const int port)
|
|||||||
{
|
{
|
||||||
// 等待恢复
|
// 等待恢复
|
||||||
usleep(USB_TIME_RST_REC * 100);
|
usleep(USB_TIME_RST_REC * 100);
|
||||||
// kdebug("to check if reset ok");
|
|
||||||
uint32_t val = xhci_read_op_reg32(id, port_status_offset + XHCI_PORT_PORTSC);
|
uint32_t val = xhci_read_op_reg32(id, port_status_offset + XHCI_PORT_PORTSC);
|
||||||
io_mfence();
|
io_mfence();
|
||||||
|
|
||||||
|
// kdebug("to check if reset ok, val=%#010lx", val);
|
||||||
|
|
||||||
// 如果reset之后,enable bit仍然是1,那么说明reset成功
|
// 如果reset之后,enable bit仍然是1,那么说明reset成功
|
||||||
if (val & (1 << 1))
|
if (val & (1 << 1))
|
||||||
{
|
{
|
||||||
@ -928,7 +927,7 @@ static uint64_t xhci_initialize_slot(const int id, const int slot_id, const int
|
|||||||
// kdebug("slot id=%d, device_context_vaddr=%#018lx, port=%d", slot_id, device_context_vaddr, port);
|
// kdebug("slot id=%d, device_context_vaddr=%#018lx, port=%d", slot_id, device_context_vaddr, port);
|
||||||
// 写到数组中
|
// 写到数组中
|
||||||
__write8b(xhci_hc[id].dcbaap_vaddr + (slot_id * sizeof(uint64_t)), virt_2_phys(device_context_vaddr));
|
__write8b(xhci_hc[id].dcbaap_vaddr + (slot_id * sizeof(uint64_t)), virt_2_phys(device_context_vaddr));
|
||||||
|
struct xhci_slot_context_t slot_ctx = {0};
|
||||||
slot_ctx.entries = 1;
|
slot_ctx.entries = 1;
|
||||||
slot_ctx.speed = speed;
|
slot_ctx.speed = speed;
|
||||||
slot_ctx.route_string = 0;
|
slot_ctx.route_string = 0;
|
||||||
@ -964,6 +963,7 @@ static void xhci_initialize_ep(const int id, const uint64_t slot_vaddr, const in
|
|||||||
// 由于目前只实现获取设备的描述符,因此暂时只支持control ep
|
// 由于目前只实现获取设备的描述符,因此暂时只支持control ep
|
||||||
if (type != USB_EP_CONTROL)
|
if (type != USB_EP_CONTROL)
|
||||||
return;
|
return;
|
||||||
|
struct xhci_ep_context_t ep_ctx = {0};
|
||||||
memset(&ep_ctx, 0, sizeof(struct xhci_ep_context_t));
|
memset(&ep_ctx, 0, sizeof(struct xhci_ep_context_t));
|
||||||
|
|
||||||
xhci_hc[id].control_ep_info.ep_ring_vbase = xhci_create_ring(XHCI_TRBS_PER_RING);
|
xhci_hc[id].control_ep_info.ep_ring_vbase = xhci_create_ring(XHCI_TRBS_PER_RING);
|
||||||
@ -1004,6 +1004,8 @@ static void xhci_initialize_ep(const int id, const uint64_t slot_vaddr, const in
|
|||||||
static int xhci_set_address(const int id, const uint64_t slot_vaddr, const int slot_id, const bool block)
|
static int xhci_set_address(const int id, const uint64_t slot_vaddr, const int slot_id, const bool block)
|
||||||
{
|
{
|
||||||
int retval = 0;
|
int retval = 0;
|
||||||
|
struct xhci_slot_context_t slot;
|
||||||
|
struct xhci_ep_context_t ep;
|
||||||
// 创建输入上下文缓冲区
|
// 创建输入上下文缓冲区
|
||||||
uint64_t input_ctx_buffer = (uint64_t)kzalloc(xhci_hc[id].context_size * 32, 0);
|
uint64_t input_ctx_buffer = (uint64_t)kzalloc(xhci_hc[id].context_size * 32, 0);
|
||||||
|
|
||||||
@ -1011,9 +1013,16 @@ static int xhci_set_address(const int id, const uint64_t slot_vaddr, const int s
|
|||||||
__write4b(input_ctx_buffer + 4, 0x3);
|
__write4b(input_ctx_buffer + 4, 0x3);
|
||||||
|
|
||||||
// 拷贝slot上下文和control ep上下文到输入上下文中
|
// 拷贝slot上下文和control ep上下文到输入上下文中
|
||||||
__write_slot(input_ctx_buffer + xhci_hc[id].context_size, (struct xhci_slot_context_t *)slot_vaddr);
|
|
||||||
|
|
||||||
__write_ep(id, input_ctx_buffer, 2, (struct xhci_ep_context_t *)(slot_vaddr + XHCI_EP_CONTROL * xhci_hc[id].context_size));
|
// __write_ep(id, input_ctx_buffer, 2, &ep_ctx);
|
||||||
|
__read_from_slot(&slot, slot_vaddr);
|
||||||
|
__read_from_ep(id, slot_vaddr, 1, &ep);
|
||||||
|
ep.err_cnt = 3;
|
||||||
|
kdebug("slot.slot_state=%d, speed=%d, root hub port num=%d", slot.slot_state, slot.speed, slot.rh_port_num);
|
||||||
|
kdebug("ep.type=%d, max_packet=%d, dequeue_ptr=%#018lx", ep.ep_type, ep.max_packet_size, ep.tr_dequeue_ptr);
|
||||||
|
|
||||||
|
__write_slot(input_ctx_buffer + xhci_hc[id].context_size, &slot);
|
||||||
|
__write_ep(id, input_ctx_buffer, 2, &ep);
|
||||||
|
|
||||||
struct xhci_TRB_normal_t trb = {0};
|
struct xhci_TRB_normal_t trb = {0};
|
||||||
trb.buf_paddr = virt_2_phys(input_ctx_buffer);
|
trb.buf_paddr = virt_2_phys(input_ctx_buffer);
|
||||||
@ -1027,25 +1036,15 @@ static int xhci_set_address(const int id, const uint64_t slot_vaddr, const int s
|
|||||||
if (unlikely(retval != 0))
|
if (unlikely(retval != 0))
|
||||||
{
|
{
|
||||||
kerror("slotid:%d, address device failed", slot_id);
|
kerror("slotid:%d, address device failed", slot_id);
|
||||||
|
|
||||||
goto failed;
|
goto failed;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct xhci_TRB_cmd_complete_t *trb_done = (struct xhci_TRB_cmd_complete_t *)&trb;
|
struct xhci_TRB_cmd_complete_t *trb_done = (struct xhci_TRB_cmd_complete_t *)&trb;
|
||||||
// kdebug("address slot: comp code=%d", trb_done->code);
|
|
||||||
if (trb_done->code == TRB_COMP_TRB_SUCCESS) // 成功执行
|
if (trb_done->code == TRB_COMP_TRB_SUCCESS) // 成功执行
|
||||||
{
|
{
|
||||||
// 如果要从控制器获取刚刚设置的设备地址的话,可以在这里读取slot context
|
// 如果要从控制器获取刚刚设置的设备地址的话,可以在这里读取slot context
|
||||||
// ksuccess("slot %d successfully addressed.", slot_id);
|
ksuccess("slot %d successfully addressed.", slot_id);
|
||||||
struct xhci_slot_context_t slot;
|
|
||||||
struct xhci_ep_context_t ep;
|
|
||||||
__read_from_slot(&slot, slot_vaddr);
|
|
||||||
slot_ctx.slot_state = slot.slot_state;
|
|
||||||
slot_ctx.device_address = slot.device_address;
|
|
||||||
__read_from_ep(id, slot_vaddr, 1, &ep);
|
|
||||||
// kdebug("ep.ep_state=%d, slot_state=%d", ep.ep_state, slot.slot_state);
|
|
||||||
ep_ctx.ep_state = ep.ep_state;
|
|
||||||
ep_ctx.max_packet_size = ep.max_packet_size;
|
|
||||||
retval = 0;
|
retval = 0;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -1323,12 +1322,13 @@ static int xhci_get_descriptor(const int id, const int port_id)
|
|||||||
*/
|
*/
|
||||||
struct xhci_TRB_normal_t trb = {0};
|
struct xhci_TRB_normal_t trb = {0};
|
||||||
trb.TRB_type = TRB_TYPE_ENABLE_SLOT;
|
trb.TRB_type = TRB_TYPE_ENABLE_SLOT;
|
||||||
kdebug("to enable slot");
|
// kdebug("to enable slot");
|
||||||
if (xhci_send_command(id, (struct xhci_TRB_t *)&trb, true) != 0)
|
if (xhci_send_command(id, (struct xhci_TRB_t *)&trb, true) != 0)
|
||||||
{
|
{
|
||||||
kerror("portid:%d: send enable slot failed", port_id);
|
kerror("portid:%d: send enable slot failed", port_id);
|
||||||
return -ETIMEDOUT;
|
return -ETIMEDOUT;
|
||||||
}
|
}
|
||||||
|
// kdebug("send enable slot ok");
|
||||||
|
|
||||||
uint32_t slot_id = ((struct xhci_TRB_cmd_complete_t *)&trb)->slot_id;
|
uint32_t slot_id = ((struct xhci_TRB_cmd_complete_t *)&trb)->slot_id;
|
||||||
int16_t max_packet;
|
int16_t max_packet;
|
||||||
@ -1350,48 +1350,27 @@ static int xhci_get_descriptor(const int id, const int port_id)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// kdebug("speed=%d", speed);
|
||||||
kdebug("speed=%d", speed);
|
|
||||||
// 初始化接口的上下文
|
// 初始化接口的上下文
|
||||||
uint64_t slot_vaddr = xhci_initialize_slot(id, slot_id, port_id, speed, max_packet);
|
uint64_t slot_vaddr = xhci_initialize_slot(id, slot_id, port_id, speed, max_packet);
|
||||||
kdebug("set addr");
|
|
||||||
|
|
||||||
// 发送 address_device命令
|
// kdebug("set addr again");
|
||||||
retval = xhci_set_address(id, slot_vaddr, slot_id, true);
|
// 再次发送 set_address命令
|
||||||
|
// kdebug("to set addr again");
|
||||||
|
retval = xhci_set_address(id, slot_vaddr, slot_id, false);
|
||||||
if (retval != 0)
|
if (retval != 0)
|
||||||
return retval;
|
return retval;
|
||||||
kdebug("crtl in");
|
|
||||||
|
|
||||||
// 发送用于 “get_descriptor” 的数据包。
|
// kdebug("ctrl in again");
|
||||||
count = xhci_control_in(id, &dev_desc, 8, slot_id, max_packet);
|
|
||||||
|
count = xhci_control_in(id, &dev_desc, 18, slot_id, max_packet);
|
||||||
if (unlikely(count == 0))
|
if (unlikely(count == 0))
|
||||||
return -EAGAIN;
|
return -EAGAIN;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
TODO: if the dev_desc.max_packet was different than what we have as max_packet,
|
TODO: if the dev_desc.max_packet was different than what we have as max_packet,
|
||||||
you would need to change it here and in the slot context by doing a
|
you would need to change it here and in the slot context by doing a
|
||||||
evaluate_slot_context call.
|
evaluate_slot_context call.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
kdebug("reset port");
|
|
||||||
// 重置当前端口
|
|
||||||
kdebug("to reset");
|
|
||||||
xhci_reset_port(id, port_id);
|
|
||||||
|
|
||||||
kdebug("set addr again");
|
|
||||||
// 再次发送 set_address命令
|
|
||||||
kdebug("to set addr again");
|
|
||||||
retval = xhci_set_address(id, slot_vaddr, slot_id, false);
|
|
||||||
if (retval != 0)
|
|
||||||
return retval;
|
|
||||||
|
|
||||||
|
|
||||||
kdebug("ctrl in again");
|
|
||||||
|
|
||||||
count = xhci_control_in(id, &dev_desc, 18, slot_id, max_packet);
|
|
||||||
if (unlikely(count == 0))
|
|
||||||
return -EAGAIN;
|
|
||||||
|
|
||||||
// print the descriptor
|
// print the descriptor
|
||||||
printk(" Found USB Device:\n"
|
printk(" Found USB Device:\n"
|
||||||
" port: %i\n"
|
" port: %i\n"
|
||||||
@ -1430,18 +1409,22 @@ static int xhci_hc_start_ports(int id)
|
|||||||
// 注意,这两个循环应该不能合并到一起,因为可能存在usb2端口offset在前,usb3端口在后的情况,那样的话就会出错
|
// 注意,这两个循环应该不能合并到一起,因为可能存在usb2端口offset在前,usb3端口在后的情况,那样的话就会出错
|
||||||
|
|
||||||
// 循环启动所有的usb3端口
|
// 循环启动所有的usb3端口
|
||||||
// for (int i = 0; i < xhci_hc[id].port_num; ++i)
|
for (int i = 0; i < xhci_hc[id].port_num; ++i)
|
||||||
for (int i = 0; i < 1; ++i)
|
|
||||||
{
|
{
|
||||||
if (XHCI_PORT_IS_USB3(id, i) && XHCI_PORT_IS_ACTIVE(id, i))
|
if (XHCI_PORT_IS_USB3(id, i) && XHCI_PORT_IS_ACTIVE(id, i))
|
||||||
{
|
{
|
||||||
io_mfence();
|
io_mfence();
|
||||||
|
// kdebug("to reset port %d, rflags=%#018lx", id, get_rflags());
|
||||||
|
int rst_ret = xhci_reset_port(id, i);
|
||||||
|
// kdebug("reset done!, val=%d", rst_ret);
|
||||||
// reset该端口
|
// reset该端口
|
||||||
if (likely(xhci_reset_port(id, i) == 0)) // 如果端口reset成功,就获取它的描述符
|
if (likely(rst_ret == 0)) // 如果端口reset成功,就获取它的描述符
|
||||||
// 否则,reset函数会把它给设置为未激活,并且标志配对的usb2端口是激活的
|
// 否则,reset函数会把它给设置为未激活,并且标志配对的usb2端口是激活的
|
||||||
{
|
{
|
||||||
|
// kdebug("reset port %d ok", id);
|
||||||
if (xhci_get_descriptor(id, i) == 0)
|
if (xhci_get_descriptor(id, i) == 0)
|
||||||
++cnt;
|
++cnt;
|
||||||
|
kdebug("usb3 port %d get desc ok", i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1454,17 +1437,15 @@ static int xhci_hc_start_ports(int id)
|
|||||||
{
|
{
|
||||||
// kdebug("initializing usb2: %d", i);
|
// kdebug("initializing usb2: %d", i);
|
||||||
// reset该端口
|
// reset该端口
|
||||||
kdebug("to reset port %d, rflags=%#018lx", id, get_rflags());
|
// kdebug("to reset port %d, rflags=%#018lx", i, get_rflags());
|
||||||
if (likely(xhci_reset_port(id, i) == 0)) // 如果端口reset成功,就获取它的描述符
|
if (likely(xhci_reset_port(id, i) == 0)) // 如果端口reset成功,就获取它的描述符
|
||||||
// 否则,reset函数会把它给设置为未激活,并且标志配对的usb2端口是激活的
|
// 否则,reset函数会把它给设置为未激活,并且标志配对的usb2端口是激活的
|
||||||
{
|
{
|
||||||
kdebug("reset port %d ok", id);
|
// kdebug("reset port %d ok", id);
|
||||||
|
|
||||||
if (xhci_get_descriptor(id, i) == 0)
|
if (xhci_get_descriptor(id, i) == 0)
|
||||||
++cnt;
|
++cnt;
|
||||||
else
|
kdebug("USB2 port %d get desc ok", i);
|
||||||
break;
|
|
||||||
kdebug("port %d get desc ok", id);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1711,6 +1692,23 @@ void xhci_init(struct pci_device_structure_general_device_t *dev_hdr)
|
|||||||
// 写入dcbaap
|
// 写入dcbaap
|
||||||
xhci_write_op_reg64(cid, XHCI_OPS_DCBAAP, virt_2_phys(xhci_hc[cid].dcbaap_vaddr));
|
xhci_write_op_reg64(cid, XHCI_OPS_DCBAAP, virt_2_phys(xhci_hc[cid].dcbaap_vaddr));
|
||||||
io_mfence();
|
io_mfence();
|
||||||
|
|
||||||
|
// 创建scratchpad buffer array
|
||||||
|
uint32_t max_scratchpad_buf = (((uint32_t)hcs2.max_scratchpad_buf_HI5) << 5) | hcs2.max_scratchpad_buf_LO5;
|
||||||
|
kdebug("max scratchpad buffer=%d", max_scratchpad_buf);
|
||||||
|
if (max_scratchpad_buf > 0)
|
||||||
|
{
|
||||||
|
xhci_hc[cid].scratchpad_buf_array_vaddr = (uint64_t)kzalloc(sizeof(uint64_t) * max_scratchpad_buf, 0);
|
||||||
|
__write8b(xhci_hc[cid].dcbaap_vaddr, virt_2_phys(xhci_hc[cid].scratchpad_buf_array_vaddr));
|
||||||
|
|
||||||
|
// 创建scratchpad buffers
|
||||||
|
for (int i = 0; i < max_scratchpad_buf; ++i)
|
||||||
|
{
|
||||||
|
uint64_t buf_vaddr = kzalloc(xhci_hc[cid].page_size, 0);
|
||||||
|
__write8b(xhci_hc[cid].scratchpad_buf_array_vaddr, virt_2_phys(buf_vaddr));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 创建command ring
|
// 创建command ring
|
||||||
xhci_hc[cid].cmd_ring_vaddr = xhci_create_ring(XHCI_CMND_RING_TRBS);
|
xhci_hc[cid].cmd_ring_vaddr = xhci_create_ring(XHCI_CMND_RING_TRBS);
|
||||||
xhci_hc[cid].cmd_trb_vaddr = xhci_hc[cid].cmd_ring_vaddr;
|
xhci_hc[cid].cmd_trb_vaddr = xhci_hc[cid].cmd_ring_vaddr;
|
||||||
|
@ -518,22 +518,26 @@ struct xhci_host_controller_t
|
|||||||
uint64_t vbase_op; // Operational registers 起始虚拟地址
|
uint64_t vbase_op; // Operational registers 起始虚拟地址
|
||||||
uint32_t rts_offset; // Runtime Register Space offset
|
uint32_t rts_offset; // Runtime Register Space offset
|
||||||
uint32_t db_offset; // Doorbell offset
|
uint32_t db_offset; // Doorbell offset
|
||||||
uint32_t ext_caps_off; // 扩展能力寄存器偏移量
|
|
||||||
uint8_t context_size; // 设备上下文大小
|
uint32_t ext_caps_off; // 扩展能力寄存器偏移量
|
||||||
uint16_t port_num; // 总的端口数量
|
uint16_t port_num; // 总的端口数量
|
||||||
uint8_t port_num_u2; // usb 2.0端口数量
|
uint8_t context_size; // 设备上下文大小
|
||||||
uint8_t port_num_u3; // usb 3端口数量
|
uint8_t port_num_u2; // usb 2.0端口数量
|
||||||
uint32_t page_size; // page size
|
|
||||||
uint64_t dcbaap_vaddr; // Device Context Base Address Array Pointer的虚拟地址
|
uint8_t port_num_u3; // usb 3端口数量
|
||||||
uint64_t cmd_ring_vaddr; // command ring的虚拟地址
|
uint8_t current_event_ring_cycle; // 当前event ring cycle
|
||||||
uint64_t cmd_trb_vaddr; // 下一个要写入的trb的虚拟地址
|
uint8_t cmd_trb_cycle; // 当前command ring cycle
|
||||||
uint64_t event_ring_vaddr; // event ring的虚拟地址
|
uint32_t page_size; // page size
|
||||||
uint64_t event_ring_table_vaddr; // event ring table的虚拟地址
|
|
||||||
uint64_t current_event_ring_vaddr; // 下一个要读取的event TRB的虚拟地址
|
uint64_t dcbaap_vaddr; // Device Context Base Address Array Pointer的虚拟地址
|
||||||
uint8_t cmd_trb_cycle; // 当前command ring cycle
|
uint64_t cmd_ring_vaddr; // command ring的虚拟地址
|
||||||
uint8_t current_event_ring_cycle; // 当前event ring cycle
|
uint64_t cmd_trb_vaddr; // 下一个要写入的trb的虚拟地址
|
||||||
struct xhci_port_info_t ports[XHCI_MAX_ROOT_HUB_PORTS]; // 指向端口信息数组的指针(由于端口offset是从1开始的,因此该数组第0项为空)
|
uint64_t event_ring_vaddr; // event ring的虚拟地址
|
||||||
struct xhci_ep_ring_info_t control_ep_info; // 控制端点的信息
|
uint64_t event_ring_table_vaddr; // event ring table的虚拟地址
|
||||||
|
uint64_t current_event_ring_vaddr; // 下一个要读取的event TRB的虚拟地址
|
||||||
|
uint64_t scratchpad_buf_array_vaddr; // 草稿行缓冲区数组的虚拟地址
|
||||||
|
struct xhci_port_info_t ports[XHCI_MAX_ROOT_HUB_PORTS]; // 指向端口信息数组的指针(由于端口offset是从1开始的,因此该数组第0项为空)
|
||||||
|
struct xhci_ep_ring_info_t control_ep_info; // 控制端点的信息
|
||||||
};
|
};
|
||||||
|
|
||||||
// Common TRB types
|
// Common TRB types
|
||||||
|
@ -463,7 +463,9 @@ ul initial_kernel_thread(ul arg)
|
|||||||
{
|
{
|
||||||
// kinfo("initial proc running...\targ:%#018lx", arg);
|
// kinfo("initial proc running...\targ:%#018lx", arg);
|
||||||
fat32_init();
|
fat32_init();
|
||||||
usb_init();
|
// 使用单独的内核线程来初始化usb驱动程序
|
||||||
|
int usb_pid = kernel_thread(usb_init, 0, 0);
|
||||||
|
|
||||||
kinfo("LZ4 lib Version=%s", LZ4_versionString());
|
kinfo("LZ4 lib Version=%s", LZ4_versionString());
|
||||||
|
|
||||||
// 对一些组件进行单元测试
|
// 对一些组件进行单元测试
|
||||||
@ -471,21 +473,14 @@ ul initial_kernel_thread(ul arg)
|
|||||||
ktest_start(ktest_test_bitree, 0),
|
ktest_start(ktest_test_bitree, 0),
|
||||||
ktest_start(ktest_test_kfifo, 0),
|
ktest_start(ktest_test_kfifo, 0),
|
||||||
ktest_start(ktest_test_mutex, 0),
|
ktest_start(ktest_test_mutex, 0),
|
||||||
|
usb_pid,
|
||||||
};
|
};
|
||||||
kinfo("Waiting test thread exit...");
|
kinfo("Waiting test thread exit...");
|
||||||
// 等待测试进程退出
|
// 等待测试进程退出
|
||||||
for (int i = 0; i < sizeof(tpid) / sizeof(uint64_t); ++i)
|
for (int i = 0; i < sizeof(tpid) / sizeof(uint64_t); ++i)
|
||||||
waitpid(tpid[i], NULL, NULL);
|
waitpid(tpid[i], NULL, NULL);
|
||||||
kinfo("All test done.");
|
kinfo("All test done.");
|
||||||
// pid_t p = fork();
|
|
||||||
// if (p == 0)
|
|
||||||
// {
|
|
||||||
// kdebug("in subproc, rflags=%#018lx", get_rflags());
|
|
||||||
|
|
||||||
// while (1)
|
|
||||||
// usleep(1000);
|
|
||||||
// }
|
|
||||||
// kdebug("subprocess pid=%d", p);
|
|
||||||
|
|
||||||
// 准备切换到用户态
|
// 准备切换到用户态
|
||||||
struct pt_regs *regs;
|
struct pt_regs *regs;
|
||||||
|
@ -26,18 +26,17 @@ void nanosleep_handler(void *pcb)
|
|||||||
*/
|
*/
|
||||||
int nanosleep(const struct timespec *rqtp, struct timespec *rmtp)
|
int nanosleep(const struct timespec *rqtp, struct timespec *rmtp)
|
||||||
{
|
{
|
||||||
int64_t total_ns = rqtp->tv_nsec;
|
|
||||||
|
|
||||||
if (total_ns < 0 || total_ns >= 1000000000)
|
if (rqtp->tv_nsec < 0 || rqtp->tv_nsec >= 1000000000)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
|
|
||||||
// 对于小于500us的时间,使用spin/rdtsc来进行定时
|
// 对于小于500us的时间,使用spin/rdtsc来进行定时
|
||||||
if (total_ns < 500000)
|
if (rqtp->tv_nsec < 500000)
|
||||||
{
|
{
|
||||||
kdebug("use rdtsc to nanosleep");
|
uint64_t expired_tsc = rdtsc() + (((uint64_t)rqtp->tv_nsec) * Cpu_tsc_freq) / 1000000000;
|
||||||
uint64_t expired_tsc = rdtsc() + (total_ns * Cpu_tsc_freq) / 1000000000;
|
|
||||||
while (rdtsc() < expired_tsc)
|
while (rdtsc() < expired_tsc)
|
||||||
pause();
|
;
|
||||||
|
|
||||||
if (rmtp != NULL)
|
if (rmtp != NULL)
|
||||||
{
|
{
|
||||||
@ -51,7 +50,7 @@ int nanosleep(const struct timespec *rqtp, struct timespec *rmtp)
|
|||||||
struct timer_func_list_t *sleep_task = (struct timer_func_list_t *)kmalloc(sizeof(struct timer_func_list_t), 0);
|
struct timer_func_list_t *sleep_task = (struct timer_func_list_t *)kmalloc(sizeof(struct timer_func_list_t), 0);
|
||||||
memset(sleep_task, 0, sizeof(struct timer_func_list_t));
|
memset(sleep_task, 0, sizeof(struct timer_func_list_t));
|
||||||
|
|
||||||
timer_func_init_us(sleep_task, &nanosleep_handler, (void *)current_pcb, total_ns / 1000);
|
timer_func_init_us(sleep_task, &nanosleep_handler, (void *)current_pcb, rqtp->tv_nsec / 1000);
|
||||||
|
|
||||||
timer_func_add(sleep_task);
|
timer_func_add(sleep_task);
|
||||||
|
|
||||||
|
7
run.sh
7
run.sh
@ -11,6 +11,13 @@ IA32_USE_QEMU=1
|
|||||||
bochsrc="./bochsrc"
|
bochsrc="./bochsrc"
|
||||||
ARCH="x86_64"
|
ARCH="x86_64"
|
||||||
|
|
||||||
|
for i in "$@"
|
||||||
|
do
|
||||||
|
if [ $i == "--no-qemu" ];then
|
||||||
|
IA32_USE_QEMU=0
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
if [ ${IA32_USE_QEMU} == "1" ];then
|
if [ ${IA32_USE_QEMU} == "1" ];then
|
||||||
export EMULATOR=__QEMU_EMULATION__
|
export EMULATOR=__QEMU_EMULATION__
|
||||||
else
|
else
|
||||||
|
Loading…
x
Reference in New Issue
Block a user