Пример #1
0
NTSTATUS
AmccPciEvtDeviceReleaseHardware (
    _In_ WDFDEVICE       hDevice,
    _In_ WDFCMRESLIST   ResourcesTranslated
    )
/*++

Routine Description:

    EvtDeviceReleaseHardware is called by the framework whenever the PnP manager
    is revoking ownership of our resources.  This may be in response to either
    IRP_MN_STOP_DEVICE or IRP_MN_REMOVE_DEVICE.  The callback is made before
    passing down the IRP to the lower driver.

    In this callback, do anything necessary to free those resources.

Arguments:

    Device - Handle to a framework device object.

    ResourcesTranslated - Handle to a collection of framework resource objects.
                This collection identifies the translated (system-physical)
                hardware resources that have been assigned to the device.
                The resources appear from the CPU's point of view.
                Use this list of resources to map I/O space and
                device-accessible memory into virtual address space

Return Value:

    VOID
--*/
{
    PAMCC_DEVICE_EXTENSION   devExt = NULL;

    UNREFERENCED_PARAMETER(ResourcesTranslated);

    PAGED_CODE();

    devExt = AmccPciGetDevExt(hDevice);

    //
    // Unmap the IO resource
    //
    if (devExt->PortBase) {

        if (devExt->PortMapped) {

            MmUnmapIoSpace( devExt->PortBase,  devExt->PortCount );

        }
        devExt->PortBase = NULL;
    }

    return STATUS_SUCCESS;
}
Пример #2
0
NTSTATUS
AmccPciAddDevice(
    _In_    WDFDRIVER        Driver,
    _Inout_ PWDFDEVICE_INIT  DeviceInit
    )
/*++

Routine Description:

    EvtDeviceAdd is called by the framework in response to AddDevice
    call from the PnP manager.  It is responsible for initializing and
    creating a WDFDEVICE object.

    Any work that should be done after the object is created should be
    deferred until EvtDeviceSoftwareInit, as that callback will be made
    with the device lock held (if there is one.)

Arguments:

    Driver - Handle to a framework driver object created in DriverEntry

    DeviceInit - Pointer to a framework-allocated WDFDEVICE_INIT structure.

Return Value:

    NTSTATUS

--*/
{
    NTSTATUS                   status = STATUS_SUCCESS;
    WDF_PNPPOWER_EVENT_CALLBACKS pnpPowerCallbacks;
    WDF_OBJECT_ATTRIBUTES       fdoAttributes;
    WDF_INTERRUPT_CONFIG        interruptConfig;
    WDF_OBJECT_ATTRIBUTES       interruptAttributes;
    WDF_IO_QUEUE_CONFIG         ioQueueConfig;
    PAMCC_DEVICE_EXTENSION           devExt;
    WDFQUEUE                    hQueue;
    WDFDEVICE                   device;

    PAGED_CODE();

    TraceEvents(TRACE_LEVEL_INFORMATION, AMCC_TRACE_INIT,
                        "AmccPciAddDevice: 0x%p", Driver);

    //
    // Zero out the PnpPowerCallbacks structure.
    //
    WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&pnpPowerCallbacks);

    //
    // Set Callbacks for any of the functions we are interested in.
    // If no callback is set, Framework will take the default action
    // by itself.
    //
    pnpPowerCallbacks.EvtDevicePrepareHardware = AmccPciEvtDevicePrepareHardware;
    pnpPowerCallbacks.EvtDeviceReleaseHardware = AmccPciEvtDeviceReleaseHardware;
    pnpPowerCallbacks.EvtDeviceD0Entry         = AmccPciEvtDeviceD0Entry;
    pnpPowerCallbacks.EvtDeviceD0Exit          = AmccPciEvtDeviceD0Exit;

    //
    // Register the PnP Callbacks..
    //
    WdfDeviceInitSetPnpPowerEventCallbacks(DeviceInit, &pnpPowerCallbacks);

    //
    // Set various attributes for this device
    //
    WdfDeviceInitSetIoType( DeviceInit, WdfDeviceIoDirect );

    WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&fdoAttributes, AMCC_DEVICE_EXTENSION);
    fdoAttributes.EvtCleanupCallback = AmccPciContextCleanup;
    //
    // We want all the queue callbacks, cancel routine, and DpcForIsr to be serialized
    // at the device level, so we don't have worry about any synchronization issues.
    //
    fdoAttributes.SynchronizationScope = WdfSynchronizationScopeDevice;

    status = WdfDeviceCreate( &DeviceInit, &fdoAttributes, &device );

    if ( !NT_SUCCESS(status) ) {
        TraceEvents(TRACE_LEVEL_ERROR, AMCC_TRACE_INIT,
                                "WdfDeviceInitialize failed 0x%X", status);
        return status;
    }

    //
    // Device Initialization is complete.
    // Get the Device Extension and initialize it.
    //
    devExt = AmccPciGetDevExt(device);

    devExt->Device = device;

    TraceEvents(TRACE_LEVEL_INFORMATION, AMCC_TRACE_INIT,
                        "PDO 0x%p, FDO 0x%p, DevExt 0x%p",
                        WdfDeviceWdmGetPhysicalDevice(device),
                        WdfDeviceWdmGetDeviceObject( device ), devExt);

    //
    // This device generates an interrupt.  So create an interrupt object which
    // will later be associated with the devices resources and connected
    // by the Framework.
    //

    WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&interruptAttributes, INTERRUPT_DATA);

    //
    // Configure the Interrupt object
    //
    WDF_INTERRUPT_CONFIG_INIT(&interruptConfig,
                              AmccPciEvtInterruptIsr,
                              AmccPciEvtInterruptDpc);

    status = WdfInterruptCreate(device,
                                &interruptConfig,
                                &interruptAttributes,
                                &devExt->WdfInterrupt);
    if (!NT_SUCCESS (status))
    {
        TraceEvents(TRACE_LEVEL_ERROR, AMCC_TRACE_INIT,
                    "WdfInterruptCreate failed: %!STATUS!\n", status);
        return status;
    }

    //
    // The S5933 requires DMA buffers be aligned on a 32-bit boundary
    //
    // NOTE: Read the existing alignment value. If it is greater than
    //       or equal then keep it.  If it is less then update the
    //       alignment requirement field with this device's required
    //       value.
    //
    // NOTE: See the MSDN section titled "Initializing a Device Object"
    //       for details on how to specify this alignment value.
    //
    // NOTE: AMCC5933_ALIGNMENT__32BITS is equated to (4-1) for 32-bit
    //       alignment.
    //
    {
        ULONG alignReq;

        alignReq = WdfDeviceGetAlignmentRequirement( device );

        if (alignReq < AMCC5933_ALIGNMENT__32BITS) {

            //
            // Set the S5933 alignment requirement as new value.
            //
            WdfDeviceSetAlignmentRequirement( device,
                                              AMCC5933_ALIGNMENT__32BITS);
        }
    }

    //
    // Register I/O callbacks.
    //
    // Create a sequential IO Queue for serial operation. That means all the requests (Read/Write
    // & IOCTL) are serialized to the device. Until the driver completes the request presented to it,
    // the framework will not schedule another one. The requests held in the framework will be
    // cancelled automatically if the source of request (application) terminate or cancels it.
    //
    WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE( &ioQueueConfig,
                              WdfIoQueueDispatchSequential);

    ioQueueConfig.EvtIoDefault = AmccPciEvtIoDefault;
    
    //
    // By default, Static Driver Verifier (SDV) displays a warning if it 
    // doesn't find the EvtIoStop callback on a power-managed queue. 
    // The 'assume' below causes SDV to suppress this warning. If the driver 
    // has not explicitly set PowerManaged to WdfFalse, the framework creates
    // power-managed queues when the device is not a filter driver.  Normally 
    // the EvtIoStop is required for power-managed queues, but for this driver
    // it is not needed b/c the driver doesn't hold on to the requests for 
    // long time or forward them to other drivers. 
    // If the EvtIoStop callback is not implemented, the framework waits for
    // all driver-owned requests to be done before moving in the Dx/sleep 
    // states or before removing the device, which is the correct behavior 
    // for this type of driver. If the requests were taking an indeterminate
    // amount of time to complete, or if the driver forwarded the requests
    // to a lower driver/another stack, the queue should have an 
    // EvtIoStop/EvtIoResume.
    //
    __analysis_assume(ioQueueConfig.EvtIoStop != 0);
    status = WdfIoQueueCreate( device,
                               &ioQueueConfig,
                               WDF_NO_OBJECT_ATTRIBUTES,
                               &hQueue );
    __analysis_assume(ioQueueConfig.EvtIoStop == 0);
    if (!NT_SUCCESS (status)) {
        //
        // We don't have worry about deleting the device here because framework will automatically
        // cleanup that when the driver unloads.
        //
        TraceEvents(TRACE_LEVEL_ERROR, AMCC_TRACE_INIT,
                                "WdfIoQueueCreate failed %!STATUS!", status);
        return status;
    }

    //
    // Register an interface so that application can find and talk to us.
    // NOTE: See the note in Public.h concerning this GUID value.
    //
    status = WdfDeviceCreateDeviceInterface( device,
                                             (LPGUID) &GUID_DEVINTERFACE_AMCC_PCI,
                                             NULL );

    if (!NT_SUCCESS(status)) {
        TraceEvents(TRACE_LEVEL_ERROR, AMCC_TRACE_INIT,
                "<-- AMCCAddDevice: WdfDeviceCreateDeviceInterface failed %!STATUS!", status);
        return status;
    }

    devExt->MaximumTransferLength = MAXIMUM_REQUEST_CONTEXT_LENGTH;

    //
    // Set the maximum physical pages for now, but this value may change if
    // there aren't enough map registers
    //
    devExt->MaximumPhysicalPages = MAXIMUM_PHYSICAL_PAGES;

    return status;
}
Пример #3
0
NTSTATUS
AmccPciEvtDevicePrepareHardware(
    _In_ WDFDEVICE       Device,
    _In_ WDFCMRESLIST   Resources,
    _In_ WDFCMRESLIST   ResourcesTranslated
    )
/*++

Routine Description:

    EvtDevicePrepareHardware event callback performs operations that are necessary
    to use the device's control registers.

Arguments:

    Device - Handle to a framework device object.

    Resources - Handle to a collection of framework resource objects.
                This collection identifies the raw (bus-relative) hardware
                resources that have been assigned to the device.

    ResourcesTranslated - Handle to a collection of framework resource objects.
                This collection identifies the translated (system-physical)
                hardware resources that have been assigned to the device.
                The resources appear from the CPU's point of view.
                Use this list of resources to map I/O space and
                device-accessible memory into virtual address space

Return Value:

    WDF status code.

    Let us not worry about cleaning up the resources here if we fail start,
    because the PNP manager will send a remove-request and we will free all
    the allocated resources in AmccPciEvtDeviceReleaseHardware.

--*/
{
    ULONG                               i;
    NTSTATUS                            status = STATUS_SUCCESS;
    PAMCC_DEVICE_EXTENSION                   devExt = NULL;
    BOOLEAN                             foundPort      = FALSE;
    PHYSICAL_ADDRESS                    portBasePA     = {0};
    ULONG                               portCount      = 0;
    WDF_DMA_ENABLER_CONFIG              dmaConfig;
    PCM_PARTIAL_RESOURCE_DESCRIPTOR     desc;

    PAGED_CODE();

    //
    // The Resources collection is not used for PCI devices, since the PCI
    // bus driver manages the device's PCI Base Address Registers.
    //

    UNREFERENCED_PARAMETER( Resources );


    devExt = AmccPciGetDevExt(Device);

    //
    // Parse the resource list and save the resource information.
    //
    for (i=0; i < WdfCmResourceListGetCount(ResourcesTranslated); i++) {

        desc = WdfCmResourceListGetDescriptor(ResourcesTranslated, i);

        if(!desc) {
            TraceEvents(TRACE_LEVEL_ERROR, AMCC_TRACE_INIT,
                            "WdfResourceCmGetDescriptor failed");
            return STATUS_DEVICE_CONFIGURATION_ERROR;
        }

        switch (desc->Type) {

        case CmResourceTypePort:

            portBasePA = desc->u.Port.Start;
            portCount  = desc->u.Port.Length;

            devExt->PortMapped =
                (desc->Flags & CM_RESOURCE_PORT_IO) ? FALSE : TRUE;

            foundPort = TRUE;

            //
            // Map in the single IO Space resource.
            //
            if (devExt->PortMapped) {

                devExt->PortBase =
                    (PUCHAR) MmMapIoSpace( portBasePA, portCount, MmNonCached );

                if (!devExt->PortBase) {

                    TraceEvents(TRACE_LEVEL_ERROR, AMCC_TRACE_INIT,
                                    "Unable to map port range 0x%p, length %d",
                                        devExt->PortBase, devExt->PortCount);

                    return STATUS_INSUFFICIENT_RESOURCES;
                }

                devExt->PortCount = portCount;

            } else {

                devExt->PortBase  = (PUCHAR)(ULONG_PTR) portBasePA.QuadPart;
                devExt->PortCount = portCount;
            }

            devExt->Regs = (PREG5933) devExt->PortBase;

            break;

        default:
            TraceEvents(TRACE_LEVEL_WARNING, AMCC_TRACE_INIT,
                                "Unknown resource type %d", desc->Type);
            break;
        }

    }

    if (!foundPort) {
        TraceEvents(TRACE_LEVEL_ERROR, AMCC_TRACE_INIT,
                            "Missing hardware resources");
        return STATUS_DEVICE_CONFIGURATION_ERROR;
    }


    //
    // Configure the DMA  object
    //

    WDF_DMA_ENABLER_CONFIG_INIT( &dmaConfig,
                                 WdfDmaProfilePacket,
                                 devExt->MaximumTransferLength );

    status = WdfDmaEnablerCreate( devExt->Device,
                                  &dmaConfig,
                                  WDF_NO_OBJECT_ATTRIBUTES,
                                  &devExt->DmaEnabler );

    if (!NT_SUCCESS (status)) {
        TraceEvents(TRACE_LEVEL_ERROR, AMCC_TRACE_INIT,
                       "WdfDmaEnablerCreate failed %08X", status);
        return status;
    }

    return STATUS_SUCCESS;
}
Пример #4
0
BOOLEAN
AmccPciProgramDma(
    __in WDFDMATRANSACTION       Transaction,
    __in WDFDEVICE               Device,
    __in PVOID                   Context,
    __in WDF_DMA_DIRECTION       Direction,
    __in PSCATTER_GATHER_LIST    SgList
    )
/*++

Routine Description:

Arguments:

Return Value:

--*/
{
    AMCC_DEVICE_EXTENSION  * devExt;
    ULONG                    address;
    ULONG                    length;

    union {
        ULONG      ulong;
        MCSR_REG   bits;
    } mcsr;

    union {
        ULONG      ulong;
        INTCSR_REG bits;
    } intcsr;


    UNREFERENCED_PARAMETER( Transaction );
    UNREFERENCED_PARAMETER( Context );

    //
    // Reestablish working parameters.
    //
    devExt = AmccPciGetDevExt(Device);

    //
    // The S5933 used only 32-bit packet mode DMA operations.
    //
    ASSERT(SgList->NumberOfElements == 1);
    ASSERT(SgList->Elements[0].Address.HighPart == 0);

    //
    // Only the first Scatter/Gather element is relevant for packet mode.
    // S5933 only does 32-bit DMA transfer operations: only low part of
    // physical address is usable.
    //
    address = SgList->Elements[0].Address.LowPart;
    length  = SgList->Elements[0].Length;

    TraceEvents(TRACE_LEVEL_INFORMATION, AMCC_TRACE_IO,
                "Address 0x%08X, Length %d", address, length);

    //
    // Read the Master Control/Status Register (MCSR) and
    // the Interrupt Control/Status Register (INTCSR).
    //
    mcsr.ulong   = READ_PORT_ULONG((PULONG) &(devExt->Regs->MCSR));
    intcsr.ulong = READ_PORT_ULONG((PULONG) &devExt->Regs->INTCSR);

    //
    // Setup read or write transfer registers.
    //
    // NOTE: The S5933 calls a transfer from memory to the device a "read".
    //
    if (Direction == WdfDmaDirectionWriteToDevice) {

        mcsr.bits.ReadFifoMgmtScheme = TRUE;
        mcsr.bits.ReadTransferEnable = TRUE;

        intcsr.bits.IntOnReadTransferComplete = TRUE;

        WRITE_PORT_ULONG((PULONG) &devExt->Regs->MRTC, length);
        WRITE_PORT_ULONG((PULONG) &devExt->Regs->MRAR, address);

    } else {

        mcsr.bits.WriteFifoMgmtScheme = TRUE;
        mcsr.bits.WriteTransferEnable = TRUE;

        intcsr.bits.IntOnWriteTransferComplete = TRUE;

        WRITE_PORT_ULONG((PULONG) &devExt->Regs->MWTC, length);
        WRITE_PORT_ULONG((PULONG) &devExt->Regs->MWAR, address);
    }

    //
    // Write modified INTCSR to enable the appropriate interrupt and
    // the MCSR to actually start the transfer.
    //
    WRITE_PORT_ULONG((PULONG) &devExt->Regs->INTCSR, intcsr.ulong);
    WRITE_PORT_ULONG((PULONG) &devExt->Regs->MCSR,   mcsr.ulong);

    return TRUE;
}
Пример #5
0
VOID
AmccPciEvtInterruptDpc(
    __in WDFINTERRUPT WdfInterrupt,
    __in WDFOBJECT    WdfDevice
    )
/*++

Routine Description:

    DPC callback for ISR.

Arguments:

    WdfInterrupt - Handle to the framework interrupt object

    WdfDevice - Associated device object.

Return Value:

--*/
{
    PAMCC_DEVICE_EXTENSION   devExt;
    WDFREQUEST               request;
    REQUEST_CONTEXT        * transfer;
    NTSTATUS                 status;
    size_t                   transferred;
    BOOLEAN                  transactionComplete;

    UNREFERENCED_PARAMETER( WdfInterrupt );

    devExt = AmccPciGetDevExt(WdfDevice);

    //
    // Retreive request and transfer.
    //
    request  = devExt->CurrentRequest;
    transfer = GetRequestContext(request);

    //
    // Check to see if the request is cancelled by the system. While
    // we are DMAing a large buffer into multiple transaction,
    // there is good possibilty for the request to get cancelled because
    // the originator of the request exited or cancelled the I/O explicitly.
    //
    if(WdfRequestIsCanceled(request)) {
        TraceEvents(TRACE_LEVEL_ERROR, AMCC_TRACE_IO,
                                    "Aborted DMA transaction 0x%p",  request);
        WdfObjectDelete( transfer->DmaTransaction );
        devExt->CurrentRequest = NULL;
        WdfRequestComplete(request, STATUS_CANCELLED);
        return;
    }

    //
    // The boolean transactionComplete indicates whether the transaction has
    // exited the transfer state, e.g. no further transfers are scheduled.
    //
    // If transactionComplete == FALSE, then the next DMA transfer has been
    // scheduled, e.g. the next interrrupt will drive the ISR again.
    //
    // If transactionComplete == TRUE, then status indicates the reason;
    // SUCCESS is the nomative case, while non-SUCCESS indicates the
    // DMA transaction failed for "status" reason.
    //
    transactionComplete = WdfDmaTransactionDmaCompleted( transfer->DmaTransaction,
                                                     &status );

    if (transactionComplete) {

        ASSERT(status != STATUS_MORE_PROCESSING_REQUIRED);

        //
        // No more data: request is complete
        //
        TraceEvents(TRACE_LEVEL_INFORMATION, AMCC_TRACE_IO,
                    "Request %p completed: status %X",
                    request, status);

        //
        // Get the final bytes transferred count.
        //
        transferred =
            WdfDmaTransactionGetBytesTransferred( transfer->DmaTransaction );

        TraceEvents(TRACE_LEVEL_INFORMATION, AMCC_TRACE_IO,
                    "Bytes transfered %d", (int) transferred );

        //
        // Delete this DmaTransaction transaction.
        //
        WdfObjectDelete( transfer->DmaTransaction );

        //
        // Clean-up for this request.
        //
        devExt->CurrentRequest = NULL;

        //
        // Complete this IO request.
        //
        WdfRequestCompleteWithInformation( request,
                                           status,
                                           (NT_SUCCESS(status)) ?
                                           transferred : 0 );
    }

}
Пример #6
0
VOID
AmccPciEvtIoDefault(
    __in WDFQUEUE       Queue,
    __in WDFREQUEST     Request
    )
/*++

Routine Description:

    Start the IRP on the device.  This driver allows only one I/O to
    be active on the adapter at any one time.  If multiple I/Os are sent
    to the driver, they will be queued and completed as they complete on
    the adapter (one IRP per interrupt).

Arguments:

    Queue - Default queue handle
    Request - Handle to the write request
    Parameters - Contains current stack location information from the IRP

Return Value:

    None

--*/
{
    PAMCC_DEVICE_EXTENSION    devExt;
    REQUEST_CONTEXT         * transfer;
    NTSTATUS                  status;
    size_t                    length;
    WDF_DMA_DIRECTION         direction;
    WDFDMATRANSACTION         dmaTransaction;
    WDF_REQUEST_PARAMETERS    params;

    WDF_REQUEST_PARAMETERS_INIT(&params);

    WdfRequestGetParameters(
        Request,
        &params
        );

    //
    // Get the device extension.
    //
    devExt = AmccPciGetDevExt(WdfIoQueueGetDevice( Queue ));

    //
    // Validate and gather parameters.
    //
    switch (params.Type) {

        case WdfRequestTypeRead:
            length    = params.Parameters.Read.Length;
            direction = WdfDmaDirectionReadFromDevice;
            break;

        case WdfRequestTypeWrite:
            length    = params.Parameters.Write.Length;
            direction = WdfDmaDirectionWriteToDevice;
            break;

        default:
            TraceEvents(TRACE_LEVEL_WARNING, AMCC_TRACE_IO,
                        "Request type not Read or Write\n");
            WdfRequestComplete(Request, STATUS_INVALID_PARAMETER);
            return;
    }

    TraceEvents(TRACE_LEVEL_INFORMATION, AMCC_TRACE_IO,
                "Request %p: %s %d bytes",
                Request, (direction)?"Write":"Read", (ULONG)length);

    //
    // The length must be non-zero.
    //
    if (length == 0) {
        TraceEvents(TRACE_LEVEL_WARNING, AMCC_TRACE_IO,
                    "Zero transfer length input to read/write");
        WdfRequestComplete(Request, STATUS_INVALID_PARAMETER);
        return;
    }

    transfer = GetRequestContext(Request);

    //
    // Create new DmaRequst to conduct this DMA transaction.
    //
    status = WdfDmaTransactionCreate( devExt->DmaEnabler,
                                      WDF_NO_OBJECT_ATTRIBUTES,
                                      &dmaTransaction );

    if(!NT_SUCCESS(status)) {
        TraceEvents(TRACE_LEVEL_ERROR, AMCC_TRACE_IO,
                    "WdfDmaRequestCreate failed: %X", status);
        WdfRequestComplete(Request, status);
        return;
    }

    //
    // Create new DmaTransaction.
    //
    status = WdfDmaTransactionInitializeUsingRequest( dmaTransaction,
                                                      Request,
                                                      AmccPciProgramDma,
                                                      direction );

    if(!NT_SUCCESS(status)) {
        TraceEvents(TRACE_LEVEL_ERROR, AMCC_TRACE_IO,
                    "WdfDmaRequestInitializeWithRequest failed: %X",
                    status);

        WdfObjectDelete(dmaTransaction);

        WdfRequestComplete(Request, status);
        return;
    }

    //
    // Fill transfer context structure
    //
    transfer->Request        = Request;
    transfer->DmaTransaction = dmaTransaction;

    //
    // Save the current Request as the "in-progress" request.
    //
    devExt->CurrentRequest = Request;

    //
    // Execute this dmaTransaction transaction.
    //
    status = WdfDmaTransactionExecute( dmaTransaction, WDF_NO_CONTEXT);
    if (!NT_SUCCESS(status)) {
        TraceEvents(TRACE_LEVEL_ERROR, AMCC_TRACE_IO,
                    "WdfDmaTransactionExecute failed: %X",
                    status);

        WdfObjectDelete(dmaTransaction);
        WdfRequestComplete(Request, status);
        return;
    }

    return;
}
Пример #7
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;
}