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