/*++ 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; iHwInitData.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; }