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