1 /*
2 * PROJECT: ReactOS HAL
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: hal/halx86/legacy/bus/bushndlr.c
5 * PURPOSE: Generic HAL Bus Handler Support
6 * PROGRAMMERS: Stefan Ginsberg (stefan.ginsberg@reactos.org)
7 */
8
9 /* INCLUDES *******************************************************************/
10
11 #include <hal.h>
12 #define NDEBUG
13 #include <debug.h>
14
15 /* GLOBALS ********************************************************************/
16
17 KSPIN_LOCK HalpBusDatabaseSpinLock;
18 KEVENT HalpBusDatabaseEvent;
19 LIST_ENTRY HalpAllBusHandlers;
20 PARRAY HalpBusTable;
21 PARRAY HalpConfigTable;
22
23 /* PRIVATE FUNCTIONS **********************************************************/
24
25 PARRAY
26 NTAPI
HalpAllocateArray(IN ULONG ArraySize)27 HalpAllocateArray(IN ULONG ArraySize)
28 {
29 PARRAY Array;
30 ULONG Size;
31
32 /* Compute array size */
33 if (ArraySize == MAXULONG) ArraySize = 0;
34 Size = ArraySize * sizeof(PARRAY) + sizeof(ARRAY);
35
36 /* Allocate the array */
37 Array = ExAllocatePoolWithTag(NonPagedPool,
38 Size,
39 TAG_BUS_HANDLER);
40 if (!Array) KeBugCheckEx(HAL_MEMORY_ALLOCATION, Size, 0, (ULONG_PTR)__FILE__, __LINE__);
41
42 /* Initialize it */
43 Array->ArraySize = ArraySize;
44 RtlZeroMemory(Array->Element, sizeof(PVOID) * (ArraySize + 1));
45 return Array;
46 }
47
48 VOID
49 NTAPI
HalpGrowArray(IN PARRAY * CurrentArray,IN PARRAY * NewArray)50 HalpGrowArray(IN PARRAY *CurrentArray,
51 IN PARRAY *NewArray)
52 {
53 PVOID Tmp;
54
55 /* Check if the current array doesn't exist yet, or if it's smaller than the new one */
56 if (!(*CurrentArray) || ((*NewArray)->ArraySize > (*CurrentArray)->ArraySize))
57 {
58 /* Does it exist (and can it fit?) */
59 if (*CurrentArray)
60 {
61 /* Copy the current array into the new one */
62 RtlCopyMemory(&(*NewArray)->Element,
63 &(*CurrentArray)->Element,
64 sizeof(PVOID) * ((*CurrentArray)->ArraySize + 1));
65 }
66
67 /* Swap the pointers (XOR swap would be more l33t) */
68 Tmp = *CurrentArray;
69 *CurrentArray = *NewArray;
70 *NewArray = Tmp;
71 }
72 }
73
74 PBUS_HANDLER
75 FASTCALL
HalpLookupHandler(IN PARRAY Array,IN ULONG Type,IN ULONG Number,IN BOOLEAN AddReference)76 HalpLookupHandler(IN PARRAY Array,
77 IN ULONG Type,
78 IN ULONG Number,
79 IN BOOLEAN AddReference)
80 {
81 PHAL_BUS_HANDLER Bus;
82 PBUS_HANDLER Handler = NULL;
83
84 /* Make sure the entry exists */
85 if (Array->ArraySize >= Type)
86 {
87 /* Retrieve it */
88 Array = Array->Element[Type];
89
90 /* Make sure the entry array exists */
91 if ((Array) && (Array->ArraySize >= Number))
92 {
93 /* Retrieve the bus and its handler */
94 Bus = Array->Element[Number];
95 Handler = &Bus->Handler;
96
97 /* Reference the handler if needed */
98 if (AddReference) Bus->ReferenceCount++;
99 }
100 }
101
102 /* Return the handler */
103 return Handler;
104 }
105
106 /**
107 * @brief Handler for buses without configuration space.
108 **/
109 ULONG
110 NTAPI
HalpNoBusData(_In_ PBUS_HANDLER BusHandler,_In_ PBUS_HANDLER RootHandler,_In_ ULONG SlotNumber,_In_ PVOID Buffer,_In_ ULONG Offset,_In_ ULONG Length)111 HalpNoBusData(
112 _In_ PBUS_HANDLER BusHandler,
113 _In_ PBUS_HANDLER RootHandler,
114 _In_ ULONG SlotNumber,
115 _In_ PVOID Buffer,
116 _In_ ULONG Offset,
117 _In_ ULONG Length)
118 {
119 DPRINT1("STUB GetSetBusData(Bus %x:%x.%x)\n",
120 BusHandler->InterfaceType,
121 BusHandler->ConfigurationType,
122 BusHandler->BusNumber);
123
124 /* Just return a dummy value */
125 return 0;
126 }
127
128 /**
129 * @brief Handler for buses without configuration space.
130 **/
131 NTSTATUS
132 NTAPI
HalpNoAdjustResourceList(_In_ PBUS_HANDLER BusHandler,_In_ PBUS_HANDLER RootHandler,_Inout_ PIO_RESOURCE_REQUIREMENTS_LIST * pResourceList)133 HalpNoAdjustResourceList(
134 _In_ PBUS_HANDLER BusHandler,
135 _In_ PBUS_HANDLER RootHandler,
136 _Inout_ PIO_RESOURCE_REQUIREMENTS_LIST* pResourceList)
137 {
138 DPRINT1("STUB Adjustment(Bus %x:%x.%x)\n",
139 BusHandler->InterfaceType,
140 BusHandler->ConfigurationType,
141 BusHandler->BusNumber);
142
143 return STATUS_UNSUCCESSFUL;
144 }
145
146 /**
147 * @brief Handler for buses without configuration space.
148 **/
149 NTSTATUS
150 NTAPI
HalpNoAssignSlotResources(_In_ PBUS_HANDLER BusHandler,_In_ PBUS_HANDLER RootHandler,_In_ PUNICODE_STRING RegistryPath,_In_opt_ PUNICODE_STRING DriverClassName,_In_ PDRIVER_OBJECT DriverObject,_In_opt_ PDEVICE_OBJECT DeviceObject,_In_ ULONG SlotNumber,_Inout_ PCM_RESOURCE_LIST * AllocatedResources)151 HalpNoAssignSlotResources(
152 _In_ PBUS_HANDLER BusHandler,
153 _In_ PBUS_HANDLER RootHandler,
154 _In_ PUNICODE_STRING RegistryPath,
155 _In_opt_ PUNICODE_STRING DriverClassName,
156 _In_ PDRIVER_OBJECT DriverObject,
157 _In_opt_ PDEVICE_OBJECT DeviceObject,
158 _In_ ULONG SlotNumber,
159 _Inout_ PCM_RESOURCE_LIST* AllocatedResources)
160 {
161 DPRINT1("STUB Assignment(Bus %x:%x.%x)\n",
162 BusHandler->InterfaceType,
163 BusHandler->ConfigurationType,
164 BusHandler->BusNumber);
165
166 return STATUS_NOT_SUPPORTED;
167 }
168
169 VOID
170 FASTCALL
HaliReferenceBusHandler(IN PBUS_HANDLER Handler)171 HaliReferenceBusHandler(IN PBUS_HANDLER Handler)
172 {
173 PHAL_BUS_HANDLER Bus;
174
175 /* Find and reference the bus handler */
176 Bus = CONTAINING_RECORD(Handler, HAL_BUS_HANDLER, Handler);
177 Bus->ReferenceCount++;
178 }
179
180 VOID
181 FASTCALL
HaliDereferenceBusHandler(IN PBUS_HANDLER Handler)182 HaliDereferenceBusHandler(IN PBUS_HANDLER Handler)
183 {
184 PHAL_BUS_HANDLER Bus;
185
186 /* Find and dereference the bus handler */
187 Bus = CONTAINING_RECORD(Handler, HAL_BUS_HANDLER, Handler);
188 Bus->ReferenceCount--;
189 ASSERT(Bus->ReferenceCount != 0);
190 }
191
192 PBUS_HANDLER
193 FASTCALL
HaliHandlerForBus(IN INTERFACE_TYPE InterfaceType,IN ULONG BusNumber)194 HaliHandlerForBus(IN INTERFACE_TYPE InterfaceType,
195 IN ULONG BusNumber)
196 {
197 /* Lookup the interface in the bus table */
198 return HalpLookupHandler(HalpBusTable, InterfaceType, BusNumber, FALSE);
199 }
200
201 PBUS_HANDLER
202 FASTCALL
HaliHandlerForConfigSpace(IN BUS_DATA_TYPE ConfigType,IN ULONG BusNumber)203 HaliHandlerForConfigSpace(IN BUS_DATA_TYPE ConfigType,
204 IN ULONG BusNumber)
205 {
206 /* Lookup the configuration in the configuration table */
207 return HalpLookupHandler(HalpConfigTable, ConfigType, BusNumber, FALSE);
208 }
209
210 PBUS_HANDLER
211 FASTCALL
HaliReferenceHandlerForBus(IN INTERFACE_TYPE InterfaceType,IN ULONG BusNumber)212 HaliReferenceHandlerForBus(IN INTERFACE_TYPE InterfaceType,
213 IN ULONG BusNumber)
214 {
215 /* Lookup the interface in the bus table, and reference the handler */
216 return HalpLookupHandler(HalpBusTable, InterfaceType, BusNumber, TRUE);
217 }
218
219 PBUS_HANDLER
220 FASTCALL
HaliReferenceHandlerForConfigSpace(IN BUS_DATA_TYPE ConfigType,IN ULONG BusNumber)221 HaliReferenceHandlerForConfigSpace(IN BUS_DATA_TYPE ConfigType,
222 IN ULONG BusNumber)
223 {
224 /* Lookup the configuration in the configuration table and add a reference */
225 return HalpLookupHandler(HalpConfigTable, ConfigType, BusNumber, TRUE);
226 }
227
228 PBUS_HANDLER
229 NTAPI
HalpContextToBusHandler(IN ULONG_PTR ContextValue)230 HalpContextToBusHandler(IN ULONG_PTR ContextValue)
231 {
232 PLIST_ENTRY NextEntry;
233 PHAL_BUS_HANDLER BusHandler, ThisHandler;
234
235 /* Start lookup */
236 NextEntry = HalpAllBusHandlers.Flink;
237 ThisHandler = CONTAINING_RECORD(NextEntry, HAL_BUS_HANDLER, AllHandlers);
238 if (ContextValue)
239 {
240 /* If the list is empty, quit */
241 if (IsListEmpty(&HalpAllBusHandlers)) return NULL;
242
243 /* Otherwise, scan the list */
244 BusHandler = CONTAINING_RECORD(ContextValue, HAL_BUS_HANDLER, Handler);
245 do
246 {
247 /* Check if we've reached the right one */
248 ThisHandler = CONTAINING_RECORD(NextEntry, HAL_BUS_HANDLER, AllHandlers);
249 if (ThisHandler == BusHandler) break;
250
251 /* Try the next one */
252 NextEntry = NextEntry->Flink;
253 } while (NextEntry != &HalpAllBusHandlers);
254 }
255
256 /* If we looped back to the end, we didn't find anything */
257 if (NextEntry == &HalpAllBusHandlers) return NULL;
258
259 /* Otherwise return the handler */
260 return &ThisHandler->Handler;
261 }
262
263 #ifndef _MINIHAL_
264 NTSTATUS
265 NTAPI
HaliRegisterBusHandler(IN INTERFACE_TYPE InterfaceType,IN BUS_DATA_TYPE ConfigType,IN ULONG BusNumber,IN INTERFACE_TYPE ParentBusType,IN ULONG ParentBusNumber,IN ULONG ExtraData,IN PINSTALL_BUS_HANDLER InstallCallback,OUT PBUS_HANDLER * ReturnedBusHandler)266 HaliRegisterBusHandler(IN INTERFACE_TYPE InterfaceType,
267 IN BUS_DATA_TYPE ConfigType,
268 IN ULONG BusNumber,
269 IN INTERFACE_TYPE ParentBusType,
270 IN ULONG ParentBusNumber,
271 IN ULONG ExtraData,
272 IN PINSTALL_BUS_HANDLER InstallCallback,
273 OUT PBUS_HANDLER *ReturnedBusHandler)
274 {
275 PHAL_BUS_HANDLER Bus, OldHandler = NULL;
276 PHAL_BUS_HANDLER* BusEntry;
277 //PVOID CodeHandle;
278 PARRAY InterfaceArray, InterfaceBusNumberArray, ConfigArray, ConfigBusNumberArray;
279 PBUS_HANDLER ParentHandler;
280 KIRQL OldIrql;
281 NTSTATUS Status;
282
283 /* Make sure we have a valid handler */
284 ASSERT((InterfaceType != InterfaceTypeUndefined) ||
285 (ConfigType != ConfigurationSpaceUndefined));
286
287 /* Allocate the bus handler */
288 Bus = ExAllocatePoolWithTag(NonPagedPool,
289 sizeof(HAL_BUS_HANDLER) + ExtraData,
290 TAG_BUS_HANDLER);
291 if (!Bus) return STATUS_INSUFFICIENT_RESOURCES;
292
293 /* Return the handler */
294 *ReturnedBusHandler = &Bus->Handler;
295
296 /* FIXME: Fix the kernel first. Don't page us out */
297 //CodeHandle = MmLockPagableDataSection(&HaliRegisterBusHandler);
298
299 /* Synchronize with anyone else */
300 KeWaitForSingleObject(&HalpBusDatabaseEvent,
301 WrExecutive,
302 KernelMode,
303 FALSE,
304 NULL);
305
306 /* Check for unknown/root bus */
307 if (BusNumber == -1)
308 {
309 /* We must have an interface */
310 ASSERT(InterfaceType != InterfaceTypeUndefined);
311
312 /* Find the right bus */
313 BusNumber = 0;
314 while (HaliHandlerForBus(InterfaceType, BusNumber)) BusNumber++;
315 }
316
317 /* Allocate arrays for the handler */
318 InterfaceArray = HalpAllocateArray(InterfaceType);
319 InterfaceBusNumberArray = HalpAllocateArray(BusNumber);
320 ConfigArray = HalpAllocateArray(ConfigType);
321 ConfigBusNumberArray = HalpAllocateArray(BusNumber);
322
323 /* Only proceed if all allocations succeeded */
324 if ((InterfaceArray) && (InterfaceBusNumberArray) && (ConfigArray) && (ConfigBusNumberArray))
325 {
326 /* Find the parent handler if any */
327 ParentHandler = HaliReferenceHandlerForBus(ParentBusType, ParentBusNumber);
328
329 /* Initialize the handler */
330 RtlZeroMemory(Bus, sizeof(HAL_BUS_HANDLER) + ExtraData);
331 Bus->ReferenceCount = 1;
332
333 /* Fill out bus data */
334 Bus->Handler.BusNumber = BusNumber;
335 Bus->Handler.InterfaceType = InterfaceType;
336 Bus->Handler.ConfigurationType = ConfigType;
337 Bus->Handler.ParentHandler = ParentHandler;
338
339 /* Fill out dummy handlers */
340 Bus->Handler.GetBusData = HalpNoBusData;
341 Bus->Handler.SetBusData = HalpNoBusData;
342 Bus->Handler.AdjustResourceList = HalpNoAdjustResourceList;
343 Bus->Handler.AssignSlotResources = HalpNoAssignSlotResources;
344
345 /* Make space for extra data */
346 if (ExtraData) Bus->Handler.BusData = Bus + 1;
347
348 /* Check for a parent handler */
349 if (ParentHandler)
350 {
351 /* Inherit the parent routines */
352 Bus->Handler.GetBusData = ParentHandler->GetBusData;
353 Bus->Handler.SetBusData = ParentHandler->SetBusData;
354 Bus->Handler.AdjustResourceList = ParentHandler->AdjustResourceList;
355 Bus->Handler.AssignSlotResources = ParentHandler->AssignSlotResources;
356 Bus->Handler.TranslateBusAddress = ParentHandler->TranslateBusAddress;
357 Bus->Handler.GetInterruptVector = ParentHandler->GetInterruptVector;
358 }
359
360 /* We don't support this yet */
361 ASSERT(!InstallCallback);
362
363 /* Lock the buses */
364 KeAcquireSpinLock(&HalpBusDatabaseSpinLock, &OldIrql);
365
366 /* Make space for the interface */
367 HalpGrowArray(&HalpBusTable, &InterfaceArray);
368
369 /* Check if we really have an interface */
370 if (InterfaceType != InterfaceTypeUndefined)
371 {
372 /* Make space for the association */
373 HalpGrowArray((PARRAY*)&HalpBusTable->Element[InterfaceType],
374 &InterfaceBusNumberArray);
375
376 /* Get the bus handler pointer */
377 BusEntry = (PHAL_BUS_HANDLER*)&((PARRAY)HalpBusTable->Element[InterfaceType])->Element[BusNumber];
378
379 /* Check if there was already a handler there, and set the new one */
380 if (*BusEntry) OldHandler = *BusEntry;
381 *BusEntry = Bus;
382 }
383
384 /* Now add a space for the configuration space */
385 HalpGrowArray(&HalpConfigTable, &ConfigArray);
386
387 /* Check if we really have one */
388 if (ConfigType != ConfigurationSpaceUndefined)
389 {
390 /* Make space for this association */
391 HalpGrowArray((PARRAY*)&HalpConfigTable->Element[ConfigType],
392 &ConfigBusNumberArray);
393
394 /* Get the bus handler pointer */
395 BusEntry = (PHAL_BUS_HANDLER*)&((PARRAY)HalpConfigTable->Element[ConfigType])->Element[BusNumber];
396 if (*BusEntry)
397 {
398 /* Get the old entry, but make sure it's the same we had before */
399 ASSERT((OldHandler == NULL) || (OldHandler == *BusEntry));
400 OldHandler = *BusEntry;
401 }
402
403 /* Set the new entry */
404 *BusEntry = Bus;
405 }
406
407 /* Link the adapter */
408 InsertTailList(&HalpAllBusHandlers, &Bus->AllHandlers);
409
410 /* Remove the old linkage */
411 Bus = OldHandler;
412 if (Bus) RemoveEntryList(&Bus->AllHandlers);
413
414 /* Release the lock */
415 KeReleaseSpinLock(&HalpBusDatabaseSpinLock, OldIrql);
416 Status = STATUS_SUCCESS;
417 }
418 else
419 {
420 /* Fail */
421 Status = STATUS_INSUFFICIENT_RESOURCES;
422 }
423
424 /* Signal the event */
425 KeSetEvent(&HalpBusDatabaseEvent, 0, FALSE);
426
427 /* FIXME: Fix the kernel first. Re-page the function */
428 //MmUnlockPagableImageSection(CodeHandle);
429
430 /* Free all allocations */
431 if (Bus) ExFreePoolWithTag(Bus, TAG_BUS_HANDLER);
432 if (InterfaceArray) ExFreePoolWithTag(InterfaceArray, TAG_BUS_HANDLER);
433 if (InterfaceBusNumberArray) ExFreePoolWithTag(InterfaceBusNumberArray, TAG_BUS_HANDLER);
434 if (ConfigArray) ExFreePoolWithTag(ConfigArray, TAG_BUS_HANDLER);
435 if (ConfigBusNumberArray) ExFreePoolWithTag(ConfigBusNumberArray, TAG_BUS_HANDLER);
436
437 /* And we're done */
438 return Status;
439 }
440 #endif
441
442 VOID
443 NTAPI
HalpInitBusHandler(VOID)444 HalpInitBusHandler(VOID)
445 {
446 /* Setup the bus lock */
447 KeInitializeSpinLock(&HalpBusDatabaseSpinLock);
448
449 /* Setup the bus event */
450 KeInitializeEvent(&HalpBusDatabaseEvent, SynchronizationEvent, TRUE);
451
452 /* Setup the bus configuration and bus table */
453 HalpBusTable = HalpAllocateArray(0);
454 HalpConfigTable = HalpAllocateArray(0);
455
456 /* Setup the bus list */
457 InitializeListHead(&HalpAllBusHandlers);
458
459 /* Setup the HAL Dispatch routines */
460 #ifndef _MINIHAL_
461 HalRegisterBusHandler = HaliRegisterBusHandler;
462 HalHandlerForBus = HaliHandlerForBus;
463 HalHandlerForConfigSpace = HaliHandlerForConfigSpace;
464 HalReferenceHandlerForBus = HaliReferenceHandlerForBus;
465 HalReferenceBusHandler = HaliReferenceBusHandler;
466 HalDereferenceBusHandler = HaliDereferenceBusHandler;
467 #endif
468 HalPciAssignSlotResources = HalpAssignSlotResources;
469 HalPciTranslateBusAddress = HaliTranslateBusAddress; /* PCI Driver can override */
470 if (!HalFindBusAddressTranslation) HalFindBusAddressTranslation = HaliFindBusAddressTranslation;
471 }
472
473 /* EOF */
474