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