[FREELDR]
[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 DBG_DEFAULT_CHANNEL(HWDETECT);
27
28 static
29 PPCI_IRQ_ROUTING_TABLE
30 GetPciIrqRoutingTable(VOID)
31 {
32 PPCI_IRQ_ROUTING_TABLE Table;
33 PUCHAR Ptr;
34 ULONG Sum;
35 ULONG i;
36
37 Table = (PPCI_IRQ_ROUTING_TABLE)0xF0000;
38 while ((ULONG_PTR)Table < 0x100000)
39 {
40 if (Table->Signature == 'RIP$')
41 {
42 TRACE("Found signature\n");
43
44 if (Table->TableSize < FIELD_OFFSET(PCI_IRQ_ROUTING_TABLE, Slot) ||
45 Table->TableSize % 16 != 0)
46 {
47 ERR("Invalid routing table size (%u) at %p. Continue searching...\n", Table->TableSize, Table);
48 Table = (PPCI_IRQ_ROUTING_TABLE)((ULONG_PTR)Table + 0x10);
49 continue;
50 }
51
52 Ptr = (PUCHAR)Table;
53 Sum = 0;
54 for (i = 0; i < Table->TableSize; i++)
55 {
56 Sum += Ptr[i];
57 }
58
59 if ((Sum & 0xFF) != 0)
60 {
61 ERR("Invalid routing table checksum (%#lx) at %p. Continue searching...\n", Sum & 0xFF, Table);
62 }
63 else
64 {
65 TRACE("Valid checksum\n");
66 return Table;
67 }
68 }
69
70 Table = (PPCI_IRQ_ROUTING_TABLE)((ULONG_PTR)Table + 0x10);
71 }
72
73 ERR("No valid routing table found!\n");
74
75 return NULL;
76 }
77
78
79 static BOOLEAN
80 FindPciBios(PPCI_REGISTRY_INFO BusData)
81 {
82 REGS RegsIn;
83 REGS RegsOut;
84
85 RegsIn.b.ah = 0xB1; /* Subfunction B1h */
86 RegsIn.b.al = 0x01; /* PCI BIOS present */
87
88 Int386(0x1A, &RegsIn, &RegsOut);
89
90 if (INT386_SUCCESS(RegsOut) &&
91 (RegsOut.d.edx == 0x20494350) &&
92 (RegsOut.b.ah == 0))
93 {
94 TRACE("Found PCI bios\n");
95
96 TRACE("AL: %x\n", RegsOut.b.al);
97 TRACE("BH: %x\n", RegsOut.b.bh);
98 TRACE("BL: %x\n", RegsOut.b.bl);
99 TRACE("CL: %x\n", RegsOut.b.cl);
100
101 BusData->NoBuses = RegsOut.b.cl + 1;
102 BusData->MajorRevision = RegsOut.b.bh;
103 BusData->MinorRevision = RegsOut.b.bl;
104 BusData->HardwareMechanism = RegsOut.b.al;
105
106 return TRUE;
107 }
108
109 TRACE("No PCI bios found\n");
110
111 return FALSE;
112 }
113
114
115 static
116 VOID
117 DetectPciIrqRoutingTable(PCONFIGURATION_COMPONENT_DATA BusKey)
118 {
119 PCM_PARTIAL_RESOURCE_LIST PartialResourceList;
120 PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor;
121 PPCI_IRQ_ROUTING_TABLE Table;
122 PCONFIGURATION_COMPONENT_DATA TableKey;
123 ULONG Size;
124
125 Table = GetPciIrqRoutingTable();
126 if (Table != NULL)
127 {
128 TRACE("Table size: %u\n", Table->TableSize);
129
130 /* Set 'Configuration Data' value */
131 Size = FIELD_OFFSET(CM_PARTIAL_RESOURCE_LIST, PartialDescriptors) +
132 2 * sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) + Table->TableSize;
133 PartialResourceList = FrLdrHeapAlloc(Size, TAG_HW_RESOURCE_LIST);
134 if (PartialResourceList == NULL)
135 {
136 ERR("Failed to allocate resource descriptor\n");
137 return;
138 }
139
140 /* Initialize resource descriptor */
141 memset(PartialResourceList, 0, Size);
142 PartialResourceList->Version = 1;
143 PartialResourceList->Revision = 1;
144 PartialResourceList->Count = 2;
145
146 PartialDescriptor = &PartialResourceList->PartialDescriptors[0];
147 PartialDescriptor->Type = CmResourceTypeBusNumber;
148 PartialDescriptor->ShareDisposition = CmResourceShareDeviceExclusive;
149 PartialDescriptor->u.BusNumber.Start = 0;
150 PartialDescriptor->u.BusNumber.Length = 1;
151
152 PartialDescriptor = &PartialResourceList->PartialDescriptors[1];
153 PartialDescriptor->Type = CmResourceTypeDeviceSpecific;
154 PartialDescriptor->ShareDisposition = CmResourceShareUndetermined;
155 PartialDescriptor->u.DeviceSpecificData.DataSize = Table->TableSize;
156
157 memcpy(&PartialResourceList->PartialDescriptors[2],
158 Table,
159 Table->TableSize);
160
161 FldrCreateComponentKey(BusKey,
162 PeripheralClass,
163 RealModeIrqRoutingTable,
164 0x0,
165 0x0,
166 0xFFFFFFFF,
167 "PCI Real-mode IRQ Routing Table",
168 PartialResourceList,
169 Size,
170 &TableKey);
171 }
172 }
173
174
175 VOID
176 DetectPciBios(PCONFIGURATION_COMPONENT_DATA SystemKey, ULONG *BusNumber)
177 {
178 PCM_PARTIAL_RESOURCE_LIST PartialResourceList;
179 PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor;
180 PCI_REGISTRY_INFO BusData;
181 PCONFIGURATION_COMPONENT_DATA BiosKey;
182 ULONG Size;
183 PCONFIGURATION_COMPONENT_DATA BusKey;
184 ULONG i;
185
186 /* Report the PCI BIOS */
187 if (FindPciBios(&BusData))
188 {
189 /* Set 'Configuration Data' value */
190 Size = FIELD_OFFSET(CM_PARTIAL_RESOURCE_LIST, PartialDescriptors);
191 PartialResourceList = FrLdrHeapAlloc(Size, TAG_HW_RESOURCE_LIST);
192 if (PartialResourceList == NULL)
193 {
194 ERR("Failed to allocate resource descriptor\n");
195 return;
196 }
197
198 /* Initialize resource descriptor */
199 memset(PartialResourceList, 0, Size);
200
201 /* Create new bus key */
202 FldrCreateComponentKey(SystemKey,
203 AdapterClass,
204 MultiFunctionAdapter,
205 0x0,
206 0x0,
207 0xFFFFFFFF,
208 "PCI BIOS",
209 PartialResourceList,
210 Size,
211 &BiosKey);
212
213 /* Increment bus number */
214 (*BusNumber)++;
215
216 DetectPciIrqRoutingTable(BiosKey);
217
218 /* Report PCI buses */
219 for (i = 0; i < (ULONG)BusData.NoBuses; i++)
220 {
221 /* Check if this is the first bus */
222 if (i == 0)
223 {
224 /* Set 'Configuration Data' value */
225 Size = FIELD_OFFSET(CM_PARTIAL_RESOURCE_LIST,
226 PartialDescriptors) +
227 sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) +
228 sizeof(PCI_REGISTRY_INFO);
229 PartialResourceList = FrLdrHeapAlloc(Size, TAG_HW_RESOURCE_LIST);
230 if (!PartialResourceList)
231 {
232 ERR("Failed to allocate resource descriptor\n");
233 return;
234 }
235
236 /* Initialize resource descriptor */
237 memset(PartialResourceList, 0, Size);
238 PartialResourceList->Version = 1;
239 PartialResourceList->Revision = 1;
240 PartialResourceList->Count = 1;
241 PartialDescriptor = &PartialResourceList->PartialDescriptors[0];
242 PartialDescriptor->Type = CmResourceTypeDeviceSpecific;
243 PartialDescriptor->ShareDisposition = CmResourceShareUndetermined;
244 PartialDescriptor->u.DeviceSpecificData.DataSize = sizeof(PCI_REGISTRY_INFO);
245 memcpy(&PartialResourceList->PartialDescriptors[1],
246 &BusData,
247 sizeof(PCI_REGISTRY_INFO));
248 }
249 else
250 {
251 /* Set 'Configuration Data' value */
252 Size = FIELD_OFFSET(CM_PARTIAL_RESOURCE_LIST,
253 PartialDescriptors);
254 PartialResourceList = FrLdrHeapAlloc(Size, TAG_HW_RESOURCE_LIST);
255 if (!PartialResourceList)
256 {
257 ERR("Failed to allocate resource descriptor\n");
258 return;
259 }
260
261 /* Initialize resource descriptor */
262 memset(PartialResourceList, 0, Size);
263 }
264
265 /* Create the bus key */
266 FldrCreateComponentKey(SystemKey,
267 AdapterClass,
268 MultiFunctionAdapter,
269 0x0,
270 0x0,
271 0xFFFFFFFF,
272 "PCI",
273 PartialResourceList,
274 Size,
275 &BusKey);
276
277 /* Increment bus number */
278 (*BusNumber)++;
279 }
280 }
281 }
282
283 /* EOF */