Serenity Operating System
at portability 191 lines 5.9 kB view raw
1/* 2 * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright notice, this 9 * list of conditions and the following disclaimer. 10 * 11 * 2. Redistributions in binary form must reproduce the above copyright notice, 12 * this list of conditions and the following disclaimer in the documentation 13 * and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 22 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27#include <Kernel/PCI/Access.h> 28#include <Kernel/PCI/IOAccess.h> 29 30namespace Kernel { 31 32static PCI::Access* s_access; 33 34PCI::Access& PCI::Access::the() 35{ 36 if (s_access == nullptr) { 37 ASSERT_NOT_REACHED(); // We failed to initialize the PCI subsystem, so stop here! 38 } 39 return *s_access; 40} 41 42bool PCI::Access::is_initialized() 43{ 44 return (s_access != nullptr); 45} 46 47PCI::Access::Access() 48{ 49 s_access = this; 50} 51 52void PCI::Access::enumerate_functions(int type, u8 bus, u8 slot, u8 function, Function<void(Address, ID)>& callback) 53{ 54 Address address(0, bus, slot, function); 55 if (type == -1 || type == read_type(address)) 56 callback(address, { read16_field(address, PCI_VENDOR_ID), read16_field(address, PCI_DEVICE_ID) }); 57 if (read_type(address) == PCI_TYPE_BRIDGE) { 58 u8 secondary_bus = read8_field(address, PCI_SECONDARY_BUS); 59#ifdef PCI_DEBUG 60 kprintf("PCI: Found secondary bus: %u\n", secondary_bus); 61#endif 62 ASSERT(secondary_bus != bus); 63 enumerate_bus(type, secondary_bus, callback); 64 } 65} 66 67void PCI::Access::enumerate_slot(int type, u8 bus, u8 slot, Function<void(Address, ID)>& callback) 68{ 69 Address address(0, bus, slot, 0); 70 if (read16_field(address, PCI_VENDOR_ID) == PCI_NONE) 71 return; 72 enumerate_functions(type, bus, slot, 0, callback); 73 if (!(read8_field(address, PCI_HEADER_TYPE) & 0x80)) 74 return; 75 for (u8 function = 1; function < 8; ++function) { 76 Address address(0, bus, slot, function); 77 if (read16_field(address, PCI_VENDOR_ID) != PCI_NONE) 78 enumerate_functions(type, bus, slot, function, callback); 79 } 80} 81 82PCI::ID PCI::Access::get_id(Address address) 83{ 84 return { read16_field(address, PCI_VENDOR_ID), read16_field(address, PCI_DEVICE_ID) }; 85} 86 87void PCI::Access::enumerate_bus(int type, u8 bus, Function<void(Address, ID)>& callback) 88{ 89 for (u8 slot = 0; slot < 32; ++slot) 90 enumerate_slot(type, bus, slot, callback); 91} 92 93void PCI::Access::enable_bus_mastering(Address address) 94{ 95 auto value = read16_field(address, PCI_COMMAND); 96 value |= (1 << 2); 97 value |= (1 << 0); 98 write16_field(address, PCI_COMMAND, value); 99} 100 101void PCI::Access::disable_bus_mastering(Address address) 102{ 103 auto value = read16_field(address, PCI_COMMAND); 104 value &= ~(1 << 2); 105 value |= (1 << 0); 106 write16_field(address, PCI_COMMAND, value); 107} 108 109namespace PCI { 110 void enumerate_all(Function<void(Address, ID)> callback) 111 { 112 PCI::Access::the().enumerate_all(callback); 113 } 114 115 ID get_id(Address address) 116 { 117 return PCI::Access::the().get_id(address); 118 } 119 120 void enable_interrupt_line(Address address) 121 { 122 PCI::Access::the().enable_interrupt_line(address); 123 } 124 void disable_interrupt_line(Address address) 125 { 126 PCI::Access::the().disable_interrupt_line(address); 127 } 128 129 u8 get_interrupt_line(Address address) 130 { 131 return PCI::Access::the().get_interrupt_line(address); 132 } 133 u32 get_BAR0(Address address) 134 { 135 return PCI::Access::the().get_BAR0(address); 136 } 137 u32 get_BAR1(Address address) 138 { 139 return PCI::Access::the().get_BAR1(address); 140 } 141 u32 get_BAR2(Address address) 142 { 143 return PCI::Access::the().get_BAR2(address); 144 } 145 u32 get_BAR3(Address address) 146 { 147 return PCI::Access::the().get_BAR3(address); 148 } 149 u32 get_BAR4(Address address) 150 { 151 return PCI::Access::the().get_BAR4(address); 152 } 153 u32 get_BAR5(Address address) 154 { 155 return PCI::Access::the().get_BAR5(address); 156 } 157 u8 get_revision_id(Address address) 158 { 159 return PCI::Access::the().get_revision_id(address); 160 } 161 u8 get_subclass(Address address) 162 { 163 return PCI::Access::the().get_subclass(address); 164 } 165 u8 get_class(Address address) 166 { 167 return PCI::Access::the().get_class(address); 168 } 169 u16 get_subsystem_id(Address address) 170 { 171 return PCI::Access::the().get_subsystem_id(address); 172 } 173 u16 get_subsystem_vendor_id(Address address) 174 { 175 return PCI::Access::the().get_subsystem_vendor_id(address); 176 } 177 void enable_bus_mastering(Address address) 178 { 179 PCI::Access::the().enable_bus_mastering(address); 180 } 181 void disable_bus_mastering(Address address) 182 { 183 PCI::Access::the().disable_bus_mastering(address); 184 } 185 size_t get_BAR_Space_Size(Address address, u8 bar_number) 186 { 187 return PCI::Access::the().get_BAR_Space_Size(address, bar_number); 188 } 189} 190 191}