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