Leaked source code of windows server 2003
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.
 
 
 
 
 
 

632 lines
20 KiB

#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