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
;
187 PVOID NotificationStructure
;
188 BOOLEAN CallCurrentEntry
;
190 ASSERT(DeviceObject
);
192 KeAcquireGuardedMutex(&PnpNotifyListLock
);
193 if (IsListEmpty(&PnpNotifyListHead
))
195 KeReleaseGuardedMutex(&PnpNotifyListLock
);
199 switch (EventCategory
)
201 case EventCategoryDeviceInterfaceChange
:
203 PDEVICE_INTERFACE_CHANGE_NOTIFICATION NotificationInfos
;
204 NotificationStructure
= NotificationInfos
= ExAllocatePoolWithTag(
206 sizeof(DEVICE_INTERFACE_CHANGE_NOTIFICATION
),
208 NotificationInfos
->Version
= 1;
209 NotificationInfos
->Size
= sizeof(DEVICE_INTERFACE_CHANGE_NOTIFICATION
);
210 RtlCopyMemory(&NotificationInfos
->Event
, Event
, sizeof(GUID
));
211 RtlCopyMemory(&NotificationInfos
->InterfaceClassGuid
, EventCategoryData1
, sizeof(GUID
));
212 NotificationInfos
->SymbolicLinkName
= (PUNICODE_STRING
)EventCategoryData2
;
215 case EventCategoryHardwareProfileChange
:
217 PHWPROFILE_CHANGE_NOTIFICATION NotificationInfos
;
218 NotificationStructure
= NotificationInfos
= ExAllocatePoolWithTag(
220 sizeof(HWPROFILE_CHANGE_NOTIFICATION
),
222 NotificationInfos
->Version
= 1;
223 NotificationInfos
->Size
= sizeof(HWPROFILE_CHANGE_NOTIFICATION
);
224 RtlCopyMemory(&NotificationInfos
->Event
, Event
, sizeof(GUID
));
227 case EventCategoryTargetDeviceChange
:
229 PTARGET_DEVICE_REMOVAL_NOTIFICATION NotificationInfos
;
230 NotificationStructure
= NotificationInfos
= ExAllocatePoolWithTag(
232 sizeof(TARGET_DEVICE_REMOVAL_NOTIFICATION
),
234 NotificationInfos
->Version
= 1;
235 NotificationInfos
->Size
= sizeof(TARGET_DEVICE_REMOVAL_NOTIFICATION
);
236 RtlCopyMemory(&NotificationInfos
->Event
, Event
, sizeof(GUID
));
237 NotificationInfos
->FileObject
= (PFILE_OBJECT
)EventCategoryData1
;
242 DPRINT1("IopNotifyPlugPlayNotification(): unknown EventCategory 0x%x UNIMPLEMENTED\n", EventCategory
);
247 /* Loop through procedures registred in PnpNotifyListHead
248 * list to find those that meet some criteria.
251 LIST_FOR_EACH(ChangeEntry
,&PnpNotifyListHead
, PNP_NOTIFY_ENTRY
, PnpNotifyList
)
253 CallCurrentEntry
= FALSE
;
255 switch (EventCategory
)
257 case EventCategoryDeviceInterfaceChange
:
259 if (ChangeEntry
->EventCategory
== EventCategory
260 && RtlCompareUnicodeString(&ChangeEntry
->Guid
, (PUNICODE_STRING
)EventCategoryData1
, FALSE
) == 0)
262 CallCurrentEntry
= TRUE
;
266 case EventCategoryHardwareProfileChange
:
268 CallCurrentEntry
= TRUE
;
271 case EventCategoryTargetDeviceChange
:
273 if (ChangeEntry
->FileObject
== (PFILE_OBJECT
)EventCategoryData1
)
274 CallCurrentEntry
= TRUE
;
278 DPRINT1("IopNotifyPlugPlayNotification(): unknown EventCategory 0x%x UNIMPLEMENTED\n", EventCategory
);
283 if (CallCurrentEntry
)
285 /* Call entry into new allocated memory */
286 DPRINT("IopNotifyPlugPlayNotification(): found suitable callback %p\n",
289 (ChangeEntry
->PnpNotificationProc
)(
290 NotificationStructure
,
291 ChangeEntry
->Context
);
295 KeReleaseGuardedMutex(&PnpNotifyListLock
);
296 ExFreePoolWithTag(NotificationStructure
, TAG_PNP_NOTIFY
);
300 IopInitPnpNotificationImplementation(VOID
)
302 KeInitializeGuardedMutex(&PnpNotifyListLock
);
303 InitializeListHead(&PnpNotifyListHead
);