611bb10b6c2dc4d4747d79bf1f86fc6906e136ac
[reactos.git] / reactos / boot / freeldr / freeldr / arch / i386 / hwpci.c
1 /*
2 * FreeLoader
3 *
4 * Copyright (C) 2004 Eric Kohl
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 */
20
21 #include <freeldr.h>
22
23 #define NDEBUG
24 #include <debug.h>
25
26 #include <pshpack1.h>
27
28 typedef struct _ROUTING_SLOT
29 {
30 UCHAR BusNumber;
31 UCHAR DeviceNumber;
32 UCHAR LinkA;
33 USHORT BitmapA;
34 UCHAR LinkB;
35 USHORT BitmapB;
36 UCHAR LinkC;
37 USHORT BitmapC;
38 UCHAR LinkD;
39 USHORT BitmapD;
40 UCHAR SlotNumber;
41 UCHAR Reserved;
42 } ROUTING_SLOT, *PROUTING_SLOT;
43
44 typedef struct _PCI_IRQ_ROUTING_TABLE
45 {
46 ULONG Signature;
47 USHORT Version;
48 USHORT Size;
49 UCHAR RouterBus;
50 UCHAR RouterSlot;
51 USHORT ExclusiveIRQs;
52 ULONG CompatibleRouter;
53 ULONG MiniportData;
54 UCHAR Reserved[11];
55 UCHAR Checksum;
56 ROUTING_SLOT Slot[1];
57 } PCI_IRQ_ROUTING_TABLE, *PPCI_IRQ_ROUTING_TABLE;
58
59 #include <poppack.h>
60
61 typedef struct _PCI_REGISTRY_INFO
62 {
63 UCHAR MajorRevision;
64 UCHAR MinorRevision;
65 UCHAR NoBuses;
66 UCHAR HardwareMechanism;
67 } PCI_REGISTRY_INFO, *PPCI_REGISTRY_INFO;
68
69 static PPCI_IRQ_ROUTING_TABLE
70 GetPciIrqRoutingTable(VOID)
71 {
72 PPCI_IRQ_ROUTING_TABLE Table;
73 PUCHAR Ptr;
74 ULONG Sum;
75 ULONG i;
76
77 Table = (PPCI_IRQ_ROUTING_TABLE)0xF0000;
78 while ((ULONG_PTR)Table < 0x100000)
79 {
80 if (Table->Signature == 0x52495024)
81 {
82 DPRINTM(DPRINT_HWDETECT,
83 "Found signature\n");
84
85 Ptr = (PUCHAR)Table;
86 Sum = 0;
87 for (i = 0; i < Table->Size; i++)
88 {
89 Sum += Ptr[i];
90 }
91
92 if ((Sum & 0xFF) != 0)
93 {
94 DPRINTM(DPRINT_HWDETECT,
95 "Invalid routing table\n");
96 return NULL;
97 }
98
99 DPRINTM(DPRINT_HWDETECT,
100 "Valid checksum\n");
101
102 return Table;
103 }
104
105 Table = (PPCI_IRQ_ROUTING_TABLE)((ULONG_PTR)Table + 0x10);
106 }
107
108 return NULL;
109 }
110
111
112 static BOOLEAN
113 FindPciBios(PPCI_REGISTRY_INFO BusData)
114 {
115 REGS RegsIn;
116 REGS RegsOut;
117
118 RegsIn.b.ah = 0xB1; /* Subfunction B1h */
119 RegsIn.b.al = 0x01; /* PCI BIOS present */
120
121 Int386(0x1A, &RegsIn, &RegsOut);
122
123 if (INT386_SUCCESS(RegsOut) && RegsOut.d.edx == 0x20494350 && RegsOut.b.ah == 0)
124 {
125 DPRINTM(DPRINT_HWDETECT, "Found PCI bios\n");
126
127 DPRINTM(DPRINT_HWDETECT, "AL: %x\n", RegsOut.b.al);
128 DPRINTM(DPRINT_HWDETECT, "BH: %x\n", RegsOut.b.bh);
129 DPRINTM(DPRINT_HWDETECT, "BL: %x\n", RegsOut.b.bl);
130 DPRINTM(DPRINT_HWDETECT, "CL: %x\n", RegsOut.b.cl);
131
132 BusData->NoBuses = RegsOut.b.cl + 1;
133 BusData->MajorRevision = RegsOut.b.bh;
134 BusData->MinorRevision = RegsOut.b.bl;
135 BusData->HardwareMechanism = RegsOut.b.al;
136
137 return TRUE;
138 }
139
140
141 DPRINTM(DPRINT_HWDETECT, "No PCI bios found\n");
142
143 return FALSE;
144 }
145
146
147 static VOID
148 DetectPciIrqRoutingTable(PCONFIGURATION_COMPONENT_DATA BusKey)
149 {
150 PCM_PARTIAL_RESOURCE_LIST PartialResourceList;
151 PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor;
152 PPCI_IRQ_ROUTING_TABLE Table;
153 PCONFIGURATION_COMPONENT_DATA TableKey;
154 ULONG Size;
155
156 Table = GetPciIrqRoutingTable();
157 if (Table != NULL)
158 {
159 DPRINTM(DPRINT_HWDETECT, "Table size: %u\n", Table->Size);
160
161 /* Set 'Configuration Data' value */
162 Size = FIELD_OFFSET(CM_PARTIAL_RESOURCE_LIST, PartialDescriptors) +
163 2 * sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) + Table->Size;
164 PartialResourceList = MmHeapAlloc(Size);
165 if (PartialResourceList == NULL)
166 {
167 DPRINTM(DPRINT_HWDETECT,
168 "Failed to allocate resource descriptor\n");
169 return;
170 }
171
172 /* Initialize resource descriptor */
173 memset(PartialResourceList, 0, Size);
174 PartialResourceList->Version = 1;
175 PartialResourceList->Revision = 1;
176 PartialResourceList->Count = 2;
177
178 PartialDescriptor = &PartialResourceList->PartialDescriptors[0];
179 PartialDescriptor->Type = CmResourceTypeBusNumber;
180 PartialDescriptor->ShareDisposition = CmResourceShareDeviceExclusive;
181 PartialDescriptor->u.BusNumber.Start = 0;
182 PartialDescriptor->u.BusNumber.Length = 1;
183
184 PartialDescriptor = &PartialResourceList->PartialDescriptors[1];
185 PartialDescriptor->Type = CmResourceTypeDeviceSpecific;
186 PartialDescriptor->ShareDisposition = CmResourceShareUndetermined;
187 PartialDescriptor->u.DeviceSpecificData.DataSize = Table->Size;
188
189 memcpy(&PartialResourceList->PartialDescriptors[2],
190 Table, Table->Size);
191
192 FldrCreateComponentKey(BusKey,
193 PeripheralClass,
194 RealModeIrqRoutingTable,
195 0x0,
196 0x0,
197 0xFFFFFFFF,
198 "PCI Real-mode IRQ Routing Table",
199 PartialResourceList,
200 Size,
201 &TableKey);
202
203 MmHeapFree(PartialResourceList);
204 }
205 }
206
207
208 VOID
209 DetectPciBios(PCONFIGURATION_COMPONENT_DATA SystemKey, ULONG *BusNumber)
210 {
211 PCM_PARTIAL_RESOURCE_LIST PartialResourceList;
212 PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor;
213 PCI_REGISTRY_INFO BusData;
214 PCONFIGURATION_COMPONENT_DATA BiosKey;
215 ULONG Size;
216 PCONFIGURATION_COMPONENT_DATA BusKey;
217 ULONG i;
218
219 /* Report the PCI BIOS */
220 if (FindPciBios(&BusData))
221 {
222 /* Set 'Configuration Data' value */
223 Size = FIELD_OFFSET(CM_PARTIAL_RESOURCE_LIST,
224 PartialDescriptors);
225 PartialResourceList = MmHeapAlloc(Size);
226 if (PartialResourceList == NULL)
227 {
228 DPRINTM(DPRINT_HWDETECT,
229 "Failed to allocate resource descriptor\n");
230 return;
231 }
232
233 /* Initialize resource descriptor */
234 memset(PartialResourceList, 0, Size);
235
236 /* Create new bus key */
237 FldrCreateComponentKey(SystemKey,
238 AdapterClass,
239 MultiFunctionAdapter,
240 0x0,
241 0x0,
242 0xFFFFFFFF,
243 "PCI BIOS",
244 PartialResourceList,
245 Size,
246 &BiosKey);
247
248 /* Increment bus number */
249 (*BusNumber)++;
250
251 MmHeapFree(PartialResourceList);
252
253 DetectPciIrqRoutingTable(BiosKey);
254
255 /* Report PCI buses */
256 for (i = 0; i < (ULONG)BusData.NoBuses; i++)
257 {
258 /* Check if this is the first bus */
259 if (i == 0)
260 {
261 /* Set 'Configuration Data' value */
262 Size = FIELD_OFFSET(CM_PARTIAL_RESOURCE_LIST,
263 PartialDescriptors) +
264 sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) +
265 sizeof(PCI_REGISTRY_INFO);
266 PartialResourceList = MmHeapAlloc(Size);
267 if (!PartialResourceList)
268 {
269 DPRINTM(DPRINT_HWDETECT,
270 "Failed to allocate resource descriptor\n");
271 return;
272 }
273
274 /* Initialize resource descriptor */
275 memset(PartialResourceList, 0, Size);
276 PartialResourceList->Version = 1;
277 PartialResourceList->Revision = 1;
278 PartialResourceList->Count = 1;
279 PartialDescriptor = &PartialResourceList->PartialDescriptors[0];
280 PartialDescriptor->Type = CmResourceTypeDeviceSpecific;
281 PartialDescriptor->ShareDisposition = CmResourceShareUndetermined;
282 PartialDescriptor->u.DeviceSpecificData.DataSize = sizeof(PCI_REGISTRY_INFO);
283 memcpy(&PartialResourceList->PartialDescriptors[1],
284 &BusData,
285 sizeof(PCI_REGISTRY_INFO));
286 }
287 else
288 {
289 /* Set 'Configuration Data' value */
290 Size = FIELD_OFFSET(CM_PARTIAL_RESOURCE_LIST,
291 PartialDescriptors);
292 PartialResourceList = MmHeapAlloc(Size);
293 if (!PartialResourceList)
294 {
295 DPRINTM(DPRINT_HWDETECT,
296 "Failed to allocate resource descriptor\n");
297 return;
298 }
299
300 /* Initialize resource descriptor */
301 memset(PartialResourceList, 0, Size);
302 }
303
304 /* Create the bus key */
305 FldrCreateComponentKey(SystemKey,
306 AdapterClass,
307 MultiFunctionAdapter,
308 0x0,
309 0x0,
310 0xFFFFFFFF,
311 "PCI",
312 PartialResourceList,
313 Size,
314 &BusKey);
315
316 MmHeapFree(PartialResourceList);
317
318 /* Increment bus number */
319 (*BusNumber)++;
320 }
321 }
322 }
323
324 /* EOF */