Serenity Operating System
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}