📄 plxchipapi.c
字号:
// Write register values if they have changed
if (RegData.BitsToClear != 0)
{
// Synchronize write of Interrupt Control/Status Register
KeSynchronizeExecution(
pdx->pInterruptObject,
PlxSynchronizedRegisterModify,
&RegData
);
}
if (QueueCsr != QueueCsr_Original)
{
PLX_9000_REG_WRITE(
pdx,
PCI9056_FIFO_CTRL_STAT,
QueueCsr
);
}
return ApiSuccess;
}
/******************************************************************************
*
* Function : PlxChip_EepromReadByOffset
*
* Description: Read a 32-bit value from the EEPROM at a specified offset
*
******************************************************************************/
RETURN_CODE
PlxChip_EepromReadByOffset(
DEVICE_EXTENSION *pdx,
U16 offset,
U32 *pValue
)
{
// Verify the offset
if ((offset & 0x3) || (offset > 0x200))
{
DebugPrintf(("ERROR - Invalid EEPROM offset\n"));
return ApiInvalidOffset;
}
// Read EEPROM
Plx9000_EepromReadByOffset(
pdx,
Eeprom93CS56,
offset,
pValue
);
return ApiSuccess;
}
/******************************************************************************
*
* Function : PlxChip_EepromWriteByOffset
*
* Description: Write a 32-bit value to the EEPROM at a specified offset
*
******************************************************************************/
RETURN_CODE
PlxChip_EepromWriteByOffset(
DEVICE_EXTENSION *pdx,
U16 offset,
U32 value
)
{
U32 RegisterSave;
// Verify the offset
if ((offset & 0x3) || (offset > 0x200))
{
DebugPrintf(("ERROR - Invalid EEPROM offset\n"));
return ApiInvalidOffset;
}
// Unprotect the EEPROM for write access
RegisterSave =
PLX_9000_REG_READ(
pdx,
PCI9056_ENDIAN_DESC
);
PLX_9000_REG_WRITE(
pdx,
PCI9056_ENDIAN_DESC,
RegisterSave & ~(0xFF << 16)
);
// Write to EEPROM
Plx9000_EepromWriteByOffset(
pdx,
Eeprom93CS56,
offset,
value
);
// Restore EEPROM Write-Protected Address Boundary
PLX_9000_REG_WRITE(
pdx,
PCI9056_ENDIAN_DESC,
RegisterSave
);
return ApiSuccess;
}
/******************************************************************************
*
* Function : PlxChip_DmaControl
*
* Description: Control the DMA engine
*
******************************************************************************/
RETURN_CODE
PlxChip_DmaControl(
DEVICE_EXTENSION *pdx,
U8 channel,
PLX_DMA_COMMAND command
)
{
U8 i;
U8 shift;
U32 RegValue;
// Verify valid DMA channel
switch (channel)
{
case 0:
case 1:
i = channel;
shift = (channel * 8);
break;
default:
DebugPrintf(("ERROR - Invalid DMA channel\n"));
return ApiDmaChannelInvalid;
}
switch (command)
{
case DmaPause:
// Pause the DMA Channel
RegValue =
PLX_9000_REG_READ(
pdx,
PCI9056_DMA_COMMAND_STAT
);
PLX_9000_REG_WRITE(
pdx,
PCI9056_DMA_COMMAND_STAT,
RegValue & ~((1 << 0) << shift)
);
// Check if the transfer has completed
RegValue =
PLX_9000_REG_READ(
pdx,
PCI9056_DMA_COMMAND_STAT
);
if (RegValue & ((1 << 4) << shift))
return ApiDmaDone;
break;
case DmaResume:
// Verify that the DMA Channel is paused
RegValue =
PLX_9000_REG_READ(
pdx,
PCI9056_DMA_COMMAND_STAT
);
if ((RegValue & (((1 << 4) | (1 << 0)) << shift)) == 0)
{
PLX_9000_REG_WRITE(
pdx,
PCI9056_DMA_COMMAND_STAT,
RegValue | ((1 << 0) << shift)
);
}
else
{
return ApiDmaInProgress;
}
break;
case DmaAbort:
// Pause the DMA Channel
RegValue =
PLX_9000_REG_READ(
pdx,
PCI9056_DMA_COMMAND_STAT
);
PLX_9000_REG_WRITE(
pdx,
PCI9056_DMA_COMMAND_STAT,
RegValue & ~((1 << 0) << shift)
);
// Check if the transfer has completed
RegValue =
PLX_9000_REG_READ(
pdx,
PCI9056_DMA_COMMAND_STAT
);
if (RegValue & ((1 << 4) << shift))
return ApiDmaDone;
// Abort the transfer (should cause an interrupt)
PLX_9000_REG_WRITE(
pdx,
PCI9056_DMA_COMMAND_STAT,
RegValue | ((1 << 2) << shift)
);
break;
default:
return ApiDmaCommandInvalid;
}
return ApiSuccess;
}
/******************************************************************************
*
* Function : PlxChip_DmaStatus
*
* Description: Get status of a DMA channel
*
******************************************************************************/
RETURN_CODE
PlxChip_DmaStatus(
DEVICE_EXTENSION *pdx,
U8 channel
)
{
U32 RegValue;
// Verify valid DMA channel
switch (channel)
{
case 0:
case 1:
break;
default:
DebugPrintf(("ERROR - Invalid DMA channel\n"));
return ApiDmaChannelInvalid;
}
// Return the current DMA status
RegValue =
PLX_9000_REG_READ(
pdx,
PCI9056_DMA_COMMAND_STAT
);
// Shift status for channel 1
if (channel == 1)
RegValue = RegValue >> 8;
if ((RegValue & ((1 << 4) | (1 << 0))) == 0)
return ApiDmaPaused;
if (RegValue & (1 << 4))
return ApiDmaDone;
return ApiDmaInProgress;
}
/******************************************************************************
*
* Function : PlxChip_DmaChannelOpen
*
* Description: Open a DMA channel
*
******************************************************************************/
RETURN_CODE
PlxChip_DmaChannelOpen(
DEVICE_EXTENSION *pdx,
U8 channel,
PLX_DMA_PROP *pProp,
VOID *pOwner
)
{
U8 i;
U32 RegValue;
KIRQL OriginalIrqL;
PLX_REG_DATA RegData;
// Verify valid DMA channel
switch (channel)
{
case 0:
case 1:
i = channel;
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].bOpen)
{
DebugPrintf(("ERROR - DMA channel already opened\n"));
KeReleaseSpinLock(
&(pdx->Lock_DmaChannel),
OriginalIrqL
);
return ApiDmaChannelUnavailable;
}
// Open the channel
pdx->DmaInfo[i].bOpen = TRUE;
// Record the Owner
pdx->DmaInfo[i].pOwner = pOwner;
// No SGL DMA is pending
pdx->DmaInfo[i].bSglPending = FALSE;
KeReleaseSpinLock(
&(pdx->Lock_DmaChannel),
OriginalIrqL
);
// Setup for synchronized access to Interrupt register
RegData.pdx = pdx;
RegData.offset = PCI9056_INT_CTRL_STAT;
RegData.BitsToClear = 0;
KeAcquireSpinLock(
&(pdx->Lock_HwAccess),
&OriginalIrqL
);
// Setup DMA properties
RegValue =
(0 << 9) | // Disable chaining
(1 << 10) | // Enable DMA done interrupt
(1 << 17) | // Route interrupt to PCI
(0 << 18) | // Disable Dual-Addressing
(0 << 20) | // Disable Valid mode
(pProp->LocalBusWidth << 0) |
(pProp->WaitStates << 2) |
(pProp->ReadyInput << 6) |
(pProp->BurstInfinite << 7) |
(pProp->Burst << 8) |
(pProp->LocalAddrConst << 11) |
(pProp->DemandMode << 12) |
(pProp->WriteInvalidMode << 13) |
(pProp->EOTPin << 14) |
(pProp->StopTransferMode << 15);
if (channel == 0)
{
// Write DMA mode
PLX_9000_REG_WRITE(
pdx,
PCI9056_DMA0_MODE,
RegValue
);
// Clear Dual Address cycle register
PLX_9000_REG_WRITE(
pdx,
PCI9056_DMA0_PCI_DAC,
0
);
// Enable DMA channel interrupt
RegData.BitsToSet = (1 << 18);
}
else
{
// Write DMA mode
PLX_9000_REG_WRITE(
pdx,
PCI9056_DMA1_MODE,
RegValue
);
// Clear Dual Address cycle register
PLX_9000_REG_WRITE(
pdx,
PCI9056_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
*
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -