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

📄 dispatch.cpp

📁 使用DDK编写的PCI9054芯片的驱动程序
💻 CPP
📖 第 1 页 / 共 5 页
字号:
	ULONG	lAddress;
	UCHAR	cInterrupt;
	UCHAR	cCommand;

	lAddress = (ULONG)((PDEVICE_EXTENSION)pdx)->LocalRegisterMemBase;

    // Read interrupt status register.
	lRegisterValue = READ_REGISTER_ULONG((ULONG *)(lAddress + PCI9054_INT_CTRL_STAT));

    // Check for master PCI interrupt enable.
	if ((lRegisterValue & 0x100) == 0)	//Interupt Control/Status Register: 8
	{
		return FALSE;		//如果不是该设备的中断,必须返回FALSE,否则系统会出问题。
	}

	KdPrint((DBG_NAME "On Interrupt!!!\n"));
	KdPrint((DBG_NAME "ICS Register is 0x%X.\n", lRegisterValue));
	// Check to see if an interrupt is active. 
	if (lRegisterValue & 0x00E0E000)//13,14,15,Doorbell, Abort,Local,21,22,23通道0,1,BIST是否有中断产生,如果有则进行下面的操作
	{
		lRegisterValue &= (~0x108);//将3位mailbox interrurpt和pci interruipt 两位清零,先禁止中断;
		
		WRITE_REGISTER_ULONG((ULONG *)(lAddress + PCI9054_INT_CTRL_STAT), lRegisterValue);
		KdPrint((DBG_NAME "Operate the Interrupt.\n"));
		if (pdx->pWaitEvent != NULL)
			KeSetEvent(pdx->pWaitEvent, 0, FALSE);	//通知应用程序,中断的到来
		//在此,处理中断
		if (pdx->DmaInfo[0].State == DMA_STATE_BLOCK)
		{
			KdPrint((DBG_NAME "Block DMA Interrupt!!!\n"));
			//清除中断标志
		//	WRITE_REGISTER_ULONG((ULONG *)(lAddress + PCI9054_DMA_COMMAND_STAT), lRegisterValue | (1 << 3));
		//	DmaCloseBlockChannel(pdx, 0, FALSE);
			
			if (pdx->DmaInfo[0].bWriteToLocal == FALSE)
			{
				KdPrint((DBG_NAME "Local->Pci!\n"));
				PDEVICE_OBJECT fdo	= ((PDEVICE_EXTENSION)pdx)->pDeviceObject;
				if (fdo != NULL)
				{
					PIRP pIrp = fdo->CurrentIrp;
					if (pIrp != NULL)
					{
						KdPrint((DBG_NAME "Call Dpc Routine.\n"));
						IoRequestDpc(fdo, pIrp, (PVOID)pdx);
					}
				}
			}
			else if (pdx->DmaInfo[0].bWriteToLocal == TRUE)
			{
				KdPrint((DBG_NAME "Pci->Local!\n"));
				WRITE_REGISTER_ULONG((ULONG *)(lAddress + PCI9054_DMA_COMMAND_STAT), lRegisterValue | (1 << 3));
				DmaCloseBlockChannel(pdx, 0, FALSE);
			}

		}
		else if (pdx->DmaInfo[0].State == DMA_STATE_SGL)
		{
			KdPrint((DBG_NAME "SGL DMA Interrupt!!!\n"));
			//如果不能很快处理,则交给Dpc处理,如下:
			PDEVICE_OBJECT fdo	= ((PDEVICE_EXTENSION)pdx)->pDeviceObject;
			if (fdo != NULL)
			{
				PIRP pIrp = fdo->CurrentIrp;
				if (pIrp != NULL)
				{
					KdPrint((DBG_NAME "Call Dpc Routine.\n"));
					IoRequestDpc(fdo, pIrp, (PVOID)pdx);
				}
			}
		}	

        return TRUE;	//如果是该设备的中断,必须返回TRUE。
    }

	// Check if Mssaging Unit Outbound Post Interrupt is active.
	lRegisterValue = READ_REGISTER_ULONG((ULONG *)(lAddress + PCI9054_OUTPOST_INT_STAT));
	if (lRegisterValue & (0x08))
	{
		//Operate the interrupt.
		WRITE_REGISTER_ULONG((ULONG *)(lAddress + PCI9054_OUTPOST_INT_MASK), (1 << 3));
		return TRUE;
	}
    // If we reach here, then the interrupt is not ours
	return FALSE;
}												//OnInterrupt

/******************************************************************************
 *
 * Function   :  DpcForIsr
 *
 * Description:  This routine will be triggered by the ISR to service an interrupt.
 *
 * Note       :  The 9052 supports Edge-triggerable interrupts as well as level
 *               triggered interrupts.  The 9050 only supports level triggered
 *               interrupts.  The interrupt masking code below handles both cases.
 *               If the chip is a 9050, the same code is used but should work
 *               ok since edge triggerable interrupts will always be disabled.
 *
 ******************************************************************************/
VOID DpcForIsr(IN PKDPC pDpc,
			   IN PDEVICE_OBJECT fdo,
			   IN PIRP pIrp, 
			   IN PDEVICE_EXTENSION pdx)
{												//OnInterrupt DpcForIsr
	KdPrint((DBG_NAME "DpcForIsr Start.\n"));
	ULONG lReturnedValue = 0;
	if (pIrp->Cancel)
		pdx->TransmitIrpStatus = STATUS_CANCELLED;

	KIRQL OldIrql;

	//Remove Cancel Routine.
	IoAcquireCancelSpinLock(&OldIrql);
	IoSetCancelRoutine(pIrp,NULL);
	IoReleaseCancelSpinLock(OldIrql);
	

	if (!LockDevice(pdx))
	{
		CompleteRequest(pIrp, STATUS_DELETE_PENDING);
	}
	
	KIRQL	OriginalIrqL;
	KeAcquireSpinLock(&(pdx->HardwareAccessLock), &OriginalIrqL);

	ULONG lRegAddress = (ULONG)pdx->LocalRegisterMemBase;
    // Read interrupt status register
    ULONG lRegValue = READ_REGISTER_ULONG((ULONG *)(lRegAddress + PCI9054_INT_CTRL_STAT));

	REG_DATA	RegData;
	ULONG		lValue;

    // Local Interrupt 
    if (lRegValue & (1 << 15))
    {
		// Setup to synchronize access to Interrupt Control/Status Register
		RegData.lRegAddress	= lRegAddress + PCI9054_INT_CTRL_STAT;
		RegData.lBitsToSet	= 0;
		RegData.lBitsToClear = (1 << 11);

		// Mask Local Interrupt 1
        KeSynchronizeExecution(pdx->pInterruptObject, 
								(PKSYNCHRONIZE_ROUTINE)SynchronizedModifyRegister, 
								(VOID *)&RegData);
    }

    // Doorbell Interrupt
	if (lRegValue & (1 << 13))
    {
		// Get Doorbell register
		lValue = READ_REGISTER_ULONG((ULONG *)(lRegAddress + PCI9054_PCI_DOORBELL));
		// Clear Doorbell interrupt
		WRITE_REGISTER_ULONG((ULONG *)(lRegAddress + PCI9054_PCI_DOORBELL), lValue);

		// Save this value in case it is requested later
		pdx->IntraDoorbellValue = lValue;
    }

	// PCI Abort interrupt
	if (lRegValue & (1 << 14))
    {
		// Get the PCI Command register
		lValue = READ_REGISTER_ULONG((ULONG *)(lRegAddress + CFG_COMMAND));

		// Write to back to clear PCI Abort
		WRITE_REGISTER_ULONG((ULONG *)(lRegAddress + CFG_COMMAND), lValue);
	}

	// DMA Channel 0 interrupt
	if (lRegValue & (1 << 21))
	{
        // Make sure DMA interrupt is for PCI side
		lValue = READ_REGISTER_ULONG((ULONG *)(lRegAddress + PCI9054_DMA0_MODE));
		KdPrint((DBG_NAME "DMA interrupt.\n"));
		// Verify that DMA interrupt is routed to PCI
        if (lValue & (1 << 17))
        {
			
            // Get DMA Control/Status
			ULONG lValue = READ_REGISTER_ULONG((ULONG *)(lRegAddress + PCI9054_DMA_COMMAND_STAT));

            // Clear DMA interrupt
			WRITE_REGISTER_ULONG((ULONG *)(lRegAddress + PCI9054_DMA_COMMAND_STAT), lValue | (1 << 3));

			lValue = READ_REGISTER_ULONG((ULONG *)(lRegAddress + PCI9054_DMA0_MODE));

            // Check if SGL is enabled & cleanup
            if (lValue & (1 << 9))
            {
				DmaCloseSglChannel(pdx, 0, FALSE);
				(*pdx->DmaInfo[0].pDmaAdapterObject->DmaOperations->FlushAdapterBuffers)(
												pdx->DmaInfo[0].pDmaAdapterObject,
												pdx->DmaInfo[0].pMdl,
												pdx->DmaInfo[0].pMapRegisterBase,
												pdx->DmaInfo[0].vaSglTransfer,
												pdx->DmaInfo[0].lSglTransferSize,
												pdx->DmaInfo[0].bWriteToLocal);

			}	
			else
			{
				DmaCloseBlockChannel(pdx, 0, FALSE);
				
				
				if (pdx->DmaInfo[0].bWriteToLocal == FALSE)
				{
					KdPrint((DBG_NAME "RtlCopyMemory.\n"));
					RtlCopyMemory(pIrp->AssociatedIrp.SystemBuffer, pdx->DmaInfo[0].vaCommonBuffer, pdx->DmaInfo[0].lTransferedBytes);
					lReturnedValue = pdx->DmaInfo[0].lTransferedBytes;
				}
            }
        }
    }

    // DMA Channel 1 interrupt
    if (lRegValue & (1 << 22))
    {
        // Make sure DMA interrupt is for PCI side
		lValue = READ_REGISTER_ULONG((ULONG *)(lRegAddress + PCI9054_DMA1_MODE));

        // Verify that DMA interrupt is routed to PCI
        if (lValue & (1 << 17))
        {
			// Get DMA Control/Status
			ULONG lValue = READ_REGISTER_ULONG((ULONG *)(lRegAddress + PCI9054_DMA_COMMAND_STAT));
			// Clear DMA interrupt
			WRITE_REGISTER_ULONG((ULONG *)(lRegAddress + PCI9054_DMA_COMMAND_STAT), lValue | (1 << 11));

			lValue = READ_REGISTER_ULONG((ULONG *)(lRegAddress + PCI9054_DMA1_MODE));
			// Check if SGL is enabled & cleanup
			if (lValue & (1 << 9))
			{
				DmaCloseSglChannel(pdx, 1, FALSE);
				(*pdx->DmaInfo[1].pDmaAdapterObject->DmaOperations->FlushAdapterBuffers)(
												pdx->DmaInfo[1].pDmaAdapterObject,
												pdx->DmaInfo[1].pMdl,
												pdx->DmaInfo[1].pMapRegisterBase,
												pdx->DmaInfo[1].vaSglTransfer,
												pdx->DmaInfo[1].lSglTransferSize,
												pdx->DmaInfo[1].bWriteToLocal);
			}
			else
			{
				DmaCloseBlockChannel(pdx, 1, FALSE);
			}
        }
    }

	// Local Data Parity Check Error
	if (lRegValue & ( 1 << 7))
	{
		KdPrint((DBG_NAME "There is a Local Data Parity Check Error!!!\n"));
	}

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

    // Re-enable PCI interrupts

	KeSynchronizeExecution(pdx->pInterruptObject, 
								(PKSYNCHRONIZE_ROUTINE)EnablePciInterrupt, 
								(VOID *)(PDEVICE_EXTENSION)pdx);

	UnlockDevice(pdx);

	KdPrint((DBG_NAME "DpcForIsr End.\n"));
	CompleteRequestInfo(pIrp, STATUS_SUCCESS, lReturnedValue);
	IoStartNextPacket(fdo, FALSE);

}												//OnInterrupt DpcForIsr




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

	ULONG lRegAddress = (ULONG)pdx->LocalRegisterMemBase;
	ULONG lRegValue;

	// Verify valid DMA channel
	if ((lDmaChannel < 0) || (lDmaChannel > 1))
		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;
	}

	KdPrint((DBG_NAME "Now Open Block DMA Channel.\n"));
	// Open the channel
	pdx->DmaInfo[lDmaChannel].State = DMA_STATE_BLOCK;

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

	// Setup for synchronized access to Interrupt register
	RegData.lRegAddress = lRegAddress + 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));
		KdPrint((DBG_NAME "Now Set DMA priority. \n"));
		// 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 =	(0 <<  9) |                  // No Chaining
				(1 << 10) |                  // Enable DMA Done interrupt
				(1 << 17) |                  // Route interrupts to PCI
				(pDmaChannelDescription->LocalBusWidth					<<  0) | //DMA_MODE_REG;0:1=01为16位
				(pDmaChannelDescription->InternalWaitStates				<<  2) |//等待1
				(pDmaChannelDescription->ReadyInputEnable				<<  6) |//
				(pDmaChannelDescription->BTERMInputEnable				<<  7) |
				(pDmaChannelDescription->LocalBurstEnable				<<  8) |
				(pDmaChannelDescription->LocalAddressingMode			<< 11) |
				(pDmaChannelDescription->DemandMode						<< 12) |
				(pDmaChannelDescription->MemoryWriteAndInvalidateMode	<< 13) |
				(pDmaChannelDescription->DmaEOTPinEnable				<< 14) |
				(pDmaChannelDescription->FastSlowTerminateModeSelect	<< 15) |
				(pDmaChannelDescription->DACChainLoad					<< 18);

		// Get DMA Threshold
		lRegValue = READ_REGISTER_ULONG((ULONG *)(lRegAddress + PCI9054_DMA_THRESHOLD));
		KdPrint((DBG_NAME "Now Set DMA Threshold. \n"));
		if (lDmaChannel == 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);
			KdPrint((DBG_NAME "The mode is : 0x%X.\n", lMode));

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

⌨️ 快捷键说明

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