Пример #1
0
/*++

Routine Description:

    DPC callback for ISR. Please note that on a multiprocessor system,
    you could have more than one DPCs running simulataneously on
    multiple processors. So if you are accesing any global resources
    make sure to synchrnonize the accesses with a spinlock.

Arguments:

    Interupt  - Handle to WDFINTERRUPT Object for this device.
    Device    - WDFDEVICE object passed to InterruptCreate

Return Value:

--*/
VOID PCIEEvtInterruptDpc(IN WDFINTERRUPT Interrupt,IN WDFDEVICE Device)
{
    NTSTATUS            Status;
    PDEVICE_EXTENSION   pDevExt;
    BOOLEAN             fTxInterrupt = FALSE;
    BOOLEAN             fRxInterrupt = FALSE;
    
    UNREFERENCED_PARAMETER(Device);

    pDevExt  = PCIEGetDeviceContext(WdfInterruptGetDevice(Interrupt));
    
    do
    {
        //
        // Acquire this device's InterruptSpinLock.
        //
        WdfInterruptAcquireLock( Interrupt );

        WdfInterruptReleaseLock( Interrupt );

      
    }while (FALSE);
    
    return;
}
Пример #2
0
BOOLEAN VirtRngEvtInterruptIsr(IN WDFINTERRUPT Interrupt, IN ULONG MessageId)
{
    PDEVICE_CONTEXT context = GetDeviceContext(
        WdfInterruptGetDevice(Interrupt));
    WDF_INTERRUPT_INFO info;
    BOOLEAN serviced;

    TraceEvents(TRACE_LEVEL_VERBOSE, DBG_INTERRUPT,
        "--> %!FUNC! Interrupt: %p MessageId: %u", Interrupt, MessageId);

    WDF_INTERRUPT_INFO_INIT(&info);
    WdfInterruptGetInfo(context->WdfInterrupt, &info);

    if ((info.MessageSignaled && (MessageId == 0)) ||
        VirtIODeviceISR(&context->VirtDevice))
    {
        WdfInterruptQueueDpcForIsr(Interrupt);
        serviced = TRUE;
    }
    else
    {
        serviced = FALSE;
    }

    TraceEvents(TRACE_LEVEL_VERBOSE, DBG_INTERRUPT, "<-- %!FUNC!");

    return serviced;
}
Пример #3
0
//
// Routine Description:
//
//  PL011EvtInterruptIsr is the interrupt service routine for 
//  ARM PL011 UART. PL011EvtInterruptIsr calls PL011pInterruptIsr to do
//  incoming events ISR level processing, and schedules a DPC level 
//  processing PL011EvtInterruptDpc if our device generated the interrupt.
//
// Arguments:
//
//  WdfInterrupt - The WDF interrupt object the created for the ARM PL011
//      interrupt.
//
//  MessageID - The message ID, in case the device is using MSIs, otherwise 0.
//
// Return Value:
//
//  TRUE if the interrupt originated from the PL011 device and was serviced,
//  otherwise FALSE.
//
_Use_decl_annotations_
BOOLEAN
PL011EvtInterruptIsr(
    WDFINTERRUPT WdfInterrupt,
    ULONG MessageID
    )
{
    UNREFERENCED_PARAMETER(MessageID);

    WDFDEVICE wdfDevice = WdfInterruptGetDevice(WdfInterrupt);
    PL011_DEVICE_EXTENSION* devExtPtr = PL011DeviceGetExtension(wdfDevice);

    //
    // Get and process UART events (ISR level)
    //
    BOOLEAN isUartInterrupt = PL011pInterruptIsr(devExtPtr);
    if (!isUartInterrupt) {

        return FALSE;
    }

    PL011_ASSERT(WdfInterrupt == devExtPtr->WdfUartInterrupt);

    WdfInterruptQueueDpcForIsr(devExtPtr->WdfUartInterrupt);

    PL011_LOG_TRACE(
        "UART ISR, status 0x%04X",
        USHORT(devExtPtr->IntEventsForDpc)
        );

    return TRUE;
}
Пример #4
0
VOID VioCryptInterruptDpc(IN WDFINTERRUPT Interrupt,
    IN WDFOBJECT AssociatedObject)
{
    PDEVICE_CONTEXT context = GetDeviceContext(
        WdfInterruptGetDevice(Interrupt));
    UNREFERENCED_PARAMETER(AssociatedObject);
    UNREFERENCED_PARAMETER(context);
}
Пример #5
0
BOOLEAN
NICEvtInterruptIsr(
    IN WDFINTERRUPT Interrupt,
    IN ULONG        MessageID
    )
/*++
Routine Description:

    Interrupt handler for the device.

Arguments:

    Interupt - Address of the framework interrupt object
    MessageID -

Return Value:

     TRUE if our device is interrupting, FALSE otherwise.

--*/
{
    BOOLEAN    InterruptRecognized = FALSE;
    PFDO_DATA  FdoData = NULL;
    USHORT     IntStatus;

    UNREFERENCED_PARAMETER( MessageID );

    TraceEvents(TRACE_LEVEL_VERBOSE, DBG_INTERRUPT, "--> NICEvtInterruptIsr\n");

    FdoData = FdoGetData(WdfInterruptGetDevice(Interrupt));

    //
    // We process the interrupt if it's not disabled and it's active
    //
    if (!NIC_INTERRUPT_DISABLED(FdoData) && NIC_INTERRUPT_ACTIVE(FdoData))
    {
        InterruptRecognized = TRUE;

        //
        // Disable the interrupt (will be re-enabled in NICEvtInterruptDpc
        //
        NICDisableInterrupt(FdoData);

        //
        // Acknowledge the interrupt(s) and get the interrupt status
        //

        NIC_ACK_INTERRUPT(FdoData, IntStatus);

        WdfInterruptQueueDpcForIsr( Interrupt );

    }

    TraceEvents(TRACE_LEVEL_VERBOSE, DBG_INTERRUPT, "<-- NICEvtInterruptIsr\n");

    return InterruptRecognized;
}
Пример #6
0
///////////////////////////////////////////////////////////////////////////////
// SmplInterruptEvtDisable 
///////////////////////////////////////////////////////////////////////////////
NTSTATUS SmplInterruptEvtDisable(
  __in  WDFINTERRUPT Interrupt,
  __in  WDFDEVICE AssociatedDevice
)
{
    PDEVICE_CONTEXT pDeviceContext = DeviceGetContext(WdfInterruptGetDevice(Interrupt));
    DbgPrintEx(DPFLTR_IHVDRIVER_ID, 1234,"SmplInterruptEvtDisable\n");
    WRITE_INTERRUPT_ENABLE( pDeviceContext->pPortAddress, 0);
    return STATUS_SUCCESS;

} // end SmplInterruptEvtDisable
Пример #7
0
BOOLEAN 
DeviceInterrupt_EvtAttachDetachInterruptIsr (
    _In_ WDFINTERRUPT Interrupt,
    _In_ ULONG MessageID
    )
/*++

Routine Description:

    'EvtInterruptIsr' handler for the attach/detach interrupt object.
    http://msdn.microsoft.com/en-us/library/windows/hardware/ff541735(v=vs.85).aspx

Arguments:

    Interrupt - Associated interrupt object.

    MessageID - Message IDs for MSI

Return Value:

    BOOLEAN

--*/
{
    PCONTROLLER_CONTEXT ControllerContext;

    UNREFERENCED_PARAMETER(MessageID);

    TraceEntry();

    ControllerContext = DeviceGetControllerContext(WdfInterruptGetDevice(Interrupt));
    
    WdfInterruptAcquireLock(ControllerContext->DeviceInterrupt);

    //
    // This is an ActiveBoth interrupt used for attach/detach.  State is determined
    // by counting interrupts.  Previous state was attached, so this is a detach.
    //
    if (!ControllerContext->Attached) {
        ControllerContext->Attached = TRUE;
        ControllerContext->GotAttachOrDetach = TRUE;

        (void) WdfInterruptQueueDpcForIsr(Interrupt);
    } else  {
        ControllerContext->Attached = FALSE;
        ControllerContext->GotAttachOrDetach = TRUE;
        (void) WdfInterruptQueueDpcForIsr(Interrupt);
    }
        
    WdfInterruptReleaseLock(ControllerContext->DeviceInterrupt);
        
    TraceExit();
    return TRUE;
}
Пример #8
0
///////////////////////////////////////////////////////////////////////////////
// Interrupt Service Routine (ISR) event callback function 
// processing on IRQL_DIRQL
///////////////////////////////////////////////////////////////////////////////
BOOLEAN SmplInterruptEvtIsr(
  __in  WDFINTERRUPT Interrupt,
  __in  ULONG MessageID
)
{
    WDFDEVICE Device = WdfInterruptGetDevice(Interrupt);
    PDEVICE_CONTEXT pSmplDeviceContext = DeviceGetContext(Device);
    BOOLEAN bReturnValue = FALSE;

#pragma warning(push)
#pragma warning(disable:4127) // warning C4127: conditional expression is constant
    while(TRUE)
#pragma warning(pop)
    {   // First check: Is it ours???
        UCHAR rcvd;
        UCHAR IntId = READ_INTERRUPT_IDENTIFICATION(pSmplDeviceContext->pPortAddress);
        if (IntId & IIR_NOT_FIRED)
        {
            break;
        }

        DbgPrintEx(DPFLTR_IHVDRIVER_ID, 1234,"Interrupt\n");
        bReturnValue = TRUE;

        switch (IntId) 
        {
            case IIR_RECEIVER_FULL: 
                rcvd = READ_RECEIVER_BUFFER (pSmplDeviceContext->pPortAddress);
                if (FALSE == RingbufferInsertCharacter(pSmplDeviceContext->pRingBuffer, rcvd)) 
                {
                    DbgPrintEx(DPFLTR_IHVDRIVER_ID, 1234,"Ringbuffer overflow %x\n", rcvd);
                }
                break;
            case IIR_RECEIVER_ERROR:
            case IIR_TRANSMITTER_EMPTY:
            case IIR_STATUS_CHANGE:
            default:
                ;
        } // end switch

    } // end while

    if(TRUE == bReturnValue)
        WdfInterruptQueueDpcForIsr(Interrupt);

    return bReturnValue;

} // end SmplInterruptEvtIsr
Пример #9
0
NTSTATUS VirtRngEvtInterruptDisable(IN WDFINTERRUPT Interrupt,
                                    IN WDFDEVICE AssociatedDevice)
{
    PDEVICE_CONTEXT context = GetDeviceContext(
        WdfInterruptGetDevice(Interrupt));

    TraceEvents(TRACE_LEVEL_VERBOSE, DBG_INTERRUPT,
        "--> %!FUNC! Interrupt: %p Device: %p",
        Interrupt, AssociatedDevice);

    virtqueue_disable_cb(context->VirtQueue);

    TraceEvents(TRACE_LEVEL_VERBOSE, DBG_INTERRUPT, "<-- %!FUNC!");

    return STATUS_SUCCESS;
}
Пример #10
0
BOOLEAN OnInterruptIsr(
	WDFINTERRUPT Interrupt,
	ULONG MessageID){
	UNREFERENCED_PARAMETER(MessageID);

	WDFDEVICE Device = WdfInterruptGetDevice(Interrupt);
	PDEVICE_CONTEXT pDevice = GetDeviceContext(Device);

	if (!pDevice->ConnectInterrupt)
		return true;

	struct cyapa_regs regs;
	SpbReadDataSynchronously(&pDevice->I2CContext, 0, &regs, sizeof(regs));
	pDevice->lastregs = regs;
	pDevice->RegsSet = true;
	return true;
}
Пример #11
0
///////////////////////////////////////////////////////////////////////////////
// Deferred procedure call (DPC) event callback function 
// for postprocessing after interrupt on IRQL_DISPATCH_LEVEL
///////////////////////////////////////////////////////////////////////////////
VOID
SmplInterruptEvtDpc(
    IN WDFINTERRUPT Interrupt,
    IN WDFOBJECT AssociatedObject
    )
{
    WDFDEVICE Device = WdfInterruptGetDevice(Interrupt);
    PDEVICE_CONTEXT pSmplDeviceContext = DeviceGetContext(Device);

    DbgPrintEx(DPFLTR_IHVDRIVER_ID, 1234,"SmplInterruptEvtDpc >>\n");

    WdfObjectAcquireLock(pSmplDeviceContext->Queue);

    while(TRUE == SmplIoQueueRequestTryComplete(pSmplDeviceContext));

    WdfObjectReleaseLock(pSmplDeviceContext->Queue);

} // end SmplInterruptEvtDpc
Пример #12
0
/*++
Routine Description:

Interrupt handler for this driver. Called at DIRQL level when the
device or another device sharing the same interrupt line asserts
the interrupt. The driver first checks the device to make sure whether
this interrupt is generated by its device and if so clear the interrupt
register to disable further generation of interrupts and queue a
DPC to do other I/O work related to interrupt - such as reading
the device memory, starting a DMA transaction, coping it to
the request buffer and completing the request, etc.

Arguments:

Interupt   - Handle to WDFINTERRUPT Object for this device.
MessageID  - MSI message ID (always 0 in this configuration)

Return Value:

TRUE   --  This device generated the interrupt.
FALSE  --  This device did not generated this interrupt.

--*/
BOOLEAN PCIEEvtInterruptIsr(IN WDFINTERRUPT Interrupt, IN ULONG MessageID)
{
    PDEVICE_EXTENSION   pDevExt;
    BOOLEAN             IsRecognized = FALSE;

    UNREFERENCED_PARAMETER(MessageID);

    // Our ISR Routine will be called event if the test card hasn't trigger any interrupt signal.
    pDevExt  = PCIEGetDeviceContext(WdfInterruptGetDevice(Interrupt));

    
    if (IsRecognized)
    {
        WdfInterruptQueueDpcForIsr(pDevExt->Interrupt);
    }

    return IsRecognized;
}
BOOLEAN
BalloonInterruptIsr(
    IN WDFINTERRUPT WdfInterrupt,
    IN ULONG        MessageID
    )
{
    PDEVICE_CONTEXT     devCtx = NULL;
    WDFDEVICE           Device;

    UNREFERENCED_PARAMETER( MessageID );

    TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INTERRUPT, "--> %s\n", __FUNCTION__);
    Device = WdfInterruptGetDevice(WdfInterrupt);
    devCtx = GetDeviceContext(Device);

    if(VirtIODeviceISR(&devCtx->VDevice) > 0)
    {
        WdfInterruptQueueDpcForIsr( WdfInterrupt );
        return TRUE;
    }
    return FALSE;
}
Пример #14
0
BOOLEAN VioCryptInterruptIsr(IN WDFINTERRUPT Interrupt, IN ULONG MessageId)
{
    PDEVICE_CONTEXT context = GetDeviceContext(
        WdfInterruptGetDevice(Interrupt));
    WDF_INTERRUPT_INFO info;
    BOOLEAN processed;

    WDF_INTERRUPT_INFO_INIT(&info);
    WdfInterruptGetInfo(context->WdfInterrupt, &info);

    processed = ((info.MessageSignaled && (MessageId == 0)) ||
        VirtIOWdfGetISRStatus(&context->VDevice));
    
    if (processed)
    {
        WdfInterruptQueueDpcForIsr(Interrupt);
    }

    Trace(TRACE_LEVEL_VERBOSE, "[%s] %sprocessed", __FUNCTION__, processed ? "" : "not ");

    return processed;
}
Пример #15
0
NTSTATUS
PLxEvtInterruptDisable(
    IN WDFINTERRUPT Interrupt,
    IN WDFDEVICE    Device
    )
/*++

Routine Description:

    Called by the framework at DIRQL before Deregistering the ISR with the kernel
    by calling IoDisconnectInterrupt.

Return Value:

    NTSTATUS
--*/
{
    PDEVICE_EXTENSION  devExt;

    union {
        INT_CSR   bits;
        ULONG     ulong;
    } intCSR;

    TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INTERRUPT,
                "PLxEvtInterruptDisable: Interrupt 0x%p, Device 0x%p\n",
                Interrupt, Device);

    devExt  = PLxGetDeviceContext(WdfInterruptGetDevice(Interrupt));

    intCSR.ulong = READ_REGISTER_ULONG( (PULONG) &devExt->Regs->Int_Csr );

    intCSR.bits.PciIntEnable = FALSE;

    WRITE_REGISTER_ULONG( (PULONG) &devExt->Regs->Int_Csr,
                          intCSR.ulong );

    return STATUS_SUCCESS;
}
Пример #16
0
_Use_decl_annotations_
VOID
PLxEvtInterruptDpc(
    WDFINTERRUPT Interrupt,
    WDFOBJECT    Device
    )
/*++

Routine Description:

    DPC callback for ISR. Please note that on a multiprocessor system,
    you could have more than one DPCs running simulataneously on
    multiple processors. So if you are accesing any global resources
    make sure to synchrnonize the accesses with a spinlock.

Arguments:

    Interupt  - Handle to WDFINTERRUPT Object for this device.
    Device    - WDFDEVICE object passed to InterruptCreate

Return Value:

--*/
{
    NTSTATUS            status;
    WDFDMATRANSACTION   dmaTransaction;
    PDEVICE_EXTENSION   devExt;
    BOOLEAN             writeInterrupt = FALSE;
    BOOLEAN             readInterrupt  = FALSE;

    UNREFERENCED_PARAMETER(Device);


    TraceEvents(TRACE_LEVEL_INFORMATION, DBG_DPC, "--> EvtInterruptDpc");

    devExt  = PLxGetDeviceContext(WdfInterruptGetDevice(Interrupt));

    //
    // Acquire this device's InterruptSpinLock.
    //
    WdfInterruptAcquireLock( Interrupt );


    if ((devExt->IntCsr.bits.DmaChan0IntActive) &&
        (devExt->Dma0Csr.bits.Done)) {

        //
        // If Dma0 channel 0 (write) is interrupting and the
        //  Done bit is set in the Dma0 CSR,
        //  we're interrupting because a WRITE is complete.
        // Clear the done bit and channel interrupting bit from
        //  our copies...
        //
        devExt->IntCsr.bits.DmaChan0IntActive = FALSE;
        devExt->Dma0Csr.uchar = 0;

        writeInterrupt = TRUE;
    }

    if ((devExt->IntCsr.bits.DmaChan1IntActive) &&
        (devExt->Dma1Csr.bits.Done)) {

        //
        // If DMA channel 1 is interrupting and the
        //  DONE bit is set in the DMA1 control/status
        //  register, we're interrupting because a READ
        //  is complete.
        // Clear the done bit and channel interrupting bit from
        //  our copies...
        //
        devExt->IntCsr.bits.DmaChan1IntActive = FALSE;
        devExt->Dma0Csr.uchar = 0;

        readInterrupt = TRUE;
    }

    //
    // Release our interrupt spinlock
    //
    WdfInterruptReleaseLock( Interrupt );

    //
    // Did a Write DMA complete?
    //
    if (writeInterrupt) {

        BOOLEAN transactionComplete;

        //
        // Get the current Write DmaTransaction.
        //
        dmaTransaction = devExt->WriteDmaTransaction;

        //
        // Indicate this DMA operation has completed:
        // This may drive the transfer on the next packet if
        // there is still data to be transfered in the request.
        //
        transactionComplete = WdfDmaTransactionDmaCompleted( dmaTransaction,
                                                         &status );

        if (transactionComplete) {
            //
            // Complete this DmaTransaction.
            //
            TraceEvents(TRACE_LEVEL_INFORMATION, DBG_DPC,
                                     "Completing Write request in the DpcForIsr");

            PLxWriteRequestComplete( dmaTransaction, status );

        }
    }

    //
    // Did a Read DMA complete?
    //
    if (readInterrupt) {

        BOOLEAN                transactionComplete;
        PDMA_TRANSFER_ELEMENT  dteVA;
        size_t                 length;

        //
        // Get the current Read DmaTransaction.
        //
        dmaTransaction = devExt->ReadDmaTransaction;

        //
        // Only on Read-side --
        //    Use "DMA Clear-Count Mode" to get complemetary
        //    transferred byte count.
        //
        length = WdfDmaTransactionGetCurrentDmaTransferLength( dmaTransaction );

        dteVA = (PDMA_TRANSFER_ELEMENT) devExt->ReadCommonBufferBase;

        while(dteVA->DescPtr.LastElement == FALSE) {
            length -= dteVA->TransferSize;
            dteVA++;
        }
        length -= dteVA->TransferSize;

        //
        // Indicate this DMA operation has completed:
        // This may drive the transfer on the next packet if
        // there is still data to be transfered in the request.
        //
        transactionComplete =
            WdfDmaTransactionDmaCompletedWithLength( dmaTransaction,
                                                     length,
                                                     &status );

        if (transactionComplete) {
            //
            // Complete this DmaTransaction.
            //
            TraceEvents(TRACE_LEVEL_INFORMATION, DBG_DPC,
                                    "Completing Read request in the DpcForIsr");

            PLxReadRequestComplete( dmaTransaction, status );

        }
    }

    TraceEvents(TRACE_LEVEL_INFORMATION, DBG_DPC, "<-- EvtInterruptDpc");

    return;
}
Пример #17
0
BOOLEAN
SerialISR(
    IN WDFINTERRUPT Interrupt,
    IN ULONG        MessageID
    )

/*++

Routine Description:

    This is the interrupt service routine for the serial port driver.
    It will determine whether the serial port is the source of this
    interrupt.  If it is, then this routine will do the minimum of
    processing to quiet the interrupt.  It will store any information
    necessary for later processing.

Arguments:

    InterruptObject - Points to the interrupt object declared for this
    device.  We *do not* use this parameter.


Return Value:

    This function will return TRUE if the serial port is the source
    of this interrupt, FALSE otherwise.

--*/

{
    //
    // Holds the information specific to handling this device.
    //
    PSERIAL_DEVICE_EXTENSION Extension = NULL;

    //
    // Holds the contents of the interrupt identification record.
    // A low bit of zero in this register indicates that there is
    // an interrupt pending on this device.
    //
    UCHAR InterruptIdReg;

    //
    // Will hold whether we've serviced any interrupt causes in this
    // routine.
    //
    BOOLEAN ServicedAnInterrupt;

    UCHAR tempLSR;
    PREQUEST_CONTEXT reqContext = NULL;

    UNREFERENCED_PARAMETER(MessageID);

    Extension = SerialGetDeviceExtension(WdfInterruptGetDevice(Interrupt));

    //
    // Make sure we have an interrupt pending.  If we do then
    // we need to make sure that the device is open.  If the
    // device isn't open or powered down then quiet the device.  Note that
    // if the device isn't opened when we enter this routine
    // it can't open while we're in it.
    //

    InterruptIdReg = READ_INTERRUPT_ID_REG(Extension, Extension->Controller);

    if ((InterruptIdReg & SERIAL_IIR_NO_INTERRUPT_PENDING)) {

        ServicedAnInterrupt = FALSE;

    } else if (!Extension->DeviceIsOpened/*
               || (Extension->PowerState != PowerDeviceD0)*/) {


        //
        // We got an interrupt with the device being closed or when the
        // device is supposed to be powered down.  This
        // is not unlikely with a serial device.  We just quietly
        // keep servicing the causes until it calms down.
        //

        ServicedAnInterrupt = TRUE;
        do {

            InterruptIdReg &= (~SERIAL_IIR_FIFOS_ENABLED);
            switch (InterruptIdReg) {

                case SERIAL_IIR_RLS: {

                    READ_LINE_STATUS(Extension, Extension->Controller);

                    break;

                }

                case SERIAL_IIR_RDA:
                case SERIAL_IIR_CTI: {

                    READ_RECEIVE_BUFFER(Extension, Extension->Controller);

                    break;

                }

                case SERIAL_IIR_THR: {

                    //
                    // Alread clear from reading the iir.
                    //
                    // We want to keep close track of whether
                    // the holding register is empty.
                    //

                    Extension->HoldingEmpty = TRUE;
                    break;

                }

                case SERIAL_IIR_MS: {

                    READ_MODEM_STATUS(Extension, Extension->Controller);
                    break;

                }

                default: {

                    ASSERT(FALSE);
                    break;

                }

            }

        } while (!((InterruptIdReg =
                    READ_INTERRUPT_ID_REG(Extension, Extension->Controller))
                    & SERIAL_IIR_NO_INTERRUPT_PENDING));

    } else {

        ServicedAnInterrupt = TRUE;
        do {

            //
            // We only care about bits that can denote an interrupt.
            //

            InterruptIdReg &= SERIAL_IIR_RLS | SERIAL_IIR_RDA |
                              SERIAL_IIR_CTI | SERIAL_IIR_THR |
                              SERIAL_IIR_MS;

            //
            // We have an interrupt.  We look for interrupt causes
            // in priority order.  The presence of a higher interrupt
            // will mask out causes of a lower priority.  When we service
            // and quiet a higher priority interrupt we then need to check
            // the interrupt causes to see if a new interrupt cause is
            // present.
            //

            switch (InterruptIdReg) {

                case SERIAL_IIR_RLS: {

                    SerialProcessLSR(Extension);

                    break;

                }

                case SERIAL_IIR_RDA:
                case SERIAL_IIR_CTI:

                {

                    //
                    // Reading the receive buffer will quiet this interrupt.
                    //
                    // It may also reveal a new interrupt cause.
                    //
                    UCHAR ReceivedChar;

                    do {

                        ReceivedChar =
                            READ_RECEIVE_BUFFER(Extension, Extension->Controller);
                        Extension->PerfStats.ReceivedCount++;
                        Extension->WmiPerfData.ReceivedCount++;

                        ReceivedChar &= Extension->ValidDataMask;

                        if (!ReceivedChar &&
                            (Extension->HandFlow.FlowReplace &
                             SERIAL_NULL_STRIPPING)) {

                            //
                            // If what we got is a null character
                            // and we're doing null stripping, then
                            // we simply act as if we didn't see it.
                            //

                            goto ReceiveDoLineStatus;

                        }

                        if ((Extension->HandFlow.FlowReplace &
                             SERIAL_AUTO_TRANSMIT) &&
                            ((ReceivedChar ==
                              Extension->SpecialChars.XonChar) ||
                             (ReceivedChar ==
                              Extension->SpecialChars.XoffChar))) {

                            //
                            // No matter what happens this character
                            // will never get seen by the app.
                            //

                            if (ReceivedChar ==
                                Extension->SpecialChars.XoffChar) {

                                Extension->TXHolding |= SERIAL_TX_XOFF;

                                if ((Extension->HandFlow.FlowReplace &
                                     SERIAL_RTS_MASK) ==
                                     SERIAL_TRANSMIT_TOGGLE) {

                                    SerialInsertQueueDpc(
                                        Extension->StartTimerLowerRTSDpc
                                        )?Extension->CountOfTryingToLowerRTS++:0;

                                }


                            } else {

                                if (Extension->TXHolding & SERIAL_TX_XOFF) {

                                    //
                                    // We got the xon char **AND*** we
                                    // were being held up on transmission
                                    // by xoff.  Clear that we are holding
                                    // due to xoff.  Transmission will
                                    // automatically restart because of
                                    // the code outside the main loop that
                                    // catches problems chips like the
                                    // SMC and the Winbond.
                                    //

                                    Extension->TXHolding &= ~SERIAL_TX_XOFF;

                                }

                            }

                            goto ReceiveDoLineStatus;

                        }

                        //
                        // Check to see if we should note
                        // the receive character or special
                        // character event.
                        //

                        if (Extension->IsrWaitMask) {

                            if (Extension->IsrWaitMask &
                                SERIAL_EV_RXCHAR) {

                                Extension->HistoryMask |= SERIAL_EV_RXCHAR;

                            }

                            if ((Extension->IsrWaitMask &
                                 SERIAL_EV_RXFLAG) &&
                                (Extension->SpecialChars.EventChar ==
                                 ReceivedChar)) {

                                Extension->HistoryMask |= SERIAL_EV_RXFLAG;

                            }

                            if (Extension->IrpMaskLocation &&
                                Extension->HistoryMask) {

                                *Extension->IrpMaskLocation =
                                 Extension->HistoryMask;
                                Extension->IrpMaskLocation = NULL;
                                Extension->HistoryMask = 0;
                                reqContext = SerialGetRequestContext(Extension->CurrentWaitRequest);
                                reqContext->Information = sizeof(ULONG);
                                SerialInsertQueueDpc(
                                    Extension->CommWaitDpc
                                    );

                            }

                        }

                        SerialPutChar(
                            Extension,
                            ReceivedChar
                            );

                        //
                        // If we're doing line status and modem
                        // status insertion then we need to insert
                        // a zero following the character we just
                        // placed into the buffer to mark that this
                        // was reception of what we are using to
                        // escape.
                        //

                        if (Extension->EscapeChar &&
                            (Extension->EscapeChar ==
                             ReceivedChar)) {

                            SerialPutChar(
                                Extension,
                                SERIAL_LSRMST_ESCAPE
                                );

                        }


ReceiveDoLineStatus:    ;
                        //
                        // This reads the interrupt ID register and detemines if bits are 0
                        // If either of the reserved bits are 1, we stop servicing interrupts
                        // Since this detection method is not guarenteed this is enabled via
                        // a registry entry "UartDetectRemoval" and intialized on DriverEntry.
                        // This is disabled by default and will only be enabled on Stratus systems
                        // that allow hot replacement of serial cards
                        //
                        if(Extension->UartRemovalDetect)
                        {
                           UCHAR DetectRemoval;

                           DetectRemoval = READ_INTERRUPT_ID_REG(Extension, Extension->Controller);

                           if(DetectRemoval & SERIAL_IIR_MUST_BE_ZERO)
                           {
                               // break out of this loop and stop processing interrupts
                               break;
                           }
                        }

                        if (!((tempLSR = SerialProcessLSR(Extension)) &
                              SERIAL_LSR_DR)) {

                            //
                            // No more characters, get out of the
                            // loop.
                            //

                            break;

                        }

                        if ((tempLSR & ~(SERIAL_LSR_THRE | SERIAL_LSR_TEMT |
                                         SERIAL_LSR_DR)) &&
                            Extension->EscapeChar) {

                           //
                           // An error was indicated and inserted into the
                           // stream, get out of the loop.
                           //

                           break;
                        }

                    } WHILE (TRUE);

                    break;

                }

                case SERIAL_IIR_THR: {

doTrasmitStuff:;
                    Extension->HoldingEmpty = TRUE;

                    if (Extension->WriteLength ||
                        Extension->TransmitImmediate ||
                        Extension->SendXoffChar ||
                        Extension->SendXonChar) {

                        //
                        // Even though all of the characters being
                        // sent haven't all been sent, this variable
                        // will be checked when the transmit queue is
                        // empty.  If it is still true and there is a
                        // wait on the transmit queue being empty then
                        // we know we finished transmitting all characters
                        // following the initiation of the wait since
                        // the code that initiates the wait will set
                        // this variable to false.
                        //
                        // One reason it could be false is that
                        // the writes were cancelled before they
                        // actually started, or that the writes
                        // failed due to timeouts.  This variable
                        // basically says a character was written
                        // by the isr at some point following the
                        // initiation of the wait.
                        //

                        Extension->EmptiedTransmit = TRUE;

                        //
                        // If we have output flow control based on
                        // the modem status lines, then we have to do
                        // all the modem work before we output each
                        // character. (Otherwise we might miss a
                        // status line change.)
                        //

                        if (Extension->HandFlow.ControlHandShake &
                            SERIAL_OUT_HANDSHAKEMASK) {

                            SerialHandleModemUpdate(
                                Extension,
                                TRUE
                                );

                        }

                        //
                        // We can only send the xon character if
                        // the only reason we are holding is because
                        // of the xoff.  (Hardware flow control or
                        // sending break preclude putting a new character
                        // on the wire.)
                        //

                        if (Extension->SendXonChar &&
                            !(Extension->TXHolding & ~SERIAL_TX_XOFF)) {

                            if ((Extension->HandFlow.FlowReplace &
                                 SERIAL_RTS_MASK) ==
                                 SERIAL_TRANSMIT_TOGGLE) {

                                //
                                // We have to raise if we're sending
                                // this character.
                                //

                                SerialSetRTS(Extension->WdfInterrupt, Extension);

                                Extension->PerfStats.TransmittedCount++;
                                Extension->WmiPerfData.TransmittedCount++;

                                WRITE_TRANSMIT_HOLDING(Extension, Extension->Controller,
                                                                Extension->SpecialChars.XonChar);
                                SerialInsertQueueDpc(
                                    Extension->StartTimerLowerRTSDpc
                                    )?Extension->CountOfTryingToLowerRTS++:0;


                            } else {

                                Extension->PerfStats.TransmittedCount++;
                                Extension->WmiPerfData.TransmittedCount++;

                                WRITE_TRANSMIT_HOLDING(Extension,
                                    Extension->Controller,
                                    Extension->SpecialChars.XonChar);
                            }


                            Extension->SendXonChar = FALSE;
                            Extension->HoldingEmpty = FALSE;

                            //
                            // If we send an xon, by definition we
                            // can't be holding by Xoff.
                            //

                            Extension->TXHolding &= ~SERIAL_TX_XOFF;

                            //
                            // If we are sending an xon char then
                            // by definition we can't be "holding"
                            // up reception by Xoff.
                            //

                            Extension->RXHolding &= ~SERIAL_RX_XOFF;

                        } else if (Extension->SendXoffChar &&
                              !Extension->TXHolding) {

                            if ((Extension->HandFlow.FlowReplace &
                                 SERIAL_RTS_MASK) ==
                                 SERIAL_TRANSMIT_TOGGLE) {

                                //
                                // We have to raise if we're sending
                                // this character.
                                //

                                SerialSetRTS(Extension->WdfInterrupt, Extension);

                                Extension->PerfStats.TransmittedCount++;
                                Extension->WmiPerfData.TransmittedCount++;
                                WRITE_TRANSMIT_HOLDING(Extension,
                                    Extension->Controller,
                                    Extension->SpecialChars.XoffChar);

                                SerialInsertQueueDpc(
                                    Extension->StartTimerLowerRTSDpc
                                    )?Extension->CountOfTryingToLowerRTS++:0;

                            } else {

                                Extension->PerfStats.TransmittedCount++;
                                Extension->WmiPerfData.TransmittedCount++;
                                WRITE_TRANSMIT_HOLDING(Extension,
                                    Extension->Controller,
                                    Extension->SpecialChars.XoffChar);

                            }

                            //
                            // We can't be sending an Xoff character
                            // if the transmission is already held
                            // up because of Xoff.  Therefore, if we
                            // are holding then we can't send the char.
                            //

                            //
                            // If the application has set xoff continue
                            // mode then we don't actually stop sending
                            // characters if we send an xoff to the other
                            // side.
                            //

                            if (!(Extension->HandFlow.FlowReplace &
                                  SERIAL_XOFF_CONTINUE)) {

                                Extension->TXHolding |= SERIAL_TX_XOFF;

                                if ((Extension->HandFlow.FlowReplace &
                                     SERIAL_RTS_MASK) ==
                                     SERIAL_TRANSMIT_TOGGLE) {

                                    SerialInsertQueueDpc(
                                        Extension->StartTimerLowerRTSDpc
                                        )?Extension->CountOfTryingToLowerRTS++:0;

                                }

                            }

                            Extension->SendXoffChar = FALSE;
                            Extension->HoldingEmpty = FALSE;

                        //
                        // Even if transmission is being held
                        // up, we should still transmit an immediate
                        // character if all that is holding us
                        // up is xon/xoff (OS/2 rules).
                        //

                        } else if (Extension->TransmitImmediate &&
                            (!Extension->TXHolding ||
                             (Extension->TXHolding == SERIAL_TX_XOFF)
                            )) {

                            Extension->TransmitImmediate = FALSE;

                            if ((Extension->HandFlow.FlowReplace &
                                 SERIAL_RTS_MASK) ==
                                 SERIAL_TRANSMIT_TOGGLE) {

                                //
                                // We have to raise if we're sending
                                // this character.
                                //

                                SerialSetRTS(Extension->WdfInterrupt, Extension);

                                Extension->PerfStats.TransmittedCount++;
                                Extension->WmiPerfData.TransmittedCount++;
                                WRITE_TRANSMIT_HOLDING(Extension,
                                    Extension->Controller,
                                    Extension->ImmediateChar);

                                SerialInsertQueueDpc(
                                    Extension->StartTimerLowerRTSDpc
                                    )?Extension->CountOfTryingToLowerRTS++:0;

                            } else {

                                Extension->PerfStats.TransmittedCount++;
                                Extension->WmiPerfData.TransmittedCount++;
                                WRITE_TRANSMIT_HOLDING(Extension,
                                    Extension->Controller,
                                    Extension->ImmediateChar);

                            }

                            Extension->HoldingEmpty = FALSE;

                            SerialInsertQueueDpc(
                                Extension->CompleteImmediateDpc
                                );

                        } else if (!Extension->TXHolding) {

                            ULONG amountToWrite;

                            if (Extension->FifoPresent) {

                                amountToWrite = (Extension->TxFifoAmount <
                                                 Extension->WriteLength)?
                                                Extension->TxFifoAmount:
                                                Extension->WriteLength;

                            } else {

                                amountToWrite = 1;

                            }
                            if ((Extension->HandFlow.FlowReplace &
                                 SERIAL_RTS_MASK) ==
                                 SERIAL_TRANSMIT_TOGGLE) {

                                //
                                // We have to raise if we're sending
                                // this character.
                                //

                                SerialSetRTS(Extension->WdfInterrupt, Extension);

                                if (amountToWrite == 1) {

                                    Extension->PerfStats.TransmittedCount++;
                                    Extension->WmiPerfData.TransmittedCount++;
                                    WRITE_TRANSMIT_HOLDING(Extension,
                                        Extension->Controller,
                                        *(Extension->WriteCurrentChar));

                                } else {

                                    Extension->PerfStats.TransmittedCount +=
                                        amountToWrite;
                                    Extension->WmiPerfData.TransmittedCount +=
                                       amountToWrite;
                                    WRITE_TRANSMIT_FIFO_HOLDING(Extension,
                                        Extension->Controller,
                                        Extension->WriteCurrentChar,
                                        amountToWrite);
                                }

                                SerialInsertQueueDpc(
                                    Extension->StartTimerLowerRTSDpc
                                    )?Extension->CountOfTryingToLowerRTS++:0;

                            } else {

                                if (amountToWrite == 1) {

                                    Extension->PerfStats.TransmittedCount++;
                                    Extension->WmiPerfData.TransmittedCount++;
                                    WRITE_TRANSMIT_HOLDING(Extension,
                                        Extension->Controller,
                                        *(Extension->WriteCurrentChar));

                                } else {

                                    Extension->PerfStats.TransmittedCount +=
                                        amountToWrite;
                                    Extension->WmiPerfData.TransmittedCount +=
                                        amountToWrite;
                                    WRITE_TRANSMIT_FIFO_HOLDING(Extension,
                                        Extension->Controller,
                                        Extension->WriteCurrentChar,
                                        amountToWrite);

                                }

                            }

                            Extension->HoldingEmpty = FALSE;
                            Extension->WriteCurrentChar += amountToWrite;
                            Extension->WriteLength -= amountToWrite;

                            if (!Extension->WriteLength) {

                                //
                                // No More characters left.  This
                                // write is complete.  Take care
                                // when updating the information field,
                                // we could have an xoff counter masquerading
                                // as a write request.
                                //
                                reqContext = SerialGetRequestContext(Extension->CurrentWriteRequest);

                                reqContext->Information =
                                    (reqContext->MajorFunction == IRP_MJ_WRITE)?
                                        (reqContext->Length): (1);

                                SerialInsertQueueDpc(
                                    Extension->CompleteWriteDpc
                                    );

                            }

                        }

                    }

                    break;

                }

                case SERIAL_IIR_MS: {

                    SerialHandleModemUpdate(
                        Extension,
                        FALSE
                        );

                    break;

                }

            }

        } while (!((InterruptIdReg =
                    READ_INTERRUPT_ID_REG(Extension, Extension->Controller))
                    & SERIAL_IIR_NO_INTERRUPT_PENDING));

        //
        // Besides catching the WINBOND and SMC chip problems this
        // will also cause transmission to restart incase of an xon
        // char being received.  Don't remove.
        //

        if (SerialProcessLSR(Extension) & SERIAL_LSR_THRE) {

            if (!Extension->TXHolding &&
                (Extension->WriteLength ||
                 Extension->TransmitImmediate)) {

                goto doTrasmitStuff;

            }

        }

    }

    return ServicedAnInterrupt;

}
Пример #18
0
BOOLEAN
AmccPciEvtInterruptIsr(
    __in WDFINTERRUPT Interrupt,
    __in ULONG        MessageID
    )
/*++

Routine Description:

    This routine assumes that only a single I/O can be completed at a
    time on the hardware (i.e. at most one I/O completed per interrupt).

Arguments:

    Interupt - Address of the framework interrupt object
    MessageID -

Return Value:

    TRUE - Interrupt belongs to this device.

--*/
{
    PAMCC_DEVICE_EXTENSION   devExt = NULL;
    WDFDEVICE                hDevice;

    union {
        ULONG      ulong;
        INTCSR_REG bits;
    } intcsr;

    union {
        ULONG      ulong;
        MCSR_REG   bits;
    } mcsr;

    UNREFERENCED_PARAMETER( MessageID );

    hDevice = WdfInterruptGetDevice(Interrupt);
    devExt = AmccPciGetDevExt(hDevice);

    //
    // Read interrupt control/status register and see if an interrupt is pending.
    // If not, return FALSE immediately.
    //
    intcsr.ulong = READ_PORT_ULONG((PULONG) &devExt->Regs->INTCSR);

    if (!intcsr.bits.InterruptAsserted) {
        return FALSE;
    }

    //
    // Disable bus-mastering
    //
    mcsr.ulong = READ_PORT_ULONG((PULONG) &devExt->Regs->MCSR);

    mcsr.bits.WriteTransferEnable = FALSE;
    mcsr.bits.ReadTransferEnable  = FALSE;

    WRITE_PORT_ULONG((PULONG) &devExt->Regs->MCSR, mcsr.ulong );

    //
    // This will take effect when INTCSR is rewritten later.
    //
    intcsr.bits.IntOnWriteTransferComplete = FALSE;
    intcsr.bits.IntOnReadTransferComplete  = FALSE;

    //
    // Process pending interrupts. We're expecting an interrupt due
    // to a transfer count going to zero, but we might be getting a
    // master or target abort instead.
    //
    while (intcsr.bits.InterruptAsserted) {

        //
        // Merge new interrupts with old
        //
        _InterlockedOr((PLONG) &devExt->Intcsr, (LONG) intcsr.ulong );

        //
        // Interrupt flags on the S5933 are cleared by writing a "1" bit
        // to them, so clear all the interrupts just examined.
        //
        WRITE_PORT_ULONG((PULONG) &devExt->Regs->INTCSR, intcsr.ulong);

        //
        // Check for additional interrupts
        //
        intcsr.ulong = READ_PORT_ULONG((PULONG) &devExt->Regs->INTCSR);
    }

    //
    // Check if there is a current Request.  If not, then this interrupt cannot
    // do anything.  This driver design requires an I/O to be pending in order
    // to queue the DPC.  If there is no I/O current, then there is no need
    // to have a DPC queued.  This driver also assumes one I/O per interrupt.
    //
    // IMPORTANT: Before returning TRUE, the interrupt must have been cleared
    // on the device or the system will hang trying to service this level
    // sensitive interrupt.
    //
    if (!devExt->CurrentRequest) {
        TraceEvents(TRACE_LEVEL_WARNING, AMCC_TRACE_IO,
                    "Hardware generated interrupt with no request pending");
        return TRUE;
    }

    //
    // Request the DPC to complete the transfer.
    //
    WdfInterruptQueueDpcForIsr( Interrupt );

    //
    // Indicate that this adapter was interrupting.
    //
    return TRUE;
}
Пример #19
0
VOID VirtRngEvtInterruptDpc(IN WDFINTERRUPT Interrupt,
                            IN WDFOBJECT AssociatedObject)
{
    PDEVICE_CONTEXT context = GetDeviceContext(
        WdfInterruptGetDevice(Interrupt));
    struct virtqueue *vq = context->VirtQueue;
    PREAD_BUFFER_ENTRY entry;
    PSINGLE_LIST_ENTRY iter;
    NTSTATUS status;
    PVOID buffer;
    size_t bufferLen;
    unsigned int length;

    UNREFERENCED_PARAMETER(AssociatedObject);

    TraceEvents(TRACE_LEVEL_VERBOSE, DBG_DPC,
        "--> %!FUNC! Interrupt: %p", Interrupt);

    for (;;)
    {
        WdfSpinLockAcquire(context->VirtQueueLock);

        entry = (PREAD_BUFFER_ENTRY)virtqueue_get_buf(vq, &length);
        if (entry == NULL)
        {
            WdfSpinLockRelease(context->VirtQueueLock);
            break;
        }

        TraceEvents(TRACE_LEVEL_VERBOSE, DBG_READ,
            "Got %p Request: %p Buffer: %p",
            entry, entry->Request, entry->Buffer);

        iter = &context->ReadBuffersList;
        while (iter->Next != NULL)
        {
            PREAD_BUFFER_ENTRY current = CONTAINING_RECORD(iter->Next,
                READ_BUFFER_ENTRY, ListEntry);

            if (entry == current)
            {
                TraceEvents(TRACE_LEVEL_VERBOSE, DBG_READ,
                    "Delete %p Request: %p Buffer: %p",
                    entry, entry->Request, entry->Buffer);

                iter->Next = current->ListEntry.Next;
                break;
            }
            else
            {
                iter = iter->Next;
            }
        };

        if ((entry->Request == NULL) ||
            (WdfRequestUnmarkCancelable(entry->Request) == STATUS_CANCELLED))
        {
            TraceEvents(TRACE_LEVEL_INFORMATION, DBG_DPC,
                "Ignoring a canceled read request: %p", entry->Request);

            entry->Request = NULL;
        }

        WdfSpinLockRelease(context->VirtQueueLock);

        if (entry->Request != NULL)
        {
            status = WdfRequestRetrieveOutputBuffer(entry->Request, length,
                &buffer, &bufferLen);

            if (NT_SUCCESS(status))
            {
                length = min(length, (unsigned)bufferLen);
                RtlCopyMemory(buffer, entry->Buffer, length);

                TraceEvents(TRACE_LEVEL_VERBOSE, DBG_DPC,
                    "Complete Request: %p Length: %d", entry->Request, length);

                WdfRequestCompleteWithInformation(entry->Request,
                    STATUS_SUCCESS, (ULONG_PTR)length);
            }
            else
            {
                TraceEvents(TRACE_LEVEL_ERROR, DBG_READ,
                    "WdfRequestRetrieveOutputBuffer failed: %!STATUS!", status);
                WdfRequestComplete(entry->Request, status);
            }
        }

        ExFreePoolWithTag(entry->Buffer, VIRT_RNG_MEMORY_TAG);
        ExFreePoolWithTag(entry, VIRT_RNG_MEMORY_TAG);
    }

    TraceEvents(TRACE_LEVEL_VERBOSE, DBG_DPC, "<-- %!FUNC!");
}
Пример #20
0
//
// Routine Description:
//
//  PL011EvtInterruptDpc is the called by the framework, when 
//  the interrupt processing requires more work that needs to be done
//  at IRQL lower than ISR.
//  The routine processes each received events:
//  1) RX interrupt:
//     - Copy from RX FIFO
//     - Indicate new data to SerCx2, if RX state allows it.
//  2) TX interrupt:
//     - Copy to TX FIFO
//     - Notify SerCx2 based on RX state:
//          a) Normal TX mode: TX readiness.
//          b) Drain FIFO: 'Drain FIFO' status.
//  3) Serial port events:
//      - Notify SerCx2 if it was waiting for those.
//
// Arguments:
//
//  WdfInterrupt - The WDF interrupt object the created for the ARM PL011
//      interrupt.
//
//  AssociatedObject - Our WDFDEVICE object.
//
// Return Value:
//
_Use_decl_annotations_
VOID
PL011EvtInterruptDpc(
    WDFINTERRUPT WdfInterrupt,
    WDFOBJECT AssociatedObject
    )
{
    UNREFERENCED_PARAMETER(AssociatedObject);

    WDFDEVICE wdfDevice = WdfInterruptGetDevice(WdfInterrupt);
    PL011_DEVICE_EXTENSION* devExtPtr = PL011DeviceGetExtension(wdfDevice);

    //
    // Get new events ISR added
    //
    ULONG interruptEventsToHandle = ULONG(InterlockedExchange(
            reinterpret_cast<volatile LONG*>(&devExtPtr->IntEventsForDpc),
            0));

    //
    // RX interrupt:
    // If a character has been received, or the FIFO is
    // not empty, and RX timeout has occurred.
    // Basically if RX FIFO is not empty.
    //
    // Copy the RX FIFO to our local RX buffer.
    //
    if ((interruptEventsToHandle & (UARTRIS_RXIS | UARTRIS_RTIS)) != 0) {
        //
        // Copy new data from RX FIFO to PIO RX buffer.
        //
        (void)PL011RxPioFifoCopy(devExtPtr, nullptr);

        //
        // Notify SerCxs if notifications have not been canceled,
        // or if SerCx2 was already notified.
        //
        if (PL011RxPioStateSetCompare(
                devExtPtr->SerCx2PioReceive, 
                PL011_RX_PIO_STATE::RX_PIO_STATE__WAIT_READ_DATA,
                PL011_RX_PIO_STATE::RX_PIO_STATE__WAIT_DATA
                )) {
            //
            // Data is ready, come get it...
            //
            SerCx2PioReceiveReady(devExtPtr->SerCx2PioReceive);

        } // If RX state set to RX_PIO_STATE__WAIT_READ_DATA

    } // if (RX interrupt)

    //
    // TX interrupt:
    // If TX FIFOs occupancy has gone bellow the configured
    // trigger level.
    //
    // Copy our local TX buffer to TX FIFO, and check if 
    // a 'TX Drain' FIFO request is in progress.
    //
    if ((interruptEventsToHandle & UARTRIS_TXIS) != 0) {
        //
        // Copy pending data from PIO TX buffer to TX FIFO, if any...
        //
        (void)PL011TxPioFifoCopy(devExtPtr, nullptr);

        //
        // Notify SerCxs if notifications have not been canceled.
        //
        if (PL011TxPioStateSetCompare(
                devExtPtr->SerCx2PioTransmit,
                PL011_TX_PIO_STATE::TX_PIO_STATE__WAIT_SEND_DATA,
                PL011_TX_PIO_STATE::TX_PIO_STATE__WAIT_DATA_SENT
                )) {
            //
            // Ready for more TX data...
            //
            SerCx2PioTransmitReady(devExtPtr->SerCx2PioTransmit);

        } // if (TX state set TX_PIO_STATE__WAIT_SEND_DATA)

    } // if (TX interrupt)

    //
    // Record errors and break events, if any...
    //
    PL011DeviceRecordErrors(
        devExtPtr, 
        (interruptEventsToHandle & (UART_INTERUPPTS_ERRORS | UARTRIS_BEIS))
        );

    //
    // Notify the framework of new events, if any...
    //
    PL011DeviceNotifyEvents(
        devExtPtr,
        interruptEventsToHandle
        );
}
Пример #21
0
BOOLEAN
PLxEvtInterruptIsr(
    IN WDFINTERRUPT Interrupt,
    IN ULONG        MessageID
    )
/*++
Routine Description:

    Interrupt handler for this driver. Called at DIRQL level when the
    device or another device sharing the same interrupt line asserts
    the interrupt. The driver first checks the device to make sure whether
    this interrupt is generated by its device and if so clear the interrupt
    register to disable further generation of interrupts and queue a
    DPC to do other I/O work related to interrupt - such as reading
    the device memory, starting a DMA transaction, coping it to
    the request buffer and completing the request, etc.

Arguments:

    Interupt   - Handle to WDFINTERRUPT Object for this device.
    MessageID  - MSI message ID (always 0 in this configuration)

Return Value:

     TRUE   --  This device generated the interrupt.
     FALSE  --  This device did not generated this interrupt.

--*/
{
    PDEVICE_EXTENSION   devExt;
    BOOLEAN             isRecognized = FALSE;

    union {
        INT_CSR bits;
        ULONG   ulong;
    } intCsr;

    UNREFERENCED_PARAMETER(MessageID);

    //TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INTERRUPT,
    //            "--> PLxInterruptHandler");

    devExt  = PLxGetDeviceContext(WdfInterruptGetDevice(Interrupt));

    //
    // Read the Interrupt CSR register (INTCSR)
    //
    intCsr.ulong = READ_REGISTER_ULONG( (PULONG) &devExt->Regs->Int_Csr );

    //
    // Is DMA channel 0 (Write-side) Active?
    //
    if (intCsr.bits.DmaChan0IntActive) {

        TraceEvents(TRACE_LEVEL_INFORMATION,  DBG_INTERRUPT,
                    " Interrupt for DMA Channel 0 (write)");

        devExt->IntCsr.bits.DmaChan0IntActive = TRUE;

        //
        // Clear this interrupt.
        //
        devExt->Dma0Csr.uchar =
            READ_REGISTER_UCHAR( (PUCHAR) &devExt->Regs->Dma0_Csr );

        devExt->Dma0Csr.bits.Clear = TRUE;

        WRITE_REGISTER_UCHAR( (PUCHAR) &devExt->Regs->Dma0_Csr,
                              devExt->Dma0Csr.uchar );

        isRecognized = TRUE;
    }

    //
    // Is DMA channel 1 (Read-side) Active?
    //
    if (intCsr.bits.DmaChan1IntActive) {

        TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INTERRUPT,
                    " Interrupt for DMA Channel 1 (read)");

        devExt->IntCsr.bits.DmaChan1IntActive = TRUE;

        //
        // Clear this interrupt.
        //
        devExt->Dma1Csr.uchar =
            READ_REGISTER_UCHAR( (PUCHAR) &devExt->Regs->Dma1_Csr );

        devExt->Dma1Csr.bits.Clear = TRUE;

        WRITE_REGISTER_UCHAR( (PUCHAR) &devExt->Regs->Dma1_Csr,
                              devExt->Dma1Csr.uchar );

        isRecognized = TRUE;
    }

    if ((isRecognized) &&
        ((devExt->Dma0Csr.bits.Done) ||
         (devExt->Dma1Csr.bits.Done))) {
        //
        // A read or a write or both is done. Queue a DPC.
        //
        WdfInterruptQueueDpcForIsr( devExt->Interrupt );
    }

    //TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INTERRUPT,
    //            "<-- PLxInterruptHandler");

    return isRecognized;
}
Пример #22
0
BOOLEAN
OnInterruptPassiveIsr(
    _In_ WDFINTERRUPT PortControllerInterrupt,
    _In_ ULONG MessageID
)
/*++

Routine Description:

    Per the TCPCI spec, the port controller hardware will drive the Alert pin high
    when a hardware event occurs. This routine services such a hardware interrupt at PASSIVE_LEVEL.
    The routine determines if an interrupt is an alert from the port controller hardware;
    if so, it completes processing of the alert.

Arguments:

    Interrupt: A handle to a framework interrupt object.

    MessageID: If the device is using message-signaled interrupts (MSIs), this parameter
    is the message number that identifies the device's hardware interrupt message.
    Otherwise, this value is 0.

Return Value:

    TRUE if the function services the hardware interrupt.
    Otherwise, this function must return FALSE.

--*/
{
    TRACE_FUNC_ENTRY(TRACE_ALERT);

    UNREFERENCED_PARAMETER(MessageID);
    PAGED_CODE();

    NTSTATUS status;
    PDEVICE_CONTEXT deviceContext;
    ALERT_REGISTER alertRegister;
    BOOLEAN interruptRecognized = FALSE;
    int numAlertsProcessed = 0;
    deviceContext = DeviceGetContext(WdfInterruptGetDevice(PortControllerInterrupt));

    // Process the alerts as long as there are bits set in the alert register.
    // Set a maximum number of alerts to process in this loop. If the hardware is messed up and we're unable
    // to quiesce the interrupt by writing to the alert register, then we don't want to be stuck in an
    // infinite loop.
    while (numAlertsProcessed <= MAX_ALERTS_TO_PROCESS)
    {
        status = I2CReadSynchronously(deviceContext,
            I2CRequestSourceAlertIsr,
            ALERT,
            &alertRegister,
            sizeof(alertRegister));
        if (!NT_SUCCESS(status))
        {
            goto Exit;
        }
        // If there are no bits set in the alert register, we should not service this interrupt.
        if (alertRegister.AsUInt16 == 0)
        {
            goto Exit;
        }

        // Since there are bits set in the alert register, we can safely assume that the
        // interrupt is ours to process.
        interruptRecognized = TRUE;

        ProcessAndSendAlerts(&alertRegister, deviceContext);
        ++numAlertsProcessed;
    }

Exit:
    TRACE_FUNC_EXIT(TRACE_ALERT);
    return interruptRecognized;
}