/*****************************************************************************/
/**
* 将给定的BD克隆到列表中的每个BD中
* 源BD的每个字段被复制到列表的每个BD中。
*
* 这个函数只能在所有的BDs都在free组中时调用,例如在使用XEmacPs_BdRingCreate()初始化之后立即调用。
* 这可以防止在硬件或用户使用bd时对它们进行修改。
*
* @param RingPtr 要处理的BD环实例的指针。
* @param SrcBdPtr 要克隆到列表中的源BD模板。这个BD会被修改。
* @param Direction XEMACPS_SEND或XEMACPS_RECV,表示哪个方向。
*
* @return
* - XST_SUCCESS 如果列表被修改.
* - XST_DMA_SG_NO_LIST 如果没有创建列表.
* - XST_DMA_SG_LIST_ERROR 如果这个通道的一些BD在硬件或用户控制。
* - XST_DEVICE_IS_STARTED 如果DMA通道没有停止
*
*****************************************************************************/
LONG XEmacPs_BdRingClone(XEmacPs_BdRing * RingPtr, XEmacPs_Bd * SrcBdPtr,
u8 Direction)
{
u32 i;
UINTPTR CurBd;
/* 如果没有环,则无法执行此功能 */
if (RingPtr->AllCnt == 0x00000000U) {
return (LONG)(XST_DMA_SG_NO_LIST);
}
/* 在通道运行时无法执行此功能 */
if (RingPtr->RunState == (u32)XST_DMA_SG_IS_STARTED) {
return (LONG)(XST_DEVICE_IS_STARTED);
}
/* 当某些 BD 正在使用时无法执行此功能 */
if (RingPtr->FreeCnt != RingPtr->AllCnt) {
return (LONG)(XST_DMA_SG_LIST_ERROR);
}
if ((Direction != (u8)XEMACPS_SEND) && (Direction != (u8)XEMACPS_RECV)) {
return (LONG)(XST_INVALID_PARAM);
}
/* 从环的顶部开始, 保存 BD.Next, 用模板覆盖整个BD, 然后恢复BD.Next */
CurBd = RingPtr->BaseBdAddr;
for (i = 0U; i < RingPtr->AllCnt; i++) {
memcpy((void *)CurBd, SrcBdPtr, sizeof(XEmacPs_Bd));
CurBd += RingPtr->Separation;
}
CurBd -= RingPtr->Separation;
if (Direction == XEMACPS_RECV) {
XEmacPs_BdSetRxWrap(CurBd);
}
else {
XEmacPs_BdSetTxWrap(CurBd);
}
return (LONG)(XST_SUCCESS);
}