📄 dispatch.cpp
字号:
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 + -