[WIN32K]
[reactos.git] / reactos / hal / halx86 / legacy / bus / bushndlr.c
1 /*
2 * PROJECT: ReactOS HAL
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: hal/halx86/generic/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 */