📄 apifunctions.c
字号:
pdx,
OffsetDmaBase + 0xc,
pDmaData->TransferCount
);
// Write Descriptor Pointer
RegValue = (pDmaData->TerminalCountIntr << 2) |
(pDmaData->LocalToPciDma << 3);
PLX_REG_WRITE(
pdx,
OffsetDmaBase + 0x10,
RegValue
);
// Write the high PCI address
PLX_REG_WRITE(
pdx,
OffsetPciAddrHigh,
pDmaData->PciAddrHigh
);
// Enable DMA Channel
RegValue =
PLX_REG_READ(
pdx,
PCI9054_DMA_COMMAND_STAT
);
PLX_REG_WRITE(
pdx,
PCI9054_DMA_COMMAND_STAT,
RegValue | ((1 << 0) << shift)
);
KeReleaseSpinLock(
&(pdx->Lock_HwAccess),
OriginalIrqL
);
DebugPrintf(("Starting DMA transfer...\n"));
// Start DMA
PLX_REG_WRITE(
pdx,
PCI9054_DMA_COMMAND_STAT,
RegValue | (((1 << 0) | (1 << 1)) << shift)
);
return ApiSuccess;
}
/******************************************************************************
*
* Function : PlxDmaBlockChannelClose
*
* Description: Close a previously opened channel
*
******************************************************************************/
RETURN_CODE
PlxDmaBlockChannelClose(
DEVICE_EXTENSION *pdx,
DMA_CHANNEL channel,
BOOLEAN bCheckInProgress
)
{
U8 i;
U32 RegValue;
KIRQL OriginalIrqL;
// Verify valid DMA channel
switch (channel)
{
case PrimaryPciChannel0:
i = 0;
break;
case PrimaryPciChannel1:
i = 1;
break;
default:
DebugPrintf(("ERROR - Invalid DMA channel\n"));
return ApiDmaChannelInvalid;
}
if (bCheckInProgress)
{
// Verify that DMA is not in progress
RegValue =
PLX_REG_READ(
pdx,
PCI9054_DMA_COMMAND_STAT
);
if (channel == PrimaryPciChannel1)
RegValue = RegValue >> 8;
if ((RegValue & (1 << 4)) == 0)
{
if (RegValue & (1 << 0))
return ApiDmaInProgress;
else
return ApiDmaPaused;
}
}
KeAcquireSpinLock(
&(pdx->Lock_DmaChannel),
&OriginalIrqL
);
// Verify DMA Channel was opened correctly
if (pdx->DmaInfo[i].state != DmaStateBlock)
{
DebugPrintf(("ERROR - DMA Channel has not been opened for Block DMA\n"));
KeReleaseSpinLock(
&(pdx->Lock_DmaChannel),
OriginalIrqL
);
return ApiDmaChannelUnavailable;
}
// Close the channel
pdx->DmaInfo[i].state = DmaStateClosed;
// Clear owner information
pdx->DmaInfo[i].pOwner = NULL;
KeReleaseSpinLock(
&(pdx->Lock_DmaChannel),
OriginalIrqL
);
return ApiSuccess;
}
/******************************************************************************
*
* Function : PlxDmaSglChannelOpen
*
* Description: Open a DMA channel for SGL mode
*
******************************************************************************/
RETURN_CODE
PlxDmaSglChannelOpen(
DEVICE_EXTENSION *pdx,
DMA_CHANNEL channel,
DMA_CHANNEL_DESC *pDesc,
VOID *pOwner
)
{
U8 i;
U32 mode;
U32 RegValue;
U32 threshold;
KIRQL OriginalIrqL;
PLX_REG_DATA RegData;
// Verify valid DMA channel
switch (channel)
{
case PrimaryPciChannel0:
i = 0;
break;
case PrimaryPciChannel1:
i = 1;
break;
default:
DebugPrintf(("ERROR - Invalid DMA channel\n"));
return ApiDmaChannelInvalid;
}
KeAcquireSpinLock(
&(pdx->Lock_DmaChannel),
&OriginalIrqL
);
// Verify that we can open the channel
if (pdx->DmaInfo[i].state != DmaStateClosed)
{
DebugPrintf(("ERROR - DMA channel already opened\n"));
KeReleaseSpinLock(
&(pdx->Lock_DmaChannel),
OriginalIrqL
);
return ApiDmaChannelUnavailable;
}
// Open the channel
pdx->DmaInfo[i].state = DmaStateSgl;
// Record the Owner
pdx->DmaInfo[i].pOwner = pOwner;
// Mark DMA as free
pdx->DmaInfo[i].bPending = FALSE;
KeReleaseSpinLock(
&(pdx->Lock_DmaChannel),
OriginalIrqL
);
// Setup for synchronized access to Interrupt register
RegData.pdx = pdx;
RegData.offset = PCI9054_INT_CTRL_STAT;
RegData.BitsToClear = 0;
KeAcquireSpinLock(
&(pdx->Lock_HwAccess),
&OriginalIrqL
);
// Get DMA priority
RegValue =
PLX_REG_READ(
pdx,
PCI9054_LOCAL_DMA_ARBIT
);
// Clear priority
RegValue &= ~((1 << 20) | (1 << 19));
// Set the priority
switch (pDesc->DmaChannelPriority)
{
case Channel0Highest:
PLX_REG_WRITE(
pdx,
PCI9054_LOCAL_DMA_ARBIT,
RegValue | (1 << 19)
);
break;
case Channel1Highest:
PLX_REG_WRITE(
pdx,
PCI9054_LOCAL_DMA_ARBIT,
RegValue | (1 << 20)
);
break;
case Rotational:
PLX_REG_WRITE(
pdx,
PCI9054_LOCAL_DMA_ARBIT,
RegValue
);
break;
default:
DebugPrintf((
"WARNING - DmaChannelOpen() invalid priority state\n"
));
break;
}
threshold =
(pDesc->TholdForIopWrites << 0) |
(pDesc->TholdForIopReads << 4) |
(pDesc->TholdForPciWrites << 8) |
(pDesc->TholdForPciReads << 12);
mode =
(1 << 9) | // Enable Chaining
(1 << 10) | // Enable DMA Done interrupt
(1 << 17) | // Route interrupts to PCI
(0 << 18) | // Disable Dual-Addressing
(pDesc->IopBusWidth << 0) |
(pDesc->WaitStates << 2) |
(pDesc->EnableReadyInput << 6) |
(pDesc->EnableBTERMInput << 7) |
(pDesc->EnableIopBurst << 8) |
(pDesc->HoldIopAddrConst << 11) |
(pDesc->DemandMode << 12) |
(pDesc->EnableWriteInvalidMode << 13) |
(pDesc->EnableDmaEOTPin << 14) |
(pDesc->DmaStopTransferMode << 15);
// Keep track if local address should remain constant
if (pDesc->HoldIopAddrConst)
pdx->DmaInfo[i].bLocalAddrConstant = TRUE;
else
pdx->DmaInfo[i].bLocalAddrConstant = FALSE;
// Get DMA Threshold
RegValue =
PLX_REG_READ(
pdx,
PCI9054_DMA_THRESHOLD
);
if (channel == PrimaryPciChannel0)
{
// Setup threshold
PLX_REG_WRITE(
pdx,
PCI9054_DMA_THRESHOLD,
(RegValue & 0xffff0000) | threshold
);
// Write DMA mode
PLX_REG_WRITE(
pdx,
PCI9054_DMA0_MODE,
mode
);
// Enable DMA Channel interrupt
RegData.BitsToSet = (1 << 18);
KeSynchronizeExecution(
pdx->pInterruptObject,
PlxSynchronizedRegisterModify,
&RegData
);
// Clear Dual Address cycle register
PLX_REG_WRITE(
pdx,
PCI9054_DMA0_PCI_DAC,
0
);
}
else
{
// Setup threshold
PLX_REG_WRITE(
pdx,
PCI9054_DMA_THRESHOLD,
(RegValue & 0x0000ffff) | (threshold << 16)
);
// Write DMA mode
PLX_REG_WRITE(
pdx,
PCI9054_DMA1_MODE,
mode
);
// Enable DMA Channel interrupt
RegData.BitsToSet = (1 << 19);
KeSynchronizeExecution(
pdx->pInterruptObject,
PlxSynchronizedRegisterModify,
&RegData
);
// Clear Dual Address cycle register
PLX_REG_WRITE(
pdx,
PCI9054_DMA1_PCI_DAC,
0
);
}
KeReleaseSpinLock(
&(pdx->Lock_HwAccess),
OriginalIrqL
);
return ApiSuccess;
}
/******************************************************************************
*
* Function : PlxDmaSglTransfer
*
* Description: Performs a DMA SGL transfer
*
******************************************************************************/
RETURN_CODE
PlxDmaSglTransfer(
DEVICE_EXTENSION *pdx,
DMA_CHANNEL channel,
DMA_TRANSFER_ELEMENT *pDmaData
)
{
U8 i;
U8 shift;
U16 OffsetDesc;
U32 RegValue;
U32 SglPciAddress;
KIRQL OriginalIrqL;
// Verify valid DMA channel
switch (channel)
{
case PrimaryPciChannel0:
i = 0;
shift = 0;
OffsetDesc = PCI9054_DMA0_DESC_PTR;
break;
case PrimaryPciChannel1:
i = 1;
shift = 8;
OffsetDesc = PCI9054_DMA1_DESC_PTR;
break;
default:
DebugPrintf(("ERROR - Invalid DMA channel\n"));
return ApiDmaChannelInvalid;
}
// Verify that DMA is not in progress
RegValue =
PLX_REG_READ(
pdx,
PCI9054_DMA_COMMAND_STAT
);
if ((RegValue & ((1 << 4) << shift)) == 0)
{
DebugPrintf(("ERROR - DMA Channel is currently active\n"));
return ApiDmaInProgress;
}
KeAcquireSpinLock(
&(pdx->Lock_DmaChannel),
&OriginalIrqL
);
// Verify DMA Channel was opened correctly
if (pdx->DmaInfo[i].state != DmaStateSgl)
{
DebugPrintf(("ERROR - DMA channel has not been opened for SGL DMA\n"));
KeReleaseSpinLock(
&(pdx->Lock_DmaChannel),
OriginalIrqL
);
return ApiDmaChannelUnavailable;
}
// Verify a DMA transfer is not pending
if (pdx->DmaInfo[i].bPending)
{
DebugPrintf((
"ERROR - A DMA transfer is currently in progress\n"
));
KeReleaseSpinLock(
&(pdx->Lock_DmaChannel),
OriginalIrqL
);
return ApiDmaInProgress;
}
// Set the DMA pending flag
pdx->DmaInfo[i].bPending = TRUE;
KeReleaseSpinLock(
&(pdx->Lock_DmaChannel),
OriginalIrqL
);
SglPciAddress =
PlxLockBufferAndBuildSgl(
pdx,
i,
pDmaData
);
if (SglPciAddress == 0)
{
DebugPrintf(("ERROR - Unable to lock buffer and build SGL list\n"));
pdx->DmaInfo[i].bPending = FALSE;
return ApiDmaSglBuildFailed;
}
KeAcquireSpinLock(
&(pdx->Lock_HwAccess),
&OriginalIrqL
);
// Write SGL physical address & set descriptors in PCI space
PLX_REG_WRITE(
pdx,
OffsetDesc,
SglPciAddress | (1 << 0)
);
RegValue =
PLX_REG_READ(
pdx,
PCI9054_DMA_COMMAND_STAT
);
// Enable DMA channel
PLX_REG_WRITE(
pdx,
PCI9054_DMA_COMMAND_STAT,
RegValue | ((1 << 0) << shift)
);
KeReleaseSpinLock(
&(pdx->Lock_HwAccess),
OriginalIrqL
);
DebugPrintf(("Starting DMA transfer...\n"));
// Start DMA
PLX_REG_WRITE(
pdx,
PCI9054_DMA_COMMAND_STAT,
RegValue | (((1 << 0) | (1 << 1)) << shift)
);
return ApiSuccess;
}
/******************************************************************************
*
* Function : PlxDmaSglChannelClose
*
* Description: Close a previously opened channel
*
********************************************************************
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -