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