1 /* 2 * PROJECT: ReactOS Kernel 3 * LICENSE: BSD - See COPYING.ARM in the top level directory 4 * FILE: ntoskrnl/io/pnpmgr/pnpinit.c 5 * PURPOSE: PnP Initialization Code 6 * PROGRAMMERS: ReactOS Portable Systems Group 7 */ 8 9 /* INCLUDES *******************************************************************/ 10 11 #include <ntoskrnl.h> 12 #define NDEBUG 13 #include <debug.h> 14 15 /* GLOBALS ********************************************************************/ 16 17 typedef struct _IOPNP_DEVICE_EXTENSION 18 { 19 PWCHAR CompatibleIdList; 20 ULONG CompatibleIdListSize; 21 } IOPNP_DEVICE_EXTENSION, *PIOPNP_DEVICE_EXTENSION; 22 23 PUNICODE_STRING PiInitGroupOrderTable; 24 USHORT PiInitGroupOrderTableCount; 25 INTERFACE_TYPE PnpDefaultInterfaceType; 26 BOOLEAN PnPBootDriversLoaded = FALSE; 27 28 ARBITER_INSTANCE IopRootBusNumberArbiter; 29 ARBITER_INSTANCE IopRootIrqArbiter; 30 ARBITER_INSTANCE IopRootDmaArbiter; 31 ARBITER_INSTANCE IopRootMemArbiter; 32 ARBITER_INSTANCE IopRootPortArbiter; 33 34 extern KEVENT PiEnumerationFinished; 35 36 NTSTATUS NTAPI IopPortInitialize(VOID); 37 NTSTATUS NTAPI IopMemInitialize(VOID); 38 NTSTATUS NTAPI IopDmaInitialize(VOID); 39 NTSTATUS NTAPI IopIrqInitialize(VOID); 40 NTSTATUS NTAPI IopBusNumberInitialize(VOID); 41 42 /* FUNCTIONS ******************************************************************/ 43 44 INTERFACE_TYPE 45 NTAPI 46 IopDetermineDefaultInterfaceType(VOID) 47 { 48 /* FIXME: ReactOS doesn't support MicroChannel yet */ 49 return Isa; 50 } 51 52 NTSTATUS 53 NTAPI 54 IopInitializeArbiters(VOID) 55 { 56 NTSTATUS Status; 57 58 Status = IopPortInitialize(); 59 if (!NT_SUCCESS(Status)) 60 { 61 DPRINT1("IopPortInitialize() return %X\n", Status); 62 return Status; 63 } 64 65 Status = IopMemInitialize(); 66 if (!NT_SUCCESS(Status)) 67 { 68 DPRINT1("IopMemInitialize() return %X\n", Status); 69 return Status; 70 } 71 72 Status = IopDmaInitialize(); 73 if (!NT_SUCCESS(Status)) 74 { 75 DPRINT1("IopDmaInitialize() return %X\n", Status); 76 return Status; 77 } 78 79 Status = IopIrqInitialize(); 80 if (!NT_SUCCESS(Status)) 81 { 82 DPRINT1("IopIrqInitialize() return %X\n", Status); 83 return Status; 84 } 85 86 Status = IopBusNumberInitialize(); 87 if (!NT_SUCCESS(Status)) 88 { 89 DPRINT1("IopBusNumberInitialize() return %X\n", Status); 90 } 91 92 return Status; 93 } 94 95 96 INIT_FUNCTION 97 NTSTATUS 98 NTAPI 99 PiInitCacheGroupInformation(VOID) 100 { 101 HANDLE KeyHandle; 102 NTSTATUS Status; 103 PKEY_VALUE_FULL_INFORMATION KeyValueInformation; 104 PUNICODE_STRING GroupTable; 105 ULONG Count; 106 UNICODE_STRING GroupString = 107 RTL_CONSTANT_STRING(L"\\Registry\\Machine\\System\\CurrentControlSet" 108 L"\\Control\\ServiceGroupOrder"); 109 110 /* Open the registry key */ 111 Status = IopOpenRegistryKeyEx(&KeyHandle, 112 NULL, 113 &GroupString, 114 KEY_READ); 115 if (NT_SUCCESS(Status)) 116 { 117 /* Get the list */ 118 Status = IopGetRegistryValue(KeyHandle, L"List", &KeyValueInformation); 119 ZwClose(KeyHandle); 120 121 /* Make sure we got it */ 122 if (NT_SUCCESS(Status)) 123 { 124 /* Make sure it's valid */ 125 if ((KeyValueInformation->Type == REG_MULTI_SZ) && 126 (KeyValueInformation->DataLength)) 127 { 128 /* Convert it to unicode strings */ 129 Status = PnpRegMultiSzToUnicodeStrings(KeyValueInformation, 130 &GroupTable, 131 &Count); 132 133 /* Cache it for later */ 134 PiInitGroupOrderTable = GroupTable; 135 PiInitGroupOrderTableCount = (USHORT)Count; 136 } 137 else 138 { 139 /* Fail */ 140 Status = STATUS_UNSUCCESSFUL; 141 } 142 143 /* Free the information */ 144 ExFreePool(KeyValueInformation); 145 } 146 } 147 148 /* Return status */ 149 return Status; 150 } 151 152 USHORT 153 NTAPI 154 PpInitGetGroupOrderIndex(IN HANDLE ServiceHandle) 155 { 156 NTSTATUS Status; 157 PKEY_VALUE_FULL_INFORMATION KeyValueInformation; 158 USHORT i; 159 PVOID Buffer; 160 UNICODE_STRING Group; 161 PAGED_CODE(); 162 163 /* Make sure we have a cache */ 164 if (!PiInitGroupOrderTable) return -1; 165 166 /* If we don't have a handle, the rest is easy -- return the count */ 167 if (!ServiceHandle) return PiInitGroupOrderTableCount + 1; 168 169 /* Otherwise, get the group value */ 170 Status = IopGetRegistryValue(ServiceHandle, L"Group", &KeyValueInformation); 171 if (!NT_SUCCESS(Status)) return PiInitGroupOrderTableCount; 172 173 /* Make sure we have a valid string */ 174 ASSERT(KeyValueInformation->Type == REG_SZ); 175 ASSERT(KeyValueInformation->DataLength); 176 177 /* Convert to unicode string */ 178 Buffer = (PVOID)((ULONG_PTR)KeyValueInformation + KeyValueInformation->DataOffset); 179 PnpRegSzToString(Buffer, KeyValueInformation->DataLength, &Group.Length); 180 Group.MaximumLength = (USHORT)KeyValueInformation->DataLength; 181 Group.Buffer = Buffer; 182 183 /* Loop the groups */ 184 for (i = 0; i < PiInitGroupOrderTableCount; i++) 185 { 186 /* Try to find a match */ 187 if (RtlEqualUnicodeString(&Group, &PiInitGroupOrderTable[i], TRUE)) break; 188 } 189 190 /* We're done */ 191 ExFreePool(KeyValueInformation); 192 return i; 193 } 194 195 USHORT 196 NTAPI 197 PipGetDriverTagPriority(IN HANDLE ServiceHandle) 198 { 199 NTSTATUS Status; 200 HANDLE KeyHandle = NULL; 201 PKEY_VALUE_FULL_INFORMATION KeyValueInformation = NULL; 202 PKEY_VALUE_FULL_INFORMATION KeyValueInformationTag; 203 PKEY_VALUE_FULL_INFORMATION KeyValueInformationGroupOrderList; 204 PVOID Buffer; 205 UNICODE_STRING Group; 206 PULONG GroupOrder; 207 ULONG Count, Tag = 0; 208 USHORT i = -1; 209 UNICODE_STRING GroupString = 210 RTL_CONSTANT_STRING(L"\\Registry\\Machine\\System\\CurrentControlSet" 211 L"\\Control\\ServiceGroupOrder"); 212 213 /* Open the key */ 214 Status = IopOpenRegistryKeyEx(&KeyHandle, NULL, &GroupString, KEY_READ); 215 if (!NT_SUCCESS(Status)) goto Quickie; 216 217 /* Read the group */ 218 Status = IopGetRegistryValue(ServiceHandle, L"Group", &KeyValueInformation); 219 if (!NT_SUCCESS(Status)) goto Quickie; 220 221 /* Make sure we have a group */ 222 if ((KeyValueInformation->Type == REG_SZ) && 223 (KeyValueInformation->DataLength)) 224 { 225 /* Convert to unicode string */ 226 Buffer = (PVOID)((ULONG_PTR)KeyValueInformation + KeyValueInformation->DataOffset); 227 PnpRegSzToString(Buffer, KeyValueInformation->DataLength, &Group.Length); 228 Group.MaximumLength = (USHORT)KeyValueInformation->DataLength; 229 Group.Buffer = Buffer; 230 } 231 232 /* Now read the tag */ 233 Status = IopGetRegistryValue(ServiceHandle, L"Tag", &KeyValueInformationTag); 234 if (!NT_SUCCESS(Status)) goto Quickie; 235 236 /* Make sure we have a tag */ 237 if ((KeyValueInformationTag->Type == REG_DWORD) && 238 (KeyValueInformationTag->DataLength)) 239 { 240 /* Read it */ 241 Tag = *(PULONG)((ULONG_PTR)KeyValueInformationTag + 242 KeyValueInformationTag->DataOffset); 243 } 244 245 /* We can get rid of this now */ 246 ExFreePool(KeyValueInformationTag); 247 248 /* Now let's read the group's tag order */ 249 Status = IopGetRegistryValue(KeyHandle, 250 Group.Buffer, 251 &KeyValueInformationGroupOrderList); 252 253 /* We can get rid of this now */ 254 Quickie: 255 if (KeyValueInformation) ExFreePool(KeyValueInformation); 256 if (KeyHandle) NtClose(KeyHandle); 257 if (!NT_SUCCESS(Status)) return -1; 258 259 /* We're on the success path -- validate the tag order*/ 260 if ((KeyValueInformationGroupOrderList->Type == REG_BINARY) && 261 (KeyValueInformationGroupOrderList->DataLength)) 262 { 263 /* Get the order array */ 264 GroupOrder = (PULONG)((ULONG_PTR)KeyValueInformationGroupOrderList + 265 KeyValueInformationGroupOrderList->DataOffset); 266 267 /* Get the count */ 268 Count = *GroupOrder; 269 ASSERT(((Count + 1) * sizeof(ULONG)) <= 270 KeyValueInformationGroupOrderList->DataLength); 271 272 /* Now loop each tag */ 273 GroupOrder++; 274 for (i = 1; i <= Count; i++) 275 { 276 /* If we found it, we're out */ 277 if (Tag == *GroupOrder) break; 278 279 /* Try the next one */ 280 GroupOrder++; 281 } 282 } 283 284 /* Last buffer to free */ 285 ExFreePool(KeyValueInformationGroupOrderList); 286 return i; 287 } 288 289 NTSTATUS 290 NTAPI 291 PipCallDriverAddDevice(IN PDEVICE_NODE DeviceNode, 292 IN BOOLEAN LoadDriver, 293 IN PDRIVER_OBJECT DriverObject) 294 { 295 NTSTATUS Status; 296 HANDLE EnumRootKey, SubKey; 297 HANDLE ControlKey, ClassKey = NULL, PropertiesKey; 298 UNICODE_STRING ClassGuid, Properties; 299 UNICODE_STRING EnumRoot = RTL_CONSTANT_STRING(ENUM_ROOT); 300 UNICODE_STRING ControlClass = 301 RTL_CONSTANT_STRING(L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Class"); 302 PKEY_VALUE_FULL_INFORMATION KeyValueInformation = NULL; 303 PWCHAR Buffer; 304 305 /* Open enumeration root key */ 306 Status = IopOpenRegistryKeyEx(&EnumRootKey, 307 NULL, 308 &EnumRoot, 309 KEY_READ); 310 if (!NT_SUCCESS(Status)) 311 { 312 DPRINT1("IopOpenRegistryKeyEx() failed for '%wZ' with status 0x%lx\n", 313 &EnumRoot, Status); 314 return Status; 315 } 316 317 /* Open instance subkey */ 318 Status = IopOpenRegistryKeyEx(&SubKey, 319 EnumRootKey, 320 &DeviceNode->InstancePath, 321 KEY_READ); 322 ZwClose(EnumRootKey); 323 if (!NT_SUCCESS(Status)) 324 { 325 DPRINT1("IopOpenRegistryKeyEx() failed for '%wZ' with status 0x%lx\n", 326 &DeviceNode->InstancePath, Status); 327 return Status; 328 } 329 330 /* Get class GUID */ 331 Status = IopGetRegistryValue(SubKey, 332 REGSTR_VAL_CLASSGUID, 333 &KeyValueInformation); 334 if (NT_SUCCESS(Status)) 335 { 336 /* Convert to unicode string */ 337 Buffer = (PVOID)((ULONG_PTR)KeyValueInformation + KeyValueInformation->DataOffset); 338 PnpRegSzToString(Buffer, KeyValueInformation->DataLength, &ClassGuid.Length); 339 ClassGuid.MaximumLength = (USHORT)KeyValueInformation->DataLength; 340 ClassGuid.Buffer = Buffer; 341 342 /* Open the key */ 343 Status = IopOpenRegistryKeyEx(&ControlKey, 344 NULL, 345 &ControlClass, 346 KEY_READ); 347 if (!NT_SUCCESS(Status)) 348 { 349 /* No class key */ 350 DPRINT1("IopOpenRegistryKeyEx() failed for '%wZ' with status 0x%lx\n", 351 &ControlClass, Status); 352 } 353 else 354 { 355 /* Open the class key */ 356 Status = IopOpenRegistryKeyEx(&ClassKey, 357 ControlKey, 358 &ClassGuid, 359 KEY_READ); 360 ZwClose(ControlKey); 361 if (!NT_SUCCESS(Status)) 362 { 363 /* No class key */ 364 DPRINT1("IopOpenRegistryKeyEx() failed for '%wZ' with status 0x%lx\n", 365 &ClassGuid, Status); 366 } 367 } 368 369 /* Check if we made it till here */ 370 if (ClassKey) 371 { 372 /* Get the device properties */ 373 RtlInitUnicodeString(&Properties, REGSTR_KEY_DEVICE_PROPERTIES); 374 Status = IopOpenRegistryKeyEx(&PropertiesKey, 375 ClassKey, 376 &Properties, 377 KEY_READ); 378 if (!NT_SUCCESS(Status)) 379 { 380 /* No properties */ 381 DPRINT("IopOpenRegistryKeyEx() failed for '%wZ' with status 0x%lx\n", 382 &Properties, Status); 383 PropertiesKey = NULL; 384 } 385 else 386 { 387 ZwClose(PropertiesKey); 388 } 389 } 390 391 /* Free the registry data */ 392 ExFreePool(KeyValueInformation); 393 } 394 395 /* Do ReactOS-style setup */ 396 Status = IopAttachFilterDrivers(DeviceNode, SubKey, ClassKey, TRUE); 397 if (!NT_SUCCESS(Status)) 398 { 399 IopRemoveDevice(DeviceNode); 400 goto Exit; 401 } 402 403 Status = IopInitializeDevice(DeviceNode, DriverObject); 404 if (!NT_SUCCESS(Status)) 405 { 406 goto Exit; 407 } 408 409 Status = IopAttachFilterDrivers(DeviceNode, SubKey, ClassKey, FALSE); 410 if (!NT_SUCCESS(Status)) 411 { 412 IopRemoveDevice(DeviceNode); 413 goto Exit; 414 } 415 416 Status = IopStartDevice(DeviceNode); 417 418 Exit: 419 /* Close keys and return status */ 420 ZwClose(SubKey); 421 if (ClassKey != NULL) 422 { 423 ZwClose(ClassKey); 424 } 425 return Status; 426 } 427 428 INIT_FUNCTION 429 NTSTATUS 430 NTAPI 431 IopInitializePlugPlayServices(VOID) 432 { 433 NTSTATUS Status; 434 ULONG Disposition; 435 HANDLE KeyHandle, EnumHandle, ParentHandle, TreeHandle, ControlHandle; 436 UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"\\REGISTRY\\MACHINE\\SYSTEM\\CURRENTCONTROLSET"); 437 UNICODE_STRING PnpManagerDriverName = RTL_CONSTANT_STRING(DRIVER_ROOT_NAME L"PnpManager"); 438 PDEVICE_OBJECT Pdo; 439 440 /* Initialize locks and such */ 441 KeInitializeSpinLock(&IopDeviceTreeLock); 442 KeInitializeSpinLock(&IopDeviceActionLock); 443 InitializeListHead(&IopDeviceActionRequestList); 444 KeInitializeEvent(&PiEnumerationFinished, NotificationEvent, TRUE); 445 446 /* Get the default interface */ 447 PnpDefaultInterfaceType = IopDetermineDefaultInterfaceType(); 448 449 /* Initialize arbiters */ 450 Status = IopInitializeArbiters(); 451 if (!NT_SUCCESS(Status)) return Status; 452 453 /* Setup the group cache */ 454 Status = PiInitCacheGroupInformation(); 455 if (!NT_SUCCESS(Status)) return Status; 456 457 /* Open the current control set */ 458 Status = IopOpenRegistryKeyEx(&KeyHandle, 459 NULL, 460 &KeyName, 461 KEY_ALL_ACCESS); 462 if (!NT_SUCCESS(Status)) return Status; 463 464 /* Create the control key */ 465 RtlInitUnicodeString(&KeyName, L"Control"); 466 Status = IopCreateRegistryKeyEx(&ControlHandle, 467 KeyHandle, 468 &KeyName, 469 KEY_ALL_ACCESS, 470 REG_OPTION_NON_VOLATILE, 471 &Disposition); 472 if (!NT_SUCCESS(Status)) return Status; 473 474 /* Check if it's a new key */ 475 if (Disposition == REG_CREATED_NEW_KEY) 476 { 477 HANDLE DeviceClassesHandle; 478 479 /* Create the device classes key */ 480 RtlInitUnicodeString(&KeyName, L"DeviceClasses"); 481 Status = IopCreateRegistryKeyEx(&DeviceClassesHandle, 482 ControlHandle, 483 &KeyName, 484 KEY_ALL_ACCESS, 485 REG_OPTION_NON_VOLATILE, 486 &Disposition); 487 if (!NT_SUCCESS(Status)) return Status; 488 489 ZwClose(DeviceClassesHandle); 490 } 491 492 ZwClose(ControlHandle); 493 494 /* Create the enum key */ 495 RtlInitUnicodeString(&KeyName, REGSTR_KEY_ENUM); 496 Status = IopCreateRegistryKeyEx(&EnumHandle, 497 KeyHandle, 498 &KeyName, 499 KEY_ALL_ACCESS, 500 REG_OPTION_NON_VOLATILE, 501 &Disposition); 502 if (!NT_SUCCESS(Status)) return Status; 503 504 /* Check if it's a new key */ 505 if (Disposition == REG_CREATED_NEW_KEY) 506 { 507 /* FIXME: DACLs */ 508 } 509 510 /* Create the root key */ 511 ParentHandle = EnumHandle; 512 RtlInitUnicodeString(&KeyName, REGSTR_KEY_ROOTENUM); 513 Status = IopCreateRegistryKeyEx(&EnumHandle, 514 ParentHandle, 515 &KeyName, 516 KEY_ALL_ACCESS, 517 REG_OPTION_NON_VOLATILE, 518 &Disposition); 519 NtClose(ParentHandle); 520 if (!NT_SUCCESS(Status)) return Status; 521 NtClose(EnumHandle); 522 523 /* Open the root key now */ 524 RtlInitUnicodeString(&KeyName, L"\\REGISTRY\\MACHINE\\SYSTEM\\CURRENTCONTROLSET\\ENUM"); 525 Status = IopOpenRegistryKeyEx(&EnumHandle, 526 NULL, 527 &KeyName, 528 KEY_ALL_ACCESS); 529 if (NT_SUCCESS(Status)) 530 { 531 /* Create the root dev node */ 532 RtlInitUnicodeString(&KeyName, REGSTR_VAL_ROOT_DEVNODE); 533 Status = IopCreateRegistryKeyEx(&TreeHandle, 534 EnumHandle, 535 &KeyName, 536 KEY_ALL_ACCESS, 537 REG_OPTION_NON_VOLATILE, 538 NULL); 539 NtClose(EnumHandle); 540 if (NT_SUCCESS(Status)) NtClose(TreeHandle); 541 } 542 543 /* Create the root driver */ 544 Status = IoCreateDriver(&PnpManagerDriverName, PnpRootDriverEntry); 545 if (!NT_SUCCESS(Status)) 546 { 547 DPRINT1("IoCreateDriverObject() failed\n"); 548 KeBugCheckEx(PHASE1_INITIALIZATION_FAILED, Status, 0, 0, 0); 549 } 550 551 /* Create the root PDO */ 552 Status = IoCreateDevice(IopRootDriverObject, 553 sizeof(IOPNP_DEVICE_EXTENSION), 554 NULL, 555 FILE_DEVICE_CONTROLLER, 556 0, 557 FALSE, 558 &Pdo); 559 if (!NT_SUCCESS(Status)) 560 { 561 DPRINT1("IoCreateDevice() failed\n"); 562 KeBugCheckEx(PHASE1_INITIALIZATION_FAILED, Status, 0, 0, 0); 563 } 564 565 /* This is a bus enumerated device */ 566 Pdo->Flags |= DO_BUS_ENUMERATED_DEVICE; 567 568 /* Create the root device node */ 569 IopRootDeviceNode = PipAllocateDeviceNode(Pdo); 570 571 /* Set flags */ 572 IopRootDeviceNode->Flags |= DNF_STARTED + DNF_PROCESSED + DNF_ENUMERATED + 573 DNF_MADEUP + DNF_NO_RESOURCE_REQUIRED + 574 DNF_ADDED; 575 576 /* Create instance path */ 577 RtlCreateUnicodeString(&IopRootDeviceNode->InstancePath, 578 REGSTR_VAL_ROOT_DEVNODE); 579 580 /* Call the add device routine */ 581 IopRootDriverObject->DriverExtension->AddDevice(IopRootDriverObject, 582 IopRootDeviceNode->PhysicalDeviceObject); 583 584 /* Initialize PnP-Event notification support */ 585 Status = IopInitPlugPlayEvents(); 586 if (!NT_SUCCESS(Status)) return Status; 587 588 /* Report the device to the user-mode pnp manager */ 589 IopQueueTargetDeviceEvent(&GUID_DEVICE_ARRIVAL, 590 &IopRootDeviceNode->InstancePath); 591 592 /* Initialize the Bus Type GUID List */ 593 PnpBusTypeGuidList = ExAllocatePool(PagedPool, sizeof(IO_BUS_TYPE_GUID_LIST)); 594 RtlZeroMemory(PnpBusTypeGuidList, sizeof(IO_BUS_TYPE_GUID_LIST)); 595 ExInitializeFastMutex(&PnpBusTypeGuidList->Lock); 596 597 /* Launch the firmware mapper */ 598 Status = IopUpdateRootKey(); 599 if (!NT_SUCCESS(Status)) return Status; 600 601 /* Close the handle to the control set */ 602 NtClose(KeyHandle); 603 604 /* Initialize PnP root relations (this is a syncronous operation) */ 605 PiQueueDeviceAction(IopRootDeviceNode->PhysicalDeviceObject, PiActionEnumRootDevices, NULL, NULL); 606 607 /* We made it */ 608 return STATUS_SUCCESS; 609 } 610 611 /* EOF */ 612