#include "precomp.h" // Precompiled header /************************************************************************/ /* */ /* Title : Specialix Generic Dispatch Functions. */ /* */ /* Author : N.P.Vassallo */ /* */ /* Creation : 29th September 1998 */ /* */ /* Version : 1.0.0 */ /* */ /* Description : Dispatch entry points are routed here */ /* for PnP/Power filtering before being */ /* passed to the main functions: */ /* Spx_Flush */ /* Spx_Write */ /* Spx_Read */ /* Spx_IoControl */ /* Spx_InternalIoControl */ /* Spx_CreateOpen */ /* Spx_Close */ /* Spx_Cleanup */ /* Spx_QueryInformationFile */ /* Spx_SetInformationFile */ /* */ /* Spx_UnstallIRPs */ /* Spx_KillStalledIRPs */ /* */ /************************************************************************/ /* History... 1.0.0 29/09/98 NPV Creation. */ #define FILE_ID SPX_DISP_C // File ID for Event Logging see SPX_DEFS.H for values. /***************************************************************************** ******************************* ******************************* ******************************* Prototypes ******************************* ******************************* ******************************* *****************************************************************************/ NTSTATUS Spx_FilterIRPs(IN PDEVICE_OBJECT pDevObject,IN PIRP pIrp); VOID Spx_FilterCancelQueued(IN PDEVICE_OBJECT pDevObj,IN PIRP pIrp); /***************************************************************************** ******************************** Spx_Flush ******************************* *****************************************************************************/ NTSTATUS Spx_Flush(IN PDEVICE_OBJECT pDevObject,IN PIRP pIrp) { NTSTATUS status; if(!SPX_SUCCESS(status = Spx_FilterIRPs(pDevObject,pIrp))) { pIrp->IoStatus.Status = status; if(status != STATUS_PENDING) IoCompleteRequest(pIrp, IO_NO_INCREMENT); if((status == STATUS_PENDING) || (status == STATUS_CANCELLED)) ClearUnstallingFlag(pDevObject->DeviceExtension); } else status = SerialFlush(pDevObject,pIrp); return(status); } // End Spx_Flush /***************************************************************************** ******************************** Spx_Write ******************************* *****************************************************************************/ NTSTATUS Spx_Write(IN PDEVICE_OBJECT pDevObject,IN PIRP pIrp) { PPORT_DEVICE_EXTENSION pPort = pDevObject->DeviceExtension; NTSTATUS status; if(!SPX_SUCCESS(status = Spx_FilterIRPs(pDevObject,pIrp))) { pIrp->IoStatus.Status = status; if(status != STATUS_PENDING) IoCompleteRequest(pIrp, IO_NO_INCREMENT); if((status == STATUS_PENDING) || (status == STATUS_CANCELLED)) ClearUnstallingFlag(pDevObject->DeviceExtension); } else status = SerialWrite(pDevObject,pIrp); return(status); } // End Spx_Write /***************************************************************************** ******************************** Spx_Read ******************************** *****************************************************************************/ NTSTATUS Spx_Read(IN PDEVICE_OBJECT pDevObject,IN PIRP pIrp) { NTSTATUS status; if(!SPX_SUCCESS(status = Spx_FilterIRPs(pDevObject,pIrp))) { pIrp->IoStatus.Status = status; if(status != STATUS_PENDING) IoCompleteRequest(pIrp, IO_NO_INCREMENT); if((status == STATUS_PENDING) || (status == STATUS_CANCELLED)) ClearUnstallingFlag(pDevObject->DeviceExtension); } else status = SerialRead(pDevObject,pIrp); return(status); } // End Spx_Read /***************************************************************************** ****************************** Spx_IoControl ***************************** *****************************************************************************/ NTSTATUS Spx_IoControl(IN PDEVICE_OBJECT pDevObject,IN PIRP pIrp) { NTSTATUS status; if(!SPX_SUCCESS(status = Spx_FilterIRPs(pDevObject,pIrp))) { pIrp->IoStatus.Status = status; if(status != STATUS_PENDING) IoCompleteRequest(pIrp, IO_NO_INCREMENT); if((status == STATUS_PENDING) || (status == STATUS_CANCELLED)) ClearUnstallingFlag(pDevObject->DeviceExtension); } else status = SerialIoControl(pDevObject,pIrp); return(status); } // End Spx_IoControl /***************************************************************************** ************************** Spx_InternalIoControl ************************* *****************************************************************************/ NTSTATUS Spx_InternalIoControl(IN PDEVICE_OBJECT pDevObject,IN PIRP pIrp) { NTSTATUS status; if(!SPX_SUCCESS(status = Spx_FilterIRPs(pDevObject,pIrp))) { pIrp->IoStatus.Status = status; if(status != STATUS_PENDING) IoCompleteRequest(pIrp, IO_NO_INCREMENT); if((status == STATUS_PENDING) || (status == STATUS_CANCELLED)) ClearUnstallingFlag(pDevObject->DeviceExtension); } else status = Spx_SerialInternalIoControl(pDevObject,pIrp); return(status); } // Spx_InternalIoControl /***************************************************************************** ***************************** Spx_CreateOpen ***************************** *****************************************************************************/ NTSTATUS Spx_CreateOpen(IN PDEVICE_OBJECT pDevObject,IN PIRP pIrp) { PPORT_DEVICE_EXTENSION pPort = pDevObject->DeviceExtension; NTSTATUS status; if(pDevObject->DeviceType != FILE_DEVICE_SERIAL_PORT) { pIrp->IoStatus.Status = STATUS_ACCESS_DENIED; pIrp->IoStatus.Information = 0; IoCompleteRequest(pIrp, IO_NO_INCREMENT); return(STATUS_ACCESS_DENIED); } // Lock out state Query stop and Query remove IRPs from changing the state // of the port part way through openening the port. ExAcquireFastMutex(&pPort->OpenMutex); if(!SPX_SUCCESS(status = Spx_FilterIRPs(pDevObject,pIrp))) { pIrp->IoStatus.Status = status; if(status != STATUS_PENDING) IoCompleteRequest(pIrp, IO_NO_INCREMENT); if((status == STATUS_PENDING) || (status == STATUS_CANCELLED)) ClearUnstallingFlag(pDevObject->DeviceExtension); } else { if(pPort->DeviceIsOpen) // Is port already open? { status = STATUS_ACCESS_DENIED; // Yes, deny access pIrp->IoStatus.Status = status; IoCompleteRequest(pIrp,IO_NO_INCREMENT); } else status = SerialCreateOpen(pDevObject,pIrp); } ExReleaseFastMutex(&pPort->OpenMutex); return(status); } // End Spx_CreateOpen /***************************************************************************** ******************************** Spx_Close ******************************* *****************************************************************************/ NTSTATUS Spx_Close(IN PDEVICE_OBJECT pDevObject,IN PIRP pIrp) { PPORT_DEVICE_EXTENSION pPort = pDevObject->DeviceExtension; NTSTATUS status; if(!SPX_SUCCESS(status = Spx_FilterIRPs(pDevObject,pIrp))) { if(status == STATUS_DELETE_PENDING) // Successful close if device is removed { pPort->BufferSize = 0; SpxFreeMem(pPort->InterruptReadBuffer); pPort->InterruptReadBuffer = NULL; status = STATUS_SUCCESS; } pIrp->IoStatus.Status = status; if(status != STATUS_PENDING) IoCompleteRequest(pIrp, IO_NO_INCREMENT); if((status == STATUS_PENDING) || (status == STATUS_CANCELLED)) ClearUnstallingFlag(pDevObject->DeviceExtension); } else status = SerialClose(pDevObject,pIrp); return(status); } // End Spx_Close /***************************************************************************** ******************************* Spx_Cleanup ****************************** *****************************************************************************/ NTSTATUS Spx_Cleanup(IN PDEVICE_OBJECT pDevObject,IN PIRP pIrp) { NTSTATUS status; if(!SPX_SUCCESS(status = Spx_FilterIRPs(pDevObject,pIrp))) { if(status == STATUS_DELETE_PENDING) { status = STATUS_SUCCESS; } pIrp->IoStatus.Status = status; if(status != STATUS_PENDING) IoCompleteRequest(pIrp, IO_NO_INCREMENT); if((status == STATUS_PENDING) || (status == STATUS_CANCELLED)) ClearUnstallingFlag(pDevObject->DeviceExtension); } else { Spx_KillStalledIRPs(pDevObject); status = SerialCleanup(pDevObject,pIrp); } return(status); } // End Spx_Cleanup /***************************************************************************** ************************ Spx_QueryInformationFile ************************ *****************************************************************************/ NTSTATUS Spx_QueryInformationFile(IN PDEVICE_OBJECT pDevObject,IN PIRP pIrp) { NTSTATUS status; if(!SPX_SUCCESS(status = Spx_FilterIRPs(pDevObject,pIrp))) { pIrp->IoStatus.Status = status; if(status != STATUS_PENDING) IoCompleteRequest(pIrp, IO_NO_INCREMENT); if((status == STATUS_PENDING) || (status == STATUS_CANCELLED)) ClearUnstallingFlag(pDevObject->DeviceExtension); } else status = SerialQueryInformationFile(pDevObject,pIrp); return(status); } // End Spx_QueryInformationFile /***************************************************************************** ************************* Spx_SetInformationFile ************************* *****************************************************************************/ NTSTATUS Spx_SetInformationFile(IN PDEVICE_OBJECT pDevObject,IN PIRP pIrp) { NTSTATUS status; if(!SPX_SUCCESS(status = Spx_FilterIRPs(pDevObject,pIrp))) { pIrp->IoStatus.Status = status; if(status != STATUS_PENDING) IoCompleteRequest(pIrp, IO_NO_INCREMENT); if((status == STATUS_PENDING) || (status == STATUS_CANCELLED)) ClearUnstallingFlag(pDevObject->DeviceExtension); } else status = SerialSetInformationFile(pDevObject,pIrp); return(status); } // End Spx_SetInformationFile /***************************************************************************** ***************************** ***************************** ***************************** Spx_FilterIRPs ***************************** ***************************** ***************************** ****************************************************************************** prototype: NTSTATUS Spx_FilterIRPs(IN PDEVICE_OBJECT pDevObject,IN PIRP pIrp) description: Filter incoming SERIAL IRPs (except PNP and POWER) to check the current PNP/POWER states and return an NT status code to just complete the IRP if device is blocked for the following reasons: parameters: pDevObject points to the device object for this IRP pIrp points to the IRP to filter returns: NT Status Code */ NTSTATUS Spx_FilterIRPs(IN PDEVICE_OBJECT pDevObject,IN PIRP pIrp) { PPORT_DEVICE_EXTENSION pPort = pDevObject->DeviceExtension; PIO_STACK_LOCATION pIrpStack = IoGetCurrentIrpStackLocation(pIrp); KIRQL oldIrqlFlags; KIRQL StalledOldIrql; LARGE_INTEGER delay; if(pIrpStack->MajorFunction == IRP_MJ_PNP) // Don't filter Plug and Play IRPs return(STATUS_SUCCESS); if(pIrpStack->MajorFunction == IRP_MJ_POWER) // Don't filter Plug and Play IRPs return(STATUS_SUCCESS); if(pIrpStack->MajorFunction == IRP_MJ_SYSTEM_CONTROL) // Don't filter WMI IRPs return(STATUS_SUCCESS); if(pPort->IsFDO) // Don't filter card IRPs return(STATUS_SUCCESS); if(pIrpStack->MajorFunction != IRP_MJ_PNP) { SpxDbgMsg(SPX_TRACE_FILTER_IRPS,("%s[card=%d,port=%d]: Spx_FilterIRPs for Major %02X, Minor %02X\n", PRODUCT_NAME,pPort->pParentCardExt->CardNumber,pPort->PortNumber,pIrpStack->MajorFunction,pIrpStack->MinorFunction)); } KeAcquireSpinLock(&pPort->PnpPowerFlagsLock, &oldIrqlFlags); if(pPort->PnpPowerFlags & PPF_REMOVED) // Has this object been "removed"? { KeReleaseSpinLock(&pPort->PnpPowerFlagsLock,oldIrqlFlags); SpxDbgMsg(SPX_TRACE_FILTER_IRPS,("%s[card=%d,port=%d]: Spx_FilterIRPs for Major %02X, Minor %02X STATUS_SUCCESS\n", PRODUCT_NAME,pPort->pParentCardExt->CardNumber,pPort->PortNumber,pIrpStack->MajorFunction,pIrpStack->MinorFunction)); return(STATUS_NO_SUCH_DEVICE); } if(pPort->PnpPowerFlags & PPF_REMOVE_PENDING) // Removing the device? { KeReleaseSpinLock(&pPort->PnpPowerFlagsLock,oldIrqlFlags); SpxDbgMsg(SPX_TRACE_FILTER_IRPS,("%s[card=%d,port=%d]: Spx_FilterIRPs for Major %02X, Minor %02X STATUS_DELETE_PENDING\n", PRODUCT_NAME,pPort->pParentCardExt->CardNumber,pPort->PortNumber,pIrpStack->MajorFunction,pIrpStack->MinorFunction)); return(STATUS_DELETE_PENDING); } if((pPort->PnpPowerFlags & PPF_STOP_PENDING) // Device stopping? ||(!(pPort->PnpPowerFlags & PPF_POWERED)) // Device not powered? ||(!(pPort->PnpPowerFlags & PPF_STARTED))) // Device not started? { KIRQL oldIrql; KeReleaseSpinLock(&pPort->PnpPowerFlagsLock,oldIrqlFlags); KeAcquireSpinLock(&pPort->StalledIrpLock, &StalledOldIrql); while(pPort->UnstallingFlag) // We do not wish to add any more IRPs to the queue if have started unstalling those currently queued. { KeReleaseSpinLock(&pPort->StalledIrpLock, StalledOldIrql); delay = RtlLargeIntegerNegate(RtlConvertUlongToLargeInteger(1000000)); // 1mS KeDelayExecutionThread(KernelMode, FALSE, &delay); KeAcquireSpinLock(&pPort->StalledIrpLock, &StalledOldIrql); } pPort->UnstallingFlag = TRUE; KeReleaseSpinLock(&pPort->StalledIrpLock, StalledOldIrql); IoAcquireCancelSpinLock(&oldIrql); if(pIrp->Cancel) // Has IRP been cancelled? { // Yes IoReleaseCancelSpinLock(oldIrql); SpxDbgMsg(SPX_TRACE_FILTER_IRPS,("%s[card=%d,port=%d]: Spx_FilterIRPs for Major %02X, Minor %02X STATUS_CANCELLED\n", PRODUCT_NAME,pPort->pParentCardExt->CardNumber,pPort->PortNumber,pIrpStack->MajorFunction,pIrpStack->MinorFunction)); return(STATUS_CANCELLED); } // Mark the IRP as pending and queue on the stalled list... pIrp->IoStatus.Status = STATUS_PENDING; // Mark IRP as pending IoMarkIrpPending(pIrp); InsertTailList(&pPort->StalledIrpQueue,&pIrp->Tail.Overlay.ListEntry); IoSetCancelRoutine(pIrp,Spx_FilterCancelQueued); IoReleaseCancelSpinLock(oldIrql); SpxDbgMsg(SPX_TRACE_FILTER_IRPS,("%s[card=%d,port=%d]: Spx_FilterIRPs for Major %02X, Minor %02X STATUS_PENDING\n", PRODUCT_NAME,pPort->pParentCardExt->CardNumber,pPort->PortNumber,pIrpStack->MajorFunction,pIrpStack->MinorFunction)); return(STATUS_PENDING); } KeReleaseSpinLock(&pPort->PnpPowerFlagsLock,oldIrqlFlags); SpxDbgMsg(SPX_TRACE_FILTER_IRPS,("%s[card=%d,port=%d]: Spx_FilterIRPs for Major %02X, Minor %02X STATUS_SUCCESS\n", PRODUCT_NAME,pPort->pParentCardExt->CardNumber,pPort->PortNumber,pIrpStack->MajorFunction,pIrpStack->MinorFunction)); return(STATUS_SUCCESS); } // End Spx_FilterIRPs /***************************************************************************** ***************************** **************************** ***************************** Spx_UnstallIRPs **************************** ***************************** **************************** ****************************************************************************** prototype: VOID Spx_UnstallIrps(IN PPORT_DEVICE_EXTENSION pPort) description: Restart all IRPs stored on the temporary stalled list. parameters: pPort points to the device extension to unstall returns: None */ VOID Spx_UnstallIrps(IN PPORT_DEVICE_EXTENSION pPort) { PLIST_ENTRY pIrpLink; PIRP pIrp; PIO_STACK_LOCATION pIrpStack; PDEVICE_OBJECT pDevObj; PDRIVER_OBJECT pDrvObj; KIRQL oldIrql; KIRQL StalledOldIrql; LARGE_INTEGER delay; SpxDbgMsg(SPX_TRACE_FILTER_IRPS,("%s[card=%d,port=%d]: Spx_UnstallIRPs Entry\n", PRODUCT_NAME,pPort->pParentCardExt->CardNumber,pPort->PortNumber)); KeAcquireSpinLock(&pPort->StalledIrpLock, &StalledOldIrql); while(pPort->UnstallingFlag) // We do not unstall any queued IRPs if some one is just about to be added to the queue. { KeReleaseSpinLock(&pPort->StalledIrpLock, StalledOldIrql); delay = RtlLargeIntegerNegate(RtlConvertUlongToLargeInteger(1000000)); // 1mS KeDelayExecutionThread(KernelMode, FALSE, &delay); KeAcquireSpinLock(&pPort->StalledIrpLock, &StalledOldIrql); } pPort->UnstallingFlag = TRUE; KeReleaseSpinLock(&pPort->StalledIrpLock, StalledOldIrql); IoAcquireCancelSpinLock(&oldIrql); pIrpLink = pPort->StalledIrpQueue.Flink; // Restart each waiting IRP on the stalled list... while(pIrpLink != &pPort->StalledIrpQueue) { pIrp = CONTAINING_RECORD(pIrpLink,IRP,Tail.Overlay.ListEntry); pIrpLink = pIrp->Tail.Overlay.ListEntry.Flink; RemoveEntryList(&pIrp->Tail.Overlay.ListEntry); pIrpStack = IoGetCurrentIrpStackLocation(pIrp); pDevObj = pIrpStack->DeviceObject; pDrvObj = pDevObj->DriverObject; IoSetCancelRoutine(pIrp,NULL); IoReleaseCancelSpinLock(oldIrql); SpxDbgMsg(SPX_TRACE_FILTER_IRPS,("%s[card=%d,port=%d]: Unstalling IRP 0x%X, Major %02X, Minor %02X\n", PRODUCT_NAME,pPort->pParentCardExt->CardNumber,pPort->PortNumber, pIrp,pIrpStack->MajorFunction,pIrpStack->MinorFunction)); pDrvObj->MajorFunction[pIrpStack->MajorFunction](pDevObj,pIrp); IoAcquireCancelSpinLock(&oldIrql); } IoReleaseCancelSpinLock(oldIrql); ClearUnstallingFlag(pPort); SpxDbgMsg(SPX_TRACE_FILTER_IRPS,("%s[card=%d,port=%d]: Spx_UnstallIRPs Exit\n", PRODUCT_NAME,pPort->pParentCardExt->CardNumber,pPort->PortNumber)); } // End Spx_UnstallIRPs /***************************************************************************** ************************* ************************* ************************* Spx_FilterCancelQueued ************************* ************************* ************************* ****************************************************************************** prototype: VOID Spx_FilterCancelQueued(IN PDEVICE_OBJECT pDevObj,IN PIRP pIrp) description: Routine to cancel IRPs queued on the stalled list parameters: pDevObj the device object containing the queue pIrp points to the IRP to cancel returns: None */ VOID Spx_FilterCancelQueued(IN PDEVICE_OBJECT pDevObj,IN PIRP pIrp) { PPORT_DEVICE_EXTENSION pPort = pDevObj->DeviceExtension; PIO_STACK_LOCATION pIrpSp = IoGetCurrentIrpStackLocation(pIrp); pIrp->IoStatus.Status = STATUS_CANCELLED; pIrp->IoStatus.Information = 0; RemoveEntryList(&pIrp->Tail.Overlay.ListEntry); IoReleaseCancelSpinLock(pIrp->CancelIrql); } // End Spx_FilterCancelQueued /***************************************************************************** *************************** ************************** *************************** Spx_KillStalledIRPs ************************** *************************** ************************** ****************************************************************************** prototype: VOID Spx_KillStalledIRPs(IN PDEVICE_OBJECT pDevObj) description: Kill all IRPs queued on the stalled list parameters: pDevObj the device object containing the queue returns: None */ VOID Spx_KillStalledIRPs(IN PDEVICE_OBJECT pDevObj) { PPORT_DEVICE_EXTENSION pPort = pDevObj->DeviceExtension; PDRIVER_CANCEL cancelRoutine; KIRQL cancelIrql; IoAcquireCancelSpinLock(&cancelIrql); // Call the cancel routine of all IRPs queued on the stalled list... while(!IsListEmpty(&pPort->StalledIrpQueue)) { PIRP pIrp = CONTAINING_RECORD(pPort->StalledIrpQueue.Blink, IRP, Tail.Overlay.ListEntry); RemoveEntryList(pPort->StalledIrpQueue.Blink); cancelRoutine = pIrp->CancelRoutine; // Get the cancel routine for this IRP pIrp->CancelIrql = cancelIrql; pIrp->CancelRoutine = NULL; pIrp->Cancel = TRUE; cancelRoutine(pDevObj,pIrp); // Call the cancel routine IoAcquireCancelSpinLock(&cancelIrql); } IoReleaseCancelSpinLock(cancelIrql); } // End Spx_KillStalledIRPs // End of SPX_DISP.C