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