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

📄 dispatch.cpp

📁 使用DDK编写的PCI9054芯片的驱动程序
💻 CPP
📖 第 1 页 / 共 5 页
字号:
								(VOID *)&RegData);
		}
		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);
		}
	}	//pDmaChannelDescription != NULL
	else	//pDmaChannelDescription == NULL
	{
		if (lDmaChannel == 0)
		{
			// Disable chaining & route DMA Interrupts to PCI
			lRegValue = READ_REGISTER_ULONG((ULONG *)(lRegAddress + PCI9054_DMA0_MODE));

			lRegValue |=  (1 << 17);     // Route DMA interrupt to PCI
			lRegValue &= ~(1 << 9);      // Disable Chaining

			WRITE_REGISTER_ULONG((ULONG *)(lRegAddress + PCI9054_DMA0_MODE), lRegValue);
		}
		else
		{
			// Disable chaining & route DMA Interrupts to PCI
			lRegValue = READ_REGISTER_ULONG((ULONG *)(lRegAddress + PCI9054_DMA1_MODE));

			lRegValue |=  (1 << 17);     // Route DMA interrupt to PCI
			lRegValue &= ~(1 << 9);      // Disable Chaining
			
			WRITE_REGISTER_ULONG((ULONG *)(lRegAddress + PCI9054_DMA1_MODE), lRegValue);
		}
	}	//pDmaChannelDescription == NULL

	KeReleaseSpinLock(&(pdx->HardwareAccessLock), OriginalIrqL);
	KdPrint((DBG_NAME "Block DMA Opened. \n"));
	return RC_SUCCESS;
}

/*********************************************************************
*
* Function   :  SynchronizedModifyRegister
*
* Description:  Register modify to be called with KeSynchronizeExecution()
*
**********************************************************************/
BOOLEAN SynchronizedModifyRegister(PREG_DATA RegData)
{
    ULONG lRegValue;
    lRegValue = READ_REGISTER_ULONG((ULONG *)RegData->lRegAddress);

    lRegValue |= RegData->lBitsToSet;
    lRegValue &= ~(RegData->lBitsToClear);

    WRITE_REGISTER_ULONG((ULONG *)RegData->lRegAddress, lRegValue);

    return TRUE;
}


/******************************************************************************
 *
 * Function   :  DmaBlockTransfer
 *
 * Description:  Performs DMA block transfer.
 *
 ******************************************************************************/
RETURN_CODE DmaBlockTransfer(DEVICE_EXTENSION  *pdx,
						 ULONG		           lDmaChannel,
						 DMA_TRANSFER_ELEMENT *pDmaData)
{
    unsigned char cShift;
    ULONG   lRegDmaBase;
    ULONG   lRegPciHighAddress;
    ULONG	lRegValue;
    KIRQL	OriginalIrqL;
	ULONG	lRegAddress;

    if (pDmaData == NULL)
        return RC_FAILED;
	lRegAddress = (ULONG)pdx->LocalRegisterMemBase;

    // Setup transfer registers
    switch (lDmaChannel)
    {
        case 0:
            cShift				= 0;
            lRegDmaBase			= (ULONG)pdx->LocalRegisterMemBase + PCI9054_DMA0_MODE;
            lRegPciHighAddress	= (ULONG)pdx->LocalRegisterMemBase + PCI9054_DMA0_PCI_DAC;
            break;
        case 1:
            cShift				= 8;
            lRegDmaBase			= (ULONG)pdx->LocalRegisterMemBase + PCI9054_DMA1_MODE;
            lRegPciHighAddress	= (ULONG)pdx->LocalRegisterMemBase + PCI9054_DMA1_PCI_DAC;
            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)//DMA的A8积存器中的值,表示有没有被打开 
    {
        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_BLOCK) //DMA通道没有被打开 
    {
        KdPrint((DBG_NAME "ERROR - DMA Channel has not been opened for Block DMA\n"));

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

        return RC_DMA_CHANNEL_UNAVAILABLE;
    }

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

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

    // Make sure DMA done interrupt is enabled
    lRegValue = READ_REGISTER_ULONG((ULONG *)lRegDmaBase);

    lRegValue |= (1 << 10);//当完成传输时产生一个中断
	KdPrint((DBG_NAME "Set DMA done interrupt\n"));
	WRITE_REGISTER_ULONG((ULONG *)lRegDmaBase, lRegValue);

	KdPrint((DBG_NAME "Write PCI Address\n"));					//写入0x80,84,88,8c,90	·寄存器的值
	// Write PCI Address
	WRITE_REGISTER_ULONG((ULONG *)(lRegDmaBase + 0x4), pDmaData->lPciAddress);
	KdPrint((DBG_NAME "Write Local Address\n"));
    // Write Local Address
	WRITE_REGISTER_ULONG((ULONG *)(lRegDmaBase + 0x8), pDmaData->lLocalAddress);
	KdPrint((DBG_NAME "Write Transfer Count\n"));	
    // Write Transfer Count
	WRITE_REGISTER_ULONG((ULONG *)(lRegDmaBase + 0xc), pDmaData->lTransferSize);
	KdPrint((DBG_NAME "Write Descriptor Pointer\n"));
    // Write Descriptor Pointer
    lRegValue = (pDmaData->InterruptAfterTerminalCount << 2) |
                (pDmaData->DirectionOfTransfer		<< 3);
	WRITE_REGISTER_ULONG((ULONG *)(lRegDmaBase + 0x10), lRegValue);
	KdPrint((DBG_NAME "Write the high PCI address\n"));
    // Write the high PCI address
	WRITE_REGISTER_ULONG((ULONG *)(lRegPciHighAddress), pDmaData->lPciDualAddress);
	
	KdPrint((DBG_NAME "Start Block DMA.\n"));

    // Enable and Start DMA
    lRegValue = READ_REGISTER_ULONG((ULONG *)(lRegAddress + PCI9054_DMA_COMMAND_STAT));
 
	lRegValue |= (((1 << 0) | (1 << 1)) << cShift);
	WRITE_REGISTER_ULONG((ULONG *)(lRegAddress + PCI9054_DMA_COMMAND_STAT), lRegValue);

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

    return RC_SUCCESS;
}





/******************************************************************************
 *
 * Function   :  DmaRestartBlockTransfer
 *
 * Description:  Start a preprogrammed data transfer again.
 *
 ******************************************************************************/
RETURN_CODE DmaRestartBlockTransfer(DEVICE_EXTENSION *pdx,
									ULONG lDmaChannel,
									ULONG lTransferSize,
									PIRP  pIrp)
{
    unsigned char cShift;
    ULONG	lDmaCountReg;
    ULONG	lRegValue;
    KIRQL	OriginalIrqL;
	ULONG	lRegAddress = (ULONG)pdx->LocalRegisterMemBase;

    // Verify valid DMA channel
    switch (lDmaChannel)
    {
        case 0:
            cShift       = 0;
            lDmaCountReg = PCI9054_DMA0_COUNT;
            break;
        case 1:
            cShift       = 8;
            lDmaCountReg = PCI9054_DMA1_COUNT;
            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_BLOCK)
    {
        KdPrint((DBG_NAME "ERROR - DMA Channel has not been opened for Block DMA\n"));

        KeReleaseSpinLock(&(pdx->DmaChannelLock), OriginalIrqL);
        return RC_DMA_CHANNEL_UNAVAILABLE;
    }

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

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

    // Write the DMA transfer count
	WRITE_REGISTER_ULONG((ULONG *)(lRegAddress + lDmaCountReg), lTransferSize);

    // Enable DMA
	WRITE_REGISTER_ULONG((ULONG *)(lRegAddress + PCI9054_DMA_COMMAND_STAT), 
						lRegValue | ((1 << 0) << cShift));

    // 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   :  DmaCloseBlockChannel
 *
 * Description:  Close a previously opened channel.
 *
 ******************************************************************************/
RETURN_CODE DmaCloseBlockChannel(DEVICE_EXTENSION *pdx,
								ULONG       lDmaChannel,
								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   :  DmaControl
 *
 * 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)
            {

⌨️ 快捷键说明

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