KD System Rewrite:
[reactos.git] / reactos / ntoskrnl / io / plugplay.c
1 /* $Id$
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/io/plugplay.c
6 * PURPOSE: Plug-and-play interface routines
7 *
8 * PROGRAMMERS: Eric Kohl <eric.kohl@t-online.de>
9 */
10
11 /* INCLUDES *****************************************************************/
12
13 #include <ntoskrnl.h>
14
15 #define NDEBUG
16 #include <internal/debug.h>
17
18
19 typedef struct _PNP_EVENT_ENTRY
20 {
21 LIST_ENTRY ListEntry;
22 PLUGPLAY_EVENT_BLOCK Event;
23 } PNP_EVENT_ENTRY, *PPNP_EVENT_ENTRY;
24
25
26 /* GLOBALS *******************************************************************/
27
28 static LIST_ENTRY IopPnpEventQueueHead;
29 static KEVENT IopPnpNotifyEvent;
30
31 /* FUNCTIONS *****************************************************************/
32
33 NTSTATUS INIT_FUNCTION
34 IopInitPlugPlayEvents(VOID)
35 {
36
37 InitializeListHead(&IopPnpEventQueueHead);
38
39 KeInitializeEvent(&IopPnpNotifyEvent,
40 SynchronizationEvent,
41 FALSE);
42
43 return STATUS_SUCCESS;
44 }
45
46
47 NTSTATUS
48 IopQueueTargetDeviceEvent(const GUID *Guid,
49 PUNICODE_STRING DeviceIds)
50 {
51 PPNP_EVENT_ENTRY EventEntry;
52 DWORD TotalSize;
53
54 TotalSize =
55 FIELD_OFFSET(PLUGPLAY_EVENT_BLOCK, TargetDevice.DeviceIds) +
56 DeviceIds->MaximumLength;
57
58 EventEntry = ExAllocatePool(NonPagedPool,
59 TotalSize + FIELD_OFFSET(PNP_EVENT_ENTRY, Event));
60 if (EventEntry == NULL)
61 return STATUS_INSUFFICIENT_RESOURCES;
62
63 memcpy(&EventEntry->Event.EventGuid,
64 Guid,
65 sizeof(GUID));
66 EventEntry->Event.EventCategory = TargetDeviceChangeEvent;
67 EventEntry->Event.TotalSize = TotalSize;
68
69 memcpy(&EventEntry->Event.TargetDevice.DeviceIds,
70 DeviceIds->Buffer,
71 DeviceIds->MaximumLength);
72
73 InsertHeadList(&IopPnpEventQueueHead,
74 &EventEntry->ListEntry);
75 KeSetEvent(&IopPnpNotifyEvent,
76 0,
77 FALSE);
78
79 return STATUS_SUCCESS;
80 }
81
82
83 /*
84 * Remove the current PnP event from the tail of the event queue
85 * and signal IopPnpNotifyEvent if there is yet another event in the queue.
86 */
87 static VOID
88 IopRemovePlugPlayEvent(VOID)
89 {
90 /* Remove a pnp event entry from the tail of the queue */
91 if (!IsListEmpty(&IopPnpEventQueueHead))
92 {
93 ExFreePool(RemoveTailList(&IopPnpEventQueueHead));
94 }
95
96 /* Signal the next pnp event in the queue */
97 if (!IsListEmpty(&IopPnpEventQueueHead))
98 {
99 KeSetEvent(&IopPnpNotifyEvent,
100 0,
101 FALSE);
102 }
103 }
104
105
106 /*
107 * @implemented
108 */
109 NTSTATUS STDCALL
110 NtGetPlugPlayEvent(IN ULONG Reserved1,
111 IN ULONG Reserved2,
112 OUT PPLUGPLAY_EVENT_BLOCK Buffer,
113 IN ULONG BufferLength)
114 {
115 PPNP_EVENT_ENTRY Entry;
116 NTSTATUS Status;
117
118 DPRINT("NtGetPlugPlayEvent() called\n");
119
120 /* Function can only be called from user-mode */
121 if (KeGetPreviousMode() != UserMode)
122 {
123 DPRINT1("NtGetPlugPlayEvent cannot be called from kernel mode!\n");
124 return STATUS_ACCESS_DENIED;
125 }
126
127 /* Check for Tcb privilege */
128 if (!SeSinglePrivilegeCheck(SeTcbPrivilege,
129 UserMode))
130 {
131 DPRINT1("NtGetPlugPlayEvent: Caller does not hold the SeTcbPrivilege privilege!\n");
132 return STATUS_PRIVILEGE_NOT_HELD;
133 }
134
135 /* Wait for a PnP event */
136 DPRINT("Waiting for pnp notification event\n");
137 Status = KeWaitForSingleObject(&IopPnpNotifyEvent,
138 UserRequest,
139 KernelMode,
140 FALSE,
141 NULL);
142 if (!NT_SUCCESS(Status))
143 {
144 DPRINT1("KeWaitForSingleObject() failed (Status %lx)\n", Status);
145 return Status;
146 }
147
148 /* Get entry from the tail of the queue */
149 Entry = CONTAINING_RECORD(IopPnpEventQueueHead.Blink,
150 PNP_EVENT_ENTRY,
151 ListEntry);
152
153 /* Check the buffer size */
154 if (BufferLength < Entry->Event.TotalSize)
155 {
156 DPRINT1("Buffer is too small for the pnp-event\n");
157 return STATUS_BUFFER_TOO_SMALL;
158 }
159
160 /* Copy event data to the user buffer */
161 memcpy(Buffer,
162 &Entry->Event,
163 Entry->Event.TotalSize);
164
165 DPRINT("NtGetPlugPlayEvent() done\n");
166
167 return STATUS_SUCCESS;
168 }
169
170
171 /*
172 * @unimplemented
173 */
174 NTSTATUS STDCALL
175 NtPlugPlayControl(IN ULONG ControlCode,
176 IN OUT PVOID Buffer,
177 IN ULONG BufferLength)
178 {
179 DPRINT("NtPlugPlayControl(%lu %p %lu) called\n",
180 ControlCode, Buffer, BufferLength);
181
182 switch (ControlCode)
183 {
184 case PLUGPLAY_USER_RESPONSE:
185 IopRemovePlugPlayEvent();
186 return STATUS_SUCCESS;
187 }
188
189 return STATUS_NOT_IMPLEMENTED;
190 }
191
192 /* EOF */