Finalize xHCI and USB modules

Scratchpad buffers allocation added to xHCI. Missing initialization steps
for keyboards - set configuration and set idle - added to USB. (Even
though they are specific to HID protocol, they go through USB command
endpoint, and with current module contents it's cleaner to have them
in USB module.)
This commit is contained in:
2026-08-25 21:20:53 +03:00
parent c58605b56d
commit d72169473f
3 changed files with 43 additions and 11 deletions
+24 -3
View File
@@ -1,12 +1,12 @@
#include "src/kernel/xhci.h"
#include "src/kernel/log.h"
#include "src/kernel/memory.h"
#include "src/kernel/panic.h"
#include "src/kernel/pci.h"
#include "src/kernel/stream.h"
#include "src/lib/layout.h"
#include "src/lib/memory.h"
#include "src/lib/util.h"
#include <stdint.h>
#define XHCI_PCI_CLASS 0x0C
#define XHCI_PCI_SUBCLASS 0x03
@@ -29,6 +29,7 @@ typedef volatile struct __attribute__((packed)) {
#define XHCI_CAP_REGS_MAX_INTRS(c) BITS_R((c)->hcsparams1, 18, 8)
#define XHCI_CAP_REGS_MAX_PORTS(c) BITS_R((c)->hcsparams1, 31, 24)
#define XHCI_CAP_REGS_MAX_ERSTS(c) BITS_R((c)->hcsparams2, 7, 4)
#define XHCI_CAP_REGS_MAX_SCRATCHPAD_BUFFERS(c) (BITS_R((c)->hcsparams2, 31, 27) << 5 | BITS_R((c)->hcsparams2, 4, 0))
typedef volatile struct __attribute__((packed)) {
uint32_t usbcmd;
@@ -96,6 +97,8 @@ static xhci_db_regs *db_regs;
#define MAX_SLOTS 32
static void *scratchpads[32];
static void *dcbaa[MAX_SLOTS + 1] __attribute__((aligned(PAGE_SIZE)));
typedef struct __attribute__((packed)) {
@@ -408,6 +411,13 @@ void xhci_init() {
RING_WRAP(cmd);
XHCI_TRB_CYCLE_W(&cmd_r[RING_LENGTH], cmd_r_cycle);
LOG_LN_INFO("Setting up scratchpad buffers...");
ASSERT(XHCI_CAP_REGS_MAX_SCRATCHPAD_BUFFERS(cap_regs) <= sizeof(scratchpads), "Too many scratchpad buffers expected.");
for (uint32_t i = 0; i < XHCI_CAP_REGS_MAX_SCRATCHPAD_BUFFERS(cap_regs); i++) {
scratchpads[i] = memory_page_allocate();
}
dcbaa[0] = VIRT_TO_PHYS(scratchpads);
LOG_LN_INFO("Configuring controller...");
XHCI_OP_REGS_MAX_SLOTS_EN_W(op_regs, MAX_SLOTS);
op_regs->dcbaap = (uint64_t)VIRT_TO_PHYS(dcbaa);
@@ -475,13 +485,17 @@ xhci_slot_t xhci_attach(xhci_port_t port) {
RING_WRAP(tsf);
LOG_LN_STEP("Resetting device...");
LOG_VAL_TRACE(port_regs[port].portsc, "%x");
port_regs[port].portsc = (port_regs[port].portsc & ~(uint32_t)0x00FE0000) | 0x00FE0000;
LOG_VAL_TRACE(port_regs[port].portsc, "%x");
port_regs[port].portsc = (port_regs[port].portsc & ~(uint32_t)0x00FE0000) | (1 << 4);
LOG_VAL_TRACE(port_regs[port].portsc, "%x");
while (XHCI_PORT_REGS_PR_R(&port_regs[port]))
;
LOG_VAL_TRACE(&port_regs[port].portsc, "%x");
LOG_VAL_TRACE(port_regs[port].portsc, "%x");
while (!XHCI_PORT_REGS_PED(&port_regs[port]) && XHCI_PORT_REGS_PLL(&port_regs[port]) != 0)
;
LOG_VAL_TRACE(&port_regs[port].portsc, "%x");
LOG_VAL_TRACE(port_regs[port].portsc, "%x");
LOG_LN_STEP("Enabling a slot...");
xhci_trb_t cmd_es;
@@ -612,10 +626,17 @@ uint16_t xhci_read_endpoint(xhci_slot_t slot, xhci_endpoint_t endpoint, uint16_t
LOG_LN_STEP("Received transfer event, returning...");
ep_processed_events++;
LOG_VAL_TRACE(cmp->parameter, "%lx");
LOG_VAL_TRACE(cmp->status, "%x");
LOG_VAL_TRACE(cmp->control, "%x");
xhci_trb_t *cmd = PHYS_TO_VIRT(cmp->parameter);
uint16_t size = max < cmd->status ? max : (uint16_t)cmd->status;
memory_copy(PHYS_TO_VIRT(cmd->parameter), size, to);
LOG_VAL_TRACE(size, "%d");
LOG_VAL_TRACE(*(uint64_t *)to, "%lx");
transferred = size;
}