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