mirror of
https://github.com/RGBCube/serenity
synced 2025-07-25 19:37:35 +00:00
Kernel: Add support for SD host controllers on the PCI bus
This commit is contained in:
parent
47cae8005f
commit
5fe6c6fc24
5 changed files with 124 additions and 5 deletions
|
@ -84,6 +84,7 @@ enum class ClassID {
|
||||||
MassStorage = 0x1,
|
MassStorage = 0x1,
|
||||||
Multimedia = 0x4,
|
Multimedia = 0x4,
|
||||||
Bridge = 0x6,
|
Bridge = 0x6,
|
||||||
|
Base = 0x8,
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace MassStorage {
|
namespace MassStorage {
|
||||||
|
@ -116,6 +117,14 @@ enum class SubclassID {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace Base {
|
||||||
|
|
||||||
|
enum class SubclassID {
|
||||||
|
SDHostController = 0x5,
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
AK_TYPEDEF_DISTINCT_ORDERED_ID(u8, CapabilityID);
|
AK_TYPEDEF_DISTINCT_ORDERED_ID(u8, CapabilityID);
|
||||||
|
|
||||||
namespace Capabilities {
|
namespace Capabilities {
|
||||||
|
|
|
@ -112,6 +112,7 @@ set(KERNEL_SOURCES
|
||||||
Storage/NVMe/NVMeInterruptQueue.cpp
|
Storage/NVMe/NVMeInterruptQueue.cpp
|
||||||
Storage/NVMe/NVMePollQueue.cpp
|
Storage/NVMe/NVMePollQueue.cpp
|
||||||
Storage/NVMe/NVMeQueue.cpp
|
Storage/NVMe/NVMeQueue.cpp
|
||||||
|
Storage/SD/PCISDHostController.cpp
|
||||||
Storage/SD/SDHostController.cpp
|
Storage/SD/SDHostController.cpp
|
||||||
Storage/SD/SDMemoryCard.cpp
|
Storage/SD/SDMemoryCard.cpp
|
||||||
Storage/DiskPartition.cpp
|
Storage/DiskPartition.cpp
|
||||||
|
|
37
Kernel/Storage/SD/PCISDHostController.cpp
Normal file
37
Kernel/Storage/SD/PCISDHostController.cpp
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2023, the SerenityOS developers.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <Kernel/Bus/PCI/API.h>
|
||||||
|
#include <Kernel/Storage/SD/PCISDHostController.h>
|
||||||
|
|
||||||
|
namespace Kernel {
|
||||||
|
|
||||||
|
ErrorOr<NonnullRefPtr<PCISDHostController>> PCISDHostController::try_initialize(PCI::DeviceIdentifier const& device_identifier)
|
||||||
|
{
|
||||||
|
auto sdhc = TRY(adopt_nonnull_ref_or_enomem(new (nothrow) PCISDHostController(device_identifier)));
|
||||||
|
TRY(sdhc->initialize());
|
||||||
|
|
||||||
|
return sdhc;
|
||||||
|
}
|
||||||
|
|
||||||
|
PCISDHostController::PCISDHostController(PCI::DeviceIdentifier const& device_identifier)
|
||||||
|
: PCI::Device(device_identifier)
|
||||||
|
, SDHostController()
|
||||||
|
{
|
||||||
|
auto slot_information_register = read_slot_information();
|
||||||
|
|
||||||
|
if (slot_information_register.slots_available() != 1) {
|
||||||
|
// TODO: Support multiple slots
|
||||||
|
dmesgln("SD Host Controller has {} slots, but we currently only support using only one", slot_information_register.slots_available());
|
||||||
|
}
|
||||||
|
|
||||||
|
auto physical_address_of_sdhc_registers = PhysicalAddress {
|
||||||
|
PCI::get_BAR(device_identifier, static_cast<PCI::HeaderType0BaseRegister>(slot_information_register.first_bar_number))
|
||||||
|
};
|
||||||
|
m_registers = Memory::map_typed_writable<SD::HostControlRegisterMap volatile>(physical_address_of_sdhc_registers).release_value_but_fixme_should_propagate_errors();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
50
Kernel/Storage/SD/PCISDHostController.h
Normal file
50
Kernel/Storage/SD/PCISDHostController.h
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2023, the SerenityOS developers.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <Kernel/Bus/PCI/API.h>
|
||||||
|
#include <Kernel/Bus/PCI/Device.h>
|
||||||
|
#include <Kernel/Memory/TypedMapping.h>
|
||||||
|
#include <Kernel/Storage/SD/SDHostController.h>
|
||||||
|
|
||||||
|
namespace Kernel {
|
||||||
|
|
||||||
|
class PCISDHostController : public PCI::Device
|
||||||
|
, public SDHostController {
|
||||||
|
public:
|
||||||
|
static ErrorOr<NonnullRefPtr<PCISDHostController>> try_initialize(PCI::DeviceIdentifier const& device_identifier);
|
||||||
|
|
||||||
|
// ^PCI::Device
|
||||||
|
virtual StringView device_name() const override { return "SD Host Controller"sv; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
// ^SDHostController
|
||||||
|
virtual SD::HostControlRegisterMap volatile* get_register_map_base_address() override { return m_registers.ptr(); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
PCISDHostController(PCI::DeviceIdentifier const& device_identifier);
|
||||||
|
|
||||||
|
struct [[gnu::packed]] SlotInformationRegister {
|
||||||
|
u8 first_bar_number : 3;
|
||||||
|
u8 : 1;
|
||||||
|
u8 number_of_slots : 3;
|
||||||
|
u8 : 1;
|
||||||
|
|
||||||
|
u8 slots_available() const { return number_of_slots + 1; }
|
||||||
|
};
|
||||||
|
static_assert(AssertSize<SlotInformationRegister, 1>());
|
||||||
|
|
||||||
|
SlotInformationRegister read_slot_information() const
|
||||||
|
{
|
||||||
|
SpinlockLocker locker(device_identifier().operation_lock());
|
||||||
|
return bit_cast<SlotInformationRegister>(PCI::Access::the().read8_field(device_identifier(), 0x40));
|
||||||
|
}
|
||||||
|
|
||||||
|
Memory::TypedMapping<SD::HostControlRegisterMap volatile> m_registers;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -28,6 +28,7 @@
|
||||||
#include <Kernel/Storage/ATA/AHCI/Controller.h>
|
#include <Kernel/Storage/ATA/AHCI/Controller.h>
|
||||||
#include <Kernel/Storage/ATA/GenericIDE/Controller.h>
|
#include <Kernel/Storage/ATA/GenericIDE/Controller.h>
|
||||||
#include <Kernel/Storage/NVMe/NVMeController.h>
|
#include <Kernel/Storage/NVMe/NVMeController.h>
|
||||||
|
#include <Kernel/Storage/SD/PCISDHostController.h>
|
||||||
#include <Kernel/Storage/SD/SDHostController.h>
|
#include <Kernel/Storage/SD/SDHostController.h>
|
||||||
#include <Kernel/Storage/StorageManagement.h>
|
#include <Kernel/Storage/StorageManagement.h>
|
||||||
#include <LibPartition/EBRPartitionTable.h>
|
#include <LibPartition/EBRPartitionTable.h>
|
||||||
|
@ -88,7 +89,6 @@ UNMAP_AFTER_INIT void StorageManagement::enumerate_pci_controllers(bool force_pi
|
||||||
{
|
{
|
||||||
VERIFY(m_controllers.is_empty());
|
VERIFY(m_controllers.is_empty());
|
||||||
|
|
||||||
using SubclassID = PCI::MassStorage::SubclassID;
|
|
||||||
if (!kernel_command_line().disable_physical_storage()) {
|
if (!kernel_command_line().disable_physical_storage()) {
|
||||||
// NOTE: Search for VMD devices before actually searching for storage controllers
|
// NOTE: Search for VMD devices before actually searching for storage controllers
|
||||||
// because the VMD device is only a bridge to such (NVMe) controllers.
|
// because the VMD device is only a bridge to such (NVMe) controllers.
|
||||||
|
@ -100,10 +100,8 @@ UNMAP_AFTER_INIT void StorageManagement::enumerate_pci_controllers(bool force_pi
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
MUST(PCI::enumerate([&](PCI::DeviceIdentifier const& device_identifier) -> void {
|
auto const& handle_mass_storage_device = [&](PCI::DeviceIdentifier const& device_identifier) {
|
||||||
if (device_identifier.class_code().value() != to_underlying(PCI::ClassID::MassStorage)) {
|
using SubclassID = PCI::MassStorage::SubclassID;
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto subclass_code = static_cast<SubclassID>(device_identifier.subclass_code().value());
|
auto subclass_code = static_cast<SubclassID>(device_identifier.subclass_code().value());
|
||||||
#if ARCH(X86_64)
|
#if ARCH(X86_64)
|
||||||
|
@ -135,6 +133,30 @@ UNMAP_AFTER_INIT void StorageManagement::enumerate_pci_controllers(bool force_pi
|
||||||
m_controllers.append(controller.release_value());
|
m_controllers.append(controller.release_value());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
auto const& handle_base_device = [&](PCI::DeviceIdentifier const& device_identifier) {
|
||||||
|
using SubclassID = PCI::Base::SubclassID;
|
||||||
|
|
||||||
|
auto subclass_code = static_cast<SubclassID>(device_identifier.subclass_code().value());
|
||||||
|
if (subclass_code == SubclassID::SDHostController) {
|
||||||
|
|
||||||
|
auto sdhc_or_error = PCISDHostController::try_initialize(device_identifier);
|
||||||
|
if (sdhc_or_error.is_error()) {
|
||||||
|
dmesgln("PCI: Failed to initialize SD Host Controller ({} - {}): {}", device_identifier.address(), device_identifier.hardware_id(), sdhc_or_error.error());
|
||||||
|
} else {
|
||||||
|
m_controllers.append(sdhc_or_error.release_value());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
MUST(PCI::enumerate([&](PCI::DeviceIdentifier const& device_identifier) -> void {
|
||||||
|
auto class_code = device_identifier.class_code().value();
|
||||||
|
if (class_code == to_underlying(PCI::ClassID::MassStorage)) {
|
||||||
|
handle_mass_storage_device(device_identifier);
|
||||||
|
} else if (class_code == to_underlying(PCI::ClassID::Base)) {
|
||||||
|
handle_base_device(device_identifier);
|
||||||
|
}
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue