📄 plxchipapi.c
字号:
(pProp->EOTPin << 14) |
(pProp->StopTransferMode << 15);
if (channel == 0)
{
// Write DMA mode
PLX_9000_REG_WRITE(
pdx,
PCI9054_DMA0_MODE,
RegValue
);
// Clear Dual Address cycle register
PLX_9000_REG_WRITE(
pdx,
PCI9054_DMA0_PCI_DAC,
0
);
// Enable DMA channel interrupt
RegData.BitsToSet = (1 << 18);
}
else
{
// Write DMA mode
PLX_9000_REG_WRITE(
pdx,
PCI9054_DMA1_MODE,
RegValue
);
// Clear Dual Address cycle register
PLX_9000_REG_WRITE(
pdx,
PCI9054_DMA1_PCI_DAC,
0
);
// Enable DMA channel interrupt
RegData.BitsToSet = (1 << 19);
}
// Update interrupt register
KeSynchronizeExecution(
pdx->pInterruptObject,
PlxSynchronizedRegisterModify,
&RegData
);
KeReleaseSpinLock(
&(pdx->Lock_HwAccess),
OriginalIrqL
);
DebugPrintf((
"Opened DMA channel %d\n",
channel
));
return ApiSuccess;
}
/******************************************************************************
*
* Function : PlxChip_DmaTransferBlock
*
* Description: Performs DMA block transfer
*
******************************************************************************/
RETURN_CODE
PlxChip_DmaTransferBlock(
DEVICE_EXTENSION *pdx,
U8 channel,
PLX_DMA_PARAMS *pParams
)
{
U8 shift;
U16 OffsetDmaMode;
U32 RegValue;
KIRQL OriginalIrqL;
// Verify DMA channel & setup register offsets
switch (channel)
{
case 0:
OffsetDmaMode = PCI9054_DMA0_MODE;
break;
case 1:
OffsetDmaMode = PCI9054_DMA1_MODE;
break;
default:
DebugPrintf(("ERROR - Invalid DMA channel\n"));
return ApiDmaChannelInvalid;
}
// Set shift for status register
shift = (channel * 8);
// Verify that DMA is not in progress
RegValue =
PLX_9000_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
if (pdx->DmaInfo[channel].bOpen == FALSE)
{
DebugPrintf(("ERROR - DMA channel has not been opened\n"));
KeReleaseSpinLock(
&(pdx->Lock_DmaChannel),
OriginalIrqL
);
return ApiDmaChannelUnavailable;
}
KeReleaseSpinLock(
&(pdx->Lock_DmaChannel),
OriginalIrqL
);
KeAcquireSpinLock(
&(pdx->Lock_HwAccess),
&OriginalIrqL
);
// Get DMA mode
RegValue =
PLX_9000_REG_READ(
pdx,
OffsetDmaMode
);
// Disable DMA chaining
RegValue &= ~(1 << 9);
// Enable interrupt & route interrupt to PCI
RegValue |= (1 << 10) | (1 << 17);
PLX_9000_REG_WRITE(
pdx,
OffsetDmaMode,
RegValue
);
// Write PCI Address
PLX_9000_REG_WRITE(
pdx,
OffsetDmaMode + 0x4,
pParams->u.PciAddrLow
);
// Write Local Address
PLX_9000_REG_WRITE(
pdx,
OffsetDmaMode + 0x8,
pParams->LocalAddr
);
// Write Transfer Count
PLX_9000_REG_WRITE(
pdx,
OffsetDmaMode + 0xc,
pParams->ByteCount
);
// Write Descriptor Pointer
RegValue = (pParams->TerminalCountIntr << 2) |
(pParams->LocalToPciDma << 3);
PLX_9000_REG_WRITE(
pdx,
OffsetDmaMode + 0x10,
RegValue
);
// Enable DMA channel
RegValue =
PLX_9000_REG_READ(
pdx,
PCI9054_DMA_COMMAND_STAT
);
PLX_9000_REG_WRITE(
pdx,
PCI9054_DMA_COMMAND_STAT,
RegValue | ((1 << 0) << shift)
);
KeReleaseSpinLock(
&(pdx->Lock_HwAccess),
OriginalIrqL
);
DebugPrintf(("Starting DMA transfer...\n"));
// Start DMA
PLX_9000_REG_WRITE(
pdx,
PCI9054_DMA_COMMAND_STAT,
RegValue | (((1 << 0) | (1 << 1)) << shift)
);
return ApiSuccess;
}
/******************************************************************************
*
* Function : PlxChip_DmaTransferUserBuffer
*
* Description: Transfers a user-mode buffer using SGL DMA
*
******************************************************************************/
RETURN_CODE
PlxChip_DmaTransferUserBuffer(
DEVICE_EXTENSION *pdx,
U8 channel,
PLX_DMA_PARAMS *pParams
)
{
U8 i;
U8 shift;
U16 OffsetDmaMode;
U32 RegValue;
U32 SglPciAddress;
KIRQL OriginalIrqL;
RETURN_CODE rc;
// Verify DMA channel & setup register offsets
switch (channel)
{
case 0:
OffsetDmaMode = PCI9054_DMA0_MODE;
break;
case 1:
OffsetDmaMode = PCI9054_DMA1_MODE;
break;
default:
DebugPrintf(("ERROR - Invalid DMA channel\n"));
return ApiDmaChannelInvalid;
}
// For code readability
i = channel;
// Set shift for status register
shift = (channel * 8);
// Verify that DMA is not in progress
RegValue =
PLX_9000_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
if (pdx->DmaInfo[i].bOpen == FALSE)
{
DebugPrintf(("ERROR - DMA channel has not been opened\n"));
KeReleaseSpinLock(
&(pdx->Lock_DmaChannel),
OriginalIrqL
);
return ApiDmaChannelUnavailable;
}
// Verify an SGL DMA transfer is not pending
if (pdx->DmaInfo[i].bSglPending)
{
DebugPrintf(("ERROR - An SGL DMA transfer is currently pending\n"));
KeReleaseSpinLock(
&(pdx->Lock_DmaChannel),
OriginalIrqL
);
return ApiDmaInProgress;
}
// Set the SGL DMA pending flag
pdx->DmaInfo[i].bSglPending = TRUE;
KeReleaseSpinLock(
&(pdx->Lock_DmaChannel),
OriginalIrqL
);
// Get DMA mode
RegValue =
PLX_9000_REG_READ(
pdx,
OffsetDmaMode
);
// Keep track if local address should remain constant
if (RegValue & (1 << 11))
pdx->DmaInfo[i].bLocalAddrConstant = TRUE;
else
pdx->DmaInfo[i].bLocalAddrConstant = FALSE;
// Enable DMA chaining, interrupt, & route interrupt to PCI
RegValue |= (1 << 9) | (1 << 10) | (1 << 17);
PLX_9000_REG_WRITE(
pdx,
OffsetDmaMode,
RegValue
);
// Page-lock user buffer & build SGL
rc =
PlxLockBufferAndBuildSgl(
pdx,
i,
pParams,
&SglPciAddress
);
if (rc != ApiSuccess)
{
DebugPrintf(("ERROR - Unable to lock buffer and build SGL list\n"));
pdx->DmaInfo[i].bSglPending = FALSE;
return rc;
}
KeAcquireSpinLock(
&(pdx->Lock_HwAccess),
&OriginalIrqL
);
// Write SGL physical address & set descriptors in PCI space
PLX_9000_REG_WRITE(
pdx,
OffsetDmaMode + 0x10,
SglPciAddress | (1 << 0)
);
// Enable DMA channel
RegValue =
PLX_9000_REG_READ(
pdx,
PCI9054_DMA_COMMAND_STAT
);
PLX_9000_REG_WRITE(
pdx,
PCI9054_DMA_COMMAND_STAT,
RegValue | ((1 << 0) << shift)
);
KeReleaseSpinLock(
&(pdx->Lock_HwAccess),
OriginalIrqL
);
DebugPrintf(("Starting DMA transfer...\n"));
// Start DMA
PLX_9000_REG_WRITE(
pdx,
PCI9054_DMA_COMMAND_STAT,
RegValue | (((1 << 0) | (1 << 1)) << shift)
);
return ApiSuccess;
}
/******************************************************************************
*
* Function : PlxChip_DmaChannelClose
*
* Description: Close a previously opened channel
*
******************************************************************************/
RETURN_CODE
PlxChip_DmaChannelClose(
DEVICE_EXTENSION *pdx,
U8 channel,
BOOLEAN bCheckInProgress
)
{
U8 i;
U32 RegValue;
KIRQL OriginalIrqL;
DebugPrintf((
"Closing DMA channel %d...\n",
channel
));
// Verify valid DMA channel
switch (channel)
{
case 0:
case 1:
i = channel;
break;
default:
DebugPrintf(("ERROR - Invalid DMA channel\n"));
return ApiDmaChannelInvalid;
}
// Verify DMA channel was opened
if (pdx->DmaInfo[i].bOpen == FALSE)
{
DebugPrintf(("ERROR - DMA channel has not been opened\n"));
return ApiDmaChannelUnavailable;
}
// Check DMA status
RegValue =
PLX_9000_REG_READ(
pdx,
PCI9054_DMA_COMMAND_STAT
);
// Shift status for channel 1
if (channel == 1)
RegValue = RegValue >> 8;
// Verify DMA is not in progress
if ((RegValue & (1 << 4)) == 0)
{
// DMA is still in progress
if (bCheckInProgress)
{
if (RegValue & (1 << 0))
return ApiDmaInProgress;
else
return ApiDmaPaused;
}
DebugPrintf(("DMA in progress, aborting...\n"));
// Force DMA abort, which may generate a DMA done interrupt
PlxChip_DmaControl(
pdx,
channel,
DmaAbort
);
}
KeAcquireSpinLock(
&(pdx->Lock_DmaChannel),
&OriginalIrqL
);
// Close the channel
pdx->DmaInfo[i].bOpen = FALSE;
// Clear owner information
pdx->DmaInfo[i].pOwner = NULL;
KeReleaseSpinLock(
&(pdx->Lock_DmaChannel),
OriginalIrqL
);
// If DMA is hung, an SGL transfer could be pending, so release user buffer
if (pdx->DmaInfo[i].bSglPending)
{
PlxSglDmaTransferComplete(
pdx,
i
);
}
// Release memory previously used for SGL descriptors
if (pdx->DmaInfo[i].SglBuffer.pKernelVa != NULL)
{
DebugPrintf((
"Releasing memory used for SGL descriptors...\n"
));
Plx_dma_buffer_free(
pdx,
&pdx->DmaInfo[i].SglBuffer
);
}
return ApiSuccess;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -