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/cmbpnp.c
5 * PURPOSE: Plug-and-Play IOCTL/IRP Handling
6 * PROGRAMMERS: ReactOS Portable Systems Group
9 /* INCLUDES *******************************************************************/
13 /* FUNCTIONS ******************************************************************/
17 CmBattIoCompletion(IN PDEVICE_OBJECT DeviceObject
,
21 if (CmBattDebug
& 2) DbgPrint("CmBattIoCompletion: Event (%x)\n", Event
);
23 /* Set the completion event */
24 KeSetEvent(Event
, IO_NO_INCREMENT
, FALSE
);
25 return STATUS_MORE_PROCESSING_REQUIRED
;
30 CmBattGetAcpiInterfaces(IN PDEVICE_OBJECT DeviceObject
,
31 IN OUT PACPI_INTERFACE_STANDARD AcpiInterface
)
35 PIO_STACK_LOCATION IoStackLocation
;
38 /* Allocate the IRP */
39 Irp
= IoAllocateIrp(DeviceObject
->StackSize
, 0);
43 if (CmBattDebug
& 0xC)
44 DbgPrint("CmBattGetAcpiInterfaces: Failed to allocate Irp\n");
45 return STATUS_INSUFFICIENT_RESOURCES
;
48 /* Set default error code */
49 Irp
->IoStatus
.Status
= STATUS_NOT_SUPPORTED
;
52 IoStackLocation
= IoGetNextIrpStackLocation(Irp
);
53 IoStackLocation
->MinorFunction
= IRP_MN_QUERY_INTERFACE
;
54 IoStackLocation
->Parameters
.QueryInterface
.InterfaceType
= &GUID_ACPI_INTERFACE_STANDARD
;
55 IoStackLocation
->Parameters
.QueryInterface
.Size
= sizeof(ACPI_INTERFACE_STANDARD
);
56 IoStackLocation
->Parameters
.QueryInterface
.Version
= 1;
57 IoStackLocation
->Parameters
.QueryInterface
.Interface
= (PINTERFACE
)AcpiInterface
;
58 IoStackLocation
->Parameters
.QueryInterface
.InterfaceSpecificData
= NULL
;
60 /* Set default ACPI interface data */
61 AcpiInterface
->Size
= sizeof(ACPI_INTERFACE_STANDARD
);
62 AcpiInterface
->Version
= 1;
64 /* Initialize our wait event */
65 KeInitializeEvent(&Event
, SynchronizationEvent
, 0);
67 /* Set the completion routine */
68 IoCopyCurrentIrpStackLocationToNext(Irp
);
69 IoSetCompletionRoutine(Irp
,
70 (PVOID
)CmBattIoCompletion
,
77 Status
= IoCallDriver(DeviceObject
, Irp
);
78 if (Status
== STATUS_PENDING
)
80 /* Wait for completion */
81 KeWaitForSingleObject(&Event
,
86 Status
= Irp
->IoStatus
.Status
;
93 if (!(NT_SUCCESS(Status
)) && (CmBattDebug
& 0xC))
94 DbgPrint("CmBattGetAcpiInterfaces: Could not get ACPI driver interfaces, status = %x\n", Status
);
100 CmBattDestroyFdo(IN PDEVICE_OBJECT DeviceObject
)
103 if (CmBattDebug
& 0x220) DbgPrint("CmBattDestroyFdo, Battery.\n");
105 /* Delete the device */
106 IoDeleteDevice(DeviceObject
);
107 if (CmBattDebug
& 0x220) DbgPrint("CmBattDestroyFdo: done.\n");
112 CmBattRemoveDevice(IN PDEVICE_OBJECT DeviceObject
,
115 PCMBATT_DEVICE_EXTENSION DeviceExtension
;
117 DeviceExtension
= DeviceObject
->DeviceExtension
;
119 DbgPrint("CmBattRemoveDevice: CmBatt (%x), Type %d, _UID %d\n",
121 DeviceExtension
->FdoType
,
122 DeviceExtension
->DeviceId
);
124 /* Make sure it's safe to go ahead */
125 IoReleaseRemoveLockAndWait(&DeviceExtension
->RemoveLock
, 0);
127 /* Check for pending power IRP */
128 if (DeviceExtension
->PowerIrp
)
130 /* Cancel and clear */
131 IoCancelIrp(DeviceExtension
->PowerIrp
);
132 DeviceExtension
->PowerIrp
= NULL
;
135 /* Check what type of FDO is being removed */
136 Context
= DeviceExtension
->AcpiInterface
.Context
;
137 if (DeviceExtension
->FdoType
== CmBattBattery
)
139 /* Unregister battery FDO */
140 DeviceExtension
->AcpiInterface
.UnregisterForDeviceNotifications(Context
,
141 (PVOID
)CmBattNotifyHandler
);
142 CmBattWmiDeRegistration(DeviceExtension
);
143 if (!NT_SUCCESS(BatteryClassUnload(DeviceExtension
->ClassData
))) ASSERT(FALSE
);
147 /* Unregister AC adapter FDO */
148 DeviceExtension
->AcpiInterface
.UnregisterForDeviceNotifications(Context
,
149 (PVOID
)CmBattNotifyHandler
);
150 CmBattWmiDeRegistration(DeviceExtension
);
154 /* Detach and delete */
155 IoDetachDevice(DeviceExtension
->AttachedDevice
);
156 IoDeleteDevice(DeviceExtension
->DeviceObject
);
157 return STATUS_SUCCESS
;
162 CmBattPowerDispatch(PDEVICE_OBJECT DeviceObject
,
166 return STATUS_NOT_IMPLEMENTED
;
171 CmBattPnpDispatch(PDEVICE_OBJECT DeviceObject
,
175 return STATUS_NOT_IMPLEMENTED
;
180 CmBattCreateFdo(IN PDRIVER_OBJECT DriverObject
,
181 IN PDEVICE_OBJECT DeviceObject
,
182 IN ULONG DeviceExtensionSize
,
183 IN PDEVICE_OBJECT
*NewDeviceObject
)
185 PDEVICE_OBJECT FdoDeviceObject
;
187 PCMBATT_DEVICE_EXTENSION FdoExtension
;
188 UCHAR Buffer
[sizeof(KEY_VALUE_PARTIAL_INFORMATION
) + sizeof(ULONG
)];
189 PKEY_VALUE_PARTIAL_INFORMATION PartialInfo
= (PVOID
)Buffer
;
191 UNICODE_STRING KeyString
;
195 if (CmBattDebug
& 0x220) DbgPrint("CmBattCreateFdo: Entered\n");
198 Status
= CmBattGetUniqueId(DeviceObject
, &UniqueId
);
199 if (!NT_SUCCESS(Status
))
204 DbgPrint("CmBattCreateFdo: Error %x from _UID, assuming unit #0\n", Status
);
208 Status
= IoCreateDevice(DriverObject
,
212 FILE_DEVICE_SECURE_OPEN
,
215 if (!NT_SUCCESS(Status
))
218 if (CmBattDebug
& 0xC)
219 DbgPrint("CmBattCreateFdo: error (0x%x) creating device object\n", Status
);
224 FdoDeviceObject
->Flags
|= DO_BUFFERED_IO
;
225 FdoDeviceObject
->Flags
|= DO_MAP_IO_BUFFER
;
226 FdoDeviceObject
->Flags
&= ~DO_DEVICE_INITIALIZING
;
228 /* Initialize the extension */
229 FdoExtension
= FdoDeviceObject
->DeviceExtension
;
230 RtlZeroMemory(FdoExtension
, DeviceExtensionSize
);
231 FdoExtension
->DeviceObject
= FdoDeviceObject
;
232 FdoExtension
->FdoDeviceObject
= FdoDeviceObject
;
233 FdoExtension
->PdoDeviceObject
= DeviceObject
;
236 FdoExtension
->AttachedDevice
= IoAttachDeviceToDeviceStack(FdoDeviceObject
,
238 if (!FdoExtension
->AttachedDevice
)
240 /* Destroy and fail */
241 CmBattDestroyFdo(FdoExtension
->FdoDeviceObject
);
242 if (CmBattDebug
& 0xC)
243 DbgPrint("CmBattCreateFdo: IoAttachDeviceToDeviceStack failed.\n");
244 return STATUS_UNSUCCESSFUL
;
247 /* Get ACPI interface for EVAL */
248 Status
= CmBattGetAcpiInterfaces(FdoExtension
->AttachedDevice
,
249 &FdoExtension
->AcpiInterface
);
250 if (!FdoExtension
->AttachedDevice
)
252 /* Detach, destroy, and fail */
253 IoDetachDevice(FdoExtension
->AttachedDevice
);
254 CmBattDestroyFdo(FdoExtension
->FdoDeviceObject
);
255 if (CmBattDebug
& 0xC)
256 DbgPrint("CmBattCreateFdo: Could not get ACPI interfaces: %x\n", Status
);
257 return STATUS_UNSUCCESSFUL
;
260 /* Setup the rest of the extension */
261 ExInitializeFastMutex(&FdoExtension
->FastMutex
);
262 IoInitializeRemoveLock(&FdoExtension
->RemoveLock
, 0, 0, 0);
263 FdoExtension
->HandleCount
= 0;
264 FdoExtension
->WaitWakeEnable
= FALSE
;
265 FdoExtension
->DeviceId
= UniqueId
;
266 FdoExtension
->DeviceName
= NULL
;
267 FdoExtension
->DelayNotification
= FALSE
;
268 FdoExtension
->ArFlag
= 0;
270 /* Open the device key */
271 Status
= IoOpenDeviceRegistryKey(DeviceObject
,
272 PLUGPLAY_REGKEY_DEVICE
,
275 if (NT_SUCCESS(Status
))
277 /* Read wait wake value */
278 RtlInitUnicodeString(&KeyString
, L
"WaitWakeEnabled");
279 Status
= ZwQueryValueKey(KeyHandle
,
281 KeyValuePartialInformation
,
285 if (NT_SUCCESS(Status
))
288 FdoExtension
->WaitWakeEnable
= *(PULONG
)PartialInfo
->Data
;
291 /* Close the handle */
295 /* Return success and the new FDO */
296 *NewDeviceObject
= FdoDeviceObject
;
297 if (CmBattDebug
& 0x220)
298 DbgPrint("CmBattCreateFdo: Created FDO %x\n", FdoDeviceObject
);
299 return STATUS_SUCCESS
;
304 CmBattAddBattery(IN PDRIVER_OBJECT DriverObject
,
305 IN PDEVICE_OBJECT DeviceObject
)
307 BATTERY_MINIPORT_INFO MiniportInfo
;
309 PDEVICE_OBJECT FdoDeviceObject
;
310 PCMBATT_DEVICE_EXTENSION FdoExtension
;
312 if (CmBattDebug
& 0x220)
313 DbgPrint("CmBattAddBattery: pdo %x\n", DeviceObject
);
316 Status
= CmBattCreateFdo(DriverObject
,
318 sizeof(CMBATT_DEVICE_EXTENSION
),
320 if (!NT_SUCCESS(Status
))
322 if (CmBattDebug
& 0xC)
323 DbgPrint("CmBattAddBattery: error (0x%x) creating Fdo\n", Status
);
327 /* Build the FDO extensio, check if we support trip points */
328 FdoExtension
= FdoDeviceObject
->DeviceExtension
;
329 FdoExtension
->FdoType
= CmBattBattery
;
330 FdoExtension
->Started
= 0;
331 FdoExtension
->NotifySent
= TRUE
;
332 InterlockedExchange(&FdoExtension
->ArLockValue
, 0);
333 FdoExtension
->TripPointValue
= BATTERY_UNKNOWN_CAPACITY
;
334 FdoExtension
->Tag
= 0;
335 FdoExtension
->InterruptTime
= KeQueryInterruptTime();
336 FdoExtension
->TripPointSet
= CmBattSetTripPpoint(FdoExtension
, 0) !=
337 STATUS_OBJECT_NAME_NOT_FOUND
;
339 /* Setup the battery miniport information structure */
340 RtlZeroMemory(&MiniportInfo
, sizeof(MiniportInfo
));
341 MiniportInfo
.Pdo
= DeviceObject
;
342 MiniportInfo
.MajorVersion
= BATTERY_CLASS_MAJOR_VERSION
;
343 MiniportInfo
.MinorVersion
= BATTERY_CLASS_MINOR_VERSION
;
344 MiniportInfo
.Context
= FdoExtension
;
345 MiniportInfo
.QueryTag
= (PVOID
)CmBattQueryTag
;
346 MiniportInfo
.QueryInformation
= (PVOID
)CmBattQueryInformation
;
347 MiniportInfo
.SetInformation
= NULL
;
348 MiniportInfo
.QueryStatus
= (PVOID
)CmBattQueryStatus
;
349 MiniportInfo
.SetStatusNotify
= (PVOID
)CmBattSetStatusNotify
;
350 MiniportInfo
.DisableStatusNotify
= (PVOID
)CmBattDisableStatusNotify
;
351 MiniportInfo
.DeviceName
= FdoExtension
->DeviceName
;
353 /* Register with the class driver */
354 Status
= BatteryClassInitializeDevice(&MiniportInfo
, &FdoExtension
->ClassData
);
355 if (!NT_SUCCESS(Status
))
357 IoDetachDevice(FdoExtension
->AttachedDevice
);
358 CmBattDestroyFdo(FdoExtension
->FdoDeviceObject
);
359 if (CmBattDebug
& 0xC)
360 DbgPrint("CmBattAddBattery: error (0x%x) registering with class\n", Status
);
365 Status
= CmBattWmiRegistration(FdoExtension
);
366 if (!NT_SUCCESS(Status
))
368 if (CmBattDebug
& 0xC)
369 DbgPrint("CmBattAddBattery: Could not register as a WMI provider, status = %Lx\n", Status
);
374 Status
= FdoExtension
->AcpiInterface
.RegisterForDeviceNotifications(FdoExtension
->AcpiInterface
.Context
,
375 (PVOID
)CmBattNotifyHandler
,
377 if (!NT_SUCCESS(Status
))
379 CmBattWmiDeRegistration(FdoExtension
);
380 BatteryClassUnload(FdoExtension
->ClassData
);
381 IoDetachDevice(FdoExtension
->AttachedDevice
);
382 CmBattDestroyFdo(FdoExtension
->FdoDeviceObject
);
383 if (CmBattDebug
& 0xC)
384 DbgPrint("CmBattAddBattery: Could not register for battery notify, status = %Lx\n", Status
);
393 CmBattAddAcAdapter(IN PDRIVER_OBJECT DriverObject
,
394 IN PDEVICE_OBJECT PdoDeviceObject
)
396 PDEVICE_OBJECT FdoDeviceObject
;
398 PCMBATT_DEVICE_EXTENSION DeviceExtension
;
400 if (CmBattDebug
& 0x220)
401 DbgPrint("CmBattAddAcAdapter: pdo %x\n", PdoDeviceObject
);
403 /* Check if we already have an AC adapter */
406 /* Don't do anything */
407 if (CmBattDebug
& 0xC)
408 DbgPrint("CmBatt: Second AC adapter found. Current version of driver only supports 1 aadapter.\n");
412 /* Set this as the AC adapter's PDO */
413 AcAdapterPdo
= PdoDeviceObject
;
416 /* Create the FDO for the adapter */
417 Status
= CmBattCreateFdo(DriverObject
,
419 sizeof(CMBATT_DEVICE_EXTENSION
),
421 if (!NT_SUCCESS(Status
))
424 if (CmBattDebug
& 0xC)
425 DbgPrint("CmBattAddAcAdapter: error (0x%x) creating Fdo\n", Status
);
429 /* Set the type and do WMI registration */
430 DeviceExtension
= FdoDeviceObject
->DeviceExtension
;
431 DeviceExtension
->FdoType
= CmBattAcAdapter
;
432 Status
= CmBattWmiRegistration(DeviceExtension
);
433 if (!NT_SUCCESS(Status
))
435 /* We can go on without WMI */
436 if (CmBattDebug
& 0xC)
437 DbgPrint("CmBattAddBattery: Could not register as a WMI provider, status = %Lx\n", Status
);
440 /* Register with ACPI */
441 Status
= DeviceExtension
->AcpiInterface
.RegisterForDeviceNotifications(DeviceExtension
->AcpiInterface
.Context
,
442 (PVOID
)CmBattNotifyHandler
,
444 if (!(NT_SUCCESS(Status
)) && (CmBattDebug
& 0xC))
445 DbgPrint("CmBattAddAcAdapter: Could not register for power notify, status = %Lx\n", Status
);
447 /* Send the first manual notification */
448 CmBattNotifyHandler(DeviceExtension
, ACPI_BATT_NOTIFY_STATUS
);
449 return STATUS_SUCCESS
;
454 CmBattAddDevice(IN PDRIVER_OBJECT DriverObject
,
455 IN PDEVICE_OBJECT PdoDeviceObject
)
460 UNICODE_STRING KeyString
;
461 UCHAR Buffer
[sizeof(KEY_VALUE_PARTIAL_INFORMATION
) + sizeof(ULONG
)];
462 PKEY_VALUE_PARTIAL_INFORMATION PartialInfo
= (PVOID
)Buffer
;
463 ULONG PowerSourceType
;
465 if (CmBattDebug
& 0x220)
466 DbgPrint("CmBattAddDevice: Entered with pdo %x\n", PdoDeviceObject
);
468 /* Make sure we have a PDO */
469 if (!PdoDeviceObject
)
471 /* Should not be having as one */
472 if (CmBattDebug
& 0x24) DbgPrint("CmBattAddDevice: Asked to do detection\n");
473 return STATUS_NO_MORE_ENTRIES
;
476 /* Open the driver key */
477 Status
= IoOpenDeviceRegistryKey(PdoDeviceObject
,
478 PLUGPLAY_REGKEY_DRIVER
,
481 if (!NT_SUCCESS(Status
))
483 if (CmBattDebug
& 0xC)
484 DbgPrint("CmBattAddDevice: Could not get the software branch: %x\n", Status
);
488 /* Read the power source type */
489 RtlInitUnicodeString(&KeyString
, L
"PowerSourceType");
490 Status
= ZwQueryValueKey(KeyHandle
,
492 KeyValuePartialInformation
,
497 if (!NT_SUCCESS(Status
))
499 /* We need the data, fail without it */
500 if (CmBattDebug
& 0xC)
501 DbgPrint("CmBattAddDevice: Could not read the power type identifier: %x\n", Status
);
505 /* Check what kind of power source this is */
506 PowerSourceType
= *(PULONG
)PartialInfo
->Data
;
507 if (PowerSourceType
== 1)
509 /* Create an AC adapter */
510 Status
= CmBattAddAcAdapter(DriverObject
, PdoDeviceObject
);
512 else if (PowerSourceType
== 0)
514 /* Create a battery */
515 Status
= CmBattAddBattery(DriverObject
, PdoDeviceObject
);
519 /* Unknown type, fail */
520 if (CmBattDebug
& 0xC)
521 DbgPrint("CmBattAddDevice: Invalid POWER_SOURCE_TYPE == %d \n", PowerSourceType
);
522 return STATUS_UNSUCCESSFUL
;
525 /* Return whatever the FDO creation routine did */