📄 util.c
字号:
/*++
Routine Description:
This routine is called on when the given IRP is cancelled. It
will dequeue this IRP off the work queue and complete the
request as CANCELLED. If it can't get if off the queue then
this routine will ignore the CANCEL request since the IRP
is about to complete anyway.
Arguments:
DeviceObject - Supplies the device object.
Irp - Supplies the IRP.
Return Value:
None.
--*/
{
PDEVICE_EXTENSION Extension;
SYNCHRONIZED_COUNT_CONTEXT SyncContext;
PptDump2(PARCANCEL, ("CANCEL IRP %x\n", Irp) );
Extension = DeviceObject->DeviceExtension;
SyncContext.Count = &Extension->WorkQueueCount;
if (Extension->InterruptRefCount) {
KeSynchronizeExecution(Extension->InterruptObject,
PptSynchronizedDecrement,
&SyncContext);
} else {
PptSynchronizedDecrement(&SyncContext);
}
RemoveEntryList(&Irp->Tail.Overlay.ListEntry);
IoReleaseCancelSpinLock(Irp->CancelIrql);
Irp->IoStatus.Information = 0;
Irp->IoStatus.Status = STATUS_CANCELLED;
PptReleaseRemoveLock(&Extension->RemoveLock, Irp);
PptCompleteRequest(Irp, IO_NO_INCREMENT);
}
VOID
PptFreePortDpc(
IN PKDPC Dpc,
IN OUT PVOID Extension,
IN PVOID SystemArgument1,
IN PVOID SystemArgument2
)
/*++
Routine Description:
This routine is a DPC that will free the port and if necessary
complete an alloc request that is waiting.
Arguments:
Dpc - Not used.
Extension - Supplies the device extension.
SystemArgument1 - Not used.
SystemArgument2 - Not used.
Return Value:
None.
--*/
{
UNREFERENCED_PARAMETER( Dpc );
UNREFERENCED_PARAMETER( SystemArgument1 );
UNREFERENCED_PARAMETER( SystemArgument2 );
PptFreePort(Extension);
}
BOOLEAN
PptTryAllocatePortAtInterruptLevel(
IN PVOID Context
)
/*++
Routine Description:
This routine is called at interrupt level to quickly allocate
the parallel port if it is available. This call will fail
if the port is not available.
Arguments:
Context - Supplies the device extension.
Return Value:
FALSE - The port was not allocated.
TRUE - The port was successfully allocated.
--*/
{
if (((PDEVICE_EXTENSION) Context)->WorkQueueCount == -1) {
((PDEVICE_EXTENSION) Context)->WorkQueueCount = 0;
( (PDEVICE_EXTENSION)Context )->WmiPortAllocFreeCounts.PortAllocates++;
return(TRUE);
} else {
return(FALSE);
}
}
VOID
PptFreePortFromInterruptLevel(
IN PVOID Context
)
/*++
Routine Description:
This routine frees the port that was allocated at interrupt level.
Arguments:
Context - Supplies the device extension.
Return Value:
None.
--*/
{
// If no one is waiting for the port then this is simple operation,
// otherwise queue a DPC to free the port later on.
if (((PDEVICE_EXTENSION) Context)->WorkQueueCount == 0) {
((PDEVICE_EXTENSION) Context)->WorkQueueCount = -1;
} else {
KeInsertQueueDpc(&((PDEVICE_EXTENSION) Context)->FreePortDpc, NULL, NULL);
}
}
BOOLEAN
PptInterruptService(
IN PKINTERRUPT Interrupt,
IN PVOID Extension
)
/*++
Routine Description:
This routine services the interrupt for the parallel port.
This routine will call out to all of the interrupt routines
that connected with this device via
IOCTL_INTERNAL_PARALLEL_CONNECT_INTERRUPT in order until
one of them returns TRUE.
Arguments:
Interrupt - Supplies the interrupt object.
Extension - Supplies the device extension.
Return Value:
FALSE - The interrupt was not handled.
TRUE - The interrupt was handled.
--*/
{
PLIST_ENTRY Current;
PISR_LIST_ENTRY IsrListEntry;
PDEVICE_EXTENSION DeviceExtension;
DeviceExtension = Extension;
for (Current = DeviceExtension->IsrList.Flink;
Current != &DeviceExtension->IsrList;
Current = Current->Flink) {
IsrListEntry = CONTAINING_RECORD(Current, ISR_LIST_ENTRY, ListEntry);
if (IsrListEntry->ServiceRoutine(Interrupt, IsrListEntry->ServiceContext)) {
return(TRUE);
}
}
return(FALSE);
}
BOOLEAN
PptTryAllocatePort(
IN PVOID Extension
)
/*++
Routine Description:
This routine attempts to allocate the port. If the port is
available then the call will succeed with the port allocated.
If the port is not available the then call will fail
immediately.
Arguments:
Extension - Supplies the device extension.
Return Value:
FALSE - The port was not allocated.
TRUE - The port was allocated.
--*/
{
PDEVICE_EXTENSION DeviceExtension = Extension;
KIRQL CancelIrql;
BOOLEAN b;
if (DeviceExtension->InterruptRefCount) {
b = KeSynchronizeExecution(DeviceExtension->InterruptObject,
PptTryAllocatePortAtInterruptLevel,
DeviceExtension);
} else {
IoAcquireCancelSpinLock(&CancelIrql);
b = PptTryAllocatePortAtInterruptLevel(DeviceExtension);
IoReleaseCancelSpinLock(CancelIrql);
}
PptDump2(PARDUMP_PORT_ALLOC_FREE,
("PptTryAllocatePort %x Allocate Port returned %x.\n",
DeviceExtension->PortInfo.Controller, b) );
return b;
}
BOOLEAN
PptTraversePortCheckList(
IN PVOID Extension
)
/*++
Routine Description:
This routine traverses the deferred port check routines. This
call must be synchronized at interrupt level so that real
interrupts are blocked until these routines are completed.
Arguments:
Extension - Supplies the device extension.
Return Value:
FALSE - The port is in use so no action taken by this routine.
TRUE - All of the deferred interrupt routines were called.
--*/
{
PDEVICE_EXTENSION DeviceExtension = Extension;
PLIST_ENTRY Current;
PISR_LIST_ENTRY CheckEntry;
//
// First check to make sure that the port is still free.
//
if (DeviceExtension->WorkQueueCount >= 0) {
return FALSE;
}
for (Current = DeviceExtension->IsrList.Flink;
Current != &DeviceExtension->IsrList;
Current = Current->Flink) {
CheckEntry = CONTAINING_RECORD(Current,
ISR_LIST_ENTRY,
ListEntry);
if (CheckEntry->DeferredPortCheckRoutine) {
CheckEntry->DeferredPortCheckRoutine(CheckEntry->CheckContext);
}
}
return TRUE;
}
VOID
PptFreePort(
IN PVOID Extension
)
/*++
Routine Description:
This routine frees the port.
Arguments:
Extension - Supplies the device extension.
Return Value:
None.
--*/
{
PDEVICE_EXTENSION DeviceExtension = Extension;
SYNCHRONIZED_COUNT_CONTEXT SyncContext;
KIRQL CancelIrql;
PLIST_ENTRY Head;
PIRP Irp;
PIO_STACK_LOCATION IrpSp;
ULONG InterruptRefCount;
PPARALLEL_1284_COMMAND Command;
BOOLEAN Allocated;
PptDump2(PARDUMP_PORT_ALLOC_FREE,
("PptFreePort %x FREE Port\n", DeviceExtension->PortInfo.Controller) );
SyncContext.Count = &DeviceExtension->WorkQueueCount;
IoAcquireCancelSpinLock(&CancelIrql);
if (DeviceExtension->InterruptRefCount) {
KeSynchronizeExecution(DeviceExtension->InterruptObject,
PptSynchronizedDecrement,
&SyncContext);
} else {
PptSynchronizedDecrement(&SyncContext);
}
IoReleaseCancelSpinLock(CancelIrql);
//
// Log the free for WMI
//
DeviceExtension->WmiPortAllocFreeCounts.PortFrees++;
//
// Port is free, check for queued ALLOCATE and/or SELECT requests
//
Allocated = FALSE;
while ( !Allocated && SyncContext.NewCount >= 0 ) {
//
// We have ALLOCATE and/or SELECT requests queued,
// satisfy the first request
//
IoAcquireCancelSpinLock(&CancelIrql);
Head = RemoveHeadList(&DeviceExtension->WorkQueue);
Irp = CONTAINING_RECORD(Head, IRP, Tail.Overlay.ListEntry);
PptSetCancelRoutine(Irp, NULL);
if ( Irp->Cancel ) {
Irp->IoStatus.Status = STATUS_CANCELLED;
// Irp was cancelled so have to get next in line
SyncContext.Count = &DeviceExtension->WorkQueueCount;
if (DeviceExtension->InterruptRefCount) {
KeSynchronizeExecution(DeviceExtension->InterruptObject,
PptSynchronizedDecrement,
&SyncContext);
} else {
PptSynchronizedDecrement(&SyncContext);
}
IoReleaseCancelSpinLock(CancelIrql);
} else {
Allocated = TRUE;
IoReleaseCancelSpinLock(CancelIrql);
// Finding out what kind of IOCTL it was
IrpSp = IoGetCurrentIrpStackLocation(Irp);
// Check to see if we need to select a
if (IrpSp->Parameters.DeviceIoControl.IoControlCode == IOCTL_INTERNAL_SELECT_DEVICE ) {
// request at head of queue was a SELECT
// so call the select function with the device command saying we already have port
Command = (PPARALLEL_1284_COMMAND)Irp->AssociatedIrp.SystemBuffer;
Command->CommandFlags |= PAR_HAVE_PORT_KEEP_PORT;
// Call Function to try to select device
Irp->IoStatus.Status = PptTrySelectDevice( Extension, Command );
} else {
// request at head of queue was an ALLOCATE
Irp->IoStatus.Status = STATUS_SUCCESS;
}
//
// Note that another Allocate request has been granted for WMI
//
DeviceExtension->WmiPortAllocFreeCounts.PortAllocates++;
}
// Remove remove lock on Irp and Complete request whether the Irp
// was cancelled or we acquired the port
PptReleaseRemoveLock(&DeviceExtension->RemoveLock, Irp);
if ( Irp->IoStatus.Status != STATUS_CANCELLED ) {
// only increase if we got the port
PptCompleteRequest(Irp, IO_PARALLEL_INCREMENT);
} else {
PptCompleteRequest(Irp, IO_NO_INCREMENT);
}
}
if ( !Allocated ) {
//
// ALLOCATE/SELECT request queue was empty
//
IoAcquireCancelSpinLock(&CancelIrql);
InterruptRefCount = DeviceExtension->InterruptRefCount;
IoReleaseCancelSpinLock(CancelIrql);
if ( InterruptRefCount ) {
KeSynchronizeExecution(DeviceExtension->InterruptObject,
PptTraversePortCheckList,
DeviceExtension);
}
}
}
ULONG
PptQueryNumWaiters(
IN PVOID Extension
)
/*++
Routine Description:
This routine returns the number of irps queued waiting for
the parallel port.
Arguments:
Extension - Supplies the device extension.
Return Value:
The number of irps queued waiting for the port.
--*/
{
PDEVICE_EXTENSION DeviceExtension = Extension;
KIRQL CancelIrql;
SYNCHRONIZED_COUNT_CONTEXT SyncContext;
SyncContext.Count = &DeviceExtension->WorkQueueCount;
if (DeviceExtension->InterruptRefCount) {
KeSynchronizeExecution(DeviceExtension->InterruptObject,
PptSynchronizedRead,
&SyncContext);
} else {
IoAcquireCancelSpinLock(&CancelIrql);
PptSynchronizedRead(&SyncContext);
IoReleaseCancelSpinLock(CancelIrql);
}
return((SyncContext.NewCount >= 0) ? ((ULONG) SyncContext.NewCount) : 0);
}
PVOID
PptSetCancelRoutine(PIRP Irp, PDRIVER_CANCEL CancelRoutine)
{
// #pragma warning( push )
// 4054: 'type cast' : from function pointer to data pointer
// 4055: 'type cast' : from data pointer to function pointer
// 4152: nonstandard extension, function/data pointer conversion in expression
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -