45903cb16e038c1014e16d6e81ac27ddeb2f6fcf
[reactos.git] / reactos / drivers / bus / acpi / cmbatt / cmbatt.c
1 /*
2 * PROJECT: ReactOS ACPI-Compliant Control Method Battery
3 * LICENSE: BSD - See COPYING.ARM in the top level directory
4 * FILE: boot/drivers/bus/acpi/cmbatt/cmbatt.c
5 * PURPOSE: Main Initialization Code and IRP Handling
6 * PROGRAMMERS: ReactOS Portable Systems Group
7 */
8
9 /* INCLUDES *******************************************************************/
10
11 #include "cmbatt.h"
12
13 /* GLOBALS ********************************************************************/
14
15 ULONG CmBattDebug;
16 PCALLBACK_OBJECT CmBattPowerCallBackObject;
17 PVOID CmBattPowerCallBackRegistration;
18 UNICODE_STRING GlobalRegistryPath;
19 KTIMER CmBattWakeDpcTimerObject;
20 KDPC CmBattWakeDpcObject;
21 PDEVICE_OBJECT AcAdapterPdo;
22
23 /* FUNCTIONS ******************************************************************/
24
25 VOID
26 NTAPI
27 CmBattPowerCallBack(PCMBATT_DEVICE_EXTENSION DeviceExtension,
28 PVOID Argument1,
29 PVOID Argument2)
30 {
31 UNIMPLEMENTED;
32 }
33
34 VOID
35 NTAPI
36 CmBattWakeDpc(PKDPC Dpc,
37 PCMBATT_DEVICE_EXTENSION FdoExtension,
38 PVOID SystemArgument1,
39 PVOID SystemArgument2)
40 {
41
42 }
43
44 VOID
45 NTAPI
46 CmBattNotifyHandler(PCMBATT_DEVICE_EXTENSION DeviceExtension,
47 ULONG NotifyValue)
48 {
49 UNIMPLEMENTED;
50 }
51
52 VOID
53 NTAPI
54 CmBattUnload(IN PDRIVER_OBJECT DriverObject)
55 {
56 if (CmBattDebug & CMBATT_GENERIC_INFO) DPRINT("CmBattUnload: \n");
57
58 /* Check if we have a registered power callback */
59 if (CmBattPowerCallBackObject)
60 {
61 /* Get rid of it */
62 ExUnregisterCallback(CmBattPowerCallBackRegistration);
63 ObfDereferenceObject(CmBattPowerCallBackObject);
64 }
65
66 /* Free the registry buffer if it exists */
67 if (GlobalRegistryPath.Buffer) ExFreePool(GlobalRegistryPath.Buffer);
68
69 /* Make sure we don't still have references to the DO */
70 if ((DriverObject->DeviceObject) && (CmBattDebug & CMBATT_GENERIC_WARNING))
71 {
72 DbgPrint("Unload called before all devices removed.\n");
73 }
74 }
75
76 NTSTATUS
77 NTAPI
78 CmBattVerifyStaticInfo(PCMBATT_DEVICE_EXTENSION DeviceExtension,
79 ULONG BatteryTag)
80 {
81 UNIMPLEMENTED;
82 return STATUS_NOT_IMPLEMENTED;
83 }
84
85 NTSTATUS
86 NTAPI
87 CmBattOpenClose(IN PDEVICE_OBJECT DeviceObject,
88 IN PIRP Irp)
89 {
90 NTSTATUS Status = STATUS_SUCCESS;
91 PIO_STACK_LOCATION IoStackLocation;
92 UCHAR Major;
93 ULONG Count;
94 PCMBATT_DEVICE_EXTENSION DeviceExtension;
95 PAGED_CODE();
96 if (CmBattDebug & CMBATT_GENERIC_INFO) DPRINT("CmBattOpenClose\n");
97
98 /* Grab the device extension and lock it */
99 DeviceExtension = DeviceObject->DeviceExtension;
100 ExAcquireFastMutex(&DeviceExtension->FastMutex);
101
102 /* Check if someone is trying to open a device that doesn't exist yet */
103 Count = DeviceExtension->HandleCount;
104 if (Count == 0xFFFFFFFF)
105 {
106 /* Fail the request */
107 Status = STATUS_NO_SUCH_DEVICE;
108 if (CmBattDebug & CMBATT_PNP_INFO)
109 {
110 DbgPrint("CmBattOpenClose: Failed (UID = %x)(device being removed).\n",
111 DeviceExtension->Tag);
112 }
113 goto Complete;
114 }
115
116 /* Check if this is an open or close */
117 IoStackLocation = IoGetCurrentIrpStackLocation(Irp);
118 Major = IoStackLocation->MajorFunction;
119 if (Major == IRP_MJ_CREATE)
120 {
121 /* Increment the open count */
122 DeviceExtension->HandleCount = Count + 1;
123 if (CmBattDebug & CMBATT_PNP_INFO)
124 {
125 DbgPrint("CmBattOpenClose: Open (DeviceNumber = %x)(count = %x).\n",
126 DeviceExtension->DeviceId, Count + 1);
127 }
128 }
129 else if (Major == IRP_MJ_CLOSE)
130 {
131 /* Decrement the open count */
132 DeviceExtension->HandleCount = Count - 1;
133 if (CmBattDebug & CMBATT_PNP_INFO)
134 {
135 DbgPrint("CmBattOpenClose: Close (DeviceNumber = %x)(count = %x).\n",
136 DeviceExtension->DeviceId, Count + 1);
137 }
138 }
139
140 Complete:
141 /* Release lock and complete request */
142 ExReleaseFastMutex(&DeviceExtension->FastMutex);
143 Irp->IoStatus.Status = Status;
144 IofCompleteRequest(Irp, IO_NO_INCREMENT);
145 return Status;
146 }
147
148 NTSTATUS
149 NTAPI
150 CmBattIoctl(PDEVICE_OBJECT DeviceObject,
151 PIRP Irp)
152 {
153 UNIMPLEMENTED;
154 return STATUS_NOT_IMPLEMENTED;
155 }
156
157 NTSTATUS
158 NTAPI
159 CmBattQueryTag(PCMBATT_DEVICE_EXTENSION DeviceExtension,
160 PULONG BatteryTag)
161 {
162 UNIMPLEMENTED;
163 return STATUS_NOT_IMPLEMENTED;
164 }
165
166 NTSTATUS
167 NTAPI
168 CmBattDisableStatusNotify(PCMBATT_DEVICE_EXTENSION DeviceExtension)
169 {
170 UNIMPLEMENTED;
171 return STATUS_NOT_IMPLEMENTED;
172 }
173
174 NTSTATUS
175 NTAPI
176 CmBattSetStatusNotify(PCMBATT_DEVICE_EXTENSION DeviceExtension,
177 ULONG BatteryTag,
178 PBATTERY_NOTIFY BatteryNotify)
179 {
180 UNIMPLEMENTED;
181 return STATUS_NOT_IMPLEMENTED;
182 }
183
184 NTSTATUS
185 NTAPI
186 CmBattGetBatteryStatus(IN PCMBATT_DEVICE_EXTENSION DeviceExtension,
187 IN ULONG Tag)
188 {
189 ULONG PsrData = 0;
190 NTSTATUS Status;
191 ULONG BstState;
192 ULONG DesignVoltage, PresentRate, RemainingCapacity;
193 PAGED_CODE();
194 if (CmBattDebug & CMBATT_GENERIC_INFO)
195 DbgPrint("CmBattGetBatteryStatus - CmBatt (%08x) Tag (%d)\n", DeviceExtension, Tag);
196
197 /* Validate ACPI data */
198 Status = CmBattVerifyStaticInfo(DeviceExtension, Tag);
199 if (!NT_SUCCESS(Status)) return Status;
200
201 /* Check for delayed status notifications */
202 if (DeviceExtension->DelayNotification)
203 {
204 /* Process them now and don't do any other work */
205 CmBattNotifyHandler(DeviceExtension, ACPI_BATT_NOTIFY_STATUS);
206 return Status;
207 }
208
209 /* Get _BST from ACPI */
210 Status = CmBattGetBstData(DeviceExtension, &DeviceExtension->BstData);
211 if (!NT_SUCCESS(Status))
212 {
213 /* Fail */
214 InterlockedExchange(&DeviceExtension->ArLockValue, 0);
215 return Status;
216 }
217
218 /* Clear current BST information */
219 DeviceExtension->State = 0;
220 DeviceExtension->RemainingCapacity = 0;
221 DeviceExtension->PresentVoltage = 0;
222 DeviceExtension->Rate = 0;
223
224 /* Get battery state */
225 BstState = DeviceExtension->BstData.State;
226
227 /* Is the battery both charging and discharging? */
228 if ((BstState & ACPI_BATT_STAT_DISCHARG) && (BstState & ACPI_BATT_STAT_CHARGING) &&
229 (CmBattDebug & (CMBATT_ACPI_WARNING | CMBATT_GENERIC_WARNING)))
230 DbgPrint("************************ ACPI BIOS BUG ********************\n* "
231 "CmBattGetBatteryStatus: Invalid state: _BST method returned 0x%08x for Battery State.\n"
232 "* One battery cannot be charging and discharging at the same time.\n",
233 BstState);
234
235 /* Is the battery discharging? */
236 if (BstState & ACPI_BATT_STAT_DISCHARG)
237 {
238 /* Set power state and check if it just started discharging now */
239 DeviceExtension->State |= BATTERY_DISCHARGING;
240 if (!(DeviceExtension->State & ACPI_BATT_STAT_DISCHARG))
241 {
242 /* Remember the time when the state changed */
243 DeviceExtension->InterruptTime = KeQueryInterruptTime();
244 }
245 }
246 else if (BstState & ACPI_BATT_STAT_CHARGING)
247 {
248 /* Battery is charging, update power state */
249 DeviceExtension->State |= (BATTERY_CHARGING | BATTERY_POWER_ON_LINE);
250 }
251
252 /* Is the battery in a critical state? */
253 if (BstState & ACPI_BATT_STAT_CRITICAL) DeviceExtension->State |= BATTERY_CRITICAL;
254
255 /* Read the voltage data */
256 DeviceExtension->PresentVoltage = DeviceExtension->BstData.PresentVoltage;
257
258 /* Check if we have an A/C adapter */
259 if (AcAdapterPdo)
260 {
261 /* Query information on it */
262 CmBattGetPsrData(AcAdapterPdo, &PsrData);
263 }
264 else
265 {
266 /* Otherwise, check if the battery is charging */
267 if (BstState & ACPI_BATT_STAT_CHARGING)
268 {
269 /* Then we'll assume there's a charger */
270 PsrData = 1;
271 }
272 else
273 {
274 /* Assume no charger */
275 PsrData = 0;
276 }
277 }
278
279 /* Is there a charger? */
280 if (PsrData)
281 {
282 /* Set the power state flag to reflect this */
283 DeviceExtension->State |= BATTERY_POWER_ON_LINE;
284 if (CmBattDebug & (CMBATT_GENERIC_INFO | CMBATT_GENERIC_STATUS))
285 DbgPrint("CmBattGetBatteryStatus: AC adapter is connected\n");
286 }
287 else if (CmBattDebug & (CMBATT_GENERIC_INFO | CMBATT_GENERIC_STATUS))
288 {
289 DbgPrint("CmBattGetBatteryStatus: AC adapter is NOT connected\n");
290 }
291
292 /* Get some data we'll need */
293 DesignVoltage = DeviceExtension->BifData.DesignVoltage;
294 PresentRate = DeviceExtension->BstData.PresentRate;
295 RemainingCapacity = DeviceExtension->BstData.RemainingCapacity;
296
297 /* Check if we have battery data in Watts instead of Amps */
298 if (DeviceExtension->BifData.PowerUnit == ACPI_BATT_POWER_UNIT_WATTS)
299 {
300 /* Get the data from the BST */
301 DeviceExtension->RemainingCapacity = RemainingCapacity;
302 DeviceExtension->Rate = PresentRate;
303
304 /* Check if the rate is invalid */
305 if (PresentRate > CM_MAX_VALUE)
306 {
307 /* Set an unknown rate and don't touch the old value */
308 DeviceExtension->Rate = BATTERY_UNKNOWN_RATE;
309 if ((PresentRate != CM_UNKNOWN_VALUE) && (CmBattDebug & CMBATT_ACPI_WARNING))
310 {
311 DbgPrint("CmBattGetBatteryStatus - Rate is greater than CM_MAX_VALUE\n");
312 DbgPrint("---------------------- PresentRate = 0x%08x\n", PresentRate);
313 }
314 }
315 }
316 else if ((DesignVoltage != CM_UNKNOWN_VALUE) && (DesignVoltage))
317 {
318 /* We have voltage data, what about capacity? */
319 if (RemainingCapacity == CM_UNKNOWN_VALUE)
320 {
321 /* Unable to calculate it */
322 DeviceExtension->RemainingCapacity = BATTERY_UNKNOWN_CAPACITY;
323 if (CmBattDebug & CMBATT_ACPI_WARNING)
324 {
325 DbgPrint("CmBattGetBatteryStatus - Can't calculate RemainingCapacity \n");
326 DbgPrint("---------------------- RemainingCapacity = CM_UNKNOWN_VALUE\n");
327 }
328 }
329 else
330 {
331 /* Compute the capacity with the information we have */
332 DeviceExtension->RemainingCapacity = (DesignVoltage * RemainingCapacity + 500) / 1000;
333 }
334
335 /* Check if we have a rate */
336 if (PresentRate != CM_UNKNOWN_VALUE)
337 {
338 /* Make sure the rate isn't too large */
339 if (PresentRate > (-500 / DesignVoltage))
340 {
341 /* It is, so set unknown state */
342 DeviceExtension->Rate = BATTERY_UNKNOWN_RATE;
343 if (CmBattDebug & CMBATT_ACPI_WARNING)
344 {
345 DbgPrint("CmBattGetBatteryStatus - Can't calculate Rate \n");
346 DbgPrint("---------------------- Overflow: PresentRate = 0x%08x\n", PresentRate);
347 }
348 }
349
350 /* Compute the rate */
351 DeviceExtension->Rate = (PresentRate * DesignVoltage + 500) / 1000;
352 }
353 else
354 {
355 /* We don't have a rate, so set unknown value */
356 DeviceExtension->Rate = BATTERY_UNKNOWN_RATE;
357 if (CmBattDebug & CMBATT_ACPI_WARNING)
358 {
359 DbgPrint("CmBattGetBatteryStatus - Can't calculate Rate \n");
360 DbgPrint("---------------------- Present Rate = CM_UNKNOWN_VALUE\n");
361 }
362 }
363 }
364 else
365 {
366 /* We have no rate, and no capacity, set unknown values */
367 DeviceExtension->Rate = BATTERY_UNKNOWN_RATE;
368 DeviceExtension->RemainingCapacity = BATTERY_UNKNOWN_CAPACITY;
369 if (CmBattDebug & CMBATT_ACPI_WARNING)
370 {
371 DbgPrint("CmBattGetBatteryStatus - Can't calculate RemainingCapacity and Rate \n");
372 DbgPrint("---------------------- DesignVoltage = 0x%08x\n", DesignVoltage);
373 }
374 }
375
376 /* Check if we have an unknown rate */
377 if (DeviceExtension->Rate == BATTERY_UNKNOWN_RATE)
378 {
379 /* The battery is discharging but we don't know by how much... this is bad! */
380 if ((BstState & ACPI_BATT_STAT_DISCHARG) &&
381 (CmBattDebug & (CMBATT_ACPI_WARNING | CMBATT_GENERIC_WARNING)))
382 DbgPrint("CmBattGetBatteryStatus: battery rate is unkown when battery is not charging!\n");
383 }
384 else if (DeviceExtension->State & BATTERY_DISCHARGING)
385 {
386 /* The battery is discharging, so treat the rate as a negative rate */
387 DeviceExtension->Rate = -DeviceExtension->Rate;
388 }
389 else if (!(DeviceExtension->State & BATTERY_CHARGING) && (DeviceExtension->Rate))
390 {
391 /* We are not charging, not discharging, but have a rate? Ignore it! */
392 if (CmBattDebug & CMBATT_GENERIC_WARNING)
393 DbgPrint("CmBattGetBatteryStatus: battery is not charging or discharging, but rate = %x\n",
394 DeviceExtension->Rate);
395 DeviceExtension->Rate = 0;
396 }
397
398 /* Done */
399 return STATUS_SUCCESS;
400 }
401
402 NTSTATUS
403 NTAPI
404 CmBattQueryInformation(IN PCMBATT_DEVICE_EXTENSION FdoExtension,
405 IN ULONG Tag,
406 IN BATTERY_QUERY_INFORMATION_LEVEL InfoLevel,
407 IN OPTIONAL LONG AtRate,
408 IN PVOID Buffer,
409 IN ULONG BufferLength,
410 OUT PULONG ReturnedLength)
411 {
412 NTSTATUS Status;
413 PVOID QueryData = NULL;
414 ULONG QueryLength = 0;
415 ULONG RemainingTime = 0;
416 ANSI_STRING TempString;
417 UNICODE_STRING TempString2;
418 WCHAR InfoBuffer[256];
419 WCHAR TempBuffer[256];
420 UNICODE_STRING InfoString;
421 ULONG RemainingCapacity;
422 BATTERY_REPORTING_SCALE BatteryReportingScale[2];
423 LONG Rate;
424 PAGED_CODE();
425 if (CmBattDebug & (CMBATT_ACPI_WARNING | CMBATT_GENERIC_INFO))
426 DbgPrint("CmBattQueryInformation - Tag (%d) Device %d, Informationlevel %d\n",
427 Tag,
428 FdoExtension->DeviceId,
429 InfoLevel);
430
431 /* Check ACPI Data */
432 Status = CmBattVerifyStaticInfo(FdoExtension, Tag);
433 if (!NT_SUCCESS(Status)) return Status;
434
435 /* Check what caller wants */
436 switch (InfoLevel)
437 {
438 case BatteryInformation:
439 /* Just return our static information */
440 QueryData = &FdoExtension->BatteryInformation;
441 QueryLength = sizeof(BATTERY_INFORMATION);
442 break;
443
444 case BatteryGranularityInformation:
445
446 /* Return our static information, we have two scales */
447 BatteryReportingScale[0].Granularity = FdoExtension->BatteryCapacityGranularity1;
448 BatteryReportingScale[0].Capacity = FdoExtension->BatteryInformation.DefaultAlert1;
449 BatteryReportingScale[1].Granularity = FdoExtension->BatteryCapacityGranularity2;
450 BatteryReportingScale[1].Capacity = FdoExtension->BatteryInformation.DesignedCapacity;
451 QueryData = BatteryReportingScale;
452 QueryLength = sizeof(BATTERY_REPORTING_SCALE) * 2;
453 break;
454
455 case BatteryEstimatedTime:
456
457 /* Check if it's been more than 2 1/2 minutes since the last change */
458 if ((KeQueryInterruptTime() - 150000000) > (FdoExtension->InterruptTime))
459 {
460 /* Get new battery status */
461 CmBattGetBatteryStatus(FdoExtension, FdoExtension->Tag);
462
463 /* If the caller didn't specify a rate, use our static one */
464 Rate = AtRate;
465 if (!Rate) Rate = FdoExtension->Rate;
466
467 /* If we don't have a valid negative rate, use unknown value */
468 if (Rate >= 0) Rate = BATTERY_UNKNOWN_RATE;
469
470 /* Grab the remaining capacity */
471 RemainingCapacity = FdoExtension->RemainingCapacity;
472
473 /* See if we don't know one or the other */
474 if ((Rate == BATTERY_UNKNOWN_RATE) ||
475 (RemainingCapacity == BATTERY_UNKNOWN_CAPACITY))
476 {
477 /* If the battery is discharging, we can't give out a time */
478 if ((FdoExtension->BstData.State & ACPI_BATT_STAT_DISCHARG) &&
479 (CmBattDebug & CMBATT_GENERIC_WARNING))
480 DbgPrint("CmBattQueryInformation: Can't calculate EstimatedTime.\n");
481
482 /* Check if we don't have a rate and capacity is going down */
483 if ((FdoExtension->Rate == BATTERY_UNKNOWN_RATE) &&
484 (FdoExtension->BstData.State & ACPI_BATT_STAT_DISCHARG))
485 {
486 /* We have to fail, since we lack data */
487 Status = STATUS_INVALID_DEVICE_REQUEST;
488 if (CmBattDebug & CMBATT_GENERIC_WARNING)
489 DbgPrint("---------------------- PresentRate = BATTERY_UNKNOWN_RATE\n");
490 }
491
492 /* If we don't have capacity, the rate is useless */
493 if (RemainingCapacity == BATTERY_UNKNOWN_CAPACITY)
494 {
495 /* We have to fail the request */
496 Status = STATUS_INVALID_DEVICE_REQUEST;
497 if (CmBattDebug & CMBATT_GENERIC_WARNING)
498 DbgPrint("---------------------- RemainingCapacity = BATTERY_UNKNOWN_CAPACITY\n");
499 }
500 }
501 else
502 {
503 /* We have data, but is it valid? */
504 if (RemainingCapacity > 0x123456)
505 {
506 /* The capacity seems bogus, so don't use it */
507 if (CmBattDebug & CMBATT_ACPI_WARNING)
508 DbgPrint("CmBattQueryInformation: Data Overflow in calculating Remaining Capacity.\n");
509 }
510 else
511 {
512 /* Compute the remaining time in seconds, based on rate */
513 RemainingTime = (RemainingCapacity * 3600) / -Rate;
514 }
515 }
516 }
517
518 /* Return the remaining time */
519 QueryData = &RemainingTime;
520 QueryLength = sizeof(ULONG);
521 break;
522
523 case BatteryDeviceName:
524
525 /* Build the model number string */
526 RtlInitAnsiString(&TempString, FdoExtension->ModelNumber);
527
528 /* Convert it to Unicode */
529 InfoString.Buffer = InfoBuffer;
530 InfoString.MaximumLength = sizeof(InfoBuffer);
531 Status = RtlAnsiStringToUnicodeString(&InfoString, &TempString, 0);
532
533 /* Return the unicode buffer */
534 QueryData = InfoString.Buffer;
535 QueryLength = InfoString.Length;
536 break;
537
538 case BatteryTemperature:
539 case BatteryManufactureDate:
540
541 /* We don't support these */
542 Status = STATUS_INVALID_DEVICE_REQUEST;
543 break;
544
545 case BatteryManufactureName:
546
547 /* Build the OEM info string */
548 RtlInitAnsiString(&TempString, FdoExtension->OemInfo);
549
550 /* Convert it to Unicode */
551 InfoString.Buffer = InfoBuffer;
552 InfoString.MaximumLength = sizeof(InfoBuffer);
553 Status = RtlAnsiStringToUnicodeString(&InfoString, &TempString, 0);
554
555 /* Return the unicode buffer */
556 QueryData = InfoString.Buffer;
557 QueryLength = InfoString.Length;
558 break;
559
560 case BatteryUniqueID:
561
562 /* Build the serial number string */
563 RtlInitAnsiString(&TempString, FdoExtension->SerialNumber);
564
565 /* Convert it to Unicode */
566 InfoString.Buffer = InfoBuffer;
567 InfoString.MaximumLength = sizeof(InfoBuffer);
568 RtlAnsiStringToUnicodeString(&InfoString, &TempString, 0);
569
570 /* Setup a temporary string for concatenation */
571 TempString2.Buffer = TempBuffer;
572 TempString2.MaximumLength = sizeof(TempBuffer);
573
574 /* Check if there's an OEM string */
575 if (FdoExtension->OemInfo[0])
576 {
577 /* Build the OEM info string */
578 RtlInitAnsiString(&TempString, FdoExtension->OemInfo);
579
580 /* Convert it to Unicode and append it */
581 RtlAnsiStringToUnicodeString(&TempString2, &TempString, 0);
582 RtlAppendUnicodeStringToString(&InfoString, &TempString2);
583 }
584
585 /* Build the model number string */
586 RtlInitAnsiString(&TempString, FdoExtension->ModelNumber);
587
588 /* Convert it to Unicode and append it */
589 RtlAnsiStringToUnicodeString(&TempString2, &TempString, 0);
590 RtlAppendUnicodeStringToString(&InfoString, &TempString2);
591
592 /* Return the final appended string */
593 QueryData = InfoString.Buffer;
594 QueryLength = InfoString.Length;
595 break;
596
597 default:
598
599 /* Everything else is unknown */
600 Status = STATUS_INVALID_PARAMETER;
601 break;
602 }
603
604 /* Return the required length and check if the caller supplied enough */
605 *ReturnedLength = QueryLength;
606 if (BufferLength < QueryLength) Status = STATUS_BUFFER_TOO_SMALL;
607
608 /* Copy the data if there's enough space and it exists */
609 if ((NT_SUCCESS(Status)) && (QueryData)) RtlCopyMemory(Buffer, QueryData, QueryLength);
610
611 /* Return function result */
612 return Status;
613 }
614
615 NTSTATUS
616 NTAPI
617 CmBattQueryStatus(IN PCMBATT_DEVICE_EXTENSION DeviceExtension,
618 IN ULONG Tag,
619 IN PBATTERY_STATUS BatteryStatus)
620 {
621 NTSTATUS Status;
622 PAGED_CODE();
623 if (CmBattDebug & (CMBATT_ACPI_WARNING | CMBATT_GENERIC_INFO))
624 DbgPrint("CmBattQueryStatus - Tag (%d) Device %x\n", Tag, DeviceExtension->DeviceId);
625
626 /* Query ACPI information */
627 Status = CmBattGetBatteryStatus(DeviceExtension, Tag);
628 if (NT_SUCCESS(Status))
629 {
630 BatteryStatus->PowerState = DeviceExtension->State;
631 BatteryStatus->Capacity = DeviceExtension->RemainingCapacity;
632 BatteryStatus->Voltage = DeviceExtension->PresentVoltage;
633 BatteryStatus->Rate = DeviceExtension->Rate;
634 }
635
636 /* Return status */
637 if (CmBattDebug & (CMBATT_GENERIC_INFO))
638 DbgPrint("CmBattQueryStatus: Returning [%#08lx][%#08lx][%#08lx][%#08lx]\n",
639 BatteryStatus->PowerState,
640 BatteryStatus->Capacity,
641 BatteryStatus->Voltage,
642 BatteryStatus->Rate);
643 return Status;
644 }
645
646 NTSTATUS
647 NTAPI
648 DriverEntry(IN PDRIVER_OBJECT DriverObject,
649 IN PUNICODE_STRING RegistryPath)
650 {
651 NTSTATUS Status;
652 PDRIVER_EXTENSION DriverExtension;
653 OBJECT_ATTRIBUTES ObjectAttributes;
654 UNICODE_STRING CallbackName;
655
656 /* Allocate registry path */
657 GlobalRegistryPath.MaximumLength = RegistryPath->Length + sizeof(UNICODE_NULL);
658 GlobalRegistryPath.Length = RegistryPath->Length;
659 GlobalRegistryPath.Buffer = ExAllocatePoolWithTag(PagedPool,
660 GlobalRegistryPath.MaximumLength,
661 'MtaB');
662 if (!GlobalRegistryPath.Buffer)
663 {
664 /* Fail if we're out of memory this early */
665 if (CmBattDebug & CMBATT_GENERIC_WARNING)
666 DbgPrint("CmBatt: Couldn't allocate pool for registry path.");
667 return STATUS_INSUFFICIENT_RESOURCES;
668 }
669
670 /* Buffer allocated, copy the string */
671 RtlCopyUnicodeString(&GlobalRegistryPath, RegistryPath);
672 if (CmBattDebug & CMBATT_GENERIC_INFO)
673 DbgPrint("CmBatt DriverEntry - Obj (%08x) Path \"%ws\"\n",
674 DriverObject,
675 RegistryPath->Buffer);
676
677 /* Setup the major dispatchers */
678 DriverObject->MajorFunction[0] = CmBattOpenClose;
679 DriverObject->MajorFunction[2] = CmBattOpenClose;
680 DriverObject->MajorFunction[14] = CmBattIoctl;
681 DriverObject->MajorFunction[22] = CmBattPowerDispatch;
682 DriverObject->MajorFunction[27] = CmBattPnpDispatch;
683 DriverObject->MajorFunction[23] = CmBattSystemControl;
684
685 /* And the unload routine */
686 DriverObject->DriverUnload = CmBattUnload;
687
688 /* And the add device routine */
689 DriverExtension = DriverObject->DriverExtension;
690 DriverExtension->AddDevice = CmBattAddDevice;
691
692 /* Create a power callback */
693 RtlInitUnicodeString(&CallbackName, L"\\Callback\\PowerState");
694 InitializeObjectAttributes(&ObjectAttributes,
695 &CallbackName,
696 OBJ_KERNEL_HANDLE,
697 NULL,
698 NULL);
699 Status = ExCreateCallback(&CmBattPowerCallBackObject, &ObjectAttributes, 0, TRUE);
700 if (!NT_SUCCESS(Status))
701 {
702 /* No callback, fail */
703 CmBattPowerCallBackObject = 0;
704 if (CmBattDebug & CMBATT_GENERIC_WARNING)
705 DbgPrint("CmBattRegisterPowerCallBack: failed status=0x%08x\n", Status);
706 }
707 else
708 {
709 /* Register the power callback now */
710 CmBattPowerCallBackRegistration = ExRegisterCallback(CmBattPowerCallBackObject,
711 (PVOID)CmBattPowerCallBack,
712 DriverObject);
713 if (CmBattPowerCallBackRegistration)
714 {
715 /* Last thing: setup our DPC and timer for battery wake */
716 KeInitializeDpc(&CmBattWakeDpcObject, (PVOID)CmBattWakeDpc, DriverObject);
717 KeInitializeTimer(&CmBattWakeDpcTimerObject);
718 }
719 else
720 {
721 ObfDereferenceObject(CmBattPowerCallBackObject);
722 if (CmBattDebug & CMBATT_GENERIC_WARNING)
723 DbgPrint("CmBattRegisterPowerCallBack: ExRegisterCallback failed.\n");
724 }
725
726 /* All good */
727 Status = STATUS_SUCCESS;
728 }
729
730 /* Return failure or success */
731 return Status;
732 }
733
734 /* EOF */