You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
519 lines
11 KiB
519 lines
11 KiB
/*++
|
|
|
|
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;
|
|
|
|
}
|
|
|