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