Sync with trunk for console graphics palettes.
[reactos.git] / drivers / battery / battc / battc.c
1 /*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: drivers/battery/battc/battc.c
5 * PURPOSE: Battery Class Driver
6 * PROGRAMMERS: Cameron Gutman (cameron.gutman@reactos.org)
7 */
8
9 #include <battc.h>
10
11 #define NDEBUG
12 #include <debug.h>
13
14 NTSTATUS
15 NTAPI
16 DriverEntry(PDRIVER_OBJECT DriverObject,
17 PUNICODE_STRING RegistryPath)
18 {
19 DPRINT("Battery class driver initialized\n");
20
21 return STATUS_SUCCESS;
22 }
23
24 BCLASSAPI
25 NTSTATUS
26 NTAPI
27 BatteryClassUnload(PVOID ClassData)
28 {
29 PBATTERY_CLASS_DATA BattClass = ClassData;
30
31 DPRINT("Battery 0x%x is being unloaded\n");
32
33 if (BattClass->InterfaceName.Length != 0)
34 {
35 IoSetDeviceInterfaceState(&BattClass->InterfaceName, FALSE);
36 RtlFreeUnicodeString(&BattClass->InterfaceName);
37 }
38
39 ExFreePoolWithTag(BattClass,
40 BATTERY_CLASS_DATA_TAG);
41
42 return STATUS_SUCCESS;
43 }
44
45 BCLASSAPI
46 NTSTATUS
47 NTAPI
48 BatteryClassSystemControl(PVOID ClassData,
49 PVOID WmiLibContext,
50 PDEVICE_OBJECT DeviceObject,
51 PIRP Irp,
52 PVOID Disposition)
53 {
54 UNIMPLEMENTED
55
56 return STATUS_WMI_GUID_NOT_FOUND;
57 }
58
59 BCLASSAPI
60 NTSTATUS
61 NTAPI
62 BatteryClassQueryWmiDataBlock(PVOID ClassData,
63 PDEVICE_OBJECT DeviceObject,
64 PIRP Irp,
65 ULONG GuidIndex,
66 PULONG InstanceLengthArray,
67 ULONG OutBufferSize,
68 PUCHAR Buffer)
69 {
70 UNIMPLEMENTED
71
72 return STATUS_WMI_GUID_NOT_FOUND;
73 }
74
75 BCLASSAPI
76 NTSTATUS
77 NTAPI
78 BatteryClassStatusNotify(PVOID ClassData)
79 {
80 PBATTERY_CLASS_DATA BattClass = ClassData;
81 PBATTERY_WAIT_STATUS BattWait = BattClass->EventTriggerContext;
82 BATTERY_STATUS BattStatus;
83 NTSTATUS Status;
84
85 DPRINT("Received battery status notification from 0x%x\n", ClassData);
86
87 ExAcquireFastMutex(&BattClass->Mutex);
88 if (!BattClass->Waiting)
89 {
90 ExReleaseFastMutex(&BattClass->Mutex);
91 return STATUS_SUCCESS;
92 }
93
94 switch (BattClass->EventTrigger)
95 {
96 case EVENT_BATTERY_TAG:
97 ExReleaseFastMutex(&BattClass->Mutex);
98 DPRINT1("Waiting for battery is UNIMPLEMENTED!\n");
99 break;
100
101 case EVENT_BATTERY_STATUS:
102 ExReleaseFastMutex(&BattClass->Mutex);
103 Status = BattClass->MiniportInfo.QueryStatus(BattClass->MiniportInfo.Context,
104 BattWait->BatteryTag,
105 &BattStatus);
106 if (!NT_SUCCESS(Status))
107 return Status;
108
109 ExAcquireFastMutex(&BattClass->Mutex);
110
111 if (!(BattWait->PowerState & BattStatus.PowerState) ||
112 (BattWait->HighCapacity > BattStatus.Capacity) ||
113 (BattWait->LowCapacity < BattStatus.Capacity))
114 {
115 KeSetEvent(&BattClass->WaitEvent, IO_NO_INCREMENT, FALSE);
116 }
117
118 ExReleaseFastMutex(&BattClass->Mutex);
119 break;
120
121 default:
122 ExReleaseFastMutex(&BattClass->Mutex);
123 ASSERT(FALSE);
124 break;
125 }
126
127 return STATUS_SUCCESS;
128 }
129
130 BCLASSAPI
131 NTSTATUS
132 NTAPI
133 BatteryClassInitializeDevice(PBATTERY_MINIPORT_INFO MiniportInfo,
134 PVOID *ClassData)
135 {
136 NTSTATUS Status;
137 PBATTERY_CLASS_DATA BattClass = ExAllocatePoolWithTag(NonPagedPool,
138 sizeof(BATTERY_CLASS_DATA),
139 BATTERY_CLASS_DATA_TAG);
140
141 if (!BattClass)
142 return STATUS_INSUFFICIENT_RESOURCES;
143
144 RtlZeroMemory(BattClass, sizeof(BATTERY_CLASS_DATA));
145
146 RtlCopyMemory(&BattClass->MiniportInfo,
147 MiniportInfo,
148 sizeof(BattClass->MiniportInfo));
149
150 KeInitializeEvent(&BattClass->WaitEvent, SynchronizationEvent, FALSE);
151
152 ExInitializeFastMutex(&BattClass->Mutex);
153
154 Status = IoRegisterDeviceInterface(MiniportInfo->Pdo,
155 &GUID_DEVICE_BATTERY,
156 NULL,
157 &BattClass->InterfaceName);
158 if (NT_SUCCESS(Status))
159 {
160 DPRINT("Initialized battery interface: %wZ\n", &BattClass->InterfaceName);
161 IoSetDeviceInterfaceState(&BattClass->InterfaceName, TRUE);
162 }
163 else
164 {
165 DPRINT1("IoRegisterDeviceInterface failed (0x%x)\n", Status);
166 }
167
168 *ClassData = BattClass;
169
170 return STATUS_SUCCESS;
171 }
172
173 BCLASSAPI
174 NTSTATUS
175 NTAPI
176 BatteryClassIoctl(PVOID ClassData,
177 PIRP Irp)
178 {
179 PBATTERY_CLASS_DATA BattClass = ClassData;
180 PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
181 NTSTATUS Status;
182 ULONG WaitTime;
183 PBATTERY_WAIT_STATUS BattWait;
184 PBATTERY_QUERY_INFORMATION BattQueryInfo;
185 PBATTERY_SET_INFORMATION BattSetInfo;
186 LARGE_INTEGER Timeout;
187 PBATTERY_STATUS BattStatus;
188 BATTERY_NOTIFY BattNotify;
189 ULONG ReturnedLength;
190
191 Irp->IoStatus.Information = 0;
192
193 DPRINT("Received IOCTL %x for 0x%x\n", IrpSp->Parameters.DeviceIoControl.IoControlCode,
194 ClassData);
195
196 switch (IrpSp->Parameters.DeviceIoControl.IoControlCode)
197 {
198 case IOCTL_BATTERY_QUERY_TAG:
199 if (IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(ULONG) ||
200 IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(ULONG))
201 {
202 Status = STATUS_BUFFER_TOO_SMALL;
203 break;
204 }
205
206 WaitTime = *(PULONG)Irp->AssociatedIrp.SystemBuffer;
207
208 Timeout.QuadPart = Int32x32To64(WaitTime, -1000);
209
210 Status = BattClass->MiniportInfo.QueryTag(BattClass->MiniportInfo.Context,
211 (PULONG)Irp->AssociatedIrp.SystemBuffer);
212 if (!NT_SUCCESS(Status))
213 {
214 ExAcquireFastMutex(&BattClass->Mutex);
215 BattClass->EventTrigger = EVENT_BATTERY_TAG;
216 BattClass->Waiting = TRUE;
217 ExReleaseFastMutex(&BattClass->Mutex);
218
219 Status = KeWaitForSingleObject(&BattClass->WaitEvent,
220 Executive,
221 KernelMode,
222 FALSE,
223 WaitTime != -1 ? &Timeout : NULL);
224
225 ExAcquireFastMutex(&BattClass->Mutex);
226 BattClass->Waiting = FALSE;
227 ExReleaseFastMutex(&BattClass->Mutex);
228
229 if (Status == STATUS_SUCCESS)
230 {
231 Status = BattClass->MiniportInfo.QueryTag(BattClass->MiniportInfo.Context,
232 (PULONG)Irp->AssociatedIrp.SystemBuffer);
233 if (NT_SUCCESS(Status))
234 Irp->IoStatus.Information = sizeof(ULONG);
235 }
236 else
237 {
238 Status = STATUS_NO_SUCH_DEVICE;
239 }
240 }
241 else
242 Irp->IoStatus.Information = sizeof(ULONG);
243 break;
244
245 case IOCTL_BATTERY_QUERY_STATUS:
246 if (IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(*BattWait) ||
247 IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(BATTERY_STATUS))
248 {
249 Status = STATUS_BUFFER_TOO_SMALL;
250 break;
251 }
252
253 BattWait = Irp->AssociatedIrp.SystemBuffer;
254
255 Timeout.QuadPart = Int32x32To64(BattWait->Timeout, -1000);
256
257 Status = BattClass->MiniportInfo.QueryStatus(BattClass->MiniportInfo.Context,
258 BattWait->BatteryTag,
259 (PBATTERY_STATUS)Irp->AssociatedIrp.SystemBuffer);
260
261 BattStatus = Irp->AssociatedIrp.SystemBuffer;
262
263 if (!NT_SUCCESS(Status) ||
264 ((BattWait->PowerState & BattStatus->PowerState) &&
265 (BattWait->HighCapacity <= BattStatus->Capacity) &&
266 (BattWait->LowCapacity >= BattStatus->Capacity)))
267 {
268 BattNotify.PowerState = BattWait->PowerState;
269 BattNotify.HighCapacity = BattWait->HighCapacity;
270 BattNotify.LowCapacity = BattWait->LowCapacity;
271
272 BattClass->MiniportInfo.SetStatusNotify(BattClass->MiniportInfo.Context,
273 BattWait->BatteryTag,
274 &BattNotify);
275
276 ExAcquireFastMutex(&BattClass->Mutex);
277 BattClass->EventTrigger = EVENT_BATTERY_STATUS;
278 BattClass->EventTriggerContext = BattWait;
279 BattClass->Waiting = TRUE;
280 ExReleaseFastMutex(&BattClass->Mutex);
281
282 Status = KeWaitForSingleObject(&BattClass->WaitEvent,
283 Executive,
284 KernelMode,
285 FALSE,
286 BattWait->Timeout != -1 ? &Timeout : NULL);
287
288 ExAcquireFastMutex(&BattClass->Mutex);
289 BattClass->Waiting = FALSE;
290 ExReleaseFastMutex(&BattClass->Mutex);
291
292 BattClass->MiniportInfo.DisableStatusNotify(BattClass->MiniportInfo.Context);
293
294 if (Status == STATUS_SUCCESS)
295 {
296 Status = BattClass->MiniportInfo.QueryStatus(BattClass->MiniportInfo.Context,
297 BattWait->BatteryTag,
298 (PBATTERY_STATUS)Irp->AssociatedIrp.SystemBuffer);
299 if (NT_SUCCESS(Status))
300 Irp->IoStatus.Information = sizeof(ULONG);
301 }
302 else
303 {
304 Status = STATUS_NO_SUCH_DEVICE;
305 }
306 }
307 else
308 Irp->IoStatus.Information = sizeof(BATTERY_STATUS);
309 break;
310
311 case IOCTL_BATTERY_QUERY_INFORMATION:
312 if (IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(*BattQueryInfo))
313 {
314 Status = STATUS_BUFFER_TOO_SMALL;
315 break;
316 }
317
318 BattQueryInfo = Irp->AssociatedIrp.SystemBuffer;
319
320 Status = BattClass->MiniportInfo.QueryInformation(BattClass->MiniportInfo.Context,
321 BattQueryInfo->BatteryTag,
322 BattQueryInfo->InformationLevel,
323 BattQueryInfo->AtRate,
324 Irp->AssociatedIrp.SystemBuffer,
325 IrpSp->Parameters.DeviceIoControl.OutputBufferLength,
326 &ReturnedLength);
327 Irp->IoStatus.Information = ReturnedLength;
328 if (!NT_SUCCESS(Status))
329 DPRINT1("QueryInformation failed (0x%x)\n", Status);
330 break;
331 case IOCTL_BATTERY_SET_INFORMATION:
332 if (IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(*BattSetInfo))
333 {
334 Status = STATUS_BUFFER_TOO_SMALL;
335 break;
336 }
337
338 BattSetInfo = Irp->AssociatedIrp.SystemBuffer;
339
340 Status = BattClass->MiniportInfo.SetInformation(BattClass->MiniportInfo.Context,
341 BattSetInfo->BatteryTag,
342 BattSetInfo->InformationLevel,
343 BattSetInfo->Buffer);
344 if (!NT_SUCCESS(Status))
345 DPRINT1("SetInformation failed (0x%x)\n", Status);
346 break;
347
348 default:
349 DPRINT1("Received unsupported IRP %x\n", IrpSp->Parameters.DeviceIoControl.IoControlCode);
350 /* Do NOT complete the irp */
351 return STATUS_NOT_SUPPORTED;
352 }
353
354 Irp->IoStatus.Status = Status;
355 IoCompleteRequest(Irp, IO_NO_INCREMENT);
356
357 return Status;
358 }