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