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 /* FUNCTIONS *****************************************************************/
40 IoPnPDeliverServicePowerNotification(
41 ULONG VetoedPowerOperation OPTIONAL
,
42 ULONG PowerNotification
,
43 ULONG Unknown OPTIONAL
,
56 IoRegisterPlugPlayNotification(
57 IN IO_NOTIFICATION_EVENT_CATEGORY EventCategory
,
58 IN ULONG EventCategoryFlags
,
59 IN PVOID EventCategoryData OPTIONAL
,
60 IN PDRIVER_OBJECT DriverObject
,
61 IN PDRIVER_NOTIFICATION_CALLBACK_ROUTINE CallbackRoutine
,
63 OUT PVOID
*NotificationEntry
)
65 PPNP_NOTIFY_ENTRY Entry
;
66 PWSTR SymbolicLinkList
;
71 DPRINT("IoRegisterPlugPlayNotification(EventCategory 0x%x, EventCategoryFlags 0x%lx, DriverObject %p) called.\n",
76 ObReferenceObject(DriverObject
);
78 /* Try to allocate entry for notification before sending any notification */
79 Entry
= ExAllocatePoolWithTag(
81 sizeof(PNP_NOTIFY_ENTRY
),
85 DPRINT("ExAllocatePool() failed\n");
86 ObDereferenceObject(DriverObject
);
87 return STATUS_INSUFFICIENT_RESOURCES
;
90 if (EventCategory
== EventCategoryTargetDeviceChange
91 && EventCategoryFlags
& PNPNOTIFY_DEVICE_INTERFACE_INCLUDE_EXISTING_INTERFACES
)
93 Status
= IoGetDeviceInterfaces(
94 (LPGUID
)EventCategoryData
,
95 NULL
, /* PhysicalDeviceObject OPTIONAL */
98 if (!NT_SUCCESS(Status
))
100 DPRINT("IoGetDeviceInterfaces() failed with status 0x%08lx\n", Status
);
101 ExFreePoolWithTag(Entry
, TAG_PNP_NOTIFY
);
102 ObDereferenceObject(DriverObject
);
105 /* FIXME: enumerate SymbolicLinkList */
106 DPRINT1("IoRegisterPlugPlayNotification(): need to send notifications for existing interfaces!\n");
107 ExFreePool(SymbolicLinkList
);
110 Entry
->PnpNotificationProc
= CallbackRoutine
;
111 Entry
->EventCategory
= EventCategory
;
112 Entry
->Context
= Context
;
113 switch (EventCategory
)
115 case EventCategoryDeviceInterfaceChange
:
117 Status
= RtlStringFromGUID(EventCategoryData
, &Entry
->Guid
);
118 if (!NT_SUCCESS(Status
))
120 ExFreePoolWithTag(Entry
, TAG_PNP_NOTIFY
);
121 ObDereferenceObject(DriverObject
);
126 case EventCategoryHardwareProfileChange
:
131 case EventCategoryTargetDeviceChange
:
133 Entry
->FileObject
= (PFILE_OBJECT
)EventCategoryData
;
138 DPRINT1("IoRegisterPlugPlayNotification(): unknown EventCategory 0x%x UNIMPLEMENTED\n", EventCategory
);
143 KeAcquireGuardedMutex(&PnpNotifyListLock
);
144 InsertHeadList(&PnpNotifyListHead
,
145 &Entry
->PnpNotifyList
);
146 KeReleaseGuardedMutex(&PnpNotifyListLock
);
148 DPRINT("IoRegisterPlugPlayNotification() returns NotificationEntry %p\n",
150 *NotificationEntry
= Entry
;
151 return STATUS_SUCCESS
;
159 IoUnregisterPlugPlayNotification(
160 IN PVOID NotificationEntry
)
162 PPNP_NOTIFY_ENTRY Entry
;
166 Entry
= (PPNP_NOTIFY_ENTRY
)NotificationEntry
;
167 DPRINT("IoUnregisterPlugPlayNotification(NotificationEntry %p) called\n",
170 KeAcquireGuardedMutex(&PnpNotifyListLock
);
171 RtlFreeUnicodeString(&Entry
->Guid
);
172 RemoveEntryList(&Entry
->PnpNotifyList
);
173 KeReleaseGuardedMutex(&PnpNotifyListLock
);
175 return STATUS_SUCCESS
;
179 IopNotifyPlugPlayNotification(
180 IN PDEVICE_OBJECT DeviceObject
,
181 IN IO_NOTIFICATION_EVENT_CATEGORY EventCategory
,
183 IN PVOID EventCategoryData1
,
184 IN PVOID EventCategoryData2
)
186 PPNP_NOTIFY_ENTRY ChangeEntry
;
188 PVOID NotificationStructure
;
189 BOOLEAN CallCurrentEntry
;
191 ASSERT(DeviceObject
);
193 KeAcquireGuardedMutex(&PnpNotifyListLock
);
194 if (IsListEmpty(&PnpNotifyListHead
))
196 KeReleaseGuardedMutex(&PnpNotifyListLock
);
200 switch (EventCategory
)
202 case EventCategoryDeviceInterfaceChange
:
204 PDEVICE_INTERFACE_CHANGE_NOTIFICATION NotificationInfos
;
205 NotificationStructure
= NotificationInfos
= ExAllocatePoolWithTag(
207 sizeof(DEVICE_INTERFACE_CHANGE_NOTIFICATION
),
209 NotificationInfos
->Version
= 1;
210 NotificationInfos
->Size
= sizeof(DEVICE_INTERFACE_CHANGE_NOTIFICATION
);
211 RtlCopyMemory(&NotificationInfos
->Event
, Event
, sizeof(GUID
));
212 RtlCopyMemory(&NotificationInfos
->InterfaceClassGuid
, EventCategoryData1
, sizeof(GUID
));
213 NotificationInfos
->SymbolicLinkName
= (PUNICODE_STRING
)EventCategoryData2
;
216 case EventCategoryHardwareProfileChange
:
218 PHWPROFILE_CHANGE_NOTIFICATION NotificationInfos
;
219 NotificationStructure
= NotificationInfos
= ExAllocatePoolWithTag(
221 sizeof(HWPROFILE_CHANGE_NOTIFICATION
),
223 NotificationInfos
->Version
= 1;
224 NotificationInfos
->Size
= sizeof(HWPROFILE_CHANGE_NOTIFICATION
);
225 RtlCopyMemory(&NotificationInfos
->Event
, Event
, sizeof(GUID
));
228 case EventCategoryTargetDeviceChange
:
230 PTARGET_DEVICE_REMOVAL_NOTIFICATION NotificationInfos
;
231 NotificationStructure
= NotificationInfos
= ExAllocatePoolWithTag(
233 sizeof(TARGET_DEVICE_REMOVAL_NOTIFICATION
),
235 NotificationInfos
->Version
= 1;
236 NotificationInfos
->Size
= sizeof(TARGET_DEVICE_REMOVAL_NOTIFICATION
);
237 RtlCopyMemory(&NotificationInfos
->Event
, Event
, sizeof(GUID
));
238 NotificationInfos
->FileObject
= (PFILE_OBJECT
)EventCategoryData1
;
243 DPRINT1("IopNotifyPlugPlayNotification(): unknown EventCategory 0x%x UNIMPLEMENTED\n", EventCategory
);
248 /* Loop through procedures registred in PnpNotifyListHead
249 * list to find those that meet some criteria.
252 Entry
= PnpNotifyListHead
.Flink
;
253 while (Entry
!= &PnpNotifyListHead
)
255 ChangeEntry
= CONTAINING_RECORD(Entry
, PNP_NOTIFY_ENTRY
, PnpNotifyList
);
256 CallCurrentEntry
= FALSE
;
258 switch (EventCategory
)
260 case EventCategoryDeviceInterfaceChange
:
262 if (ChangeEntry
->EventCategory
== EventCategory
263 && RtlCompareUnicodeString(&ChangeEntry
->Guid
, (PUNICODE_STRING
)EventCategoryData1
, FALSE
) == 0)
265 CallCurrentEntry
= TRUE
;
269 case EventCategoryHardwareProfileChange
:
271 CallCurrentEntry
= TRUE
;
274 case EventCategoryTargetDeviceChange
:
276 if (ChangeEntry
->FileObject
== (PFILE_OBJECT
)EventCategoryData1
)
277 CallCurrentEntry
= TRUE
;
281 DPRINT1("IopNotifyPlugPlayNotification(): unknown EventCategory 0x%x UNIMPLEMENTED\n", EventCategory
);
286 if (CallCurrentEntry
)
288 /* Call entry into new allocated memory */
289 DPRINT("IopNotifyPlugPlayNotification(): found suitable callback %p\n",
292 (ChangeEntry
->PnpNotificationProc
)(
293 NotificationStructure
,
294 ChangeEntry
->Context
);
297 Entry
= Entry
->Flink
;
299 KeReleaseGuardedMutex(&PnpNotifyListLock
);
300 ExFreePoolWithTag(NotificationStructure
, TAG_PNP_NOTIFY
);
304 IopInitPnpNotificationImplementation(VOID
)
306 KeInitializeGuardedMutex(&PnpNotifyListLock
);
307 InitializeListHead(&PnpNotifyListHead
);