1c2c66affSColin Finck /* 2c2c66affSColin Finck * PROJECT: ReactOS Kernel 3c2c66affSColin Finck * COPYRIGHT: GPL - See COPYING in the top level directory 4c2c66affSColin Finck * FILE: ntoskrnl/io/pnpmgr/pnpreport.c 5c2c66affSColin Finck * PURPOSE: Device Changes Reporting Functions 6c2c66affSColin Finck * PROGRAMMERS: Cameron Gutman (cameron.gutman@reactos.org) 7c2c66affSColin Finck * Pierre Schweitzer 8c2c66affSColin Finck */ 9c2c66affSColin Finck 10c2c66affSColin Finck /* INCLUDES ******************************************************************/ 11c2c66affSColin Finck 12c2c66affSColin Finck #include <ntoskrnl.h> 13c2c66affSColin Finck #define NDEBUG 14c2c66affSColin Finck #include <debug.h> 15c2c66affSColin Finck 16c2c66affSColin Finck /* TYPES *******************************************************************/ 17c2c66affSColin Finck 18c2c66affSColin Finck typedef struct _INTERNAL_WORK_QUEUE_ITEM 19c2c66affSColin Finck { 20c2c66affSColin Finck WORK_QUEUE_ITEM WorkItem; 21c2c66affSColin Finck PDEVICE_OBJECT PhysicalDeviceObject; 22c2c66affSColin Finck PDEVICE_CHANGE_COMPLETE_CALLBACK Callback; 23c2c66affSColin Finck PVOID Context; 24c2c66affSColin Finck PTARGET_DEVICE_CUSTOM_NOTIFICATION NotificationStructure; 25c2c66affSColin Finck } INTERNAL_WORK_QUEUE_ITEM, *PINTERNAL_WORK_QUEUE_ITEM; 26c2c66affSColin Finck 27c2c66affSColin Finck NTSTATUS 28c2c66affSColin Finck NTAPI 29c2c66affSColin Finck IopCreateDeviceKeyPath(IN PCUNICODE_STRING RegistryPath, 30c2c66affSColin Finck IN ULONG CreateOptions, 31c2c66affSColin Finck OUT PHANDLE Handle); 32c2c66affSColin Finck 33c2c66affSColin Finck NTSTATUS 34c2c66affSColin Finck IopSetDeviceInstanceData(HANDLE InstanceKey, 35c2c66affSColin Finck PDEVICE_NODE DeviceNode); 36c2c66affSColin Finck 37c2c66affSColin Finck NTSTATUS 38c2c66affSColin Finck IopActionInterrogateDeviceStack(PDEVICE_NODE DeviceNode, 39c2c66affSColin Finck PVOID Context); 40c2c66affSColin Finck 41c2c66affSColin Finck NTSTATUS 42c2c66affSColin Finck PpSetCustomTargetEvent(IN PDEVICE_OBJECT DeviceObject, 43c2c66affSColin Finck IN OUT PKEVENT SyncEvent OPTIONAL, 44c2c66affSColin Finck IN OUT PNTSTATUS SyncStatus OPTIONAL, 45c2c66affSColin Finck IN PDEVICE_CHANGE_COMPLETE_CALLBACK Callback OPTIONAL, 46c2c66affSColin Finck IN PVOID Context OPTIONAL, 47c2c66affSColin Finck IN PTARGET_DEVICE_CUSTOM_NOTIFICATION NotificationStructure); 48c2c66affSColin Finck 49c2c66affSColin Finck /* PRIVATE FUNCTIONS *********************************************************/ 50c2c66affSColin Finck 51c2c66affSColin Finck PWCHAR 52c2c66affSColin Finck IopGetInterfaceTypeString(INTERFACE_TYPE IfType) 53c2c66affSColin Finck { 54c2c66affSColin Finck switch (IfType) 55c2c66affSColin Finck { 56c2c66affSColin Finck case Internal: 57c2c66affSColin Finck return L"Internal"; 58c2c66affSColin Finck 59c2c66affSColin Finck case Isa: 60c2c66affSColin Finck return L"Isa"; 61c2c66affSColin Finck 62c2c66affSColin Finck case Eisa: 63c2c66affSColin Finck return L"Eisa"; 64c2c66affSColin Finck 65c2c66affSColin Finck case MicroChannel: 66c2c66affSColin Finck return L"MicroChannel"; 67c2c66affSColin Finck 68c2c66affSColin Finck case TurboChannel: 69c2c66affSColin Finck return L"TurboChannel"; 70c2c66affSColin Finck 71c2c66affSColin Finck case PCIBus: 72c2c66affSColin Finck return L"PCIBus"; 73c2c66affSColin Finck 74c2c66affSColin Finck case VMEBus: 75c2c66affSColin Finck return L"VMEBus"; 76c2c66affSColin Finck 77c2c66affSColin Finck case NuBus: 78c2c66affSColin Finck return L"NuBus"; 79c2c66affSColin Finck 80c2c66affSColin Finck case PCMCIABus: 81c2c66affSColin Finck return L"PCMCIABus"; 82c2c66affSColin Finck 83c2c66affSColin Finck case CBus: 84c2c66affSColin Finck return L"CBus"; 85c2c66affSColin Finck 86c2c66affSColin Finck case MPIBus: 87c2c66affSColin Finck return L"MPIBus"; 88c2c66affSColin Finck 89c2c66affSColin Finck case MPSABus: 90c2c66affSColin Finck return L"MPSABus"; 91c2c66affSColin Finck 92c2c66affSColin Finck case ProcessorInternal: 93c2c66affSColin Finck return L"ProcessorInternal"; 94c2c66affSColin Finck 95c2c66affSColin Finck case PNPISABus: 96c2c66affSColin Finck return L"PNPISABus"; 97c2c66affSColin Finck 98c2c66affSColin Finck case PNPBus: 99c2c66affSColin Finck return L"PNPBus"; 100c2c66affSColin Finck 101c2c66affSColin Finck case Vmcs: 102c2c66affSColin Finck return L"Vmcs"; 103c2c66affSColin Finck 104c2c66affSColin Finck default: 105c2c66affSColin Finck DPRINT1("Invalid bus type: %d\n", IfType); 106c2c66affSColin Finck return NULL; 107c2c66affSColin Finck } 108c2c66affSColin Finck } 109c2c66affSColin Finck 110c2c66affSColin Finck VOID 111c2c66affSColin Finck NTAPI 112c2c66affSColin Finck IopReportTargetDeviceChangeAsyncWorker(PVOID Context) 113c2c66affSColin Finck { 114c2c66affSColin Finck PINTERNAL_WORK_QUEUE_ITEM Item; 115c2c66affSColin Finck 116c2c66affSColin Finck Item = (PINTERNAL_WORK_QUEUE_ITEM)Context; 117c2c66affSColin Finck PpSetCustomTargetEvent(Item->PhysicalDeviceObject, NULL, NULL, Item->Callback, Item->Context, Item->NotificationStructure); 118c2c66affSColin Finck ObDereferenceObject(Item->PhysicalDeviceObject); 119c2c66affSColin Finck ExFreePoolWithTag(Context, ' pP'); 120c2c66affSColin Finck } 121c2c66affSColin Finck 122c2c66affSColin Finck NTSTATUS 123c2c66affSColin Finck PpSetCustomTargetEvent(IN PDEVICE_OBJECT DeviceObject, 124c2c66affSColin Finck IN OUT PKEVENT SyncEvent OPTIONAL, 125c2c66affSColin Finck IN OUT PNTSTATUS SyncStatus OPTIONAL, 126c2c66affSColin Finck IN PDEVICE_CHANGE_COMPLETE_CALLBACK Callback OPTIONAL, 127c2c66affSColin Finck IN PVOID Context OPTIONAL, 128c2c66affSColin Finck IN PTARGET_DEVICE_CUSTOM_NOTIFICATION NotificationStructure) 129c2c66affSColin Finck { 130c2c66affSColin Finck ASSERT(NotificationStructure != NULL); 131c2c66affSColin Finck ASSERT(DeviceObject != NULL); 132c2c66affSColin Finck 133c2c66affSColin Finck if (SyncEvent) 134c2c66affSColin Finck { 135c2c66affSColin Finck ASSERT(SyncStatus); 136c2c66affSColin Finck *SyncStatus = STATUS_PENDING; 137c2c66affSColin Finck } 138c2c66affSColin Finck 139c2c66affSColin Finck /* That call is totally wrong but notifications handler must be fixed first */ 140c2c66affSColin Finck IopNotifyPlugPlayNotification(DeviceObject, 141c2c66affSColin Finck EventCategoryTargetDeviceChange, 142c2c66affSColin Finck &GUID_PNP_CUSTOM_NOTIFICATION, 143c2c66affSColin Finck NotificationStructure, 144c2c66affSColin Finck NULL); 145c2c66affSColin Finck 146c2c66affSColin Finck if (SyncEvent) 147c2c66affSColin Finck { 148c2c66affSColin Finck KeSetEvent(SyncEvent, IO_NO_INCREMENT, FALSE); 149c2c66affSColin Finck *SyncStatus = STATUS_SUCCESS; 150c2c66affSColin Finck } 151c2c66affSColin Finck 152c2c66affSColin Finck return STATUS_SUCCESS; 153c2c66affSColin Finck } 154c2c66affSColin Finck 155c2c66affSColin Finck /* PUBLIC FUNCTIONS **********************************************************/ 156c2c66affSColin Finck 157c2c66affSColin Finck /* 158c2c66affSColin Finck * @implemented 159c2c66affSColin Finck */ 160c2c66affSColin Finck NTSTATUS 161c2c66affSColin Finck NTAPI 162c2c66affSColin Finck IoReportDetectedDevice(IN PDRIVER_OBJECT DriverObject, 163c2c66affSColin Finck IN INTERFACE_TYPE LegacyBusType, 164c2c66affSColin Finck IN ULONG BusNumber, 165c2c66affSColin Finck IN ULONG SlotNumber, 166c2c66affSColin Finck IN PCM_RESOURCE_LIST ResourceList, 167c2c66affSColin Finck IN PIO_RESOURCE_REQUIREMENTS_LIST ResourceRequirements OPTIONAL, 168c2c66affSColin Finck IN BOOLEAN ResourceAssigned, 169c2c66affSColin Finck IN OUT PDEVICE_OBJECT *DeviceObject OPTIONAL) 170c2c66affSColin Finck { 171c2c66affSColin Finck PDEVICE_NODE DeviceNode; 172c2c66affSColin Finck PDEVICE_OBJECT Pdo; 173c2c66affSColin Finck NTSTATUS Status; 174c2c66affSColin Finck HANDLE InstanceKey; 175c2c66affSColin Finck ULONG RequiredLength; 176c2c66affSColin Finck UNICODE_STRING ValueName, ServiceName; 177c2c66affSColin Finck WCHAR HardwareId[256]; 178c2c66affSColin Finck PWCHAR IfString; 179c2c66affSColin Finck ULONG IdLength; 180c2c66affSColin Finck 181c2c66affSColin Finck DPRINT("IoReportDetectedDevice (DeviceObject %p, *DeviceObject %p)\n", 182c2c66affSColin Finck DeviceObject, DeviceObject ? *DeviceObject : NULL); 183c2c66affSColin Finck 184c2c66affSColin Finck ServiceName = DriverObject->DriverExtension->ServiceKeyName; 185c2c66affSColin Finck 186c2c66affSColin Finck /* If the interface type is unknown, treat it as internal */ 187c2c66affSColin Finck if (LegacyBusType == InterfaceTypeUndefined) 188c2c66affSColin Finck LegacyBusType = Internal; 189c2c66affSColin Finck 190c2c66affSColin Finck /* Get the string equivalent of the interface type */ 191c2c66affSColin Finck IfString = IopGetInterfaceTypeString(LegacyBusType); 192c2c66affSColin Finck 193c2c66affSColin Finck /* If NULL is returned then it's a bad type */ 194c2c66affSColin Finck if (!IfString) 195c2c66affSColin Finck return STATUS_INVALID_PARAMETER; 196c2c66affSColin Finck 197c2c66affSColin Finck /* We use the caller's PDO if they supplied one */ 198c2c66affSColin Finck if (DeviceObject && *DeviceObject) 199c2c66affSColin Finck { 200c2c66affSColin Finck Pdo = *DeviceObject; 201c2c66affSColin Finck } 202c2c66affSColin Finck else 203c2c66affSColin Finck { 204c2c66affSColin Finck /* Create the PDO */ 205c2c66affSColin Finck Status = PnpRootCreateDevice(&ServiceName, 206c2c66affSColin Finck NULL, 207c2c66affSColin Finck &Pdo, 208c2c66affSColin Finck NULL); 209c2c66affSColin Finck if (!NT_SUCCESS(Status)) 210c2c66affSColin Finck { 211c2c66affSColin Finck DPRINT("PnpRootCreateDevice() failed (Status 0x%08lx)\n", Status); 212c2c66affSColin Finck return Status; 213c2c66affSColin Finck } 214c2c66affSColin Finck } 215c2c66affSColin Finck 216c2c66affSColin Finck /* Create the device node for the new PDO */ 217c2c66affSColin Finck Status = IopCreateDeviceNode(IopRootDeviceNode, 218c2c66affSColin Finck Pdo, 219c2c66affSColin Finck NULL, 220c2c66affSColin Finck &DeviceNode); 221c2c66affSColin Finck 222c2c66affSColin Finck if (!NT_SUCCESS(Status)) 223c2c66affSColin Finck { 224c2c66affSColin Finck DPRINT("IopCreateDeviceNode() failed (Status 0x%08lx)\n", Status); 225c2c66affSColin Finck return Status; 226c2c66affSColin Finck } 227c2c66affSColin Finck 228c2c66affSColin Finck /* We're enumerated already */ 229c2c66affSColin Finck IopDeviceNodeSetFlag(DeviceNode, DNF_ENUMERATED); 230c2c66affSColin Finck 231c2c66affSColin Finck /* We don't call AddDevice for devices reported this way */ 232c2c66affSColin Finck IopDeviceNodeSetFlag(DeviceNode, DNF_ADDED); 233c2c66affSColin Finck 234c2c66affSColin Finck /* We don't send IRP_MN_START_DEVICE */ 235c2c66affSColin Finck IopDeviceNodeSetFlag(DeviceNode, DNF_STARTED); 236c2c66affSColin Finck 237c2c66affSColin Finck /* We need to get device IDs */ 238c2c66affSColin Finck #if 0 239c2c66affSColin Finck IopDeviceNodeSetFlag(DeviceNode, DNF_NEED_QUERY_IDS); 240c2c66affSColin Finck #endif 241c2c66affSColin Finck 242c2c66affSColin Finck /* This is a legacy driver for this device */ 243c2c66affSColin Finck IopDeviceNodeSetFlag(DeviceNode, DNF_LEGACY_DRIVER); 244c2c66affSColin Finck 245c2c66affSColin Finck /* Perform a manual configuration of our device */ 246c2c66affSColin Finck IopActionInterrogateDeviceStack(DeviceNode, DeviceNode->Parent); 247c2c66affSColin Finck IopActionConfigureChildServices(DeviceNode, DeviceNode->Parent); 248c2c66affSColin Finck 249c2c66affSColin Finck /* Open a handle to the instance path key */ 250c2c66affSColin Finck /* REG_OPTION_VOLATILE is a HACK!!! */ 251c2c66affSColin Finck Status = IopCreateDeviceKeyPath(&DeviceNode->InstancePath, REG_OPTION_VOLATILE, &InstanceKey); 252c2c66affSColin Finck if (!NT_SUCCESS(Status)) 253c2c66affSColin Finck return Status; 254c2c66affSColin Finck 255c2c66affSColin Finck /* Add DETECTEDInterfaceType\DriverName */ 256c2c66affSColin Finck IdLength = 0; 257c2c66affSColin Finck IdLength += swprintf(&HardwareId[IdLength], 258c2c66affSColin Finck L"DETECTED%ls\\%wZ", 259c2c66affSColin Finck IfString, 260c2c66affSColin Finck &ServiceName); 261c2c66affSColin Finck IdLength++; 262c2c66affSColin Finck 263c2c66affSColin Finck /* Add DETECTED\DriverName */ 264c2c66affSColin Finck IdLength += swprintf(&HardwareId[IdLength], 265c2c66affSColin Finck L"DETECTED\\%wZ", 266c2c66affSColin Finck &ServiceName); 267c2c66affSColin Finck IdLength++; 268c2c66affSColin Finck 269c2c66affSColin Finck /* Terminate the string with another null */ 270c2c66affSColin Finck HardwareId[IdLength++] = UNICODE_NULL; 271c2c66affSColin Finck 272c2c66affSColin Finck /* Store the value for CompatibleIDs */ 273c2c66affSColin Finck RtlInitUnicodeString(&ValueName, L"CompatibleIDs"); 274c2c66affSColin Finck Status = ZwSetValueKey(InstanceKey, &ValueName, 0, REG_MULTI_SZ, HardwareId, IdLength * sizeof(WCHAR)); 275c2c66affSColin Finck if (!NT_SUCCESS(Status)) 276c2c66affSColin Finck { 277c2c66affSColin Finck DPRINT("Failed to write the compatible IDs: 0x%x\n", Status); 278c2c66affSColin Finck ZwClose(InstanceKey); 279c2c66affSColin Finck return Status; 280c2c66affSColin Finck } 281c2c66affSColin Finck 282c2c66affSColin Finck /* Add a hardware ID if the driver didn't report one */ 283c2c66affSColin Finck RtlInitUnicodeString(&ValueName, L"HardwareID"); 284c2c66affSColin Finck if (ZwQueryValueKey(InstanceKey, &ValueName, KeyValueBasicInformation, NULL, 0, &RequiredLength) == STATUS_OBJECT_NAME_NOT_FOUND) 285c2c66affSColin Finck { 286c2c66affSColin Finck /* Just use our most specific compatible ID */ 287c2c66affSColin Finck IdLength = 0; 288c2c66affSColin Finck IdLength += swprintf(&HardwareId[IdLength], 289c2c66affSColin Finck L"DETECTED%ls\\%wZ", 290c2c66affSColin Finck IfString, 291c2c66affSColin Finck &ServiceName); 292c2c66affSColin Finck IdLength++; 293c2c66affSColin Finck 294c2c66affSColin Finck HardwareId[IdLength++] = UNICODE_NULL; 295c2c66affSColin Finck 296c2c66affSColin Finck /* Write the value to the registry */ 297c2c66affSColin Finck Status = ZwSetValueKey(InstanceKey, &ValueName, 0, REG_MULTI_SZ, HardwareId, IdLength * sizeof(WCHAR)); 298c2c66affSColin Finck if (!NT_SUCCESS(Status)) 299c2c66affSColin Finck { 300c2c66affSColin Finck DPRINT("Failed to write the hardware ID: 0x%x\n", Status); 301c2c66affSColin Finck ZwClose(InstanceKey); 302c2c66affSColin Finck return Status; 303c2c66affSColin Finck } 304c2c66affSColin Finck } 305c2c66affSColin Finck 306c2c66affSColin Finck /* Assign the resources to the device node */ 307c2c66affSColin Finck DeviceNode->BootResources = ResourceList; 308c2c66affSColin Finck DeviceNode->ResourceRequirements = ResourceRequirements; 309c2c66affSColin Finck 310c2c66affSColin Finck /* Set appropriate flags */ 311c2c66affSColin Finck if (DeviceNode->BootResources) 312c2c66affSColin Finck IopDeviceNodeSetFlag(DeviceNode, DNF_HAS_BOOT_CONFIG); 313c2c66affSColin Finck 314c2c66affSColin Finck if (!DeviceNode->ResourceRequirements && !DeviceNode->BootResources) 315c2c66affSColin Finck IopDeviceNodeSetFlag(DeviceNode, DNF_NO_RESOURCE_REQUIRED); 316c2c66affSColin Finck 317c2c66affSColin Finck /* Write the resource information to the registry */ 318c2c66affSColin Finck IopSetDeviceInstanceData(InstanceKey, DeviceNode); 319c2c66affSColin Finck 320c2c66affSColin Finck /* If the caller didn't get the resources assigned for us, do it now */ 321c2c66affSColin Finck if (!ResourceAssigned) 322c2c66affSColin Finck { 323c2c66affSColin Finck Status = IopAssignDeviceResources(DeviceNode); 324c2c66affSColin Finck 325c2c66affSColin Finck /* See if we failed */ 326c2c66affSColin Finck if (!NT_SUCCESS(Status)) 327c2c66affSColin Finck { 328c2c66affSColin Finck DPRINT("Assigning resources failed: 0x%x\n", Status); 329c2c66affSColin Finck ZwClose(InstanceKey); 330c2c66affSColin Finck return Status; 331c2c66affSColin Finck } 332c2c66affSColin Finck } 333c2c66affSColin Finck 334c2c66affSColin Finck /* Close the instance key handle */ 335c2c66affSColin Finck ZwClose(InstanceKey); 336c2c66affSColin Finck 337c2c66affSColin Finck /* Register the given DO with PnP root if required */ 338c2c66affSColin Finck if (DeviceObject && *DeviceObject) 339c2c66affSColin Finck PnpRootRegisterDevice(*DeviceObject); 340c2c66affSColin Finck 341c2c66affSColin Finck /* Report the device's enumeration to umpnpmgr */ 342c2c66affSColin Finck IopQueueTargetDeviceEvent(&GUID_DEVICE_ENUMERATED, 343c2c66affSColin Finck &DeviceNode->InstancePath); 344c2c66affSColin Finck 345c2c66affSColin Finck /* Report the device's arrival to umpnpmgr */ 346c2c66affSColin Finck IopQueueTargetDeviceEvent(&GUID_DEVICE_ARRIVAL, 347c2c66affSColin Finck &DeviceNode->InstancePath); 348c2c66affSColin Finck 349c2c66affSColin Finck DPRINT("Reported device: %S (%wZ)\n", HardwareId, &DeviceNode->InstancePath); 350c2c66affSColin Finck 351c2c66affSColin Finck /* Return the PDO */ 352c2c66affSColin Finck if (DeviceObject) *DeviceObject = Pdo; 353c2c66affSColin Finck 354c2c66affSColin Finck return STATUS_SUCCESS; 355c2c66affSColin Finck } 356c2c66affSColin Finck 357c2c66affSColin Finck /* 358c2c66affSColin Finck * @halfplemented 359c2c66affSColin Finck */ 360c2c66affSColin Finck NTSTATUS 361c2c66affSColin Finck NTAPI 362c2c66affSColin Finck IoReportResourceForDetection(IN PDRIVER_OBJECT DriverObject, 363c2c66affSColin Finck IN PCM_RESOURCE_LIST DriverList OPTIONAL, 364c2c66affSColin Finck IN ULONG DriverListSize OPTIONAL, 365c2c66affSColin Finck IN PDEVICE_OBJECT DeviceObject OPTIONAL, 366c2c66affSColin Finck IN PCM_RESOURCE_LIST DeviceList OPTIONAL, 367c2c66affSColin Finck IN ULONG DeviceListSize OPTIONAL, 368c2c66affSColin Finck OUT PBOOLEAN ConflictDetected) 369c2c66affSColin Finck { 370c2c66affSColin Finck PCM_RESOURCE_LIST ResourceList; 371c2c66affSColin Finck NTSTATUS Status; 372c2c66affSColin Finck 373c2c66affSColin Finck *ConflictDetected = FALSE; 374c2c66affSColin Finck 375c2c66affSColin Finck if (!DriverList && !DeviceList) 376c2c66affSColin Finck return STATUS_INVALID_PARAMETER; 377c2c66affSColin Finck 378c2c66affSColin Finck /* Find the real list */ 379c2c66affSColin Finck if (!DriverList) 380c2c66affSColin Finck ResourceList = DeviceList; 381c2c66affSColin Finck else 382c2c66affSColin Finck ResourceList = DriverList; 383c2c66affSColin Finck 384c2c66affSColin Finck /* Look for a resource conflict */ 385c2c66affSColin Finck Status = IopDetectResourceConflict(ResourceList, FALSE, NULL); 386c2c66affSColin Finck if (Status == STATUS_CONFLICTING_ADDRESSES) 387c2c66affSColin Finck { 388c2c66affSColin Finck /* Oh noes */ 389c2c66affSColin Finck *ConflictDetected = TRUE; 390c2c66affSColin Finck } 391c2c66affSColin Finck else if (NT_SUCCESS(Status)) 392c2c66affSColin Finck { 393c2c66affSColin Finck /* Looks like we're good to go */ 394c2c66affSColin Finck 395c2c66affSColin Finck /* TODO: Claim the resources in the ResourceMap */ 396c2c66affSColin Finck } 397c2c66affSColin Finck 398c2c66affSColin Finck return Status; 399c2c66affSColin Finck } 400c2c66affSColin Finck 401c2c66affSColin Finck VOID 402c2c66affSColin Finck NTAPI 403c2c66affSColin Finck IopSetEvent(IN PVOID Context) 404c2c66affSColin Finck { 405c2c66affSColin Finck PKEVENT Event = Context; 406c2c66affSColin Finck 407c2c66affSColin Finck /* Set the event */ 408c2c66affSColin Finck KeSetEvent(Event, IO_NO_INCREMENT, FALSE); 409c2c66affSColin Finck } 410c2c66affSColin Finck 411c2c66affSColin Finck /* 412c2c66affSColin Finck * @implemented 413c2c66affSColin Finck */ 414c2c66affSColin Finck NTSTATUS 415c2c66affSColin Finck NTAPI 416c2c66affSColin Finck IoReportTargetDeviceChange(IN PDEVICE_OBJECT PhysicalDeviceObject, 417c2c66affSColin Finck IN PVOID NotificationStructure) 418c2c66affSColin Finck { 419c2c66affSColin Finck KEVENT NotifyEvent; 420c2c66affSColin Finck NTSTATUS Status, NotifyStatus; 421c2c66affSColin Finck PTARGET_DEVICE_CUSTOM_NOTIFICATION notifyStruct = (PTARGET_DEVICE_CUSTOM_NOTIFICATION)NotificationStructure; 422c2c66affSColin Finck 423c2c66affSColin Finck ASSERT(notifyStruct); 424c2c66affSColin Finck 425c2c66affSColin Finck /* Check for valid PDO */ 426c2c66affSColin Finck if (!IopIsValidPhysicalDeviceObject(PhysicalDeviceObject)) 427c2c66affSColin Finck { 428*d6792047SIvan Labutin KeBugCheckEx(PNP_DETECTED_FATAL_ERROR, 0x2, (ULONG_PTR)PhysicalDeviceObject, 0, 0); 429c2c66affSColin Finck } 430c2c66affSColin Finck 431c2c66affSColin Finck /* FileObject must be null. PnP will fill in it */ 432c2c66affSColin Finck ASSERT(notifyStruct->FileObject == NULL); 433c2c66affSColin Finck 434c2c66affSColin Finck /* Do not handle system PnP events */ 435c2c66affSColin Finck if ((RtlCompareMemory(&(notifyStruct->Event), &(GUID_TARGET_DEVICE_QUERY_REMOVE), sizeof(GUID)) != sizeof(GUID)) || 436c2c66affSColin Finck (RtlCompareMemory(&(notifyStruct->Event), &(GUID_TARGET_DEVICE_REMOVE_CANCELLED), sizeof(GUID)) != sizeof(GUID)) || 437c2c66affSColin Finck (RtlCompareMemory(&(notifyStruct->Event), &(GUID_TARGET_DEVICE_REMOVE_COMPLETE), sizeof(GUID)) != sizeof(GUID))) 438c2c66affSColin Finck { 439c2c66affSColin Finck return STATUS_INVALID_DEVICE_REQUEST; 440c2c66affSColin Finck } 441c2c66affSColin Finck 442c2c66affSColin Finck if (notifyStruct->Version != 1) 443c2c66affSColin Finck { 444c2c66affSColin Finck return STATUS_INVALID_DEVICE_REQUEST; 445c2c66affSColin Finck } 446c2c66affSColin Finck 447c2c66affSColin Finck /* Initialize even that will let us know when PnP will have finished notify */ 448c2c66affSColin Finck KeInitializeEvent(&NotifyEvent, NotificationEvent, FALSE); 449c2c66affSColin Finck 450c2c66affSColin Finck Status = PpSetCustomTargetEvent(PhysicalDeviceObject, &NotifyEvent, &NotifyStatus, NULL, NULL, notifyStruct); 451c2c66affSColin Finck /* If no error, wait for the notify to end and return the status of the notify and not of the event */ 452c2c66affSColin Finck if (NT_SUCCESS(Status)) 453c2c66affSColin Finck { 454c2c66affSColin Finck KeWaitForSingleObject(&NotifyEvent, Executive, KernelMode, FALSE, NULL); 455c2c66affSColin Finck Status = NotifyStatus; 456c2c66affSColin Finck } 457c2c66affSColin Finck 458c2c66affSColin Finck return Status; 459c2c66affSColin Finck } 460c2c66affSColin Finck 461c2c66affSColin Finck /* 462c2c66affSColin Finck * @implemented 463c2c66affSColin Finck */ 464c2c66affSColin Finck NTSTATUS 465c2c66affSColin Finck NTAPI 466c2c66affSColin Finck IoReportTargetDeviceChangeAsynchronous(IN PDEVICE_OBJECT PhysicalDeviceObject, 467c2c66affSColin Finck IN PVOID NotificationStructure, 468c2c66affSColin Finck IN PDEVICE_CHANGE_COMPLETE_CALLBACK Callback OPTIONAL, 469c2c66affSColin Finck IN PVOID Context OPTIONAL) 470c2c66affSColin Finck { 471c2c66affSColin Finck PINTERNAL_WORK_QUEUE_ITEM Item = NULL; 472c2c66affSColin Finck PTARGET_DEVICE_CUSTOM_NOTIFICATION notifyStruct = (PTARGET_DEVICE_CUSTOM_NOTIFICATION)NotificationStructure; 473c2c66affSColin Finck 474c2c66affSColin Finck ASSERT(notifyStruct); 475c2c66affSColin Finck 476c2c66affSColin Finck /* Check for valid PDO */ 477c2c66affSColin Finck if (!IopIsValidPhysicalDeviceObject(PhysicalDeviceObject)) 478c2c66affSColin Finck { 479*d6792047SIvan Labutin KeBugCheckEx(PNP_DETECTED_FATAL_ERROR, 0x2, (ULONG_PTR)PhysicalDeviceObject, 0, 0); 480c2c66affSColin Finck } 481c2c66affSColin Finck 482c2c66affSColin Finck /* FileObject must be null. PnP will fill in it */ 483c2c66affSColin Finck ASSERT(notifyStruct->FileObject == NULL); 484c2c66affSColin Finck 485c2c66affSColin Finck /* Do not handle system PnP events */ 486c2c66affSColin Finck if ((RtlCompareMemory(&(notifyStruct->Event), &(GUID_TARGET_DEVICE_QUERY_REMOVE), sizeof(GUID)) != sizeof(GUID)) || 487c2c66affSColin Finck (RtlCompareMemory(&(notifyStruct->Event), &(GUID_TARGET_DEVICE_REMOVE_CANCELLED), sizeof(GUID)) != sizeof(GUID)) || 488c2c66affSColin Finck (RtlCompareMemory(&(notifyStruct->Event), &(GUID_TARGET_DEVICE_REMOVE_COMPLETE), sizeof(GUID)) != sizeof(GUID))) 489c2c66affSColin Finck { 490c2c66affSColin Finck return STATUS_INVALID_DEVICE_REQUEST; 491c2c66affSColin Finck } 492c2c66affSColin Finck 493c2c66affSColin Finck if (notifyStruct->Version != 1) 494c2c66affSColin Finck { 495c2c66affSColin Finck return STATUS_INVALID_DEVICE_REQUEST; 496c2c66affSColin Finck } 497c2c66affSColin Finck 498c2c66affSColin Finck /* We need to store all the data given by the caller with the WorkItem, so use our own struct */ 499c2c66affSColin Finck Item = ExAllocatePoolWithTag(NonPagedPool, sizeof(INTERNAL_WORK_QUEUE_ITEM), ' pP'); 500c2c66affSColin Finck if (!Item) return STATUS_INSUFFICIENT_RESOURCES; 501c2c66affSColin Finck 502c2c66affSColin Finck /* Initialize all stuff */ 503c2c66affSColin Finck ObReferenceObject(PhysicalDeviceObject); 504c2c66affSColin Finck Item->NotificationStructure = notifyStruct; 505c2c66affSColin Finck Item->PhysicalDeviceObject = PhysicalDeviceObject; 506c2c66affSColin Finck Item->Callback = Callback; 507c2c66affSColin Finck Item->Context = Context; 508c2c66affSColin Finck ExInitializeWorkItem(&(Item->WorkItem), IopReportTargetDeviceChangeAsyncWorker, Item); 509c2c66affSColin Finck 510c2c66affSColin Finck /* Finally, queue the item, our work here is done */ 511c2c66affSColin Finck ExQueueWorkItem(&(Item->WorkItem), DelayedWorkQueue); 512c2c66affSColin Finck 513c2c66affSColin Finck return STATUS_PENDING; 514c2c66affSColin Finck } 515