SylixOS DMA 传输框架

1. 文件结构简介

SylixOS 系统下 dma 代码文件结构,目录:libsylixos/SylixOS/system/device/dma

文件名描述
dma.c主要是 dma 通用抽象,提供 dma 通用的结构抽象,以及 dma 过程的同步
dma.hdma 数据结构的抽象和对外接口
dmaLib.c主要是 dma 使用中链表结构的抽象,用于 dma 任务的增删更改
dmaLib.hdma 链表使用的相关结构抽象

SylixOS dma 文件结构

2. 数据框架流程图

dma 框架的主要流程,使用 API_DmaJobAdd 向任务队列添加相关传输信息,在传输完成中断中清除已经完成的任务,并设置新的任务;

在这里插入图片描述

3. 主要数据结构

/*********************************************************************************************************
  DMA 传输参数
  
  DMA 操作的为物理地址, 所以 Src 和 Dest 地址均为物理地址.
  有些系统 CPU 体系构架的 CACHE 是使用虚拟地址作为索引的, 有些是使用物理地址做索引的.
  所以 DMA 软件层不处理任何 CACHE 相关的操作, 将这些操作留给驱动程序或应用程序完成.
  
  注意: 回调函数将可能会在中断上下文中执行.
*********************************************************************************************************/

typedef struct {
    UINT8                     *DMAT_pucSrcAddress;                      /*  源端缓冲区地址              */
    UINT8                     *DMAT_pucDestAddress;                     /*  目的端缓冲区地址            */
    
    size_t                     DMAT_stDataBytes;                        /*  传输的字节数                */
    
    INT                        DMAT_iSrcAddrCtl;                        /*  源端地址方向控制            */
    INT                        DMAT_iDestAddrCtl;                       /*  目的地址方向控制            */
    
    INT                        DMAT_iHwReqNum;                          /*  外设请求端编号              */
    BOOL                       DMAT_bHwReqEn;                           /*  是否为外设启动 DMA 传输     */
    BOOL                       DMAT_bHwHandshakeEn;                     /*  是否使用硬件握手            */
    
    INT                        DMAT_iTransMode;                         /*  传输模式, 自定义            */
    PVOID                      DMAT_pvTransParam;                       /*  传输参数, 自定义            */
    ULONG                      DMAT_ulOption;                           /*  体系结构相关参数            */
    
    PVOID                      DMAT_pvArgStart;                         /*  启动回调参数                */
    VOID                     (*DMAT_pfuncStart)(UINT     uiChannel,
                                                PVOID    pvArg);        /*  启动本次传输之前的回调函数  */
    
    PVOID                     *DMAT_pvArg;                              /*  回调函数参数                */
    VOID                     (*DMAT_pfuncCallback)(UINT     uiChannel,
                                                   PVOID    pvArg);     /*  本次传输完成后的回调函数    */
} LW_DMA_TRANSACTION;
typedef LW_DMA_TRANSACTION    *PLW_DMA_TRANSACTION;

/*********************************************************************************************************
  DMA 设备定义 (驱动程序接口)
*********************************************************************************************************/

typedef struct lw_dma_funcs {
    VOID                     (*DMAF_pfuncReset)(UINT     uiChannel,
                                                struct lw_dma_funcs *pdmafuncs);
                                                                        /*  复位 DMA 当前的操作         */
    INT                      (*DMAF_pfuncTrans)(UINT     uiChannel,
                                                struct lw_dma_funcs *pdmafuncs,
                                                PLW_DMA_TRANSACTION  pdmatMsg);
                                                                        /*  启动一次 DMA 传输           */
    INT                      (*DMAF_pfuncStatus)(UINT    uiChannel,
                                                 struct lw_dma_funcs *pdmafuncs);
                                                                        /*  获得 DMA 当前的工作状态     */
} LW_DMA_FUNCS;
typedef LW_DMA_FUNCS    *PLW_DMA_FUNCS;
/*********************************************************************************************************
  DMA 传输控制节点
*********************************************************************************************************/

typedef struct {
    LW_LIST_RING            DMAN_ringManage;                            /*  双向管理链表                */
    BOOL                    DMAN_bDontFree;                             /*  是否释放内存                */
    LW_DMA_TRANSACTION      DMAN_pdmatMsg;                              /*  传输传输控制块              */
} __DMA_WAITNODE;
typedef __DMA_WAITNODE     *__PDMA_WAITNODE;

/*********************************************************************************************************
  DMA 通道控制块
*********************************************************************************************************/

typedef struct {
    PLW_LIST_RING           DMAC_pringHead;                             /*  传输控制链表头              */

    INT                     DMAC_iNodeCounter;                          /*  节点计数器, 调试使用        */
    INT                     DMAC_iMaxNode;                              /*  列队中可以存在的最多 NODE   */
                                                                        /*  当 dma job add 超过此数量时 */
                                                                        /*  将阻塞, 直到少于此值        */
    LW_OBJECT_HANDLE        DMAC_ulJobSync;                             /*  任务队列同步锁              */
    BOOL                    DMAC_bIsInFlush;                            /*  是否正在清除队列            */
    
    PLW_DMA_FUNCS           DMAC_pdmafuncs;                             /*  DMA 驱动程序                */
    size_t                  DMAC_stMaxDataBytes;                        /*  最大传输传输长度            */
} __DMA_CHANNEL;
typedef __DMA_CHANNEL      *__PDMA_CHANNEL;

4. 主要函数

  • API_DmaDrvInstall
    dma 驱动函数安装,根据不同的 dma 外设,安装相应的驱动;
/*********************************************************************************************************
** 函数名称: API_DmaDrvInstall
** 功能描述: 安装通用 DMA 驱动程序
** 输 入  : uiChannel              通道
**           pdmafuncs              驱动函数集
**           stMaxDataBytes         每一次传输的最多字节数
** 输 出  : ERROR
** 全局变量: 
** 调用模块: 
                                           API 函数
*********************************************************************************************************/
LW_API 
INT    API_DmaDrvInstall (UINT              uiChannel,
                          PLW_DMA_FUNCS     pdmafuncs,
                          size_t            stMaxDataBytes)
{
#define __DMA_CHANNEL_MAX_NODE              8                           /*  默认单通道最大任务节点数    */

    static   BOOL   bIsInit = LW_FALSE;
    
    if (bIsInit == LW_FALSE) {
        bIsInit =  LW_TRUE;
        LW_SPIN_INIT(&_G_slDmaManage);                                  /*  初始化自旋锁                */
        _dmaInit();                                                     /*  初始化相关结构              */
    }
    
    if (__DMA_CHANNEL_INVALID(uiChannel)) {
        _DebugHandle(__ERRORMESSAGE_LEVEL, "dma channel invalid.\r\n");
        _ErrorHandle(ERROR_DMA_CHANNEL_INVALID);
        return  (PX_ERROR);
    }
    
    if ((pdmafuncs == LW_NULL) || (stMaxDataBytes == 0)) {              /*  检查参数                    */
        _ErrorHandle(EINVAL);
        return  (PX_ERROR);
    }
    
    _G_dmacChannel[uiChannel].DMAC_pdmafuncs      = pdmafuncs;
    _G_dmacChannel[uiChannel].DMAC_stMaxDataBytes = stMaxDataBytes;
                                                                        /*  没有安装过驱动              */
    if (_G_dmacChannel[uiChannel].DMAC_ulJobSync == LW_OBJECT_HANDLE_INVALID) {
        _G_dmacChannel[uiChannel].DMAC_pringHead    = LW_NULL;
        _G_dmacChannel[uiChannel].DMAC_iNodeCounter = 0;
        _G_dmacChannel[uiChannel].DMAC_iMaxNode     = __DMA_CHANNEL_MAX_NODE;   
                                                                        /*  默认最多 8 个节点           */
        _G_dmacChannel[uiChannel].DMAC_ulJobSync    = API_SemaphoreBCreate("dma_jobsync", 
                                                                   LW_FALSE, 
                                                                   LW_OPTION_WAIT_FIFO | 
                                                                   LW_OPTION_OBJECT_GLOBAL, 
                                                                   LW_NULL);
                                                                        /*  创建同步工作队列            */
        if (!_G_dmacChannel[uiChannel].DMAC_ulJobSync) {
            _DebugHandle(__ERRORMESSAGE_LEVEL, "can not create dma_jobsync.\r\n");
            return  (PX_ERROR);
        }
    }
    __DMA_CHANNEL_RESET(uiChannel);
    
    return  (ERROR_NONE);
}
  • API_DmaReset
    操作驱动对指定通道的 DMA 进行复位
/*********************************************************************************************************
** 函数名称: API_DmaReset
** 功能描述: 复位指定通道的 DMA 控制器 
** 输 入  : uiChannel      DMA 通道号
** 输 出  : PX_ERROR or ERROR_NONE
** 全局变量: 
** 调用模块: 
                                           API 函数
*********************************************************************************************************/
LW_API 
INT     API_DmaReset (UINT  uiChannel)
{
    if (__DMA_CHANNEL_INVALID(uiChannel)) {
        _DebugHandle(__ERRORMESSAGE_LEVEL, "dma channel invalid.\r\n");
        _ErrorHandle(ERROR_DMA_CHANNEL_INVALID);
        return  (PX_ERROR);
    }
    
    __DMA_CHANNEL_RESET(uiChannel);
    
    return  (ERROR_NONE);
}
  • API_DmaJobNodeNum
    获取指定通道 dma 缓存节点个数
/*********************************************************************************************************
** 函数名称: API_DmaJobNodeNum
** 功能描述: 获得指定 DMA 通道当前等待队列的节点数
** 输 入  : uiChannel      DMA 通道号
**           piNodeNum      当前节点数量缓存
** 输 出  : PX_ERROR or ERROR_NONE
** 全局变量: 
** 调用模块: 
                                           API 函数
*********************************************************************************************************/
LW_API 
INT     API_DmaJobNodeNum (UINT   uiChannel, INT  *piNodeNum)
{
             INTREG             iregInterLevel;
    REGISTER __PDMA_CHANNEL     pdmacChannel;

    if (__DMA_CHANNEL_INVALID(uiChannel)) {
        _DebugHandle(__ERRORMESSAGE_LEVEL, "dma channel invalid.\r\n");
        _ErrorHandle(ERROR_DMA_CHANNEL_INVALID);
        return  (PX_ERROR);
    }
    
    pdmacChannel = __DMA_CHANNEL_GET(uiChannel);
    
    if (piNodeNum) {
        LW_SPIN_LOCK_QUICK(&_G_slDmaManage, &iregInterLevel);           /*  关闭中断同时锁住 spinlock   */
        *piNodeNum = pdmacChannel->DMAC_iNodeCounter;
        LW_SPIN_UNLOCK_QUICK(&_G_slDmaManage, iregInterLevel);          /*  打开中断同时解锁 spinlock   */
    }
    
    return  (ERROR_NONE);
}
  • API_DmaMaxNodeNumGet
    获取指定 dma 通道允许的最大节点数
/*********************************************************************************************************
** 函数名称: API_DmaMaxNodeNumGet
** 功能描述: 获得指定 DMA 通道当前等待队列的节点数
** 输 入  : uiChannel      DMA 通道号
**           piMaxNodeNum   允许最大节点缓冲
** 输 出  : PX_ERROR or ERROR_NONE
** 全局变量: 
** 调用模块: 
                                           API 函数
*********************************************************************************************************/
LW_API 
INT     API_DmaMaxNodeNumGet (UINT   uiChannel, INT  *piMaxNodeNum)
{
             INTREG             iregInterLevel;
    REGISTER __PDMA_CHANNEL     pdmacChannel;

    if (__DMA_CHANNEL_INVALID(uiChannel)) {
        _DebugHandle(__ERRORMESSAGE_LEVEL, "dma channel invalid.\r\n");
        _ErrorHandle(ERROR_DMA_CHANNEL_INVALID);
        return  (PX_ERROR);
    }
    
    pdmacChannel = __DMA_CHANNEL_GET(uiChannel);
    
    if (piMaxNodeNum) {
        LW_SPIN_LOCK_QUICK(&_G_slDmaManage, &iregInterLevel);           /*  关闭中断同时锁住 spinlock   */
        *piMaxNodeNum = pdmacChannel->DMAC_iMaxNode;
        LW_SPIN_UNLOCK_QUICK(&_G_slDmaManage, iregInterLevel);          /*  打开中断同时解锁 spinlock   */
    }
    
    return  (ERROR_NONE);
}
  • API_DmaMaxNodeNumSet
    设置指定通道 dma 最大允许的节点数;
/*********************************************************************************************************
** 函数名称: API_DmaMaxNodeNumSet
** 功能描述: 设置指定 DMA 通道当前等待队列的节点数
** 输 入  : uiChannel      DMA 通道号
**           iMaxNodeNum    允许最大节点缓冲
** 输 出  : PX_ERROR or ERROR_NONE
** 全局变量: 
** 调用模块: 
                                           API 函数
*********************************************************************************************************/
LW_API 
INT     API_DmaMaxNodeNumSet (UINT   uiChannel, INT  iMaxNodeNum)
{
             INTREG             iregInterLevel;
    REGISTER __PDMA_CHANNEL     pdmacChannel;

    if (__DMA_CHANNEL_INVALID(uiChannel)) {
        _DebugHandle(__ERRORMESSAGE_LEVEL, "dma channel invalid.\r\n");
        _ErrorHandle(ERROR_DMA_CHANNEL_INVALID);
        return  (PX_ERROR);
    }
    
    pdmacChannel = __DMA_CHANNEL_GET(uiChannel);
    
    /*
     *  注意, 这里并没有判断 iMaxNodeNum 有效性, 可能设置为 0 或者负数停止工作队列执行.
     */
    LW_SPIN_LOCK_QUICK(&_G_slDmaManage, &iregInterLevel);               /*  关闭中断同时锁住 spinlock   */
    pdmacChannel->DMAC_iMaxNode = iMaxNodeNum;
    LW_SPIN_UNLOCK_QUICK(&_G_slDmaManage, iregInterLevel);              /*  打开中断同时解锁 spinlock   */
    
    return  (ERROR_NONE);
}
  • API_DmaJobAdd
    向指定通道的 dma 添加相关传输请求;
/*********************************************************************************************************
** 函数名称: API_DmaJobAdd
** 功能描述: 添加一个 DMA 传输请求
** 输 入  : uiChannel      DMA 通道号
**           pdmatMsg       DMA 相关信息
** 输 出  : PX_ERROR or ERROR_NONE
** 全局变量: 
** 调用模块: 
                                           API 函数
*********************************************************************************************************/
LW_API 
INT     API_DmaJobAdd (UINT                 uiChannel,
                       PLW_DMA_TRANSACTION  pdmatMsg)
{
#define __SAFE()    if (!bInterContext) {   LW_THREAD_SAFE();   }
#define __UNSAFE()  if (!bInterContext) {   LW_THREAD_UNSAFE(); }

             INTREG             iregInterLevel;
    REGISTER __PDMA_CHANNEL     pdmacChannel;
    REGISTER __PDMA_WAITNODE    pdmanNodeNew;
             BOOL               bInterContext;
    
    if (__DMA_CHANNEL_INVALID(uiChannel)) {
        _DebugHandle(__ERRORMESSAGE_LEVEL, "dma channel invalid.\r\n");
        _ErrorHandle(ERROR_DMA_CHANNEL_INVALID);
        return  (PX_ERROR);
    }
    
    if (!pdmatMsg) {
        _DebugHandle(__ERRORMESSAGE_LEVEL, "pdmatMsg invalid.\r\n");
        _ErrorHandle(ERROR_DMA_TRANSMSG_INVALID);
        return  (PX_ERROR);
    }
    
    if (pdmatMsg->DMAT_stDataBytes > 
        _G_dmacChannel[uiChannel].DMAC_stMaxDataBytes) {                /*  数据量过大                  */
        _DebugHandle(__ERRORMESSAGE_LEVEL, "data too large.\r\n");
        _ErrorHandle(ERROR_DMA_DATA_TOO_LARGE);
        return  (PX_ERROR);
    }
    
    bInterContext = API_InterContext();
    pdmacChannel  = __DMA_CHANNEL_GET(uiChannel);
    
    do {
        LW_SPIN_LOCK_QUICK(&_G_slDmaManage, &iregInterLevel);           /*  关闭中断同时锁住 spinlock   */
        if (pdmacChannel->DMAC_iNodeCounter >= 
            pdmacChannel->DMAC_iMaxNode) {
            LW_SPIN_UNLOCK_QUICK(&_G_slDmaManage, iregInterLevel);      /*  打开中断同时解锁 spinlock   */
            
            if (bInterContext) {                                        /*  在中断中调用                */
                _ErrorHandle(ERROR_DMA_MAX_NODE);
                return  (PX_ERROR);
                
            } else if (API_SemaphoreBPend(pdmacChannel->DMAC_ulJobSync, 
                            LW_OPTION_WAIT_INFINITE) != ERROR_NONE) {   /*  等待                        */
                return  (PX_ERROR);
            }
        } else {                                                        /*  满足插入节点条件            */
            LW_SPIN_UNLOCK_QUICK(&_G_slDmaManage, iregInterLevel);      /*  打开中断同时解锁 spinlock   */
            break;
        }
    } while (1);                                                        /*  循环等待                    */
    
    __SAFE();
    
    LW_SPIN_LOCK_QUICK(&_G_slDmaManage, &iregInterLevel);               /*  关闭中断同时锁住 spinlock   */
    pdmanNodeNew = _dmaWaitnodeAlloc();                                 /*  使用快速分配节点            */
    LW_SPIN_UNLOCK_QUICK(&_G_slDmaManage, iregInterLevel);              /*  打开中断同时解锁 spinlock   */
    
    if (pdmanNodeNew) {                                                 /*  有可供快速使用的节点        */
        pdmanNodeNew->DMAN_bDontFree = LW_TRUE;                         /*  不需要释放操作              */
    } else {                                                            /*  需要进行动态内存分配        */
        
        if (bInterContext) {                                            /*  在中断中调用                */
            __UNSAFE();
            _ErrorHandle(ERROR_DMA_NO_FREE_NODE);                       /*  缺少空闲节点                */
            return  (PX_ERROR);
        }
        
        pdmanNodeNew = (__PDMA_WAITNODE)__SHEAP_ALLOC(sizeof(__DMA_WAITNODE));
        if (pdmanNodeNew) {
            pdmanNodeNew->DMAN_bDontFree = LW_FALSE;                    /*  需要释放操作                */
        
        } else {
            __UNSAFE();
            _ErrorHandle(ERROR_SYSTEM_LOW_MEMORY);                      /*  缺少内存                    */
            return  (PX_ERROR);
        }
    }
    
    pdmanNodeNew->DMAN_pdmatMsg = *pdmatMsg;                            /*  保存消息                    */
    
    LW_SPIN_LOCK_QUICK(&_G_slDmaManage, &iregInterLevel);               /*  关闭中断同时锁住 spinlock   */
    _dmaInsertToWaitList(pdmacChannel, pdmanNodeNew);                   /*  插入 DMA 待处理队列         */
    if (pdmacChannel->DMAC_iNodeCounter == 1) {                         /*  只有唯一的一个节点          */
        if (pdmanNodeNew->DMAN_pdmatMsg.DMAT_pfuncStart) {
            pdmanNodeNew->DMAN_pdmatMsg.DMAT_pfuncStart(uiChannel,
            pdmanNodeNew->DMAN_pdmatMsg.DMAT_pvArgStart);               /*  执行启动回调                */
        }
        {
            INT     iRet = ERROR_NONE;
            __DMA_CHANNEL_TRANS(uiChannel, pdmatMsg, iRet);             /*  初始化传输诸元              */
            (VOID)iRet;                                                 /*  暂不处理错误                */
        }
    }
    LW_SPIN_UNLOCK_QUICK(&_G_slDmaManage, iregInterLevel);              /*  打开中断同时解锁 spinlock   */
    
    __UNSAFE();
    
    return  (ERROR_NONE);
}
  • API_DmaFlush
    删除指定通道下 dma 所有的任务节点;
/*********************************************************************************************************
** 函数名称: API_DmaFlush
** 功能描述: 删除所有被延迟处理的传输请求 (不调用回调函数)
** 输 入  : uiChannel      DMA 通道号
** 输 出  : PX_ERROR or ERROR_NONE
** 全局变量: 
** 调用模块: 
                                           API 函数
*********************************************************************************************************/
LW_API 
INT     API_DmaFlush (UINT   uiChannel)
{
             INTREG             iregInterLevel;
    REGISTER __PDMA_CHANNEL     pdmacChannel;
    REGISTER __PDMA_WAITNODE    pdmanNode;
    
    if (__DMA_CHANNEL_INVALID(uiChannel)) {
        _DebugHandle(__ERRORMESSAGE_LEVEL, "dma channel invalid.\r\n");
        _ErrorHandle(ERROR_DMA_CHANNEL_INVALID);
        return  (PX_ERROR);
    }
    
    if (LW_CPU_GET_CUR_NESTING()) {                                     /*  不能在中断中调用            */
        _ErrorHandle(ERROR_KERNEL_IN_ISR);
        return  (PX_ERROR);
    }
    
    pdmacChannel = __DMA_CHANNEL_GET(uiChannel);                        /*  获得通道控制块              */
    
    LW_THREAD_SAFE();
    
    pdmacChannel->DMAC_bIsInFlush = LW_TRUE;                            /*  开始进行 FLUSH 操作         */
    for (;;) {
        LW_SPIN_LOCK_QUICK(&_G_slDmaManage, &iregInterLevel);           /*  关闭中断同时锁住 spinlock   */
        pdmanNode = _dmaGetFirstInWaitList(pdmacChannel);               /*  获得最近的一个节点          */
        if (!pdmanNode) {                                               /*  没有节点了                  */
            __DMA_CHANNEL_RESET(uiChannel);                             /*  复位通道                    */
            LW_SPIN_UNLOCK_QUICK(&_G_slDmaManage, iregInterLevel);      /*  打开中断同时解锁 spinlock   */
            break;                                                      /*  跳出循环                    */
        }
        _dmaDeleteFromWaitList(pdmacChannel, pdmanNode);                /*  从等待队列删除这个节点      */
        if (pdmanNode->DMAN_bDontFree) {
            _dmaWaitnodeFree(pdmanNode);                                /*  加入到空闲队列              */
            LW_SPIN_UNLOCK_QUICK(&_G_slDmaManage, iregInterLevel);      /*  打开中断同时解锁 spinlock   */
        
        } else {
            LW_SPIN_UNLOCK_QUICK(&_G_slDmaManage, iregInterLevel);      /*  打开中断同时解锁 spinlock   */
            __SHEAP_FREE(pdmanNode);                                    /*  释放到内存堆中              */
        }
    }
    pdmacChannel->DMAC_bIsInFlush = LW_FALSE;                           /*  结束 FLUSH 操作             */
    
    API_SemaphoreBPost(pdmacChannel->DMAC_ulJobSync);                   /*  释放同步信号量              */
    
    LW_THREAD_UNSAFE();
    
    return  (ERROR_NONE);
}
  • API_DmaContext

指定通道 DMA 中断服务函数;

/*********************************************************************************************************
** 函数名称: API_DmaContext
** 功能描述: 指定通道 DMA 中断服务函数.这里不判断通道有效性,使用时请小心!
** 输 入  : uiChannel      DMA 通道号
** 输 出  : PX_ERROR or ERROR_NONE
** 全局变量: 
** 调用模块: 
                                           API 函数
*********************************************************************************************************/
LW_API 
INT     API_DmaContext (UINT   uiChannel)
{
             INTREG             iregInterLevel;
    REGISTER __PDMA_CHANNEL     pdmacChannel;
    REGISTER __PDMA_WAITNODE    pdmanNode;
    REGISTER __PDMA_WAITNODE    pdmanNodeNew;                           /*  最新需要处理的节点          */
    
    pdmacChannel = __DMA_CHANNEL_GET(uiChannel);                        /*  获得通道控制块              */
    
    if (pdmacChannel->DMAC_bIsInFlush) {                                /*  在执行 FLUSH 操作           */
        return  (ERROR_NONE);
    }
    
    LW_SPIN_LOCK_QUICK(&_G_slDmaManage, &iregInterLevel);               /*  关闭中断同时锁住 spinlock   */
    pdmanNode = _dmaGetFirstInWaitList(pdmacChannel);                   /*  获得最近的一个节点          */
    if (!pdmanNode) {                                                   /*  没有节点了                  */
        LW_SPIN_UNLOCK_QUICK(&_G_slDmaManage, iregInterLevel);          /*  打开中断同时解锁 spinlock   */
        return  (ERROR_NONE);
    }
    _dmaDeleteFromWaitList(pdmacChannel, pdmanNode);                    /*  从等待队列删除这个节点      */
    LW_SPIN_UNLOCK_QUICK(&_G_slDmaManage, iregInterLevel);              /*  打开中断同时解锁 spinlock   */
    
    /*
     *  以最快方式插入新节点, 防止音频播放断续.
     */
    LW_SPIN_LOCK_QUICK(&_G_slDmaManage, &iregInterLevel);               /*  关闭中断同时锁住 spinlock   */
    pdmanNodeNew = _dmaGetFirstInWaitList(pdmacChannel);                /*  获得最近的一个节点          */
    if (pdmanNodeNew) {                                                 /*  存在新节点                  */
        if (pdmanNodeNew->DMAN_pdmatMsg.DMAT_pfuncStart) {
            pdmanNodeNew->DMAN_pdmatMsg.DMAT_pfuncStart(uiChannel,
            pdmanNodeNew->DMAN_pdmatMsg.DMAT_pvArgStart);               /*  执行启动回调                */
        }
        {
            INT     iRet = ERROR_NONE;
            __DMA_CHANNEL_TRANS(uiChannel,
                                &pdmanNodeNew->DMAN_pdmatMsg,
                                iRet);                                  /*  初始化传输诸元              */
            (VOID)iRet;                                                 /*  暂不处理错误                */
        }
    }
    LW_SPIN_UNLOCK_QUICK(&_G_slDmaManage, iregInterLevel);              /*  打开中断同时解锁 spinlock   */
    
    if (pdmanNode->DMAN_pdmatMsg.DMAT_pfuncCallback) {
        pdmanNode->DMAN_pdmatMsg.DMAT_pfuncCallback(uiChannel,
        pdmanNode->DMAN_pdmatMsg.DMAT_pvArg);                           /*  调用回调函数                */
    }
    
    /*
     *  释放原有节点
     */
    if (pdmanNode->DMAN_bDontFree) {
        LW_SPIN_LOCK_QUICK(&_G_slDmaManage, &iregInterLevel);           /*  关闭中断同时锁住 spinlock   */
        _dmaWaitnodeFree(pdmanNode);                                    /*  加入到空闲队列              */
        LW_SPIN_UNLOCK_QUICK(&_G_slDmaManage, iregInterLevel);          /*  打开中断同时解锁 spinlock   */
    
    } else {
        _excJobAdd((VOIDFUNCPTR)_HeapFree, 
                   (PVOID)_K_pheapSystem, 
                   (PVOID)pdmanNode,                                    /*  释放节点                    */
                   (PVOID)LW_FALSE,
                   0, 0, 0);                                            /*  添加到延迟作业队列处理      */
    }
    
    /*
     *  检查是否需要释放同步信号量.
     */
    LW_SPIN_LOCK_QUICK(&_G_slDmaManage, &iregInterLevel);               /*  关闭中断同时锁住 spinlock   */
    if ((pdmacChannel->DMAC_iMaxNode - pdmacChannel->DMAC_iNodeCounter) == 1) {
        LW_SPIN_UNLOCK_QUICK(&_G_slDmaManage, iregInterLevel);          /*  打开中断同时解锁 spinlock   */
        API_SemaphoreBPost(pdmacChannel->DMAC_ulJobSync);               /*  释放同步信号量              */
    
    } else {
        LW_SPIN_UNLOCK_QUICK(&_G_slDmaManage, iregInterLevel);          /*  打开中断同时解锁 spinlock   */
    }
    
    return  (ERROR_NONE);
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值