USB driver polling user app, handle only one XHCI controller for now, Implement USB device addressing
This commit is contained in:
@@ -4,6 +4,7 @@
|
||||
#include <device/partitions.h>
|
||||
#include <device/ramdrv.h>
|
||||
#include <device/terminal.h>
|
||||
#include <device_info.h>
|
||||
#include <devices.h>
|
||||
#include <id/id_alloc.h>
|
||||
#include <libk/align.h>
|
||||
@@ -50,7 +51,7 @@ struct device* device_find (const char* key) {
|
||||
return hash_entry (found_link, struct device, device_table_link);
|
||||
}
|
||||
|
||||
struct device* device_create (const char* key, device_op_func_t* ops, size_t ops_len,
|
||||
struct device* device_create (int type, const char* key, device_op_func_t* ops, size_t ops_len,
|
||||
device_init_func_t init, device_fini_func_t fini, void* arg,
|
||||
struct proc* proc, struct reschedule_ctx* rctx) {
|
||||
uint64_t fdt;
|
||||
@@ -68,6 +69,7 @@ struct device* device_create (const char* key, device_op_func_t* ops, size_t ops
|
||||
device->init = init;
|
||||
device->fini = fini;
|
||||
memcpy (device->key, key, strlen_null (key));
|
||||
device->type = type;
|
||||
|
||||
if (ops != NULL)
|
||||
memcpy (device->ops, ops, ops_len * sizeof (device_op_func_t));
|
||||
@@ -91,6 +93,40 @@ struct device* device_create (const char* key, device_op_func_t* ops, size_t ops
|
||||
return device;
|
||||
}
|
||||
|
||||
size_t device_populate_device_infos (struct device_info* infos, size_t count) {
|
||||
uint64_t fdt, fd;
|
||||
|
||||
if (count >= DEVICES_MAX)
|
||||
count = DEVICES_MAX;
|
||||
|
||||
size_t j = 0;
|
||||
|
||||
spin_lock (&device_table.lock, &fdt);
|
||||
|
||||
for (size_t i = 0; i < lengthof (device_table.device_buckets); i++) {
|
||||
struct hash_node_link* hash_link = device_table.device_buckets[i];
|
||||
|
||||
while (hash_link != NULL && j < count) {
|
||||
struct device* device = hash_entry (hash_link, struct device, device_table_link);
|
||||
struct device_info* info = &infos[j];
|
||||
|
||||
spin_lock (&device->lock, &fd);
|
||||
|
||||
memcpy (info->key, device->key, sizeof (info->key));
|
||||
info->type = device->type;
|
||||
|
||||
spin_unlock (&device->lock, fd);
|
||||
|
||||
hash_link = hash_link->next;
|
||||
j++;
|
||||
}
|
||||
}
|
||||
|
||||
spin_unlock (&device_table.lock, fdt);
|
||||
|
||||
return j;
|
||||
}
|
||||
|
||||
static void debugconsole_device_init (void) {
|
||||
struct reschedule_ctx rctx;
|
||||
memset (&rctx, 0, sizeof (rctx));
|
||||
@@ -98,8 +134,8 @@ static void debugconsole_device_init (void) {
|
||||
device_op_func_t ops[] = {
|
||||
[DEBUGCONSOLE_PUTSTR] = &debugconsole_putstr,
|
||||
};
|
||||
device_create ("debugconsole", ops, lengthof (ops), &debugconsole_init, &debugconsole_fini, NULL,
|
||||
thiscpu->kproc, &rctx);
|
||||
device_create (DEVICE_TYPE_DEBUGCONSOLE, "debugconsole", ops, lengthof (ops), &debugconsole_init,
|
||||
&debugconsole_fini, NULL, thiscpu->kproc, &rctx);
|
||||
}
|
||||
|
||||
static void terminal_device_init (void) {
|
||||
@@ -110,8 +146,8 @@ static void terminal_device_init (void) {
|
||||
[TERMINAL_PUTSTR] = &terminal_putstr,
|
||||
[TERMINAL_DIMENSIONS] = &terminal_dimensions,
|
||||
};
|
||||
device_create ("terminal", ops, lengthof (ops), &terminal_init, &terminal_fini, NULL,
|
||||
thiscpu->kproc, &rctx);
|
||||
device_create (DEVICE_TYPE_TERMINAL, "terminal", ops, lengthof (ops), &terminal_init,
|
||||
&terminal_fini, NULL, thiscpu->kproc, &rctx);
|
||||
}
|
||||
|
||||
static void sys_device_init (void) {
|
||||
@@ -155,8 +191,8 @@ static void sys_device_init (void) {
|
||||
.sector_size = 512,
|
||||
.buffer = unpack_buffer,
|
||||
};
|
||||
device_create ("sys0", ops, lengthof (ops), &ramdrv_init, &ramdrv_fini, &init, thiscpu->kproc,
|
||||
&rctx);
|
||||
device_create (DEVICE_TYPE_DRIVE, "sys0", ops, lengthof (ops), &ramdrv_init, &ramdrv_fini, &init,
|
||||
thiscpu->kproc, &rctx);
|
||||
|
||||
LZ4F_freeDecompressionContext (dctx);
|
||||
}
|
||||
@@ -177,8 +213,8 @@ static void temp_device_init (void) {
|
||||
.total_size = 1024 * 1024 * 20,
|
||||
.sector_size = 512,
|
||||
};
|
||||
device_create ("temp0", ops, lengthof (ops), &ramdrv_init, &ramdrv_fini, &init, thiscpu->kproc,
|
||||
&rctx);
|
||||
device_create (DEVICE_TYPE_DRIVE, "temp0", ops, lengthof (ops), &ramdrv_init, &ramdrv_fini, &init,
|
||||
thiscpu->kproc, &rctx);
|
||||
}
|
||||
|
||||
#if defined(__x86_64__)
|
||||
@@ -189,7 +225,8 @@ static void ps2kb_device_init (void) {
|
||||
device_op_func_t ops[] = {
|
||||
[KB_READ_KEY] = &ps2kb_read_key,
|
||||
};
|
||||
device_create ("kb", ops, lengthof (ops), &ps2kb_init, &ps2kb_fini, NULL, thiscpu->kproc, &rctx);
|
||||
device_create (DEVICE_TYPE_KEYBOARD, "kb", ops, lengthof (ops), &ps2kb_init, &ps2kb_fini, NULL,
|
||||
thiscpu->kproc, &rctx);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#ifndef _KERNEL_DEVICE_DEVICE_H
|
||||
#define _KERNEL_DEVICE_DEVICE_H
|
||||
|
||||
#include <device_info.h>
|
||||
#include <libk/hash.h>
|
||||
#include <libk/list.h>
|
||||
#include <libk/std.h>
|
||||
@@ -35,14 +36,17 @@ struct device {
|
||||
device_init_func_t init;
|
||||
device_fini_func_t fini;
|
||||
void* udata;
|
||||
int type;
|
||||
};
|
||||
|
||||
struct device* device_create (const char* key, device_op_func_t* ops, size_t ops_len,
|
||||
struct device* device_create (int type, const char* key, device_op_func_t* ops, size_t ops_len,
|
||||
device_init_func_t init, device_fini_func_t fini, void* arg,
|
||||
struct proc* proc, struct reschedule_ctx* rctx);
|
||||
|
||||
struct device* device_find (const char* key);
|
||||
|
||||
size_t device_populate_device_infos (struct device_info* infos, size_t count);
|
||||
|
||||
void devices_init (void);
|
||||
|
||||
#endif // _KERNEL_DEVICE_DEVICE_H
|
||||
|
||||
@@ -59,7 +59,8 @@ static int device_probe_partitions_dos (struct proc* proc, struct reschedule_ctx
|
||||
memset (key, 0, sizeof (key));
|
||||
snprintf (key, sizeof (key), "%sp%zu", device->key, i);
|
||||
|
||||
device_create (key, ops, lengthof (ops), &partdrv_init, &partdrv_fini, &init, proc, rctx);
|
||||
device_create (DEVICE_TYPE_DRIVE, key, ops, lengthof (ops), &partdrv_init, &partdrv_fini, &init,
|
||||
proc, rctx);
|
||||
}
|
||||
|
||||
spin_unlock (&device->lock, fd);
|
||||
|
||||
@@ -58,8 +58,8 @@ static void ide_make_device (struct proc* proc, struct reschedule_ctx* rctx,
|
||||
.irq = probe.irq,
|
||||
.irqs_support = probe.irqs_support,
|
||||
};
|
||||
struct device* ide = device_create (device_key, ops, lengthof (ops), &idedrv_init, &idedrv_fini,
|
||||
&init, proc, rctx);
|
||||
struct device* ide = device_create (DEVICE_TYPE_DRIVE, device_key, ops, lengthof (ops),
|
||||
&idedrv_init, &idedrv_fini, &init, proc, rctx);
|
||||
device_probe_partitions (proc, rctx, ide);
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include <device/pci_info.h>
|
||||
#include <device/pci_xhci.h>
|
||||
#include <device/xhci.h>
|
||||
#include <devices.h>
|
||||
#include <libk/align.h>
|
||||
#include <libk/lengthof.h>
|
||||
#include <libk/printf.h>
|
||||
@@ -16,16 +17,11 @@
|
||||
#include <sys/debug.h>
|
||||
#include <sys/mm.h>
|
||||
|
||||
static int xhci_counter = 0;
|
||||
static bool xhci_init_done = false;
|
||||
|
||||
bool pci_xhci_init (struct proc* proc, struct reschedule_ctx* rctx, struct pci_info pci_info) {
|
||||
struct limine_hhdm_response* hhdm = limine_hhdm_request.response;
|
||||
|
||||
if (xhci_counter == 3) {
|
||||
DEBUG ("Cannot initialize more XHCI controllers\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t progif = pci_read8 (pci_info.bus, pci_info.slot, pci_info.func, PCI_PROG_IF);
|
||||
|
||||
/* not an XHCI controller */
|
||||
@@ -33,6 +29,11 @@ bool pci_xhci_init (struct proc* proc, struct reschedule_ctx* rctx, struct pci_i
|
||||
return true;
|
||||
}
|
||||
|
||||
if (xhci_init_done) {
|
||||
DEBUG ("Cannot initialize more XHCI controllers\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
uint16_t pci_cmd = pci_read16 (pci_info.bus, pci_info.slot, pci_info.func, PCI_COMMAND);
|
||||
|
||||
uint16_t new_cmd = (pci_cmd | (1 << 1) | (1 << 2)) & ~(1 << 10);
|
||||
@@ -48,7 +49,7 @@ bool pci_xhci_init (struct proc* proc, struct reschedule_ctx* rctx, struct pci_i
|
||||
map_pages = pci_get_bar_size (pci_info.bus, pci_info.slot, pci_info.func, PCI_BAR0);
|
||||
map_pages = div_align_up (map_pages, PAGE_SIZE);
|
||||
|
||||
if ((bar0 & PCI_BAR_MEM64)) {
|
||||
if ((bar0 & 0x6) == 0x4) {
|
||||
uint32_t bar1 = pci_read32 (pci_info.bus, pci_info.slot, pci_info.func, PCI_BAR1);
|
||||
xhci_phys = ((uint64_t)bar1 << 32) | (bar0 & ~0xF);
|
||||
DEBUG ("XHCI phys base addr=%p (64 bit)\n", xhci_phys);
|
||||
@@ -73,15 +74,13 @@ bool pci_xhci_init (struct proc* proc, struct reschedule_ctx* rctx, struct pci_i
|
||||
|
||||
bool irqs_support = false;
|
||||
|
||||
uint32_t irq = INTR_XHCI0 + xhci_counter;
|
||||
|
||||
if (!pci_msi_init (pci_info.bus, pci_info.slot, pci_info.func, irq, thiscpu->lapic_id)) {
|
||||
if (!pci_msi_init (pci_info.bus, pci_info.slot, pci_info.func, INTR_XHCI, thiscpu->lapic_id)) {
|
||||
uint8_t intr_line = pci_read8 (pci_info.bus, pci_info.slot, pci_info.func, PCI_INTERRUPT_LINE);
|
||||
uint8_t intr_pin = pci_read8 (pci_info.bus, pci_info.slot, pci_info.func, PCI_INTERRUPT_PIN);
|
||||
|
||||
if (intr_pin != 0) {
|
||||
irqs_support = true;
|
||||
ioapic_route_irq (irq, intr_line, 0, thiscpu->lapic_id);
|
||||
ioapic_route_irq (INTR_XHCI, intr_line, 0, thiscpu->lapic_id);
|
||||
}
|
||||
} else {
|
||||
irqs_support = true;
|
||||
@@ -89,19 +88,20 @@ bool pci_xhci_init (struct proc* proc, struct reschedule_ctx* rctx, struct pci_i
|
||||
|
||||
DEBUG ("IRQ support=%d\n", irqs_support);
|
||||
|
||||
char key[32];
|
||||
snprintf (key, sizeof (key), "xhci%d", xhci_counter++);
|
||||
|
||||
struct xhci_init init = {
|
||||
.xhci_mmio_base = xhci_base,
|
||||
.irqs_support = irqs_support,
|
||||
.irq = irq,
|
||||
.irq = INTR_XHCI,
|
||||
};
|
||||
|
||||
device_op_func_t ops[] = {0};
|
||||
device_op_func_t ops[] = {
|
||||
[XUSBCTRL_POLL_DRIVER] = &xhci_poll_driver,
|
||||
};
|
||||
|
||||
struct device* xhci =
|
||||
device_create (key, ops, lengthof (ops), &xhci_init, &xhci_fini, &init, proc, rctx);
|
||||
device_create (DEVICE_TYPE_USB_CTRL, "xhci", ops, lengthof (ops), &xhci_init, &xhci_fini, &init,
|
||||
proc, rctx);
|
||||
|
||||
xhci_init_done = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include <proc/proc.h>
|
||||
#include <proc/reschedule.h>
|
||||
#include <proc/suspension_q.h>
|
||||
#include <status.h>
|
||||
#include <sys/debug.h>
|
||||
#include <sys/spin_lock.h>
|
||||
#include <sys/stall.h>
|
||||
@@ -180,6 +181,37 @@ static void xhci_port_reset (struct xhci* xhci, uint8_t port) {
|
||||
stall_ms (100);
|
||||
}
|
||||
|
||||
static void xhci_create_plugged_device (struct xhci* xhci, uint8_t port) {
|
||||
struct xhci_plugged_device* pdevice;
|
||||
|
||||
list_find (struct xhci_plugged_device, xhci->xhci_plugged_devices, pdevice, port_value, port,
|
||||
plugged_devices_link);
|
||||
|
||||
if (pdevice != NULL)
|
||||
return;
|
||||
|
||||
pdevice = malloc (sizeof (*pdevice));
|
||||
memset (pdevice, 0, sizeof (*pdevice));
|
||||
pdevice->port_value = port;
|
||||
pdevice->slot_id = -1;
|
||||
|
||||
list_append (xhci->xhci_plugged_devices, &pdevice->plugged_devices_link);
|
||||
}
|
||||
|
||||
static void xhci_delete_plugged_device (struct xhci* xhci, uint8_t port) {
|
||||
struct xhci_plugged_device* pdevice;
|
||||
|
||||
list_find (struct xhci_plugged_device, xhci->xhci_plugged_devices, pdevice, port_value, port,
|
||||
plugged_devices_link);
|
||||
|
||||
list_remove (xhci->xhci_plugged_devices, &pdevice->plugged_devices_link);
|
||||
|
||||
if (pdevice->endpoint0_ring_phys != 0)
|
||||
pmm_free (pdevice->endpoint0_ring_phys, 1);
|
||||
|
||||
free (pdevice);
|
||||
}
|
||||
|
||||
static void xhci_event_dispatch (struct xhci* xhci, struct xhci_trb* event, uint8_t type) {
|
||||
switch (type) {
|
||||
case XHCI_TRB_CMD_CMPL_EVENT: {
|
||||
@@ -187,6 +219,8 @@ static void xhci_event_dispatch (struct xhci* xhci, struct xhci_trb* event, uint
|
||||
uint8_t slot_id = (event->ctrl >> 24) & 0xFF;
|
||||
|
||||
DEBUG ("cmd completion: code=%u,slot=%u\n", cmpl_code, slot_id);
|
||||
|
||||
xhci->last_slot_id = slot_id;
|
||||
} break;
|
||||
case XHCI_TRB_PORT_STS_CHNG: {
|
||||
uint8_t port = ((event->param >> 24) & 0xFF) - 1;
|
||||
@@ -200,10 +234,15 @@ static void xhci_event_dispatch (struct xhci* xhci, struct xhci_trb* event, uint
|
||||
xhci_portsc_write (xhci, port, portsc);
|
||||
|
||||
if ((portsc & (1 << 17))) {
|
||||
if ((portsc & (1 << 0)))
|
||||
if ((portsc & (1 << 0))) {
|
||||
DEBUG ("Device attached to port %u!\n", port);
|
||||
else
|
||||
|
||||
xhci_create_plugged_device (xhci, port);
|
||||
} else {
|
||||
DEBUG ("Device detached from port %u!\n", port);
|
||||
|
||||
xhci_delete_plugged_device (xhci, port);
|
||||
}
|
||||
}
|
||||
|
||||
if ((portsc & (1 << 21)))
|
||||
@@ -271,11 +310,8 @@ static void xhci_irq (void* arg, void* regs, bool user, struct reschedule_ctx* r
|
||||
spin_unlock (&xhci->device->lock, fd);
|
||||
}
|
||||
|
||||
void xhci_send_cmd (struct xhci* xhci, uint64_t param, uint32_t status, uint32_t ctrl) {
|
||||
uint64_t fd;
|
||||
|
||||
spin_lock (&xhci->device->lock, &fd);
|
||||
|
||||
static void xhci_send_cmd (struct xhci* xhci, uint64_t param, uint32_t status, uint32_t ctrl,
|
||||
uint64_t* lockflags) {
|
||||
if (xhci->irqs_support) {
|
||||
if (xhci->cmd_ring_idx == (xhci->cmd_ring_size - 1)) {
|
||||
struct xhci_trb* link = &xhci->cmd_ring[xhci->cmd_ring_idx];
|
||||
@@ -298,14 +334,14 @@ void xhci_send_cmd (struct xhci* xhci, uint64_t param, uint32_t status, uint32_t
|
||||
|
||||
xhci_write32 (xhci->xhci_doorbell_base, 0, 0);
|
||||
|
||||
spin_unlock (&xhci->device->lock, fd);
|
||||
|
||||
int timeout = 100;
|
||||
|
||||
while (atomic_load (&xhci->pending) && --timeout > 0)
|
||||
stall_ms (1);
|
||||
spin_unlock (&xhci->device->lock, *lockflags);
|
||||
|
||||
spin_lock (&xhci->device->lock, &fd);
|
||||
while (atomic_load (&xhci->pending) && --timeout > 0)
|
||||
stall_ms (10);
|
||||
|
||||
spin_lock (&xhci->device->lock, lockflags);
|
||||
|
||||
if (timeout == 0)
|
||||
DEBUG ("timed out\n");
|
||||
@@ -315,8 +351,6 @@ void xhci_send_cmd (struct xhci* xhci, uint64_t param, uint32_t status, uint32_t
|
||||
spin_lock_relax ();
|
||||
}
|
||||
}
|
||||
|
||||
spin_unlock (&xhci->device->lock, fd);
|
||||
}
|
||||
|
||||
static void xhci_bios_handover (struct xhci* xhci) {
|
||||
@@ -406,8 +440,6 @@ static void xhci_reset_ports (struct xhci* xhci) {
|
||||
|
||||
DEBUG ("PORT %u: USB %u.%u\n", port, major, minor);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
uint8_t next = (cap >> 8) & 0xFF;
|
||||
@@ -451,6 +483,9 @@ DEFINE_DEVICE_INIT (xhci_init) {
|
||||
uint32_t hcsparams2 = xhci_read32 (xhci->xhci_mmio_base, XHCI_HCSPARAMS2);
|
||||
xhci->max_scratchpad = (((hcsparams2 >> 21) & 0x1F) << 5) | ((hcsparams2 >> 27) & 0x1F);
|
||||
|
||||
uint32_t hccparams1 = xhci_read32 (xhci->xhci_mmio_base, XHCI_HCCPARAMS1);
|
||||
xhci->xhci_ctx_size = (hccparams1 & (1 << 2)) ? 64 : 32;
|
||||
|
||||
DEBUG ("starting init sequence\n");
|
||||
|
||||
/* stop running / clear Run/Stop bit */
|
||||
@@ -544,7 +579,7 @@ DEFINE_DEVICE_INIT (xhci_init) {
|
||||
usbcmd = xhci_read32 (xhci->xhci_oper_base, XHCI_USBCMD);
|
||||
xhci_write32 (xhci->xhci_oper_base, XHCI_USBCMD, usbcmd | (1 << 0) | (1 << 2));
|
||||
|
||||
xhci_send_cmd (xhci, 0, 0, XHCI_TRB_SLOT_ENAB_CMD << 10);
|
||||
stall_ms (500);
|
||||
|
||||
xhci_reset_ports (xhci);
|
||||
|
||||
@@ -569,6 +604,13 @@ DEFINE_DEVICE_FINI (xhci_fini) {
|
||||
pmm_free (scratchpads_phys, 1);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < PAGE_SIZE / sizeof (xhci->xhci_dcbaa[0]); i++) {
|
||||
uintptr_t out_ctx = xhci->xhci_dcbaa[i];
|
||||
|
||||
if (out_ctx != 0)
|
||||
pmm_free (out_ctx, 1);
|
||||
}
|
||||
|
||||
pmm_free (xhci->xhci_dcbaa_phys, 1);
|
||||
pmm_free (xhci->cmd_ring_phys, 1);
|
||||
pmm_free (xhci->event_ring_phys, 1);
|
||||
@@ -586,3 +628,86 @@ DEFINE_DEVICE_FINI (xhci_fini) {
|
||||
|
||||
free (xhci);
|
||||
}
|
||||
|
||||
static void xhci_poll_setup_devices (struct xhci* xhci, uint64_t* lockflags) {
|
||||
struct list_node_link *pdevice_link, *tmp_pdevice_link;
|
||||
struct limine_hhdm_response* hhdm = limine_hhdm_request.response;
|
||||
|
||||
list_foreach (xhci->xhci_plugged_devices, pdevice_link, tmp_pdevice_link) {
|
||||
struct xhci_plugged_device* pdevice =
|
||||
list_entry (pdevice_link, struct xhci_plugged_device, plugged_devices_link);
|
||||
|
||||
/* slot assigned */
|
||||
if (pdevice->slot_id != -1)
|
||||
continue;
|
||||
|
||||
struct xhci_port* xhci_port;
|
||||
list_find (struct xhci_port, xhci->xhci_ports, xhci_port, port_value, pdevice->port_value,
|
||||
ports_link);
|
||||
|
||||
xhci_send_cmd (xhci, 0, 0, XHCI_TRB_SLOT_ENAB_CMD << 10, lockflags);
|
||||
uint8_t slot_id = xhci->last_slot_id;
|
||||
|
||||
pdevice->slot_id = slot_id;
|
||||
|
||||
uintptr_t out_ctx_phys = pmm_alloc (1);
|
||||
void* out_ctx_virt = (void*)(out_ctx_phys + (uintptr_t)hhdm->offset);
|
||||
memset (out_ctx_virt, 0, PAGE_SIZE);
|
||||
xhci->xhci_dcbaa[pdevice->slot_id] = out_ctx_phys;
|
||||
|
||||
pdevice->endpoint0_ring_phys = pmm_alloc (1);
|
||||
pdevice->endpoint0_ring =
|
||||
(struct xhci_trb*)(pdevice->endpoint0_ring_phys + (uintptr_t)hhdm->offset);
|
||||
memset (pdevice->endpoint0_ring, 0, PAGE_SIZE);
|
||||
|
||||
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);
|
||||
|
||||
if (xhci->xhci_ctx_size == 64) {
|
||||
struct xhci_input_ctx64* ctx64 = input_ctx_virt;
|
||||
|
||||
size_t max_packet_size = (xhci_port->type == XHCI_PORT_USB3) ? 512 : 64;
|
||||
|
||||
/* Add slot and endpoint 0 */
|
||||
ctx64->ctrl.dw[1] = (1 << 0) | (1 << 1);
|
||||
|
||||
ctx64->slot.dw[0] = (1 << 27);
|
||||
ctx64->slot.dw[1] = ((pdevice->port_value + 1) << 16);
|
||||
|
||||
ctx64->endpoints[0].dw[1] = (3 << 1) | (4 << 3) | (max_packet_size << 16);
|
||||
ctx64->endpoints[0].dw[2] = (uint32_t)pdevice->endpoint0_ring_phys | (1 << 0);
|
||||
ctx64->endpoints[0].dw[3] = (uint32_t)(pdevice->endpoint0_ring_phys >> 32);
|
||||
} else {
|
||||
struct xhci_input_ctx32* ctx32 = input_ctx_virt;
|
||||
|
||||
size_t max_packet_size = (xhci_port->type == XHCI_PORT_USB3) ? 512 : 64;
|
||||
|
||||
ctx32->ctrl.dw[1] = (1 << 0) | (1 << 1);
|
||||
|
||||
ctx32->slot.dw[0] = (1 << 27);
|
||||
ctx32->slot.dw[1] = ((pdevice->port_value + 1) << 16);
|
||||
|
||||
ctx32->endpoints[0].dw[1] = (3 << 1) | (4 << 3) | (max_packet_size << 16);
|
||||
ctx32->endpoints[0].dw[2] = (uint32_t)pdevice->endpoint0_ring_phys | (1 << 0);
|
||||
ctx32->endpoints[0].dw[3] = (uint32_t)(pdevice->endpoint0_ring_phys >> 32);
|
||||
}
|
||||
|
||||
uint32_t ctrl = (pdevice->slot_id << 24) | (XHCI_TRB_ADDR_DEV_CMD << 10);
|
||||
xhci_send_cmd (xhci, input_ctx_phys, 0, ctrl, lockflags);
|
||||
|
||||
stall_ms (500);
|
||||
|
||||
DEBUG ("Device on port %u addressed on slot %u!\n", pdevice->port_value, pdevice->slot_id);
|
||||
|
||||
pmm_free (input_ctx_phys, 1);
|
||||
}
|
||||
}
|
||||
|
||||
DEFINE_DEVICE_OP (xhci_poll_driver) {
|
||||
struct xhci* xhci = device->udata;
|
||||
|
||||
xhci_poll_setup_devices (xhci, lockflags);
|
||||
|
||||
return ST_OK;
|
||||
}
|
||||
|
||||
@@ -23,6 +23,26 @@ struct xhci_trb {
|
||||
uint32_t ctrl;
|
||||
} PACKED;
|
||||
|
||||
struct xhci_ctx32 {
|
||||
uint32_t dw[8];
|
||||
} PACKED;
|
||||
|
||||
struct xhci_ctx64 {
|
||||
uint32_t dw[16];
|
||||
} PACKED;
|
||||
|
||||
struct xhci_input_ctx32 {
|
||||
struct xhci_ctx32 ctrl;
|
||||
struct xhci_ctx32 slot;
|
||||
struct xhci_ctx32 endpoints[31];
|
||||
};
|
||||
|
||||
struct xhci_input_ctx64 {
|
||||
struct xhci_ctx64 ctrl;
|
||||
struct xhci_ctx64 slot;
|
||||
struct xhci_ctx64 endpoints[31];
|
||||
};
|
||||
|
||||
struct xhci_init {
|
||||
uintptr_t xhci_mmio_base;
|
||||
bool irqs_support;
|
||||
@@ -38,6 +58,15 @@ struct xhci_port {
|
||||
int type;
|
||||
};
|
||||
|
||||
struct xhci_plugged_device {
|
||||
struct list_node_link plugged_devices_link;
|
||||
uint8_t port_value;
|
||||
int slot_id;
|
||||
|
||||
struct xhci_trb* endpoint0_ring;
|
||||
uintptr_t endpoint0_ring_phys;
|
||||
};
|
||||
|
||||
struct xhci {
|
||||
struct device* device;
|
||||
|
||||
@@ -73,13 +102,21 @@ struct xhci {
|
||||
struct xhci_erst_entry* erst;
|
||||
uintptr_t erst_phys;
|
||||
|
||||
atomic_bool pending;
|
||||
size_t xhci_ctx_size;
|
||||
|
||||
struct list_node_link* xhci_ports;
|
||||
struct list_node_link* xhci_plugged_devices;
|
||||
|
||||
atomic_bool pending;
|
||||
uint8_t last_slot_id;
|
||||
|
||||
spin_lock_t setup_lock;
|
||||
};
|
||||
|
||||
DEFINE_DEVICE_INIT (xhci_init);
|
||||
|
||||
DEFINE_DEVICE_FINI (xhci_fini);
|
||||
|
||||
DEFINE_DEVICE_OP (xhci_poll_driver);
|
||||
|
||||
#endif // _KERNEL_DEVICE_XHCI_H
|
||||
|
||||
Reference in New Issue
Block a user