windows-nt/Source/XPSP1/NT/base/busdrv/acpi/smbus/smbhc/smbhc.c
2020-09-26 16:20:57 +08:00

520 lines
11 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
Copyright (c) 1990 Microsoft Corporation
Module Name:
smbhc.c
Abstract:
SMB Host Controller Driver
Author:
Ken Reneris
Environment:
Notes:
Revision History:
--*/
#include "smbhcp.h"
ULONG SMBHCDebug = 0x0;
//
// Prototypes
//
typedef struct {
ULONG Base;
ULONG Query;
} NEW_HC_DEVICE, *PNEW_HC_DEVICE;
NTSTATUS
DriverEntry(
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath
);
NTSTATUS
SmbHcAddDevice(
IN PDRIVER_OBJECT DriverObject,
IN PDEVICE_OBJECT Pdo
);
NTSTATUS
SmbHcNewHc (
IN PSMB_CLASS SmbClass,
IN PVOID Extension,
IN PVOID Context
);
NTSTATUS
SmbHcSynchronousRequest (
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Context
);
NTSTATUS
SmbHcResetDevice (
IN struct _SMB_CLASS *SmbClass,
IN PVOID SmbMiniport
);
NTSTATUS
SmbHcStopDevice (
IN struct _SMB_CLASS *SmbClass,
IN PVOID SmbMiniport
);
#ifdef ALLOC_PRAGMA
#pragma alloc_text(INIT,DriverEntry)
#pragma alloc_text(PAGE,SmbHcAddDevice)
#pragma alloc_text(PAGE,SmbHcResetDevice)
#pragma alloc_text(PAGE,SmbHcStopDevice)
#pragma alloc_text(PAGE,SmbHcNewHc)
#pragma alloc_text(PAGE,SmbHcSynchronousRequest)
#endif
NTSTATUS
DriverEntry(
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath
)
/*++
Routine Description:
This routine initializes the SM Bus Host 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.
--*/
{
NTSTATUS Status;
//
// Have class driver allocate a new SMB miniport device
//
Status = SmbClassInitializeDevice (
SMB_HC_MAJOR_VERSION,
SMB_HC_MINOR_VERSION,
DriverObject
);
//
// AddDevice comes directly to this miniport
//
DriverObject->DriverExtension->AddDevice = SmbHcAddDevice;
return (Status);
}
NTSTATUS
SmbHcAddDevice(
IN PDRIVER_OBJECT DriverObject,
IN PDEVICE_OBJECT Pdo
)
/*++
Routine Description:
This routine creates functional device objects for each SmbHc controller in the
system and attaches them to the physical device objects for the controllers
Arguments:
DriverObject - a pointer to the object for this driver
PhysicalDeviceObject - a pointer to the physical object we need to attach to
Return Value:
Status from device creation and initialization
--*/
{
NTSTATUS status;
PDEVICE_OBJECT fdo = NULL;
PAGED_CODE();
SmbPrint(SMB_LOW, ("SmbHcAddDevice Entered with pdo %x\n", Pdo));
if (Pdo == NULL) {
//
// Have we been asked to do detection on our own?
// if so just return no more devices
//
SmbPrint(SMB_LOW, ("SmbHcAddDevice - asked to do detection\n"));
return STATUS_NO_MORE_ENTRIES;
}
//
// Create and initialize the new functional device object
//
status = SmbClassCreateFdo(
DriverObject,
Pdo,
sizeof (SMB_DATA),
SmbHcNewHc,
NULL,
&fdo
);
if (!NT_SUCCESS(status) || fdo == NULL) {
SmbPrint(SMB_LOW, ("SmbHcAddDevice - error creating Fdo. Status = %08x\n", status));
}
return status;
}
NTSTATUS
SmbHcNewHc (
IN PSMB_CLASS SmbClass,
IN PVOID Extension,
IN PVOID Context
)
/*++
Routine Description:
This function is called by the smb bus class driver for the
miniport to perform miniport specific initialization
Arguments:
SmbClass - Shared class driver & miniport structure.
Extension - Buffer for miniport specific storage
Context - Passed through class driver
Return Value:
Status
--*/
{
ACPI_EVAL_INPUT_BUFFER inputBuffer;
ACPI_EVAL_OUTPUT_BUFFER outputBuffer;
IO_STATUS_BLOCK ioStatusBlock;
KEVENT event;
NTSTATUS status;
PACPI_METHOD_ARGUMENT argument;
PIRP irp;
PSMB_DATA smbData;
ULONG cmReturn;
PAGED_CODE();
SmbPrint(SMB_LOW, ("SmbHcNewHc: Entry\n") );
smbData = (PSMB_DATA) Extension;
//
// Fill in SmbClass info
//
SmbClass->StartIo = SmbHcStartIo;
SmbClass->ResetDevice = SmbHcResetDevice;
SmbClass->StopDevice = SmbHcStopDevice;
//
// Lower device is the EC driver, but we will use the ACPI PDO, since
// the ACPI filter driver will pass it thru.
//
smbData->Pdo = SmbClass->PDO;
smbData->LowerDeviceObject = SmbClass->LowerDeviceObject; // ACPI filter will handle it
//
// Initialize the input parameters
//
RtlZeroMemory( &inputBuffer, sizeof(ACPI_EVAL_INPUT_BUFFER) );
inputBuffer.MethodNameAsUlong = CM_EC_METHOD;
inputBuffer.Signature = ACPI_EVAL_INPUT_BUFFER_SIGNATURE;
//
// Initialize the even to wait on
//
KeInitializeEvent( &event, NotificationEvent, FALSE);
//
// Build the synchronouxe request
//
irp = IoBuildDeviceIoControlRequest(
IOCTL_ACPI_ASYNC_EVAL_METHOD,
SmbClass->LowerDeviceObject,
&inputBuffer,
sizeof(ACPI_EVAL_INPUT_BUFFER),
&outputBuffer,
sizeof(ACPI_EVAL_OUTPUT_BUFFER),
FALSE,
&event,
&ioStatusBlock
);
if (!irp) {
SmbPrint(SMB_ERROR, ("SmbHcNewHc: Couldn't allocate Irp\n"));
return STATUS_INSUFFICIENT_RESOURCES;
}
//
// Send to ACPI driver
//
status = IoCallDriver (smbData->LowerDeviceObject, irp);
if (status == STATUS_PENDING) {
KeWaitForSingleObject( &event, Suspended, KernelMode, FALSE, NULL);
status = ioStatusBlock.Status;
}
argument = outputBuffer.Argument;
if (!NT_SUCCESS(status) ||
outputBuffer.Signature != ACPI_EVAL_OUTPUT_BUFFER_SIGNATURE ||
outputBuffer.Count == 0 ||
argument->Type != ACPI_METHOD_ARGUMENT_INTEGER) {
SmbPrint(SMB_LOW, ("SmbHcNewHc: _EC Control Method failed, status = %Lx\n", status));
return status;
}
//
// Remember the result
//
cmReturn = argument->Argument;
//
// Fill in miniport info
//
smbData->Class = SmbClass;
smbData->IoState = SMB_IO_IDLE;
smbData->EcQuery = (UCHAR) cmReturn; // Per ACPI Spec, LSB=Query
smbData->EcBase = (UCHAR) (cmReturn >> 8); // Per ACPI Spec, MSB=Base
SmbPrint(SMB_LOW, ("SmbHcNewHc: Exit\n"));
return status;
}
NTSTATUS
SmbHcSynchronousRequest (
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Context
)
/*++
Routine Description:
Completion function for synchronous IRPs sent to this driver.
Context is the event to set
--*/
{
PAGED_CODE();
return STATUS_MORE_PROCESSING_REQUIRED;
}
NTSTATUS
SmbHcResetDevice (
IN struct _SMB_CLASS *SmbClass,
IN PVOID SmbMiniport
)
{
EC_HANDLER_REQUEST queryConnect;
PSMB_DATA smbData;
KEVENT event;
NTSTATUS status;
IO_STATUS_BLOCK ioStatusBlock;
PIRP irp;
SmbPrint(SMB_LOW, ("SmbHcResetDevice: Entry\n") );
PAGED_CODE();
smbData = (PSMB_DATA) SmbMiniport;
//
// Initialize the even to wait on
//
KeInitializeEvent( &event, NotificationEvent, FALSE);
//
// Build the input data to the EC
//
queryConnect.Vector = smbData->EcQuery;
queryConnect.Handler = SmbHcQueryEvent;
queryConnect.Context = smbData;
//
// Connect Query notify with EC driver
//
irp = IoBuildDeviceIoControlRequest(
EC_CONNECT_QUERY_HANDLER,
smbData->LowerDeviceObject,
&queryConnect,
sizeof(EC_HANDLER_REQUEST),
NULL,
0,
TRUE,
&event,
&ioStatusBlock
);
if (!irp) {
SmbPrint(SMB_ERROR, ("SmbHcResetDevice: Couldn't allocate Irp\n"));
return STATUS_INSUFFICIENT_RESOURCES;
}
//
// Send off to EC driver
//
status = IoCallDriver (smbData->LowerDeviceObject, irp);
if (status == STATUS_PENDING) {
KeWaitForSingleObject( &event, Suspended, KernelMode, FALSE, NULL);
status = ioStatusBlock.Status;
}
if (!NT_SUCCESS(status)) {
SmbPrint(SMB_LOW, ("SmbHcResetDevice: Connect query failed, status = %Lx\n", status));
}
SmbPrint(SMB_LOW, ("SmbHcResetDevice: Exit\n"));
return status;
}
NTSTATUS
SmbHcStopDevice (
IN struct _SMB_CLASS *SmbClass,
IN PVOID SmbMiniport
)
{
EC_HANDLER_REQUEST queryConnect;
PSMB_DATA smbData;
KEVENT event;
NTSTATUS status;
IO_STATUS_BLOCK ioStatusBlock;
PIRP irp;
SmbPrint(SMB_LOW, ("SmbHcStopDevice: Entry\n") );
//
// There is currently no way to test this code path.
// Leaving untested code for potential future use/development
//
DbgPrint("SmbHcStopDevice: Encountered previously untested code.\n"
"enter 'g' to continue, or contact the appropriate developer.\n");
DbgBreakPoint();
// Cutting code to reduce file size (see above comment)
#if 0
PAGED_CODE();
smbData = (PSMB_DATA) SmbMiniport;
//
// Initialize the even to wait on
//
KeInitializeEvent( &event, NotificationEvent, FALSE);
//
// Build the input data to the EC
//
queryConnect.Vector = smbData->EcQuery;
queryConnect.Handler = SmbHcQueryEvent;
queryConnect.Context = smbData;
//
// Connect Query notify with EC driver
//
irp = IoBuildDeviceIoControlRequest(
EC_DISCONNECT_QUERY_HANDLER,
smbData->LowerDeviceObject,
&queryConnect,
sizeof(EC_HANDLER_REQUEST),
NULL,
0,
TRUE,
&event,
&ioStatusBlock
);
if (!irp) {
SmbPrint(SMB_ERROR, ("SmbHcStopDevice: Couldn't allocate Irp\n"));
return STATUS_INSUFFICIENT_RESOURCES;
}
//
// Send off to EC driver
//
status = IoCallDriver (smbData->LowerDeviceObject, irp);
if (status == STATUS_PENDING) {
KeWaitForSingleObject( &event, Suspended, KernelMode, FALSE, NULL);
status = ioStatusBlock.Status;
}
if (!NT_SUCCESS(status)) {
SmbPrint(SMB_LOW, ("SmbHcStopDevice: Connect query failed, status = %Lx\n", status));
}
SmbPrint(SMB_LOW, ("SmbHcStopDevice: Exit\n"));
return status;
#endif
return STATUS_SUCCESS;
}