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 ExFreePoolWithTag(NotificationStructure
, TAG_PNP_NOTIFY
);
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
;
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("%s(EventCategory 0x%x, EventCategoryFlags 0x%lx, DriverObject %p) called.\n",
269 ObReferenceObject(DriverObject
);
271 /* Try to allocate entry for notification before sending any notification */
272 Entry
= ExAllocatePoolWithTag(NonPagedPool
,
273 sizeof(PNP_NOTIFY_ENTRY
),
278 DPRINT("ExAllocatePool() failed\n");
279 ObDereferenceObject(DriverObject
);
280 return STATUS_INSUFFICIENT_RESOURCES
;
283 if (EventCategory
== EventCategoryDeviceInterfaceChange
&&
284 EventCategoryFlags
& PNPNOTIFY_DEVICE_INTERFACE_INCLUDE_EXISTING_INTERFACES
)
286 DEVICE_INTERFACE_CHANGE_NOTIFICATION NotificationInfos
;
287 UNICODE_STRING SymbolicLinkU
;
290 Status
= IoGetDeviceInterfaces((LPGUID
)EventCategoryData
,
291 NULL
, /* PhysicalDeviceObject OPTIONAL */
294 if (NT_SUCCESS(Status
))
296 /* Enumerate SymbolicLinkList */
297 NotificationInfos
.Version
= 1;
298 NotificationInfos
.Size
= sizeof(DEVICE_INTERFACE_CHANGE_NOTIFICATION
);
299 RtlCopyMemory(&NotificationInfos
.Event
,
300 &GUID_DEVICE_INTERFACE_ARRIVAL
,
302 RtlCopyMemory(&NotificationInfos
.InterfaceClassGuid
,
305 NotificationInfos
.SymbolicLinkName
= &SymbolicLinkU
;
307 for (SymbolicLink
= SymbolicLinkList
;
309 SymbolicLink
+= wcslen(SymbolicLink
) + 1)
311 RtlInitUnicodeString(&SymbolicLinkU
, SymbolicLink
);
312 DPRINT("Calling callback routine for %S\n", SymbolicLink
);
313 (*CallbackRoutine
)(&NotificationInfos
, Context
);
316 ExFreePool(SymbolicLinkList
);
320 Entry
->PnpNotificationProc
= CallbackRoutine
;
321 Entry
->EventCategory
= EventCategory
;
322 Entry
->Context
= Context
;
323 Entry
->DriverObject
= DriverObject
;
324 switch (EventCategory
)
326 case EventCategoryDeviceInterfaceChange
:
328 Status
= RtlStringFromGUID(EventCategoryData
, &Entry
->Guid
);
329 if (!NT_SUCCESS(Status
))
331 ExFreePoolWithTag(Entry
, TAG_PNP_NOTIFY
);
332 ObDereferenceObject(DriverObject
);
337 case EventCategoryHardwareProfileChange
:
342 case EventCategoryTargetDeviceChange
:
344 Entry
->FileObject
= (PFILE_OBJECT
)EventCategoryData
;
349 DPRINT1("%s: unknown EventCategory 0x%x UNIMPLEMENTED\n",
350 __FUNCTION__
, EventCategory
);
355 KeAcquireGuardedMutex(&PnpNotifyListLock
);
356 InsertHeadList(&PnpNotifyListHead
,
357 &Entry
->PnpNotifyList
);
358 KeReleaseGuardedMutex(&PnpNotifyListLock
);
360 DPRINT("%s returns NotificationEntry %p\n", __FUNCTION__
, Entry
);
362 *NotificationEntry
= Entry
;
364 return STATUS_SUCCESS
;
372 IoUnregisterPlugPlayNotification(IN PVOID NotificationEntry
)
374 PPNP_NOTIFY_ENTRY Entry
;
377 Entry
= (PPNP_NOTIFY_ENTRY
)NotificationEntry
;
378 DPRINT("%s(NotificationEntry %p) called\n", __FUNCTION__
, Entry
);
380 KeAcquireGuardedMutex(&PnpNotifyListLock
);
381 RemoveEntryList(&Entry
->PnpNotifyList
);
382 KeReleaseGuardedMutex(&PnpNotifyListLock
);
384 RtlFreeUnicodeString(&Entry
->Guid
);
386 ObDereferenceObject(Entry
->DriverObject
);
388 ExFreePoolWithTag(Entry
, TAG_PNP_NOTIFY
);
390 return STATUS_SUCCESS
;