XHCI configure device endpoints
This commit is contained in:
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user