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