|
|
/*++
Copyright (c) 1990 Microsoft Corporation
Module Name:
acpiec.c
Abstract:
ACPI Embedded Controller Driver
Author:
Ken Reneris
Environment:
Kernel mode
Notes:
Revision History: 13-Feb-97 PnP/Power support - Bob Moore
--*/
#include "ecp.h"
//
// List of FDOs managed by this driver
//
PDEVICE_OBJECT FdoList = NULL;
#if DEBUG
ULONG ECDebug = EC_ERRORS; #endif
//
// Prototypes
//
NTSTATUS DriverEntry( IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath );
NTSTATUS AcpiEcPnpDispatch( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp );
NTSTATUS AcpiEcPowerDispatch( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp );
NTSTATUS AcpiEcAddDevice( IN PDRIVER_OBJECT DriverObject, IN PDEVICE_OBJECT Pdo );
//
// ReadWrite and PowerDispatch should stay resident
//
#ifdef ALLOC_PRAGMA
#pragma alloc_text(INIT,DriverEntry)
#pragma alloc_text(PAGE,AcpiEcUnload)
#pragma alloc_text(PAGE,AcpiEcOpenClose)
#pragma alloc_text(PAGE,AcpiEcInternalControl)
#endif
NTSTATUS DriverEntry( IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath ) /*++
Routine Description:
This routine initializes the ACPI Embedded Controller Driver
Arguments:
DriverObject - Pointer to driver object created by system. RegistryPath - Pointer to the Unicode name of the registry path for this driver.
Return Value:
The function value is the final status from the initialization operation.
--*/ {
//
// Set up the device driver entry points.
//
#if DEBUG
// Security: Can only open file handles in debug builds
DriverObject->MajorFunction[IRP_MJ_CREATE] = AcpiEcOpenClose; DriverObject->MajorFunction[IRP_MJ_CLOSE] = AcpiEcOpenClose; #endif
DriverObject->MajorFunction[IRP_MJ_READ] = AcpiEcReadWrite; DriverObject->MajorFunction[IRP_MJ_WRITE] = AcpiEcReadWrite; DriverObject->MajorFunction[IRP_MJ_POWER] = AcpiEcPowerDispatch; DriverObject->MajorFunction[IRP_MJ_PNP] = AcpiEcPnpDispatch; DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = AcpiEcForwardRequest; DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = AcpiEcInternalControl; DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = AcpiEcForwardRequest; DriverObject->DriverExtension->AddDevice = AcpiEcAddDevice; DriverObject->DriverUnload = AcpiEcUnload;
return STATUS_SUCCESS; }
VOID AcpiEcUnload( IN PDRIVER_OBJECT DriverObject ) /*++
Routine Description:
This routine unloads the ACPI Embedded Controller Driver Note: The driver should be already disconnected from the GPE by this time.
Arguments:
DriverObject - Pointer to driver object created by system.
Return Value:
None.
--*/ { PVOID LockPtr; KIRQL OldIrql; PECDATA EcData;
EcPrint(EC_LOW, ("AcpiEcUnload: Entering\n" ));
LockPtr = MmLockPagableCodeSection(AcpiEcUnload);
while (DriverObject->DeviceObject) {
EcData = DriverObject->DeviceObject->DeviceExtension;
//
// Device can only be active if initialization was completed
//
if (EcData->IsStarted) {
//
// Set state to determine when unload can occur, and issue a device service
// call to get it unloaded now of the device is idle
//
ASSERT (EcData->DeviceState == EC_DEVICE_WORKING); EcData->DeviceState = EC_DEVICE_UNLOAD_PENDING; AcpiEcServiceDevice (EcData);
//
// Wait for device to cleanup
//
while (EcData->DeviceState != EC_DEVICE_UNLOAD_COMPLETE) { KeWaitForSingleObject (&EcData->Unload, Suspended, KernelMode, FALSE, NULL); } }
//
// Make sure caller signalling the unload is done
//
KeAcquireSpinLock (&EcData->Lock, &OldIrql); KeReleaseSpinLock (&EcData->Lock, OldIrql);
//
// Free resources
//
IoFreeIrp (EcData->QueryRequest); IoFreeIrp (EcData->MiscRequest);
if (EcData->VectorTable) { ExFreePool (EcData->VectorTable); }
IoDeleteDevice (EcData->DeviceObject); }
//
// Done
//
MmUnlockPagableImageSection(LockPtr);
EcPrint(EC_LOW, ("AcpiEcUnload: Driver Unloaded\n")); }
NTSTATUS AcpiEcOpenClose( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) { PAGED_CODE();
//
// Complete the request and return status.
//
Irp->IoStatus.Status = STATUS_SUCCESS; Irp->IoStatus.Information = 0; IoCompleteRequest(Irp, IO_NO_INCREMENT); return(STATUS_SUCCESS); }
NTSTATUS AcpiEcReadWrite( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp )
/*++
Routine Description:
This routine is the dispatch routine for read & write requests.
Arguments:
DeviceObject - Pointer to class device object.
Irp - Pointer to the request packet.
Return Value:
Status is returned.
--*/
{ PIO_STACK_LOCATION irpSp; PECDATA EcData; KIRQL OldIrql; BOOLEAN StartIo; NTSTATUS Status; #if DEBUG
UCHAR i; #endif
Status = STATUS_INVALID_PARAMETER; Irp->IoStatus.Information = 0; Irp->IoStatus.Status = Status;
//
// Get a pointer to the current parameters for this request. The
// information is contained in the current stack location.
//
irpSp = IoGetCurrentIrpStackLocation(Irp); EcData = DeviceObject->DeviceExtension;
#if !DEBUG
//
// Security: Refuse any request sent from user mode (except on debug builds)
//
if (Irp->RequestorMode != KernelMode) { Status = STATUS_ACCESS_DENIED; Irp->IoStatus.Status = Status; } else #endif
if (irpSp->Parameters.Read.ByteOffset.HighPart || irpSp->Parameters.Read.ByteOffset.LowPart > 255 || irpSp->Parameters.Read.ByteOffset.LowPart + irpSp->Parameters.Read.Length > 256) { //
// Verify offset is within Embedded Controller range
//
Status = STATUS_END_OF_FILE; Irp->IoStatus.Status = Status;
} else {
//
// Queue the transfer up
//
KeAcquireSpinLock (&EcData->Lock, &OldIrql);
if (EcData->DeviceState > EC_DEVICE_UNLOAD_PENDING) { //
// Device is unloading
//
Status = STATUS_NO_SUCH_DEVICE; Irp->IoStatus.Status = Status;
} else {
#if DEBUG
if ((irpSp->MajorFunction == IRP_MJ_WRITE) && (ECDebug & EC_TRANSACTION)) { EcPrint (EC_TRANSACTION, ("AcpiEcReadWrite: Write (")); for (i=0; i < irpSp->Parameters.Write.Length; i++) { EcPrint (EC_TRANSACTION, ("%02x ", ((PUCHAR)Irp->AssociatedIrp.SystemBuffer) [i]));
} EcPrint (EC_TRANSACTION, (") to %02x length %02x\n", (UCHAR)irpSp->Parameters.Write.ByteOffset.LowPart, (UCHAR)irpSp->Parameters.Write.Length)); } #endif
Status = STATUS_PENDING; Irp->IoStatus.Status = Status; IoMarkIrpPending (Irp); InsertTailList (&EcData->WorkQueue, &Irp->Tail.Overlay.ListEntry); StartIo = DeviceObject->CurrentIrp == NULL; AcpiEcLogAction (EcData, EC_ACTION_QUEUED_IO, StartIo); }
KeReleaseSpinLock (&EcData->Lock, OldIrql);
}
//
// Handle status
//
if (Status == STATUS_PENDING) {
//
// IO is queued, if device is not busy start it
//
if (StartIo) { AcpiEcServiceDevice (EcData); }
} else { //
// For opregion requests, there is no way to fail the request, so return -1
//
RtlFillMemory (Irp->AssociatedIrp.SystemBuffer, irpSp->Parameters.Read.Length, 0xff);
IoCompleteRequest(Irp, IO_NO_INCREMENT); }
return Status; }
NTSTATUS AcpiEcPowerDispatch( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp )
/*++
Routine Description:
This routine is the dispatch routine for power requests.
Arguments:
DeviceObject - Pointer to class device object. Irp - Pointer to the request packet.
Return Value:
Status is returned.
--*/
{ NTSTATUS status; PECDATA ecData = DeviceObject->DeviceExtension;
//
// Start the next power irp
//
PoStartNextPowerIrp( Irp );
//
// Handle the irp
//
if (ecData->LowerDeviceObject != NULL) {
IoSkipCurrentIrpStackLocation( Irp ); status = PoCallDriver( ecData->LowerDeviceObject, Irp );
} else {
//
// Complete irp with the current code;
status = Irp->IoStatus.Status; IoCompleteRequest( Irp, IO_NO_INCREMENT );
}
return status; }
NTSTATUS AcpiEcInternalControl( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp )
/*++
Routine Description: Internal IOCTL dispatch routine
Arguments:
DeviceObject - Pointer to class device object. Irp - Pointer to the request packet.
Return Value:
Status is returned.
--*/
{ PIO_STACK_LOCATION IrpSp; PECDATA EcData; NTSTATUS Status;
PAGED_CODE();
Status = STATUS_INVALID_PARAMETER; Irp->IoStatus.Information = 0;
//
// Get a pointer to the current parameters for this request. The
// information is contained in the current stack location.
//
IrpSp = IoGetCurrentIrpStackLocation(Irp); EcData = DeviceObject->DeviceExtension;
EcPrint (EC_NOTE, ("AcpiEcInternalControl: dispatch, code = %d\n", IrpSp->Parameters.DeviceIoControl.IoControlCode));
Status = STATUS_INVALID_PARAMETER; switch (IrpSp->Parameters.DeviceIoControl.IoControlCode) {
case EC_CONNECT_QUERY_HANDLER: Status = AcpiEcConnectHandler (EcData, Irp); break;
case EC_DISCONNECT_QUERY_HANDLER: Status = AcpiEcDisconnectHandler (EcData, Irp); break; }
if (Status != STATUS_PENDING) {
Irp->IoStatus.Status = Status; IoCompleteRequest (Irp, IO_NO_INCREMENT); }
return Status;
}
NTSTATUS AcpiEcForwardRequest( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) /*++
Routine Description:
This routine forwards the irp down the stack
Arguments:
DeviceObject - The target Irp - The request
Return Value:
NTSTATUS
--*/ { NTSTATUS status; PECDATA ecData = DeviceObject->DeviceExtension;
if (ecData->LowerDeviceObject != NULL) {
IoSkipCurrentIrpStackLocation( Irp ); status = IoCallDriver( ecData->LowerDeviceObject, Irp );
} else {
status = Irp->IoStatus.Status; IoCompleteRequest( Irp, IO_NO_INCREMENT );
}
return status; }
|