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)
10 /* INCLUDES ******************************************************************/
16 /* TYPES *******************************************************************/
18 typedef struct _PNP_NOTIFY_ENTRY
20 LIST_ENTRY PnpNotifyList
;
21 IO_NOTIFICATION_EVENT_CATEGORY EventCategory
;
24 PFILE_OBJECT FileObject
;
25 PDRIVER_NOTIFICATION_CALLBACK_ROUTINE PnpNotificationProc
;
26 } PNP_NOTIFY_ENTRY
, *PPNP_NOTIFY_ENTRY
;
28 KGUARDED_MUTEX PnpNotifyListLock
;
29 LIST_ENTRY PnpNotifyListHead
;
31 /* FUNCTIONS *****************************************************************/
34 IopNotifyPlugPlayNotification(
35 IN PDEVICE_OBJECT DeviceObject
,
36 IN IO_NOTIFICATION_EVENT_CATEGORY EventCategory
,
38 IN PVOID EventCategoryData1
,
39 IN PVOID EventCategoryData2
)
41 PPNP_NOTIFY_ENTRY ChangeEntry
;
42 PLIST_ENTRY ListEntry
;
43 PVOID NotificationStructure
;
44 BOOLEAN CallCurrentEntry
;
45 UNICODE_STRING GuidString
;
50 KeAcquireGuardedMutex(&PnpNotifyListLock
);
51 if (IsListEmpty(&PnpNotifyListHead
))
53 KeReleaseGuardedMutex(&PnpNotifyListLock
);
57 switch (EventCategory
)
59 case EventCategoryDeviceInterfaceChange
:
61 PDEVICE_INTERFACE_CHANGE_NOTIFICATION NotificationInfos
;
62 NotificationStructure
= NotificationInfos
= ExAllocatePoolWithTag(
64 sizeof(DEVICE_INTERFACE_CHANGE_NOTIFICATION
),
66 if (!NotificationInfos
)
68 KeReleaseGuardedMutex(&PnpNotifyListLock
);
71 NotificationInfos
->Version
= 1;
72 NotificationInfos
->Size
= sizeof(DEVICE_INTERFACE_CHANGE_NOTIFICATION
);
73 RtlCopyMemory(&NotificationInfos
->Event
, Event
, sizeof(GUID
));
74 RtlCopyMemory(&NotificationInfos
->InterfaceClassGuid
, EventCategoryData1
, sizeof(GUID
));
75 NotificationInfos
->SymbolicLinkName
= (PUNICODE_STRING
)EventCategoryData2
;
76 Status
= RtlStringFromGUID(&NotificationInfos
->InterfaceClassGuid
, &GuidString
);
77 if (!NT_SUCCESS(Status
))
79 KeReleaseGuardedMutex(&PnpNotifyListLock
);
80 ExFreePool(NotificationStructure
);
85 case EventCategoryHardwareProfileChange
:
87 PHWPROFILE_CHANGE_NOTIFICATION NotificationInfos
;
88 NotificationStructure
= NotificationInfos
= ExAllocatePoolWithTag(
90 sizeof(HWPROFILE_CHANGE_NOTIFICATION
),
92 if (!NotificationInfos
)
94 KeReleaseGuardedMutex(&PnpNotifyListLock
);
97 NotificationInfos
->Version
= 1;
98 NotificationInfos
->Size
= sizeof(HWPROFILE_CHANGE_NOTIFICATION
);
99 RtlCopyMemory(&NotificationInfos
->Event
, Event
, sizeof(GUID
));
102 case EventCategoryTargetDeviceChange
:
104 PTARGET_DEVICE_REMOVAL_NOTIFICATION NotificationInfos
;
105 NotificationStructure
= NotificationInfos
= ExAllocatePoolWithTag(
107 sizeof(TARGET_DEVICE_REMOVAL_NOTIFICATION
),
109 if (!NotificationInfos
)
111 KeReleaseGuardedMutex(&PnpNotifyListLock
);
114 NotificationInfos
->Version
= 1;
115 NotificationInfos
->Size
= sizeof(TARGET_DEVICE_REMOVAL_NOTIFICATION
);
116 RtlCopyMemory(&NotificationInfos
->Event
, Event
, sizeof(GUID
));
117 NotificationInfos
->FileObject
= (PFILE_OBJECT
)EventCategoryData1
;
122 DPRINT1("IopNotifyPlugPlayNotification(): unknown EventCategory 0x%x UNIMPLEMENTED\n", EventCategory
);
123 KeReleaseGuardedMutex(&PnpNotifyListLock
);
128 /* Loop through procedures registred in PnpNotifyListHead
129 * list to find those that meet some criteria.
131 ListEntry
= PnpNotifyListHead
.Flink
;
132 while (ListEntry
!= &PnpNotifyListHead
)
134 ChangeEntry
= CONTAINING_RECORD(ListEntry
, PNP_NOTIFY_ENTRY
, PnpNotifyList
);
135 CallCurrentEntry
= FALSE
;
137 if (ChangeEntry
->EventCategory
!= EventCategory
)
139 ListEntry
= ListEntry
->Flink
;
143 switch (EventCategory
)
145 case EventCategoryDeviceInterfaceChange
:
147 if (RtlCompareUnicodeString(&ChangeEntry
->Guid
, &GuidString
, FALSE
) == 0)
149 CallCurrentEntry
= TRUE
;
153 case EventCategoryHardwareProfileChange
:
155 CallCurrentEntry
= TRUE
;
158 case EventCategoryTargetDeviceChange
:
160 if (ChangeEntry
->FileObject
== (PFILE_OBJECT
)EventCategoryData1
)
161 CallCurrentEntry
= TRUE
;
165 DPRINT1("IopNotifyPlugPlayNotification(): unknown EventCategory 0x%x UNIMPLEMENTED\n", EventCategory
);
170 /* Move to the next element now, as callback may unregister itself */
171 ListEntry
= ListEntry
->Flink
;
172 /* FIXME: If ListEntry was the last element and that callback registers
173 * new notifications, those won't be checked... */
175 if (CallCurrentEntry
)
177 /* Call entry into new allocated memory */
178 DPRINT("IopNotifyPlugPlayNotification(): found suitable callback %p\n",
181 KeReleaseGuardedMutex(&PnpNotifyListLock
);
182 (ChangeEntry
->PnpNotificationProc
)(
183 NotificationStructure
,
184 ChangeEntry
->Context
);
185 KeAcquireGuardedMutex(&PnpNotifyListLock
);
189 KeReleaseGuardedMutex(&PnpNotifyListLock
);
190 ExFreePoolWithTag(NotificationStructure
, TAG_PNP_NOTIFY
);
191 if (EventCategory
== EventCategoryDeviceInterfaceChange
)
192 RtlFreeUnicodeString(&GuidString
);
195 /* PUBLIC FUNCTIONS **********************************************************/
202 IoPnPDeliverServicePowerNotification(ULONG VetoedPowerOperation OPTIONAL
,
203 ULONG PowerNotification
,
204 ULONG Unknown OPTIONAL
,
216 IoRegisterPlugPlayNotification(IN IO_NOTIFICATION_EVENT_CATEGORY EventCategory
,
217 IN ULONG EventCategoryFlags
,
218 IN PVOID EventCategoryData OPTIONAL
,
219 IN PDRIVER_OBJECT DriverObject
,
220 IN PDRIVER_NOTIFICATION_CALLBACK_ROUTINE CallbackRoutine
,
222 OUT PVOID
*NotificationEntry
)
224 PPNP_NOTIFY_ENTRY Entry
;
225 PWSTR SymbolicLinkList
;
229 DPRINT("__FUNCTION__(EventCategory 0x%x, EventCategoryFlags 0x%lx, DriverObject %p) called.\n",
234 ObReferenceObject(DriverObject
);
236 /* Try to allocate entry for notification before sending any notification */
237 Entry
= ExAllocatePoolWithTag(NonPagedPool
,
238 sizeof(PNP_NOTIFY_ENTRY
),
243 DPRINT("ExAllocatePool() failed\n");
244 ObDereferenceObject(DriverObject
);
245 return STATUS_INSUFFICIENT_RESOURCES
;
248 if (EventCategory
== EventCategoryDeviceInterfaceChange
&&
249 EventCategoryFlags
& PNPNOTIFY_DEVICE_INTERFACE_INCLUDE_EXISTING_INTERFACES
)
251 DEVICE_INTERFACE_CHANGE_NOTIFICATION NotificationInfos
;
252 UNICODE_STRING SymbolicLinkU
;
255 Status
= IoGetDeviceInterfaces((LPGUID
)EventCategoryData
,
256 NULL
, /* PhysicalDeviceObject OPTIONAL */
259 if (!NT_SUCCESS(Status
))
261 DPRINT("IoGetDeviceInterfaces() failed with status 0x%08lx\n",
263 ExFreePoolWithTag(Entry
, TAG_PNP_NOTIFY
);
264 ObDereferenceObject(DriverObject
);
268 /* Enumerate SymbolicLinkList */
269 NotificationInfos
.Version
= 1;
270 NotificationInfos
.Size
= sizeof(DEVICE_INTERFACE_CHANGE_NOTIFICATION
);
271 RtlCopyMemory(&NotificationInfos
.Event
,
272 &GUID_DEVICE_INTERFACE_ARRIVAL
,
274 RtlCopyMemory(&NotificationInfos
.InterfaceClassGuid
,
277 NotificationInfos
.SymbolicLinkName
= &SymbolicLinkU
;
279 for (SymbolicLink
= SymbolicLinkList
;
281 SymbolicLink
+= wcslen(SymbolicLink
) + 1)
283 RtlInitUnicodeString(&SymbolicLinkU
, SymbolicLink
);
284 DPRINT("Calling callback routine for %S\n", SymbolicLink
);
285 (*CallbackRoutine
)(&NotificationInfos
, Context
);
288 ExFreePool(SymbolicLinkList
);
291 Entry
->PnpNotificationProc
= CallbackRoutine
;
292 Entry
->EventCategory
= EventCategory
;
293 Entry
->Context
= Context
;
294 switch (EventCategory
)
296 case EventCategoryDeviceInterfaceChange
:
298 Status
= RtlStringFromGUID(EventCategoryData
, &Entry
->Guid
);
299 if (!NT_SUCCESS(Status
))
301 ExFreePoolWithTag(Entry
, TAG_PNP_NOTIFY
);
302 ObDereferenceObject(DriverObject
);
307 case EventCategoryHardwareProfileChange
:
312 case EventCategoryTargetDeviceChange
:
314 Entry
->FileObject
= (PFILE_OBJECT
)EventCategoryData
;
319 DPRINT1("__FUNCTION__(): unknown EventCategory 0x%x UNIMPLEMENTED\n",
325 KeAcquireGuardedMutex(&PnpNotifyListLock
);
326 InsertHeadList(&PnpNotifyListHead
,
327 &Entry
->PnpNotifyList
);
328 KeReleaseGuardedMutex(&PnpNotifyListLock
);
330 DPRINT("IoRegisterPlugPlayNotification() returns NotificationEntry %p\n",
333 *NotificationEntry
= Entry
;
335 return STATUS_SUCCESS
;
343 IoUnregisterPlugPlayNotification(IN PVOID NotificationEntry
)
345 PPNP_NOTIFY_ENTRY Entry
;
348 Entry
= (PPNP_NOTIFY_ENTRY
)NotificationEntry
;
349 DPRINT("__FUNCTION__(NotificationEntry %p) called\n", Entry
);
351 KeAcquireGuardedMutex(&PnpNotifyListLock
);
352 RtlFreeUnicodeString(&Entry
->Guid
);
353 RemoveEntryList(&Entry
->PnpNotifyList
);
354 KeReleaseGuardedMutex(&PnpNotifyListLock
);
356 return STATUS_SUCCESS
;