5c5e39fac36e2f1af8063993811f9f5d64b79770
[reactos.git] / reactos / ntoskrnl / io / pnpnotify.c
1 /* $Id$
2 *
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
7 *
8 * PROGRAMMERS: Filip Navara (xnavara@volny.cz)
9 * Hervé Poussineau (hpoussin@reactos.com)
10 */
11
12 /* INCLUDES ******************************************************************/
13
14 #define NDEBUG
15 #include <ntoskrnl.h>
16 #include <internal/debug.h>
17
18 #if defined (ALLOC_PRAGMA)
19 #pragma alloc_text(INIT, IopInitPnpNotificationImplementation)
20 #endif
21
22
23 /* TYPES *******************************************************************/
24
25 typedef struct _PNP_NOTIFY_ENTRY
26 {
27 LIST_ENTRY PnpNotifyList;
28 IO_NOTIFICATION_EVENT_CATEGORY EventCategory;
29 PVOID Context;
30 UNICODE_STRING Guid;
31 PFILE_OBJECT FileObject;
32 PDRIVER_NOTIFICATION_CALLBACK_ROUTINE PnpNotificationProc;
33 } PNP_NOTIFY_ENTRY, *PPNP_NOTIFY_ENTRY;
34
35 static KGUARDED_MUTEX PnpNotifyListLock;
36 static LIST_ENTRY PnpNotifyListHead;
37
38 /* FUNCTIONS *****************************************************************/
39
40 /*
41 * @unimplemented
42 */
43 ULONG
44 STDCALL
45 IoPnPDeliverServicePowerNotification(
46 ULONG VetoedPowerOperation OPTIONAL,
47 ULONG PowerNotification,
48 ULONG Unknown OPTIONAL,
49 BOOLEAN Synchronous
50 )
51 {
52 UNIMPLEMENTED;
53 return 0;
54 }
55
56 /*
57 * @implemented
58 */
59 NTSTATUS
60 STDCALL
61 IoRegisterPlugPlayNotification(
62 IN IO_NOTIFICATION_EVENT_CATEGORY EventCategory,
63 IN ULONG EventCategoryFlags,
64 IN PVOID EventCategoryData OPTIONAL,
65 IN PDRIVER_OBJECT DriverObject,
66 IN PDRIVER_NOTIFICATION_CALLBACK_ROUTINE CallbackRoutine,
67 IN PVOID Context,
68 OUT PVOID *NotificationEntry)
69 {
70 PPNP_NOTIFY_ENTRY Entry;
71 PWSTR SymbolicLinkList;
72 NTSTATUS Status;
73
74 PAGED_CODE();
75
76 DPRINT("IoRegisterPlugPlayNotification(EventCategory 0x%x, EventCategoryFlags 0x%lx, DriverObject %p) called.\n",
77 EventCategory,
78 EventCategoryFlags,
79 DriverObject);
80
81 ObReferenceObject(DriverObject);
82
83 /* Try to allocate entry for notification before sending any notification */
84 Entry = ExAllocatePoolWithTag(
85 NonPagedPool,
86 sizeof(PNP_NOTIFY_ENTRY),
87 TAG_PNP_NOTIFY);
88 if (!Entry)
89 {
90 DPRINT("ExAllocatePool() failed\n");
91 ObDereferenceObject(DriverObject);
92 return STATUS_INSUFFICIENT_RESOURCES;
93 }
94
95 if (EventCategory == EventCategoryTargetDeviceChange
96 && EventCategoryFlags & PNPNOTIFY_DEVICE_INTERFACE_INCLUDE_EXISTING_INTERFACES)
97 {
98 Status = IoGetDeviceInterfaces(
99 (LPGUID)EventCategoryData,
100 NULL, /* PhysicalDeviceObject OPTIONAL */
101 0, /* Flags */
102 &SymbolicLinkList);
103 if (!NT_SUCCESS(Status))
104 {
105 DPRINT("IoGetDeviceInterfaces() failed with status 0x%08lx\n", Status);
106 ExFreePoolWithTag(Entry, TAG_PNP_NOTIFY);
107 ObDereferenceObject(DriverObject);
108 return Status;
109 }
110 /* FIXME: enumerate SymbolicLinkList */
111 DPRINT1("IoRegisterPlugPlayNotification(): need to send notifications for existing interfaces!\n");
112 ExFreePool(SymbolicLinkList);
113 }
114
115 Entry->PnpNotificationProc = CallbackRoutine;
116 Entry->EventCategory = EventCategory;
117 Entry->Context = Context;
118 switch (EventCategory)
119 {
120 case EventCategoryDeviceInterfaceChange:
121 {
122 Status = RtlStringFromGUID(EventCategoryData, &Entry->Guid);
123 if (!NT_SUCCESS(Status))
124 {
125 ExFreePoolWithTag(Entry, TAG_PNP_NOTIFY);
126 ObDereferenceObject(DriverObject);
127 return Status;
128 }
129 break;
130 }
131 case EventCategoryHardwareProfileChange:
132 {
133 /* nothing to do */
134 break;
135 }
136 case EventCategoryTargetDeviceChange:
137 {
138 Entry->FileObject = (PFILE_OBJECT)EventCategoryData;
139 break;
140 }
141 default:
142 {
143 DPRINT1("IoRegisterPlugPlayNotification(): unknown EventCategory 0x%x UNIMPLEMENTED\n", EventCategory);
144 break;
145 }
146 }
147
148 KeAcquireGuardedMutex(&PnpNotifyListLock);
149 InsertHeadList(&PnpNotifyListHead,
150 &Entry->PnpNotifyList);
151 KeReleaseGuardedMutex(&PnpNotifyListLock);
152
153 DPRINT("IoRegisterPlugPlayNotification() returns NotificationEntry %p\n",
154 Entry);
155 *NotificationEntry = Entry;
156 return STATUS_SUCCESS;
157 }
158
159 /*
160 * @implemented
161 */
162 NTSTATUS
163 STDCALL
164 IoUnregisterPlugPlayNotification(
165 IN PVOID NotificationEntry)
166 {
167 PPNP_NOTIFY_ENTRY Entry;
168
169 PAGED_CODE();
170
171 Entry = (PPNP_NOTIFY_ENTRY)NotificationEntry;
172 DPRINT("IoUnregisterPlugPlayNotification(NotificationEntry %p) called\n",
173 Entry);
174
175 KeAcquireGuardedMutex(&PnpNotifyListLock);
176 RtlFreeUnicodeString(&Entry->Guid);
177 RemoveEntryList(&Entry->PnpNotifyList);
178 KeReleaseGuardedMutex(&PnpNotifyListLock);
179
180 return STATUS_SUCCESS;
181 }
182
183 VOID
184 IopNotifyPlugPlayNotification(
185 IN PDEVICE_OBJECT DeviceObject,
186 IN IO_NOTIFICATION_EVENT_CATEGORY EventCategory,
187 IN GUID* Event,
188 IN PVOID EventCategoryData1,
189 IN PVOID EventCategoryData2)
190 {
191 PPNP_NOTIFY_ENTRY ChangeEntry;
192 PVOID NotificationStructure;
193 BOOLEAN CallCurrentEntry;
194
195 ASSERT(DeviceObject);
196
197 KeAcquireGuardedMutex(&PnpNotifyListLock);
198 if (IsListEmpty(&PnpNotifyListHead))
199 {
200 KeReleaseGuardedMutex(&PnpNotifyListLock);
201 return;
202 }
203
204 switch (EventCategory)
205 {
206 case EventCategoryDeviceInterfaceChange:
207 {
208 PDEVICE_INTERFACE_CHANGE_NOTIFICATION NotificationInfos;
209 NotificationStructure = NotificationInfos = ExAllocatePoolWithTag(
210 PagedPool,
211 sizeof(DEVICE_INTERFACE_CHANGE_NOTIFICATION),
212 TAG_PNP_NOTIFY);
213 NotificationInfos->Version = 1;
214 NotificationInfos->Size = sizeof(DEVICE_INTERFACE_CHANGE_NOTIFICATION);
215 RtlCopyMemory(&NotificationInfos->Event, Event, sizeof(GUID));
216 RtlCopyMemory(&NotificationInfos->InterfaceClassGuid, EventCategoryData1, sizeof(GUID));
217 NotificationInfos->SymbolicLinkName = (PUNICODE_STRING)EventCategoryData2;
218 break;
219 }
220 case EventCategoryHardwareProfileChange:
221 {
222 PHWPROFILE_CHANGE_NOTIFICATION NotificationInfos;
223 NotificationStructure = NotificationInfos = ExAllocatePoolWithTag(
224 PagedPool,
225 sizeof(HWPROFILE_CHANGE_NOTIFICATION),
226 TAG_PNP_NOTIFY);
227 NotificationInfos->Version = 1;
228 NotificationInfos->Size = sizeof(HWPROFILE_CHANGE_NOTIFICATION);
229 RtlCopyMemory(&NotificationInfos->Event, Event, sizeof(GUID));
230 break;
231 }
232 case EventCategoryTargetDeviceChange:
233 {
234 PTARGET_DEVICE_REMOVAL_NOTIFICATION NotificationInfos;
235 NotificationStructure = NotificationInfos = ExAllocatePoolWithTag(
236 PagedPool,
237 sizeof(TARGET_DEVICE_REMOVAL_NOTIFICATION),
238 TAG_PNP_NOTIFY);
239 NotificationInfos->Version = 1;
240 NotificationInfos->Size = sizeof(TARGET_DEVICE_REMOVAL_NOTIFICATION);
241 RtlCopyMemory(&NotificationInfos->Event, Event, sizeof(GUID));
242 NotificationInfos->FileObject = (PFILE_OBJECT)EventCategoryData1;
243 break;
244 }
245 default:
246 {
247 DPRINT1("IopNotifyPlugPlayNotification(): unknown EventCategory 0x%x UNIMPLEMENTED\n", EventCategory);
248 return;
249 }
250 }
251
252 /* Loop through procedures registred in PnpNotifyListHead
253 * list to find those that meet some criteria.
254 */
255
256 LIST_FOR_EACH(ChangeEntry,&PnpNotifyListHead, PNP_NOTIFY_ENTRY, PnpNotifyList)
257 {
258 CallCurrentEntry = FALSE;
259
260 switch (EventCategory)
261 {
262 case EventCategoryDeviceInterfaceChange:
263 {
264 if (ChangeEntry->EventCategory == EventCategory
265 && RtlCompareUnicodeString(&ChangeEntry->Guid, (PUNICODE_STRING)EventCategoryData1, FALSE) == 0)
266 {
267 CallCurrentEntry = TRUE;
268 }
269 break;
270 }
271 case EventCategoryHardwareProfileChange:
272 {
273 CallCurrentEntry = TRUE;
274 break;
275 }
276 case EventCategoryTargetDeviceChange:
277 {
278 if (ChangeEntry->FileObject == (PFILE_OBJECT)EventCategoryData1)
279 CallCurrentEntry = TRUE;
280 }
281 default:
282 {
283 DPRINT1("IopNotifyPlugPlayNotification(): unknown EventCategory 0x%x UNIMPLEMENTED\n", EventCategory);
284 break;
285 }
286 }
287
288 if (CallCurrentEntry)
289 {
290 /* Call entry into new allocated memory */
291 DPRINT("IopNotifyPlugPlayNotification(): found suitable callback %p\n",
292 ChangeEntry);
293
294 (ChangeEntry->PnpNotificationProc)(
295 NotificationStructure,
296 ChangeEntry->Context);
297 }
298
299 }
300 KeReleaseGuardedMutex(&PnpNotifyListLock);
301 ExFreePoolWithTag(NotificationStructure, TAG_PNP_NOTIFY);
302 }
303
304 VOID INIT_FUNCTION
305 IopInitPnpNotificationImplementation(VOID)
306 {
307 KeInitializeGuardedMutex(&PnpNotifyListLock);
308 InitializeListHead(&PnpNotifyListHead);
309 }
310
311 /* EOF */