521 lines
11 KiB
C
521 lines
11 KiB
C
|
/*++
|
|||
|
|
|||
|
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.
|
|||
|
//
|
|||
|
|
|||
|
DriverObject->MajorFunction[IRP_MJ_CREATE] = AcpiEcOpenClose;
|
|||
|
DriverObject->MajorFunction[IRP_MJ_CLOSE] = AcpiEcOpenClose;
|
|||
|
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;
|
|||
|
|
|||
|
//
|
|||
|
// Verify offset is within Embedded Controller range
|
|||
|
//
|
|||
|
|
|||
|
if (irpSp->Parameters.Read.ByteOffset.HighPart ||
|
|||
|
irpSp->Parameters.Read.ByteOffset.LowPart > 255 ||
|
|||
|
irpSp->Parameters.Read.ByteOffset.LowPart + irpSp->Parameters.Read.Length > 256) {
|
|||
|
|
|||
|
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;
|
|||
|
}
|