📄 dispatch.cpp
字号:
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 : PlxDmaSglTransfer
*
* 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 : PlxDmaSglChannelClose
*
* 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);
return RC_DMA_CHANNEL_UNAVAILABLE;
}
// Close the channel
pdx->DmaInfo[lDmaChannel].State = DMA_STATE_CLOSED;
KeReleaseSpinLock(&(pdx->DmaChannelLock), OriginalIrqL);
return RC_SUCCESS;
}
/******************************************************************************
*
* Function : PlxDmaShuttleChannelOpen
*
* Description: Open a DMA channel for Shuttle transfers.
*
******************************************************************************/
RETURN_CODE DmaOpenShuttleChannel(DEVICE_EXTENSION *pdx,
ULONG lDmaChannel,
DMA_CHANNEL_DESCRIPTION *pDmaChannelDescription,
PFILE_OBJECT pFileObject)
{
ULONG lMode = 0;
ULONG lRegValue = 0;
ULONG lThreshold = 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;
}
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_SHUTTLE;
// Clear the buffer parameters
pdx->DmaInfo[lDmaChannel].pSgl = NULL;
pdx->DmaInfo[lDmaChannel].pMdl = NULL;
KeReleaseSpinLock(&(pdx->DmaChannelLock), OriginalIrqL);
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)
{
// 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);
// 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);
// Clear Dual Address cycle register
WRITE_REGISTER_ULONG((ULONG *)(lRegAddress + PCI9054_DMA1_PCI_DAC), 0);
}
}
else
{
if (lDmaChannel == 0)
{
// Enable Chaining & disable DMA Done interrupt
lRegValue = READ_REGISTER_ULONG((ULONG *)(lRegAddress + PCI9054_DMA0_MODE));
lRegValue |= (1 << 9); // Enable Chaining
lRegValue &= ~((1 << 10) | (1 << 18)); // Disable DMA Done Int & Dual-Address
WRITE_REGISTER_ULONG((ULONG *)(lRegAddress + PCI9054_DMA0_MODE), lRegValue);
// Keep track if local address should remain constant
if (lRegValue & (1 << 11))
pdx->DmaInfo[0].HoldLocalAddressConstant = TRUE;
// Clear Dual Address cycle register
WRITE_REGISTER_ULONG((ULONG *)(lRegAddress + PCI9054_DMA0_PCI_DAC), 0);
}
else
{
// Enable Chaining & disable DMA Done interrupt
lRegValue = READ_REGISTER_ULONG((ULONG *)(lRegAddress + PCI9054_DMA1_MODE));
lRegValue |= (1 << 9); // Enable Chaining
lRegValue &= ~((1 << 10) | (1 << 18)); // Disable DMA Done Int & Dual-Address
WRITE_REGISTER_ULONG((ULONG *)(lRegAddress + PCI9054_DMA1_MODE), lRegValue);
// Keep track if local address should remain constant
if (lRegValue & (1 << 11))
pdx->DmaInfo[1].HoldLocalAddressConstant = TRUE;
// Clear Dual Address cycle register
WRITE_REGISTER_ULONG((ULONG *)(lRegAddress + PCI9054_DMA1_PCI_DAC), 0);
}
}
KeReleaseSpinLock(&(pdx->HardwareAccessLock), OriginalIrqL);
return RC_SUCCESS;
}
/******************************************************************************
*
* Function : PlxDmaShuttleTransfer
*
* Description: Performs a DMA transfer using Shuttle mode.
*
******************************************************************************/
RETURN_CODE DmaShuttleTransfer(DEVICE_EXTENSION *pdx,
ULONG lDmaChannel,
DMA_TRANSFER_ELEMENT *pDmaData)
{
UCHAR cShift = 0;
ULONG lRegDmaDescription = 0;
ULONG lRegValue = 0;
KIRQL OriginalIrqL;
PVOID pSglPciAddress = NULL;
ULONG lRegAddress = (ULONG)pdx->LocalRegisterMemBase;
if (pDmaData == NULL)
return RC_NULL_PARAMETER;
// 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_SHUTTLE)
{
KdPrint((DBG_NAME "ERROR - DMA channel has not been opened for Shuttle DMA\n"));
KeReleaseSpinLock(&(pdx->DmaChannelLock), OriginalIrqL);
return RC_DMA_CHANNEL_UNAVAILABLE;
}
// Verify no transfer is in progress
if ((pdx->DmaInfo[lDmaChannel].pSgl != NULL) ||
(pdx->DmaInfo[lDmaChannel].pMdl != NULL))
{
KdPrint((DBG_NAME "ERROR - DMA Channel is active\n"));
KeReleaseSpinLock(&(pdx->DmaChannelLock), OriginalIrqL);
return RC_DMA_IN_PROGRESS;
}
KeReleaseSpinLock(&(pdx->DmaChannelLock), OriginalIrqL);
/*
SglPciAddress =
PlxLockBufferAndBuildSgl(
pdx,
i,
pDmaData->Pci9054Dma.LowPciAddr,
pDmaData->Pci9054Dma.IopAddr,
pDmaData->Pci9054Dma.TransferCount,
(U8)pDmaData->Pci9054Dma.IopToPciDma,
TRUE
);
*/
if (pSglPciAddress == NULL)
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -