forked from Bananymous/banan-os
Kernel: Take ownership of xHCI controller from bios
This commit is contained in:
parent
baa4e6475a
commit
86e9d92ecb
|
@ -38,7 +38,8 @@ namespace Kernel
|
|||
};
|
||||
|
||||
public:
|
||||
static BAN::ErrorOr<BAN::UniqPtr<XHCIController>> initialize(PCI::Device&);
|
||||
static BAN::ErrorOr<void> take_ownership(PCI::Device&);
|
||||
static BAN::ErrorOr<BAN::UniqPtr<XHCIController>> create(PCI::Device&);
|
||||
|
||||
void handle_irq() final override;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -241,8 +241,6 @@ namespace Kernel::Input
|
|||
|
||||
BAN::ErrorOr<void> PS2Controller::initialize_impl()
|
||||
{
|
||||
// FIXME: Initialise USB Controllers
|
||||
|
||||
// Determine if the PS/2 Controller Exists
|
||||
auto* fadt = static_cast<const ACPI::FADT*>(ACPI::ACPI::get().get_header("FACP"_sv, 0));
|
||||
if (fadt && fadt->revision > 1 && !(fadt->iapc_boot_arch & (1 << 1)))
|
||||
|
|
|
@ -13,6 +13,36 @@ namespace Kernel
|
|||
ASSERT(!s_instance);
|
||||
auto manager = TRY(BAN::UniqPtr<USBManager>::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);
|
||||
}
|
||||
|
||||
|
|
|
@ -22,7 +22,51 @@ namespace Kernel
|
|||
m_port_updater->exit(0, SIGKILL);
|
||||
}
|
||||
|
||||
BAN::ErrorOr<BAN::UniqPtr<XHCIController>> XHCIController::initialize(PCI::Device& pci_device)
|
||||
BAN::ErrorOr<void> 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<volatile XHCI::CapabilityRegs*>(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<volatile XHCI::ExtendedCap*>(ext_addr);
|
||||
|
||||
if (ext_cap.capability_id == XHCI::ExtendedCapabilityID::USBLegacySupport)
|
||||
{
|
||||
auto& legacy = *reinterpret_cast<volatile XHCI::USBLegacySupportCap*>(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<BAN::UniqPtr<XHCIController>> XHCIController::create(PCI::Device& pci_device)
|
||||
{
|
||||
auto controller = TRY(BAN::UniqPtr<XHCIController>::create(pci_device));
|
||||
TRY(controller->initialize_impl());
|
||||
|
|
|
@ -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();
|
||||
|
|
Loading…
Reference in New Issue