ReactOS 0.4.15-dev-7968-g24a56f8
pnpnotify.c
Go to the documentation of this file.
1/*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4 * PURPOSE: Plug & Play notification functions
5 * COPYRIGHT: Copyright 2003 Filip Navara <xnavara@volny.cz>
6 * Copyright 2005-2006 Hervé Poussineau <hpoussin@reactos.org>
7 * Copyright 2010 Pierre Schweitzer <pierre@reactos.org>
8 * Copyright 2020 Victor Perevertkin <victor.perevertkin@reactos.org>
9 */
10
11/* INCLUDES ******************************************************************/
12
13#include <ntoskrnl.h>
14#define NDEBUG
15#include <debug.h>
16
17/* DATA **********************************************************************/
18
22
24LIST_ENTRY PiNotifyHwProfileListHead;
25
27LIST_ENTRY PiNotifyDeviceInterfaceListHead;
28
29/* TYPES *********************************************************************/
30
31typedef struct _PNP_NOTIFY_ENTRY
32{
33 LIST_ENTRY PnpNotifyList;
36 PDRIVER_NOTIFICATION_CALLBACK_ROUTINE PnpNotificationProc;
37 union
38 {
39 GUID Guid; // for EventCategoryDeviceInterfaceChange
40 struct
41 {
42 PFILE_OBJECT FileObject; // for EventCategoryTargetDeviceChange
44 };
45 };
47 UINT8 RefCount;
50
51/* FUNCTIONS *****************************************************************/
52
53CODE_SEG("INIT")
54VOID
56{
60 InitializeListHead(&PiNotifyHwProfileListHead);
61 InitializeListHead(&PiNotifyDeviceInterfaceListHead);
62}
63
64static
65CODE_SEG("PAGE")
66VOID
69{
70 PAGED_CODE();
71 ASSERT(Entry->RefCount > 0);
72
73 ObDereferenceObject(Entry->DriverObject);
74 Entry->RefCount--;
75 if (Entry->RefCount == 0)
76 {
77 ASSERT(Entry->Deleted);
78
79 RemoveEntryList(&Entry->PnpNotifyList);
80 if (Entry->EventCategory == EventCategoryTargetDeviceChange)
81 {
82 // IopGetRelatedTargetDevice referenced the device upon the notification registration
83 ObDereferenceObject(Entry->DeviceObject);
84 }
86 }
87}
88
89static
90CODE_SEG("PAGE")
91VOID
94{
95 PAGED_CODE();
96 ObReferenceObject(Entry->DriverObject);
97 Entry->RefCount++;
98}
99
103static
104CODE_SEG("PAGE")
105VOID
110{
111 PAGED_CODE();
112#if DBG
113 KIRQL oldIrql = KeGetCurrentIrql();
114 ULONG oldApcDisable = KeGetCurrentThread()->CombinedApcDisable;
115#endif
116
118
119 ASSERT(oldIrql == KeGetCurrentIrql() &&
120 oldApcDisable == KeGetCurrentThread()->CombinedApcDisable);
121}
122
123static
124CODE_SEG("PAGE")
126VOID
127PiProcessSingleNotification(
131 _Out_ PLIST_ENTRY *NextEntry)
132{
133 PAGED_CODE();
134
135 // the notification may be unregistered inside the procedure
136 // thus reference the entry so we may proceed
138
139 // release the lock because the notification routine has to be called without any
140 // limitations regarding APCs
142 PiCallNotifyProc(Entry->PnpNotificationProc, NotificationStructure, Entry->Context);
144
145 // take the next entry link only after the callback finishes
146 // the lock is not held there, so Entry may have changed at this point
147 *NextEntry = Entry->PnpNotifyList.Flink;
149}
150
159CODE_SEG("PAGE")
160VOID
165{
166 PAGED_CODE();
167
169 notifyStruct = ExAllocatePoolWithTag(PagedPool, sizeof(*notifyStruct), TAG_PNP_NOTIFY);
170 if (!notifyStruct)
171 {
172 return;
173 }
174
175 *notifyStruct = (DEVICE_INTERFACE_CHANGE_NOTIFICATION) {
176 .Version = 1,
178 .Event = *Event,
181 };
182
183 DPRINT("Delivering a DeviceInterfaceChange PnP event\n");
184
186
187 PLIST_ENTRY entry = PiNotifyDeviceInterfaceListHead.Flink;
188 while (entry != &PiNotifyDeviceInterfaceListHead)
189 {
191
192 if (!IsEqualGUID(&notifyStruct->InterfaceClassGuid, &nEntry->Guid))
193 {
194 entry = entry->Flink;
195 continue;
196 }
197
198 PiProcessSingleNotification(nEntry, notifyStruct, &PiNotifyDeviceInterfaceLock, &entry);
199 }
200
202 ExFreePoolWithTag(notifyStruct, TAG_PNP_NOTIFY);
203}
204
205
212CODE_SEG("PAGE")
213VOID
216{
217 PAGED_CODE();
218
220 notifyStruct = ExAllocatePoolWithTag(PagedPool, sizeof(*notifyStruct), TAG_PNP_NOTIFY);
221 if (!notifyStruct)
222 {
223 return;
224 }
225
226 *notifyStruct = (HWPROFILE_CHANGE_NOTIFICATION) {
227 .Version = 1,
228 .Size = sizeof(HWPROFILE_CHANGE_NOTIFICATION),
229 .Event = *Event
230 };
231
232 DPRINT("Delivering a HardwareProfileChange PnP event\n");
233
235
236 PLIST_ENTRY entry = PiNotifyHwProfileListHead.Flink;
237 while (entry != &PiNotifyHwProfileListHead)
238 {
240
241 PiProcessSingleNotification(nEntry, notifyStruct, &PiNotifyHwProfileLock, &entry);
242 }
243
245 ExFreePoolWithTag(notifyStruct, TAG_PNP_NOTIFY);
246}
247
256CODE_SEG("PAGE")
257VOID
262{
263 PAGED_CODE();
264
265 PVOID notificationStruct;
266 // just in case our device is removed during the operation
268
270 ASSERT(deviceNode);
271
272 if (!IsEqualGUID(Event, &GUID_PNP_CUSTOM_NOTIFICATION))
273 {
275 notifStruct = ExAllocatePoolWithTag(PagedPool, sizeof(*notifStruct), TAG_PNP_NOTIFY);
276 if (!notifStruct)
277 {
278 return;
279 }
280
281 *notifStruct = (TARGET_DEVICE_REMOVAL_NOTIFICATION) {
282 .Version = 1,
284 .Event = *Event
285 };
286
287 notificationStruct = notifStruct;
288
289 DPRINT("Delivering a (non-custom) TargetDeviceChange PnP event\n");
290 }
291 else
292 {
293 ASSERT(CustomNotification);
294 // assuming everythng else is correct
295
296 notificationStruct = CustomNotification;
297
298 DPRINT("Delivering a (custom) TargetDeviceChange PnP event\n");
299 }
300
302
304 while (entry != &deviceNode->TargetDeviceNotify)
305 {
307
308 // put the file object from our saved entry to this particular notification's struct
309 ((PTARGET_DEVICE_REMOVAL_NOTIFICATION)notificationStruct)->FileObject = nEntry->FileObject;
310 // so you don't need to look at the definition ;)
313
314 PiProcessSingleNotification(nEntry, notificationStruct, &PiNotifyTargetDeviceLock, &entry);
315 }
316
318 ExFreePoolWithTag(notificationStruct, TAG_PNP_NOTIFY);
320}
321
322/* PUBLIC FUNCTIONS **********************************************************/
323
324/*
325 * @unimplemented
326 */
327ULONG
328NTAPI
330 _In_ ULONG VetoedPowerOperation,
331 _In_ ULONG PowerNotificationCode,
332 _In_ ULONG PowerNotificationData,
333 _In_ BOOLEAN Synchronous)
334{
336 return 0;
337}
338
339/*
340 * @implemented
341 */
342CODE_SEG("PAGE")
344NTAPI
353{
357 PAGED_CODE();
358
359 DPRINT("%s(EventCategory 0x%x, EventCategoryFlags 0x%lx, DriverObject %p) called.\n",
361
363
364 /* Try to allocate entry for notification before sending any notification */
366 if (!Entry)
367 {
368 DPRINT("ExAllocatePool() failed\n");
371 }
372
374 .PnpNotificationProc = CallbackRoutine,
375 .Context = Context,
376 .DriverObject = DriverObject,
377 .EventCategory = EventCategory,
378 .RefCount = 1
379 };
380
381 switch (EventCategory)
382 {
384 {
386
387 // first register the notification
389 InsertTailList(&PiNotifyDeviceInterfaceListHead, &Entry->PnpNotifyList);
391
392 // then process existing interfaces if asked
394 {
395 DEVICE_INTERFACE_CHANGE_NOTIFICATION NotificationInfos;
396 UNICODE_STRING SymbolicLinkU;
398
400 NULL, /* PhysicalDeviceObject OPTIONAL */
401 0, /* Flags */
403 if (NT_SUCCESS(Status))
404 {
405 /* Enumerate SymbolicLinkList */
406 NotificationInfos.Version = 1;
407 NotificationInfos.Size = sizeof(DEVICE_INTERFACE_CHANGE_NOTIFICATION);
408 NotificationInfos.Event = GUID_DEVICE_INTERFACE_ARRIVAL;
409 NotificationInfos.InterfaceClassGuid = *(LPGUID)EventCategoryData;
410 NotificationInfos.SymbolicLinkName = &SymbolicLinkU;
411
414 SymbolicLink += (SymbolicLinkU.Length / sizeof(WCHAR)) + 1)
415 {
416 RtlInitUnicodeString(&SymbolicLinkU, SymbolicLink);
417 DPRINT("Calling callback routine for %S\n", SymbolicLink);
418 PiCallNotifyProc(CallbackRoutine, &NotificationInfos, Context);
419 }
420
422 }
423 }
424 break;
425 }
427 {
429 InsertTailList(&PiNotifyHwProfileListHead, &Entry->PnpNotifyList);
431 break;
432 }
434 {
435 PDEVICE_NODE deviceNode;
436 Entry->FileObject = (PFILE_OBJECT)EventCategoryData;
437
438 // NOTE: the device node's PDO is referenced here
439 Status = IopGetRelatedTargetDevice(Entry->FileObject, &deviceNode);
440 if (!NT_SUCCESS(Status))
441 {
444 return Status;
445 }
446 // save it so we can dereference it later
447 Entry->DeviceObject = deviceNode->PhysicalDeviceObject;
448
449 // each DEVICE_NODE has its own registered notifications list
451 InsertTailList(&deviceNode->TargetDeviceNotify, &Entry->PnpNotifyList);
453 break;
454 }
455 default:
456 {
457 DPRINT1("%s: unknown EventCategory 0x%x UNIMPLEMENTED\n",
458 __FUNCTION__, EventCategory);
459
463 }
464 }
465
466 DPRINT("%s returns NotificationEntry %p\n", __FUNCTION__, Entry);
467
469
470 return STATUS_SUCCESS;
471}
472
473/*
474 * @implemented
475 */
476CODE_SEG("PAGE")
478NTAPI
481{
484
485 PAGED_CODE();
486
487 DPRINT("%s(NotificationEntry %p) called\n", __FUNCTION__, Entry);
488
489 switch (Entry->EventCategory)
490 {
493 break;
496 break;
499 break;
500 default:
503 }
504
506 if (!Entry->Deleted)
507 {
508 Entry->Deleted = TRUE; // so it can't be unregistered two times
510 }
511 else
512 {
513 DPRINT1("IoUnregisterPlugPlayNotification called two times for 0x%p\n", NotificationEntry);
514 }
516
517 return STATUS_SUCCESS;
518}
#define PAGED_CODE()
#define CODE_SEG(...)
unsigned char BOOLEAN
unsigned char UINT8
LONG NTSTATUS
Definition: precomp.h:26
#define DPRINT1
Definition: precomp.h:8
#define UNIMPLEMENTED
Definition: debug.h:115
#define _Guarded_by_(lock)
#define _Requires_lock_held_(lock)
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
static const WCHAR SymbolicLink[]
Definition: interface.c:31
#define __FUNCTION__
Definition: types.h:116
const GUID GUID_DEVICE_INTERFACE_ARRIVAL
Definition: deviface.c:14
#define RemoveEntryList(Entry)
Definition: env_spec_w32.h:986
#define InsertTailList(ListHead, Entry)
#define ExAllocatePoolWithTag(hernya, size, tag)
Definition: env_spec_w32.h:350
UCHAR KIRQL
Definition: env_spec_w32.h:591
#define KeGetCurrentIrql()
Definition: env_spec_w32.h:706
#define ExFreePool(addr)
Definition: env_spec_w32.h:352
#define InitializeListHead(ListHead)
Definition: env_spec_w32.h:944
#define PagedPool
Definition: env_spec_w32.h:308
_Must_inspect_result_ _In_ PFLT_GET_OPERATION_STATUS_CALLBACK CallbackRoutine
Definition: fltkernel.h:1035
Status
Definition: gdiplustypes.h:25
VOID FASTCALL KeInitializeGuardedMutex(OUT PKGUARDED_MUTEX GuardedMutex)
Definition: gmutex.c:31
VOID FASTCALL KeReleaseGuardedMutex(IN OUT PKGUARDED_MUTEX GuardedMutex)
Definition: gmutex.c:53
VOID FASTCALL KeAcquireGuardedMutex(IN PKGUARDED_MUTEX GuardedMutex)
Definition: gmutex.c:42
#define KeGetCurrentThread
Definition: hal.h:55
#define C_ASSERT(e)
Definition: intsafe.h:73
uint32_t entry
Definition: isohybrid.c:63
@ Deleted
Definition: kstypes.h:187
#define ASSERT(a)
Definition: mode.c:44
#define ExFreePoolWithTag(_P, _T)
Definition: module.h:1109
#define _Inout_opt_
Definition: ms_sal.h:379
#define _Out_
Definition: ms_sal.h:345
#define _In_
Definition: ms_sal.h:308
#define _In_opt_
Definition: ms_sal.h:309
NTSYSAPI VOID NTAPI RtlInitUnicodeString(PUNICODE_STRING DestinationString, PCWSTR SourceString)
#define UNREACHABLE
PDEVICE_NODE FASTCALL IopGetDeviceNode(IN PDEVICE_OBJECT DeviceObject)
NTSTATUS NTAPI IopGetRelatedTargetDevice(IN PFILE_OBJECT FileObject, OUT PDEVICE_NODE *DeviceNode)
Definition: device.c:653
NTSTATUS NTAPI IoGetDeviceInterfaces(IN CONST GUID *InterfaceClassGuid, IN PDEVICE_OBJECT PhysicalDeviceObject OPTIONAL, IN ULONG Flags, OUT PWSTR *SymbolicLinkList)
Definition: deviface.c:454
#define STATUS_NOT_SUPPORTED
Definition: ntstatus.h:423
ULONG NTAPI IoPnPDeliverServicePowerNotification(_In_ ULONG VetoedPowerOperation, _In_ ULONG PowerNotificationCode, _In_ ULONG PowerNotificationData, _In_ BOOLEAN Synchronous)
Definition: pnpnotify.c:329
VOID PiNotifyTargetDeviceChange(_In_ LPCGUID Event, _In_ PDEVICE_OBJECT DeviceObject, _In_opt_ PTARGET_DEVICE_CUSTOM_NOTIFICATION CustomNotification)
Delivers the event to all drivers subscribed to EventCategoryTargetDeviceChange PnP event.
Definition: pnpnotify.c:258
* PPNP_NOTIFY_ENTRY
Definition: pnpnotify.c:49
NTSTATUS NTAPI IoRegisterPlugPlayNotification(_In_ IO_NOTIFICATION_EVENT_CATEGORY EventCategory, _In_ ULONG EventCategoryFlags, _In_opt_ PVOID EventCategoryData, _In_ PDRIVER_OBJECT DriverObject, _In_ PDRIVER_NOTIFICATION_CALLBACK_ROUTINE CallbackRoutine, _Inout_opt_ PVOID Context, _Out_ PVOID *NotificationEntry)
Definition: pnpnotify.c:345
KGUARDED_MUTEX PiNotifyDeviceInterfaceLock
Definition: pnpnotify.c:21
VOID PiNotifyDeviceInterfaceChange(_In_ LPCGUID Event, _In_ LPCGUID InterfaceClassGuid, _In_ PUNICODE_STRING SymbolicLinkName)
Delivers the event to all drivers subscribed to EventCategoryDeviceInterfaceChange.
Definition: pnpnotify.c:161
static VOID PiCallNotifyProc(_In_ PDRIVER_NOTIFICATION_CALLBACK_ROUTINE Proc, _In_ PVOID NotificationStructure, _In_ PVOID Context)
Calls PnP notification routine and makes some checks to detect faulty drivers.
Definition: pnpnotify.c:106
KGUARDED_MUTEX PiNotifyTargetDeviceLock
Definition: pnpnotify.c:19
static VOID PiDereferencePnpNotifyEntry(_In_ PPNP_NOTIFY_ENTRY Entry)
Definition: pnpnotify.c:67
NTSTATUS NTAPI IoUnregisterPlugPlayNotification(_In_ PVOID NotificationEntry)
Definition: pnpnotify.c:479
KGUARDED_MUTEX PiNotifyHwProfileLock
Definition: pnpnotify.c:20
VOID PiInitializeNotifications(VOID)
Definition: pnpnotify.c:55
PNP_NOTIFY_ENTRY
Definition: pnpnotify.c:49
static VOID PiReferencePnpNotifyEntry(_In_ PPNP_NOTIFY_ENTRY Entry)
Definition: pnpnotify.c:92
VOID PiNotifyHardwareProfileChange(_In_ LPCGUID Event)
Delivers the event to all drivers subscribed to EventCategoryHardwareProfileChange PnP event.
Definition: pnpnotify.c:214
#define IsEqualGUID(rguid1, rguid2)
Definition: guiddef.h:147
GUID * LPGUID
Definition: guiddef.h:81
#define STATUS_SUCCESS
Definition: shellext.h:65
#define DPRINT
Definition: sndvol32.h:71
base of all file and directory entries
Definition: entries.h:83
PDEVICE_OBJECT PhysicalDeviceObject
Definition: iotypes.h:892
LIST_ENTRY TargetDeviceNotify
Definition: iotypes.h:906
Definition: typedefs.h:120
struct _LIST_ENTRY * Flink
Definition: typedefs.h:121
#define TAG_PNP_NOTIFY
Definition: tag.h:91
uint16_t * PWSTR
Definition: typedefs.h:56
#define FIELD_OFFSET(t, f)
Definition: typedefs.h:255
#define NTAPI
Definition: typedefs.h:36
#define CONTAINING_RECORD(address, type, field)
Definition: typedefs.h:260
uint32_t ULONG
Definition: typedefs.h:59
#define STATUS_INSUFFICIENT_RESOURCES
Definition: udferr_usr.h:158
_In_ PDEVICE_OBJECT DeviceObject
Definition: wdfdevice.h:2055
_In_ WDFREQUEST _In_ WDFFILEOBJECT FileObject
Definition: wdfdevice.h:550
_Must_inspect_result_ _In_ WDFDEVICE _In_ PCUNICODE_STRING SymbolicLinkName
Definition: wdfdevice.h:3739
_Must_inspect_result_ _In_ PDRIVER_OBJECT DriverObject
Definition: wdfdriver.h:213
_Must_inspect_result_ _In_ WDFOBJECT _In_ CONST GUID * Guid
Definition: wdfobject.h:762
_Must_inspect_result_ _In_opt_ PWDF_OBJECT_ATTRIBUTES _Out_ WDFWAITLOCK * Lock
Definition: wdfsync.h:127
_In_opt_ PDEVICE_OBJECT _In_ ULONG _Outptr_result_nullonfailure_ _At_ * SymbolicLinkList(return==0, __drv_allocatesMem(Mem))) PZZWSTR *SymbolicLinkList
_In_ ULONG EventCategoryFlags
Definition: iofuncs.h:1149
_In_ CONST GUID * InterfaceClassGuid
Definition: iofuncs.h:1136
_In_ ULONG _In_opt_ PVOID _In_ PDRIVER_OBJECT _In_ PDRIVER_NOTIFICATION_CALLBACK_ROUTINE _Inout_opt_ __drv_aliasesMem PVOID _Outptr_result_nullonfailure_ _At_ * NotificationEntry(return==0, __drv_allocatesMem(Mem))) PVOID *NotificationEntry
_In_ ULONG _In_opt_ PVOID EventCategoryData
Definition: iofuncs.h:1150
_In_ PVOID NotificationStructure
Definition: iofuncs.h:1206
enum _IO_NOTIFICATION_EVENT_CATEGORY IO_NOTIFICATION_EVENT_CATEGORY
struct _DEVICE_INTERFACE_CHANGE_NOTIFICATION DEVICE_INTERFACE_CHANGE_NOTIFICATION
@ EventCategoryTargetDeviceChange
Definition: iotypes.h:1227
@ EventCategoryDeviceInterfaceChange
Definition: iotypes.h:1226
@ EventCategoryHardwareProfileChange
Definition: iotypes.h:1225
struct _HWPROFILE_CHANGE_NOTIFICATION HWPROFILE_CHANGE_NOTIFICATION
* PFILE_OBJECT
Definition: iotypes.h:1998
DRIVER_NOTIFICATION_CALLBACK_ROUTINE * PDRIVER_NOTIFICATION_CALLBACK_ROUTINE
Definition: iotypes.h:1247
struct _TARGET_DEVICE_REMOVAL_NOTIFICATION TARGET_DEVICE_REMOVAL_NOTIFICATION
struct _TARGET_DEVICE_REMOVAL_NOTIFICATION * PTARGET_DEVICE_REMOVAL_NOTIFICATION
#define PNPNOTIFY_DEVICE_INTERFACE_INCLUDE_EXISTING_INTERFACES
Definition: iotypes.h:1239
#define ObDereferenceObject
Definition: obfuncs.h:203
#define ObReferenceObject
Definition: obfuncs.h:204
__wchar_t WCHAR
Definition: xmlstorage.h:180