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

📄 dispatch.cpp

📁 在vxworks下
💻 CPP
📖 第 1 页 / 共 5 页
字号:
								BOOLEAN     bCheckInProgress)
{
    ULONG lStatus;
    KIRQL OriginalIrqL;
	ULONG lRegAddress = (ULONG)pdx->LocalRegisterMemBase;

    // Verify valid DMA channel
    if (lDmaChannel > 1)
    {
        KdPrint((DBG_NAME "ERROR - Invalid DMA channel\n"));
        return RC_DMA_CHANNEL_INVALID;	
    }


    if (bCheckInProgress)
    {
        // Verify that DMA is not in progress
        lStatus = READ_REGISTER_ULONG((ULONG *)(lRegAddress + PCI9054_DMA_COMMAND_STAT));

        if (lDmaChannel == 1)
            lStatus = lStatus >> 8;

        if ((lStatus & (1 << 4)) == 0)
        {
            if (lStatus & (1 << 0))
                return RC_DMA_IN_PROGRESS;
            else
                return RC_DMA_PAUSED;
        }
    }

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

    // Verify DMA Channel was opened correctly
    if (pdx->DmaInfo[lDmaChannel].State != DMA_STATE_BLOCK)
    {
        KdPrint((DBG_NAME "ERROR - DMA Channel has not been opened for Block DMA\n"));

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

	//	return RC_DMA_CHANNEL_UNAVAILABLE;	
    }

    // Close the channel
    pdx->DmaInfo[lDmaChannel].State = DMA_STATE_CLOSED;

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

    return RC_SUCCESS;
}


/******************************************************************************
 *
 * Function   :  PlxDmaControl
 *
 * Description:  Control the DMA engine
 *
 ******************************************************************************/
RETURN_CODE DmaControl(DEVICE_EXTENSION *pdx,
					   ULONG			lDmaChannel,
					   DMA_COMMAND		DmaCommand)
{
    unsigned char cShift = 0;
    ULONG lDmaStatus;
	ULONG lRegAddress = (ULONG)pdx->LocalRegisterMemBase;

    // Verify valid DMA channel
    if (lDmaChannel > 1)
    {
        KdPrint((DBG_NAME "ERROR - Invalid DMA channel\n"));
        return RC_DMA_CHANNEL_INVALID;
    }

	if (lDmaChannel == 1)
		cShift = 8;

    // Verify that this channel has been opened
    if (pdx->DmaInfo[lDmaChannel].State == DMA_STATE_CLOSED)
    {
        KdPrint((DBG_NAME "ERROR - DMA Channel has not been opened\n"));
        return RC_DMA_CHANNEL_UNAVAILABLE;
    }

	lDmaStatus = READ_REGISTER_ULONG((ULONG *)(lRegAddress + PCI9054_DMA_COMMAND_STAT));
    switch (DmaCommand)
    {
        case DMA_PAUSE:
            // Pause the DMA Channel
			WRITE_REGISTER_ULONG((ULONG *)(lRegAddress + PCI9054_DMA_COMMAND_STAT), 
								lDmaStatus & ~((1 << 0) << cShift));

            // Check if the transfer has completed
            lDmaStatus = READ_REGISTER_ULONG((ULONG *)(lRegAddress + PCI9054_DMA_COMMAND_STAT));

            if (lDmaStatus & ((1 << 4) << cShift))
                return RC_DMA_DONE;
            break;
        case DMA_RESUME:
            // Verify that the DMA Channel is paused
            if ((lDmaStatus & (((1 << 4) | (1 << 0)) << cShift)) == 0)
            {
				WRITE_REGISTER_ULONG((ULONG *)(lRegAddress + PCI9054_DMA_COMMAND_STAT), 
								lDmaStatus & ~((1 << 0) << cShift));
            }
            else
            {
                return RC_DMA_NOT_PAUSED;
            }
            break;
        case DMA_ABORT:
            // Pause the DMA Channel
			WRITE_REGISTER_ULONG((ULONG *)(lRegAddress + PCI9054_DMA_COMMAND_STAT), 
								lDmaStatus & ~((1 << 0) << cShift));
            // Check if the transfer has completed
			lDmaStatus = READ_REGISTER_ULONG((ULONG *)(lRegAddress + PCI9054_DMA_COMMAND_STAT));

            if (lDmaStatus & ((1 << 4) << cShift))
                return RC_DMA_DONE;

            // Abort the transfer (should cause an interrupt)
			WRITE_REGISTER_ULONG((ULONG *)(lRegAddress + PCI9054_DMA_COMMAND_STAT), 
								lDmaStatus | ((1 << 2) << cShift));

            // If Shuttle transfer, release resources used
            if (pdx->DmaInfo[lDmaChannel].State == DMA_STATE_SHUTTLE)
            {
                DmaShuttleTransferComplete(pdx, lDmaChannel);
            }
            break;

        default:
            return RC_DMA_COMMAND_INVALID;
    }

    return RC_SUCCESS;
}

/******************************************************************************
 *
 * Function   :  PlxShuttleDmaTransferComplete
 *
 * Description:  Perform any necessary cleanup after a Shuttle DMA transfer.
 *
 ******************************************************************************/
VOID DmaShuttleTransferComplete(DEVICE_EXTENSION *pdx,
								ULONG lDmaChannel)
{
/*	KIRQL OriginalIrqL;

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

	// Unlock data buffer and free MDL
	if (pdx->DmaInfo[lDmaChannel].pMdl != NULL)
	{
		MmUnlockPages(pdx->DmaInfo[lDmaChannel].pMdl);

		IoFreeMdl(pdx->DmaInfo[lDmaChannel].pMdl);

		pdx->DmaInfo[lDmaChannel].pMdl = NULL;
	}

	// Release the SGL Descriptor buffer
	if (pdx->DmaInfo[lDmaChannel].pSgl != NULL)
	{
		DriverBufferFree(pdx->DmaInfo[lDmaChannel].pSgl);

		pdx->DmaInfo[lDmaChannel].pSgl = NULL;
	}

	KeReleaseSpinLock(&(pdx->DmaChannelLock), OriginalIrqL);
*/
}

/******************************************************************************
 *
 * Function   :  DmaGetStatus
 *
 * Description:  Get status of a DMA channel
 *
 ******************************************************************************/
RETURN_CODE DmaGetStatus(DEVICE_EXTENSION *pdx,
						 ULONG lDmaChannel)
{
	ULONG lDmaStatus;

    // Verify valid DMA channel
    if (lDmaChannel > 1)
    {
        KdPrint((DBG_NAME "ERROR - Invalid DMA channel\n"));
        return RC_DMA_CHANNEL_INVALID;
    }

    // Return the current DMA status
    lDmaStatus = READ_REGISTER_ULONG((ULONG *)(pdx->LocalRegisterMemBase + PCI9054_DMA_COMMAND_STAT));

    if (lDmaChannel == 1)
        lDmaStatus = lDmaStatus >> 8;

    if ((lDmaStatus & ((1 << 4) | (1 << 0))) == 0)
        return RC_DMA_PAUSED;

    if (lDmaStatus & (1 << 4))
        return RC_DMA_DONE;

    return RC_DMA_IN_PROGRESS;
}


/******************************************************************************
 *
 * Function   :  PlxDmaSglChannelOpen
 *
 * Description:  Requests usage of a device's DMA channel.
 *
 ******************************************************************************/
RETURN_CODE DmaOpenSglChannel(DEVICE_EXTENSION			*pdx,
							  ULONG						lDmaChannel,
							  DMA_CHANNEL_DESCRIPTION	*pDmaChannelDescription)
{
    ULONG		lMode = 0;
    ULONG		lRegValue = 0;
    ULONG		lThreshold = 0;
    KIRQL		OriginalIrqL;
    REG_DATA	RegData;

	ULONG lRegAddress = (ULONG)pdx->LocalRegisterMemBase;

    // Verify valid DMA channel
	if (lDmaChannel > 1)
	{
        KdPrint((DBG_NAME "ERROR - Invalid DMA channel\n"));
        return RC_DMA_CHANNEL_INVALID;
    }

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

    // Verify that we can open the channel
    if (pdx->DmaInfo[lDmaChannel].State != DMA_STATE_CLOSED)
    {
        KdPrint((DBG_NAME "ERROR - DMA channel already opened\n"));

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

        return RC_DMA_CHANNEL_UNAVAILABLE;
    }

    // Open the channel
    pdx->DmaInfo[lDmaChannel].State = DMA_STATE_SGL;

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

    // Setup for synchronized access to Interrupt register
	RegData.lRegAddress = (ULONG)pdx->LocalRegisterMemBase + PCI9054_INT_CTRL_STAT;
    RegData.lBitsToClear = 0;

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

    if (pDmaChannelDescription != NULL)
    {
        // Get DMA priority
        lRegValue = READ_REGISTER_ULONG((ULONG *)(lRegAddress + PCI9054_MODE_DMA_ARBITRATION));
        // Clear priority
        lRegValue &= ~((1 << 20) | (1 << 19));

        // Set the priority
        switch (pDmaChannelDescription->DmaChannelPriority)
        {
            case Channel0Highest:
				WRITE_REGISTER_ULONG((ULONG *)(lRegAddress + PCI9054_MODE_DMA_ARBITRATION), 
									lRegValue | (1 << 19));
                break;
            case Channel1Highest:
				WRITE_REGISTER_ULONG((ULONG *)(lRegAddress + PCI9054_MODE_DMA_ARBITRATION), 
									lRegValue | (1 << 20));
                break;
            case Rotational:
				WRITE_REGISTER_ULONG((ULONG *)(lRegAddress + PCI9054_MODE_DMA_ARBITRATION), 
									lRegValue);
                break;
            default:
                KdPrint((DBG_NAME "WARNING - DmaChannelOpen() invalid priority state.\n"));
        }

        lThreshold =(pDmaChannelDescription->PciToLocalAlmostFull <<  0) |
					(pDmaChannelDescription->LocalToPciAlmostEmpty<<  4) |
					(pDmaChannelDescription->LocalToPciAlmostFull <<  8) |
					(pDmaChannelDescription->PciToLocalAlmostEmpty<< 12);
		lMode =	(1 <<  9) |                  // Enable Chaining
				(1 << 10) |                  // Enable DMA Done interrupt
				(1 << 17) |                  // Route interrupts to PCI
				(0 << 18) |                  // Disable Dual-Addressing
				(pDmaChannelDescription->LocalBusWidth					<<  0) |
				(pDmaChannelDescription->InternalWaitStates				<<  2) |
				(pDmaChannelDescription->ReadyInputEnable				<<  6) |
				(pDmaChannelDescription->BTERMInputEnable				<<  7) |
				(pDmaChannelDescription->LocalBurstEnable				<<  8) |
				(pDmaChannelDescription->LocalAddressingMode			<< 11) |
				(pDmaChannelDescription->DemandMode						<< 12) |
				(pDmaChannelDescription->MemoryWriteAndInvalidateMode	<< 13) |
				(pDmaChannelDescription->DmaEOTPinEnable				<< 14) |
				(pDmaChannelDescription->FastSlowTerminateModeSelect	<< 15);

        // Keep track if local address should remain constant
		if (pDmaChannelDescription->LocalAddressingMode)
			pdx->DmaInfo[lDmaChannel].HoldLocalAddressConstant = TRUE;

        // Get DMA Threshold
		lRegValue = READ_REGISTER_ULONG((ULONG *)(lRegAddress + PCI9054_DMA_THRESHOLD));

        if (lDmaChannel == 0)	//Channel 0
        {
			// Setup threshold
			WRITE_REGISTER_ULONG((ULONG *)(lRegAddress + PCI9054_DMA_THRESHOLD), 
								(lRegValue & 0xffff0000) | lThreshold);
            // Write DMA mode
			WRITE_REGISTER_ULONG((ULONG *)(lRegAddress + PCI9054_DMA0_MODE), 
								lMode);
            // Enable PCI & DMA Channel interrupts
            RegData.lBitsToSet = (1 << 8) | (1 << 18);	//
            KeSynchronizeExecution(pdx->pInterruptObject, 
								(PKSYNCHRONIZE_ROUTINE)SynchronizedModifyRegister, 
								(VOID *)&RegData);
            // Clear Dual Address cycle register
			WRITE_REGISTER_ULONG((ULONG *)(lRegAddress + PCI9054_DMA0_PCI_DAC), 0);
        }
        else
        {
			 // Setup threshold
			WRITE_REGISTER_ULONG((ULONG *)(lRegAddress + PCI9054_DMA_THRESHOLD), 
								(lRegValue & 0x0000ffff) | (lThreshold << 16));
            // Write DMA mode
			WRITE_REGISTER_ULONG((ULONG *)(lRegAddress + PCI9054_DMA1_MODE), 
								lMode);
            // Enable PCI & DMA Channel interrupts
            RegData.lBitsToSet = (1 << 8) | (1 << 19);
            KeSynchronizeExecution(pdx->pInterruptObject, 
								(PKSYNCHRONIZE_ROUTINE)SynchronizedModifyRegister, 
								(VOID *)&RegData);
            // Clear Dual Address cycle register
			WRITE_REGISTER_ULONG((ULONG *)(lRegAddress + PCI9054_DMA0_PCI_DAC), 0);
        }
    }
    else
    {
        if (lDmaChannel == 0)
        {
            // Enable DMA Done interrupt, Chaining, & Route to PCI
			lRegValue = READ_REGISTER_ULONG((ULONG *)(lRegAddress + PCI9054_DMA0_MODE));

            lRegValue &= ~(1 << 18);                 // Disable Dual-Address

			WRITE_REGISTER_ULONG((ULONG *)(lRegAddress + PCI9054_DMA0_MODE), 
						lRegValue | (1 << 9) | (1 << 10) | (1 << 17));

            // Keep track if local address should remain constant
            if (lRegValue & (1 << 11)) 
                pdx->DmaInfo[0].HoldLocalAddressConstant = TRUE;

            // Enable PCI & DMA Channel interrupts
            RegData.lBitsToSet = (1 << 8) | (1 << 18);
            KeSynchronizeExecution(pdx->pInterruptObject,
									(PKSYNCHRONIZE_ROUTINE)SynchronizedModifyRegister,
									(VOID *)&RegData);

            // Clear Dual Address cycle register
            WRITE_REGISTER_ULONG((ULONG *)(lRegAddress + PCI9054_DMA0_PCI_DAC), 0);
        }
        else
        {
            // Enable DMA Done interrupt, Chaining, & Route to PCI
			lRegValue = READ_REGISTER_ULONG((ULONG *)(lRegAddress + PCI9054_DMA1_MODE));

            lRegValue &= ~(1 << 18);                 // Disable Dual-Address

            WRITE_REGISTER_ULONG((ULONG *)(lRegAddress + PCI9054_DMA1_MODE), 
						lRegValue | (1 << 9) | (1 << 10) | (1 << 17));

            // Keep track if local address should remain constant
            if (lRegValue & (1 << 11)) 
                pdx->DmaInfo[1].HoldLocalAddressConstant = TRUE;

            // Enable PCI & DMA Channel interrupts
            RegData.lBitsToSet = (1 << 8) | (1 << 19);

⌨️ 快捷键说明

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