XHCI configure device endpoints
All checks were successful
Build ISO image / build-and-deploy (push) Successful in 5m9s
Build documentation / build-and-deploy (push) Successful in 3m24s

This commit is contained in:
2026-04-02 18:41:09 +02:00
parent 88df4cbdd5
commit f61afad77e
2 changed files with 179 additions and 32 deletions

View File

@@ -819,7 +819,151 @@ static void xhci_send_cmd (struct xhci* xhci, uint64_t param, uint32_t status, u
DEBUG ("timed out\n");
}
static void xhci_pdevice_setup_init_endpoints (struct xhci* xhci, struct xhci_pdevice* pdevice) {}
static uint8_t xhci_get_device_ctx_idx (struct usb_endpoint_desc* endpoint) {
uint8_t endpoint_num = endpoint->endpoint_addr & 0x0F;
bool in = (endpoint->endpoint_addr & 0x80) != 0;
return (endpoint_num * 2) + (in ? 1 : 0);
}
static void xhci_pdevice_setup_init_endpoints (struct xhci* xhci, struct xhci_pdevice* pdevice,
uint64_t* lockflags) {
struct limine_hhdm_response* hhdm = limine_hhdm_request.response;
uintptr_t input_ctx_phys = pmm_alloc (1);
void* input_ctx_virt = (void*)(input_ctx_phys + (uintptr_t)hhdm->offset);
memset (input_ctx_virt, 0, PAGE_SIZE);
uint8_t max_device_ctx_idx = 0;
struct list_node_link *eps_link, *tmp_eps_link;
list_foreach (pdevice->endpoints, eps_link, tmp_eps_link) {
struct xhci_pdevice_endpoint* endpoint =
list_entry (eps_link, struct xhci_pdevice_endpoint, endpoints_link);
uint8_t dci = xhci_get_device_ctx_idx (&endpoint->desc);
if (dci > max_device_ctx_idx)
max_device_ctx_idx = dci;
}
void* out_ctx_virt = (void*)(xhci->xhci_dcbaa[pdevice->slot_id] + (uintptr_t)hhdm->offset);
memcpy ((uint8_t*)input_ctx_virt + xhci->xhci_ctx_size, out_ctx_virt,
PAGE_SIZE - xhci->xhci_ctx_size);
if (xhci->xhci_ctx_size == 64) {
struct xhci_input_ctx64* ctx64 = input_ctx_virt;
ctx64->ctrl.dw[1] = (1 << 0);
// ctx64->slot.dw[0] = (max_device_ctx_idx << XHCI_SLCTX_CTX_ENTRIES);
ctx64->slot.dw[0] = (ctx64->slot.dw[0] & ~(0x1F << XHCI_SLCTX_CTX_ENTRIES)) |
(max_device_ctx_idx << XHCI_SLCTX_CTX_ENTRIES);
struct list_node_link *eps_link, *tmp_eps_link;
list_foreach (pdevice->endpoints, eps_link, tmp_eps_link) {
struct xhci_pdevice_endpoint* endpoint =
list_entry (eps_link, struct xhci_pdevice_endpoint, endpoints_link);
uint8_t dci = xhci_get_device_ctx_idx (&endpoint->desc);
ctx64->ctrl.dw[1] |= (1 << dci);
endpoint->transfer_ring.phys = pmm_alloc (1);
endpoint->transfer_ring.trbs =
(struct xhci_trb*)(endpoint->transfer_ring.phys + (uintptr_t)hhdm->offset);
memset (endpoint->transfer_ring.trbs, 0, PAGE_SIZE);
endpoint->transfer_ring.size = PAGE_SIZE / sizeof (struct xhci_trb);
endpoint->transfer_ring.idx = 0;
endpoint->transfer_ring.cycle_bit = 1;
uint8_t type = endpoint->desc.attrs & 0x03;
bool in = (endpoint->desc.endpoint_addr & 0x80) != 0;
uint32_t xhci_type = 0;
if (type == 2) {
if (in)
xhci_type = XHCI_EP_BULK_IN;
else
xhci_type = XHCI_EP_BULK_OUT;
} else if (type == 3) {
if (in)
xhci_type = XHCI_EP_INTR_IN;
else
xhci_type = XHCI_EP_INTR_OUT;
}
ctx64->endpoints[dci - 1].dw[1] = (3 << XHCI_EPCTX_ERR_COUNT) |
(xhci_type << XHCI_EPCTX_EP_TYPE) |
((uint32_t)endpoint->desc.max_packet_size << XHCI_EPCTX_MAX_PKT_SZ);
ctx64->endpoints[dci - 1].dw[2] = (uint32_t)endpoint->transfer_ring.phys | (1 << 0);
ctx64->endpoints[dci - 1].dw[3] = (uint32_t)(endpoint->transfer_ring.phys >> 32);
ctx64->endpoints[dci - 1].dw[4] = (8 << XHCI_EPCTX_AVG_TRB_LEN);
}
} else if (xhci->xhci_ctx_size == 32) {
struct xhci_input_ctx32* ctx32 = input_ctx_virt;
ctx32->ctrl.dw[1] = (1 << 0);
ctx32->slot.dw[0] = (ctx32->slot.dw[0] & ~(0x1F << XHCI_SLCTX_CTX_ENTRIES)) |
(max_device_ctx_idx << XHCI_SLCTX_CTX_ENTRIES);
struct list_node_link *eps_link, *tmp_eps_link;
list_foreach (pdevice->endpoints, eps_link, tmp_eps_link) {
struct xhci_pdevice_endpoint* endpoint =
list_entry (eps_link, struct xhci_pdevice_endpoint, endpoints_link);
uint8_t dci = xhci_get_device_ctx_idx (&endpoint->desc);
ctx32->ctrl.dw[1] |= (1 << dci);
endpoint->transfer_ring.phys = pmm_alloc (1);
endpoint->transfer_ring.trbs =
(struct xhci_trb*)(endpoint->transfer_ring.phys + (uintptr_t)hhdm->offset);
memset (endpoint->transfer_ring.trbs, 0, PAGE_SIZE);
endpoint->transfer_ring.size = PAGE_SIZE / sizeof (struct xhci_trb);
endpoint->transfer_ring.idx = 0;
endpoint->transfer_ring.cycle_bit = 1;
uint8_t type = endpoint->desc.attrs & 0x03;
bool in = (endpoint->desc.endpoint_addr & 0x80) != 0;
uint32_t xhci_type = 0;
if (type == 2) {
if (in)
xhci_type = XHCI_EP_BULK_IN;
else
xhci_type = XHCI_EP_BULK_OUT;
} else if (type == 3) {
if (in)
xhci_type = XHCI_EP_INTR_IN;
else
xhci_type = XHCI_EP_INTR_OUT;
}
ctx32->endpoints[dci - 1].dw[1] = (3 << XHCI_EPCTX_ERR_COUNT) |
(xhci_type << XHCI_EPCTX_EP_TYPE) |
((uint32_t)endpoint->desc.max_packet_size << XHCI_EPCTX_MAX_PKT_SZ);
ctx32->endpoints[dci - 1].dw[2] = (uint32_t)endpoint->transfer_ring.phys | (1 << 0);
ctx32->endpoints[dci - 1].dw[3] = (uint32_t)(endpoint->transfer_ring.phys >> 32);
ctx32->endpoints[dci - 1].dw[4] = (8 << XHCI_EPCTX_AVG_TRB_LEN);
}
}
uint32_t ctrl = (pdevice->slot_id << 24) | (XHCI_TRB_CFG_ENDP_CMD << XHCI_GTRB_TRB_TYPE);
xhci_send_cmd (xhci, input_ctx_phys, 0, ctrl, lockflags);
stall_ms (500);
if (xhci->last_cmpl_code != 1)
DEBUG ("Failed to configure endpoints for this device\n");
else
DEBUG ("Successfully configured endpoints for this device\n");
pmm_free (input_ctx_phys, 1);
}
static void xhci_pdevice_setup_set_config (struct xhci* xhci, struct xhci_pdevice* pdevice,
uint8_t config_val, uint64_t* lockflags) {
@@ -1009,36 +1153,36 @@ static bool xhci_pdevice_setup_get_config_full (struct xhci* xhci, struct xhci_p
switch (hdr->desc_type) {
case USB_DESC_CONFIG: {
struct xhci_pdevice_dconfig* dconfig = malloc (sizeof (*dconfig));
memset (dconfig, 0, sizeof (*dconfig));
dconfig->desc = *(struct usb_config_desc*)ptr;
list_append (pdevice->dconfigs, &dconfig->configs_link);
struct xhci_pdevice_config* config = malloc (sizeof (*config));
memset (config, 0, sizeof (*config));
config->desc = *(struct usb_config_desc*)ptr;
list_append (pdevice->configs, &config->configs_link);
DEBUG (
"Found USB device config: total_len=%u num_ifs=%u, cfgval=%u cfg=%u attrs=%02x maxpow=%u\n",
dconfig->desc.total_length, dconfig->desc.num_ifs, dconfig->desc.config_value,
dconfig->desc.config, dconfig->desc.attrs, dconfig->desc.max_power);
config->desc.total_length, config->desc.num_ifs, config->desc.config_value,
config->desc.config, config->desc.attrs, config->desc.max_power);
} break;
case USB_DESC_IF: {
struct xhci_pdevice_dif* dif = malloc (sizeof (*dif));
memset (dif, 0, sizeof (*dif));
dif->desc = *(struct usb_if_desc*)ptr;
list_append (pdevice->difs, &dif->ifs_link);
struct xhci_pdevice_if* if_ = malloc (sizeof (*if_));
memset (if_, 0, sizeof (*if_));
if_->desc = *(struct usb_if_desc*)ptr;
list_append (pdevice->ifs, &if_->ifs_link);
DEBUG (
"Found USB device interface: ifnum=%u altsetting=%u eps=%u ifclass=%u ifsubclass=%u ifproto=%u if=%u\n",
dif->desc.if_num, dif->desc.alt_setting, dif->desc.num_endpoints, dif->desc.if_class,
dif->desc.if_subclass, dif->desc.if_proto, dif->desc.if1);
if_->desc.if_num, if_->desc.alt_setting, if_->desc.num_endpoints, if_->desc.if_class,
if_->desc.if_subclass, if_->desc.if_proto, if_->desc.if1);
} break;
case USB_DESC_ENDPOINT: {
struct xhci_pdevice_dendpoint* dendpoint = malloc (sizeof (*dendpoint));
memset (dendpoint, 0, sizeof (*dendpoint));
dendpoint->desc = *(struct usb_endpoint_desc*)ptr;
list_append (pdevice->dendpoints, &dendpoint->endpoints_link);
struct xhci_pdevice_endpoint* endpoint = malloc (sizeof (*endpoint));
memset (endpoint, 0, sizeof (*endpoint));
endpoint->desc = *(struct usb_endpoint_desc*)ptr;
list_append (pdevice->endpoints, &endpoint->endpoints_link);
DEBUG ("Found USB device endpoint: addr=%u attrs=%u maxpkt=%u intvl=%u\n",
dendpoint->desc.endpoint_addr, dendpoint->desc.attrs, dendpoint->desc.max_packet_size,
dendpoint->desc.interval);
endpoint->desc.endpoint_addr, endpoint->desc.attrs, endpoint->desc.max_packet_size,
endpoint->desc.interval);
} break;
default:
DEBUG ("Found unknown USB descriptor of type %u\n", hdr->desc_type);
@@ -1056,18 +1200,18 @@ static void xhci_poll_setup_init_ifs (struct xhci* xhci, struct xhci_pdevice* pd
uint64_t* lockflags) {
struct list_node_link *ifs_link, *tmp_ifs_link;
list_foreach (pdevice->difs, ifs_link, tmp_ifs_link) {
struct xhci_pdevice_dif* dif = list_entry (ifs_link, struct xhci_pdevice_dif, ifs_link);
list_foreach (pdevice->ifs, ifs_link, tmp_ifs_link) {
struct xhci_pdevice_if* if_ = list_entry (ifs_link, struct xhci_pdevice_if, ifs_link);
for (size_t i = 0; i < USB_DRIVER_MAX_MATCHES; i++) {
struct usb_driver_info* info = &usb_driver_infos[i];
DEBUG ("%u %u / %u %u / %u %u\n", dif->desc.if_class, info->if_class, dif->desc.if_subclass,
info->if_subclass, dif->desc.if_proto, info->if_proto);
DEBUG ("%u %u / %u %u / %u %u\n", if_->desc.if_class, info->if_class, if_->desc.if_subclass,
info->if_subclass, if_->desc.if_proto, info->if_proto);
if (dif->desc.if_class == info->if_class &&
dif->desc.if_subclass == info->if_subclass &&
dif->desc.if_proto == info->if_proto) {
if (if_->desc.if_class == info->if_class &&
if_->desc.if_subclass == info->if_subclass &&
if_->desc.if_proto == info->if_proto) {
if (!info->init ())
DEBUG ("USB driver failed to initialize. Skipping device!\n");
}
@@ -1090,6 +1234,7 @@ static void xhci_poll_setup_devices (struct xhci* xhci, uint64_t* lockflags) {
xhci_pdevice_setup_get_config (xhci, pdevice, lockflags);
xhci_pdevice_setup_get_config_full (xhci, pdevice, lockflags);
xhci_pdevice_setup_set_config (xhci, pdevice, 0, lockflags);
xhci_pdevice_setup_init_endpoints (xhci, pdevice, lockflags);
xhci_poll_setup_init_ifs (xhci, pdevice, lockflags);
}
}

View File

@@ -67,19 +67,21 @@ struct xhci_ring {
uint8_t cycle_bit;
};
struct xhci_pdevice_dconfig {
struct xhci_pdevice_config {
struct usb_config_desc desc;
struct list_node_link configs_link;
};
struct xhci_pdevice_dif {
struct xhci_pdevice_if {
struct usb_if_desc desc;
struct list_node_link ifs_link;
};
struct xhci_pdevice_dendpoint {
struct xhci_pdevice_endpoint {
struct usb_endpoint_desc desc;
struct list_node_link endpoints_link;
struct xhci_ring transfer_ring;
};
struct xhci_pdevice {
@@ -91,9 +93,9 @@ struct xhci_pdevice {
struct usb_device_desc device_desc;
struct usb_config_desc config_desc;
struct list_node_link* dconfigs;
struct list_node_link* difs;
struct list_node_link* dendpoints;
struct list_node_link* configs;
struct list_node_link* ifs;
struct list_node_link* endpoints;
};
struct xhci_port_status_change {