windows-nt/Source/XPSP1/NT/base/busdrv/acpi/compbatt/compmisc.c

457 lines
11 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*++
Copyright (c) 1990 Microsoft Corporation
Module Name:
battmisc.c
Abstract:
Miscellaneous functions needed by the composite battery to talk to
the batteries in the system.
Author:
Scott Brenden
Environment:
Notes:
Revision History:
--*/
#include "compbatt.h"
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, BatteryIoctl)
#pragma alloc_text(PAGE, CompBattGetDeviceObjectPointer)
#endif
NTSTATUS
BattIoctlComplete (
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Context
)
{
PKEVENT Event;
Event = (PKEVENT) Context;
KeSetEvent (Event, 0, FALSE);
return STATUS_MORE_PROCESSING_REQUIRED;
}
NTSTATUS
BatteryIoctl(
IN ULONG Ioctl,
IN PDEVICE_OBJECT DeviceObject,
IN PVOID InputBuffer,
IN ULONG InputBufferLength,
IN PVOID OutputBuffer,
IN ULONG OutputBufferLength,
IN BOOLEAN PrivateIoctl
)
/*++
Routine Description:
The routine Creates an IRP and does Ioctl to the device object passed in.
Arguments:
Ioctl - code for the Ioctl
DeviceObject - Device object to send the ioctl to
InputBuffer - Input buffer for the ioctl
InputBufferLength - length of the input buffer
OutputBuffer - Buffer for containing the results of the ioctl
OutputBufferLength - Length of the output buffer
PrivateIoctl - TRUE if this is to be an IRP_MJ_DEVICE_CONTROL, FALSE
if this is to be an IRP_MJ_INTERNAL_DEVICE_CONTROL.
Return Value:
Status returned by the Ioctl
--*/
{
NTSTATUS status;
IO_STATUS_BLOCK IOSB;
PIRP irp;
KEVENT event;
// PUCHAR buffer;
// ULONG bufferSize;
// PIO_STACK_LOCATION irpSp;
PAGED_CODE();
BattPrint (BATT_TRACE, ("CompBatt: ENTERING BatteryIoctl\n"));
//
// Set the event object to the unsignaled state.
// It will be used to signal request completion.
//
KeInitializeEvent(&event, SynchronizationEvent, FALSE);
//
// Build synchronous request with no transfer.
//
irp = IoBuildDeviceIoControlRequest(
Ioctl,
DeviceObject,
InputBuffer,
InputBufferLength,
OutputBuffer,
OutputBufferLength,
PrivateIoctl,
&event,
&IOSB
);
if (irp == NULL) {
BattPrint (BATT_ERROR, ("BatteryIoctl: couldn't create Irp\n"));
return STATUS_INSUFFICIENT_RESOURCES;
}
//
// Pass request to port driver and wait for request to complete.
//
status = IoCallDriver(DeviceObject, irp);
if (status == STATUS_PENDING) {
KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
status = IOSB.Status;
}
if (!NT_SUCCESS(status)) {
BattPrint (BATT_ERROR, ("BatteryIoctl: Irp failed - %x\n", status));
}
BattPrint (BATT_TRACE, ("CompBatt: EXITING BatteryIoctl\n"));
return status;
}
BOOLEAN
IsBatteryAlreadyOnList(
IN PUNICODE_STRING SymbolicLinkName,
IN PCOMPOSITE_BATTERY CompBatt
)
/*++
Routine Description:
The routine runs through the list of batteries the composite keeps and checks
to see if the symbolic link name passed in matches one of them.
Arguments:
SymbolicLinkName - Name for battery to check if already on list
Return Value:
TRUE if the SymbolicLinkName belongs to a battery already on the list, FALSE
otherwise.
--*/
{
PCOMPOSITE_ENTRY batt;
PLIST_ENTRY entry;
BattPrint (BATT_TRACE, ("CompBatt: ENTERING IsBatteryAlreadyOnList\n"));
//
// Run through the list of batteries looking for new batteries
//
ExAcquireFastMutex (&CompBatt->ListMutex);
for (entry = CompBatt->Batteries.Flink; entry != &CompBatt->Batteries; entry = entry->Flink) {
batt = CONTAINING_RECORD (entry, COMPOSITE_ENTRY, Batteries);
if (!RtlCompareUnicodeString(SymbolicLinkName, &batt->BattName, TRUE)) {
//
// The battery is already on the list
//
ExReleaseFastMutex (&CompBatt->ListMutex);
return TRUE;
}
}
BattPrint (BATT_TRACE, ("CompBatt: EXITING IsBatteryAlreadyOnList\n"));
ExReleaseFastMutex (&CompBatt->ListMutex);
return FALSE;
}
PCOMPOSITE_ENTRY
RemoveBatteryFromList(
IN PUNICODE_STRING SymbolicLinkName,
IN PCOMPOSITE_BATTERY CompBatt
)
/*++
Routine Description:
The routine runs through the list of batteries the composite keeps and checks
to see if the symbolic link name passed in matches one of them. If a match is found,
the entry is removed from the list of batteries
Arguments:
SymbolicLinkName - Name for battery to check if already on list
Return Value:
TRUE if the SymbolicLinkName was found and deleted. FALSE otherwise.
--*/
{
PCOMPOSITE_ENTRY batt;
PLIST_ENTRY entry;
BattPrint (BATT_TRACE, ("CompBatt: ENTERING RemoveBatteryFromList\n"));
//
// Run through the list of batteries looking for new batteries
//
ExAcquireFastMutex (&CompBatt->ListMutex);
for (entry = CompBatt->Batteries.Flink; entry != &CompBatt->Batteries; entry = entry->Flink) {
batt = CONTAINING_RECORD (entry, COMPOSITE_ENTRY, Batteries);
if (!RtlCompareUnicodeString(SymbolicLinkName, &batt->BattName, TRUE)) {
//
// The battery is on the list, remove
//
//
// Wait until no one else is looking at this battery before removing it.
//
CompbattAcquireDeleteLock (&batt->DeleteLock);
ExReleaseFastMutex (&CompBatt->ListMutex);
CompbattReleaseDeleteLockAndWait (&batt->DeleteLock);
ExAcquireFastMutex (&CompBatt->ListMutex);
RemoveEntryList(entry);
ExReleaseFastMutex (&CompBatt->ListMutex);
return batt;
}
}
ExReleaseFastMutex (&CompBatt->ListMutex);
BattPrint (BATT_TRACE, ("CompBatt: EXITING RemoveBatteryFromList\n"));
return NULL;
}
NTSTATUS
CompBattGetDeviceObjectPointer(
IN PUNICODE_STRING ObjectName,
IN ACCESS_MASK DesiredAccess,
OUT PFILE_OBJECT *FileObject,
OUT PDEVICE_OBJECT *DeviceObject
)
/*++
Routine Description:
This routine is essentially a copy from ntos\io\iosubs.c
The reason for this is that we need to open the device with shared access
rather than exclusive access. In addition ZwCreateFile was used instead of
ZwOpenFile becuase that didn't seem to complie right when only wdm.h instead
of ntddk.h was included.
This routine returns a pointer to the device object specified by the
object name. It also returns a pointer to the referenced file object
that has been opened to the device that ensures that the device cannot
go away.
To close access to the device, the caller should dereference the file
object pointer.
Arguments:
ObjectName - Name of the device object for which a pointer is to be
returned.
DesiredAccess - Access desired to the target device object.
FileObject - Supplies the address of a variable to receive a pointer
to the file object for the device.
DeviceObject - Supplies the address of a variable to receive a pointer
to the device object for the specified device.
Return Value:
The function value is a referenced pointer to the specified device
object, if the device exists. Otherwise, NULL is returned.
--*/
{
PFILE_OBJECT fileObject;
OBJECT_ATTRIBUTES objectAttributes;
HANDLE fileHandle;
IO_STATUS_BLOCK ioStatus;
NTSTATUS status;
PAGED_CODE();
//
// Initialize the object attributes to open the device.
//
InitializeObjectAttributes( &objectAttributes,
ObjectName,
0,
(HANDLE) NULL,
(PSECURITY_DESCRIPTOR) NULL );
status = ZwCreateFile (
&fileHandle,
DesiredAccess, // desired access
&objectAttributes,
&ioStatus,
(PLARGE_INTEGER) NULL,
0L,
FILE_SHARE_READ | FILE_SHARE_WRITE, // share access
FILE_OPEN,
0,
NULL,
0);
if (NT_SUCCESS( status )) {
//
// The open operation was successful. Dereference the file handle
// and obtain a pointer to the device object for the handle.
//
status = ObReferenceObjectByHandle( fileHandle,
0,
*IoFileObjectType,
KernelMode,
(PVOID *) &fileObject,
NULL );
if (NT_SUCCESS( status )) {
*FileObject = fileObject;
//
// Get a pointer to the device object for this file.
//
*DeviceObject = IoGetRelatedDeviceObject( fileObject );
}
(VOID) ZwClose( fileHandle );
}
return status;
}
//
// Delete Lock routines from io\remlock.c
//
VOID
CompbattInitializeDeleteLock (
IN PCOMPBATT_DELETE_LOCK Lock
)
{
Lock->Deleted = FALSE;
Lock->RefCount = 1;
KeInitializeEvent(&Lock->DeleteEvent,
SynchronizationEvent,
FALSE);
}
NTSTATUS
CompbattAcquireDeleteLock (
IN PCOMPBATT_DELETE_LOCK Lock
)
{
LONG lockValue;
lockValue = InterlockedIncrement(&Lock->RefCount);
if (Lock->Deleted) {
if (0 == InterlockedDecrement (&Lock->RefCount)) {
KeSetEvent (&Lock->DeleteEvent, 0, FALSE);
}
return STATUS_DELETE_PENDING;
}
return STATUS_SUCCESS;
}
VOID
CompbattReleaseDeleteLock (
IN PCOMPBATT_DELETE_LOCK Lock
)
{
if (0 == InterlockedDecrement(&Lock->RefCount)) {
KeSetEvent(&Lock->DeleteEvent,
IO_NO_INCREMENT,
FALSE);
}
}
VOID
CompbattReleaseDeleteLockAndWait (
IN PCOMPBATT_DELETE_LOCK Lock
)
{
Lock->Deleted = TRUE;
InterlockedDecrement (&Lock->RefCount);
if (0 < InterlockedDecrement (&Lock->RefCount)) {
KeWaitForSingleObject (&Lock->DeleteEvent,
Executive,
KernelMode,
FALSE,
NULL);
}
}