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.
482 lines
16 KiB
482 lines
16 KiB
/*++
|
|
|
|
Copyright (c) 2000 Microsoft Corporation All Rights Reserved
|
|
|
|
Module Name:
|
|
|
|
lower.c
|
|
|
|
Abstract:
|
|
|
|
This module contains the lower filter specific IRP handlers.
|
|
|
|
The functions in this module all have the same prototypes and so
|
|
are documented here:
|
|
|
|
NTSTATUS
|
|
HpsXxxLower(
|
|
IN PIRP Irp,
|
|
IN PHPS_DEVICE_EXTENSION Extension,
|
|
IN PIO_STACK_LOCATION IrpStack
|
|
)
|
|
|
|
Arguments:
|
|
|
|
Irp - a pointer to the IRP currently being handled
|
|
Extension - a pointer to the device extension of this device. In
|
|
some functions this is of type PHPS_COMMON_EXTENSION if this
|
|
reduced extension is all that is required.
|
|
IrpStack - the current IRP stack location
|
|
|
|
Return Value:
|
|
|
|
an NT status code
|
|
|
|
Environment:
|
|
|
|
Kernel Mode
|
|
|
|
Revision History:
|
|
|
|
Davis Walker (dwalker) Oct 1 2000
|
|
|
|
--*/
|
|
|
|
#include "hpsp.h"
|
|
|
|
NTSTATUS
|
|
HpsStartLower(
|
|
IN PIRP Irp,
|
|
IN PHPS_DEVICE_EXTENSION Extension,
|
|
IN PIO_STACK_LOCATION IrpStack
|
|
)
|
|
{
|
|
NTSTATUS status;
|
|
|
|
status = HpsDeferProcessing((PHPS_COMMON_EXTENSION)Extension,
|
|
Irp
|
|
);
|
|
if (!NT_SUCCESS(status)) {
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
}
|
|
|
|
status = IoSetDeviceInterfaceState(Extension->SymbolicName,
|
|
TRUE // enable
|
|
);
|
|
|
|
Irp->IoStatus.Status = status;
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
NTSTATUS
|
|
HpsRemoveLower(
|
|
IN PIRP Irp,
|
|
IN PHPS_DEVICE_EXTENSION Extension,
|
|
IN PIO_STACK_LOCATION IrpStack
|
|
)
|
|
{
|
|
ULONG i;
|
|
|
|
IoSetDeviceInterfaceState(Extension->SymbolicName,
|
|
FALSE
|
|
);
|
|
IoWMIRegistrationControl(Extension->Self,
|
|
WMIREG_ACTION_DEREGISTER
|
|
);
|
|
|
|
if (Extension->SoftDevices) {
|
|
for (i=0; i<Extension->HwInitData.NumSlots;i++) {
|
|
if (Extension->SoftDevices[i]) {
|
|
ExFreePool(Extension->SoftDevices[i]);
|
|
}
|
|
}
|
|
ExFreePool(Extension->SoftDevices);
|
|
}
|
|
|
|
if (Extension->SymbolicName) {
|
|
ExFreePool(Extension->SymbolicName);
|
|
}
|
|
|
|
if (Extension->WmiEventContext) {
|
|
|
|
ExFreePool(Extension->WmiEventContext);
|
|
}
|
|
|
|
return HpsRemoveCommon(Irp,
|
|
(PHPS_COMMON_EXTENSION)Extension,
|
|
IrpStack
|
|
);
|
|
|
|
}
|
|
|
|
NTSTATUS
|
|
HpsStopLower(
|
|
IN PIRP Irp,
|
|
IN PHPS_DEVICE_EXTENSION Extension,
|
|
IN PIO_STACK_LOCATION IrpStack
|
|
)
|
|
{
|
|
IoSetDeviceInterfaceState(Extension->SymbolicName,
|
|
FALSE
|
|
);
|
|
|
|
return HpsPassIrp(Irp,
|
|
(PHPS_COMMON_EXTENSION)Extension,
|
|
IrpStack
|
|
);
|
|
}
|
|
|
|
NTSTATUS
|
|
HpsQueryInterfaceLower(
|
|
IN PIRP Irp,
|
|
IN PHPS_DEVICE_EXTENSION Extension,
|
|
IN PIO_STACK_LOCATION IrpStack
|
|
)
|
|
{
|
|
|
|
NTSTATUS status = STATUS_NOT_SUPPORTED;
|
|
PHPS_REGISTER_INTERRUPT_INTERFACE interruptInterface;
|
|
PHPS_MEMORY_INTERFACE memInterface;
|
|
PHPS_PING_INTERFACE pingInterface;
|
|
|
|
if (HPS_EQUAL_GUID(IrpStack->Parameters.QueryInterface.InterfaceType,
|
|
&GUID_BUS_INTERFACE_STANDARD
|
|
)) {
|
|
|
|
if (Extension->UseConfig) {
|
|
//
|
|
// Someone is requesting a bus interface standard. We need to capture
|
|
// this request and fill it in with our own.
|
|
//
|
|
DbgPrintEx(DPFLTR_HPS_ID,
|
|
DPFLTR_INFO_LEVEL,
|
|
"HPS-IRP QueryInterface for Bus Interface\n"
|
|
);
|
|
if (IrpStack->Parameters.QueryInterface.Size <
|
|
sizeof(BUS_INTERFACE_STANDARD)) {
|
|
|
|
status = STATUS_NOT_SUPPORTED;
|
|
|
|
} else {
|
|
//
|
|
// This is a query for access to config space, which we need to trap
|
|
// after PCI has filled it in.
|
|
//
|
|
status = HpsDeferProcessing((PHPS_COMMON_EXTENSION)Extension,
|
|
Irp
|
|
);
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
|
|
// PDO filled in the interface, so we can trap and modify it.
|
|
|
|
status = HpsTrapBusInterface(Extension,
|
|
IrpStack
|
|
);
|
|
|
|
//
|
|
// the status of the trap operation is the status of the IRP.
|
|
// complete the IRP with whatever status that happens to be.
|
|
//
|
|
Irp->IoStatus.Status = status;
|
|
}
|
|
|
|
//
|
|
// Complete the deferred IRP
|
|
//
|
|
IoCompleteRequest(Irp,IO_NO_INCREMENT);
|
|
return status;
|
|
}
|
|
}
|
|
|
|
} else if (HPS_EQUAL_GUID(IrpStack->Parameters.QueryInterface.InterfaceType,
|
|
&GUID_HPS_MEMORY_INTERFACE
|
|
)) {
|
|
if (IrpStack->Parameters.QueryInterface.Size <
|
|
sizeof(HPS_MEMORY_INTERFACE)) {
|
|
|
|
status = STATUS_NOT_SUPPORTED;
|
|
|
|
} else {
|
|
memInterface = (PHPS_MEMORY_INTERFACE)
|
|
IrpStack->Parameters.QueryInterface.Interface;
|
|
|
|
memInterface->Context = Extension;
|
|
memInterface->InterfaceReference = HpsMemoryInterfaceReference;
|
|
memInterface->InterfaceDereference = HpsMemoryInterfaceDereference;
|
|
memInterface->ReadRegister = HpsReadRegister;
|
|
memInterface->WriteRegister = HpsWriteRegister;
|
|
|
|
memInterface->InterfaceReference(memInterface->Context);
|
|
|
|
status = STATUS_SUCCESS;
|
|
}
|
|
|
|
} else if (HPS_EQUAL_GUID(IrpStack->Parameters.QueryInterface.InterfaceType,
|
|
&GUID_HPS_PING_INTERFACE
|
|
)) {
|
|
|
|
DbgPrintEx(DPFLTR_HPS_ID,
|
|
DPFLTR_INFO_LEVEL,
|
|
"HPS-IRP QueryInterface for Ping Interface\n"
|
|
);
|
|
if (IrpStack->Parameters.QueryInterface.Size <
|
|
sizeof(HPS_PING_INTERFACE)) {
|
|
|
|
status = STATUS_NOT_SUPPORTED;
|
|
|
|
} else {
|
|
//
|
|
// The upper filter is querying to see if there is another
|
|
// instance of the driver below it. Inform it that there is.
|
|
//
|
|
pingInterface = (PHPS_PING_INTERFACE)
|
|
IrpStack->Parameters.QueryInterface.Interface;
|
|
if (pingInterface->SenderDevice != Extension->Self) {
|
|
pingInterface->Context = Extension->Self;
|
|
pingInterface->InterfaceReference = HpsGenericInterfaceReference;
|
|
pingInterface->InterfaceDereference = HpsGenericInterfaceDereference;
|
|
}
|
|
|
|
pingInterface->InterfaceReference(pingInterface->Context);
|
|
|
|
status = STATUS_SUCCESS;
|
|
}
|
|
|
|
} else if (HPS_EQUAL_GUID(IrpStack->Parameters.QueryInterface.InterfaceType,
|
|
&GUID_REGISTER_INTERRUPT_INTERFACE
|
|
)) {
|
|
|
|
DbgPrintEx(DPFLTR_HPS_ID,
|
|
DPFLTR_INFO_LEVEL,
|
|
"HPS-IRP QueryInterface for Interrupt Interface\n"
|
|
);
|
|
if (IrpStack->Parameters.QueryInterface.Size <
|
|
sizeof(HPS_REGISTER_INTERRUPT_INTERFACE)) {
|
|
|
|
status = STATUS_NOT_SUPPORTED;
|
|
|
|
} else {
|
|
//
|
|
// The hotplug driver is querying for an interface that allows it
|
|
// to register a fake interrupt. Provide the interface.
|
|
//
|
|
interruptInterface = (PHPS_REGISTER_INTERRUPT_INTERFACE)
|
|
IrpStack->Parameters.QueryInterface.Interface;
|
|
interruptInterface->InterfaceReference = HpsGenericInterfaceReference;
|
|
interruptInterface->InterfaceDereference = HpsGenericInterfaceDereference;
|
|
interruptInterface->ConnectISR = HpsConnectInterrupt;
|
|
interruptInterface->DisconnectISR = HpsDisconnectInterrupt;
|
|
interruptInterface->SyncExecutionRoutine = HpsSynchronizeExecution;
|
|
interruptInterface->Context = Extension;
|
|
|
|
status = STATUS_SUCCESS;
|
|
}
|
|
|
|
}
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
|
|
Irp->IoStatus.Status = status;
|
|
}
|
|
|
|
IoSkipCurrentIrpStackLocation(Irp);
|
|
|
|
return IoCallDriver(Extension->LowerDO,
|
|
Irp
|
|
);
|
|
}
|
|
|
|
NTSTATUS
|
|
HpsWriteConfigLower(
|
|
IN PIRP Irp,
|
|
IN PHPS_DEVICE_EXTENSION Extension,
|
|
IN PIO_STACK_LOCATION IrpStack
|
|
)
|
|
{
|
|
if (Extension->UseConfig) {
|
|
DbgPrintEx(DPFLTR_HPS_ID,
|
|
DPFLTR_INFO_LEVEL,
|
|
"HPS-IRP Write Config at offset %d for length %d\n",
|
|
IrpStack->Parameters.ReadWriteConfig.Offset,
|
|
IrpStack->Parameters.ReadWriteConfig.Length
|
|
);
|
|
if (IS_SUBSET(IrpStack->Parameters.ReadWriteConfig.Offset,
|
|
IrpStack->Parameters.ReadWriteConfig.Length,
|
|
Extension->ConfigOffset,
|
|
sizeof(SHPC_CONFIG_SPACE)
|
|
)) {
|
|
|
|
//
|
|
// Handle the IRP internally. The request lines up with the config space
|
|
// offset of the SHPC capability.
|
|
//
|
|
HpsWriteConfig (Extension,
|
|
IrpStack->Parameters.ReadWriteConfig.Buffer,
|
|
IrpStack->Parameters.ReadWriteConfig.Offset,
|
|
IrpStack->Parameters.ReadWriteConfig.Length
|
|
);
|
|
|
|
//
|
|
// Since the write may have altered the register set, we have to recopy the
|
|
// result into the buffer before passing the IRP to Soft PCI
|
|
//
|
|
RtlCopyMemory(IrpStack->Parameters.ReadWriteConfig.Buffer,
|
|
(PUCHAR)&Extension->ConfigSpace + IrpStack->Parameters.ReadWriteConfig.Offset,
|
|
IrpStack->Parameters.ReadWriteConfig.Length
|
|
);
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// We've handled the IRP internally, but we want to keep SoftPCI in the loop,
|
|
// so pass it down.
|
|
//
|
|
IoSkipCurrentIrpStackLocation(Irp);
|
|
return IoCallDriver (Extension->LowerDO,
|
|
Irp
|
|
);
|
|
}
|
|
|
|
NTSTATUS
|
|
HpsDeviceControlLower(
|
|
PIRP Irp,
|
|
PHPS_DEVICE_EXTENSION Extension,
|
|
PIO_STACK_LOCATION IrpStack
|
|
)
|
|
{
|
|
NTSTATUS status;
|
|
PHPTEST_WRITE_CONFIG writeDescriptor;
|
|
PHPTEST_BRIDGE_INFO bridgeInfo;
|
|
|
|
switch (IrpStack->Parameters.DeviceIoControl.IoControlCode) {
|
|
|
|
case IOCTL_HPS_READ_REGISTERS:
|
|
//
|
|
// Usermode wants a copy of the register set. This is a test
|
|
// IOCTL
|
|
//
|
|
|
|
DbgPrintEx(DPFLTR_HPS_ID,
|
|
DPFLTR_INFO_LEVEL,
|
|
"HPS-Device Control IOCTL_HPS_READ_REGISTERS\n"
|
|
);
|
|
if (!Irp->AssociatedIrp.SystemBuffer ||
|
|
(IrpStack->Parameters.DeviceIoControl.OutputBufferLength <
|
|
sizeof(SHPC_WORKING_REGISTERS))) {
|
|
|
|
//
|
|
// We didn't get the buffer we expected. Fail.
|
|
//
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer,
|
|
&Extension->RegisterSet,
|
|
sizeof(SHPC_WORKING_REGISTERS)
|
|
);
|
|
Irp->IoStatus.Information = sizeof(SHPC_WORKING_REGISTERS);
|
|
status = STATUS_SUCCESS;
|
|
break;
|
|
|
|
case IOCTL_HPS_READ_CAPABILITY:
|
|
//
|
|
// Usermode wants a copy of the SHPC capability structure. This
|
|
// is a test IOCTL
|
|
//
|
|
|
|
DbgPrintEx(DPFLTR_HPS_ID,
|
|
DPFLTR_INFO_LEVEL,
|
|
"HPS-Device Control IOCTL_HPS_READ_CAPABILITY\n"
|
|
);
|
|
if (!Irp->AssociatedIrp.SystemBuffer ||
|
|
(IrpStack->Parameters.DeviceIoControl.OutputBufferLength <
|
|
sizeof(SHPC_CONFIG_SPACE))) {
|
|
|
|
//
|
|
// We didn't get the buffer we expected. Fail.
|
|
//
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
HpsHandleDirectReadConfig(Extension,
|
|
PCI_WHICHSPACE_CONFIG,
|
|
Irp->AssociatedIrp.SystemBuffer,
|
|
Extension->ConfigOffset,
|
|
sizeof(SHPC_CONFIG_SPACE)
|
|
);
|
|
Irp->IoStatus.Information = sizeof(SHPC_CONFIG_SPACE);
|
|
status = STATUS_SUCCESS;
|
|
break;
|
|
|
|
case IOCTL_HPS_WRITE_CAPABILITY:
|
|
//
|
|
// Usermode is overwriting the SHPC capability structure. This
|
|
// is a test IOCTL.
|
|
//
|
|
|
|
DbgPrintEx(DPFLTR_HPS_ID,
|
|
DPFLTR_INFO_LEVEL,
|
|
"HPS-Device Control IOCTL_HPS_WRITE_CAPABILITY\n"
|
|
);
|
|
if (!Irp->AssociatedIrp.SystemBuffer ||
|
|
(IrpStack->Parameters.DeviceIoControl.InputBufferLength <
|
|
sizeof(HPTEST_WRITE_CONFIG))) {
|
|
|
|
//
|
|
// We didn't get the buffer we expected. Fail.
|
|
//
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
writeDescriptor = (PHPTEST_WRITE_CONFIG)Irp->AssociatedIrp.SystemBuffer;
|
|
HpsHandleDirectWriteConfig(Extension,
|
|
PCI_WHICHSPACE_CONFIG,
|
|
(PUCHAR)&writeDescriptor->Buffer + writeDescriptor->Offset,
|
|
Extension->ConfigOffset+writeDescriptor->Offset,
|
|
writeDescriptor->Length
|
|
);
|
|
status = STATUS_SUCCESS;
|
|
break;
|
|
|
|
case IOCTL_HPS_BRIDGE_INFO:
|
|
//
|
|
// Usermode is requesting the bus/dev/func for this device for
|
|
// identification purposes. This is a test IOCTL.
|
|
//
|
|
|
|
DbgPrintEx(DPFLTR_HPS_ID,
|
|
DPFLTR_INFO_LEVEL,
|
|
"HPS-Device Control IOCTL_HPS_BRIDGE_INFO\n"
|
|
);
|
|
if (!Irp->AssociatedIrp.SystemBuffer ||
|
|
(IrpStack->Parameters.DeviceIoControl.OutputBufferLength <
|
|
sizeof(HPTEST_BRIDGE_INFO))) {
|
|
|
|
//
|
|
// We didn't get the buffer we expected. Fail.
|
|
//
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
bridgeInfo = (PHPTEST_BRIDGE_INFO)Irp->AssociatedIrp.SystemBuffer;
|
|
HpsGetBridgeInfo(Extension,
|
|
bridgeInfo
|
|
);
|
|
Irp->IoStatus.Information = sizeof(HPTEST_BRIDGE_INFO);
|
|
status = STATUS_SUCCESS;
|
|
break;
|
|
|
|
default:
|
|
|
|
status = STATUS_NOT_SUPPORTED;
|
|
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|