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 *******************************************************************/
13 /* FUNCTIONS ******************************************************************/
17 CompBattPowerDispatch(IN PDEVICE_OBJECT DeviceObject
,
20 PCOMPBATT_DEVICE_EXTENSION DeviceExtension
= DeviceObject
->DeviceExtension
;
21 if (CompBattDebug
& 1) DbgPrint("CompBatt: PowerDispatch received power IRP.\n");
23 /* Start the next IRP */
24 PoStartNextPowerIrp(Irp
);
26 /* Call the next driver in the stack */
27 IoSkipCurrentIrpStackLocation(Irp
);
28 return PoCallDriver(DeviceExtension
->AttachedDevice
, Irp
);
31 PCOMPBATT_BATTERY_DATA
33 RemoveBatteryFromList(IN PCUNICODE_STRING BatteryName
,
34 IN PCOMPBATT_DEVICE_EXTENSION DeviceExtension
)
36 PLIST_ENTRY ListHead
, NextEntry
;
37 PCOMPBATT_BATTERY_DATA BatteryData
;
38 if (CompBattDebug
& 1)
39 DbgPrint("CompBatt: ENTERING RemoveBatteryFromList\n");
41 /* Loop the battery list */
42 ExAcquireFastMutex(&DeviceExtension
->Lock
);
43 ListHead
= &DeviceExtension
->BatteryList
;
44 NextEntry
= ListHead
->Flink
;
45 while (NextEntry
!= ListHead
)
47 /* Get the battery information and compare the name */
48 BatteryData
= CONTAINING_RECORD(NextEntry
, COMPBATT_BATTERY_DATA
, BatteryLink
);
49 if (!RtlCompareUnicodeString(BatteryName
, &BatteryData
->BatteryName
, TRUE
))
51 /* Flush pending deletes and any lock waiters */
52 IoAcquireRemoveLock(&BatteryData
->RemoveLock
, 0);
53 ExReleaseFastMutex(&DeviceExtension
->Lock
);
54 IoReleaseRemoveLockAndWait(&BatteryData
->RemoveLock
, 0);
56 /* Remove the entry from the list */
57 ExAcquireFastMutex(&DeviceExtension
->Lock
);
58 RemoveEntryList(&BatteryData
->BatteryLink
);
59 ExReleaseFastMutex(&DeviceExtension
->Lock
);
64 NextEntry
= NextEntry
->Flink
;
68 ExReleaseFastMutex(&DeviceExtension
->Lock
);
69 if (CompBattDebug
& 1) DbgPrint("CompBatt: EXITING RemoveBatteryFromList\n");
70 return STATUS_SUCCESS
;
75 IsBatteryAlreadyOnList(IN PCUNICODE_STRING BatteryName
,
76 IN PCOMPBATT_DEVICE_EXTENSION DeviceExtension
)
78 PLIST_ENTRY ListHead
, NextEntry
;
79 PCOMPBATT_BATTERY_DATA BatteryData
;
80 BOOLEAN Found
= FALSE
;
81 if (CompBattDebug
& 1)
82 DbgPrint("CompBatt: ENTERING IsBatteryAlreadyOnList\n");
84 /* Loop the battery list */
85 ExAcquireFastMutex(&DeviceExtension
->Lock
);
86 ListHead
= &DeviceExtension
->BatteryList
;
87 NextEntry
= ListHead
->Flink
;
88 while (NextEntry
!= ListHead
)
90 /* Get the battery information and compare the name */
91 BatteryData
= CONTAINING_RECORD(NextEntry
, COMPBATT_BATTERY_DATA
, BatteryLink
);
92 if (!RtlCompareUnicodeString(BatteryName
, &BatteryData
->BatteryName
, TRUE
))
100 NextEntry
= NextEntry
->Flink
;
103 /* Release the lock and return search status */
104 ExReleaseFastMutex(&DeviceExtension
->Lock
);
105 if (CompBattDebug
& 1) DbgPrint("CompBatt: EXITING IsBatteryAlreadyOnList\n");
111 CompBattAddNewBattery(IN PUNICODE_STRING BatteryName
,
112 IN PCOMPBATT_DEVICE_EXTENSION DeviceExtension
)
114 NTSTATUS Status
= STATUS_SUCCESS
;
115 PCOMPBATT_BATTERY_DATA BatteryData
;
117 PIO_STACK_LOCATION IoStackLocation
;
118 PFILE_OBJECT FileObject
;
120 if (CompBattDebug
& 1)
121 DbgPrint("CompBatt: ENTERING AddNewBattery \"%w\" \n", BatteryName
->Buffer
);
123 /* Is this a new battery? */
124 if (!IsBatteryAlreadyOnList(BatteryName
, DeviceExtension
))
126 /* Allocate battery data */
127 BatteryData
= ExAllocatePoolWithTag(NonPagedPool
,
128 sizeof(COMPBATT_BATTERY_DATA
) +
133 /* Initialize the data and write the battery name */
134 RtlZeroMemory(BatteryData
, sizeof(COMPBATT_BATTERY_DATA
));
135 BatteryData
->Tag
= 0;
136 BatteryData
->BatteryName
.MaximumLength
= BatteryName
->Length
;
137 BatteryData
->BatteryName
.Buffer
= (PWCHAR
)(BatteryData
+ 1);
138 RtlCopyUnicodeString(&BatteryData
->BatteryName
, BatteryName
);
140 /* Get the device object */
141 Status
= CompBattGetDeviceObjectPointer(BatteryName
,
144 &BatteryData
->DeviceObject
);
145 if (NT_SUCCESS(Status
))
147 /* Reference the DO and drop the FO */
148 ObReferenceObject(BatteryData
->DeviceObject
);
149 ObDereferenceObject(FileObject
);
151 /* Allocate the battery IRP */
152 Irp
= IoAllocateIrp(BatteryData
->DeviceObject
->StackSize
+ 1, 0);
156 BatteryData
->Irp
= Irp
;
158 /* Setup the stack location */
159 IoStackLocation
= IoGetNextIrpStackLocation(Irp
);
160 IoStackLocation
->Parameters
.Others
.Argument1
= DeviceExtension
;
161 IoStackLocation
->Parameters
.Others
.Argument2
= BatteryData
;
164 IoSetNextIrpStackLocation(Irp
);
165 Irp
->IoStatus
.Status
= STATUS_DEVICE_NOT_CONNECTED
;
166 BatteryData
->WaitFlag
= 0;
168 /* Insert this battery in the list */
169 ExAcquireFastMutex(&DeviceExtension
->Lock
);
170 InsertTailList(&DeviceExtension
->BatteryList
,
171 &BatteryData
->BatteryLink
);
172 ExReleaseFastMutex(&DeviceExtension
->Lock
);
174 /* Initialize the work item and delete lock */
175 IoInitializeRemoveLock(&BatteryData
->RemoveLock
, 0, 0, 0);
176 ExInitializeWorkItem(&BatteryData
->WorkItem
,
177 (PVOID
)CompBattMonitorIrpCompleteWorker
,
180 /* Setup the IRP work entry */
181 CompBattMonitorIrpComplete(BatteryData
->DeviceObject
, Irp
, 0);
182 Status
= STATUS_SUCCESS
;
186 /* Fail, no memory */
187 if (CompBattDebug
& 8)
188 DbgPrint("CompBatt: Couldn't allocate new battery Irp\n");
189 Status
= STATUS_INSUFFICIENT_RESOURCES
;
190 ObDereferenceObject(BatteryData
->DeviceObject
);
193 else if (CompBattDebug
& 8)
196 DbgPrint("CompBattAddNewBattery: Failed to get device Object. status = %lx\n",
200 /* Free the battery data */
201 ExFreePool(BatteryData
);
205 /* Fail, no memory */
206 if (CompBattDebug
& 8)
207 DbgPrint("CompBatt: Couldn't allocate new battery node\n");
208 Status
= STATUS_INSUFFICIENT_RESOURCES
;
213 if (CompBattDebug
& 1) DbgPrint("CompBatt: EXITING AddNewBattery\n");
219 CompBattRemoveBattery(IN PCUNICODE_STRING BatteryName
,
220 IN PCOMPBATT_DEVICE_EXTENSION DeviceExtension
)
222 PCOMPBATT_BATTERY_DATA BatteryData
;
223 if (CompBattDebug
& 1) DbgPrint("CompBatt: RemoveBattery\n");
225 /* Remove the entry */
226 BatteryData
= RemoveBatteryFromList(BatteryName
, DeviceExtension
);
229 /* Dereference and free it */
230 ObDereferenceObject(BatteryData
->DeviceObject
);
231 ExFreePool(BatteryData
);
233 /* Notify class driver */
234 DeviceExtension
->Flags
= 0;
235 BatteryClassStatusNotify(DeviceExtension
->ClassData
);
239 return STATUS_SUCCESS
;
244 CompBattGetBatteries(IN PCOMPBATT_DEVICE_EXTENSION DeviceExtension
)
249 UNICODE_STRING LinkString
;
250 if (CompBattDebug
& 1) DbgPrint("CompBatt: ENTERING GetBatteries\n");
252 /* Get all battery links */
253 Status
= IoGetDeviceInterfaces(&GUID_DEVICE_BATTERY
, NULL
, 0, &LinkList
);
255 if (NT_SUCCESS(Status
))
257 /* Loop all strings inside */
260 /* Create the string */
261 RtlInitUnicodeString(&LinkString
, p
);
262 if (!LinkString
.Length
) break;
264 /* Add this battery and move on */
265 Status
= CompBattAddNewBattery(&LinkString
, DeviceExtension
);
266 p
+= (LinkString
.Length
/ sizeof(WCHAR
)) + sizeof(UNICODE_NULL
);
269 /* Parsing complete, clean up buffer */
270 ExFreePool(LinkList
);
272 else if (CompBattDebug
& 8)
275 DbgPrint("CompBatt: Couldn't get list of batteries\n");
279 if (CompBattDebug
& 1) DbgPrint("CompBatt: EXITING GetBatteries\n");
285 CompBattPnpEventHandler(IN PDEVICE_INTERFACE_CHANGE_NOTIFICATION Notification
,
286 IN PCOMPBATT_DEVICE_EXTENSION DeviceExtension
)
288 if (CompBattDebug
& 1) DbgPrint("CompBatt: ENTERING PnpEventHandler\n");
289 if (CompBattDebug
& 2) DbgPrint("CompBatt: Received device interface change notification\n");
291 /* Check what happened */
292 if (IsEqualGUIDAligned(&Notification
->Event
, &GUID_DEVICE_INTERFACE_ARRIVAL
))
294 /* Add the new battery */
295 if (CompBattDebug
& 2)
296 DbgPrint("CompBatt: Received notification of battery arrival\n");
297 CompBattAddNewBattery(Notification
->SymbolicLinkName
, DeviceExtension
);
299 else if (IsEqualGUIDAligned(&Notification
->Event
, &GUID_DEVICE_INTERFACE_REMOVAL
))
301 /* Don't do anything */
302 if (CompBattDebug
& 2)
303 DbgPrint("CompBatt: Received notification of battery removal\n");
307 /* Shouldn't happen */
308 if (CompBattDebug
& 2) DbgPrint("CompBatt: Received unhandled PnP event\n");
311 /* Done, return success */
312 if (CompBattDebug
& 1) DbgPrint("CompBatt: EXITING PnpEventHandler\n");
313 return STATUS_SUCCESS
;
318 CompBattAddDevice(IN PDRIVER_OBJECT DriverObject
,
319 IN PDEVICE_OBJECT PdoDeviceObject
)
322 UNICODE_STRING DeviceName
;
323 PCOMPBATT_DEVICE_EXTENSION DeviceExtension
;
324 PDEVICE_OBJECT DeviceObject
;
325 UNICODE_STRING SymbolicLinkName
;
326 BATTERY_MINIPORT_INFO MiniportInfo
;
327 if (CompBattDebug
& 2) DbgPrint("CompBatt: Got an AddDevice - %x\n", PdoDeviceObject
);
329 /* Create the device */
330 RtlInitUnicodeString(&DeviceName
, L
"\\Device\\CompositeBattery");
331 Status
= IoCreateDevice(DriverObject
,
332 sizeof(COMPBATT_DEVICE_EXTENSION
),
335 FILE_DEVICE_SECURE_OPEN
,
338 if (!NT_SUCCESS(Status
)) return Status
;
340 /* Setup symbolic link for Win32 access */
341 RtlInitUnicodeString(&SymbolicLinkName
, L
"\\DosDevices\\CompositeBattery");
342 IoCreateSymbolicLink(&SymbolicLinkName
, &DeviceName
);
344 /* Initialize the device extension */
345 DeviceExtension
= DeviceObject
->DeviceExtension
;
346 RtlZeroMemory(DeviceExtension
, sizeof(COMPBATT_DEVICE_EXTENSION
));
348 /* Attach to device stack and set DO pointers */
349 DeviceExtension
->AttachedDevice
= IoAttachDeviceToDeviceStack(DeviceObject
,
351 DeviceExtension
->DeviceObject
= DeviceObject
;
352 if (!DeviceExtension
->AttachedDevice
)
355 if (CompBattDebug
& 8)
356 DbgPrint("CompBattAddDevice: Could not attach to LowerDevice.\n");
357 IoDeleteDevice(DeviceObject
);
358 return STATUS_UNSUCCESSFUL
;
361 /* Set device object flags */
362 DeviceObject
->Flags
|= (DO_POWER_PAGABLE
| DO_BUFFERED_IO
);
363 DeviceObject
->Flags
&= ~DO_DEVICE_INITIALIZING
;
365 /* Setup the device extension */
366 ExInitializeFastMutex(&DeviceExtension
->Lock
);
367 InitializeListHead(&DeviceExtension
->BatteryList
);
368 DeviceExtension
->Flags
= 0;
369 DeviceExtension
->NextTag
= 1;
371 /* Setup the miniport data */
372 RtlZeroMemory(&MiniportInfo
, sizeof(MiniportInfo
));
373 MiniportInfo
.MajorVersion
= BATTERY_CLASS_MAJOR_VERSION
;
374 MiniportInfo
.MinorVersion
= BATTERY_CLASS_MINOR_VERSION
;
375 MiniportInfo
.Context
= DeviceExtension
;
376 MiniportInfo
.DeviceName
= &DeviceName
;
377 MiniportInfo
.QueryTag
= (BCLASS_QUERY_TAG
)CompBattQueryTag
;
378 MiniportInfo
.QueryInformation
= (BCLASS_QUERY_INFORMATION
)CompBattQueryInformation
;
379 MiniportInfo
.SetInformation
= NULL
;
380 MiniportInfo
.QueryStatus
= (BCLASS_QUERY_STATUS
)CompBattQueryStatus
;
381 MiniportInfo
.SetStatusNotify
= (BCLASS_SET_STATUS_NOTIFY
)CompBattSetStatusNotify
;
382 MiniportInfo
.DisableStatusNotify
= (BCLASS_DISABLE_STATUS_NOTIFY
)CompBattDisableStatusNotify
;
383 MiniportInfo
.Pdo
= NULL
;
385 /* Register with the class driver */
386 Status
= BatteryClassInitializeDevice(&MiniportInfo
,
387 &DeviceExtension
->ClassData
);
388 if (!NT_SUCCESS(Status
))
390 /* Undo everything */
391 IoDetachDevice(DeviceExtension
->AttachedDevice
);
392 IoDeleteDevice(DeviceObject
);
401 CompBattPnpDispatch(IN PDEVICE_OBJECT DeviceObject
,
404 PIO_STACK_LOCATION IoStackLocation
= IoGetCurrentIrpStackLocation(Irp
);
406 PCOMPBATT_DEVICE_EXTENSION DeviceExtension
= DeviceObject
->DeviceExtension
;
407 if (CompBattDebug
& 1) DbgPrint("CompBatt: ENTERING PnpDispatch\n");
409 /* Set default error */
410 Status
= STATUS_NOT_SUPPORTED
;
412 /* Check what kind of PnP function this is */
413 switch (IoStackLocation
->MinorFunction
)
415 case IRP_MN_START_DEVICE
:
417 /* Device is starting, register for new batteries and pick up current ones */
418 Status
= IoRegisterPlugPlayNotification(EventCategoryDeviceInterfaceChange
,
420 (PVOID
)&GUID_DEVICE_BATTERY
,
421 DeviceObject
->DriverObject
,
422 (PDRIVER_NOTIFICATION_CALLBACK_ROUTINE
)CompBattPnpEventHandler
,
424 &DeviceExtension
->NotificationEntry
);
425 if (NT_SUCCESS(Status
))
427 /* Now go get the batteries */
428 if (CompBattDebug
& 2)
429 DbgPrint("CompBatt: Successfully registered for PnP notification\n");
430 Status
= CompBattGetBatteries(DeviceExtension
);
435 if (CompBattDebug
& 8)
436 DbgPrint("CompBatt: Couldn't register for PnP notification - %x\n",
440 case IRP_MN_CANCEL_STOP_DEVICE
:
442 /* Explicitly say ok */
443 Status
= STATUS_SUCCESS
;
446 case IRP_MN_CANCEL_REMOVE_DEVICE
:
448 /* Explicitly say ok */
449 Status
= STATUS_SUCCESS
;
452 case IRP_MN_SURPRISE_REMOVAL
:
454 /* Explicitly say ok */
455 Status
= STATUS_SUCCESS
;
458 case IRP_MN_QUERY_PNP_DEVICE_STATE
:
461 Irp
->IoStatus
.Information
|= PNP_DEVICE_NOT_DISABLEABLE
;
462 Status
= STATUS_SUCCESS
;
468 Status
= STATUS_INVALID_DEVICE_REQUEST
;
472 /* Set IRP status if we have one */
473 if (Status
!= STATUS_NOT_SUPPORTED
) Irp
->IoStatus
.Status
= Status
;
475 /* Did someone pick it up? */
476 if ((NT_SUCCESS(Status
)) || (Status
== STATUS_NOT_SUPPORTED
))
478 /* Still unsupported, try ACPI */
479 IoSkipCurrentIrpStackLocation(Irp
);
480 Status
= IoCallDriver(DeviceExtension
->AttachedDevice
, Irp
);
484 /* Complete the request */
485 Status
= Irp
->IoStatus
.Status
;
486 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
489 /* Release the remove lock and return status */
490 if (CompBattDebug
& 1) DbgPrint("CompBatt: EXITING PnpDispatch\n");