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

📄 dpc.c

📁 ir 驱动程序源代码,make成功了,有兴趣的朋友可以看看
💻 C
📖 第 1 页 / 共 4 页
字号:
//
// Copyright (c) Microsoft Corporation. All rights reserved.
// Copyright 2005 OSR, Open Systems Resources, Inc. All rights Reserved.
// 
// Module Name:
// 
//     dpc.c
// 
// Abstract:
//
//     Contains routines for  DPC processing and RLC coding
// 
// Author:
//
// Revision History:
//      
#include "smscir.h"

#ifdef WPP_TRACING
#include "dpc.tmh"
#endif


//
// Forward declarations
//
VOID
SmscirEncodeAndEnqueueRLC(
    IN PSMSCIR_RLC_RECEIVER RLCReceiver,
    __in_bcount(DataLen) PCHAR Buffer,
    IN ULONG DataLen,
    IN BOOLEAN DataEnd
    );


NTSTATUS 
IrSetupCurrentReceive(
    IN PSMSCIR_RLC_RECEIVER RLCReceiver,
    IN WDFREQUEST ReceiveRequest
    );

NTSTATUS 
IrSetupCurrentPriorityReceive(
    IN PSMSCIR_RLC_RECEIVER PriorityRLCReceiver,
    IN WDFREQUEST PriorityReceiveRequest
    );

VOID
SmscIrEvtInterruptDpc(
    IN WDFINTERRUPT Interrupt,
    IN WDFOBJECT    Object
    ) {
/*++

Routine Description.

    The DpcForIsr. This routine's job is to take the 
    FIFO data that was enqueued in the ISR, RLC it,
    then attempt to complete any pending IR receive
    requests.

Arguments:

    Interrupt       - Our interrupt object

    MessageID       - For MSI interrupts. Not used.

--*/

    PSMSCIR_DATA         deviceData;
    UCHAR                rxBuffer[SMSCIR_MAX_LOCAL_BUFFER_SIZE];
    ULONG                numLoops = 0;
    BOOLEAN              dataEnd;
    ULONG                amountRxData;
    KIRQL                oldIrql;
    PSMSCIR_RLC_RECEIVER rlcReceiver;
    WDFREQUEST           successfulRequest;
    WDFREQUEST           failedRequest;
    NTSTATUS             failureStatus;
    ULONG                remainingRxBytes;
    ULONG                maxLoops;
    WDFREQUEST           txRequest = NULL;
    NTSTATUS             txRequestStatus = STATUS_SUCCESS;
    BOOLEAN              txInterrupt;

    UNREFERENCED_PARAMETER(Object);
    
    SmscIrTracePrint(
        TRACE_LEVEL_VERBOSE,
        SMSCDBG_RECEIVE_INFO,
        ("SmscIrEvtInterruptDpc: Entered"));

   
    deviceData = (PSMSCIR_DATA)GetIrData(WdfInterruptGetDevice(Interrupt));

    //
    // Get a pointer to the appropriate receiver
    //
    rlcReceiver = deviceData->InPriorityMode ? 
                    &deviceData->PriorityReceiver : &deviceData->Receiver;

    //
    // We have to get hold of the lock immediately because 
    //  we may be racing with other DPCs on other processors.
    //  If we don't hold the lock across the FIFO dequeue and 
    //  RLC encoding/enqueueing we could end up enqueueing 
    //  the RLC data out of order
    //
    KeAcquireSpinLock(&rlcReceiver->ListSpinLock, &oldIrql);

    //
    // Acquire the TX lock as we need to check if we're blasting
    //
    KeAcquireSpinLockAtDpcLevel(&deviceData->TxFifoDataLock);

    //
    // Loop some reasonable amount of times pulling FIFO data
    //  off of the FIFO queue and then RLC'ing it and putting
    //  it on the RLC queue. 
    //
    maxLoops = 2;

    do {

        numLoops++;


        //
        // The ISR enqueues the data, so we need to serialize against it.
        //  We'll also check for a TX interrupt while we have the 
        //  lock (we keep a shadow copy of the TX interrupt register)
        //
        WdfInterruptAcquireLock(deviceData->Interrupt);


        amountRxData = SmscIrDequeueFifoData(deviceData,
                                             (PUCHAR)&rxBuffer[0],
                                             sizeof(rxBuffer),
                                             &dataEnd);

        //
        // Because DPCs are not 1:1 with ISRs (multiple calls to
        //  WdfInterruptQueueDpcForIsr while the DPC is queued
        //  are no-ops). we need to watch for the case where 
        //  the last ISR fires, the DPC is already queued, and
        //  our loops here leave some number of remaining bytes
        //  on the FIFO queue**. Because we won't get another 
        //  DPC until the next ISR, we may leave some orphaned
        //  bytes here if we don't watch out for it. So, basically,
        //  we might make an extra loop to clean up some spare bytes
        //  sitting at the end of the queue. This may be unnecessary,
        //  we have know way of knowing if this DPC is going to
        //  fire again OR sitting on another proc, but better to be safe 
        //  than sorry.
        //
        // **Note that due to the numbers chosen (2 * FIFO_SIZE for
        //  the local buffer and 2 loops default) the odds of this
        //  happening are slim. The ISR would have to fire 5 times
        //  before the first DPC is satisfied (each ISR enqueues a 
        //  max of FIFO_SIZE bytes, this DPC can dequeue 4 * FIFO_SIZE 
        //  bytes per run). But, just cuz it isn't likely doesn't
        //  mean that it won't happen - with possibly hideous user
        //  experience results (imagine missing some bytes that 
        //  make up a data end, it will look like the user is 
        //  holding down the button even though they have let it go). 
        //
        remainingRxBytes = SmscIrFifoBytesRemaining(deviceData);

        if ((remainingRxBytes && 
             remainingRxBytes < SMSCIR_FIFO_SIZE)) {

            //
            // We won't go overboard here, just make one more pass. 
            //  The beauty is that if on the next loop we don't 
            //  capture all of the remaining data we know that 
            //  the ISR has fired and added more data to the FIFO, 
            //  in which case another DPC has been requested while our DPC
            //  is running and we'll be back in here again shortly...
            //
            maxLoops = 3;
        }

        //
        // Check for a TX interrupt in the shadow copy.
        //
        if (deviceData->TxIntId.Fifo) {

            //
            // Clear it in our copy.
            //
            deviceData->TxIntId.Fifo = FALSE;

            txInterrupt = TRUE;

        } else {

            txInterrupt = FALSE;

        }

        WdfInterruptReleaseLock(deviceData->Interrupt);


        //
        // Check for Tx processing to do  and skip if 
        //  we've already gotten a TX request
        //  to complete on a previous loop (if there's
        //  another request to be blasted we'll get it at 
        //  a later time)
        //
        if (txInterrupt && !txRequest) {

            //
            // TX processing to do
            //
            SmscIrContinueBlasting(deviceData,
                                   &txRequest,
                                   &txRequestStatus);
        }

        if (amountRxData) {

            //
            // RX processing to do
            //
            SmscirEncodeAndEnqueueRLC(rlcReceiver,
                                      (PCHAR)rxBuffer,
                                      amountRxData,
                                      dataEnd);

        }


    } while (numLoops < maxLoops);

    KeReleaseSpinLockFromDpcLevel(&deviceData->TxFifoDataLock);

    
    //
    // Have the helper routine grab the next pending
    //  receive, copy data into it, and then return
    //  it to us if we need to complete it. 
    //
    // This routine also dequeues the next request
    //  and tries to set it up as the current request.
    //  If that operation fails for some reason (invalid
    //  parameters in the next request, e.g.) we may
    //  also be passed a request to fail...
    //
    SmscIrProcessPendingReceives(rlcReceiver,
                                 &successfulRequest,
                                 &failedRequest,
                                 &failureStatus);


    KeReleaseSpinLock(&rlcReceiver->ListSpinLock, oldIrql);


    if (successfulRequest) {

        SmscIrTracePrint(
            TRACE_LEVEL_INFORMATION,
            SMSCDBG_RECEIVE_INFO,
            ("SmscIrEvtInterruptDpc: Completing RX request 0x%p",
                successfulRequest));

        WdfRequestCompleteWithPriorityBoost(successfulRequest, 
                                            STATUS_SUCCESS,
                                            IO_KEYBOARD_INCREMENT);
                
    }

    if (failedRequest) {
        
        SmscIrTracePrint(
            TRACE_LEVEL_INFORMATION,
            SMSCDBG_RECEIVE_INFO,
            ("SmscIrEvtInterruptDpc: Failing RX request 0x%p",
                successfulRequest));

        WdfRequestComplete(failedRequest, failureStatus);

    }

    if (txRequest) {

        //
        // Stop the dead man timer
        //
        SmscIrTracePrint(
            TRACE_LEVEL_INFORMATION,
            SMSCDBG_TRANSMIT_INFO,
            ("SmscIrEvtInterruptDpc: Completing TX request 0x%p",
                successfulRequest));
        WdfTimerStop(deviceData->DeadManTimer, FALSE);
        WdfRequestComplete(txRequest, txRequestStatus);

    }
   
    SmscIrTracePrint(
        TRACE_LEVEL_VERBOSE,
        SMSCDBG_RECEIVE_INFO,
        ("SmscIrEvtInterruptDpc: Exited"));

    return;

}


VOID
SmscirEncodeAndEnqueueRLC(
    IN PSMSCIR_RLC_RECEIVER RLCReceiver,
    __in_bcount(DataLen) PCHAR Buffer,
    IN ULONG DataLen,
    IN BOOLEAN DataEnd
    ) {

/*++

Routine Description:

    This routine takes the raw data pulled from the 
    device's FIFO and turns it into an array of
    on/off samples in 50usec units. It then 
    puts this data into a queue to be picked up
    by the class driver.
    
    RLCReceiver is *LOCKED* by caller on entry 

Arguments:

    RLCReceiver - The holder for either regular IR 
                    receivers or priority IR receivers

    Buffer        - The FIFO data teken from the device
             
    MaxLen        - Size of the Buffer parameter, in bytes

    DataEnd       - Is this a data end?

Return Value:

--*/

    ULONG       resultLen;
    PLONG       resultPtr;
    LONG        lastRLCPiece;
    ULONG       samples = 0;
    ULONG       i;
    LONG        bitsConsumed;
    PSAMPLE_RUN curSample;
    BOOLEAN     lastSampleOn;
    
    //
    // Make sure we're not going to overrun
    //  our scratch buffer (which is created to accomodate
    //  a worst case scenario of SMSCIR_MAX_LOCAL_BUFFER_SIZE
    //  samples...)
    //
    ASSERT(DataLen <= SMSCIR_MAX_LOCAL_BUFFER_SIZE);

    //
    // We're going to do a bit of a trick here. 
    //
    // We always save the last piece of the RLC calculation, 
    //  because the next piece that we get may be a continuation of it.
    //  When we get the next RLC calculation, we look at the last piece 
    //  of the previous calculation and decide if it's a continuation 
    //  or a new piece. If it's a continuation, we'll add it to the 
    //  first piece of the new calculation and go on as usual. However, 
    //  if it not a continuation, we'll stick the last piece of the 
    //  last calculation in RLCResultBuffer[0] and give that to the class
    //  driver to process. 
    //
    // We're called here under lock and we copy the data out of this
    //  scratch buffer into a real location, so we can safely use this
    //  one place for calcs without worrying about contention
    //
    resultPtr = &RLCReceiver->DeviceData->RLCResultBuffer[1];
    
    //
    // Get the state of the first sample and invert it. This will
    //  set things up for the first pass in the loop
    //
    lastSampleOn = !SmscIrSampleTable[(UCHAR)Buffer[0]]->On;

    for (i = 0; i < DataLen; i++) {

        //
        // For a long, overly winded description of what we're
        //  doing here, check out runtables.c
        //
        curSample = (PSAMPLE_RUN)&SmscIrSampleTable[(UCHAR)Buffer[i]];


        //
        // Every sample is 8 bits wide, i.e. one UCHAR. 
        //
        bitsConsumed = 8;

        //
        // While we haven't processed all of the bits in this
        //  sample...
        //
        while (bitsConsumed > 0) {

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -