📄 dispatch.cpp
字号:
(VOID *)(PDEVICE_EXTENSION)pdx);
UnlockDevice(pdx);
KdPrint((DBG_NAME "DpcForIsr End.\n"));
CompleteRequestInfo(pIrp, STATUS_SUCCESS, 0);
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) | // LocalBusWidth
(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) |
(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,
(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)
{
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);
// 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"));
// 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"));
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,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -