2 * PROJECT: ReactOS Composite Battery Driver
3 * LICENSE: BSD - See COPYING.ARM in the top level directory
4 * FILE: boot/drivers/bus/acpi/compbatt/comppnp.c
5 * PURPOSE: Plug-and-Play IOCTL/IRP Handling
6 * PROGRAMMERS: ReactOS Portable Systems Group
9 /* INCLUDES *******************************************************************/
15 /* FUNCTIONS ******************************************************************/
19 CompBattPowerDispatch(IN PDEVICE_OBJECT DeviceObject
,
22 PCOMPBATT_DEVICE_EXTENSION DeviceExtension
= DeviceObject
->DeviceExtension
;
23 if (CompBattDebug
& 1) DbgPrint("CompBatt: PowerDispatch received power IRP.\n");
25 /* Start the next IRP */
26 PoStartNextPowerIrp(Irp
);
28 /* Call the next driver in the stack */
29 IoSkipCurrentIrpStackLocation(Irp
);
30 return PoCallDriver(DeviceExtension
->AttachedDevice
, Irp
);
33 PCOMPBATT_BATTERY_DATA
35 RemoveBatteryFromList(IN PCUNICODE_STRING BatteryName
,
36 IN PCOMPBATT_DEVICE_EXTENSION DeviceExtension
)
38 PLIST_ENTRY ListHead
, NextEntry
;
39 PCOMPBATT_BATTERY_DATA BatteryData
;
40 if (CompBattDebug
& 1)
41 DbgPrint("CompBatt: ENTERING RemoveBatteryFromList\n");
43 /* Loop the battery list */
44 ExAcquireFastMutex(&DeviceExtension
->Lock
);
45 ListHead
= &DeviceExtension
->BatteryList
;
46 NextEntry
= ListHead
->Flink
;
47 while (NextEntry
!= ListHead
)
49 /* Get the battery information and compare the name */
50 BatteryData
= CONTAINING_RECORD(NextEntry
, COMPBATT_BATTERY_DATA
, BatteryLink
);
51 if (!RtlCompareUnicodeString(BatteryName
, &BatteryData
->BatteryName
, TRUE
))
53 /* Flush pending deletes and any lock waiters */
54 IoAcquireRemoveLock(&BatteryData
->RemoveLock
, 0);
55 ExReleaseFastMutex(&DeviceExtension
->Lock
);
56 IoReleaseRemoveLockAndWait(&BatteryData
->RemoveLock
, 0);
58 /* Remove the entry from the list */
59 ExAcquireFastMutex(&DeviceExtension
->Lock
);
60 RemoveEntryList(&BatteryData
->BatteryLink
);
61 ExReleaseFastMutex(&DeviceExtension
->Lock
);
66 NextEntry
= NextEntry
->Flink
;
70 ExReleaseFastMutex(&DeviceExtension
->Lock
);
71 if (CompBattDebug
& 1) DbgPrint("CompBatt: EXITING RemoveBatteryFromList\n");
72 return STATUS_SUCCESS
;
77 IsBatteryAlreadyOnList(IN PCUNICODE_STRING BatteryName
,
78 IN PCOMPBATT_DEVICE_EXTENSION DeviceExtension
)
80 PLIST_ENTRY ListHead
, NextEntry
;
81 PCOMPBATT_BATTERY_DATA BatteryData
;
82 BOOLEAN Found
= FALSE
;
83 if (CompBattDebug
& 1)
84 DbgPrint("CompBatt: ENTERING IsBatteryAlreadyOnList\n");
86 /* Loop the battery list */
87 ExAcquireFastMutex(&DeviceExtension
->Lock
);
88 ListHead
= &DeviceExtension
->BatteryList
;
89 NextEntry
= ListHead
->Flink
;
90 while (NextEntry
!= ListHead
)
92 /* Get the battery information and compare the name */
93 BatteryData
= CONTAINING_RECORD(NextEntry
, COMPBATT_BATTERY_DATA
, BatteryLink
);
94 if (!RtlCompareUnicodeString(BatteryName
, &BatteryData
->BatteryName
, TRUE
))
102 NextEntry
= NextEntry
->Flink
;
105 /* Release the lock and return search status */
106 ExReleaseFastMutex(&DeviceExtension
->Lock
);
107 if (CompBattDebug
& 1) DbgPrint("CompBatt: EXITING IsBatteryAlreadyOnList\n");
113 CompBattAddNewBattery(IN PUNICODE_STRING BatteryName
,
114 IN PCOMPBATT_DEVICE_EXTENSION DeviceExtension
)
116 NTSTATUS Status
= STATUS_SUCCESS
;
117 PCOMPBATT_BATTERY_DATA BatteryData
;
119 PIO_STACK_LOCATION IoStackLocation
;
120 PFILE_OBJECT FileObject
;
122 if (CompBattDebug
& 1)
123 DbgPrint("CompBatt: ENTERING AddNewBattery \"%w\" \n", BatteryName
->Buffer
);
125 /* Is this a new battery? */
126 if (!IsBatteryAlreadyOnList(BatteryName
, DeviceExtension
))
128 /* Allocate battery data */
129 BatteryData
= ExAllocatePoolWithTag(NonPagedPool
,
130 sizeof(COMPBATT_BATTERY_DATA
) +
135 /* Initialize the data and write the battery name */
136 RtlZeroMemory(BatteryData
, sizeof(COMPBATT_BATTERY_DATA
));
137 BatteryData
->Tag
= 0;
138 BatteryData
->BatteryName
.MaximumLength
= BatteryName
->Length
;
139 BatteryData
->BatteryName
.Buffer
= (PWCHAR
)(BatteryData
+ 1);
140 RtlCopyUnicodeString(&BatteryData
->BatteryName
, BatteryName
);
142 /* Get the device object */
143 Status
= CompBattGetDeviceObjectPointer(BatteryName
,
146 &BatteryData
->DeviceObject
);
147 if (NT_SUCCESS(Status
))
149 /* Reference the DO and drop the FO */
150 ObReferenceObject(BatteryData
->DeviceObject
);
151 ObDereferenceObject(FileObject
);
153 /* Allocate the battery IRP */
154 Irp
= IoAllocateIrp(BatteryData
->DeviceObject
->StackSize
+ 1, 0);
158 BatteryData
->Irp
= Irp
;
160 /* Setup the stack location */
161 IoStackLocation
= IoGetNextIrpStackLocation(Irp
);
162 IoStackLocation
->Parameters
.Others
.Argument1
= DeviceExtension
;
163 IoStackLocation
->Parameters
.Others
.Argument2
= BatteryData
;
166 IoSetNextIrpStackLocation(Irp
);
167 Irp
->IoStatus
.Status
= STATUS_DEVICE_NOT_CONNECTED
;
168 BatteryData
->WaitFlag
= 0;
170 /* Insert this battery in the list */
171 ExAcquireFastMutex(&DeviceExtension
->Lock
);
172 InsertTailList(&DeviceExtension
->BatteryList
,
173 &BatteryData
->BatteryLink
);
174 ExReleaseFastMutex(&DeviceExtension
->Lock
);
176 /* Initialize the work item and delete lock */
177 IoInitializeRemoveLock(&BatteryData
->RemoveLock
, 0, 0, 0);
178 ExInitializeWorkItem(&BatteryData
->WorkItem
,
179 (PVOID
)CompBattMonitorIrpCompleteWorker
,
182 /* Setup the IRP work entry */
183 CompBattMonitorIrpComplete(BatteryData
->DeviceObject
, Irp
, 0);
184 Status
= STATUS_SUCCESS
;
188 /* Fail, no memory */
189 if (CompBattDebug
& 8)
190 DbgPrint("CompBatt: Couldn't allocate new battery Irp\n");
191 Status
= STATUS_INSUFFICIENT_RESOURCES
;
192 ObDereferenceObject(BatteryData
->DeviceObject
);
195 else if (CompBattDebug
& 8)
198 DbgPrint("CompBattAddNewBattery: Failed to get device Object. status = %lx\n",
202 /* Free the battery data */
203 ExFreePool(BatteryData
);
207 /* Fail, no memory */
208 if (CompBattDebug
& 8)
209 DbgPrint("CompBatt: Couldn't allocate new battery node\n");
210 Status
= STATUS_INSUFFICIENT_RESOURCES
;
215 if (CompBattDebug
& 1) DbgPrint("CompBatt: EXITING AddNewBattery\n");
221 CompBattRemoveBattery(IN PCUNICODE_STRING BatteryName
,
222 IN PCOMPBATT_DEVICE_EXTENSION DeviceExtension
)
224 PCOMPBATT_BATTERY_DATA BatteryData
;
225 if (CompBattDebug
& 1) DbgPrint("CompBatt: RemoveBattery\n");
227 /* Remove the entry */
228 BatteryData
= RemoveBatteryFromList(BatteryName
, DeviceExtension
);
231 /* Dereference and free it */
232 ObDereferenceObject(BatteryData
->DeviceObject
);
233 ExFreePool(BatteryData
);
235 /* Notify class driver */
236 DeviceExtension
->Flags
= 0;
237 BatteryClassStatusNotify(DeviceExtension
->ClassData
);
241 return STATUS_SUCCESS
;
246 CompBattGetBatteries(IN PCOMPBATT_DEVICE_EXTENSION DeviceExtension
)
251 UNICODE_STRING LinkString
;
252 if (CompBattDebug
& 1) DbgPrint("CompBatt: ENTERING GetBatteries\n");
254 /* Get all battery links */
255 Status
= IoGetDeviceInterfaces(&GUID_DEVICE_BATTERY
, NULL
, 0, &LinkList
);
257 if (NT_SUCCESS(Status
))
259 /* Loop all strings inside */
262 /* Create the string */
263 RtlInitUnicodeString(&LinkString
, p
);
264 if (!LinkString
.Length
) break;
266 /* Add this battery and move on */
267 Status
= CompBattAddNewBattery(&LinkString
, DeviceExtension
);
268 p
+= (LinkString
.Length
/ sizeof(WCHAR
)) + sizeof(UNICODE_NULL
);
271 /* Parsing complete, clean up buffer */
272 ExFreePool(LinkList
);
274 else if (CompBattDebug
& 8)
277 DbgPrint("CompBatt: Couldn't get list of batteries\n");
281 if (CompBattDebug
& 1) DbgPrint("CompBatt: EXITING GetBatteries\n");
287 CompBattPnpEventHandler(IN PDEVICE_INTERFACE_CHANGE_NOTIFICATION Notification
,
288 IN PCOMPBATT_DEVICE_EXTENSION DeviceExtension
)
290 if (CompBattDebug
& 1) DbgPrint("CompBatt: ENTERING PnpEventHandler\n");
291 if (CompBattDebug
& 2) DbgPrint("CompBatt: Received device interface change notification\n");
293 /* Check what happened */
294 if (IsEqualGUIDAligned(&Notification
->Event
, &GUID_DEVICE_INTERFACE_ARRIVAL
))
296 /* Add the new battery */
297 if (CompBattDebug
& 2)
298 DbgPrint("CompBatt: Received notification of battery arrival\n");
299 CompBattAddNewBattery(Notification
->SymbolicLinkName
, DeviceExtension
);
301 else if (IsEqualGUIDAligned(&Notification
->Event
, &GUID_DEVICE_INTERFACE_REMOVAL
))
303 /* Don't do anything */
304 if (CompBattDebug
& 2)
305 DbgPrint("CompBatt: Received notification of battery removal\n");
309 /* Shouldn't happen */
310 if (CompBattDebug
& 2) DbgPrint("CompBatt: Received unhandled PnP event\n");
313 /* Done, return success */
314 if (CompBattDebug
& 1) DbgPrint("CompBatt: EXITING PnpEventHandler\n");
315 return STATUS_SUCCESS
;
320 CompBattAddDevice(IN PDRIVER_OBJECT DriverObject
,
321 IN PDEVICE_OBJECT PdoDeviceObject
)
324 UNICODE_STRING DeviceName
;
325 PCOMPBATT_DEVICE_EXTENSION DeviceExtension
;
326 PDEVICE_OBJECT DeviceObject
;
327 UNICODE_STRING SymbolicLinkName
;
328 BATTERY_MINIPORT_INFO MiniportInfo
;
329 if (CompBattDebug
& 2) DbgPrint("CompBatt: Got an AddDevice - %x\n", PdoDeviceObject
);
331 /* Create the device */
332 RtlInitUnicodeString(&DeviceName
, L
"\\Device\\CompositeBattery");
333 Status
= IoCreateDevice(DriverObject
,
334 sizeof(COMPBATT_DEVICE_EXTENSION
),
337 FILE_DEVICE_SECURE_OPEN
,
340 if (!NT_SUCCESS(Status
)) return Status
;
342 /* Setup symbolic link for Win32 access */
343 RtlInitUnicodeString(&SymbolicLinkName
, L
"\\DosDevices\\CompositeBattery");
344 IoCreateSymbolicLink(&SymbolicLinkName
, &DeviceName
);
346 /* Initialize the device extension */
347 DeviceExtension
= DeviceObject
->DeviceExtension
;
348 RtlZeroMemory(DeviceExtension
, sizeof(COMPBATT_DEVICE_EXTENSION
));
350 /* Attach to device stack and set DO pointers */
351 DeviceExtension
->AttachedDevice
= IoAttachDeviceToDeviceStack(DeviceObject
,
353 DeviceExtension
->DeviceObject
= DeviceObject
;
354 if (!DeviceExtension
->AttachedDevice
)
357 if (CompBattDebug
& 8)
358 DbgPrint("CompBattAddDevice: Could not attach to LowerDevice.\n");
359 IoDeleteDevice(DeviceObject
);
360 return STATUS_UNSUCCESSFUL
;
363 /* Set device object flags */
364 DeviceObject
->Flags
|= (DO_POWER_PAGABLE
| DO_BUFFERED_IO
);
365 DeviceObject
->Flags
&= ~DO_DEVICE_INITIALIZING
;
367 /* Setup the device extension */
368 ExInitializeFastMutex(&DeviceExtension
->Lock
);
369 InitializeListHead(&DeviceExtension
->BatteryList
);
370 DeviceExtension
->Flags
= 0;
371 DeviceExtension
->NextTag
= 1;
373 /* Setup the miniport data */
374 RtlZeroMemory(&MiniportInfo
, sizeof(MiniportInfo
));
375 MiniportInfo
.MajorVersion
= BATTERY_CLASS_MAJOR_VERSION
;
376 MiniportInfo
.MinorVersion
= BATTERY_CLASS_MINOR_VERSION
;
377 MiniportInfo
.Context
= DeviceExtension
;
378 MiniportInfo
.DeviceName
= &DeviceName
;
379 MiniportInfo
.QueryTag
= (BCLASS_QUERY_TAG
)CompBattQueryTag
;
380 MiniportInfo
.QueryInformation
= (BCLASS_QUERY_INFORMATION
)CompBattQueryInformation
;
381 MiniportInfo
.SetInformation
= NULL
;
382 MiniportInfo
.QueryStatus
= (BCLASS_QUERY_STATUS
)CompBattQueryStatus
;
383 MiniportInfo
.SetStatusNotify
= (BCLASS_SET_STATUS_NOTIFY
)CompBattSetStatusNotify
;
384 MiniportInfo
.DisableStatusNotify
= (BCLASS_DISABLE_STATUS_NOTIFY
)CompBattDisableStatusNotify
;
385 MiniportInfo
.Pdo
= NULL
;
387 /* Register with the class driver */
388 Status
= BatteryClassInitializeDevice(&MiniportInfo
,
389 &DeviceExtension
->ClassData
);
390 if (!NT_SUCCESS(Status
))
392 /* Undo everything */
393 IoDetachDevice(DeviceExtension
->AttachedDevice
);
394 IoDeleteDevice(DeviceObject
);
403 CompBattPnpDispatch(IN PDEVICE_OBJECT DeviceObject
,
406 PIO_STACK_LOCATION IoStackLocation
= IoGetCurrentIrpStackLocation(Irp
);
408 PCOMPBATT_DEVICE_EXTENSION DeviceExtension
= DeviceObject
->DeviceExtension
;
409 if (CompBattDebug
& 1) DbgPrint("CompBatt: ENTERING PnpDispatch\n");
411 /* Set default error */
412 Status
= STATUS_NOT_SUPPORTED
;
414 /* Check what kind of PnP function this is */
415 switch (IoStackLocation
->MinorFunction
)
417 case IRP_MN_START_DEVICE
:
419 /* Device is starting, register for new batteries and pick up current ones */
420 Status
= IoRegisterPlugPlayNotification(EventCategoryDeviceInterfaceChange
,
422 (PVOID
)&GUID_DEVICE_BATTERY
,
423 DeviceObject
->DriverObject
,
424 (PDRIVER_NOTIFICATION_CALLBACK_ROUTINE
)CompBattPnpEventHandler
,
426 &DeviceExtension
->NotificationEntry
);
427 if (NT_SUCCESS(Status
))
429 /* Now go get the batteries */
430 if (CompBattDebug
& 2)
431 DbgPrint("CompBatt: Successfully registered for PnP notification\n");
432 Status
= CompBattGetBatteries(DeviceExtension
);
437 if (CompBattDebug
& 8)
438 DbgPrint("CompBatt: Couldn't register for PnP notification - %x\n",
442 case IRP_MN_CANCEL_STOP_DEVICE
:
444 /* Explicitly say ok */
445 Status
= STATUS_SUCCESS
;
448 case IRP_MN_CANCEL_REMOVE_DEVICE
:
450 /* Explicitly say ok */
451 Status
= STATUS_SUCCESS
;
454 case IRP_MN_SURPRISE_REMOVAL
:
456 /* Explicitly say ok */
457 Status
= STATUS_SUCCESS
;
460 case IRP_MN_QUERY_PNP_DEVICE_STATE
:
463 Irp
->IoStatus
.Information
|= PNP_DEVICE_NOT_DISABLEABLE
;
464 Status
= STATUS_SUCCESS
;
470 Status
= STATUS_INVALID_DEVICE_REQUEST
;
474 /* Set IRP status if we have one */
475 if (Status
!= STATUS_NOT_SUPPORTED
) Irp
->IoStatus
.Status
= Status
;
477 /* Did someone pick it up? */
478 if ((NT_SUCCESS(Status
)) || (Status
== STATUS_NOT_SUPPORTED
))
480 /* Still unsupported, try ACPI */
481 IoSkipCurrentIrpStackLocation(Irp
);
482 Status
= IoCallDriver(DeviceExtension
->AttachedDevice
, Irp
);
486 /* Complete the request */
487 Status
= Irp
->IoStatus
.Status
;
488 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
491 /* Release the remove lock and return status */
492 if (CompBattDebug
& 1) DbgPrint("CompBatt: EXITING PnpDispatch\n");