⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 c54xx_dma_mcbsp.c

📁 用DSP5410实现对音乐文件音量的限制性调节
💻 C
字号:
/*
 *  Copyright 2003 by Texas Instruments Incorporated.
 *  All rights reserved. Property of Texas Instruments Incorporated.
 *  Restricted rights to use, duplicate or disclose this code are
 *  granted through contract.
 *  
 */
/* "@(#) DDK 1.11.00.00 11-04-03 (ddk-b13)" */
/*
 *  ======== c54xx_dma_mcbsp.c ========
 */

#include <std.h>

#include <atm.h>
#include <hwi.h>
#include <que.h>

#include <csl.h>
#include <csl_dma.h>
#include <csl_irq.h>
#include <csl_mcbsp.h>

#include <iom.h>

#include <c54xx_dma_mcbsp.h>

#define NUMPORTS        MCBSP_PORT_CNT
#define DELAY 10000

/* Channel Object -- intialized by mdCreateChan() */
typedef struct ChanObj {
    Uns         inUse;          /* TRUE => channel has been opened */

    Uns         dmaId;          /* channel id */

    void        *devp;          /* needed for McBSP access */

    DMA_Handle  hDma;           /* DMA handle */

    IOM_Packet  *flushPacket;   /* used for submit/IOM_FLUSH/output */

    IOM_Packet  *dataPacket;    /* current active I/O packet */
    QUE_Obj     pendList;       /* list of packets for I/O */

    IOM_TiomCallback cbFxn;     /* used to notify client when I/O complete */
    Ptr         cbArg;
} ChanObj, *ChanHandle;

#define CHANOBJINIT { \
    FALSE,              /* inUse */             \
    0,                  /* dmaId */             \
    NULL,               /* devp */              \
    NULL,               /* hDma */              \
    NULL,               /* flushPacket */       \
    NULL,               /* dataPacket */        \
    { NULL, NULL },     /* pendList */          \
    NULL,               /* cbFxn */             \
    NULL                /* cbArg */             \
}

/* Device Object -- intialized by mdBindDev() */
typedef struct PortObj {
    Uns         inUse;
    MCBSP_Handle hMcbsp;        /* McBSP handle */
    ChanObj     chans[NUMCHANS];
    Uns         rxIntrMask;
    Uns         txIntrMask;
} PortObj, *PortHandle;

#define PORTOBJINIT { \
    FALSE,              /* inUse */             \
    NULL,               /* hMcbsp */            \
    {                   /* chans */             \
        CHANOBJINIT,                            \
        CHANOBJINIT                             \
    },                                          \
    NULL,                                       \
    NULL                                        \
}

#if NUMPORTS == 2
static PortObj ports[NUMPORTS] = {              \
    PORTOBJINIT,                                \
    PORTOBJINIT                                 \
};
#elif NUMPORTS == 3
PortObj ports[NUMPORTS] = {                     \
    PORTOBJINIT,                                \
    PORTOBJINIT,                                \
    PORTOBJINIT                                 \
};
#else
#error Number of serials ports undefined!!
#endif

/*
 * Forward declaration of IOM interface functions.
 */
static Int mdBindDev(Ptr *devp, Int devid, Ptr devParams);
static Int mdControlChan(Ptr chanp, Uns cmd, Ptr args);
static Int mdCreateChan(Ptr *chanp, Ptr devp, String name, Int mode,
        Ptr chanParams, IOM_TiomCallback cbFxn, Ptr cbArg);
static Int mdDeleteChan(Ptr chanp);
static Int mdSubmitChan(Ptr chanp, IOM_Packet *packet);



/*
 * Public IOM interface table.
 */
IOM_Fxns C54XX_DMA_MCBSP_FXNS = {
    mdBindDev,
    IOM_UNBINDDEVNOTIMPL,
    mdControlChan,
    mdCreateChan,
    mdDeleteChan,
    mdSubmitChan,
};

/*
 * local functions
 */
static Void startDma(ChanHandle chan, IOM_Packet *packet);
static Void dmaIsr(ChanHandle chan);
static Void abortio(ChanHandle chan);
static Void mcbspStartDelay(Void);

/*
 *  ======== mdBindDev ========
 */
#pragma CODE_SECTION(mdBindDev, ".text:init")
static Int mdBindDev(Ptr *devp, Int devid, Ptr devParams)
{
    C54XX_DMA_MCBSP_DevParams *params = 
        (C54XX_DMA_MCBSP_DevParams *)devParams;
    PortHandle port = (PortHandle)&ports[devid];

    if (ATM_setu(&port->inUse, TRUE)) {
        return (IOM_EBADIO);
    }

    /* this driver requires parameters, there are no valid defaults */
    if (params == NULL) {
        return (IOM_EBADARGS);
    }

    /* Check the version number */
    if (params->versionId != C54XX_DMA_MCBSP_VERSION_1){
        return (IOM_EBADARGS);
    }

    /* open the McBSP */
    port->hMcbsp = MCBSP_open(devid, MCBSP_OPEN_RESET);
    
    if (port->hMcbsp == INV) {
        return (IOM_EBADIO);
    }
    
    MCBSP_config(port->hMcbsp, params->mcbspCfg);

    port->chans[INPUT].dmaId = params->rxDmaId;
    port->chans[OUTPUT].dmaId = params->txDmaId;

    /*store the interrupt masks */
    port->rxIntrMask = params->rxIntrMask;
    port->txIntrMask = params->txIntrMask;

    *devp = port;

    return (IOM_COMPLETED);
}

/*
 *  ======== mdControlChan ========
 */
static Int mdControlChan(Ptr chanp, Uns cmd, Ptr args)
{
    /*
     * If a channel timeouts(in IOM class driver) a calldown is made to
     * mdControlChan w/ cmd = IOM_CHAN_TIMED out. Timeout processing is
     * optionally implemented here. If not performed return status of
     * IOM_ENOTIMPL.
     */

    /*
     *  Channel timed out. Perform needed channel cleanup.
     */
    if (cmd == IOM_CHAN_TIMEDOUT) {
        abortio(chanp);
    }
    else {
        return (IOM_ENOTIMPL); /* return IOM_ENOTIMPL for codes not handled */
    }

    return (IOM_COMPLETED);
}

/*
 *  ======== mdCreateChan ========
 */
static Int mdCreateChan(Ptr *chanp, Ptr devp, String name, Int mode,
                Ptr chanParams, IOM_TiomCallback cbFxn, Ptr cbArg)
{
    PortHandle                  port = (PortHandle)devp;
    C54XX_DMA_MCBSP_ChanParams  *params =
        (C54XX_DMA_MCBSP_ChanParams *)chanParams;
    HWI_Attrs                   attrs;
    ChanHandle                  chan;
    Int                         event;

    chan = (mode == IOM_INPUT) ? &port->chans[INPUT] : &port->chans[OUTPUT];

    /* this driver requires channel parameters, no reasonable default */
    if (params == NULL) {
        return (IOM_EBADARGS);
    }

    /*
     * Check check if channel is already in use.
     * Use ATM_setu() for atomic test-and-set.
     */
    if (ATM_setu((Uns *)&chan->inUse, TRUE)) {
        return (IOM_EBADIO);    /* ERROR! channel is already open! */
    }

    QUE_new(&chan->pendList);

    chan->devp = devp;

    chan->cbFxn = cbFxn;
    chan->cbArg = cbArg;
    
    /* open and configure DMA */
    chan->hDma = DMA_open(chan->dmaId, DMA_OPEN_RESET);

    if (chan->hDma == INV) {
        return (IOM_EBADIO);
    }

    DMA_config(chan->hDma, params->dmaCfg);

    event = DMA_getEventId(chan->hDma);

    /* plug interrupt vector */
    attrs.intrMask =  (mode == IOM_INPUT) ? port->rxIntrMask : port->txIntrMask;
    attrs.arg = (Arg)chan;
    HWI_dispatchPlug(event, (Fxn)dmaIsr, &attrs);

    /* enable DMA interrupt */
    IRQ_enable(event);

    *chanp = chan;

    return (IOM_COMPLETED);             /* success */
}

/*
 *  ======== mdDeleteChan ========
 *  Mark the channel available and disable the appropriate interrupt.
 */
static Int mdDeleteChan(Ptr chanp)
{
    ChanHandle chan = (ChanHandle)chanp;

    /* disable DMA interrupt */
    IRQ_disable(DMA_getEventId(chan->hDma));

    /* close the DMA channel */
    DMA_close(chan->hDma);

    chan->inUse = FALSE;

    return (IOM_COMPLETED);
}

/*
 *  ======== mdSubmitChan ========
 */
static Int mdSubmitChan(Ptr chanp, IOM_Packet *packet)
{
    ChanHandle  chan = (ChanHandle)chanp;
    PortHandle  port = (PortHandle)chan->devp;
    Uns         imask;

    if (packet->cmd == IOM_FLUSH || packet->cmd == IOM_ABORT) {

        abortio(chan);

        packet->status = IOM_COMPLETED; /* flush/abort pkt completed */

        return (IOM_COMPLETED);
    }

    imask = HWI_disable();

    if (chan->dataPacket != NULL) {
        QUE_enqueue(&chan->pendList, packet);
    }
    else {
        chan->dataPacket = packet;
        startDma(chan, packet);
        if (packet->cmd == IOM_READ) {
                /* start the McBSP */
                MCBSP_start(port->hMcbsp, MCBSP_RCV_START, 0x0);
        }
        else {
                /* start the McBSP */
                MCBSP_start(port->hMcbsp, MCBSP_XMIT_START, 0x0);
        }

    }

    HWI_restore(imask);

    return (IOM_PENDING);
}

/*
 *  ======== C54XX_DMA_MCBSP_init ========
 */
#pragma CODE_SECTION(C54XX_DMA_MCBSP_init, ".text:init")
Void C54XX_DMA_MCBSP_init(Void)
{
    /* beware ... this is a global register! */
    DMA_FSET(DMPREC, FREE, 1);
}

/*
 *  ======== startDma ========
 */
static Void startDma(ChanHandle chan, IOM_Packet *packet)
{

    /* Program address in appropriate DMA channel and start transfer. */

    if (packet->cmd == IOM_READ) {
        DMA_RSETH(chan->hDma, DMDST, packet->addr);
        DMA_RSETH(chan->hDma, DMCTR, packet->size - 1);
        DMA_start(chan->hDma);
    }
    else {      
        DMA_RSETH(chan->hDma, DMSRC, packet->addr);
        DMA_RSETH(chan->hDma, DMCTR, packet->size - 1);
        DMA_start(chan->hDma);
    }
}

/*
 *  ======== dmaIsr ========
 */
Void dmaIsr(ChanHandle chan)
{
    PortHandle  port = (PortHandle)chan->devp;
    IOM_Packet *packet = chan->dataPacket;

    if (packet == NULL) {
        /* return if spurious interrupt */
        return;
    }

    packet->status = IOM_COMPLETED;

    chan->dataPacket = QUE_get(&chan->pendList);
    if (chan->dataPacket == (IOM_Packet *)&chan->pendList) {
        chan->dataPacket = NULL;
                if (packet->cmd == IOM_READ) {
                MCBSP_FSETH (port->hMcbsp, SPCR1, RRST, 0);
                        mcbspStartDelay();
        }
        else {
                MCBSP_FSETH (port->hMcbsp, SPCR2, XRST, 0);
                        mcbspStartDelay();
        }

    }
    else {
                if (packet->cmd == IOM_READ) {
                if ( MCBSP_rrdy(port->hMcbsp) ) {
                                /* reset the McBSP */
                    MCBSP_FSETH (port->hMcbsp, SPCR1, RRST, 0);
                                mcbspStartDelay();
                    startDma(chan, chan->dataPacket);
                    /* restart the McBSP */
                    MCBSP_start(port->hMcbsp, MCBSP_RCV_START, 0x0);
            }
            else {
                startDma(chan, chan->dataPacket);
            }
        }
        else {
                if ( MCBSP_xrdy(port->hMcbsp) ) {
                                /* reset the McBSP */
                    MCBSP_FSETH (port->hMcbsp, SPCR2, XRST, 0);
                                mcbspStartDelay();
                    startDma(chan, chan->dataPacket);
                    /* restart the McBSP */
                    MCBSP_start(port->hMcbsp, MCBSP_XMIT_START, 0x0);
            }
                        else {
                                startDma(chan, chan->dataPacket);
                        }  
                }
        }
        (*chan->cbFxn)(chan->cbArg, packet);
}

/*
 *  ======== abortio ========
 *  Aborts uncompleted i/o packet requests.
 */
static Void abortio(ChanHandle chan)
{
    IOM_Packet *tmpPacket;

    DMA_stop(chan->hDma);

    HWI_disable();
    tmpPacket = chan->dataPacket;
    chan->dataPacket = NULL;
    HWI_enable();

    if (tmpPacket) {
        tmpPacket->status = IOM_ABORTED;   /* abort current request */
        (*chan->cbFxn)(chan->cbArg, tmpPacket);

        tmpPacket = QUE_get(&chan->pendList);
        while (tmpPacket != (IOM_Packet *)&chan->pendList) {
            tmpPacket->status = IOM_ABORTED;   /* abort queued requests */
            (*chan->cbFxn)(chan->cbArg, tmpPacket);

            tmpPacket = QUE_get(&chan->pendList);
        }
    }
}

static Void mcbspStartDelay(Void)
{
        volatile int i;
        /* This delay is mainly for allowing
         * two mcbsp external clocks to happen from
         * the time Mcbsp is put in reset to the time
         * Mcbsp is taken out of reset. */
        for(i=0; i<DELAY; i++) {
        }
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -