c6x1x_edma_mcbsp.c
上传用户:dahaojd
上传日期:2008-01-29
资源大小:14357k
文件大小:26k
源码类别:

DSP编程

开发平台:

C/C++

  1. /*
  2.  *  Copyright 2003 by Texas Instruments Incorporated.
  3.  *  All rights reserved. Property of Texas Instruments Incorporated.
  4.  *  Restricted rights to use, duplicate or disclose this code are
  5.  *  granted through contract.
  6.  *  
  7.  */
  8. /* "@(#) DDK 1.11.00.00 11-04-03 (ddk-b13)" */
  9. /* 
  10.  *  ======== c6x1x_edma_mcbsp.c ========
  11.  * 
  12.  *  Generic McBSP driver for the TMS320C6x1x series. Uses the EDMA.
  13.  */
  14. #include <std.h>
  15. #include <atm.h>
  16. #include <iom.h>
  17. #include <que.h>
  18. #include <hwi.h>
  19. #include <csl.h>
  20. #include <csl_mcbsp.h>
  21. #include <csl_irq.h>
  22. #include <csl_edma.h>
  23. #include <csl_cache.h>
  24. #include <c6x1x_edma_mcbsp.h>
  25. /* Maximum number of EDMA jobs linked at a time (Must be 2). */
  26. #define MAXLINKCNT 2
  27. /* Used as index since IOM mode is a bit mask and not an index */
  28. #define INPUT 0
  29. #define OUTPUT 1
  30. /* States for chanCleanUp() */
  31. #define SETFALSE 1
  32. #define FREETCC 2
  33. #define FREETABLE 3
  34. #define FREETABLEEX 4
  35. #define DELCHAN 5
  36. /* Macro to increment and return the indice that ranges over MAXLINKCNT */
  37. #define nextIndex(index) (index) ^ 1
  38. /* Number of ports available */
  39. #define NUMPORTS  _MCBSP_PORT_CNT 
  40. /* Number of channels per port (one input and one output channel) */
  41. #define NUMCHANS 2
  42. /* Structure containing channel specific variables */
  43. typedef struct ChanObj {
  44.     Uns inUse;                /* True if the channel is in use */
  45.     Int mode;                 /* Input or output channel */
  46.     struct PortObj *port;     /* Pointer to the port which owns this chan */
  47.     EDMA_Handle xferPram;     /* Handle to transfer PaRAM */
  48.     EDMA_Handle pramTbl[MAXLINKCNT]; /* Handles to link PaRAMs */
  49.     EDMA_Handle prevPramPtr;  /* Points to the PaRAM last used */
  50.     EDMA_Handle loophEdma;    /* Handle to the Loop job PaRAM */
  51.     IOM_Packet *flushPacket;  /* Holds the flushpacket (if any) */
  52.     IOM_Packet *abortPacket;  /* Holds the abortpacket (if any) */
  53.     IOM_Packet *packetList[MAXLINKCNT]; /* Holds linked  packets */
  54.     QUE_Obj packetQueue;      /* Holds submitted but not linked packets */
  55.     Int submitCount;          /* Number of submit calls pending */
  56.     Int writeIndex;           /* Index of next PaRAM to write to */
  57.     Int readIndex;            /* Index of next PaRAM to read from */
  58.     Int tcc;                  /* Channel transfer complete code */
  59.     IOM_TiomCallback cbFxn;   /* Called when I/O complete */
  60.     Ptr cbArg;                /* Argument to callback function */
  61. } ChanObj, *ChanHandle;
  62. /* Structure containing port specific variables */
  63. typedef struct PortObj {
  64.     Uns inUse;                /* True if the port is in use */
  65.     Int devid;                /* The device id passed to mdBindDev() */
  66.     Bool cacheCalls;          /* Submitted buffers are in cacheable memory */
  67.     Uint32 enableMask;        /* Holds enable Srgr and Fsgr if applicable */
  68.     MCBSP_Handle hMcbsp;      /* CSL Device handle */
  69.     ChanObj chans[NUMCHANS];  /* The channels associated with the port */
  70. } PortObj, *PortHandle;
  71. /* Declare the port and channel structures */
  72. static PortObj ports[NUMPORTS];
  73. /* Define EDMA Event Id's Array */
  74. static Uns eventIds[NUMPORTS][2] = {
  75.     { EDMA_CHA_REVT0, EDMA_CHA_XEVT0 },
  76.     { EDMA_CHA_REVT1, EDMA_CHA_XEVT1 },
  77. #if NUMPORTS == 3
  78.     { EDMA_CHA_REVT2, EDMA_CHA_XEVT2 }
  79. #endif
  80. };
  81. /*
  82.  * Forward declaration of the IOM interface functions. They are only
  83.  * exposed via the IOM function table to avoid namespace pollution.
  84.  */
  85. static Int mdBindDev(Ptr *devp, Int devid, Ptr devParams);
  86. static Int mdCreateChan(Ptr *chanp, Ptr devp, String name, Int mode,
  87.                         Ptr chanParams, IOM_TiomCallback cbFxn, Ptr cbArg);
  88. static Int mdDeleteChan(Ptr chanp);
  89. static Int mdSubmitChan(Ptr chanp, IOM_Packet *packet);
  90. static Int mdUnBindDev(Ptr devp);
  91. /* Public IOM interface table */
  92. IOM_Fxns C6X1X_EDMA_MCBSP_FXNS = {
  93.     &mdBindDev,
  94.     &mdUnBindDev,
  95.     IOM_CONTROLCHANNOTIMPL,
  96.     &mdCreateChan,
  97.     &mdDeleteChan,
  98.     &mdSubmitChan
  99. };
  100. /* Local function prototypes */
  101. static Void isrInput(Int tcc);
  102. static Void isrOutput(Int tcc);
  103. static Void chanCleanUp(ChanHandle chan, Uns state);
  104. static Void isrCommon(ChanHandle chan);
  105. static Void linkPacket(ChanHandle chan, IOM_Packet *packet);
  106. /* Local driver variables. */
  107. static Uint32 loopDstBuf = 0;
  108. static Uint32 loopSrcBuf = 0;
  109. /*
  110.  * ======== chanCleanUp ========
  111.  * Cleans up the channel resources.
  112.  */
  113. static Void chanCleanUp(ChanHandle chan, Uns state)
  114. {
  115.     switch(state) {
  116.     case DELCHAN:
  117.         /* Close the EDMA channel */
  118.         EDMA_close(chan->xferPram);
  119.         /* Disable transfer interrupts from the EDMA */
  120.         EDMA_intDisable(chan->tcc);
  121.     case FREETABLEEX:
  122.         /* Free the EDMA link PaRAM tables */
  123.         EDMA_freeTableEx(MAXLINKCNT, chan->pramTbl);
  124.     case FREETABLE:
  125.         /* Free the loop EDMA PaRAM table */
  126.         EDMA_freeTable(chan->loophEdma);
  127.     case FREETCC:
  128.         /* Free the transfer complete code */
  129.         EDMA_intFree(chan->tcc);
  130.     case SETFALSE:
  131.         /* Mark the channel as closed */
  132.         chan->inUse = FALSE;
  133.         break;
  134.     }
  135. }
  136. /*
  137.  * ======== isrCommon ========
  138.  * Shared ISR code between input and output. Processes a normal EDMA job.
  139.  */
  140. static Void isrCommon(ChanHandle chan)
  141. {
  142.     IOM_Packet *packet;
  143.     Int cnt;
  144.     /* Check to see if this is a completed async abort call */
  145.     if (chan->abortPacket) {
  146.         /* Discard all packets in transmission or queued up */
  147.         if (chan->submitCount > MAXLINKCNT) {
  148.             cnt = MAXLINKCNT;
  149.         }
  150.         else {
  151.             cnt = chan->submitCount;
  152.         }
  153.         while (cnt > 0) {
  154.             packet = chan->packetList[chan->readIndex];
  155.             packet->status = IOM_ABORTED;
  156.             (*chan->cbFxn)(chan->cbArg, packet);
  157.             chan->readIndex = nextIndex(chan->readIndex);
  158.             cnt--;
  159.         }
  160.         while (!QUE_empty(&chan->packetQueue)) {
  161.             packet = QUE_dequeue(&chan->packetQueue);
  162.             packet->status = IOM_ABORTED;
  163.             (*chan->cbFxn)(chan->cbArg, packet);
  164.         }
  165.         /* Reset the driver channel state */
  166.         chan->writeIndex = 0;
  167.         chan->readIndex = 0;
  168.         chan->submitCount = 0;
  169.         chan->abortPacket->status = IOM_COMPLETED;
  170.         (*chan->cbFxn)(chan->cbArg, chan->abortPacket);
  171.         chan->abortPacket = NULL;
  172.         return;
  173.     }
  174.     /* Fetch the completed packet */
  175.     packet = chan->packetList[chan->readIndex];
  176.     chan->readIndex = nextIndex(chan->readIndex);
  177.     /* Mark the packet as completed */
  178.     packet->status = IOM_COMPLETED;
  179.     /* Call the callback function */
  180.     (*chan->cbFxn)(chan->cbArg, packet);
  181.     chan->submitCount--;
  182.     /*
  183.      * See if there are any unlinked packets in the packetQueue
  184.      * and if so link them.
  185.      */
  186.     if (chan->submitCount >= MAXLINKCNT) {
  187.         packet = QUE_dequeue(&chan->packetQueue);
  188.         linkPacket(chan, packet);
  189.     }
  190. }
  191. /*
  192.  * ======== isrInput ========
  193.  * The input isr called from the EDMA dispatcher every time an input
  194.  * EDMA job completes.
  195.  */
  196. static Void isrInput(Int tcc)
  197. {
  198.     ChanHandle chan;
  199.     Int portNbr;
  200.     /* Check which port was responsible for the interrupt */
  201.     for (portNbr = 0; portNbr < NUMPORTS; portNbr++) {
  202.         chan = &ports[portNbr].chans[INPUT];
  203.         if (chan->tcc == tcc && chan->inUse) {
  204.             if (EDMA_RGETH(chan->xferPram, DST) == (Uint32) &loopDstBuf &&
  205.                 chan->submitCount > 1 && !chan->abortPacket) {
  206.                 /*
  207.                  * An emulation halt has occured with more than 1 job
  208.                  * submitted. Link the currently executing job (the Loop job)
  209.                  * to the first of the linked jobs which hadn't been called
  210.                  * back. This way we still have the same number of submitted
  211.                  * jobs after the execution continues as we had before the
  212.                  * emulation halt (breakpoint) occured (this preserves double
  213.                  * buffering if used).
  214.                  */
  215.                 EDMA_disableChannel(chan->xferPram);
  216.                 EDMA_link(chan->xferPram, chan->pramTbl[chan->readIndex]);
  217.                 EDMA_enableChannel(chan->xferPram);
  218.             }
  219.             else {
  220.                 /* Call the common ISR code for a finished normal EDMA job */
  221.                 isrCommon(chan);
  222.             }
  223.         }
  224.     }
  225. }
  226. /*
  227.  * ======== isrOutput ========
  228.  * The output isr called from the EDMA dispatcher every time an output
  229.  * EDMA job completes.
  230.  */
  231. static Void isrOutput(Int tcc)
  232. {
  233.     ChanHandle chan;
  234.     Int portNbr;
  235.     /* Check which port was responsible for the interrupt */
  236.     for (portNbr = 0; portNbr < NUMPORTS; portNbr++) {
  237.         chan = &ports[portNbr].chans[OUTPUT];
  238.         if (chan->tcc == tcc && chan->inUse) {
  239.             if (EDMA_RGETH(chan->xferPram, SRC) == (Uint32) &loopSrcBuf &&
  240.                 chan->submitCount > 1 && !chan->abortPacket) {
  241.                 /*
  242.                  * An emulation halt has occured with more than 1 job
  243.                  * submitted. Link the currently executing job (the Loop job)
  244.                  * to the first of the linked jobs which hadn't been called
  245.                  * back. This way we still have the same number of submitted
  246.                  * jobs after the execution continues as we had before the
  247.                  * emulation halt (breakpoint) occured (this preserves double
  248.                  * buffering if used).
  249.                  */
  250.                 EDMA_link(chan->xferPram, chan->pramTbl[chan->readIndex]);
  251.             }
  252.             else {
  253.                 /* Call the common ISR code for a finished normal EDMA job */
  254.                 isrCommon(chan);
  255.                 /* Check to see if an async flush has completed */
  256.                 if (chan->submitCount == 0 && chan->flushPacket) {
  257.                     chan->flushPacket->status = IOM_COMPLETED;
  258.                     (*chan->cbFxn)(chan->cbArg,chan->flushPacket);
  259.                     chan->flushPacket = NULL;
  260.                 }
  261.             }
  262.         }
  263.     }
  264. }
  265. /*
  266.  * ======== linkPacket ========
  267.  * Links a packet with the EDMA. When called by mdSubmitChan() it is called
  268.  * with all interrupts disabled, but when called by an ISR only the EDMA IRQ
  269.  * is disabled.
  270.  */
  271. static Void linkPacket(ChanHandle chan, IOM_Packet *packet)
  272. {
  273.     EDMA_Handle pramPtr;
  274.     /* Store the packet in the packetList */
  275.     chan->packetList[chan->writeIndex] = packet;
  276.     /* Set up pointer to link PaRAM to write submit job info to */
  277.     pramPtr = chan->pramTbl[chan->writeIndex];
  278.     chan->writeIndex = nextIndex(chan->writeIndex);
  279.     /* Load the buffer pointer into the EDMA */
  280.     if (chan->mode == INPUT) {
  281.         EDMA_RSETH(pramPtr, DST, (Uint32) packet->addr);
  282.     }
  283.     else {
  284.         EDMA_RSETH(pramPtr, SRC, (Uint32) packet->addr);
  285.     }
  286.     /*
  287.      * Load the transfer count (in samples) into the EDMA. Use the ESIZE
  288.      * field of the EDMA job to calculate number of samples.
  289.      */
  290.     EDMA_RSETH(pramPtr, CNT, (Uint32) packet->size >>
  291.                                       (2 - EDMA_FGETH(pramPtr, OPT, ESIZE)));
  292.     /*
  293.      * Link to loop EDMA job upon termination. This way we won't
  294.      * loose the frame sync if the channel is starved.
  295.      */
  296.     EDMA_link(pramPtr, chan->loophEdma);
  297.     /* Disable the EDMA channel to make sure current job doesn't complete */
  298.     EDMA_disableChannel(chan->xferPram);
  299.     /*
  300.      * Link the currently executing job to the new job. This can be
  301.      * either the loop EDMA job or a real data EDMA job.
  302.      */
  303.     EDMA_link(chan->xferPram, pramPtr);
  304.     if (chan->submitCount > 0) {
  305.         /*
  306.          * We need to link the parameter space corresponding to the running
  307.          * job so that if a breakpoint occurs, we know how to recover.
  308.          */
  309.         EDMA_link(chan->prevPramPtr, pramPtr);
  310.     }
  311.     /* Reenable the EDMA channel */
  312.     EDMA_enableChannel(chan->xferPram);
  313.     /* Save the new job for the loop above for next time */
  314.     chan->prevPramPtr = pramPtr;
  315. }
  316. /*
  317.  * ======== mdBindDev ========
  318.  * This function allocates and configures the McBSP port specified by devid.
  319.  */
  320. static Int mdBindDev(Ptr *devp, Int devid, Ptr devParams)
  321. {
  322.     Uns old;
  323.     PortHandle port;
  324.     HWI_Attrs hwiAttrs;
  325.     C6X1X_EDMA_MCBSP_DevParams *params =
  326.         (C6X1X_EDMA_MCBSP_DevParams *) devParams;
  327.     /* This driver must receive a valid devparams */
  328.     if (params == NULL) {
  329.         return (IOM_EBADARGS);
  330.     }
  331.     
  332.     /* Check if the driver is supporting the version used by
  333.      * the application */
  334.     if(params->versionId != C6X1X_EDMA_MCBSP_VERSION_1){ 
  335.         /* Unsupported version */
  336.         return(IOM_EBADARGS);
  337.     }
  338.     /* Get the device parameters of the specified port */
  339.     port = &ports[devid];
  340.     /* Mark the port as in use */
  341.     old = ATM_setu(&(port->inUse), TRUE);
  342.     /* Check if the port was already bound */
  343.     if (old) {
  344.         return (IOM_EALLOC);
  345.     }
  346.     /* Map the supplied IRQ to the EDMA event */
  347.     IRQ_map(IRQ_EVT_EDMAINT, params->irqId);
  348.     /* set the interrupt mask */
  349.     hwiAttrs.intrMask = params->intrMask;
  350.     hwiAttrs.ccMask = IRQ_CCMASK_NONE; /* the default value */
  351.     hwiAttrs.arg = NULL;
  352.     /* Plug the EDMA dispatcher into the HWI dispatcher */
  353.     HWI_dispatchPlug(params->irqId, (Fxn)EDMA_intDispatcher, -1, &hwiAttrs);
  354.     /* Initialise the enableMask */
  355.     port->enableMask = 0;
  356.     /* Set the McBSP sample rate generator to be enabled */
  357.     if (params->enableSrgr) {
  358.         port->enableMask |= MCBSP_SRGR_START;
  359.     }
  360.     /* Set the McBSP frame sync generator to be enabled */
  361.     if (params->enableFsg) {
  362.         port->enableMask |= MCBSP_SRGR_FRAMESYNC;
  363.     }
  364.     /* True if buffers are in external memory */
  365.     port->cacheCalls = params->cacheCalls;
  366.     /* Store the devid */
  367.     port->devid = devid;
  368.     /* Open and reset the McBSP */
  369.     port->hMcbsp = MCBSP_open(devid, MCBSP_OPEN_RESET);
  370.     if (port->hMcbsp == INV) {
  371.         return (IOM_EALLOC);
  372.     }
  373.     /* Configure the McBSP with the supplied configuration */
  374.     MCBSP_config(port->hMcbsp, params->mcbspCfgPtr);
  375.     /* Return the device handle and a status code for success */
  376.     *devp = port;
  377.     return (IOM_COMPLETED);
  378. }
  379. /*
  380.  * ======== mdCreateChan ========
  381.  * This function creates and configures a device channel.
  382.  */
  383. static Int mdCreateChan(Ptr *chanp, Ptr devp, String name, Int mode,
  384.                         Ptr chanParams, IOM_TiomCallback cbFxn, Ptr cbArg)
  385. {
  386.     PortHandle port = (PortHandle) devp;
  387.     C6X1X_EDMA_MCBSP_ChanParams *params =
  388.         (C6X1X_EDMA_MCBSP_ChanParams *) chanParams;
  389.     ChanHandle chan;
  390.     Uns mcbspAddr;
  391.     Uns old;
  392.     Uns esize;
  393.     Int i;
  394.     /*
  395.      * Configuration structure for the loop EDMA job. If the McBSP
  396.      * is left to free running, this loop job is running when there is
  397.      * no data to transfer. This is useful if the McBSP is externally
  398.      * clocked.  If the driver is starved or if an emulation halt
  399.      * (breakpoint) occurs, the frame sync will still be correct when
  400.      * the driver continues transmitting data.
  401.      */
  402.     EDMA_Config loopEdmaCfg = {
  403.         EDMA_FMKS(OPT, PRI, HIGH)           |
  404.         EDMA_FMKS(OPT, ESIZE, DEFAULT)      |
  405.         EDMA_FMKS(OPT, 2DS, NO)             |
  406.         EDMA_FMKS(OPT, SUM, NONE)           |
  407.         EDMA_FMKS(OPT, 2DD, NO)             |
  408.         EDMA_FMKS(OPT, DUM, NONE)           |
  409.         EDMA_FMKS(OPT, TCINT, NO)           |
  410.         EDMA_FMKS(OPT, TCC, DEFAULT)        |
  411.         EDMA_FMKS(OPT, LINK, YES)           |
  412.         EDMA_FMKS(OPT, FS, NO),
  413.         EDMA_FMK (SRC, SRC, NULL),
  414.         EDMA_FMK (CNT, FRMCNT, NULL)        |
  415.         EDMA_FMK (CNT, ELECNT, NULL),
  416.         EDMA_FMKS(IDX, FRMIDX, DEFAULT)     |
  417.         EDMA_FMKS(IDX, ELEIDX, DEFAULT),
  418.         EDMA_FMK (DST, DST, NULL),
  419.         EDMA_FMK (RLD, ELERLD, NULL)        |
  420.         EDMA_FMK (RLD, LINK, NULL)
  421.     };
  422.     /* This driver needs a valid channel parameter structure passed */
  423.     if (params == NULL) {
  424.         return (IOM_EBADARGS);
  425.     }
  426.     /* Use own indexes since IOM mode is a bit mask and not an index */
  427.     if (mode == IOM_INPUT) {
  428.         chan = &port->chans[INPUT];
  429.         chan->mode = INPUT;
  430.     }
  431.     else {
  432.         chan = &port->chans[OUTPUT];
  433.         chan->mode = OUTPUT;
  434.     }
  435.     /* Mark the channel as used */
  436.     old = ATM_setu(&(chan->inUse), TRUE);
  437.     /* Make sure the channel wasn't already created */
  438.     if (old) {
  439.         return (IOM_EALLOC);
  440.     }
  441.     /* Initialise the channel structure */
  442.     chan->cbFxn = cbFxn;
  443.     chan->cbArg = cbArg;
  444.     chan->port = port;
  445.     chan->writeIndex = 0;
  446.     chan->readIndex = 0;
  447.     chan->submitCount = 0;
  448.     chan->flushPacket = NULL;
  449.     chan->abortPacket = NULL;
  450.     /* Initialize the packet queue */
  451.     QUE_new(&chan->packetQueue);
  452.     /*
  453.      * Set the number of elements (corresponding to number of McBSP TDM
  454.      * channels) used in the Loop job to preserve the frame sync.
  455.      */
  456.     loopEdmaCfg.cnt = EDMA_FMK(CNT, ELECNT, params->tdmChans);
  457.     /* Use the same sample size in the Loop job as in normal jobs */
  458.     esize = EDMA_FGETA(params->edmaCfgPtr, OPT, ESIZE);
  459.     EDMA_FSETA(&loopEdmaCfg, OPT, ESIZE, esize);
  460.     /* Allocate a TCC for the EDMA */
  461.     chan->tcc = EDMA_intAlloc(-1);
  462.     /* If tcc > 15 (possible on c64x) we abort. */
  463.     if (chan->tcc == -1 || chan->tcc > 15) {
  464.         chanCleanUp(chan, SETFALSE);
  465.         return (IOM_EALLOC);
  466.     }
  467.     /* Allocate an EDMA PaRAM for the Loop EDMA job. */
  468.     chan->loophEdma = EDMA_allocTable(-1);
  469.     if (chan->loophEdma == EDMA_HINV) {
  470.         chanCleanUp(chan, FREETCC);
  471.         return (IOM_EALLOC);
  472.     }
  473.     /*
  474.      * Allocate EDMA PaRAM link area based on max number of
  475.      * submits possible.
  476.      */
  477.     if (EDMA_allocTableEx(MAXLINKCNT, chan->pramTbl) != MAXLINKCNT) {
  478.         chanCleanUp(chan, FREETABLE);
  479.         return (IOM_EALLOC);
  480.     }
  481.     /* 
  482.      * Process the big endian problem for McBSP 
  483.      * See EDMA App Note (spra636) for details setting in big endian
  484.      */
  485.     if (chan->mode == INPUT) {
  486.         mcbspAddr = MCBSP_getRcvAddr(port->hMcbsp);
  487.     }
  488.     else {
  489.         mcbspAddr = MCBSP_getXmtAddr(port->hMcbsp);
  490.     }
  491. #ifdef _BIG_ENDIAN
  492.     if (esize == EDMA_OPT_ESIZE_8BIT) {
  493.         mcbspAddr += 3;
  494.     }
  495.     else if (esize == EDMA_OPT_ESIZE_16BIT) {
  496.         mcbspAddr += 2;
  497.     }
  498. #endif
  499.     if (chan->mode == INPUT) {
  500.         /* Put input specific parameters in the Loop EDMA config */
  501.         loopEdmaCfg.src = mcbspAddr;
  502.         loopEdmaCfg.dst = (Uint32) &loopDstBuf;
  503.         params->edmaCfgPtr->src = mcbspAddr;
  504.         /* Register our isrInput with the EDMA dispatcher */
  505.         EDMA_intHook(chan->tcc, &isrInput);
  506.     }
  507.     else {
  508.         /* Put output specific parameters in the Loop EDMA config */
  509.         loopEdmaCfg.src = (Uint32) &loopSrcBuf;
  510.         loopEdmaCfg.dst = mcbspAddr;
  511.         params->edmaCfgPtr->dst = mcbspAddr;
  512.         /* Register our isrOutput with the EDMA dispatcher */
  513.         EDMA_intHook(chan->tcc, &isrOutput);
  514.     }
  515.     /* Open the EDMA channel */
  516.     chan->xferPram = 
  517.             EDMA_open(eventIds[port->devid][chan->mode], EDMA_OPEN_RESET);
  518.     if (chan->xferPram == EDMA_HINV) {
  519.         chanCleanUp(chan, FREETABLEEX);
  520.         return (IOM_EALLOC);
  521.     }
  522.     /* Program the data EDMA job with the TCC */
  523.     EDMA_FSETA(params->edmaCfgPtr, OPT, TCC, chan->tcc);
  524.     /* Program the link PaRAMs with the config struct */
  525.     for (i=0; i < MAXLINKCNT; i++) {
  526.         EDMA_config(chan->pramTbl[i], params->edmaCfgPtr);
  527.     }
  528.     /* Program the Loop EDMA job with its config struct */
  529.     EDMA_config(chan->loophEdma, &loopEdmaCfg);
  530.     /*
  531.      * Link the Loop EDMA job to itself to make it run
  532.      * continuously when there is no data to transmit.
  533.      */
  534.     EDMA_link(chan->loophEdma, chan->loophEdma);
  535.     /* Configure the EDMA channel to start with the Loop EDMA job */
  536.     EDMA_config(chan->xferPram, &loopEdmaCfg);
  537.     /* Transfer complete is edge triggered, so clear before enabling */
  538.     EDMA_intClear(chan->tcc);
  539.     EDMA_intEnable(chan->tcc);
  540.     /* Enable the EDMA interrupt */
  541.     IRQ_enable(IRQ_EVT_EDMAINT);
  542.     /* Start the McBSP */
  543.     if (chan->mode == INPUT) {
  544.         MCBSP_start(port->hMcbsp, port->enableMask | MCBSP_RCV_START,
  545.                     MCBSP_SRGR_DEFAULT_DELAY);
  546.     }
  547.     else {
  548.         MCBSP_start(port->hMcbsp, port->enableMask | MCBSP_XMIT_START,
  549.                     MCBSP_SRGR_DEFAULT_DELAY);
  550.     }
  551.     *chanp = (Ptr) chan;
  552.     return (IOM_COMPLETED);
  553. }
  554. /*
  555.  * ======== mdDeleteChan ========
  556.  * This function frees a channel and all it's associated resources.
  557.  */
  558. static Int mdDeleteChan(Ptr chanp)
  559. {
  560.     ChanHandle chan = (ChanHandle) chanp;
  561.     PortHandle port = chan->port;
  562.     /* Clean up the channel resources */
  563.     chanCleanUp(chan, DELCHAN);
  564.     /*
  565.      * Reset the McBSP transmitter or receiver. If the channel is
  566.      * recreated, mdCreateChan() will reenable the transmitter/receiver
  567.      * and by pulling it out of reset it will also restart the EDMA channel.
  568.      */
  569.     if (chan->mode == INPUT) {
  570.         MCBSP_FSETSH(port->hMcbsp, SPCR, RRST, YES);
  571.     }
  572.     else {
  573.         MCBSP_FSETSH(port->hMcbsp, SPCR, XRST, YES);
  574.     }
  575.     return (IOM_COMPLETED);
  576. }
  577. /*
  578.  * ======== mdSubmitChan ========
  579.  * This function transmits a buffer to or from the McASP using the EDMA.
  580.  */
  581. static Int mdSubmitChan(Ptr chanp, IOM_Packet *packet)
  582. {
  583.     ChanHandle chan = (ChanHandle) chanp;
  584.     PortHandle port = chan->port;
  585.     Uns imask;
  586.     /* No packets can be submitted while abort or flush is active */
  587.     if (chan->flushPacket || chan->abortPacket) {
  588.         return (IOM_EBADIO);
  589.     }
  590.     /*
  591.      * Check to see if an abort command has been issued. Note that
  592.      * flushing the input channel is handled the same as abort.
  593.      */
  594.     if ((packet->cmd == IOM_FLUSH && chan->mode == INPUT) ||
  595.         packet->cmd == IOM_ABORT) {
  596.         /* Disable interrupts to protect submitCount */
  597.         imask = HWI_disable();
  598.         /* Store the abort packet for the ISR to check */
  599.         if (chan->submitCount > 0) {
  600.             chan->abortPacket = packet;
  601.             /*
  602.              * Disable the EDMA channel while linking the currently
  603.              * executing job while linking it with the Loop job to make
  604.              * sure the currently executing job doesn't complete before
  605.              * the link is complete.
  606.              */
  607.             EDMA_disableChannel(chan->xferPram);
  608.             EDMA_link(chan->xferPram, chan->loophEdma);
  609.             EDMA_enableChannel(chan->xferPram);
  610.         }
  611.         /* Reenable interrupts */
  612.         HWI_restore(imask);
  613.         if (chan->abortPacket) {
  614.             return(IOM_PENDING);
  615.         }
  616.         /* If there were no buffers in the channel, return synchronously */
  617.         packet->status = IOM_COMPLETED;
  618.         return (IOM_COMPLETED);
  619.     }
  620.     /* Check to see if the submitted packet is an output flush packet */
  621.     if (packet->cmd == IOM_FLUSH && chan->mode == OUTPUT) {
  622.         /* Disable interrupts to protect submitCount */
  623.         imask = HWI_disable();
  624.         /* Store the flush packet for the ISR to check */
  625.         if (chan->submitCount > 0) {
  626.             chan->flushPacket = packet;
  627.         }
  628.         /* Reenable interrupts */
  629.         HWI_restore(imask);
  630.         if (chan->flushPacket) {
  631.             return(IOM_PENDING);
  632.         }
  633.         /* If there were no buffers in the channel, return synchronously */
  634.         packet->status = IOM_COMPLETED;
  635.         return (IOM_COMPLETED);
  636.     }
  637.     if (packet->cmd != IOM_READ && packet->cmd != IOM_WRITE) {
  638.         /* Unsupported command passed */
  639.         return (IOM_ENOTIMPL);
  640.     }
  641.     /* maintain cache coherency */
  642.     if (chan->mode == INPUT) {
  643.         /* CACHE uses words, and packet->size is in nmaus (bytes on c6x) */
  644.         if (port->cacheCalls) {
  645.             CACHE_clean(CACHE_L2, packet->addr, packet->size >> 2);
  646.         }
  647.     }
  648.     else {
  649.         /* CACHE uses words, and packet->size is in nmaus (bytes on c6x) */
  650.         if (port->cacheCalls) {
  651.             CACHE_flush(CACHE_L2, packet->addr, packet->size >> 2);
  652.         }
  653.     }
  654.     /* Disable interrupts to protect submitCount */
  655.     imask = HWI_disable();
  656.     /*
  657.      * If there is no space available for the new packet, put it on a
  658.      * queue to be linked in when space is available. Otherwise link it in.
  659.      */
  660.     if (chan->submitCount >= MAXLINKCNT) {
  661.         QUE_enqueue(&chan->packetQueue, packet);
  662.     }
  663.     else {
  664.         linkPacket(chan, packet);
  665.     }
  666.     chan->submitCount++;
  667.     HWI_restore(imask);
  668.     return (IOM_PENDING);
  669. }
  670. /*
  671.  * ======== mdUnBindDev ========
  672.  * This function frees a port and all it's associated resources.
  673.  */
  674. static Int mdUnBindDev(Ptr devp)
  675. {
  676.     PortHandle port = (PortHandle) devp;
  677.     port->inUse = FALSE;
  678.     /* Close the McBSP */
  679.     MCBSP_close(port->hMcbsp);
  680.     return (IOM_COMPLETED);
  681. }
  682. /*
  683.  * ======== C6X1X_EDMA_MCBSP_init ========
  684.  * This function initializes the driver's data structures.
  685.  */
  686. #pragma CODE_SECTION(C6X1X_EDMA_MCBSP_init, ".text:init");
  687. Void C6X1X_EDMA_MCBSP_init()
  688. {
  689.     PortHandle port;
  690.     ChanHandle chan;
  691.     Int i, j;
  692.     /* Make sure initialization only happens once for this driver */
  693.     static Bool curInit = FALSE;
  694.     if (curInit) {
  695.         return;
  696.     }
  697.     curInit = TRUE;
  698.     for (i=0; i<NUMPORTS; i++) {
  699.         port = &ports[i];
  700.         port->inUse = FALSE;
  701.         for (j=0; j<NUMCHANS; j++) {
  702.             chan = &port->chans[j];
  703.             chan->inUse = FALSE;
  704.         }
  705.     }
  706. }