* Sync up to trunk head (r64894).
[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 if (MiniportInfo->Pdo != NULL)
155 {
156 Status = IoRegisterDeviceInterface(MiniportInfo->Pdo,
157 &GUID_DEVICE_BATTERY,
158 NULL,
159 &BattClass->InterfaceName);
160 if (NT_SUCCESS(Status))
161 {
162 DPRINT("Initialized battery interface: %wZ\n", &BattClass->InterfaceName);
163 Status = IoSetDeviceInterfaceState(&BattClass->InterfaceName, TRUE);
164 if (Status == STATUS_OBJECT_NAME_EXISTS)
165 {
166 DPRINT1("Got STATUS_OBJECT_NAME_EXISTS for SetDeviceInterfaceState\n");
167 Status = STATUS_SUCCESS;
168 }
169 }
170 else
171 {
172 DPRINT1("IoRegisterDeviceInterface failed (0x%x)\n", Status);
173 }
174 }
175
176 *ClassData = BattClass;
177
178 return STATUS_SUCCESS;
179 }
180
181 BCLASSAPI
182 NTSTATUS
183 NTAPI
184 BatteryClassIoctl(PVOID ClassData,
185 PIRP Irp)
186 {
187 PBATTERY_CLASS_DATA BattClass = ClassData;
188 PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
189 NTSTATUS Status;
190 ULONG WaitTime;
191 PBATTERY_WAIT_STATUS BattWait;
192 PBATTERY_QUERY_INFORMATION BattQueryInfo;
193 PBATTERY_SET_INFORMATION BattSetInfo;
194 LARGE_INTEGER Timeout;
195 PBATTERY_STATUS BattStatus;
196 BATTERY_NOTIFY BattNotify;
197 ULONG ReturnedLength;
198
199 Irp->IoStatus.Information = 0;
200
201 DPRINT("Received IOCTL %x for 0x%x\n", IrpSp->Parameters.DeviceIoControl.IoControlCode,
202 ClassData);
203
204 switch (IrpSp->Parameters.DeviceIoControl.IoControlCode)
205 {
206 case IOCTL_BATTERY_QUERY_TAG:
207 if (IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(ULONG) ||
208 IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(ULONG))
209 {
210 Status = STATUS_BUFFER_TOO_SMALL;
211 break;
212 }
213
214 WaitTime = *(PULONG)Irp->AssociatedIrp.SystemBuffer;
215
216 Timeout.QuadPart = Int32x32To64(WaitTime, -1000);
217
218 Status = BattClass->MiniportInfo.QueryTag(BattClass->MiniportInfo.Context,
219 (PULONG)Irp->AssociatedIrp.SystemBuffer);
220 if (!NT_SUCCESS(Status))
221 {
222 ExAcquireFastMutex(&BattClass->Mutex);
223 BattClass->EventTrigger = EVENT_BATTERY_TAG;
224 BattClass->Waiting = TRUE;
225 ExReleaseFastMutex(&BattClass->Mutex);
226
227 Status = KeWaitForSingleObject(&BattClass->WaitEvent,
228 Executive,
229 KernelMode,
230 FALSE,
231 WaitTime != -1 ? &Timeout : NULL);
232
233 ExAcquireFastMutex(&BattClass->Mutex);
234 BattClass->Waiting = FALSE;
235 ExReleaseFastMutex(&BattClass->Mutex);
236
237 if (Status == STATUS_SUCCESS)
238 {
239 Status = BattClass->MiniportInfo.QueryTag(BattClass->MiniportInfo.Context,
240 (PULONG)Irp->AssociatedIrp.SystemBuffer);
241 if (NT_SUCCESS(Status))
242 Irp->IoStatus.Information = sizeof(ULONG);
243 }
244 else
245 {
246 Status = STATUS_NO_SUCH_DEVICE;
247 }
248 }
249 else
250 Irp->IoStatus.Information = sizeof(ULONG);
251 break;
252
253 case IOCTL_BATTERY_QUERY_STATUS:
254 if (IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(*BattWait) ||
255 IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(BATTERY_STATUS))
256 {
257 Status = STATUS_BUFFER_TOO_SMALL;
258 break;
259 }
260
261 BattWait = Irp->AssociatedIrp.SystemBuffer;
262
263 Timeout.QuadPart = Int32x32To64(BattWait->Timeout, -1000);
264
265 Status = BattClass->MiniportInfo.QueryStatus(BattClass->MiniportInfo.Context,
266 BattWait->BatteryTag,
267 (PBATTERY_STATUS)Irp->AssociatedIrp.SystemBuffer);
268
269 BattStatus = Irp->AssociatedIrp.SystemBuffer;
270
271 if (!NT_SUCCESS(Status) ||
272 ((BattWait->PowerState & BattStatus->PowerState) &&
273 (BattWait->HighCapacity <= BattStatus->Capacity) &&
274 (BattWait->LowCapacity >= BattStatus->Capacity)))
275 {
276 BattNotify.PowerState = BattWait->PowerState;
277 BattNotify.HighCapacity = BattWait->HighCapacity;
278 BattNotify.LowCapacity = BattWait->LowCapacity;
279
280 BattClass->MiniportInfo.SetStatusNotify(BattClass->MiniportInfo.Context,
281 BattWait->BatteryTag,
282 &BattNotify);
283
284 ExAcquireFastMutex(&BattClass->Mutex);
285 BattClass->EventTrigger = EVENT_BATTERY_STATUS;
286 BattClass->EventTriggerContext = BattWait;
287 BattClass->Waiting = TRUE;
288 ExReleaseFastMutex(&BattClass->Mutex);
289
290 Status = KeWaitForSingleObject(&BattClass->WaitEvent,
291 Executive,
292 KernelMode,
293 FALSE,
294 BattWait->Timeout != -1 ? &Timeout : NULL);
295
296 ExAcquireFastMutex(&BattClass->Mutex);
297 BattClass->Waiting = FALSE;
298 ExReleaseFastMutex(&BattClass->Mutex);
299
300 BattClass->MiniportInfo.DisableStatusNotify(BattClass->MiniportInfo.Context);
301
302 if (Status == STATUS_SUCCESS)
303 {
304 Status = BattClass->MiniportInfo.QueryStatus(BattClass->MiniportInfo.Context,
305 BattWait->BatteryTag,
306 (PBATTERY_STATUS)Irp->AssociatedIrp.SystemBuffer);
307 if (NT_SUCCESS(Status))
308 Irp->IoStatus.Information = sizeof(ULONG);
309 }
310 else
311 {
312 Status = STATUS_NO_SUCH_DEVICE;
313 }
314 }
315 else
316 Irp->IoStatus.Information = sizeof(BATTERY_STATUS);
317 break;
318
319 case IOCTL_BATTERY_QUERY_INFORMATION:
320 if (IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(*BattQueryInfo))
321 {
322 Status = STATUS_BUFFER_TOO_SMALL;
323 break;
324 }
325
326 BattQueryInfo = Irp->AssociatedIrp.SystemBuffer;
327
328 Status = BattClass->MiniportInfo.QueryInformation(BattClass->MiniportInfo.Context,
329 BattQueryInfo->BatteryTag,
330 BattQueryInfo->InformationLevel,
331 BattQueryInfo->AtRate,
332 Irp->AssociatedIrp.SystemBuffer,
333 IrpSp->Parameters.DeviceIoControl.OutputBufferLength,
334 &ReturnedLength);
335 Irp->IoStatus.Information = ReturnedLength;
336 if (!NT_SUCCESS(Status))
337 DPRINT1("QueryInformation failed (0x%x)\n", Status);
338 break;
339 case IOCTL_BATTERY_SET_INFORMATION:
340 if (IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(*BattSetInfo))
341 {
342 Status = STATUS_BUFFER_TOO_SMALL;
343 break;
344 }
345
346 BattSetInfo = Irp->AssociatedIrp.SystemBuffer;
347
348 Status = BattClass->MiniportInfo.SetInformation(BattClass->MiniportInfo.Context,
349 BattSetInfo->BatteryTag,
350 BattSetInfo->InformationLevel,
351 BattSetInfo->Buffer);
352 if (!NT_SUCCESS(Status))
353 DPRINT1("SetInformation failed (0x%x)\n", Status);
354 break;
355
356 default:
357 DPRINT1("Received unsupported IRP %x\n", IrpSp->Parameters.DeviceIoControl.IoControlCode);
358 /* Do NOT complete the irp */
359 return STATUS_NOT_SUPPORTED;
360 }
361
362 Irp->IoStatus.Status = Status;
363 IoCompleteRequest(Irp, IO_NO_INCREMENT);
364
365 return Status;
366 }