3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/io/pnpnotify.c
6 * PURPOSE: Plug & Play notification functions
8 * PROGRAMMERS: Filip Navara (xnavara@volny.cz)
9 * Hervé Poussineau (hpoussin@reactos.com)
12 /* INCLUDES ******************************************************************/
16 #include <internal/debug.h>
18 /* TYPES *******************************************************************/
20 typedef struct _PNP_NOTIFY_ENTRY
22 LIST_ENTRY PnpNotifyList
;
23 IO_NOTIFICATION_EVENT_CATEGORY EventCategory
;
26 PFILE_OBJECT FileObject
;
27 PDRIVER_NOTIFICATION_CALLBACK_ROUTINE PnpNotificationProc
;
28 } PNP_NOTIFY_ENTRY
, *PPNP_NOTIFY_ENTRY
;
30 static KGUARDED_MUTEX PnpNotifyListLock
;
31 static LIST_ENTRY PnpNotifyListHead
;
33 #define TAG_PNP_NOTIFY TAG('P', 'n', 'P', 'N')
35 /* FUNCTIONS *****************************************************************/
42 IoPnPDeliverServicePowerNotification(
43 ULONG VetoedPowerOperation OPTIONAL
,
44 ULONG PowerNotification
,
45 ULONG Unknown OPTIONAL
,
58 IoRegisterPlugPlayNotification(
59 IN IO_NOTIFICATION_EVENT_CATEGORY EventCategory
,
60 IN ULONG EventCategoryFlags
,
61 IN PVOID EventCategoryData OPTIONAL
,
62 IN PDRIVER_OBJECT DriverObject
,
63 IN PDRIVER_NOTIFICATION_CALLBACK_ROUTINE CallbackRoutine
,
65 OUT PVOID
*NotificationEntry
)
67 PPNP_NOTIFY_ENTRY Entry
;
68 PWSTR SymbolicLinkList
;
73 DPRINT("IoRegisterPlugPlayNotification(EventCategory 0x%x, EventCategoryFlags 0x%lx, DriverObject %p) called.\n",
78 ObReferenceObject(DriverObject
);
80 /* Try to allocate entry for notification before sending any notification */
81 Entry
= ExAllocatePoolWithTag(
83 sizeof(PNP_NOTIFY_ENTRY
),
87 DPRINT("ExAllocatePool() failed\n");
88 ObDereferenceObject(DriverObject
);
89 return STATUS_INSUFFICIENT_RESOURCES
;
92 if (EventCategory
== EventCategoryTargetDeviceChange
93 && EventCategoryFlags
& PNPNOTIFY_DEVICE_INTERFACE_INCLUDE_EXISTING_INTERFACES
)
95 Status
= IoGetDeviceInterfaces(
96 (LPGUID
)EventCategoryData
,
97 NULL
, /* PhysicalDeviceObject OPTIONAL */
100 if (!NT_SUCCESS(Status
))
102 DPRINT("IoGetDeviceInterfaces() failed with status 0x%08lx\n", Status
);
103 ExFreePoolWithTag(Entry
, TAG_PNP_NOTIFY
);
104 ObDereferenceObject(DriverObject
);
107 /* FIXME: enumerate SymbolicLinkList */
108 DPRINT1("IoRegisterPlugPlayNotification(): need to send notifications for existing interfaces!\n");
109 ExFreePool(SymbolicLinkList
);
112 Entry
->PnpNotificationProc
= CallbackRoutine
;
113 Entry
->EventCategory
= EventCategory
;
114 Entry
->Context
= Context
;
115 switch (EventCategory
)
117 case EventCategoryDeviceInterfaceChange
:
119 Status
= RtlStringFromGUID(EventCategoryData
, &Entry
->Guid
);
120 if (!NT_SUCCESS(Status
))
122 ExFreePoolWithTag(Entry
, TAG_PNP_NOTIFY
);
123 ObDereferenceObject(DriverObject
);
128 case EventCategoryHardwareProfileChange
:
133 case EventCategoryTargetDeviceChange
:
135 Entry
->FileObject
= (PFILE_OBJECT
)EventCategoryData
;
140 DPRINT1("IoRegisterPlugPlayNotification(): unknown EventCategory 0x%x UNIMPLEMENTED\n", EventCategory
);
145 KeAcquireGuardedMutex(&PnpNotifyListLock
);
146 InsertHeadList(&PnpNotifyListHead
,
147 &Entry
->PnpNotifyList
);
148 KeReleaseGuardedMutex(&PnpNotifyListLock
);
150 DPRINT("IoRegisterPlugPlayNotification() returns NotificationEntry %p\n",
152 *NotificationEntry
= Entry
;
153 return STATUS_SUCCESS
;
161 IoUnregisterPlugPlayNotification(
162 IN PVOID NotificationEntry
)
164 PPNP_NOTIFY_ENTRY Entry
;
168 Entry
= (PPNP_NOTIFY_ENTRY
)NotificationEntry
;
169 DPRINT("IoUnregisterPlugPlayNotification(NotificationEntry %p) called\n",
172 KeAcquireGuardedMutex(&PnpNotifyListLock
);
173 RtlFreeUnicodeString(&Entry
->Guid
);
174 RemoveEntryList(&Entry
->PnpNotifyList
);
175 KeReleaseGuardedMutex(&PnpNotifyListLock
);
177 return STATUS_SUCCESS
;
181 IopNotifyPlugPlayNotification(
182 IN PDEVICE_OBJECT DeviceObject
,
183 IN IO_NOTIFICATION_EVENT_CATEGORY EventCategory
,
185 IN PVOID EventCategoryData1
,
186 IN PVOID EventCategoryData2
)
188 PPNP_NOTIFY_ENTRY ChangeEntry
;
190 PVOID NotificationStructure
;
191 BOOLEAN CallCurrentEntry
;
193 ASSERT(DeviceObject
);
195 KeAcquireGuardedMutex(&PnpNotifyListLock
);
196 if (IsListEmpty(&PnpNotifyListHead
))
198 KeReleaseGuardedMutex(&PnpNotifyListLock
);
202 switch (EventCategory
)
204 case EventCategoryDeviceInterfaceChange
:
206 PDEVICE_INTERFACE_CHANGE_NOTIFICATION NotificationInfos
;
207 NotificationStructure
= NotificationInfos
= ExAllocatePoolWithTag(
209 sizeof(DEVICE_INTERFACE_CHANGE_NOTIFICATION
),
211 NotificationInfos
->Version
= 1;
212 NotificationInfos
->Size
= sizeof(DEVICE_INTERFACE_CHANGE_NOTIFICATION
);
213 RtlCopyMemory(&NotificationInfos
->Event
, Event
, sizeof(GUID
));
214 RtlCopyMemory(&NotificationInfos
->InterfaceClassGuid
, EventCategoryData1
, sizeof(GUID
));
215 NotificationInfos
->SymbolicLinkName
= (PUNICODE_STRING
)EventCategoryData2
;
218 case EventCategoryHardwareProfileChange
:
220 PHWPROFILE_CHANGE_NOTIFICATION NotificationInfos
;
221 NotificationStructure
= NotificationInfos
= ExAllocatePoolWithTag(
223 sizeof(HWPROFILE_CHANGE_NOTIFICATION
),
225 NotificationInfos
->Version
= 1;
226 NotificationInfos
->Size
= sizeof(HWPROFILE_CHANGE_NOTIFICATION
);
227 RtlCopyMemory(&NotificationInfos
->Event
, Event
, sizeof(GUID
));
230 case EventCategoryTargetDeviceChange
:
232 PTARGET_DEVICE_REMOVAL_NOTIFICATION NotificationInfos
;
233 NotificationStructure
= NotificationInfos
= ExAllocatePoolWithTag(
235 sizeof(TARGET_DEVICE_REMOVAL_NOTIFICATION
),
237 NotificationInfos
->Version
= 1;
238 NotificationInfos
->Size
= sizeof(TARGET_DEVICE_REMOVAL_NOTIFICATION
);
239 RtlCopyMemory(&NotificationInfos
->Event
, Event
, sizeof(GUID
));
240 NotificationInfos
->FileObject
= (PFILE_OBJECT
)EventCategoryData1
;
245 DPRINT1("IopNotifyPlugPlayNotification(): unknown EventCategory 0x%x UNIMPLEMENTED\n", EventCategory
);
250 /* Loop through procedures registred in PnpNotifyListHead
251 * list to find those that meet some criteria.
254 Entry
= PnpNotifyListHead
.Flink
;
255 while (Entry
!= &PnpNotifyListHead
)
257 ChangeEntry
= CONTAINING_RECORD(Entry
, PNP_NOTIFY_ENTRY
, PnpNotifyList
);
258 CallCurrentEntry
= FALSE
;
260 switch (EventCategory
)
262 case EventCategoryDeviceInterfaceChange
:
264 if (ChangeEntry
->EventCategory
== EventCategory
265 && RtlCompareUnicodeString(&ChangeEntry
->Guid
, (PUNICODE_STRING
)EventCategoryData1
, FALSE
) == 0)
267 CallCurrentEntry
= TRUE
;
271 case EventCategoryHardwareProfileChange
:
273 CallCurrentEntry
= TRUE
;
276 case EventCategoryTargetDeviceChange
:
278 if (ChangeEntry
->FileObject
== (PFILE_OBJECT
)EventCategoryData1
)
279 CallCurrentEntry
= TRUE
;
283 DPRINT1("IopNotifyPlugPlayNotification(): unknown EventCategory 0x%x UNIMPLEMENTED\n", EventCategory
);
288 if (CallCurrentEntry
)
290 /* Call entry into new allocated memory */
291 DPRINT("IopNotifyPlugPlayNotification(): found suitable callback %p\n",
294 (ChangeEntry
->PnpNotificationProc
)(
295 NotificationStructure
,
296 ChangeEntry
->Context
);
299 Entry
= Entry
->Flink
;
301 KeReleaseGuardedMutex(&PnpNotifyListLock
);
302 ExFreePoolWithTag(NotificationStructure
, TAG_PNP_NOTIFY
);
306 IopInitPnpNotificationImplementation(VOID
)
308 KeInitializeGuardedMutex(&PnpNotifyListLock
);
309 InitializeListHead(&PnpNotifyListHead
);