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