📄 apifunctions.c
字号:
}
/******************************************************************************
*
* Function : PlxMuOutboundPortWrite
*
* Description: Writes to the outbound port with a free message frame
*
******************************************************************************/
RETURN_CODE
PlxMuOutboundPortWrite(
DEVICE_EXTENSION *pdx,
U32 Frame
)
{
PLX_REG_WRITE(
pdx,
0x44,
Frame
);
return ApiSuccess;
}
/******************************************************************************
*
* Function : PlxDmaControl
*
* Description: Control the DMA engine
*
******************************************************************************/
RETURN_CODE
PlxDmaControl(
DEVICE_EXTENSION *pdx,
DMA_CHANNEL channel,
DMA_COMMAND command
)
{
U8 i;
U8 shift;
U32 RegValue;
// Verify valid DMA channel
switch (channel)
{
case PrimaryPciChannel0:
i = 0;
shift = 0;
break;
case PrimaryPciChannel1:
i = 1;
shift = 8;
break;
default:
DebugPrintf(("ERROR - Invalid DMA channel\n"));
return ApiDmaChannelInvalid;
}
// Verify that this channel has been opened
if (pdx->DmaInfo[i].state == DmaStateClosed)
{
DebugPrintf(("ERROR - DMA Channel has not been opened\n"));
return ApiDmaChannelUnavailable;
}
switch (command)
{
case DmaPause:
// Pause the DMA Channel
RegValue =
PLX_REG_READ(
pdx,
PCI9054_DMA_COMMAND_STAT
);
PLX_REG_WRITE(
pdx,
PCI9054_DMA_COMMAND_STAT,
RegValue & ~((1 << 0) << shift)
);
// Check if the transfer has completed
RegValue =
PLX_REG_READ(
pdx,
PCI9054_DMA_COMMAND_STAT
);
if (RegValue & ((1 << 4) << shift))
return ApiDmaDone;
break;
case DmaResume:
// Verify that the DMA Channel is paused
RegValue =
PLX_REG_READ(
pdx,
PCI9054_DMA_COMMAND_STAT
);
if ((RegValue & (((1 << 4) | (1 << 0)) << shift)) == 0)
{
PLX_REG_WRITE(
pdx,
PCI9054_DMA_COMMAND_STAT,
RegValue | ((1 << 0) << shift)
);
}
else
{
return ApiDmaNotPaused;
}
break;
case DmaAbort:
// Pause the DMA Channel
RegValue =
PLX_REG_READ(
pdx,
PCI9054_DMA_COMMAND_STAT
);
PLX_REG_WRITE(
pdx,
PCI9054_DMA_COMMAND_STAT,
RegValue & ~((1 << 0) << shift)
);
// Check if the transfer has completed
RegValue =
PLX_REG_READ(
pdx,
PCI9054_DMA_COMMAND_STAT
);
if (RegValue & ((1 << 4) << shift))
return ApiDmaDone;
// Abort the transfer (should cause an interrupt)
PLX_REG_WRITE(
pdx,
PCI9054_DMA_COMMAND_STAT,
RegValue | ((1 << 2) << shift)
);
break;
default:
return ApiDmaCommandInvalid;
}
return ApiSuccess;
}
/******************************************************************************
*
* Function : PlxDmaStatus
*
* Description: Get status of a DMA channel
*
******************************************************************************/
RETURN_CODE
PlxDmaStatus(
DEVICE_EXTENSION *pdx,
DMA_CHANNEL channel
)
{
U32 RegValue;
// Verify valid DMA channel
switch (channel)
{
case PrimaryPciChannel0:
case PrimaryPciChannel1:
break;
default:
DebugPrintf(("ERROR - Invalid DMA channel\n"));
return ApiDmaChannelInvalid;
}
// Return the current DMA status
RegValue =
PLX_REG_READ(
pdx,
PCI9054_DMA_COMMAND_STAT
);
if (channel == PrimaryPciChannel1)
RegValue = RegValue >> 8;
if ((RegValue & ((1 << 4) | (1 << 0))) == 0)
return ApiDmaPaused;
if (RegValue & (1 << 4))
return ApiDmaDone;
return ApiDmaInProgress;
}
/******************************************************************************
*
* Function : PlxDmaBlockChannelOpen
*
* Description: Requests usage of a device's DMA channel
*
******************************************************************************/
RETURN_CODE
PlxDmaBlockChannelOpen(
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 = DmaStateBlock;
// 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 =
(0 << 9) | // No Chaining
(1 << 10) | // Enable DMA Done interrupt
(1 << 17) | // Route interrupts to PCI
(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) |
(pDesc->EnableDualAddressCycles << 18);
// 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
);
}
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
);
}
KeReleaseSpinLock(
&(pdx->Lock_HwAccess),
OriginalIrqL
);
return ApiSuccess;
}
/******************************************************************************
*
* Function : PlxDmaBlockTransfer
*
* Description: Performs DMA block transfer
*
******************************************************************************/
RETURN_CODE
PlxDmaBlockTransfer(
DEVICE_EXTENSION *pdx,
DMA_CHANNEL channel,
DMA_TRANSFER_ELEMENT *pDmaData
)
{
U8 i;
U8 shift;
U16 OffsetDmaBase;
U16 OffsetPciAddrHigh;
U32 RegValue;
KIRQL OriginalIrqL;
// Setup transfer registers
switch (channel)
{
case PrimaryPciChannel0:
i = 0;
shift = 0;
OffsetDmaBase = PCI9054_DMA0_MODE;
OffsetPciAddrHigh = PCI9054_DMA0_PCI_DAC;
break;
case PrimaryPciChannel1:
i = 1;
shift = 8;
OffsetDmaBase = PCI9054_DMA1_MODE;
OffsetPciAddrHigh = PCI9054_DMA1_PCI_DAC;
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 != DmaStateBlock)
{
DebugPrintf(("ERROR - DMA Channel has not been opened for Block DMA\n"));
KeReleaseSpinLock(
&(pdx->Lock_DmaChannel),
OriginalIrqL
);
return ApiDmaChannelUnavailable;
}
KeReleaseSpinLock(
&(pdx->Lock_DmaChannel),
OriginalIrqL
);
KeAcquireSpinLock(
&(pdx->Lock_HwAccess),
&OriginalIrqL
);
// Make sure DMA done interrupt is enabled
RegValue =
PLX_REG_READ(
pdx,
OffsetDmaBase
);
RegValue |= (1 << 10);
PLX_REG_WRITE(
pdx,
OffsetDmaBase,
RegValue
);
// Write PCI Address
PLX_REG_WRITE(
pdx,
OffsetDmaBase + 0x4,
pDmaData->u.PciAddrLow
);
// Write Local Address
PLX_REG_WRITE(
pdx,
OffsetDmaBase + 0x8,
pDmaData->LocalAddr
);
// Write Transfer Count
PLX_REG_WRITE(
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -