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