2 * PROJECT: ReactOS Kernel
3 * COPYRIGHT: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/io/pnpmgr/pnpnotify.c
5 * PURPOSE: Plug & Play notification functions
6 * PROGRAMMERS: Filip Navara (xnavara@volny.cz)
7 * Hervé Poussineau (hpoussin@reactos.org)
11 /* INCLUDES ******************************************************************/
17 /* TYPES *******************************************************************/
19 typedef struct _PNP_NOTIFY_ENTRY
21 LIST_ENTRY PnpNotifyList
;
22 IO_NOTIFICATION_EVENT_CATEGORY EventCategory
;
25 PFILE_OBJECT FileObject
;
26 PDRIVER_NOTIFICATION_CALLBACK_ROUTINE PnpNotificationProc
;
27 } PNP_NOTIFY_ENTRY
, *PPNP_NOTIFY_ENTRY
;
29 KGUARDED_MUTEX PnpNotifyListLock
;
30 LIST_ENTRY PnpNotifyListHead
;
32 /* FUNCTIONS *****************************************************************/
35 IopNotifyPlugPlayNotification(
36 IN PDEVICE_OBJECT DeviceObject
,
37 IN IO_NOTIFICATION_EVENT_CATEGORY EventCategory
,
39 IN PVOID EventCategoryData1
,
40 IN PVOID EventCategoryData2
)
42 PPNP_NOTIFY_ENTRY ChangeEntry
;
43 PLIST_ENTRY ListEntry
;
44 PVOID NotificationStructure
;
45 BOOLEAN CallCurrentEntry
;
46 UNICODE_STRING GuidString
;
48 PDEVICE_OBJECT EntryDeviceObject
= NULL
;
52 KeAcquireGuardedMutex(&PnpNotifyListLock
);
53 if (IsListEmpty(&PnpNotifyListHead
))
55 KeReleaseGuardedMutex(&PnpNotifyListLock
);
59 switch (EventCategory
)
61 case EventCategoryDeviceInterfaceChange
:
63 PDEVICE_INTERFACE_CHANGE_NOTIFICATION NotificationInfos
;
64 NotificationStructure
= NotificationInfos
= ExAllocatePoolWithTag(
66 sizeof(DEVICE_INTERFACE_CHANGE_NOTIFICATION
),
68 if (!NotificationInfos
)
70 KeReleaseGuardedMutex(&PnpNotifyListLock
);
73 NotificationInfos
->Version
= 1;
74 NotificationInfos
->Size
= sizeof(DEVICE_INTERFACE_CHANGE_NOTIFICATION
);
75 RtlCopyMemory(&NotificationInfos
->Event
, Event
, sizeof(GUID
));
76 RtlCopyMemory(&NotificationInfos
->InterfaceClassGuid
, EventCategoryData1
, sizeof(GUID
));
77 NotificationInfos
->SymbolicLinkName
= (PUNICODE_STRING
)EventCategoryData2
;
78 Status
= RtlStringFromGUID(&NotificationInfos
->InterfaceClassGuid
, &GuidString
);
79 if (!NT_SUCCESS(Status
))
81 KeReleaseGuardedMutex(&PnpNotifyListLock
);
82 ExFreePool(NotificationStructure
);
87 case EventCategoryHardwareProfileChange
:
89 PHWPROFILE_CHANGE_NOTIFICATION NotificationInfos
;
90 NotificationStructure
= NotificationInfos
= ExAllocatePoolWithTag(
92 sizeof(HWPROFILE_CHANGE_NOTIFICATION
),
94 if (!NotificationInfos
)
96 KeReleaseGuardedMutex(&PnpNotifyListLock
);
99 NotificationInfos
->Version
= 1;
100 NotificationInfos
->Size
= sizeof(HWPROFILE_CHANGE_NOTIFICATION
);
101 RtlCopyMemory(&NotificationInfos
->Event
, Event
, sizeof(GUID
));
104 case EventCategoryTargetDeviceChange
:
106 if (Event
!= &GUID_PNP_CUSTOM_NOTIFICATION
)
108 PTARGET_DEVICE_REMOVAL_NOTIFICATION NotificationInfos
;
109 NotificationStructure
= NotificationInfos
= ExAllocatePoolWithTag(
111 sizeof(TARGET_DEVICE_REMOVAL_NOTIFICATION
),
113 if (!NotificationInfos
)
115 KeReleaseGuardedMutex(&PnpNotifyListLock
);
118 NotificationInfos
->Version
= 1;
119 NotificationInfos
->Size
= sizeof(TARGET_DEVICE_REMOVAL_NOTIFICATION
);
120 RtlCopyMemory(&NotificationInfos
->Event
, Event
, sizeof(GUID
));
121 NotificationInfos
->FileObject
= (PFILE_OBJECT
)EventCategoryData1
;
125 PTARGET_DEVICE_CUSTOM_NOTIFICATION NotificationInfos
;
126 NotificationStructure
= NotificationInfos
= ExAllocatePoolWithTag(
128 sizeof(TARGET_DEVICE_CUSTOM_NOTIFICATION
),
130 if (!NotificationInfos
)
132 KeReleaseGuardedMutex(&PnpNotifyListLock
);
135 RtlCopyMemory(NotificationInfos
, EventCategoryData1
, sizeof(TARGET_DEVICE_CUSTOM_NOTIFICATION
));
141 DPRINT1("IopNotifyPlugPlayNotification(): unknown EventCategory 0x%x UNIMPLEMENTED\n", EventCategory
);
142 KeReleaseGuardedMutex(&PnpNotifyListLock
);
147 /* Loop through procedures registred in PnpNotifyListHead
148 * list to find those that meet some criteria.
150 ListEntry
= PnpNotifyListHead
.Flink
;
151 while (ListEntry
!= &PnpNotifyListHead
)
153 ChangeEntry
= CONTAINING_RECORD(ListEntry
, PNP_NOTIFY_ENTRY
, PnpNotifyList
);
154 CallCurrentEntry
= FALSE
;
156 if (ChangeEntry
->EventCategory
!= EventCategory
)
158 ListEntry
= ListEntry
->Flink
;
162 switch (EventCategory
)
164 case EventCategoryDeviceInterfaceChange
:
166 if (RtlCompareUnicodeString(&ChangeEntry
->Guid
, &GuidString
, FALSE
) == 0)
168 CallCurrentEntry
= TRUE
;
172 case EventCategoryHardwareProfileChange
:
174 CallCurrentEntry
= TRUE
;
177 case EventCategoryTargetDeviceChange
:
179 if (Event
!= &GUID_PNP_CUSTOM_NOTIFICATION
)
181 if (ChangeEntry
->FileObject
== (PFILE_OBJECT
)EventCategoryData1
)
182 CallCurrentEntry
= TRUE
;
186 Status
= IoGetRelatedTargetDevice(ChangeEntry
->FileObject
, &EntryDeviceObject
);
187 if (NT_SUCCESS(Status
))
189 if (DeviceObject
== EntryDeviceObject
)
191 ((PTARGET_DEVICE_CUSTOM_NOTIFICATION
)NotificationStructure
)->FileObject
= ChangeEntry
->FileObject
;
192 CallCurrentEntry
= TRUE
;
199 DPRINT1("IopNotifyPlugPlayNotification(): unknown EventCategory 0x%x UNIMPLEMENTED\n", EventCategory
);
204 /* Move to the next element now, as callback may unregister itself */
205 ListEntry
= ListEntry
->Flink
;
206 /* FIXME: If ListEntry was the last element and that callback registers
207 * new notifications, those won't be checked... */
209 if (CallCurrentEntry
)
211 /* Call entry into new allocated memory */
212 DPRINT("IopNotifyPlugPlayNotification(): found suitable callback %p\n",
215 KeReleaseGuardedMutex(&PnpNotifyListLock
);
216 (ChangeEntry
->PnpNotificationProc
)(
217 NotificationStructure
,
218 ChangeEntry
->Context
);
219 KeAcquireGuardedMutex(&PnpNotifyListLock
);
223 KeReleaseGuardedMutex(&PnpNotifyListLock
);
224 ExFreePoolWithTag(NotificationStructure
, TAG_PNP_NOTIFY
);
225 if (EventCategory
== EventCategoryDeviceInterfaceChange
)
226 RtlFreeUnicodeString(&GuidString
);
229 /* PUBLIC FUNCTIONS **********************************************************/
236 IoPnPDeliverServicePowerNotification(ULONG VetoedPowerOperation OPTIONAL
,
237 ULONG PowerNotification
,
238 ULONG Unknown OPTIONAL
,
250 IoRegisterPlugPlayNotification(IN IO_NOTIFICATION_EVENT_CATEGORY EventCategory
,
251 IN ULONG EventCategoryFlags
,
252 IN PVOID EventCategoryData OPTIONAL
,
253 IN PDRIVER_OBJECT DriverObject
,
254 IN PDRIVER_NOTIFICATION_CALLBACK_ROUTINE CallbackRoutine
,
256 OUT PVOID
*NotificationEntry
)
258 PPNP_NOTIFY_ENTRY Entry
;
259 PWSTR SymbolicLinkList
;
263 DPRINT("__FUNCTION__(EventCategory 0x%x, EventCategoryFlags 0x%lx, DriverObject %p) called.\n",
268 ObReferenceObject(DriverObject
);
270 /* Try to allocate entry for notification before sending any notification */
271 Entry
= ExAllocatePoolWithTag(NonPagedPool
,
272 sizeof(PNP_NOTIFY_ENTRY
),
277 DPRINT("ExAllocatePool() failed\n");
278 ObDereferenceObject(DriverObject
);
279 return STATUS_INSUFFICIENT_RESOURCES
;
282 if (EventCategory
== EventCategoryDeviceInterfaceChange
&&
283 EventCategoryFlags
& PNPNOTIFY_DEVICE_INTERFACE_INCLUDE_EXISTING_INTERFACES
)
285 DEVICE_INTERFACE_CHANGE_NOTIFICATION NotificationInfos
;
286 UNICODE_STRING SymbolicLinkU
;
289 Status
= IoGetDeviceInterfaces((LPGUID
)EventCategoryData
,
290 NULL
, /* PhysicalDeviceObject OPTIONAL */
293 if (!NT_SUCCESS(Status
))
295 DPRINT("IoGetDeviceInterfaces() failed with status 0x%08lx\n",
297 ExFreePoolWithTag(Entry
, TAG_PNP_NOTIFY
);
298 ObDereferenceObject(DriverObject
);
302 /* Enumerate SymbolicLinkList */
303 NotificationInfos
.Version
= 1;
304 NotificationInfos
.Size
= sizeof(DEVICE_INTERFACE_CHANGE_NOTIFICATION
);
305 RtlCopyMemory(&NotificationInfos
.Event
,
306 &GUID_DEVICE_INTERFACE_ARRIVAL
,
308 RtlCopyMemory(&NotificationInfos
.InterfaceClassGuid
,
311 NotificationInfos
.SymbolicLinkName
= &SymbolicLinkU
;
313 for (SymbolicLink
= SymbolicLinkList
;
315 SymbolicLink
+= wcslen(SymbolicLink
) + 1)
317 RtlInitUnicodeString(&SymbolicLinkU
, SymbolicLink
);
318 DPRINT("Calling callback routine for %S\n", SymbolicLink
);
319 (*CallbackRoutine
)(&NotificationInfos
, Context
);
322 ExFreePool(SymbolicLinkList
);
325 Entry
->PnpNotificationProc
= CallbackRoutine
;
326 Entry
->EventCategory
= EventCategory
;
327 Entry
->Context
= Context
;
328 switch (EventCategory
)
330 case EventCategoryDeviceInterfaceChange
:
332 Status
= RtlStringFromGUID(EventCategoryData
, &Entry
->Guid
);
333 if (!NT_SUCCESS(Status
))
335 ExFreePoolWithTag(Entry
, TAG_PNP_NOTIFY
);
336 ObDereferenceObject(DriverObject
);
341 case EventCategoryHardwareProfileChange
:
346 case EventCategoryTargetDeviceChange
:
348 Entry
->FileObject
= (PFILE_OBJECT
)EventCategoryData
;
353 DPRINT1("__FUNCTION__(): unknown EventCategory 0x%x UNIMPLEMENTED\n",
359 KeAcquireGuardedMutex(&PnpNotifyListLock
);
360 InsertHeadList(&PnpNotifyListHead
,
361 &Entry
->PnpNotifyList
);
362 KeReleaseGuardedMutex(&PnpNotifyListLock
);
364 DPRINT("IoRegisterPlugPlayNotification() returns NotificationEntry %p\n",
367 *NotificationEntry
= Entry
;
369 return STATUS_SUCCESS
;
377 IoUnregisterPlugPlayNotification(IN PVOID NotificationEntry
)
379 PPNP_NOTIFY_ENTRY Entry
;
382 Entry
= (PPNP_NOTIFY_ENTRY
)NotificationEntry
;
383 DPRINT("__FUNCTION__(NotificationEntry %p) called\n", Entry
);
385 KeAcquireGuardedMutex(&PnpNotifyListLock
);
386 RtlFreeUnicodeString(&Entry
->Guid
);
387 RemoveEntryList(&Entry
->PnpNotifyList
);
388 KeReleaseGuardedMutex(&PnpNotifyListLock
);
390 return STATUS_SUCCESS
;