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

📄 apifunctions.c

📁 本压缩包为作者截取的PCI9054的WDM官方驱动源码。欢迎下载。
💻 C
📖 第 1 页 / 共 5 页
字号:
}




/******************************************************************************
 *
 * Function   :  PlxMuOutboundPortWrite
 *
 * Description:  Writes to the outbound port with a free message frame
 *
 ******************************************************************************/
RETURN_CODE
PlxMuOutboundPortWrite(
    DEVICE_EXTENSION *pdx,
    U32               Frame
    )
{
    PLX_REG_WRITE(
        pdx,
        0x44,
        Frame
        );

    return ApiSuccess;
}




/******************************************************************************
 *
 * Function   :  PlxDmaControl
 *
 * Description:  Control the DMA engine
 *
 ******************************************************************************/
RETURN_CODE
PlxDmaControl(
    DEVICE_EXTENSION *pdx,
    DMA_CHANNEL       channel,
    DMA_COMMAND       command
    )
{
    U8  i;
    U8  shift;
    U32 RegValue;


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

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

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

    // Verify that this channel has been opened
    if (pdx->DmaInfo[i].state == DmaStateClosed)
    {
        DebugPrintf(("ERROR - DMA Channel has not been opened\n"));
        return ApiDmaChannelUnavailable;
    }

    switch (command)
    {
        case DmaPause:
            // Pause the DMA Channel
            RegValue =
                PLX_REG_READ(
                    pdx,
                    PCI9054_DMA_COMMAND_STAT
                    );

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

            // Check if the transfer has completed
            RegValue =
                PLX_REG_READ(
                    pdx,
                    PCI9054_DMA_COMMAND_STAT
                    );

            if (RegValue & ((1 << 4) << shift))
                return ApiDmaDone;
            break;

        case DmaResume:
            // Verify that the DMA Channel is paused
            RegValue =
                PLX_REG_READ(
                    pdx,
                    PCI9054_DMA_COMMAND_STAT
                    );

            if ((RegValue & (((1 << 4) | (1 << 0)) << shift)) == 0)
            {
                PLX_REG_WRITE(
                    pdx,
                    PCI9054_DMA_COMMAND_STAT,
                    RegValue | ((1 << 0) << shift)
                    );
            }
            else
            {
                return ApiDmaNotPaused;
            }
            break;

        case DmaAbort:
            // Pause the DMA Channel
            RegValue =
                PLX_REG_READ(
                    pdx,
                    PCI9054_DMA_COMMAND_STAT
                    );

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

            // Check if the transfer has completed
            RegValue =
                PLX_REG_READ(
                    pdx,
                    PCI9054_DMA_COMMAND_STAT
                    );

            if (RegValue & ((1 << 4) << shift))
                return ApiDmaDone;

            // Abort the transfer (should cause an interrupt)
            PLX_REG_WRITE(
                pdx,
                PCI9054_DMA_COMMAND_STAT,
                RegValue | ((1 << 2) << shift)
                );
            break;

        default:
            return ApiDmaCommandInvalid;
    }

    return ApiSuccess;
}




/******************************************************************************
 *
 * Function   :  PlxDmaStatus
 *
 * Description:  Get status of a DMA channel
 *
 ******************************************************************************/
RETURN_CODE
PlxDmaStatus(
    DEVICE_EXTENSION *pdx,
    DMA_CHANNEL       channel
    )
{
    U32 RegValue;


    // Verify valid DMA channel
    switch (channel)
    {
        case PrimaryPciChannel0:
        case PrimaryPciChannel1:
            break;

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

    // Return the current DMA status

    RegValue =
        PLX_REG_READ(
            pdx,
            PCI9054_DMA_COMMAND_STAT
            );

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

    if ((RegValue & ((1 << 4) | (1 << 0))) == 0)
        return ApiDmaPaused;

    if (RegValue & (1 << 4))
        return ApiDmaDone;

    return ApiDmaInProgress;
}




/******************************************************************************
 *
 * Function   :  PlxDmaBlockChannelOpen
 *
 * Description:  Requests usage of a device's DMA channel
 *
 ******************************************************************************/
RETURN_CODE
PlxDmaBlockChannelOpen(
    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 = DmaStateBlock;

    // 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 =
        (0 <<  9) |                  // No Chaining
        (1 << 10) |                  // Enable DMA Done interrupt
        (1 << 17) |                  // Route interrupts to PCI
        (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) |
        (pDesc->EnableDualAddressCycles  << 18);

    // 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
            );
    }
    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
            );
    }

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

    return ApiSuccess;
}




/******************************************************************************
 *
 * Function   :  PlxDmaBlockTransfer
 *
 * Description:  Performs DMA block transfer
 *
 ******************************************************************************/
RETURN_CODE
PlxDmaBlockTransfer(
    DEVICE_EXTENSION     *pdx,
    DMA_CHANNEL           channel,
    DMA_TRANSFER_ELEMENT *pDmaData
    )
{
    U8    i;
    U8    shift;
    U16   OffsetDmaBase;
    U16   OffsetPciAddrHigh;
    U32   RegValue;
    KIRQL OriginalIrqL;


    // Setup transfer registers
    switch (channel)
    {
        case PrimaryPciChannel0:
            i                 = 0;
            shift             = 0;
            OffsetDmaBase     = PCI9054_DMA0_MODE;
            OffsetPciAddrHigh = PCI9054_DMA0_PCI_DAC;
            break;

        case PrimaryPciChannel1:
            i                 = 1;
            shift             = 8;
            OffsetDmaBase     = PCI9054_DMA1_MODE;
            OffsetPciAddrHigh = PCI9054_DMA1_PCI_DAC;
            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 != DmaStateBlock)
    {
        DebugPrintf(("ERROR - DMA Channel has not been opened for Block DMA\n"));

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

        return ApiDmaChannelUnavailable;
    }

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

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

    // Make sure DMA done interrupt is enabled
    RegValue =
        PLX_REG_READ(
            pdx,
            OffsetDmaBase
            );

    RegValue |= (1 << 10);

    PLX_REG_WRITE(
        pdx,
        OffsetDmaBase,
        RegValue
        );

    // Write PCI Address
    PLX_REG_WRITE(
        pdx,
        OffsetDmaBase + 0x4,
        pDmaData->u.PciAddrLow
        );

    // Write Local Address
    PLX_REG_WRITE(
        pdx,
        OffsetDmaBase + 0x8,
        pDmaData->LocalAddr
        );

    // Write Transfer Count
    PLX_REG_WRITE(

⌨️ 快捷键说明

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