457 lines
11 KiB
C
457 lines
11 KiB
C
/*++
|
||
|
||
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);
|
||
}
|
||
}
|
||
|