⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 util.c

📁 win2k kernel 的并口驱动程序模板
💻 C
📖 第 1 页 / 共 3 页
字号:

/*++
      
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 + -