diff --git a/kernel/include/kernel/USB/XHCI/Controller.h b/kernel/include/kernel/USB/XHCI/Controller.h index 463345115c..92820261b1 100644 --- a/kernel/include/kernel/USB/XHCI/Controller.h +++ b/kernel/include/kernel/USB/XHCI/Controller.h @@ -38,7 +38,8 @@ namespace Kernel }; public: - static BAN::ErrorOr> initialize(PCI::Device&); + static BAN::ErrorOr take_ownership(PCI::Device&); + static BAN::ErrorOr> create(PCI::Device&); void handle_irq() final override; diff --git a/kernel/include/kernel/USB/XHCI/Definitions.h b/kernel/include/kernel/USB/XHCI/Definitions.h index d4ccf3b175..6a6e1b80ad 100644 --- a/kernel/include/kernel/USB/XHCI/Definitions.h +++ b/kernel/include/kernel/USB/XHCI/Definitions.h @@ -409,6 +409,17 @@ namespace Kernel::XHCI }; static_assert(sizeof(ExtendedCap) == 4); + struct USBLegacySupportCap + { + uint32_t capability_id : 8; + uint32_t next_capability : 8; + uint32_t hc_bios_owned_semaphore : 1; + uint32_t : 7; + uint32_t hc_os_owned_semaphore : 1; + uint32_t : 7; + }; + static_assert(sizeof(USBLegacySupportCap) == 4); + struct SupportedPrococolCap { uint32_t capability_id : 8; diff --git a/kernel/kernel/Input/PS2/Controller.cpp b/kernel/kernel/Input/PS2/Controller.cpp index cdc83b1b10..6f7ce69804 100644 --- a/kernel/kernel/Input/PS2/Controller.cpp +++ b/kernel/kernel/Input/PS2/Controller.cpp @@ -241,8 +241,6 @@ namespace Kernel::Input BAN::ErrorOr PS2Controller::initialize_impl() { - // FIXME: Initialise USB Controllers - // Determine if the PS/2 Controller Exists auto* fadt = static_cast(ACPI::ACPI::get().get_header("FACP"_sv, 0)); if (fadt && fadt->revision > 1 && !(fadt->iapc_boot_arch & (1 << 1))) diff --git a/kernel/kernel/USB/USBManager.cpp b/kernel/kernel/USB/USBManager.cpp index e31261c976..6b8858eb8e 100644 --- a/kernel/kernel/USB/USBManager.cpp +++ b/kernel/kernel/USB/USBManager.cpp @@ -13,6 +13,36 @@ namespace Kernel ASSERT(!s_instance); auto manager = TRY(BAN::UniqPtr::create()); s_instance = BAN::move(manager); + + PCI::PCIManager::get().for_each_device( + [](PCI::Device& pci_device) + { + if (pci_device.class_code() != 0x0C || pci_device.subclass() != 0x03) + return; + switch (pci_device.prog_if()) + { + case 0x00: + dprintln("Unsupported UHCI controller"); + break; + case 0x10: + dprintln("Unsupported OHCI controller"); + break; + case 0x20: + dprintln("Unsupported EHCI controller"); + break; + case 0x30: + if (auto ret = XHCIController::take_ownership(pci_device); ret.is_error()) + dprintln("Could not take ownership of xHCI controller: {}", ret.error()); + else + dprintln("Took ownership of xHCI controller"); + break; + default: + dprintln("Unsupported USB controller, prog if {2H}", pci_device.prog_if()); + break; + } + } + ); + return {}; } @@ -40,12 +70,13 @@ namespace Kernel dprintln("Unsupported EHCI controller"); return BAN::Error::from_errno(ENOTSUP); case 0x30: - if (auto ret = XHCIController::initialize(pci_device); ret.is_error()) + if (auto ret = XHCIController::create(pci_device); ret.is_error()) dprintln("Could not initialize XHCI controller: {}", ret.error()); else controller = ret.release_value(); break; default: + dprintln("Unsupported USB controller, prog if {2H}", pci_device.prog_if()); return BAN::Error::from_errno(EINVAL); } diff --git a/kernel/kernel/USB/XHCI/Controller.cpp b/kernel/kernel/USB/XHCI/Controller.cpp index 89a1b4e002..b546aefac0 100644 --- a/kernel/kernel/USB/XHCI/Controller.cpp +++ b/kernel/kernel/USB/XHCI/Controller.cpp @@ -22,7 +22,51 @@ namespace Kernel m_port_updater->exit(0, SIGKILL); } - BAN::ErrorOr> XHCIController::initialize(PCI::Device& pci_device) + BAN::ErrorOr XHCIController::take_ownership(PCI::Device& pci_device) + { + auto bar = TRY(pci_device.allocate_bar_region(0)); + if (bar->type() != PCI::BarType::MEM) + { + dwarnln("XHCI controller with non-memory configuration space"); + return BAN::Error::from_errno(EINVAL); + } + + auto& capabilities = *reinterpret_cast(bar->vaddr()); + const uint16_t ext_offset = capabilities.hccparams1.xhci_extended_capabilities_pointer; + if (ext_offset == 0) + { + dwarnln("XHCI controller does not have extended capabilities"); + return BAN::Error::from_errno(EFAULT); + } + + vaddr_t ext_addr = bar->vaddr() + ext_offset * 4; + while (true) + { + auto& ext_cap = *reinterpret_cast(ext_addr); + + if (ext_cap.capability_id == XHCI::ExtendedCapabilityID::USBLegacySupport) + { + auto& legacy = *reinterpret_cast(ext_addr); + if (!legacy.hc_bios_owned_semaphore) + return {}; + legacy.hc_os_owned_semaphore = 1; + + const uint64_t timeout_ms = SystemTimer::get().ms_since_boot() + 1000; + while (legacy.hc_bios_owned_semaphore) + if (SystemTimer::get().ms_since_boot() > timeout_ms) + return BAN::Error::from_errno(ETIMEDOUT); + return {}; + } + + if (ext_cap.next_capability == 0) + break; + ext_addr += ext_cap.next_capability * 4; + } + + return {}; + } + + BAN::ErrorOr> XHCIController::create(PCI::Device& pci_device) { auto controller = TRY(BAN::UniqPtr::create(pci_device)); TRY(controller->initialize_impl()); diff --git a/kernel/kernel/kernel.cpp b/kernel/kernel/kernel.cpp index 5d260974f9..584084589d 100644 --- a/kernel/kernel/kernel.cpp +++ b/kernel/kernel/kernel.cpp @@ -189,6 +189,9 @@ static void init2(void*) PCI::PCIManager::initialize(); dprintln("PCI initialized"); + MUST(USBManager::initialize()); + dprintln("USBManager initialized"); + if (ACPI::ACPI::get().enter_acpi_mode(InterruptController::get().is_using_apic()).is_error()) dprintln("Failed to enter ACPI mode"); @@ -202,14 +205,12 @@ static void init2(void*) // Initialize empty keymap MUST(LibInput::KeyboardLayout::initialize()); - // FIXME: initialize PS/2 after USB + // FIXME: implement device hot plugging, so multiple devices is possible //if (auto res = PS2Controller::initialize(); res.is_error()) // dprintln("{}", res.error()); MUST(NetworkManager::initialize()); - MUST(USBManager::initialize()); - // NOTE: PCI devices are the last ones to be initialized // so other devices can reserve predefined interrupts PCI::PCIManager::get().initialize_devices();