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

📄 dispatch.cpp

📁 使用DDK编写的PCI9054芯片的驱动程序
💻 CPP
📖 第 1 页 / 共 5 页
字号:
                DmaShuttleTransferComplete(pdx, lDmaChannel);
            }
            break;

        default:
            return RC_DMA_COMMAND_INVALID;
    }

    return RC_SUCCESS;
}

/******************************************************************************
 *
 * Function   :  DmaShuttleTransferComplete
 *
 * 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   :  DmaSglChannelOpen
 *
 * 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);
            KeSynchronizeExecution(pdx->pInterruptObject,
									(PKSYNCHRONIZE_ROUTINE)SynchronizedModifyRegister,
									(VOID *)&RegData);

            // Clear Dual Address cycle register
            WRITE_REGISTER_ULONG((ULONG *)(lRegAddress + PCI9054_DMA0_PCI_DAC), 0);
        }
    }

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

    return RC_SUCCESS;
}

/******************************************************************************
 *
 * Function   :  DmaSglTransfer
 *
 * Description:  Operate a DMA channel for SGL.
 *
 ******************************************************************************/
RETURN_CODE DmaSglTransfer(DEVICE_EXTENSION     *pdx,
						   ULONG				lDmaChannel,
						   ULONG				lMdbAddress)
{
	unsigned char	cShift = 0;
	ULONG			lRegDmaDescription = 0;
	ULONG			lRegValue = 0;
	KIRQL			OriginalIrqL;

	ULONG lRegAddress = (ULONG)pdx->LocalRegisterMemBase;

	// Verify valid DMA channel
	switch (lDmaChannel)
	{
	case 0:
		cShift      = 0;
		lRegDmaDescription = PCI9054_DMA0_DESC_PTR;
		break;
	case 1:
		cShift      = 8;
		lRegDmaDescription = PCI9054_DMA1_DESC_PTR;
		break;
	default:
		KdPrint((DBG_NAME "ERROR - Invalid DMA channel\n"));
		return RC_DMA_CHANNEL_INVALID;
	}

	// Verify that DMA is not in progress
	lRegValue = READ_REGISTER_ULONG((ULONG *)(lRegAddress + PCI9054_DMA_COMMAND_STAT));

	if ((lRegValue & ((1 << 4) << cShift)) == 0)
	{
		KdPrint((DBG_NAME "ERROR - DmaTransfer() Channel is active\n"));
		return RC_DMA_IN_PROGRESS;
	}

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

	// Verify DMA Channel was opened correctly
	if (pdx->DmaInfo[lDmaChannel].State != DMA_STATE_SGL)
	{
		KdPrint((DBG_NAME "ERROR - DMA channel has not been opened for SGL DMA\n"));
		KeReleaseSpinLock(&(pdx->DmaChannelLock), OriginalIrqL);
		return RC_DMA_CHANNEL_UNAVAILABLE;
	}
	KeReleaseSpinLock(&(pdx->DmaChannelLock), OriginalIrqL);

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

	//Set the first Descriptor Pointer Register 
	// Ensure an SGL transfer will occur & write SGL physical address
	WRITE_REGISTER_ULONG((ULONG *)(lRegAddress + lRegDmaDescription), lMdbAddress | 1);
	KdPrint((DBG_NAME "lMdbAddress = 0x%X.\n", lMdbAddress));
	lRegValue = READ_REGISTER_ULONG((ULONG *)(lRegAddress + PCI9054_DMA_COMMAND_STAT));

	// Enable and Start DMA
	WRITE_REGISTER_ULONG((ULONG *)(lRegAddress + PCI9054_DMA_COMMAND_STAT),
						lRegValue | (((1 << 0) | (1 << 1)) << cShift));
	KeReleaseSpinLock(&(pdx->HardwareAccessLock), OriginalIrqL);

	return RC_SUCCESS;
}

/******************************************************************************
 *
 * Function   :  DmaSglChannelClose
 *
 * Description:  Close a previously opened channel.
 *
 ******************************************************************************/
RETURN_CODE DmaCloseSglChannel(DEVICE_EXTENSION *pdx,
							   ULONG			lDmaChannel,
							   BOOLEAN			bCheckInProgress)
{
    ULONG	lStatus  = 0;
    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_SGL)
    {
        KdPrint((DBG_NAME "ERROR - DMA channel has not been opened for SGL DMA\n"));
        KeReleaseSpinLock(&(pdx->DmaChannelLock), OriginalIrqL);

⌨️ 快捷键说明

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