sync with trunk r46493
[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 DDKAPI
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 DDKAPI
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 DDKAPI
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 DDKAPI
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 DDKAPI
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 DDKAPI
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
190 Irp->IoStatus.Information = 0;
191
192 DPRINT("Received IOCTL %x for 0x%x\n", IrpSp->Parameters.DeviceIoControl.IoControlCode,
193 ClassData);
194
195 switch (IrpSp->Parameters.DeviceIoControl.IoControlCode)
196 {
197 case IOCTL_BATTERY_QUERY_TAG:
198 if (IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(ULONG) ||
199 IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(ULONG))
200 {
201 Status = STATUS_BUFFER_TOO_SMALL;
202 break;
203 }
204
205 WaitTime = *(PULONG)Irp->AssociatedIrp.SystemBuffer;
206
207 Timeout.QuadPart = Int32x32To64(WaitTime, -1000);
208
209 Status = BattClass->MiniportInfo.QueryTag(BattClass->MiniportInfo.Context,
210 (PULONG)Irp->AssociatedIrp.SystemBuffer);
211 if (!NT_SUCCESS(Status))
212 {
213 ExAcquireFastMutex(&BattClass->Mutex);
214 BattClass->EventTrigger = EVENT_BATTERY_TAG;
215 BattClass->Waiting = TRUE;
216 ExReleaseFastMutex(&BattClass->Mutex);
217
218 Status = KeWaitForSingleObject(&BattClass->WaitEvent,
219 Executive,
220 KernelMode,
221 FALSE,
222 WaitTime != -1 ? &Timeout : NULL);
223
224 ExAcquireFastMutex(&BattClass->Mutex);
225 BattClass->Waiting = FALSE;
226 ExReleaseFastMutex(&BattClass->Mutex);
227
228 if (Status == STATUS_SUCCESS)
229 {
230 Status = BattClass->MiniportInfo.QueryTag(BattClass->MiniportInfo.Context,
231 (PULONG)Irp->AssociatedIrp.SystemBuffer);
232 if (NT_SUCCESS(Status))
233 Irp->IoStatus.Information = sizeof(ULONG);
234 }
235 else
236 {
237 Status = STATUS_NO_SUCH_DEVICE;
238 }
239 }
240 else
241 Irp->IoStatus.Information = sizeof(ULONG);
242 break;
243
244 case IOCTL_BATTERY_QUERY_STATUS:
245 if (IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(*BattWait) ||
246 IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(BATTERY_STATUS))
247 {
248 Status = STATUS_BUFFER_TOO_SMALL;
249 break;
250 }
251
252 BattWait = Irp->AssociatedIrp.SystemBuffer;
253
254 Timeout.QuadPart = Int32x32To64(BattWait->Timeout, -1000);
255
256 Status = BattClass->MiniportInfo.QueryStatus(BattClass->MiniportInfo.Context,
257 BattWait->BatteryTag,
258 (PBATTERY_STATUS)Irp->AssociatedIrp.SystemBuffer);
259
260 BattStatus = Irp->AssociatedIrp.SystemBuffer;
261
262 if (!NT_SUCCESS(Status) ||
263 ((BattWait->PowerState & BattStatus->PowerState) &&
264 (BattWait->HighCapacity <= BattStatus->Capacity) &&
265 (BattWait->LowCapacity >= BattStatus->Capacity)))
266 {
267 BattNotify.PowerState = BattWait->PowerState;
268 BattNotify.HighCapacity = BattWait->HighCapacity;
269 BattNotify.LowCapacity = BattWait->LowCapacity;
270
271 BattClass->MiniportInfo.SetStatusNotify(BattClass->MiniportInfo.Context,
272 BattWait->BatteryTag,
273 &BattNotify);
274
275 ExAcquireFastMutex(&BattClass->Mutex);
276 BattClass->EventTrigger = EVENT_BATTERY_STATUS;
277 BattClass->EventTriggerContext = BattWait;
278 BattClass->Waiting = TRUE;
279 ExReleaseFastMutex(&BattClass->Mutex);
280
281 Status = KeWaitForSingleObject(&BattClass->WaitEvent,
282 Executive,
283 KernelMode,
284 FALSE,
285 BattWait->Timeout != -1 ? &Timeout : NULL);
286
287 ExAcquireFastMutex(&BattClass->Mutex);
288 BattClass->Waiting = FALSE;
289 ExReleaseFastMutex(&BattClass->Mutex);
290
291 BattClass->MiniportInfo.DisableStatusNotify(BattClass->MiniportInfo.Context);
292
293 if (Status == STATUS_SUCCESS)
294 {
295 Status = BattClass->MiniportInfo.QueryStatus(BattClass->MiniportInfo.Context,
296 BattWait->BatteryTag,
297 (PBATTERY_STATUS)Irp->AssociatedIrp.SystemBuffer);
298 if (NT_SUCCESS(Status))
299 Irp->IoStatus.Information = sizeof(ULONG);
300 }
301 else
302 {
303 Status = STATUS_NO_SUCH_DEVICE;
304 }
305 }
306 else
307 Irp->IoStatus.Information = sizeof(BATTERY_STATUS);
308 break;
309
310 case IOCTL_BATTERY_QUERY_INFORMATION:
311 if (IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(*BattQueryInfo))
312 {
313 Status = STATUS_BUFFER_TOO_SMALL;
314 break;
315 }
316
317 BattQueryInfo = Irp->AssociatedIrp.SystemBuffer;
318
319 Status = BattClass->MiniportInfo.QueryInformation(BattClass->MiniportInfo.Context,
320 BattQueryInfo->BatteryTag,
321 BattQueryInfo->InformationLevel,
322 BattQueryInfo->AtRate,
323 Irp->AssociatedIrp.SystemBuffer,
324 IrpSp->Parameters.DeviceIoControl.OutputBufferLength,
325 &Irp->IoStatus.Information);
326 if (!NT_SUCCESS(Status))
327 DPRINT1("QueryInformation failed (0x%x)\n", Status);
328 break;
329 case IOCTL_BATTERY_SET_INFORMATION:
330 if (IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(*BattSetInfo))
331 {
332 Status = STATUS_BUFFER_TOO_SMALL;
333 break;
334 }
335
336 BattSetInfo = Irp->AssociatedIrp.SystemBuffer;
337
338 Status = BattClass->MiniportInfo.SetInformation(BattClass->MiniportInfo.Context,
339 BattSetInfo->BatteryTag,
340 BattSetInfo->InformationLevel,
341 BattSetInfo->Buffer);
342 if (!NT_SUCCESS(Status))
343 DPRINT1("SetInformation failed (0x%x)\n", Status);
344 break;
345
346 default:
347 DPRINT1("Received unsupported IRP %x\n", IrpSp->Parameters.DeviceIoControl.IoControlCode);
348 /* Do NOT complete the irp */
349 return STATUS_NOT_SUPPORTED;
350 }
351
352 Irp->IoStatus.Status = Status;
353 IoCompleteRequest(Irp, IO_NO_INCREMENT);
354
355 return Status;
356 }