Merge 14551:14980 from trunk
[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 #define TAG_PNP_NOTIFY TAG('P', 'n', 'P', 'N')
34
35 /* FUNCTIONS *****************************************************************/
36
37 /*
38 * @unimplemented
39 */
40 ULONG
41 STDCALL
42 IoPnPDeliverServicePowerNotification(
43 ULONG VetoedPowerOperation OPTIONAL,
44 ULONG PowerNotification,
45 ULONG Unknown OPTIONAL,
46 BOOLEAN Synchronous
47 )
48 {
49 UNIMPLEMENTED;
50 return 0;
51 }
52
53 /*
54 * @implemented
55 */
56 NTSTATUS
57 STDCALL
58 IoRegisterPlugPlayNotification(
59 IN IO_NOTIFICATION_EVENT_CATEGORY EventCategory,
60 IN ULONG EventCategoryFlags,
61 IN PVOID EventCategoryData OPTIONAL,
62 IN PDRIVER_OBJECT DriverObject,
63 IN PDRIVER_NOTIFICATION_CALLBACK_ROUTINE CallbackRoutine,
64 IN PVOID Context,
65 OUT PVOID *NotificationEntry)
66 {
67 PPNP_NOTIFY_ENTRY Entry;
68 PWSTR SymbolicLinkList;
69 NTSTATUS Status;
70
71 PAGED_CODE();
72
73 DPRINT("IoRegisterPlugPlayNotification(EventCategory 0x%x, EventCategoryFlags 0x%lx, DriverObject %p) called.\n",
74 EventCategory,
75 EventCategoryFlags,
76 DriverObject);
77
78 ObReferenceObject(DriverObject);
79
80 /* Try to allocate entry for notification before sending any notification */
81 Entry = ExAllocatePoolWithTag(
82 NonPagedPool,
83 sizeof(PNP_NOTIFY_ENTRY),
84 TAG_PNP_NOTIFY);
85 if (!Entry)
86 {
87 DPRINT("ExAllocatePool() failed\n");
88 ObDereferenceObject(DriverObject);
89 return STATUS_INSUFFICIENT_RESOURCES;
90 }
91
92 if (EventCategory == EventCategoryTargetDeviceChange
93 && EventCategoryFlags & PNPNOTIFY_DEVICE_INTERFACE_INCLUDE_EXISTING_INTERFACES)
94 {
95 Status = IoGetDeviceInterfaces(
96 (LPGUID)EventCategoryData,
97 NULL, /* PhysicalDeviceObject OPTIONAL */
98 0, /* Flags */
99 &SymbolicLinkList);
100 if (!NT_SUCCESS(Status))
101 {
102 DPRINT("IoGetDeviceInterfaces() failed with status 0x%08lx\n", Status);
103 ExFreePoolWithTag(Entry, TAG_PNP_NOTIFY);
104 ObDereferenceObject(DriverObject);
105 return Status;
106 }
107 /* FIXME: enumerate SymbolicLinkList */
108 DPRINT1("IoRegisterPlugPlayNotification(): need to send notifications for existing interfaces!\n");
109 ExFreePool(SymbolicLinkList);
110 }
111
112 Entry->PnpNotificationProc = CallbackRoutine;
113 Entry->EventCategory = EventCategory;
114 Entry->Context = Context;
115 switch (EventCategory)
116 {
117 case EventCategoryDeviceInterfaceChange:
118 {
119 Status = RtlStringFromGUID(EventCategoryData, &Entry->Guid);
120 if (!NT_SUCCESS(Status))
121 {
122 ExFreePoolWithTag(Entry, TAG_PNP_NOTIFY);
123 ObDereferenceObject(DriverObject);
124 return Status;
125 }
126 break;
127 }
128 case EventCategoryHardwareProfileChange:
129 {
130 /* nothing to do */
131 break;
132 }
133 case EventCategoryTargetDeviceChange:
134 {
135 Entry->FileObject = (PFILE_OBJECT)EventCategoryData;
136 break;
137 }
138 default:
139 {
140 DPRINT1("IoRegisterPlugPlayNotification(): unknown EventCategory 0x%x UNIMPLEMENTED\n", EventCategory);
141 break;
142 }
143 }
144
145 KeAcquireGuardedMutex(&PnpNotifyListLock);
146 InsertHeadList(&PnpNotifyListHead,
147 &Entry->PnpNotifyList);
148 KeReleaseGuardedMutex(&PnpNotifyListLock);
149
150 DPRINT("IoRegisterPlugPlayNotification() returns NotificationEntry %p\n",
151 Entry);
152 *NotificationEntry = Entry;
153 return STATUS_SUCCESS;
154 }
155
156 /*
157 * @implemented
158 */
159 NTSTATUS
160 STDCALL
161 IoUnregisterPlugPlayNotification(
162 IN PVOID NotificationEntry)
163 {
164 PPNP_NOTIFY_ENTRY Entry;
165
166 PAGED_CODE();
167
168 Entry = (PPNP_NOTIFY_ENTRY)NotificationEntry;
169 DPRINT("IoUnregisterPlugPlayNotification(NotificationEntry %p) called\n",
170 Entry);
171
172 KeAcquireGuardedMutex(&PnpNotifyListLock);
173 RtlFreeUnicodeString(&Entry->Guid);
174 RemoveEntryList(&Entry->PnpNotifyList);
175 KeReleaseGuardedMutex(&PnpNotifyListLock);
176
177 return STATUS_SUCCESS;
178 }
179
180 VOID
181 IopNotifyPlugPlayNotification(
182 IN PDEVICE_OBJECT DeviceObject,
183 IN IO_NOTIFICATION_EVENT_CATEGORY EventCategory,
184 IN GUID* Event,
185 IN PVOID EventCategoryData1,
186 IN PVOID EventCategoryData2)
187 {
188 PPNP_NOTIFY_ENTRY ChangeEntry;
189 PLIST_ENTRY Entry;
190 PVOID NotificationStructure;
191 BOOLEAN CallCurrentEntry;
192
193 ASSERT(DeviceObject);
194
195 KeAcquireGuardedMutex(&PnpNotifyListLock);
196 if (IsListEmpty(&PnpNotifyListHead))
197 {
198 KeReleaseGuardedMutex(&PnpNotifyListLock);
199 return;
200 }
201
202 switch (EventCategory)
203 {
204 case EventCategoryDeviceInterfaceChange:
205 {
206 PDEVICE_INTERFACE_CHANGE_NOTIFICATION NotificationInfos;
207 NotificationStructure = NotificationInfos = ExAllocatePoolWithTag(
208 PagedPool,
209 sizeof(DEVICE_INTERFACE_CHANGE_NOTIFICATION),
210 TAG_PNP_NOTIFY);
211 NotificationInfos->Version = 1;
212 NotificationInfos->Size = sizeof(DEVICE_INTERFACE_CHANGE_NOTIFICATION);
213 RtlCopyMemory(&NotificationInfos->Event, Event, sizeof(GUID));
214 RtlCopyMemory(&NotificationInfos->InterfaceClassGuid, EventCategoryData1, sizeof(GUID));
215 NotificationInfos->SymbolicLinkName = (PUNICODE_STRING)EventCategoryData2;
216 break;
217 }
218 case EventCategoryHardwareProfileChange:
219 {
220 PHWPROFILE_CHANGE_NOTIFICATION NotificationInfos;
221 NotificationStructure = NotificationInfos = ExAllocatePoolWithTag(
222 PagedPool,
223 sizeof(HWPROFILE_CHANGE_NOTIFICATION),
224 TAG_PNP_NOTIFY);
225 NotificationInfos->Version = 1;
226 NotificationInfos->Size = sizeof(HWPROFILE_CHANGE_NOTIFICATION);
227 RtlCopyMemory(&NotificationInfos->Event, Event, sizeof(GUID));
228 break;
229 }
230 case EventCategoryTargetDeviceChange:
231 {
232 PTARGET_DEVICE_REMOVAL_NOTIFICATION NotificationInfos;
233 NotificationStructure = NotificationInfos = ExAllocatePoolWithTag(
234 PagedPool,
235 sizeof(TARGET_DEVICE_REMOVAL_NOTIFICATION),
236 TAG_PNP_NOTIFY);
237 NotificationInfos->Version = 1;
238 NotificationInfos->Size = sizeof(TARGET_DEVICE_REMOVAL_NOTIFICATION);
239 RtlCopyMemory(&NotificationInfos->Event, Event, sizeof(GUID));
240 NotificationInfos->FileObject = (PFILE_OBJECT)EventCategoryData1;
241 break;
242 }
243 default:
244 {
245 DPRINT1("IopNotifyPlugPlayNotification(): unknown EventCategory 0x%x UNIMPLEMENTED\n", EventCategory);
246 return;
247 }
248 }
249
250 /* Loop through procedures registred in PnpNotifyListHead
251 * list to find those that meet some criteria.
252 */
253
254 Entry = PnpNotifyListHead.Flink;
255 while (Entry != &PnpNotifyListHead)
256 {
257 ChangeEntry = CONTAINING_RECORD(Entry, PNP_NOTIFY_ENTRY, PnpNotifyList);
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 Entry = Entry->Flink;
300 }
301 KeReleaseGuardedMutex(&PnpNotifyListLock);
302 ExFreePoolWithTag(NotificationStructure, TAG_PNP_NOTIFY);
303 }
304
305 VOID INIT_FUNCTION
306 IopInitPnpNotificationImplementation(VOID)
307 {
308 KeInitializeGuardedMutex(&PnpNotifyListLock);
309 InitializeListHead(&PnpNotifyListHead);
310 }
311
312 /* EOF */