- ARC hardware device tree passed to the kernel contains only partial descriptors...
[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
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21 #include <freeldr.h>
22
23 #define NDEBUG
24 #include <debug.h>
25
26 typedef struct _ROUTING_SLOT
27 {
28 UCHAR BusNumber;
29 UCHAR DeviceNumber;
30 UCHAR LinkA;
31 USHORT BitmapA;
32 UCHAR LinkB;
33 USHORT BitmapB;
34 UCHAR LinkC;
35 USHORT BitmapC;
36 UCHAR LinkD;
37 USHORT BitmapD;
38 UCHAR SlotNumber;
39 UCHAR Reserved;
40 } __attribute__((packed)) ROUTING_SLOT, *PROUTING_SLOT;
41
42 typedef struct _PCI_IRQ_ROUTING_TABLE
43 {
44 ULONG Signature;
45 USHORT Version;
46 USHORT Size;
47 UCHAR RouterBus;
48 UCHAR RouterSlot;
49 USHORT ExclusiveIRQs;
50 ULONG CompatibleRouter;
51 ULONG MiniportData;
52 UCHAR Reserved[11];
53 UCHAR Checksum;
54 ROUTING_SLOT Slot[1];
55 } __attribute__((packed)) PCI_IRQ_ROUTING_TABLE, *PPCI_IRQ_ROUTING_TABLE;
56
57 typedef struct _PCI_REGISTRY_INFO
58 {
59 UCHAR MajorRevision;
60 UCHAR MinorRevision;
61 UCHAR NoBuses;
62 UCHAR HardwareMechanism;
63 } PCI_REGISTRY_INFO, *PPCI_REGISTRY_INFO;
64
65 static PPCI_IRQ_ROUTING_TABLE
66 GetPciIrqRoutingTable(VOID)
67 {
68 PPCI_IRQ_ROUTING_TABLE Table;
69 PUCHAR Ptr;
70 ULONG Sum;
71 ULONG i;
72
73 Table = (PPCI_IRQ_ROUTING_TABLE)0xF0000;
74 while ((ULONG)Table < 0x100000)
75 {
76 if (Table->Signature == 0x52495024)
77 {
78 DbgPrint((DPRINT_HWDETECT,
79 "Found signature\n"));
80
81 Ptr = (PUCHAR)Table;
82 Sum = 0;
83 for (i = 0; i < Table->Size; i++)
84 {
85 Sum += Ptr[i];
86 }
87
88 if ((Sum & 0xFF) != 0)
89 {
90 DbgPrint((DPRINT_HWDETECT,
91 "Invalid routing table\n"));
92 return NULL;
93 }
94
95 DbgPrint((DPRINT_HWDETECT,
96 "Valid checksum\n"));
97
98 return Table;
99 }
100
101 Table = (PPCI_IRQ_ROUTING_TABLE)((ULONG)Table + 0x10);
102 }
103
104 return NULL;
105 }
106
107
108 static BOOLEAN
109 FindPciBios(PPCI_REGISTRY_INFO BusData)
110 {
111 REGS RegsIn;
112 REGS RegsOut;
113
114 RegsIn.b.ah = 0xB1; /* Subfunction B1h */
115 RegsIn.b.al = 0x01; /* PCI BIOS present */
116
117 Int386(0x1A, &RegsIn, &RegsOut);
118
119 if (INT386_SUCCESS(RegsOut) && RegsOut.d.edx == 0x20494350 && RegsOut.b.ah == 0)
120 {
121 DbgPrint((DPRINT_HWDETECT, "Found PCI bios\n"));
122
123 DbgPrint((DPRINT_HWDETECT, "AL: %x\n", RegsOut.b.al));
124 DbgPrint((DPRINT_HWDETECT, "BH: %x\n", RegsOut.b.bh));
125 DbgPrint((DPRINT_HWDETECT, "BL: %x\n", RegsOut.b.bl));
126 DbgPrint((DPRINT_HWDETECT, "CL: %x\n", RegsOut.b.cl));
127
128 BusData->NoBuses = RegsOut.b.cl + 1;
129 BusData->MajorRevision = RegsOut.b.bh;
130 BusData->MinorRevision = RegsOut.b.bl;
131 BusData->HardwareMechanism = RegsOut.b.cl;
132
133 return TRUE;
134 }
135
136
137 DbgPrint((DPRINT_HWDETECT, "No PCI bios found\n"));
138
139 return FALSE;
140 }
141
142
143 static VOID
144 DetectPciIrqRoutingTable(PCONFIGURATION_COMPONENT_DATA BusKey)
145 {
146 PCM_PARTIAL_RESOURCE_LIST PartialResourceList;
147 PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor;
148 PPCI_IRQ_ROUTING_TABLE Table;
149 PCONFIGURATION_COMPONENT_DATA TableKey;
150 ULONG Size;
151
152 Table = GetPciIrqRoutingTable();
153 if (Table != NULL)
154 {
155 DbgPrint((DPRINT_HWDETECT, "Table size: %u\n", Table->Size));
156
157 FldrCreateComponentKey(BusKey,
158 L"RealModeIrqRoutingTable",
159 0,
160 PeripheralClass,
161 RealModeIrqRoutingTable,
162 &TableKey);
163
164 /* Set 'Component Information' */
165 FldrSetComponentInformation(TableKey,
166 0x0,
167 0x0,
168 0xFFFFFFFF);
169
170 /* Set 'Identifier' value */
171 FldrSetIdentifier(TableKey, L"PCI Real-mode IRQ Routing Table");
172
173 /* Set 'Configuration Data' value */
174 Size = FIELD_OFFSET(CM_PARTIAL_RESOURCE_LIST, PartialDescriptors) +
175 2 * sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) + Table->Size;
176 PartialResourceList = MmAllocateMemory(Size);
177 if (PartialResourceList == NULL)
178 {
179 DbgPrint((DPRINT_HWDETECT,
180 "Failed to allocate resource descriptor\n"));
181 return;
182 }
183
184 /* Initialize resource descriptor */
185 memset(PartialResourceList, 0, Size);
186 PartialResourceList->Version = 1;
187 PartialResourceList->Revision = 1;
188 PartialResourceList->Count = 2;
189
190 PartialDescriptor = &PartialResourceList->PartialDescriptors[0];
191 PartialDescriptor->Type = CmResourceTypeBusNumber;
192 PartialDescriptor->ShareDisposition = CmResourceShareDeviceExclusive;
193 PartialDescriptor->u.BusNumber.Start = 0;
194 PartialDescriptor->u.BusNumber.Length = 1;
195
196 PartialDescriptor = &PartialResourceList->PartialDescriptors[1];
197 PartialDescriptor->Type = CmResourceTypeDeviceSpecific;
198 PartialDescriptor->ShareDisposition = CmResourceShareUndetermined;
199 PartialDescriptor->u.DeviceSpecificData.DataSize = Table->Size;
200
201 memcpy(&PartialResourceList->PartialDescriptors[2],
202 Table, Table->Size);
203
204 /* Set 'Configuration Data' value */
205 FldrSetConfigurationData(TableKey, PartialResourceList, Size);
206 MmFreeMemory(PartialResourceList);
207 }
208 }
209
210
211 VOID
212 DetectPciBios(PCONFIGURATION_COMPONENT_DATA SystemKey, ULONG *BusNumber)
213 {
214 PCM_PARTIAL_RESOURCE_LIST PartialResourceList;
215 PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor;
216 PCI_REGISTRY_INFO BusData;
217 PCONFIGURATION_COMPONENT_DATA BiosKey;
218 ULONG Size;
219 PCONFIGURATION_COMPONENT_DATA BusKey;
220 ULONG i;
221 WCHAR szPci[] = L"PCI";
222
223 /* Report the PCI BIOS */
224 if (FindPciBios(&BusData))
225 {
226 /* Create new bus key */
227 FldrCreateComponentKey(SystemKey,
228 L"MultifunctionAdapter",
229 *BusNumber,
230 AdapterClass,
231 MultiFunctionAdapter,
232 &BiosKey);
233
234 /* Set 'Component Information' */
235 FldrSetComponentInformation(BiosKey,
236 0x0,
237 0x0,
238 0xFFFFFFFF);
239
240 /* Increment bus number */
241 (*BusNumber)++;
242
243 /* Set 'Identifier' value */
244 FldrSetIdentifier(BiosKey, L"PCI BIOS");
245
246 /* Set 'Configuration Data' value */
247 Size = FIELD_OFFSET(CM_PARTIAL_RESOURCE_LIST,
248 PartialDescriptors);
249 PartialResourceList = MmAllocateMemory(Size);
250 if (PartialResourceList == NULL)
251 {
252 DbgPrint((DPRINT_HWDETECT,
253 "Failed to allocate resource descriptor\n"));
254 return;
255 }
256
257 /* Initialize resource descriptor */
258 memset(PartialResourceList, 0, Size);
259
260 /* Set 'Configuration Data' value */
261 FldrSetConfigurationData(BiosKey, PartialResourceList, Size);
262 MmFreeMemory(PartialResourceList);
263
264 DetectPciIrqRoutingTable(BiosKey);
265
266 /* Report PCI buses */
267 for (i = 0; i < (ULONG)BusData.NoBuses; i++)
268 {
269 /* Create the bus key */
270 FldrCreateComponentKey(SystemKey,
271 L"MultifunctionAdapter",
272 *BusNumber,
273 AdapterClass,
274 MultiFunctionAdapter,
275 &BusKey);
276
277 /* Set 'Component Information' */
278 FldrSetComponentInformation(BusKey,
279 0x0,
280 0x0,
281 0xFFFFFFFF);
282
283 /* Check if this is the first bus */
284 if (i == 0)
285 {
286 /* Set 'Configuration Data' value */
287 Size = FIELD_OFFSET(CM_PARTIAL_RESOURCE_LIST,
288 PartialDescriptors) +
289 sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) +
290 sizeof(PCI_REGISTRY_INFO);
291 PartialResourceList = MmAllocateMemory(Size);
292 if (!PartialResourceList)
293 {
294 DbgPrint((DPRINT_HWDETECT,
295 "Failed to allocate resource descriptor\n"));
296 return;
297 }
298
299 /* Initialize resource descriptor */
300 memset(PartialResourceList, 0, Size);
301 PartialResourceList->Version = 1;
302 PartialResourceList->Revision = 1;
303 PartialResourceList->Count = 1;
304 PartialDescriptor = &PartialResourceList->PartialDescriptors[0];
305 PartialDescriptor->Type = CmResourceTypeDeviceSpecific;
306 PartialDescriptor->ShareDisposition = CmResourceShareUndetermined;
307 PartialDescriptor->u.DeviceSpecificData.DataSize = sizeof(PCI_REGISTRY_INFO);
308 memcpy(&PartialResourceList->PartialDescriptors[1],
309 &BusData,
310 sizeof(PCI_REGISTRY_INFO));
311
312 /* Set 'Configuration Data' value */
313 FldrSetConfigurationData(BusKey, PartialResourceList, Size);
314 MmFreeMemory(PartialResourceList);
315 }
316 else
317 {
318 /* Set 'Configuration Data' value */
319 Size = FIELD_OFFSET(CM_PARTIAL_RESOURCE_LIST,
320 PartialDescriptors);
321 PartialResourceList = MmAllocateMemory(Size);
322 if (!PartialResourceList)
323 {
324 DbgPrint((DPRINT_HWDETECT,
325 "Failed to allocate resource descriptor\n"));
326 return;
327 }
328
329 /* Initialize resource descriptor */
330 memset(PartialResourceList, 0, Size);
331
332 /* Set 'Configuration Data' value */
333 FldrSetConfigurationData(BusKey, PartialResourceList, Size);
334 MmFreeMemory(PartialResourceList);
335 }
336
337 /* Increment bus number */
338 (*BusNumber)++;
339
340 /* Set 'Identifier' value */
341 FldrSetIdentifier(BusKey, szPci);
342 }
343 }
344 }
345
346 /* EOF */