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;
|
||
}
|