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