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