Fix splitting of cells (noticed by Hartmut).
[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 PVOID NotificationStructure;
188 BOOLEAN CallCurrentEntry;
189
190 ASSERT(DeviceObject);
191
192 KeAcquireGuardedMutex(&PnpNotifyListLock);
193 if (IsListEmpty(&PnpNotifyListHead))
194 {
195 KeReleaseGuardedMutex(&PnpNotifyListLock);
196 return;
197 }
198
199 switch (EventCategory)
200 {
201 case EventCategoryDeviceInterfaceChange:
202 {
203 PDEVICE_INTERFACE_CHANGE_NOTIFICATION NotificationInfos;
204 NotificationStructure = NotificationInfos = ExAllocatePoolWithTag(
205 PagedPool,
206 sizeof(DEVICE_INTERFACE_CHANGE_NOTIFICATION),
207 TAG_PNP_NOTIFY);
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;
213 break;
214 }
215 case EventCategoryHardwareProfileChange:
216 {
217 PHWPROFILE_CHANGE_NOTIFICATION NotificationInfos;
218 NotificationStructure = NotificationInfos = ExAllocatePoolWithTag(
219 PagedPool,
220 sizeof(HWPROFILE_CHANGE_NOTIFICATION),
221 TAG_PNP_NOTIFY);
222 NotificationInfos->Version = 1;
223 NotificationInfos->Size = sizeof(HWPROFILE_CHANGE_NOTIFICATION);
224 RtlCopyMemory(&NotificationInfos->Event, Event, sizeof(GUID));
225 break;
226 }
227 case EventCategoryTargetDeviceChange:
228 {
229 PTARGET_DEVICE_REMOVAL_NOTIFICATION NotificationInfos;
230 NotificationStructure = NotificationInfos = ExAllocatePoolWithTag(
231 PagedPool,
232 sizeof(TARGET_DEVICE_REMOVAL_NOTIFICATION),
233 TAG_PNP_NOTIFY);
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;
238 break;
239 }
240 default:
241 {
242 DPRINT1("IopNotifyPlugPlayNotification(): unknown EventCategory 0x%x UNIMPLEMENTED\n", EventCategory);
243 return;
244 }
245 }
246
247 /* Loop through procedures registred in PnpNotifyListHead
248 * list to find those that meet some criteria.
249 */
250
251 LIST_FOR_EACH(ChangeEntry,&PnpNotifyListHead, PNP_NOTIFY_ENTRY, PnpNotifyList)
252 {
253 CallCurrentEntry = FALSE;
254
255 switch (EventCategory)
256 {
257 case EventCategoryDeviceInterfaceChange:
258 {
259 if (ChangeEntry->EventCategory == EventCategory
260 && RtlCompareUnicodeString(&ChangeEntry->Guid, (PUNICODE_STRING)EventCategoryData1, FALSE) == 0)
261 {
262 CallCurrentEntry = TRUE;
263 }
264 break;
265 }
266 case EventCategoryHardwareProfileChange:
267 {
268 CallCurrentEntry = TRUE;
269 break;
270 }
271 case EventCategoryTargetDeviceChange:
272 {
273 if (ChangeEntry->FileObject == (PFILE_OBJECT)EventCategoryData1)
274 CallCurrentEntry = TRUE;
275 }
276 default:
277 {
278 DPRINT1("IopNotifyPlugPlayNotification(): unknown EventCategory 0x%x UNIMPLEMENTED\n", EventCategory);
279 break;
280 }
281 }
282
283 if (CallCurrentEntry)
284 {
285 /* Call entry into new allocated memory */
286 DPRINT("IopNotifyPlugPlayNotification(): found suitable callback %p\n",
287 ChangeEntry);
288
289 (ChangeEntry->PnpNotificationProc)(
290 NotificationStructure,
291 ChangeEntry->Context);
292 }
293
294 }
295 KeReleaseGuardedMutex(&PnpNotifyListLock);
296 ExFreePoolWithTag(NotificationStructure, TAG_PNP_NOTIFY);
297 }
298
299 VOID INIT_FUNCTION
300 IopInitPnpNotificationImplementation(VOID)
301 {
302 KeInitializeGuardedMutex(&PnpNotifyListLock);
303 InitializeListHead(&PnpNotifyListHead);
304 }
305
306 /* EOF */