xref: /reactos/hal/halx86/legacy/bus/bushndlr.c (revision 845faec4)
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 ULONG
107 NTAPI
108 HalpNoBusData(IN PBUS_HANDLER BusHandler,
109               IN PBUS_HANDLER RootHandler,
110               IN ULONG SlotNumber,
111               IN PVOID Buffer,
112               IN ULONG Offset,
113               IN ULONG Length)
114 {
115     /* Not implemented */
116     DPRINT1("STUB GetSetBusData\n");
117     return 0;
118 }
119 
120 NTSTATUS
121 NTAPI
122 HalpNoAdjustResourceList(IN PBUS_HANDLER BusHandler,
123                          IN PBUS_HANDLER RootHandler,
124                          IN OUT PIO_RESOURCE_REQUIREMENTS_LIST *pResourceList)
125 {
126     DPRINT1("STUB Adjustment\n");
127     return STATUS_UNSUCCESSFUL;
128 }
129 
130 NTSTATUS
131 NTAPI
132 HalpNoAssignSlotResources(IN PBUS_HANDLER BusHandler,
133                           IN PBUS_HANDLER RootHandler,
134                           IN PUNICODE_STRING RegistryPath,
135                           IN PUNICODE_STRING DriverClassName OPTIONAL,
136                           IN PDRIVER_OBJECT DriverObject,
137                           IN PDEVICE_OBJECT DeviceObject OPTIONAL,
138                           IN ULONG SlotNumber,
139                           IN OUT PCM_RESOURCE_LIST *AllocatedResources)
140 {
141     DPRINT1("STUB Assignment\n");
142     return STATUS_NOT_SUPPORTED;
143 }
144 
145 VOID
146 FASTCALL
147 HaliReferenceBusHandler(IN PBUS_HANDLER Handler)
148 {
149     PHAL_BUS_HANDLER Bus;
150 
151     /* Find and reference the bus handler */
152     Bus = CONTAINING_RECORD(Handler, HAL_BUS_HANDLER, Handler);
153     Bus->ReferenceCount++;
154 }
155 
156 VOID
157 FASTCALL
158 HaliDereferenceBusHandler(IN PBUS_HANDLER Handler)
159 {
160     PHAL_BUS_HANDLER Bus;
161 
162     /* Find and dereference the bus handler */
163     Bus = CONTAINING_RECORD(Handler, HAL_BUS_HANDLER, Handler);
164     Bus->ReferenceCount--;
165     ASSERT(Bus->ReferenceCount != 0);
166 }
167 
168 PBUS_HANDLER
169 FASTCALL
170 HaliHandlerForBus(IN INTERFACE_TYPE InterfaceType,
171                   IN ULONG BusNumber)
172 {
173     /* Lookup the interface in the bus table */
174     return HalpLookupHandler(HalpBusTable, InterfaceType, BusNumber, FALSE);
175 }
176 
177 PBUS_HANDLER
178 FASTCALL
179 HaliHandlerForConfigSpace(IN BUS_DATA_TYPE ConfigType,
180                           IN ULONG BusNumber)
181 {
182     /* Lookup the configuration in the configuration table */
183     return HalpLookupHandler(HalpConfigTable, ConfigType, BusNumber, FALSE);
184 }
185 
186 PBUS_HANDLER
187 FASTCALL
188 HaliReferenceHandlerForBus(IN INTERFACE_TYPE InterfaceType,
189                            IN ULONG BusNumber)
190 {
191     /* Lookup the interface in the bus table, and reference the handler */
192     return HalpLookupHandler(HalpBusTable, InterfaceType, BusNumber, TRUE);
193 }
194 
195 PBUS_HANDLER
196 FASTCALL
197 HaliReferenceHandlerForConfigSpace(IN BUS_DATA_TYPE ConfigType,
198                                    IN ULONG BusNumber)
199 {
200     /* Lookup the configuration in the configuration table and add a reference */
201     return HalpLookupHandler(HalpConfigTable, ConfigType, BusNumber, TRUE);
202 }
203 
204 PBUS_HANDLER
205 NTAPI
206 HalpContextToBusHandler(IN ULONG_PTR ContextValue)
207 {
208     PLIST_ENTRY NextEntry;
209     PHAL_BUS_HANDLER BusHandler, ThisHandler;
210 
211     /* Start lookup */
212     NextEntry = HalpAllBusHandlers.Flink;
213     ThisHandler = CONTAINING_RECORD(NextEntry, HAL_BUS_HANDLER, AllHandlers);
214     if (ContextValue)
215     {
216         /* If the list is empty, quit */
217         if (IsListEmpty(&HalpAllBusHandlers)) return NULL;
218 
219         /* Otherwise, scan the list */
220         BusHandler = CONTAINING_RECORD(ContextValue, HAL_BUS_HANDLER, Handler);
221         do
222         {
223             /* Check if we've reached the right one */
224             ThisHandler = CONTAINING_RECORD(NextEntry, HAL_BUS_HANDLER, AllHandlers);
225             if (ThisHandler == BusHandler) break;
226 
227             /* Try the next one */
228             NextEntry = NextEntry->Flink;
229         } while (NextEntry != &HalpAllBusHandlers);
230     }
231 
232     /* If we looped back to the end, we didn't find anything */
233     if (NextEntry == &HalpAllBusHandlers) return NULL;
234 
235     /* Otherwise return the handler */
236     return &ThisHandler->Handler;
237 }
238 
239 #ifndef _MINIHAL_
240 NTSTATUS
241 NTAPI
242 HaliRegisterBusHandler(IN INTERFACE_TYPE InterfaceType,
243                        IN BUS_DATA_TYPE ConfigType,
244                        IN ULONG BusNumber,
245                        IN INTERFACE_TYPE ParentBusType,
246                        IN ULONG ParentBusNumber,
247                        IN ULONG ExtraData,
248                        IN PINSTALL_BUS_HANDLER InstallCallback,
249                        OUT PBUS_HANDLER *ReturnedBusHandler)
250 {
251     PHAL_BUS_HANDLER Bus, OldHandler = NULL;
252     PHAL_BUS_HANDLER* BusEntry;
253     //PVOID CodeHandle;
254     PARRAY InterfaceArray, InterfaceBusNumberArray, ConfigArray, ConfigBusNumberArray;
255     PBUS_HANDLER ParentHandler;
256     KIRQL OldIrql;
257     NTSTATUS Status;
258 
259     /* Make sure we have a valid handler */
260     ASSERT((InterfaceType != InterfaceTypeUndefined) ||
261            (ConfigType != ConfigurationSpaceUndefined));
262 
263     /* Allocate the bus handler */
264     Bus = ExAllocatePoolWithTag(NonPagedPool,
265                                 sizeof(HAL_BUS_HANDLER) + ExtraData,
266                                 TAG_BUS_HANDLER);
267     if (!Bus) return STATUS_INSUFFICIENT_RESOURCES;
268 
269     /* Return the handler */
270     *ReturnedBusHandler = &Bus->Handler;
271 
272     /* FIXME: Fix the kernel first. Don't page us out */
273     //CodeHandle = MmLockPagableDataSection(&HaliRegisterBusHandler);
274 
275     /* Synchronize with anyone else */
276     KeWaitForSingleObject(&HalpBusDatabaseEvent,
277                           WrExecutive,
278                           KernelMode,
279                           FALSE,
280                           NULL);
281 
282     /* Check for unknown/root bus */
283     if (BusNumber == -1)
284     {
285         /* We must have an interface */
286         ASSERT(InterfaceType != InterfaceTypeUndefined);
287 
288         /* Find the right bus */
289         BusNumber = 0;
290         while (HaliHandlerForBus(InterfaceType, BusNumber)) BusNumber++;
291     }
292 
293     /* Allocate arrays for the handler */
294     InterfaceArray = HalpAllocateArray(InterfaceType);
295     InterfaceBusNumberArray = HalpAllocateArray(BusNumber);
296     ConfigArray = HalpAllocateArray(ConfigType);
297     ConfigBusNumberArray = HalpAllocateArray(BusNumber);
298 
299     /* Only proceed if all allocations succeeded */
300     if ((InterfaceArray) && (InterfaceBusNumberArray) && (ConfigArray) && (ConfigBusNumberArray))
301     {
302         /* Find the parent handler if any */
303         ParentHandler = HaliReferenceHandlerForBus(ParentBusType, ParentBusNumber);
304 
305         /* Initialize the handler */
306         RtlZeroMemory(Bus, sizeof(HAL_BUS_HANDLER) + ExtraData);
307         Bus->ReferenceCount = 1;
308 
309         /* Fill out bus data */
310         Bus->Handler.BusNumber = BusNumber;
311         Bus->Handler.InterfaceType = InterfaceType;
312         Bus->Handler.ConfigurationType = ConfigType;
313         Bus->Handler.ParentHandler = ParentHandler;
314 
315         /* Fill out dummy handlers */
316         Bus->Handler.GetBusData = HalpNoBusData;
317         Bus->Handler.SetBusData = HalpNoBusData;
318         Bus->Handler.AdjustResourceList = HalpNoAdjustResourceList;
319         Bus->Handler.AssignSlotResources = HalpNoAssignSlotResources;
320 
321         /* Make space for extra data */
322         if (ExtraData) Bus->Handler.BusData = Bus + 1;
323 
324         /* Check for a parent handler */
325         if (ParentHandler)
326         {
327             /* Inherit the parent routines */
328             Bus->Handler.GetBusData = ParentHandler->GetBusData;
329             Bus->Handler.SetBusData = ParentHandler->SetBusData;
330             Bus->Handler.AdjustResourceList = ParentHandler->AdjustResourceList;
331             Bus->Handler.AssignSlotResources = ParentHandler->AssignSlotResources;
332             Bus->Handler.TranslateBusAddress = ParentHandler->TranslateBusAddress;
333             Bus->Handler.GetInterruptVector = ParentHandler->GetInterruptVector;
334         }
335 
336         /* We don't support this yet */
337         ASSERT(!InstallCallback);
338 
339         /* Lock the buses */
340         KeAcquireSpinLock(&HalpBusDatabaseSpinLock, &OldIrql);
341 
342         /* Make space for the interface */
343         HalpGrowArray(&HalpBusTable, &InterfaceArray);
344 
345         /* Check if we really have an interface */
346         if (InterfaceType != InterfaceTypeUndefined)
347         {
348             /* Make space for the association */
349             HalpGrowArray((PARRAY*)&HalpBusTable->Element[InterfaceType],
350                           &InterfaceBusNumberArray);
351 
352             /* Get the bus handler pointer */
353             BusEntry = (PHAL_BUS_HANDLER*)&((PARRAY)HalpBusTable->Element[InterfaceType])->Element[BusNumber];
354 
355             /* Check if there was already a handler there, and set the new one */
356             if (*BusEntry) OldHandler = *BusEntry;
357             *BusEntry = Bus;
358         }
359 
360         /* Now add a space for the configuration space */
361         HalpGrowArray(&HalpConfigTable, &ConfigArray);
362 
363         /* Check if we really have one */
364         if (ConfigType != ConfigurationSpaceUndefined)
365         {
366             /* Make space for this association */
367             HalpGrowArray((PARRAY*)&HalpConfigTable->Element[ConfigType],
368                           &ConfigBusNumberArray);
369 
370             /* Get the bus handler pointer */
371             BusEntry = (PHAL_BUS_HANDLER*)&((PARRAY)HalpConfigTable->Element[ConfigType])->Element[BusNumber];
372             if (*BusEntry)
373             {
374                 /* Get the old entry, but make sure it's the same we had before */
375                 ASSERT((OldHandler == NULL) || (OldHandler == *BusEntry));
376                 OldHandler = *BusEntry;
377             }
378 
379             /* Set the new entry */
380             *BusEntry = Bus;
381         }
382 
383         /* Link the adapter */
384         InsertTailList(&HalpAllBusHandlers, &Bus->AllHandlers);
385 
386         /* Remove the old linkage */
387         Bus = OldHandler;
388         if (Bus) RemoveEntryList(&Bus->AllHandlers);
389 
390         /* Release the lock */
391         KeReleaseSpinLock(&HalpBusDatabaseSpinLock, OldIrql);
392         Status = STATUS_SUCCESS;
393     }
394     else
395     {
396         /* Fail */
397         Status = STATUS_INSUFFICIENT_RESOURCES;
398     }
399 
400     /* Signal the event */
401     KeSetEvent(&HalpBusDatabaseEvent, 0, FALSE);
402 
403     /* FIXME: Fix the kernel first. Re-page the function */
404     //MmUnlockPagableImageSection(CodeHandle);
405 
406     /* Free all allocations */
407     if (Bus) ExFreePoolWithTag(Bus, TAG_BUS_HANDLER);
408     if (InterfaceArray) ExFreePoolWithTag(InterfaceArray, TAG_BUS_HANDLER);
409     if (InterfaceBusNumberArray) ExFreePoolWithTag(InterfaceBusNumberArray, TAG_BUS_HANDLER);
410     if (ConfigArray) ExFreePoolWithTag(ConfigArray, TAG_BUS_HANDLER);
411     if (ConfigBusNumberArray) ExFreePoolWithTag(ConfigBusNumberArray, TAG_BUS_HANDLER);
412 
413     /* And we're done */
414     return Status;
415 }
416 #endif
417 
418 VOID
419 NTAPI
420 HalpInitBusHandler(VOID)
421 {
422     /* Setup the bus lock */
423     KeInitializeSpinLock(&HalpBusDatabaseSpinLock);
424 
425     /* Setup the bus event */
426     KeInitializeEvent(&HalpBusDatabaseEvent, SynchronizationEvent, TRUE);
427 
428     /* Setup the bus configuration and bus table */
429     HalpBusTable = HalpAllocateArray(0);
430     HalpConfigTable = HalpAllocateArray(0);
431 
432     /* Setup the bus list */
433     InitializeListHead(&HalpAllBusHandlers);
434 
435     /* Setup the HAL Dispatch routines */
436 #ifndef _MINIHAL_
437     HalRegisterBusHandler = HaliRegisterBusHandler;
438     HalHandlerForBus = HaliHandlerForBus;
439     HalHandlerForConfigSpace = HaliHandlerForConfigSpace;
440     HalReferenceHandlerForBus = HaliReferenceHandlerForBus;
441     HalReferenceBusHandler = HaliReferenceBusHandler;
442     HalDereferenceBusHandler = HaliDereferenceBusHandler;
443 #endif
444     HalPciAssignSlotResources = HalpAssignSlotResources;
445     HalPciTranslateBusAddress = HaliTranslateBusAddress; /* PCI Driver can override */
446     if (!HalFindBusAddressTranslation) HalFindBusAddressTranslation = HaliFindBusAddressTranslation;
447 }
448 
449 /* EOF */
450