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