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

429 lines
9.7 KiB
C
Raw Permalink 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:
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;
}