429 lines
9.7 KiB
C
429 lines
9.7 KiB
C
|
/*++
|
|||
|
|
|||
|
Copyright (c) 1990 Microsoft Corporation
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
smbcpnp.c
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
SMBus Class Driver Plug and Play support
|
|||
|
|
|||
|
Author:
|
|||
|
|
|||
|
Bob Moore (Intel)
|
|||
|
|
|||
|
Environment:
|
|||
|
|
|||
|
Notes:
|
|||
|
|
|||
|
|
|||
|
Revision History:
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
#include "smbc.h"
|
|||
|
#include "oprghdlr.h"
|
|||
|
|
|||
|
|
|||
|
#define SMBHC_DEVICE_NAME L"\\Device\\SmbHc"
|
|||
|
extern ULONG SMBCDebug;
|
|||
|
|
|||
|
//
|
|||
|
// Prototypes
|
|||
|
//
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
SmbCPnpDispatch(
|
|||
|
IN PDEVICE_OBJECT DeviceObject,
|
|||
|
IN PIRP Irp
|
|||
|
);
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
SmbCStartDevice (
|
|||
|
IN PDEVICE_OBJECT FDO,
|
|||
|
IN PIRP Irp
|
|||
|
);
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
SmbCStopDevice (
|
|||
|
IN PDEVICE_OBJECT FDO,
|
|||
|
IN PIRP Irp
|
|||
|
);
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
SmbClassCreateFdo (
|
|||
|
IN PDRIVER_OBJECT DriverObject,
|
|||
|
IN PDEVICE_OBJECT PDO,
|
|||
|
IN ULONG MiniportExtensionSize,
|
|||
|
IN PSMB_INITIALIZE_MINIPORT MiniportInitialize,
|
|||
|
IN PVOID MiniportContext,
|
|||
|
OUT PDEVICE_OBJECT *FDO
|
|||
|
);
|
|||
|
|
|||
|
#ifdef ALLOC_PRAGMA
|
|||
|
#pragma alloc_text(PAGE,SmbCPnpDispatch)
|
|||
|
#pragma alloc_text(PAGE,SmbCStartDevice)
|
|||
|
#pragma alloc_text(PAGE,SmbClassCreateFdo)
|
|||
|
#endif
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
SmbCPnpDispatch(
|
|||
|
IN PDEVICE_OBJECT DeviceObject,
|
|||
|
IN PIRP Irp
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine is the dispatcher for plug and play requests.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
DeviceObject - Pointer to class device object.
|
|||
|
Irp - Pointer to the request packet.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Status is returned.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PIO_STACK_LOCATION irpStack;
|
|||
|
PSMBDATA SmbData;
|
|||
|
KEVENT syncEvent;
|
|||
|
NTSTATUS status = STATUS_NOT_SUPPORTED;
|
|||
|
|
|||
|
PAGED_CODE();
|
|||
|
|
|||
|
//
|
|||
|
// Get a pointer to the current parameters for this request. The
|
|||
|
// information is contained in the current stack location.
|
|||
|
//
|
|||
|
|
|||
|
irpStack = IoGetCurrentIrpStackLocation(Irp);
|
|||
|
SmbData = (PSMBDATA) DeviceObject->DeviceExtension;
|
|||
|
|
|||
|
SmbPrint (SMB_NOTE, ("SmbCPnpDispatch: PnP dispatch, minor = %d\n",
|
|||
|
irpStack->MinorFunction));
|
|||
|
|
|||
|
//
|
|||
|
// Dispatch minor function
|
|||
|
//
|
|||
|
|
|||
|
switch (irpStack->MinorFunction) {
|
|||
|
|
|||
|
case IRP_MN_START_DEVICE:
|
|||
|
IoCopyCurrentIrpStackLocationToNext (Irp);
|
|||
|
|
|||
|
KeInitializeEvent(&syncEvent, SynchronizationEvent, FALSE);
|
|||
|
|
|||
|
IoSetCompletionRoutine(Irp, SmbCSynchronousRequest, &syncEvent, TRUE, TRUE, TRUE);
|
|||
|
|
|||
|
status = IoCallDriver(SmbData->Class.LowerDeviceObject, Irp);
|
|||
|
|
|||
|
if (status == STATUS_PENDING) {
|
|||
|
KeWaitForSingleObject(&syncEvent, Executive, KernelMode, FALSE, NULL);
|
|||
|
status = Irp->IoStatus.Status;
|
|||
|
}
|
|||
|
|
|||
|
status = SmbCStartDevice (DeviceObject, Irp);
|
|||
|
|
|||
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|||
|
|
|||
|
return status;
|
|||
|
|
|||
|
|
|||
|
case IRP_MN_STOP_DEVICE:
|
|||
|
status = SmbCStopDevice(DeviceObject, Irp);
|
|||
|
break;
|
|||
|
|
|||
|
|
|||
|
case IRP_MN_QUERY_STOP_DEVICE:
|
|||
|
|
|||
|
SmbPrint(SMB_LOW, ("SmbCPnp: IRP_MN_QUERY_STOP_DEVICE\n"));
|
|||
|
|
|||
|
status = STATUS_SUCCESS;
|
|||
|
break;
|
|||
|
|
|||
|
|
|||
|
case IRP_MN_CANCEL_STOP_DEVICE:
|
|||
|
|
|||
|
SmbPrint(SMB_LOW, ("SmbCPnp: IRP_MN_CANCEL_STOP_DEVICE\n"));
|
|||
|
|
|||
|
status = STATUS_SUCCESS;
|
|||
|
break;
|
|||
|
|
|||
|
|
|||
|
default:
|
|||
|
SmbPrint(SMB_LOW, ("SmbCPnp: Unimplemented PNP minor code %d\n",
|
|||
|
irpStack->MinorFunction));
|
|||
|
}
|
|||
|
|
|||
|
if (status != STATUS_NOT_SUPPORTED) {
|
|||
|
|
|||
|
Irp->IoStatus.Status = status;
|
|||
|
}
|
|||
|
|
|||
|
if (NT_SUCCESS(status) || (status == STATUS_NOT_SUPPORTED)) {
|
|||
|
|
|||
|
IoSkipCurrentIrpStackLocation (Irp);
|
|||
|
status = IoCallDriver(SmbData->Class.LowerDeviceObject, Irp) ;
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
IoCompleteRequest (Irp, IO_NO_INCREMENT);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
return status;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
SmbClassCreateFdo (
|
|||
|
IN PDRIVER_OBJECT DriverObject,
|
|||
|
IN PDEVICE_OBJECT PDO,
|
|||
|
IN ULONG MiniportExtensionSize,
|
|||
|
IN PSMB_INITIALIZE_MINIPORT MiniportInitialize,
|
|||
|
IN PVOID MiniportContext,
|
|||
|
OUT PDEVICE_OBJECT *OutFDO
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine will create and initialize a functional device object to
|
|||
|
be attached to a SMBus Host controller PDO. It is called from the miniport
|
|||
|
AddDevice routine.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
DriverObject - a pointer to the driver object this is created under
|
|||
|
PDO - a pointer to the SMBus HC PDO
|
|||
|
MiniportExtensionSize - Extension size required by the miniport
|
|||
|
MiniportInitialize - a pointer to the miniport init routine
|
|||
|
MiniportContext - Miniport-defined context info
|
|||
|
OutFDO - a location to store the pointer to the new device object
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
STATUS_SUCCESS if everything was successful
|
|||
|
reason for failure otherwise
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
NTSTATUS Status;
|
|||
|
UNICODE_STRING UnicodeString;
|
|||
|
PDEVICE_OBJECT FDO;
|
|||
|
PDEVICE_OBJECT lowerDevice = NULL;
|
|||
|
PSMBDATA SmbData;
|
|||
|
|
|||
|
//
|
|||
|
// Allocate a device object for this miniport
|
|||
|
//
|
|||
|
|
|||
|
RtlInitUnicodeString(&UnicodeString, SMBHC_DEVICE_NAME);
|
|||
|
|
|||
|
Status = IoCreateDevice(
|
|||
|
DriverObject,
|
|||
|
sizeof (SMBDATA) + MiniportExtensionSize,
|
|||
|
&UnicodeString,
|
|||
|
FILE_DEVICE_UNKNOWN, // DeviceType
|
|||
|
0,
|
|||
|
FALSE,
|
|||
|
&FDO
|
|||
|
);
|
|||
|
|
|||
|
if (Status != STATUS_SUCCESS) {
|
|||
|
SmbPrint(SMB_LOW, ("SmbC: unable to create device object: %X\n", Status ));
|
|||
|
return(Status);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Initialize class data
|
|||
|
//
|
|||
|
|
|||
|
FDO->Flags |= DO_BUFFERED_IO;
|
|||
|
|
|||
|
//
|
|||
|
// Layer our FDO on top of the PDO
|
|||
|
//
|
|||
|
|
|||
|
lowerDevice = IoAttachDeviceToDeviceStack(FDO,PDO);
|
|||
|
|
|||
|
//
|
|||
|
// No status. Do the best we can.
|
|||
|
//
|
|||
|
ASSERT(lowerDevice);
|
|||
|
|
|||
|
//
|
|||
|
// Fill out class data
|
|||
|
//
|
|||
|
|
|||
|
SmbData = (PSMBDATA) FDO->DeviceExtension;
|
|||
|
SmbData->Class.MajorVersion = SMB_CLASS_MAJOR_VERSION;
|
|||
|
SmbData->Class.MinorVersion = SMB_CLASS_MINOR_VERSION;
|
|||
|
SmbData->Class.Miniport = SmbData + 1;
|
|||
|
SmbData->Class.DeviceObject = FDO;
|
|||
|
SmbData->Class.LowerDeviceObject = lowerDevice;
|
|||
|
SmbData->Class.PDO = PDO;
|
|||
|
SmbData->Class.CurrentIrp = NULL;
|
|||
|
SmbData->Class.CurrentSmb = NULL;
|
|||
|
|
|||
|
KeInitializeEvent (&SmbData->AlarmEvent, NotificationEvent, FALSE);
|
|||
|
KeInitializeSpinLock (&SmbData->SpinLock);
|
|||
|
InitializeListHead (&SmbData->WorkQueue);
|
|||
|
InitializeListHead (&SmbData->Alarms);
|
|||
|
|
|||
|
KeInitializeTimer (&SmbData->RetryTimer);
|
|||
|
KeInitializeDpc (&SmbData->RetryDpc, SmbCRetry, SmbData);
|
|||
|
|
|||
|
//
|
|||
|
// Miniport initialization
|
|||
|
//
|
|||
|
|
|||
|
Status = MiniportInitialize (&SmbData->Class, SmbData->Class.Miniport, MiniportContext);
|
|||
|
FDO->Flags |= DO_POWER_PAGABLE;
|
|||
|
FDO->Flags &= ~DO_DEVICE_INITIALIZING;
|
|||
|
|
|||
|
if (!NT_SUCCESS(Status)) {
|
|||
|
IoDeleteDevice (FDO);
|
|||
|
return Status;
|
|||
|
}
|
|||
|
|
|||
|
*OutFDO = FDO;
|
|||
|
return Status;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
SmbCStartDevice (
|
|||
|
IN PDEVICE_OBJECT FDO,
|
|||
|
IN PIRP Irp
|
|||
|
)
|
|||
|
{
|
|||
|
NTSTATUS Status;
|
|||
|
PSMBDATA SmbData;
|
|||
|
|
|||
|
|
|||
|
SmbPrint(SMB_LOW, ("SmbCStartDevice Entered with fdo %x\n", FDO));
|
|||
|
|
|||
|
SmbData = (PSMBDATA) FDO->DeviceExtension;
|
|||
|
|
|||
|
//
|
|||
|
// Initialize the Miniclass driver.
|
|||
|
//
|
|||
|
SmbData->Class.CurrentIrp = Irp;
|
|||
|
|
|||
|
Status = SmbData->Class.ResetDevice (
|
|||
|
&SmbData->Class,
|
|||
|
SmbData->Class.Miniport
|
|||
|
);
|
|||
|
|
|||
|
SmbData->Class.CurrentIrp = NULL;
|
|||
|
|
|||
|
if (!NT_SUCCESS(Status)) {
|
|||
|
|
|||
|
SmbPrint(SMB_ERROR,
|
|||
|
("SmbCStartDevice: Class.ResetDevice failed. = %Lx\n",
|
|||
|
Status));
|
|||
|
|
|||
|
return Status;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Install the Operation Region handlers
|
|||
|
//
|
|||
|
|
|||
|
Status = RegisterOpRegionHandler (SmbData->Class.LowerDeviceObject,
|
|||
|
ACPI_OPREGION_ACCESS_AS_RAW,
|
|||
|
ACPI_OPREGION_REGION_SPACE_SMB,
|
|||
|
(PACPI_OP_REGION_HANDLER)SmbCRawOpRegionHandler,
|
|||
|
SmbData,
|
|||
|
0,
|
|||
|
&SmbData->RawOperationRegionObject);
|
|||
|
if (!NT_SUCCESS(Status)) {
|
|||
|
|
|||
|
SmbPrint(SMB_ERROR,
|
|||
|
("SmbCStartDevice: Could not install raw Op region handler, status = %Lx\n",
|
|||
|
Status));
|
|||
|
|
|||
|
//
|
|||
|
// Failure to register opregion handler is not critical. It just reduces functionality
|
|||
|
//
|
|||
|
SmbData->RawOperationRegionObject = NULL;
|
|||
|
Status = STATUS_SUCCESS;
|
|||
|
}
|
|||
|
|
|||
|
return Status;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
SmbCStopDevice (
|
|||
|
IN PDEVICE_OBJECT FDO,
|
|||
|
IN PIRP Irp
|
|||
|
)
|
|||
|
{
|
|||
|
NTSTATUS Status;
|
|||
|
PSMBDATA SmbData;
|
|||
|
|
|||
|
|
|||
|
SmbPrint(SMB_LOW, ("SmbCStopDevice Entered with fdo %x\n", FDO));
|
|||
|
|
|||
|
|
|||
|
SmbData = (PSMBDATA) FDO->DeviceExtension;
|
|||
|
|
|||
|
//
|
|||
|
// Stop handling operation regions before turning off driver.
|
|||
|
//
|
|||
|
if (SmbData->RawOperationRegionObject) {
|
|||
|
DeRegisterOpRegionHandler (SmbData->Class.LowerDeviceObject,
|
|||
|
SmbData->RawOperationRegionObject);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Stop the device
|
|||
|
//
|
|||
|
|
|||
|
SmbData->Class.CurrentIrp = Irp;
|
|||
|
|
|||
|
Status = SmbData->Class.StopDevice (
|
|||
|
&SmbData->Class,
|
|||
|
SmbData->Class.Miniport
|
|||
|
);
|
|||
|
|
|||
|
SmbData->Class.CurrentIrp = NULL;
|
|||
|
|
|||
|
return Status;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
SmbCSynchronousRequest (
|
|||
|
IN PDEVICE_OBJECT DeviceObject,
|
|||
|
IN PIRP Irp,
|
|||
|
IN PKEVENT IoCompletionEvent
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Completion function for synchronous IRPs sent to this driver.
|
|||
|
No event.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
KeSetEvent(IoCompletionEvent, IO_NO_INCREMENT, FALSE);
|
|||
|
|
|||
|
return STATUS_MORE_PROCESSING_REQUIRED;
|
|||
|
}
|