xref: /reactos/ntoskrnl/io/pnpmgr/pnpreport.c (revision d6792047)
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