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_OBJECT DriverObject
;
27 PDRIVER_NOTIFICATION_CALLBACK_ROUTINE PnpNotificationProc
;
28 } PNP_NOTIFY_ENTRY
, *PPNP_NOTIFY_ENTRY
;
30 KGUARDED_MUTEX PnpNotifyListLock
;
31 LIST_ENTRY PnpNotifyListHead
;
33 /* FUNCTIONS *****************************************************************/
36 IopNotifyPlugPlayNotification(
37 IN PDEVICE_OBJECT DeviceObject
,
38 IN IO_NOTIFICATION_EVENT_CATEGORY EventCategory
,
40 IN PVOID EventCategoryData1
,
41 IN PVOID EventCategoryData2
)
43 PPNP_NOTIFY_ENTRY ChangeEntry
;
44 PLIST_ENTRY ListEntry
;
45 PVOID NotificationStructure
;
46 BOOLEAN CallCurrentEntry
;
47 UNICODE_STRING GuidString
;
49 PDEVICE_OBJECT EntryDeviceObject
= NULL
;
53 KeAcquireGuardedMutex(&PnpNotifyListLock
);
54 if (IsListEmpty(&PnpNotifyListHead
))
56 KeReleaseGuardedMutex(&PnpNotifyListLock
);
60 switch (EventCategory
)
62 case EventCategoryDeviceInterfaceChange
:
64 PDEVICE_INTERFACE_CHANGE_NOTIFICATION NotificationInfos
;
65 NotificationStructure
= NotificationInfos
= ExAllocatePoolWithTag(
67 sizeof(DEVICE_INTERFACE_CHANGE_NOTIFICATION
),
69 if (!NotificationInfos
)
71 KeReleaseGuardedMutex(&PnpNotifyListLock
);
74 NotificationInfos
->Version
= 1;
75 NotificationInfos
->Size
= sizeof(DEVICE_INTERFACE_CHANGE_NOTIFICATION
);
76 RtlCopyMemory(&NotificationInfos
->Event
, Event
, sizeof(GUID
));
77 RtlCopyMemory(&NotificationInfos
->InterfaceClassGuid
, EventCategoryData1
, sizeof(GUID
));
78 NotificationInfos
->SymbolicLinkName
= (PUNICODE_STRING
)EventCategoryData2
;
79 Status
= RtlStringFromGUID(&NotificationInfos
->InterfaceClassGuid
, &GuidString
);
80 if (!NT_SUCCESS(Status
))
82 KeReleaseGuardedMutex(&PnpNotifyListLock
);
83 ExFreePool(NotificationStructure
);
88 case EventCategoryHardwareProfileChange
:
90 PHWPROFILE_CHANGE_NOTIFICATION NotificationInfos
;
91 NotificationStructure
= NotificationInfos
= ExAllocatePoolWithTag(
93 sizeof(HWPROFILE_CHANGE_NOTIFICATION
),
95 if (!NotificationInfos
)
97 KeReleaseGuardedMutex(&PnpNotifyListLock
);
100 NotificationInfos
->Version
= 1;
101 NotificationInfos
->Size
= sizeof(HWPROFILE_CHANGE_NOTIFICATION
);
102 RtlCopyMemory(&NotificationInfos
->Event
, Event
, sizeof(GUID
));
105 case EventCategoryTargetDeviceChange
:
107 if (Event
!= &GUID_PNP_CUSTOM_NOTIFICATION
)
109 PTARGET_DEVICE_REMOVAL_NOTIFICATION NotificationInfos
;
110 NotificationStructure
= NotificationInfos
= ExAllocatePoolWithTag(
112 sizeof(TARGET_DEVICE_REMOVAL_NOTIFICATION
),
114 if (!NotificationInfos
)
116 KeReleaseGuardedMutex(&PnpNotifyListLock
);
119 NotificationInfos
->Version
= 1;
120 NotificationInfos
->Size
= sizeof(TARGET_DEVICE_REMOVAL_NOTIFICATION
);
121 RtlCopyMemory(&NotificationInfos
->Event
, Event
, sizeof(GUID
));
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 Status
= IoGetRelatedTargetDevice(ChangeEntry
->FileObject
, &EntryDeviceObject
);
180 if (NT_SUCCESS(Status
))
182 if (DeviceObject
== EntryDeviceObject
)
184 if (Event
== &GUID_PNP_CUSTOM_NOTIFICATION
)
186 ((PTARGET_DEVICE_CUSTOM_NOTIFICATION
)NotificationStructure
)->FileObject
= ChangeEntry
->FileObject
;
190 ((PTARGET_DEVICE_REMOVAL_NOTIFICATION
)NotificationStructure
)->FileObject
= ChangeEntry
->FileObject
;
192 CallCurrentEntry
= TRUE
;
198 DPRINT1("IopNotifyPlugPlayNotification(): unknown EventCategory 0x%x UNIMPLEMENTED\n", EventCategory
);
203 /* Move to the next element now, as callback may unregister itself */
204 ListEntry
= ListEntry
->Flink
;
205 /* FIXME: If ListEntry was the last element and that callback registers
206 * new notifications, those won't be checked... */
208 if (CallCurrentEntry
)
210 /* Call entry into new allocated memory */
211 DPRINT("IopNotifyPlugPlayNotification(): found suitable callback %p\n",
214 KeReleaseGuardedMutex(&PnpNotifyListLock
);
215 (ChangeEntry
->PnpNotificationProc
)(
216 NotificationStructure
,
217 ChangeEntry
->Context
);
218 KeAcquireGuardedMutex(&PnpNotifyListLock
);
222 KeReleaseGuardedMutex(&PnpNotifyListLock
);
223 ExFreePoolWithTag(NotificationStructure
, TAG_PNP_NOTIFY
);
224 if (EventCategory
== EventCategoryDeviceInterfaceChange
)
225 RtlFreeUnicodeString(&GuidString
);
228 /* PUBLIC FUNCTIONS **********************************************************/
235 IoPnPDeliverServicePowerNotification(ULONG VetoedPowerOperation OPTIONAL
,
236 ULONG PowerNotification
,
237 ULONG Unknown OPTIONAL
,
249 IoRegisterPlugPlayNotification(IN IO_NOTIFICATION_EVENT_CATEGORY EventCategory
,
250 IN ULONG EventCategoryFlags
,
251 IN PVOID EventCategoryData OPTIONAL
,
252 IN PDRIVER_OBJECT DriverObject
,
253 IN PDRIVER_NOTIFICATION_CALLBACK_ROUTINE CallbackRoutine
,
255 OUT PVOID
*NotificationEntry
)
257 PPNP_NOTIFY_ENTRY Entry
;
258 PWSTR SymbolicLinkList
;
262 DPRINT("%s(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 /* Enumerate SymbolicLinkList */
296 NotificationInfos
.Version
= 1;
297 NotificationInfos
.Size
= sizeof(DEVICE_INTERFACE_CHANGE_NOTIFICATION
);
298 RtlCopyMemory(&NotificationInfos
.Event
,
299 &GUID_DEVICE_INTERFACE_ARRIVAL
,
301 RtlCopyMemory(&NotificationInfos
.InterfaceClassGuid
,
304 NotificationInfos
.SymbolicLinkName
= &SymbolicLinkU
;
306 for (SymbolicLink
= SymbolicLinkList
;
308 SymbolicLink
+= wcslen(SymbolicLink
) + 1)
310 RtlInitUnicodeString(&SymbolicLinkU
, SymbolicLink
);
311 DPRINT("Calling callback routine for %S\n", SymbolicLink
);
312 (*CallbackRoutine
)(&NotificationInfos
, Context
);
315 ExFreePool(SymbolicLinkList
);
319 Entry
->PnpNotificationProc
= CallbackRoutine
;
320 Entry
->EventCategory
= EventCategory
;
321 Entry
->Context
= Context
;
322 Entry
->DriverObject
= DriverObject
;
323 switch (EventCategory
)
325 case EventCategoryDeviceInterfaceChange
:
327 Status
= RtlStringFromGUID(EventCategoryData
, &Entry
->Guid
);
328 if (!NT_SUCCESS(Status
))
330 ExFreePoolWithTag(Entry
, TAG_PNP_NOTIFY
);
331 ObDereferenceObject(DriverObject
);
336 case EventCategoryHardwareProfileChange
:
341 case EventCategoryTargetDeviceChange
:
343 Entry
->FileObject
= (PFILE_OBJECT
)EventCategoryData
;
348 DPRINT1("%s: unknown EventCategory 0x%x UNIMPLEMENTED\n",
349 __FUNCTION__
, EventCategory
);
354 KeAcquireGuardedMutex(&PnpNotifyListLock
);
355 InsertHeadList(&PnpNotifyListHead
,
356 &Entry
->PnpNotifyList
);
357 KeReleaseGuardedMutex(&PnpNotifyListLock
);
359 DPRINT("%s returns NotificationEntry %p\n", __FUNCTION__
, Entry
);
361 *NotificationEntry
= Entry
;
363 return STATUS_SUCCESS
;
371 IoUnregisterPlugPlayNotification(IN PVOID NotificationEntry
)
373 PPNP_NOTIFY_ENTRY Entry
;
376 Entry
= (PPNP_NOTIFY_ENTRY
)NotificationEntry
;
377 DPRINT("%s(NotificationEntry %p) called\n", __FUNCTION__
, Entry
);
379 KeAcquireGuardedMutex(&PnpNotifyListLock
);
380 RemoveEntryList(&Entry
->PnpNotifyList
);
381 KeReleaseGuardedMutex(&PnpNotifyListLock
);
383 RtlFreeUnicodeString(&Entry
->Guid
);
385 ObDereferenceObject(Entry
->DriverObject
);
387 ExFreePoolWithTag(Entry
, TAG_PNP_NOTIFY
);
389 return STATUS_SUCCESS
;