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

📄 apifunctions.c

📁 本压缩包为作者截取的PCI9054的WDM官方驱动源码。欢迎下载。
💻 C
📖 第 1 页 / 共 5 页
字号:
        pdx,
        OffsetDmaBase + 0xc,
        pDmaData->TransferCount
        );

    // Write Descriptor Pointer
    RegValue = (pDmaData->TerminalCountIntr << 2) |
               (pDmaData->LocalToPciDma     << 3);

    PLX_REG_WRITE(
        pdx,
        OffsetDmaBase + 0x10,
        RegValue
        );

    // Write the high PCI address
    PLX_REG_WRITE(
        pdx,
        OffsetPciAddrHigh,
        pDmaData->PciAddrHigh
        );

    // Enable DMA Channel
    RegValue =
        PLX_REG_READ(
            pdx,
            PCI9054_DMA_COMMAND_STAT
            );

    PLX_REG_WRITE(
        pdx,
        PCI9054_DMA_COMMAND_STAT,
        RegValue | ((1 << 0) << shift)
        );

    KeReleaseSpinLock(
        &(pdx->Lock_HwAccess),
        OriginalIrqL
        );

    DebugPrintf(("Starting DMA transfer...\n"));

    // Start DMA
    PLX_REG_WRITE(
        pdx,
        PCI9054_DMA_COMMAND_STAT,
        RegValue | (((1 << 0) | (1 << 1)) << shift)
        );

    return ApiSuccess;
}




/******************************************************************************
 *
 * Function   :  PlxDmaBlockChannelClose
 *
 * Description:  Close a previously opened channel
 *
 ******************************************************************************/
RETURN_CODE
PlxDmaBlockChannelClose(
    DEVICE_EXTENSION *pdx,
    DMA_CHANNEL       channel,
    BOOLEAN           bCheckInProgress
    )
{
    U8    i;
    U32   RegValue;
    KIRQL OriginalIrqL;


    // Verify valid DMA channel
    switch (channel)
    {
        case PrimaryPciChannel0:
            i = 0;
            break;

        case PrimaryPciChannel1:
            i = 1;
            break;

        default:
            DebugPrintf(("ERROR - Invalid DMA channel\n"));
            return ApiDmaChannelInvalid;
    }

    if (bCheckInProgress)
    {
        // Verify that DMA is not in progress
        RegValue =
            PLX_REG_READ(
                pdx,
                PCI9054_DMA_COMMAND_STAT
                );

        if (channel == PrimaryPciChannel1)
            RegValue = RegValue >> 8;

        if ((RegValue & (1 << 4)) == 0)
        {
            if (RegValue & (1 << 0))
                return ApiDmaInProgress;
            else
                return ApiDmaPaused;
        }
    }

    KeAcquireSpinLock(
        &(pdx->Lock_DmaChannel),
        &OriginalIrqL
        );

    // Verify DMA Channel was opened correctly
    if (pdx->DmaInfo[i].state != DmaStateBlock)
    {
        DebugPrintf(("ERROR - DMA Channel has not been opened for Block DMA\n"));

        KeReleaseSpinLock(
            &(pdx->Lock_DmaChannel),
            OriginalIrqL
            );

        return ApiDmaChannelUnavailable;
    }

    // Close the channel
    pdx->DmaInfo[i].state = DmaStateClosed;

    // Clear owner information
    pdx->DmaInfo[i].pOwner = NULL;

    KeReleaseSpinLock(
        &(pdx->Lock_DmaChannel),
        OriginalIrqL
        );

    return ApiSuccess;
}




/******************************************************************************
 *
 * Function   :  PlxDmaSglChannelOpen
 *
 * Description:  Open a DMA channel for SGL mode
 *
 ******************************************************************************/
RETURN_CODE
PlxDmaSglChannelOpen(
    DEVICE_EXTENSION *pdx,
    DMA_CHANNEL       channel,
    DMA_CHANNEL_DESC *pDesc,
    VOID             *pOwner
    )
{
    U8           i;
    U32          mode;
    U32          RegValue;
    U32          threshold;
    KIRQL        OriginalIrqL;
    PLX_REG_DATA RegData;


    // Verify valid DMA channel
    switch (channel)
    {
        case PrimaryPciChannel0:
            i = 0;
            break;

        case PrimaryPciChannel1:
            i = 1;
            break;

        default:
            DebugPrintf(("ERROR - Invalid DMA channel\n"));
            return ApiDmaChannelInvalid;
    }

    KeAcquireSpinLock(
        &(pdx->Lock_DmaChannel),
        &OriginalIrqL
        );

    // Verify that we can open the channel
    if (pdx->DmaInfo[i].state != DmaStateClosed)
    {
        DebugPrintf(("ERROR - DMA channel already opened\n"));

        KeReleaseSpinLock(
            &(pdx->Lock_DmaChannel),
            OriginalIrqL
            );

        return ApiDmaChannelUnavailable;
    }

    // Open the channel
    pdx->DmaInfo[i].state = DmaStateSgl;

    // Record the Owner
    pdx->DmaInfo[i].pOwner = pOwner;

    // Mark DMA as free
    pdx->DmaInfo[i].bPending = FALSE;

    KeReleaseSpinLock(
        &(pdx->Lock_DmaChannel),
        OriginalIrqL
        );

    // Setup for synchronized access to Interrupt register
    RegData.pdx         = pdx;
    RegData.offset      = PCI9054_INT_CTRL_STAT;
    RegData.BitsToClear = 0;

    KeAcquireSpinLock(
        &(pdx->Lock_HwAccess),
        &OriginalIrqL
        );

    // Get DMA priority
    RegValue =
        PLX_REG_READ(
            pdx,
            PCI9054_LOCAL_DMA_ARBIT
            );

    // Clear priority
    RegValue &= ~((1 << 20) | (1 << 19));

    // Set the priority
    switch (pDesc->DmaChannelPriority)
    {
        case Channel0Highest:
            PLX_REG_WRITE(
                pdx,
                PCI9054_LOCAL_DMA_ARBIT,
                RegValue | (1 << 19)
                );
            break;

        case Channel1Highest:
            PLX_REG_WRITE(
                pdx,
                PCI9054_LOCAL_DMA_ARBIT,
                RegValue | (1 << 20)
                );
            break;

        case Rotational:
            PLX_REG_WRITE(
                pdx,
                PCI9054_LOCAL_DMA_ARBIT,
                RegValue
                );
            break;

        default:
            DebugPrintf((
                "WARNING - DmaChannelOpen() invalid priority state\n"
                ));
            break;
    }


    threshold =
        (pDesc->TholdForIopWrites <<  0) |
        (pDesc->TholdForIopReads  <<  4) |
        (pDesc->TholdForPciWrites <<  8) |
        (pDesc->TholdForPciReads  << 12);

    mode =
        (1 <<  9) |                  // Enable Chaining
        (1 << 10) |                  // Enable DMA Done interrupt
        (1 << 17) |                  // Route interrupts to PCI
        (0 << 18) |                  // Disable Dual-Addressing
        (pDesc->IopBusWidth              <<  0) |
        (pDesc->WaitStates               <<  2) |
        (pDesc->EnableReadyInput         <<  6) |
        (pDesc->EnableBTERMInput         <<  7) |
        (pDesc->EnableIopBurst           <<  8) |
        (pDesc->HoldIopAddrConst         << 11) |
        (pDesc->DemandMode               << 12) |
        (pDesc->EnableWriteInvalidMode   << 13) |
        (pDesc->EnableDmaEOTPin          << 14) |
        (pDesc->DmaStopTransferMode      << 15);

    // Keep track if local address should remain constant
    if (pDesc->HoldIopAddrConst)
        pdx->DmaInfo[i].bLocalAddrConstant = TRUE;
    else
        pdx->DmaInfo[i].bLocalAddrConstant = FALSE;

    // Get DMA Threshold
    RegValue =
        PLX_REG_READ(
            pdx,
            PCI9054_DMA_THRESHOLD
            );

    if (channel == PrimaryPciChannel0)
    {
        // Setup threshold
        PLX_REG_WRITE(
            pdx,
            PCI9054_DMA_THRESHOLD,
            (RegValue & 0xffff0000) | threshold
            );

        // Write DMA mode
        PLX_REG_WRITE(
            pdx,
            PCI9054_DMA0_MODE,
            mode
            );

        // Enable DMA Channel interrupt
        RegData.BitsToSet = (1 << 18);
        KeSynchronizeExecution(
            pdx->pInterruptObject,
            PlxSynchronizedRegisterModify,
            &RegData
            );

        // Clear Dual Address cycle register
        PLX_REG_WRITE(
            pdx,
            PCI9054_DMA0_PCI_DAC,
            0
            );
    }
    else
    {
        // Setup threshold
        PLX_REG_WRITE(
            pdx,
            PCI9054_DMA_THRESHOLD,
            (RegValue & 0x0000ffff) | (threshold << 16)
            );

        // Write DMA mode
        PLX_REG_WRITE(
            pdx,
            PCI9054_DMA1_MODE,
            mode
            );

        // Enable DMA Channel interrupt
        RegData.BitsToSet = (1 << 19);
        KeSynchronizeExecution(
            pdx->pInterruptObject,
            PlxSynchronizedRegisterModify,
            &RegData
            );

        // Clear Dual Address cycle register
        PLX_REG_WRITE(
            pdx,
            PCI9054_DMA1_PCI_DAC,
            0
            );
    }

    KeReleaseSpinLock(
        &(pdx->Lock_HwAccess),
        OriginalIrqL
        );

    return ApiSuccess;
}




/******************************************************************************
 *
 * Function   :  PlxDmaSglTransfer
 *
 * Description:  Performs a DMA SGL transfer
 *
 ******************************************************************************/
RETURN_CODE
PlxDmaSglTransfer(
    DEVICE_EXTENSION     *pdx,
    DMA_CHANNEL           channel,
    DMA_TRANSFER_ELEMENT *pDmaData
    )
{
    U8    i;
    U8    shift;
    U16   OffsetDesc;
    U32   RegValue;
    U32   SglPciAddress;
    KIRQL OriginalIrqL;


    // Verify valid DMA channel
    switch (channel)
    {
        case PrimaryPciChannel0:
            i          = 0;
            shift      = 0;
            OffsetDesc = PCI9054_DMA0_DESC_PTR;
            break;

        case PrimaryPciChannel1:
            i          = 1;
            shift      = 8;
            OffsetDesc = PCI9054_DMA1_DESC_PTR;
            break;

        default:
            DebugPrintf(("ERROR - Invalid DMA channel\n"));
            return ApiDmaChannelInvalid;
    }

    // Verify that DMA is not in progress
    RegValue =
        PLX_REG_READ(
            pdx,
            PCI9054_DMA_COMMAND_STAT
            );

    if ((RegValue & ((1 << 4) << shift)) == 0)
    {
        DebugPrintf(("ERROR - DMA Channel is currently active\n"));
        return ApiDmaInProgress;
    }

    KeAcquireSpinLock(
        &(pdx->Lock_DmaChannel),
        &OriginalIrqL
        );

    // Verify DMA Channel was opened correctly
    if (pdx->DmaInfo[i].state != DmaStateSgl)
    {
        DebugPrintf(("ERROR - DMA channel has not been opened for SGL DMA\n"));

        KeReleaseSpinLock(
            &(pdx->Lock_DmaChannel),
            OriginalIrqL
            );

        return ApiDmaChannelUnavailable;
    }

    // Verify a DMA transfer is not pending
    if (pdx->DmaInfo[i].bPending)
    {
        DebugPrintf((
            "ERROR - A DMA transfer is currently in progress\n"
            ));

        KeReleaseSpinLock(
            &(pdx->Lock_DmaChannel),
            OriginalIrqL
            );

        return ApiDmaInProgress;
    }

    // Set the DMA pending flag
    pdx->DmaInfo[i].bPending = TRUE;

    KeReleaseSpinLock(
        &(pdx->Lock_DmaChannel),
        OriginalIrqL
        );

    SglPciAddress =
        PlxLockBufferAndBuildSgl(
            pdx,
            i,
            pDmaData
            );

    if (SglPciAddress == 0)
    {
        DebugPrintf(("ERROR - Unable to lock buffer and build SGL list\n"));
        pdx->DmaInfo[i].bPending = FALSE;
        return ApiDmaSglBuildFailed;
    }

    KeAcquireSpinLock(
        &(pdx->Lock_HwAccess),
        &OriginalIrqL
        );

    // Write SGL physical address & set descriptors in PCI space
    PLX_REG_WRITE(
        pdx,
        OffsetDesc,
        SglPciAddress | (1 << 0)
        );

    RegValue =
        PLX_REG_READ(
            pdx,
            PCI9054_DMA_COMMAND_STAT
            );

    // Enable DMA channel
    PLX_REG_WRITE(
        pdx,
        PCI9054_DMA_COMMAND_STAT,
        RegValue | ((1 << 0) << shift)
        );

    KeReleaseSpinLock(
        &(pdx->Lock_HwAccess),
        OriginalIrqL
        );

    DebugPrintf(("Starting DMA transfer...\n"));

    // Start DMA
    PLX_REG_WRITE(
        pdx,
        PCI9054_DMA_COMMAND_STAT,
        RegValue | (((1 << 0) | (1 << 1)) << shift)
        );

    return ApiSuccess;
}




/******************************************************************************
 *
 * Function   :  PlxDmaSglChannelClose
 *
 * Description:  Close a previously opened channel
 *
 ********************************************************************

⌨️ 快捷键说明

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