xref: /reactos/hal/halx86/legacy/bus/bushndlr.c (revision 7f26a396)
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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