📄 dispatch.cpp
字号:
DmaShuttleTransferComplete(pdx, lDmaChannel);
}
break;
default:
return RC_DMA_COMMAND_INVALID;
}
return RC_SUCCESS;
}
/******************************************************************************
*
* Function : DmaShuttleTransferComplete
*
* Description: Perform any necessary cleanup after a Shuttle DMA transfer.
*
******************************************************************************/
VOID DmaShuttleTransferComplete(DEVICE_EXTENSION *pdx,
ULONG lDmaChannel)
{
/* KIRQL OriginalIrqL;
KeAcquireSpinLock(&(pdx->DmaChannelLock), &OriginalIrqL);
// Unlock data buffer and free MDL
if (pdx->DmaInfo[lDmaChannel].pMdl != NULL)
{
MmUnlockPages(pdx->DmaInfo[lDmaChannel].pMdl);
IoFreeMdl(pdx->DmaInfo[lDmaChannel].pMdl);
pdx->DmaInfo[lDmaChannel].pMdl = NULL;
}
// Release the SGL Descriptor buffer
if (pdx->DmaInfo[lDmaChannel].pSgl != NULL)
{
DriverBufferFree(pdx->DmaInfo[lDmaChannel].pSgl);
pdx->DmaInfo[lDmaChannel].pSgl = NULL;
}
KeReleaseSpinLock(&(pdx->DmaChannelLock), OriginalIrqL);
*/
}
/******************************************************************************
*
* Function : DmaGetStatus
*
* Description: Get status of a DMA channel
*
******************************************************************************/
RETURN_CODE DmaGetStatus(DEVICE_EXTENSION *pdx,
ULONG lDmaChannel)
{
ULONG lDmaStatus;
// Verify valid DMA channel
if (lDmaChannel > 1)
{
KdPrint((DBG_NAME "ERROR - Invalid DMA channel\n"));
return RC_DMA_CHANNEL_INVALID;
}
// Return the current DMA status
lDmaStatus = READ_REGISTER_ULONG((ULONG *)(pdx->LocalRegisterMemBase + PCI9054_DMA_COMMAND_STAT));
if (lDmaChannel == 1)
lDmaStatus = lDmaStatus >> 8;
if ((lDmaStatus & ((1 << 4) | (1 << 0))) == 0)
return RC_DMA_PAUSED;
if (lDmaStatus & (1 << 4))
return RC_DMA_DONE;
return RC_DMA_IN_PROGRESS;
}
/******************************************************************************
*
* Function : DmaSglChannelOpen
*
* Description: Requests usage of a device's DMA channel.
*
******************************************************************************/
RETURN_CODE DmaOpenSglChannel(DEVICE_EXTENSION *pdx,
ULONG lDmaChannel,
DMA_CHANNEL_DESCRIPTION *pDmaChannelDescription)
{
ULONG lMode = 0;
ULONG lRegValue = 0;
ULONG lThreshold = 0;
KIRQL OriginalIrqL;
REG_DATA RegData;
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;
}
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;
}
// Open the channel
pdx->DmaInfo[lDmaChannel].State = DMA_STATE_SGL;
KeReleaseSpinLock(&(pdx->DmaChannelLock), OriginalIrqL);
// Setup for synchronized access to Interrupt register
RegData.lRegAddress = (ULONG)pdx->LocalRegisterMemBase + 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));
// 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 = (1 << 9) | // Enable Chaining
(1 << 10) | // Enable DMA Done interrupt
(1 << 17) | // Route interrupts to PCI
(0 << 18) | // Disable Dual-Addressing
(pDmaChannelDescription->LocalBusWidth << 0) |
(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);
// Keep track if local address should remain constant
if (pDmaChannelDescription->LocalAddressingMode)
pdx->DmaInfo[lDmaChannel].HoldLocalAddressConstant = TRUE;
// Get DMA Threshold
lRegValue = READ_REGISTER_ULONG((ULONG *)(lRegAddress + PCI9054_DMA_THRESHOLD));
if (lDmaChannel == 0) //Channel 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);
// Enable PCI & DMA Channel interrupts
RegData.lBitsToSet = (1 << 8) | (1 << 18); //
KeSynchronizeExecution(pdx->pInterruptObject,
(PKSYNCHRONIZE_ROUTINE)SynchronizedModifyRegister,
(VOID *)&RegData);
// Clear Dual Address cycle register
WRITE_REGISTER_ULONG((ULONG *)(lRegAddress + PCI9054_DMA0_PCI_DAC), 0);
}
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);
// Clear Dual Address cycle register
WRITE_REGISTER_ULONG((ULONG *)(lRegAddress + PCI9054_DMA0_PCI_DAC), 0);
}
}
else
{
if (lDmaChannel == 0)
{
// Enable DMA Done interrupt, Chaining, & Route to PCI
lRegValue = READ_REGISTER_ULONG((ULONG *)(lRegAddress + PCI9054_DMA0_MODE));
lRegValue &= ~(1 << 18); // Disable Dual-Address
WRITE_REGISTER_ULONG((ULONG *)(lRegAddress + PCI9054_DMA0_MODE),
lRegValue | (1 << 9) | (1 << 10) | (1 << 17));
// Keep track if local address should remain constant
if (lRegValue & (1 << 11))
pdx->DmaInfo[0].HoldLocalAddressConstant = TRUE;
// Enable PCI & DMA Channel interrupts
RegData.lBitsToSet = (1 << 8) | (1 << 18);
KeSynchronizeExecution(pdx->pInterruptObject,
(PKSYNCHRONIZE_ROUTINE)SynchronizedModifyRegister,
(VOID *)&RegData);
// Clear Dual Address cycle register
WRITE_REGISTER_ULONG((ULONG *)(lRegAddress + PCI9054_DMA0_PCI_DAC), 0);
}
else
{
// Enable DMA Done interrupt, Chaining, & Route to PCI
lRegValue = READ_REGISTER_ULONG((ULONG *)(lRegAddress + PCI9054_DMA1_MODE));
lRegValue &= ~(1 << 18); // Disable Dual-Address
WRITE_REGISTER_ULONG((ULONG *)(lRegAddress + PCI9054_DMA1_MODE),
lRegValue | (1 << 9) | (1 << 10) | (1 << 17));
// Keep track if local address should remain constant
if (lRegValue & (1 << 11))
pdx->DmaInfo[1].HoldLocalAddressConstant = TRUE;
// Enable PCI & DMA Channel interrupts
RegData.lBitsToSet = (1 << 8) | (1 << 19);
KeSynchronizeExecution(pdx->pInterruptObject,
(PKSYNCHRONIZE_ROUTINE)SynchronizedModifyRegister,
(VOID *)&RegData);
// Clear Dual Address cycle register
WRITE_REGISTER_ULONG((ULONG *)(lRegAddress + PCI9054_DMA0_PCI_DAC), 0);
}
}
KeReleaseSpinLock(&(pdx->HardwareAccessLock), OriginalIrqL);
return RC_SUCCESS;
}
/******************************************************************************
*
* Function : DmaSglTransfer
*
* Description: Operate a DMA channel for SGL.
*
******************************************************************************/
RETURN_CODE DmaSglTransfer(DEVICE_EXTENSION *pdx,
ULONG lDmaChannel,
ULONG lMdbAddress)
{
unsigned char cShift = 0;
ULONG lRegDmaDescription = 0;
ULONG lRegValue = 0;
KIRQL OriginalIrqL;
ULONG lRegAddress = (ULONG)pdx->LocalRegisterMemBase;
// Verify valid DMA channel
switch (lDmaChannel)
{
case 0:
cShift = 0;
lRegDmaDescription = PCI9054_DMA0_DESC_PTR;
break;
case 1:
cShift = 8;
lRegDmaDescription = PCI9054_DMA1_DESC_PTR;
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_SGL)
{
KdPrint((DBG_NAME "ERROR - DMA channel has not been opened for SGL DMA\n"));
KeReleaseSpinLock(&(pdx->DmaChannelLock), OriginalIrqL);
return RC_DMA_CHANNEL_UNAVAILABLE;
}
KeReleaseSpinLock(&(pdx->DmaChannelLock), OriginalIrqL);
KeAcquireSpinLock(&(pdx->HardwareAccessLock), &OriginalIrqL);
//Set the first Descriptor Pointer Register
// Ensure an SGL transfer will occur & write SGL physical address
WRITE_REGISTER_ULONG((ULONG *)(lRegAddress + lRegDmaDescription), lMdbAddress | 1);
KdPrint((DBG_NAME "lMdbAddress = 0x%X.\n", lMdbAddress));
lRegValue = READ_REGISTER_ULONG((ULONG *)(lRegAddress + PCI9054_DMA_COMMAND_STAT));
// Enable and 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 : DmaSglChannelClose
*
* Description: Close a previously opened channel.
*
******************************************************************************/
RETURN_CODE DmaCloseSglChannel(DEVICE_EXTENSION *pdx,
ULONG lDmaChannel,
BOOLEAN bCheckInProgress)
{
ULONG lStatus = 0;
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_SGL)
{
KdPrint((DBG_NAME "ERROR - DMA channel has not been opened for SGL DMA\n"));
KeReleaseSpinLock(&(pdx->DmaChannelLock), OriginalIrqL);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -