mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-31 15:12:45 +00:00 
			
		
		
		
	Kernel/PCI: Cache more details about PCI devices when enumerating them
There's no good reason to fetch these values each time we need them.
This commit is contained in:
		
							parent
							
								
									e22d9dc360
								
							
						
					
					
						commit
						82bb08a15c
					
				
					 14 changed files with 85 additions and 41 deletions
				
			
		|  | @ -17,7 +17,7 @@ u8 read8(Address address, u32 field) { return Access::the().read8_field(address, | ||||||
| u16 read16(Address address, u32 field) { return Access::the().read16_field(address, field); } | u16 read16(Address address, u32 field) { return Access::the().read16_field(address, field); } | ||||||
| u32 read32(Address address, u32 field) { return Access::the().read32_field(address, field); } | u32 read32(Address address, u32 field) { return Access::the().read32_field(address, field); } | ||||||
| 
 | 
 | ||||||
| void enumerate(Function<void(Address, ID)> callback) | void enumerate(Function<void(Address, PhysicalID const&)> callback) | ||||||
| { | { | ||||||
|     Access::the().fast_enumerate(callback); |     Access::the().fast_enumerate(callback); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -19,7 +19,7 @@ u32 read32(Address address, u32 field); | ||||||
| 
 | 
 | ||||||
| ID get_id(PCI::Address); | ID get_id(PCI::Address); | ||||||
| bool is_io_space_enabled(Address); | bool is_io_space_enabled(Address); | ||||||
| void enumerate(Function<void(Address, ID)> callback); | void enumerate(Function<void(Address, PhysicalID const&)> callback); | ||||||
| void enable_interrupt_line(Address); | void enable_interrupt_line(Address); | ||||||
| void disable_interrupt_line(Address); | void disable_interrupt_line(Address); | ||||||
| u8 get_interrupt_line(Address); | u8 get_interrupt_line(Address); | ||||||
|  |  | ||||||
|  | @ -381,7 +381,14 @@ UNMAP_AFTER_INIT void Access::enumerate_functions(int type, u8 bus, u8 device, u | ||||||
|     Address address(0, bus, device, function); |     Address address(0, bus, device, function); | ||||||
|     auto read_type = (read8_field(address, PCI_CLASS) << 8u) | read8_field(address, PCI_SUBCLASS); |     auto read_type = (read8_field(address, PCI_CLASS) << 8u) | read8_field(address, PCI_SUBCLASS); | ||||||
|     if (type == -1 || type == read_type) { |     if (type == -1 || type == read_type) { | ||||||
|         m_physical_ids.append(PhysicalID { address, { read16_field(address, PCI_VENDOR_ID), read16_field(address, PCI_DEVICE_ID) }, get_capabilities(address) }); |         PCI::ID id = { read16_field(address, PCI_VENDOR_ID), read16_field(address, PCI_DEVICE_ID) }; | ||||||
|  |         ClassCode class_code = read8_field(address, PCI_CLASS); | ||||||
|  |         SubclassCode subclass_code = read8_field(address, PCI_SUBCLASS); | ||||||
|  |         ProgrammingInterface prog_if = read8_field(address, PCI_PROG_IF); | ||||||
|  |         RevisionID revision_id = read8_field(address, PCI_REVISION_ID); | ||||||
|  |         SubsystemID subsystem_id = read16_field(address, PCI_SUBSYSTEM_ID); | ||||||
|  |         SubsystemVendorID subsystem_vendor_id = read16_field(address, PCI_SUBSYSTEM_VENDOR_ID); | ||||||
|  |         m_physical_ids.append(PhysicalID { address, id, revision_id, class_code, subclass_code, prog_if, subsystem_id, subsystem_vendor_id, get_capabilities(address) }); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     if (read_type == PCI_TYPE_BRIDGE && recursive && (!m_enumerated_buses.get(read8_field(address, PCI_SECONDARY_BUS)))) { |     if (read_type == PCI_TYPE_BRIDGE && recursive && (!m_enumerated_buses.get(read8_field(address, PCI_SECONDARY_BUS)))) { | ||||||
|  | @ -416,12 +423,12 @@ UNMAP_AFTER_INIT void Access::enumerate_bus(int type, u8 bus, bool recursive) | ||||||
|         enumerate_device(type, bus, device, recursive); |         enumerate_device(type, bus, device, recursive); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void Access::fast_enumerate(Function<void(Address, ID)>& callback) const | void Access::fast_enumerate(Function<void(Address, PhysicalID const&)>& callback) const | ||||||
| { | { | ||||||
|     MutexLocker locker(m_scan_lock); |     MutexLocker locker(m_scan_lock); | ||||||
|     VERIFY(!m_physical_ids.is_empty()); |     VERIFY(!m_physical_ids.is_empty()); | ||||||
|     for (auto& physical_id : m_physical_ids) { |     for (auto& physical_id : m_physical_ids) { | ||||||
|         callback(physical_id.address(), physical_id.id()); |         callback(physical_id.address(), physical_id); | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -25,7 +25,7 @@ public: | ||||||
|     static bool initialize_for_memory_access(PhysicalAddress mcfg_table); |     static bool initialize_for_memory_access(PhysicalAddress mcfg_table); | ||||||
|     static bool initialize_for_io_access(); |     static bool initialize_for_io_access(); | ||||||
| 
 | 
 | ||||||
|     void fast_enumerate(Function<void(Address, ID)>&) const; |     void fast_enumerate(Function<void(Address, PhysicalID const&)>&) const; | ||||||
|     void rescan_hardware(); |     void rescan_hardware(); | ||||||
| 
 | 
 | ||||||
|     static Access& the(); |     static Access& the(); | ||||||
|  |  | ||||||
|  | @ -181,11 +181,25 @@ private: | ||||||
|     const u8 m_ptr; |     const u8 m_ptr; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | TYPEDEF_DISTINCT_ORDERED_ID(u8, ClassCode); | ||||||
|  | TYPEDEF_DISTINCT_ORDERED_ID(u8, SubclassCode); | ||||||
|  | TYPEDEF_DISTINCT_ORDERED_ID(u8, ProgrammingInterface); | ||||||
|  | TYPEDEF_DISTINCT_ORDERED_ID(u8, RevisionID); | ||||||
|  | TYPEDEF_DISTINCT_ORDERED_ID(u16, SubsystemID); | ||||||
|  | TYPEDEF_DISTINCT_ORDERED_ID(u16, SubsystemVendorID); | ||||||
|  | 
 | ||||||
|  | class Access; | ||||||
| class PhysicalID { | class PhysicalID { | ||||||
| public: | public: | ||||||
|     PhysicalID(Address address, ID id, Vector<Capability> capabilities) |     PhysicalID(Address address, ID id, RevisionID revision_id, ClassCode class_code, SubclassCode subclass_code, ProgrammingInterface prog_if, SubsystemID subsystem_id, SubsystemVendorID subsystem_vendor_id, Vector<Capability> capabilities) | ||||||
|         : m_address(address) |         : m_address(address) | ||||||
|         , m_id(id) |         , m_id(id) | ||||||
|  |         , m_revision_id(revision_id) | ||||||
|  |         , m_class_code(class_code) | ||||||
|  |         , m_subclass_code(subclass_code) | ||||||
|  |         , m_prog_if(prog_if) | ||||||
|  |         , m_subsystem_id(subsystem_id) | ||||||
|  |         , m_subsystem_vendor_id(subsystem_vendor_id) | ||||||
|         , m_capabilities(capabilities) |         , m_capabilities(capabilities) | ||||||
|     { |     { | ||||||
|         if constexpr (PCI_DEBUG) { |         if constexpr (PCI_DEBUG) { | ||||||
|  | @ -198,13 +212,36 @@ public: | ||||||
|     const ID& id() const { return m_id; } |     const ID& id() const { return m_id; } | ||||||
|     const Address& address() const { return m_address; } |     const Address& address() const { return m_address; } | ||||||
| 
 | 
 | ||||||
|  |     RevisionID revision_id() const { return m_revision_id; } | ||||||
|  |     ClassCode class_code() const { return m_class_code; } | ||||||
|  |     SubclassCode subclass_code() const { return m_subclass_code; } | ||||||
|  |     ProgrammingInterface prog_if() const { return m_prog_if; } | ||||||
|  |     SubsystemID subsystem_id() const { return m_subsystem_id; } | ||||||
|  |     SubsystemVendorID subsystem_vendor_id() const { return m_subsystem_vendor_id; } | ||||||
|  | 
 | ||||||
|  |     void apply_subclass_code_change(Badge<Access>, SubclassCode new_subclass) | ||||||
|  |     { | ||||||
|  |         m_subclass_code = new_subclass; | ||||||
|  |     } | ||||||
|  |     void apply_prog_if_change(Badge<Access>, ProgrammingInterface new_progif) | ||||||
|  |     { | ||||||
|  |         m_prog_if = new_progif; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
| private: | private: | ||||||
|     Address m_address; |     Address m_address; | ||||||
|     ID m_id; |     ID m_id; | ||||||
|  | 
 | ||||||
|  |     RevisionID m_revision_id; | ||||||
|  |     ClassCode m_class_code; | ||||||
|  |     SubclassCode m_subclass_code; | ||||||
|  |     ProgrammingInterface m_prog_if; | ||||||
|  |     SubsystemID m_subsystem_id; | ||||||
|  |     SubsystemVendorID m_subsystem_vendor_id; | ||||||
|  | 
 | ||||||
|     Vector<Capability> m_capabilities; |     Vector<Capability> m_capabilities; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| class Access; |  | ||||||
| class Domain; | class Domain; | ||||||
| class Device; | class Device; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -56,8 +56,8 @@ UNMAP_AFTER_INIT void initialize() | ||||||
| 
 | 
 | ||||||
|     PCI::PCIBusSysFSDirectory::initialize(); |     PCI::PCIBusSysFSDirectory::initialize(); | ||||||
| 
 | 
 | ||||||
|     PCI::enumerate([&](const Address& address, ID id) { |     PCI::enumerate([&](const Address& address, PhysicalID const& physical_id) { | ||||||
|         dmesgln("{} {}", address, id); |         dmesgln("{} {}", address, physical_id.id()); | ||||||
|     }); |     }); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -41,7 +41,7 @@ UNMAP_AFTER_INIT void PCIBusSysFSDirectory::initialize() | ||||||
| UNMAP_AFTER_INIT PCIBusSysFSDirectory::PCIBusSysFSDirectory() | UNMAP_AFTER_INIT PCIBusSysFSDirectory::PCIBusSysFSDirectory() | ||||||
|     : SysFSDirectory("pci", SysFSComponentRegistry::the().buses_directory()) |     : SysFSDirectory("pci", SysFSComponentRegistry::the().buses_directory()) | ||||||
| { | { | ||||||
|     PCI::enumerate([&](const Address& address, ID) { |     PCI::enumerate([&](const Address& address, PhysicalID const&) { | ||||||
|         auto pci_device = PCI::PCIDeviceSysFSDirectory::create(*this, address); |         auto pci_device = PCI::PCIDeviceSysFSDirectory::create(*this, address); | ||||||
|         m_components.append(pci_device); |         m_components.append(pci_device); | ||||||
|     }); |     }); | ||||||
|  |  | ||||||
|  | @ -27,10 +27,10 @@ UNMAP_AFTER_INIT void USBManagement::enumerate_controllers() | ||||||
|     if (kernel_command_line().disable_usb()) |     if (kernel_command_line().disable_usb()) | ||||||
|         return; |         return; | ||||||
| 
 | 
 | ||||||
|     PCI::enumerate([this](PCI::Address const& address, PCI::ID) { |     PCI::enumerate([this](PCI::Address const& address, PCI::PhysicalID const& physical_id) { | ||||||
|         if (!(PCI::get_class(address) == 0xc && PCI::get_subclass(address) == 0x3)) |         if (!(physical_id.class_code().value() == 0xc && physical_id.subclass_code().value() == 0x3)) | ||||||
|             return; |             return; | ||||||
|         if (PCI::get_programming_interface(address) == 0x0) { |         if (physical_id.prog_if().value() == 0x0) { | ||||||
|             if (kernel_command_line().disable_uhci_controller()) |             if (kernel_command_line().disable_uhci_controller()) | ||||||
|                 return; |                 return; | ||||||
| 
 | 
 | ||||||
|  | @ -40,22 +40,22 @@ UNMAP_AFTER_INIT void USBManagement::enumerate_controllers() | ||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         if (PCI::get_programming_interface(address) == 0x10) { |         if (physical_id.prog_if().value() == 0x10) { | ||||||
|             dmesgln("USBManagement: OHCI controller found at {} is not currently supported.", address); |             dmesgln("USBManagement: OHCI controller found at {} is not currently supported.", address); | ||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         if (PCI::get_programming_interface(address) == 0x20) { |         if (physical_id.prog_if().value() == 0x20) { | ||||||
|             dmesgln("USBManagement: EHCI controller found at {} is not currently supported.", address); |             dmesgln("USBManagement: EHCI controller found at {} is not currently supported.", address); | ||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         if (PCI::get_programming_interface(address) == 0x30) { |         if (physical_id.prog_if().value() == 0x30) { | ||||||
|             dmesgln("USBManagement: xHCI controller found at {} is not currently supported.", address); |             dmesgln("USBManagement: xHCI controller found at {} is not currently supported.", address); | ||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         dmesgln("USBManagement: Unknown/unsupported controller at {} with programming interface 0x{:02x}", address, PCI::get_programming_interface(address)); |         dmesgln("USBManagement: Unknown/unsupported controller at {} with programming interface 0x{:02x}", address, physical_id.prog_if().value()); | ||||||
|     }); |     }); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -18,13 +18,13 @@ UNMAP_AFTER_INIT void detect() | ||||||
| { | { | ||||||
|     if (kernel_command_line().disable_virtio()) |     if (kernel_command_line().disable_virtio()) | ||||||
|         return; |         return; | ||||||
|     PCI::enumerate([&](const PCI::Address& address, PCI::ID id) { |     PCI::enumerate([&](const PCI::Address& address, PCI::PhysicalID const& physical_id) { | ||||||
|         if (address.is_null() || id.is_null()) |         if (address.is_null() || physical_id.id().is_null()) | ||||||
|             return; |             return; | ||||||
|         // TODO: We should also be checking that the device_id is in between 0x1000 - 0x107F inclusive
 |         // TODO: We should also be checking that the device_id is in between 0x1000 - 0x107F inclusive
 | ||||||
|         if (id.vendor_id != PCI::VendorID::VirtIO) |         if (physical_id.id().vendor_id != PCI::VendorID::VirtIO) | ||||||
|             return; |             return; | ||||||
|         switch (id.device_id) { |         switch (physical_id.id().device_id) { | ||||||
|         case PCI::DeviceID::VirtIOConsole: { |         case PCI::DeviceID::VirtIOConsole: { | ||||||
|             auto& console = Console::must_create(address).leak_ref(); |             auto& console = Console::must_create(address).leak_ref(); | ||||||
|             console.initialize(); |             console.initialize(); | ||||||
|  | @ -40,7 +40,7 @@ UNMAP_AFTER_INIT void detect() | ||||||
|             break; |             break; | ||||||
|         } |         } | ||||||
|         default: |         default: | ||||||
|             dbgln_if(VIRTIO_DEBUG, "VirtIO: Unknown VirtIO device with ID: {}", id.device_id); |             dbgln_if(VIRTIO_DEBUG, "VirtIO: Unknown VirtIO device with ID: {}", physical_id.id().device_id); | ||||||
|             break; |             break; | ||||||
|         } |         } | ||||||
|     }); |     }); | ||||||
|  |  | ||||||
|  | @ -15,12 +15,12 @@ static SerialDevice* s_the = nullptr; | ||||||
| UNMAP_AFTER_INIT void PCISerialDevice::detect() | UNMAP_AFTER_INIT void PCISerialDevice::detect() | ||||||
| { | { | ||||||
|     size_t current_device_minor = 68; |     size_t current_device_minor = 68; | ||||||
|     PCI::enumerate([&](const PCI::Address& address, PCI::ID id) { |     PCI::enumerate([&](const PCI::Address& address, PCI::PhysicalID const& physical_id) { | ||||||
|         if (address.is_null()) |         if (address.is_null()) | ||||||
|             return; |             return; | ||||||
| 
 | 
 | ||||||
|         for (auto& board_definition : board_definitions) { |         for (auto& board_definition : board_definitions) { | ||||||
|             if (board_definition.device_id != id) |             if (board_definition.device_id != physical_id.id()) | ||||||
|                 continue; |                 continue; | ||||||
| 
 | 
 | ||||||
|             auto bar_base = PCI::get_BAR(address, board_definition.pci_bar) & ~1; |             auto bar_base = PCI::get_BAR(address, board_definition.pci_bar) & ~1; | ||||||
|  |  | ||||||
|  | @ -614,19 +614,19 @@ private: | ||||||
|     virtual KResult try_generate(KBufferBuilder& builder) override |     virtual KResult try_generate(KBufferBuilder& builder) override | ||||||
|     { |     { | ||||||
|         JsonArraySerializer array { builder }; |         JsonArraySerializer array { builder }; | ||||||
|         PCI::enumerate([&array](PCI::Address address, PCI::ID id) { |         PCI::enumerate([&array](PCI::Address address, PCI::PhysicalID const& physical_id) { | ||||||
|             auto obj = array.add_object(); |             auto obj = array.add_object(); | ||||||
|             obj.add("domain", address.domain()); |             obj.add("domain", address.domain()); | ||||||
|             obj.add("bus", address.bus()); |             obj.add("bus", address.bus()); | ||||||
|             obj.add("device", address.device()); |             obj.add("device", address.device()); | ||||||
|             obj.add("function", address.function()); |             obj.add("function", address.function()); | ||||||
|             obj.add("vendor_id", id.vendor_id); |             obj.add("vendor_id", physical_id.id().vendor_id); | ||||||
|             obj.add("device_id", id.device_id); |             obj.add("device_id", physical_id.id().device_id); | ||||||
|             obj.add("revision_id", PCI::get_revision_id(address)); |             obj.add("revision_id", physical_id.revision_id().value()); | ||||||
|             obj.add("subclass", PCI::get_subclass(address)); |             obj.add("subclass", physical_id.subclass_code().value()); | ||||||
|             obj.add("class", PCI::get_class(address)); |             obj.add("class", physical_id.class_code().value()); | ||||||
|             obj.add("subsystem_id", PCI::get_subsystem_id(address)); |             obj.add("subsystem_id", physical_id.subsystem_id().value()); | ||||||
|             obj.add("subsystem_vendor_id", PCI::get_subsystem_vendor_id(address)); |             obj.add("subsystem_vendor_id", physical_id.subsystem_vendor_id().value()); | ||||||
|         }); |         }); | ||||||
|         array.finish(); |         array.finish(); | ||||||
|         return KSuccess; |         return KSuccess; | ||||||
|  |  | ||||||
|  | @ -179,13 +179,13 @@ UNMAP_AFTER_INIT bool GraphicsManagement::initialize() | ||||||
|         dbgln("Forcing no initialization of framebuffer devices"); |         dbgln("Forcing no initialization of framebuffer devices"); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     PCI::enumerate([&](const PCI::Address& address, PCI::ID id) { |     PCI::enumerate([&](const PCI::Address& address, PCI::PhysicalID const& physical_id) { | ||||||
|         // Note: Each graphics controller will try to set its native screen resolution
 |         // Note: Each graphics controller will try to set its native screen resolution
 | ||||||
|         // upon creation. Later on, if we don't want to have framebuffer devices, a
 |         // upon creation. Later on, if we don't want to have framebuffer devices, a
 | ||||||
|         // framebuffer console will take the control instead.
 |         // framebuffer console will take the control instead.
 | ||||||
|         if (!is_vga_compatible_pci_device(address) && !is_display_controller_pci_device(address)) |         if (!is_vga_compatible_pci_device(address) && !is_display_controller_pci_device(address)) | ||||||
|             return; |             return; | ||||||
|         determine_and_initialize_graphics_device(address, id); |         determine_and_initialize_graphics_device(address, physical_id.id()); | ||||||
|     }); |     }); | ||||||
| 
 | 
 | ||||||
|     if (m_graphics_devices.is_empty()) { |     if (m_graphics_devices.is_empty()) { | ||||||
|  |  | ||||||
|  | @ -91,9 +91,9 @@ UNMAP_AFTER_INIT RefPtr<NetworkAdapter> NetworkingManagement::determine_network_ | ||||||
| bool NetworkingManagement::initialize() | bool NetworkingManagement::initialize() | ||||||
| { | { | ||||||
|     if (!kernel_command_line().is_physical_networking_disabled()) { |     if (!kernel_command_line().is_physical_networking_disabled()) { | ||||||
|         PCI::enumerate([&](const PCI::Address& address, PCI::ID) { |         PCI::enumerate([&](const PCI::Address& address, PCI::PhysicalID const& physical_id) { | ||||||
|             // Note: PCI class 2 is the class of Network devices
 |             // Note: PCI class 2 is the class of Network devices
 | ||||||
|             if (PCI::get_class(address) != 0x02) |             if (physical_id.class_code().value() != 0x02) | ||||||
|                 return; |                 return; | ||||||
|             if (auto adapter = determine_network_device(address); !adapter.is_null()) |             if (auto adapter = determine_network_device(address); !adapter.is_null()) | ||||||
|                 m_adapters.append(adapter.release_nonnull()); |                 m_adapters.append(adapter.release_nonnull()); | ||||||
|  |  | ||||||
|  | @ -44,14 +44,14 @@ UNMAP_AFTER_INIT void StorageManagement::enumerate_controllers(bool force_pio) | ||||||
|     VERIFY(m_controllers.is_empty()); |     VERIFY(m_controllers.is_empty()); | ||||||
|     if (!kernel_command_line().disable_physical_storage()) { |     if (!kernel_command_line().disable_physical_storage()) { | ||||||
|         if (kernel_command_line().is_ide_enabled()) { |         if (kernel_command_line().is_ide_enabled()) { | ||||||
|             PCI::enumerate([&](const PCI::Address& address, PCI::ID) { |             PCI::enumerate([&](const PCI::Address& address, PCI::PhysicalID const& physical_id) { | ||||||
|                 if (PCI::get_class(address) == PCI_MASS_STORAGE_CLASS_ID && PCI::get_subclass(address) == PCI_IDE_CTRL_SUBCLASS_ID) { |                 if (physical_id.class_code().value() == PCI_MASS_STORAGE_CLASS_ID && physical_id.subclass_code().value() == PCI_IDE_CTRL_SUBCLASS_ID) { | ||||||
|                     m_controllers.append(IDEController::initialize(address, force_pio)); |                     m_controllers.append(IDEController::initialize(address, force_pio)); | ||||||
|                 } |                 } | ||||||
|             }); |             }); | ||||||
|         } |         } | ||||||
|         PCI::enumerate([&](const PCI::Address& address, PCI::ID) { |         PCI::enumerate([&](const PCI::Address& address, PCI::PhysicalID const& physical_id) { | ||||||
|             if (PCI::get_class(address) == PCI_MASS_STORAGE_CLASS_ID && PCI::get_subclass(address) == PCI_SATA_CTRL_SUBCLASS_ID && PCI::get_programming_interface(address) == PCI_AHCI_IF_PROGIF) { |             if (physical_id.class_code().value() == PCI_MASS_STORAGE_CLASS_ID && physical_id.subclass_code().value() == PCI_SATA_CTRL_SUBCLASS_ID && physical_id.prog_if().value() == PCI_AHCI_IF_PROGIF) { | ||||||
|                 m_controllers.append(AHCIController::initialize(address)); |                 m_controllers.append(AHCIController::initialize(address)); | ||||||
|             } |             } | ||||||
|         }); |         }); | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Liav A
						Liav A