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