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

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.10.00.23 07-02-03 (ddk-b12)" */
  9. /* 
  10.  *  ======== c6x1x_edma_mcasp.c ========
  11.  * 
  12.  *  Generic McASP driver for the TMS320C6x1x series. Uses the EDMA.
  13.  */
  14. #include <std.h>
  15. #include <atm.h>
  16. #include <hwi.h>
  17. #include <que.h>
  18. #include <iom.h>
  19. #include <csl.h>
  20. #include <csl_mcasp.h>
  21. #include <csl_irq.h>
  22. #include <csl_edma.h>
  23. #include <csl_cache.h>
  24. #include <csl_chip.h>
  25. #include <c6x1x_edma_mcasp.h>
  26. /*
  27.  *  Macro to start serializer & state machine
  28.  *  if turned on, driver will start both transmit and receive serializer 
  29.  *  and state machine synchronously  
  30.  */
  31. #define STARTSERIALIZERSYNC     0
  32. /*
  33.  *  Macro to enable edma loop job interrupt
  34.  *  if turned on, each time edma loop job gets running, an ineterrupt will
  35.  *  be generated. This is only used for debug purpose.
  36.  */
  37. #define ENABLELOOPINTR          0 
  38. #if ENABLELOOPINTR
  39. #include <log.h>
  40. extern far LOG_Obj trace;
  41. #endif
  42. #define IRQEVTINPUT             5
  43. #define IRQEVTOUTPUT            6
  44. #define IRQEDMA                 8
  45. /* Maximum number of EDMA jobs linked at a time (Must be 2). */
  46. #define MAXLINKCNT 2
  47. /* Used as index since IOM mode is a bit mask and not an index */
  48. #define INPUT   0
  49. #define OUTPUT  1
  50. /* States for chanCleanUp() */
  51. #define SETFALSE 1
  52. #define FREETCC 2
  53. #define FREETABLE 3
  54. #define FREETABLEEX 4
  55. #define DELCHAN 5
  56. /* Macro to increment and return the indice that ranges over MAXLINKCNT */
  57. #define nextIndex(index) ((index) ^ 1)
  58. /* Number of ports available */
  59. #define NUMPORTS _MCASP_PORT_CNT 
  60. /* Number of channels per port (one input and one output channel) */
  61. #define NUMCHANS 2
  62. /* Structure containing channel specific variables */
  63. typedef struct ChanObj {
  64.     Uns inUse;                /* True if the channel is in use */
  65.     Int mode;                 /* Input or output channel */
  66.     struct PortObj *port;     /* Pointer to the port which owns this chan */
  67.     EDMA_Handle xferPram;     /* Handle to transfer PaRAM */
  68.     EDMA_Handle pramTbl[MAXLINKCNT]; /* Handles to link PaRAMs */
  69.     EDMA_Handle prevPramPtr;  /* Points to the PaRAM last used */
  70.     EDMA_Handle loophEdma;    /* Handle to the Loop job PaRAM */
  71.     IOM_Packet *flushPacket;  /* Holds the flushpacket (if any) */
  72.     IOM_Packet *abortPacket;  /* Holds the abortpacket (if any) */
  73.     IOM_Packet *packetList[MAXLINKCNT]; /* Holds linked  packets */
  74.     QUE_Obj packetQueue;      /* Holds submitted but not linked packets */
  75.     Int submitCount;          /* Number of submit calls pending */
  76.     Int writeIndex;           /* Index of next PaRAM to write to */
  77.     Int readIndex;            /* Index of next PaRAM to read from */
  78.     Int tcc;                  /* Channel transfer complete code */
  79.     IOM_TiomCallback cbFxn;   /* Called when I/O complete */
  80.     Ptr cbArg;                /* Argument to callback function */
  81. } ChanObj, *ChanHandle;
  82. /* Structure containing port specific variables */
  83. typedef struct PortObj {
  84.     Uns inUse;                /* True if the port is in use */
  85.     Int devId;                /* The device id passed to mdBindDev() */
  86.     Bool cacheCalls;          /* Submitted buffers are in cacheable memory */
  87.     Uint32 enableHclkg;       /* Holds enable Hclk variable */
  88.     Uint32 enableClkg;        /* Holds enable Clk variable */
  89.     Uint32 enableFsyncg;      /* Holds enable Fsync variable */
  90.     MCASP_Handle hMcasp;      /* CSL Device handle */
  91.     ChanObj chans[NUMCHANS];  /* The channels associated with the port */
  92.     Uns chanCreated;          /* One channel in this port has been Created */
  93.     C6X1X_EDMA_MCASP_TevtCallback evtCallback; /* event callback */
  94.     Uns evtMask;              /* registered events */
  95. } PortObj, *PortHandle;
  96. /* Declare the port and channel structures */
  97. static PortObj ports[NUMPORTS];
  98. /* Define EDMA Event Id's Array */
  99. static Uns eventIds[NUMPORTS][2] = {
  100.     { EDMA_CHA_AREVT0, EDMA_CHA_AXEVT0 },
  101. #if NUMPORTS >= 2
  102.     { EDMA_CHA_AREVT1, EDMA_CHA_AXEVT1 },
  103. #endif
  104. #if NUMPORTS == 3
  105.     { EDMA_CHA_AREVT2, EDMA_CHA_AXEVT2 }
  106. #endif
  107. };
  108. /*
  109.  * Forward declaration of the IOM interface functions. They are only
  110.  * exposed via the IOM function table to avoid namespace pollution.
  111.  */
  112. static Int mdBindDev(Ptr *devp, Int devid, Ptr devParams);
  113. static Int mdCreateChan(Ptr *chanp, Ptr devp, String name, Int mode,
  114.                         Ptr chanParams, IOM_TiomCallback cbFxn, Ptr cbArg);
  115. static Int mdDeleteChan(Ptr chanp);
  116. static Int mdSubmitChan(Ptr chanp, IOM_Packet *packet);
  117. static Int mdUnBindDev(Ptr devp);
  118. #if ENABLELOOPINTR
  119. static Void isrLoop(Int tcc);
  120. #endif
  121. /* Public IOM interface table */
  122. IOM_Fxns C6X1X_EDMA_MCASP_FXNS = {
  123.     &mdBindDev,
  124.     &mdUnBindDev,
  125.     IOM_CONTROLCHANNOTIMPL,
  126.     &mdCreateChan,
  127.     &mdDeleteChan,
  128.     &mdSubmitChan
  129. };
  130. /* Local function prototypes */
  131. static Void chanCleanUp(ChanHandle chan, Uns state);
  132. static Void isrCommon(ChanHandle chan);
  133. static Void isrInput(Int tcc);
  134. static Void isrOutput(Int tcc);
  135. static Void isrEvent(Int mode);
  136. static Void linkPacket(ChanHandle chan, IOM_Packet *packet);
  137. /* Local driver variables. */
  138. static Uint32 loopDstBuf;
  139. static Uint32 loopSrcBuf;
  140. #if ENABLELOOPINTR
  141. static Void isrLoop(Int tcc)
  142. {
  143.     LOG_printf(&trace, "LOOP=%d", tcc);
  144. }
  145. #endif
  146. /*
  147.  * ======== chanCleanUp ========
  148.  * Cleans up the channel resources.
  149.  */
  150. static Void chanCleanUp(ChanHandle chan, Uns state)
  151. {
  152.     switch(state) {
  153.     case DELCHAN:
  154.         /* Close the EDMA channel */
  155.         EDMA_close(chan->xferPram);
  156.         /* Disable transfer interrupts from the EDMA */
  157.         EDMA_intDisable(chan->tcc);
  158.         /* will fall through the next case */
  159.     case FREETABLEEX:
  160.         /* Free the EDMA link PaRAM tables */
  161.         EDMA_freeTableEx(MAXLINKCNT, chan->pramTbl);
  162.         /* will fall through the next case */
  163.     case FREETABLE:
  164.         /* Free the loop EDMA PaRAM table */
  165.         EDMA_freeTable(chan->loophEdma);
  166.         /* will fall through the next case */
  167.     case FREETCC:
  168.         /* Free the transfer complete code */
  169.         EDMA_intFree(chan->tcc);
  170.         /* will fall through the next case */
  171.     case SETFALSE:
  172.         /* Mark the channel as closed */
  173.         chan->inUse = FALSE;
  174.         break;
  175.     }
  176. }
  177. /*
  178.  * ======== isrCommon ========
  179.  * Shared ISR code between input and output. Processes a normal EDMA job.
  180.  */
  181. static Void isrCommon(ChanHandle chan)
  182. {
  183.     IOM_Packet *packet;
  184.     Int cnt;
  185.     /* Check to see if this is a completed async abort call */
  186.     if (chan->abortPacket) {
  187.         /* Discard all packets in transmission or queued up */
  188.         if (chan->submitCount > MAXLINKCNT) {
  189.             cnt = MAXLINKCNT;
  190.         }
  191.         else {
  192.             cnt = chan->submitCount;
  193.         }
  194.         while (cnt > 0) {
  195.             packet = chan->packetList[chan->readIndex];
  196.             packet->status = IOM_ABORTED;
  197.             (*chan->cbFxn)(chan->cbArg, packet);
  198.             chan->readIndex = nextIndex(chan->readIndex);
  199.             cnt--;
  200.         }
  201.         while (!QUE_empty(&chan->packetQueue)) {
  202.             packet = QUE_dequeue(&chan->packetQueue);
  203.             packet->status = IOM_ABORTED;
  204.             (*chan->cbFxn)(chan->cbArg, packet);
  205.         }
  206.         /* Reset the driver channel state */
  207.         chan->writeIndex = 0;
  208.         chan->readIndex = 0;
  209.         chan->submitCount = 0;
  210.         chan->abortPacket->status = IOM_COMPLETED;
  211.         (*chan->cbFxn)(chan->cbArg, chan->abortPacket);
  212.         chan->abortPacket = NULL;
  213.         return;
  214.     }
  215.     /* Fetch the completed packet */
  216.     packet = chan->packetList[chan->readIndex];
  217.     chan->readIndex = nextIndex(chan->readIndex);
  218.     /* Mark the packet as completed */
  219.     packet->status = IOM_COMPLETED;
  220.     /* Call the callback function */
  221.     (*chan->cbFxn)(chan->cbArg, packet);
  222.     chan->submitCount--;
  223.     /*
  224.      * See if there are any unlinked packets in the packetQueue
  225.      * and if so link them.
  226.      */
  227.     if (chan->submitCount >= MAXLINKCNT) {
  228.         packet = QUE_dequeue(&chan->packetQueue);
  229.         linkPacket(chan, packet);
  230.     }
  231. }
  232. /*
  233.  * ======== isrInput ========
  234.  * The input isr called from the EDMA dispatcher every time an input
  235.  * EDMA job completes.
  236.  */
  237. static Void isrInput(Int tcc)
  238. {
  239.     ChanHandle chan;
  240.     Int portNbr;
  241.     /* Check which port was responsible for the interrupt */
  242.     for (portNbr = 0; portNbr < NUMPORTS; portNbr++) {
  243.         chan = &ports[portNbr].chans[INPUT];
  244.         if (chan->tcc == tcc && chan->inUse) {
  245.             if (EDMA_RGETH(chan->xferPram, DST) == (Uint32) &loopDstBuf &&
  246.                 chan->submitCount > 1 && !chan->abortPacket) {
  247.                 /*
  248.                  * An emulation halt has occured with more than 1 job
  249.                  * submitted. Link the currently executing job (the Loop job)
  250.                  * to the first of the linked jobs which hadn't been called
  251.                  * back. This way we still have the same number of submitted
  252.                  * jobs after the execution continues as we had before the
  253.                  * emulation halt (breakpoint) occured (this preserves double
  254.                  * buffering if used).
  255.                  */
  256.                 EDMA_disableChannel(chan->xferPram);
  257.                 EDMA_link(chan->xferPram, chan->pramTbl[chan->readIndex]);
  258.                 EDMA_enableChannel(chan->xferPram);
  259.             }
  260.             else {
  261.                 /* Call the common ISR code for a finished normal EDMA job */
  262.                 isrCommon(chan);
  263.             }
  264.         }
  265.     }
  266. }
  267. /*
  268.  * ======== isrOutput ========
  269.  * The output isr called from the EDMA dispatcher every time an output
  270.  * EDMA job completes.
  271.  */
  272. static Void isrOutput(Int tcc)
  273. {
  274.     ChanHandle chan;
  275.     Int portNbr;
  276.     /* Check which port was responsible for the interrupt */
  277.     for (portNbr = 0; portNbr < NUMPORTS; portNbr++) {
  278.         chan = &ports[portNbr].chans[OUTPUT];
  279.         if (chan->tcc == tcc && chan->inUse) {
  280.             if (EDMA_RGETH(chan->xferPram, SRC) == (Uint32)&loopSrcBuf &&
  281.                 chan->submitCount > 1 && !chan->abortPacket) {
  282.                 /*
  283.                  * An emulation halt has occured with more than 1 job
  284.                  * submitted. Link the currently executing job (the Loop job)
  285.                  * to the first of the linked jobs which hadn't been called
  286.                  * back. This way we still have the same number of submitted
  287.                  * jobs after the execution continues as we had before the
  288.                  * emulation halt (breakpoint) occured (this preserves double
  289.                  * buffering if used).
  290.                  */
  291.                 EDMA_disableChannel(chan->xferPram);
  292.                 EDMA_link(chan->xferPram, chan->pramTbl[chan->readIndex]);
  293.                 EDMA_enableChannel(chan->xferPram);
  294.             }
  295.             else {
  296.                 /* Call the common ISR code for a finished normal EDMA job */
  297.                 isrCommon(chan);
  298.                 /* Check to see if an async flush has completed */
  299.                 if (chan->submitCount == 0 && chan->flushPacket) {
  300.                     chan->flushPacket->status = IOM_COMPLETED;
  301.                     (*chan->cbFxn)(chan->cbArg,chan->flushPacket);
  302.                     chan->flushPacket = NULL;
  303.                 }
  304.             }
  305.         }
  306.     }
  307. }
  308. /*
  309.  * ======== isrEvent ========
  310.  * The event isr called when an McASP input/output event happens
  311.  * This is used for exception event handling asserted by McASP. Normal data
  312.  * hanlding is done by EDMA. 
  313.  */
  314. static Void isrEvent(Int mode)
  315. {
  316.     MCASP_Handle hMcasp;
  317.     Uns portNbr;
  318.     Uns events;
  319.     Uns eventReturn;
  320.     
  321.     /* Check which port was responsible for the interrupt */
  322.     for (portNbr = 0; portNbr < NUMPORTS; portNbr++) {
  323.         if (ports[portNbr].inUse) {
  324.             hMcasp = ports[portNbr].hMcasp;
  325.             events = 0;
  326.             if (mode == INPUT) {          
  327.                 if (MCASP_FGETH(hMcasp, RSTAT, ROVRN)) {
  328.                     MCASP_FSETSH(hMcasp, RSTAT, ROVRN, YES);
  329.                     events |= C6X1X_EDMA_MCASP_EVT_ROVRN;
  330.                 } 
  331.                 if (MCASP_FGETH(hMcasp, RSTAT, RCKFAIL)) {
  332.                     MCASP_FSETSH(hMcasp, RSTAT, RCKFAIL, YES);
  333.                     events |= C6X1X_EDMA_MCASP_EVT_RCKFAIL;
  334.                 }
  335.                 if (MCASP_FGETH(hMcasp, RSTAT, RSYNCERR)) {
  336.                     MCASP_FSETSH(hMcasp, RSTAT, RSYNCERR, YES);
  337.                     events |= C6X1X_EDMA_MCASP_EVT_RSYNCERR;
  338.                 }   
  339.                 if (MCASP_FGETH(hMcasp, RSTAT, RDMAERR)) {
  340.                     MCASP_FSETH(hMcasp, RSTAT, RDMAERR, 1);
  341.                     events |= C6X1X_EDMA_MCASP_EVT_RDMAERR;
  342.                 }   
  343.                 /* Clear not registered events here */
  344.                 MCASP_RSETH(hMcasp, RSTAT, 0xFFFFFFFF);
  345.             } 
  346.             else {
  347.                 if (MCASP_FGETH(hMcasp, XSTAT, XUNDRN)) {
  348.                     MCASP_FSETSH(hMcasp, XSTAT, XUNDRN, YES);
  349.                     events |= C6X1X_EDMA_MCASP_EVT_XUNDRN;
  350.                 } 
  351.                 if (MCASP_FGETH(hMcasp, XSTAT, XCKFAIL)) {
  352.                     MCASP_FSETSH(hMcasp, XSTAT, XCKFAIL, YES);
  353.                     events |= C6X1X_EDMA_MCASP_EVT_XCKFAIL;
  354.                 }
  355.                 if (MCASP_FGETH(hMcasp, XSTAT, XSYNCERR)) {
  356.                     MCASP_FSETSH(hMcasp, XSTAT, XSYNCERR, YES);
  357.                     events |= C6X1X_EDMA_MCASP_EVT_XSYNCERR;
  358.                 }   
  359.                 if (MCASP_FGETH(hMcasp, XSTAT, XDMAERR)) {
  360.                     MCASP_FSETH(hMcasp, XSTAT, XDMAERR, 1);
  361.                     events |= C6X1X_EDMA_MCASP_EVT_XDMAERR;
  362.                 }   
  363.                 /* Clear not registered events here */
  364.                 MCASP_RSETH(hMcasp, XSTAT, 0xFFFFFFFF);
  365.             }
  366.             eventReturn = ports[portNbr].evtMask & events;
  367.  
  368.             if (eventReturn) {
  369.                 (*ports[portNbr].evtCallback)(eventReturn, portNbr);
  370.             } 
  371.         }   
  372.     }    
  373. }
  374. /*
  375.  * ======== linkPacket ========
  376.  * Links a packet with the EDMA. When called by mdSubmitChan() it is called
  377.  * with all interrupts disabled, but when called by an ISR only the EDMA IRQ
  378.  * is disabled.
  379.  */
  380. static Void linkPacket(ChanHandle chan, IOM_Packet *packet)
  381. {
  382.     EDMA_Handle pramPtr;
  383.     Uns edmaCnt;
  384.     /* Store the packet in the packetList */
  385.     chan->packetList[chan->writeIndex] = packet;
  386.     /* Set up pointer to link PaRAM to write submit job info to */
  387.     pramPtr = chan->pramTbl[chan->writeIndex];
  388.     chan->writeIndex = nextIndex(chan->writeIndex);
  389.     /* Load the buffer pointer into the EDMA */
  390.     if (chan->mode == INPUT) {
  391.         EDMA_RSETH(pramPtr, DST, (Uint32) packet->addr);
  392.     }
  393.     else {
  394.         EDMA_RSETH(pramPtr, SRC, (Uint32) packet->addr);
  395.     }
  396.     /*
  397.      * Load the transfer count (in samples) into the EDMA. Use the ESIZE
  398.      * field of the EDMA job to calculate number of samples.
  399.      */
  400.     edmaCnt = (Uint32)packet->size >> (2 - EDMA_FGETH(pramPtr, OPT, ESIZE));
  401.     EDMA_FSETH(pramPtr, CNT, FRMCNT, (edmaCnt / 
  402.             EDMA_FGETH(pramPtr, CNT, ELECNT) - 1)); 
  403.     /*
  404.      * Link to loop EDMA job upon termination. This way we won't
  405.      * loose the frame sync if the channel is starved.
  406.      */
  407.     EDMA_link(pramPtr, chan->loophEdma);
  408.     /* Disable the EDMA channel to make sure current job doesn't complete */
  409.     EDMA_disableChannel(chan->xferPram);
  410.     /*
  411.      * Link the currently executing job to the new job. This can be
  412.      * either the loop EDMA job or a real data EDMA job.
  413.      */
  414.     EDMA_link(chan->xferPram, pramPtr);
  415.     if (chan->submitCount > 0) {
  416.         /*
  417.          * We need to link the parameter space corresponding to the running
  418.          * job so that if a breakpoint occurs, we know how to recover.
  419.          */
  420.         EDMA_link(chan->prevPramPtr, pramPtr);
  421.     }
  422.     /* Reenable the EDMA channel */
  423.     EDMA_enableChannel(chan->xferPram);
  424.     /* Save the new job for the loop above for next time */
  425.     chan->prevPramPtr = pramPtr;
  426. }
  427. /*
  428.  * ======== mdBindDev ========
  429.  * This function allocates and configures the McASP port specified by devId.
  430.  */
  431. static Int mdBindDev(Ptr *devp, Int devid, Ptr devParams)
  432. {
  433.     Uns old;
  434.     Int inIrqId;
  435.     int outIrqId;
  436.     int irqId;
  437.     PortHandle port;
  438.     HWI_Attrs hwiAttrs;
  439.     C6X1X_EDMA_MCASP_DevParams *params =
  440.         (C6X1X_EDMA_MCASP_DevParams *) devParams;
  441.     /* This driver must receive a valid devparams */
  442.     if (params == NULL) {
  443.         return (IOM_EBADARGS);
  444.     }
  445.     /* Check the version number */
  446.     if (params->versionId != C6X1X_EDMA_MCASP_VERSION_1){
  447.         /* Unsupported version */
  448.         return(IOM_EBADARGS);
  449.     }
  450.     /* Get the device parameters of the specified port */
  451.     port = &ports[devid];
  452.     /* Mark the port as in use */
  453.     old = ATM_setu(&(port->inUse), TRUE);
  454.     /* Check if the port was already bound */
  455.     if (old) {
  456.         return (IOM_EALLOC);
  457.     }
  458.     /* Map the supplied IRQ to the EDMA event */
  459.     if (params->irqId > 0 ) {
  460.         irqId = params->irqId;
  461.     }
  462.     else {
  463.         irqId = IRQEDMA;
  464.     }
  465.     IRQ_map(IRQ_EVT_EDMAINT, irqId);
  466.     hwiAttrs.intrMask = params->edmaIntrMask;
  467.     hwiAttrs.ccMask = IRQ_CCMASK_NONE; /* the default value */
  468.     hwiAttrs.arg = NULL;
  469.     /* Plug the EDMA dispatcher into the HWI dispatcher */
  470.     HWI_dispatchPlug(irqId, (Fxn)EDMA_intDispatcher, -1, &hwiAttrs);
  471.    
  472.     /* Set the McASP high frequency sample rate generator */
  473.     /* Set the McASP sample rate generator */
  474.     /* Set the McASP frame sync generator */
  475.     port->enableHclkg = params->enableHclkg;
  476.     port->enableClkg = params->enableClkg;
  477.     port->enableFsyncg = params->enableFsyncg;
  478.     /* True if buffers are in external memory */
  479.     port->cacheCalls = params->cacheCalls;
  480.     /* Store the devid */
  481.     port->devId = devid;
  482.     /* No channel create yet */
  483.     port->chanCreated = 0;
  484.     /* Open and reset the McASP */
  485.     port->hMcasp = MCASP_open(devid, MCASP_OPEN_RESET);
  486.     if (port->hMcasp == INV) {
  487.         return (IOM_EALLOC);
  488.     }
  489.     /* Configure the McASP with the supplied configuration */
  490.     MCASP_config(port->hMcasp, params->mcaspCfgPtr);
  491.     if (params->evtCallback != NULL) {
  492.         /* register the events */
  493.         port->evtCallback = params->evtCallback->evtFxn;
  494.         port->evtMask = params->evtCallback->evtMask;
  495.  
  496.         if (params->inEvtIrqId > 0) {
  497.             inIrqId = params->inEvtIrqId;
  498.         }
  499.         else {
  500.             inIrqId = IRQEVTINPUT;
  501.         } 
  502.         if (params->outEvtIrqId > 0) {
  503.             outIrqId = params->outEvtIrqId;
  504.         }
  505.         else {
  506.             outIrqId = IRQEVTOUTPUT;
  507.         } 
  508.         IRQ_map(MCASP_getXmtEventId(port->hMcasp), outIrqId);
  509.         IRQ_map(MCASP_getRcvEventId(port->hMcasp), inIrqId); 
  510.         hwiAttrs.intrMask = params->inEvtIntrMask;
  511.         hwiAttrs.ccMask = IRQ_CCMASK_NONE; /* the default value */
  512.         hwiAttrs.arg = INPUT;
  513.         HWI_dispatchPlug(inIrqId, (Fxn)isrEvent, -1, &hwiAttrs);
  514.         hwiAttrs.intrMask = params->outEvtIntrMask;
  515.         hwiAttrs.ccMask = IRQ_CCMASK_NONE; /* the default value */
  516.         hwiAttrs.arg = OUTPUT;
  517.         HWI_dispatchPlug(outIrqId, (Fxn)isrEvent, -1, &hwiAttrs);
  518.     } 
  519.     else {
  520.         port->evtCallback = NULL;
  521.     }
  522.     /* set 0xe for debug, real value should be 0 */
  523.     loopSrcBuf = 0;
  524.     loopDstBuf = 0; 
  525.     /* Return the device handle and a status code for success */
  526.     *devp = port;
  527.     return (IOM_COMPLETED);
  528. }
  529. /*
  530.  * ======== mdCreateChan ========
  531.  * This function creates and configures a device channel.
  532.  */
  533. static Int mdCreateChan(Ptr *chanp, Ptr devp, String name, Int mode,
  534.                         Ptr chanParams, IOM_TiomCallback cbFxn, Ptr cbArg)
  535. {
  536.     PortHandle port = (PortHandle) devp;
  537.     C6X1X_EDMA_MCASP_ChanParams *params =
  538.         (C6X1X_EDMA_MCASP_ChanParams *) chanParams;
  539.     ChanHandle chan;
  540.     Uns old;
  541.     Uns esize;
  542.     Uns cnt;
  543.     Uns fs;
  544.     Uns elerld;
  545.     Uns mcaspAddr;
  546.     Int edmaChanEvent;
  547.     Int i;
  548. #if ENABLELOOPINTR
  549.     Int loopTcc;
  550. #endif
  551.     /*
  552.      * Configuration structure for the loop EDMA job. If the McASP
  553.      * is left to free running, this loop job is running when there is
  554.      * no data to transfer. This is useful if the McASP is externally
  555.      * clocked.  If the driver is starved or if an emulation halt
  556.      * (breakpoint) occurs, the frame sync will still be correct when
  557.      * the driver continues transmitting data.
  558.      */
  559.     EDMA_Config loopEdmaCfg = {
  560.         EDMA_FMKS(OPT, PRI, HIGH)           |
  561.         EDMA_FMKS(OPT, ESIZE, 32BIT)        |
  562.         EDMA_FMKS(OPT, 2DS, NO)             |
  563.         EDMA_FMKS(OPT, SUM, NONE)           |
  564.         EDMA_FMKS(OPT, 2DD, NO)             |
  565.         EDMA_FMKS(OPT, DUM, NONE)           |
  566.         EDMA_FMKS(OPT, TCINT, NO)           |
  567.         EDMA_FMKS(OPT, TCC, DEFAULT)        |
  568.         EDMA_FMKS(OPT, LINK, YES)           |
  569.         EDMA_FMKS(OPT, FS, NO),
  570.         EDMA_FMK (SRC, SRC, NULL),
  571.         EDMA_FMK (CNT, FRMCNT, 0)           |
  572.         EDMA_FMK (CNT, ELECNT, 0),
  573.         EDMA_FMKS(IDX, FRMIDX, OF(0))       |
  574.         EDMA_FMKS(IDX, ELEIDX, OF(0)),
  575.         EDMA_FMK (DST, DST, NULL),
  576.         EDMA_FMK (RLD, ELERLD, 0)           |
  577.         EDMA_FMK (RLD, LINK, NULL)
  578.     };
  579.     /* This driver needs a valid channel parameter structure passed */
  580.     if (params == NULL) {
  581.         return (IOM_EBADARGS);
  582.     }
  583.     /* Use own indexes since IOM mode is a bit mask and not an index */
  584.     if (mode == IOM_INPUT) {
  585.         chan = &port->chans[INPUT];
  586.         chan->mode = INPUT;
  587.     }
  588.     else {
  589.         chan = &port->chans[OUTPUT];
  590.         chan->mode = OUTPUT;
  591.     }
  592.     /* Mark the channel as used */
  593.     old = ATM_setu(&(chan->inUse), TRUE);
  594.     /* Make sure the channel wasn't already created */
  595.     if (old) {
  596.         return (IOM_EALLOC);
  597.     }
  598.     /* Initialise the channel structure */
  599.     chan->cbFxn = cbFxn;
  600.     chan->cbArg = cbArg;
  601.     chan->port = port;
  602.     chan->writeIndex = 0;
  603.     chan->readIndex = 0;
  604.     chan->submitCount = 0;
  605.     chan->flushPacket = NULL;
  606.     chan->abortPacket = NULL;
  607.     /* Initialize the packet queue */
  608.     QUE_new(&chan->packetQueue);
  609.     /*
  610.      * Set the number of elements (corresponding to number of McASP TDM
  611.      * channels) used in the Loop job to preserve the frame sync.
  612.      * FRMCNT should be (num of TDM slots - 1);
  613.      */
  614.     cnt = params->tdmChans - 1;
  615.     EDMA_FSETA(&loopEdmaCfg.cnt, CNT, FRMCNT, cnt);
  616.     EDMA_FSETA(&loopEdmaCfg.cnt, CNT, ELECNT, params->edmaCfgPtr->cnt);
  617.     /* Use the same sample size in the Loop job as in normal jobs */
  618.     esize = EDMA_FGETA(&params->edmaCfgPtr->opt, OPT, ESIZE);
  619.     EDMA_FSETA(&loopEdmaCfg.opt, OPT, ESIZE, esize);
  620.     /* Use  the same FS info as in the normal job */
  621.     fs = EDMA_FGETA(&params->edmaCfgPtr->opt, OPT, FS); 
  622.     EDMA_FSETA(&loopEdmaCfg.opt, OPT, FS, fs);
  623.     /* Use  the same ELERLD info as in the normal job */
  624.     elerld = EDMA_FGETA(&params->edmaCfgPtr->rld, RLD, ELERLD); 
  625.     EDMA_FSETA(&loopEdmaCfg.rld, RLD, ELERLD, elerld); 
  626.     /* Allocate a TCC for the EDMA */
  627.     chan->tcc = EDMA_intAlloc(-1);
  628.     /* If tcc > 15 we abort. */
  629.     if (chan->tcc == -1 || chan->tcc > 15) {
  630.         chanCleanUp(chan, SETFALSE);
  631.         return (IOM_EALLOC);
  632.     }
  633. #if ENABLELOOPINTR
  634.     loopTcc = EDMA_intAlloc(-1);
  635.     /* If tcc > 15 we abort. */
  636.     if (loopTcc == -1 || loopTcc > 15) {
  637.         EDMA_intFree(loopTcc);
  638.         chanCleanUp(chan, FREETCC);
  639.         return (IOM_EALLOC);
  640.     }
  641. #endif
  642.     /* Allocate an EDMA PaRAM for the Loop EDMA job. */
  643.     chan->loophEdma = EDMA_allocTable(-1);
  644.     if (chan->loophEdma == EDMA_HINV) {
  645.         chanCleanUp(chan, FREETCC);
  646.         return (IOM_EALLOC);
  647.     }
  648.     /*
  649.      * Allocate EDMA PaRAM link area based on max number of
  650.      * submits possible.
  651.      */
  652.     if (EDMA_allocTableEx(MAXLINKCNT, chan->pramTbl) != MAXLINKCNT) {
  653.         chanCleanUp(chan, FREETABLE);
  654.         return (IOM_EALLOC);
  655.     }
  656.     /* workaround for big endian problem in McASP */
  657.     if (chan->mode == INPUT) {
  658.         mcaspAddr = MCASP_getRbufAddr(port->hMcasp);
  659.     }
  660.     else {
  661.         mcaspAddr = MCASP_getXbufAddr(port->hMcasp);
  662.     }
  663. #ifdef _BIG_ENDIAN
  664.     if (esize == EDMA_OPT_ESIZE_8BIT) {
  665.         mcaspAddr += 3;
  666.     }
  667.     else if (esize == EDMA_OPT_ESIZE_16BIT) {
  668.         mcaspAddr += 2;
  669.     }
  670. #endif
  671.     if (chan->mode == INPUT) {
  672.         
  673.         /* Put input specific parameters in the Loop EDMA config */
  674.         EDMA_RSETA(&loopEdmaCfg.src, SRC, mcaspAddr);
  675.         EDMA_RSETA(&loopEdmaCfg.dst, DST, (Uint32) &loopDstBuf);
  676.         EDMA_RSETA(&params->edmaCfgPtr->src, SRC, mcaspAddr);
  677.         /* Register our isrInput with the EDMA dispatcher */
  678.         EDMA_intHook(chan->tcc, &isrInput);
  679.     }
  680.     else {     
  681.         
  682.         /* Put output specific parameters in the Loop EDMA config */
  683.         EDMA_RSETA(&loopEdmaCfg.src, SRC, (Uint32) &loopSrcBuf);
  684.         EDMA_RSETA(&loopEdmaCfg.dst, DST, mcaspAddr);
  685.         EDMA_RSETA(&params->edmaCfgPtr->dst, DST, mcaspAddr);
  686.         /* Register our isrOutput with the EDMA dispatcher */
  687.         EDMA_intHook(chan->tcc, &isrOutput);
  688.     }
  689.     /* Open theEDMA Channel */
  690. #if (CHIP_DM642)
  691.     edmaChanEvent = eventIds[port->devId][chan->mode]; 
  692. #else
  693.     edmaChanEvent = EDMA_map(eventIds[port->devId][chan->mode], 
  694.             params->edmaChan); 
  695. #endif
  696.     chan->xferPram = EDMA_open(edmaChanEvent, EDMA_OPEN_RESET);
  697.     if (chan->xferPram == EDMA_HINV) {
  698.         chanCleanUp(chan, FREETABLEEX);
  699.         return (IOM_EALLOC);
  700.     }
  701.     /* Program the data EDMA job with the TCC */
  702.     EDMA_FSETA(&params->edmaCfgPtr->opt, OPT, TCC, chan->tcc);
  703. #if ENABLELOOPINTR
  704.     EDMA_intHook(loopTcc, &isrLoop);
  705.     EDMA_FSETA(&loopEdmaCfg.opt, OPT, TCINT, EDMA_OPT_TCINT_YES);
  706.     EDMA_FSETA(&loopEdmaCfg.opt, OPT, TCC, loopTcc);
  707. #endif
  708.     /* Program the link PaRAMs with the config struct */
  709.     for (i=0; i < MAXLINKCNT; i++) {
  710.         EDMA_config(chan->pramTbl[i], params->edmaCfgPtr);
  711.     }
  712.     /* Program the Loop EDMA job with its config struct */
  713.     EDMA_config(chan->loophEdma, &loopEdmaCfg);
  714.     /*
  715.      * Link the Loop EDMA job to itself to make it run
  716.      * continuously when there is no data to transmit.
  717.      */
  718.     EDMA_link(chan->loophEdma, chan->loophEdma);
  719.     /* Configure the EDMA channel to start with the Loop EDMA job */
  720.     EDMA_config(chan->xferPram, &loopEdmaCfg);
  721.     EDMA_link(chan->xferPram, chan->loophEdma);
  722.     /* Transfer complete is edge triggered, so clear before enabling */
  723.     EDMA_intClear(chan->tcc);
  724.     EDMA_intEnable(chan->tcc);
  725. #if ENABLELOOPINTR
  726.     EDMA_intClear(loopTcc);
  727.     EDMA_intEnable(loopTcc);
  728. #endif
  729.     /* Enable the EDMA interrupt */
  730.     IRQ_enable(IRQ_EVT_EDMAINT);
  731.     EDMA_enableChannel(chan->xferPram);
  732.     /* Start the McASP */
  733.     if (chan->mode == INPUT) {
  734.         old = ATM_setu(&(port->chanCreated), TRUE);
  735.         
  736.         /* 
  737.          * clock generator is divided from high frequency clock, so start high
  738.          * freq clock generator first 
  739.          */
  740.         if (port->enableHclkg == C6X1X_EDMA_MCASP_RCV) {
  741.             MCASP_enableHclk(port->hMcasp, MCASP_RCV); 
  742.             while(!MCASP_FGETH(port->hMcasp, GBLCTL, RHCLKRST));
  743.         }
  744.         else if ((port->enableHclkg == C6X1X_EDMA_MCASP_RCVXMT) && (old)) {
  745.             MCASP_enableHclk(port->hMcasp, MCASP_RCVXMT); 
  746.             while(!(MCASP_FGETH(port->hMcasp, GBLCTL, RHCLKRST) & 
  747.                     MCASP_FGETH(port->hMcasp, GBLCTL, XHCLKRST)));
  748.         }
  749.         if (port->enableClkg == C6X1X_EDMA_MCASP_RCV) {
  750.             MCASP_enableClk(port->hMcasp, MCASP_RCV); 
  751.             while(!MCASP_FGETH(port->hMcasp, GBLCTL, RCLKRST)); 
  752.         } 
  753.         else if ((port->enableClkg == C6X1X_EDMA_MCASP_RCVXMT) && (old)) {
  754.             MCASP_enableClk(port->hMcasp, MCASP_RCVXMT); 
  755.             while(!( MCASP_FGETH(port->hMcasp, GBLCTL, RCLKRST) & 
  756.                 MCASP_FGETH(port->hMcasp, GBLCTL, XCLKRST)));
  757.         } 
  758. #if STARTSERIALIZERSYNC
  759.         if (old) {
  760.             MCASP_enableSers(port->hMcasp, MCASP_RCVXMT);
  761.             while (!(MCASP_FGETH(port->hMcasp, GBLCTL, RSRCLR) &
  762.                     MCASP_FGETH(port->hMcasp, GBLCTL, XSRCLR)));
  763.             while (MCASP_xdata(port->hMcasp));
  764.             MCASP_enableSm(port->hMcasp, MCASP_RCVXMT);
  765.             while (!(MCASP_FGETH(port->hMcasp, GBLCTL, RSMRST) &
  766.                     MCASP_FGETH(port->hMcasp, GBLCTL, XSMRST)));     
  767.         }
  768. #else
  769.         MCASP_enableSers(port->hMcasp, MCASP_RCV);
  770.         while (!MCASP_FGETH(port->hMcasp, GBLCTL, RSRCLR));
  771.         MCASP_enableSm(port->hMcasp, MCASP_RCV);
  772.         while (!MCASP_FGETH(port->hMcasp, GBLCTL, RSMRST));     
  773. #endif
  774.         if (port->enableFsyncg == C6X1X_EDMA_MCASP_RCV) {
  775.               MCASP_enableFsync(port->hMcasp, MCASP_RCV);
  776.               while(!MCASP_FGETH(port->hMcasp, GBLCTL, RFRST));    
  777.         }
  778.         else if ((port->enableFsyncg == C6X1X_EDMA_MCASP_RCVXMT) && (old)) {
  779.             MCASP_enableFsync(port->hMcasp, MCASP_RCVXMT);
  780.             while(!(MCASP_FGETH(port->hMcasp, GBLCTL, RFRST) & 
  781.                     MCASP_FGETH(port->hMcasp, GBLCTL, XFRST)) );       
  782.         } 
  783.     }
  784.     else {
  785.         old = ATM_setu(&(port->chanCreated), TRUE);
  786.         /* 
  787.          * clock generator is divided from high frequency clock, so start high
  788.          * freq clock generator first 
  789.          */
  790.         if (port->enableHclkg == C6X1X_EDMA_MCASP_XMT) {
  791.             MCASP_enableHclk(port->hMcasp, MCASP_XMT); 
  792.             while(!MCASP_FGETH(port->hMcasp, GBLCTL, XHCLKRST));
  793.         }
  794.         else if ((port->enableHclkg  == C6X1X_EDMA_MCASP_RCVXMT) && (old)) {
  795.             MCASP_enableHclk(port->hMcasp, MCASP_RCVXMT); 
  796.             while(!( MCASP_FGETH(port->hMcasp, GBLCTL, RHCLKRST) & 
  797.                     MCASP_FGETH(port->hMcasp, GBLCTL, XHCLKRST)));
  798.         }
  799.         if (port->enableClkg == C6X1X_EDMA_MCASP_XMT) {
  800.             MCASP_enableClk(port->hMcasp, MCASP_XMT); 
  801.             while(!MCASP_FGETH(port->hMcasp, GBLCTL, XCLKRST));
  802.         }
  803.         else if ((port->enableClkg == C6X1X_EDMA_MCASP_RCVXMT) && (old)) {
  804.             MCASP_enableClk(port->hMcasp, MCASP_RCVXMT); 
  805.             while(!( MCASP_FGETH(port->hMcasp, GBLCTL, RCLKRST) & 
  806.                     MCASP_FGETH(port->hMcasp, GBLCTL, XCLKRST)));
  807.         }
  808. #if STARTSERIALIZERSYNC
  809.         if (old) {
  810.             MCASP_enableSers(port->hMcasp, MCASP_RCVXMT);
  811.             while (!(MCASP_FGETH(port->hMcasp, GBLCTL, XSRCLR) &
  812.                     MCASP_FGETH(port->hMcasp, GBLCTL, RSRCLR)));
  813.             while (MCASP_xdata(port->hMcasp));
  814.             MCASP_enableSm(port->hMcasp, MCASP_RCVXMT);
  815.             while (!(MCASP_FGETH(port->hMcasp, GBLCTL, XSMRST) &
  816.                     MCASP_FGETH(port->hMcasp, GBLCTL, RSMRST)));     
  817.         }
  818. #else
  819.         MCASP_enableSers(port->hMcasp, MCASP_XMT);
  820.         while (!(MCASP_FGETH(port->hMcasp, GBLCTL, XSRCLR)));
  821.         while (MCASP_xdata(port->hMcasp));
  822.         MCASP_enableSm(port->hMcasp, MCASP_XMT);
  823.         while (!(MCASP_FGETH(port->hMcasp, GBLCTL, XSMRST)));     
  824. #endif
  825.         if (port->enableFsyncg == C6X1X_EDMA_MCASP_XMT) {
  826.             MCASP_enableFsync(port->hMcasp, MCASP_XMT);
  827.             while(!MCASP_FGETH(port->hMcasp,GBLCTL, XFRST));       
  828.         }
  829.         else if ((port->enableFsyncg == C6X1X_EDMA_MCASP_RCVXMT) && (old)) {
  830.             MCASP_enableFsync(port->hMcasp, MCASP_RCVXMT);
  831.             while(!(MCASP_FGETH(port->hMcasp,GBLCTL, RFRST) & 
  832.                     MCASP_FGETH(port->hMcasp,GBLCTL, XFRST)) );       
  833.         } 
  834.     } 
  835.     /* enable McASP event interrupt if registered */
  836.     /* Clear CKFAIL error before enable interrupt */
  837.     if (chan->mode == INPUT) { 
  838.         if (port->evtCallback != NULL) {
  839.             if (port->evtMask & C6X1X_EDMA_MCASP_EVT_RCKFAIL) { 
  840.                 MCASP_FSETSH(port->hMcasp, RINTCTL, RCKFAIL, DISABLE);
  841.                 while (MCASP_FGETH(port->hMcasp, RSTAT, RCKFAIL)) {
  842.                     MCASP_FSETSH(port->hMcasp, RSTAT, RCKFAIL, YES);
  843.                 }
  844.                 MCASP_FSETSH(port->hMcasp, RINTCTL, RCKFAIL, ENABLE);
  845.             }
  846.             IRQ_enable(MCASP_getRcvEventId(port->hMcasp));
  847.         }
  848.     } 
  849.     else { 
  850.         if (port->evtCallback != NULL) { 
  851.             if (port->evtMask & C6X1X_EDMA_MCASP_EVT_XCKFAIL) { 
  852.                 MCASP_FSETSH(port->hMcasp, XINTCTL, XCKFAIL, DISABLE);
  853.                 while (MCASP_FGETH(port->hMcasp, XSTAT, XCKFAIL)) {
  854.                     MCASP_FSETSH(port->hMcasp, XSTAT, XCKFAIL, YES);
  855.                 }
  856.                 MCASP_FSETSH(port->hMcasp, XINTCTL, XCKFAIL, ENABLE);
  857.             }
  858.             IRQ_enable(MCASP_getXmtEventId(port->hMcasp));
  859.         }
  860.     }
  861.     
  862.     *chanp = (Ptr) chan;
  863.     return (IOM_COMPLETED);
  864. }
  865. /*
  866.  * ======== mdDeleteChan ========
  867.  * This function frees a channel and all it's associated resources.
  868.  */
  869. static Int mdDeleteChan(Ptr chanp)
  870. {
  871.     ChanHandle chan = (ChanHandle) chanp;
  872.     PortHandle port = chan->port;
  873.     /* Clean up the channel resources */
  874.     chanCleanUp(chan, DELCHAN);
  875.     /*
  876.      * Reset the McASP transmitter or receiver. If the channel is
  877.      * recreated, mdCreateChan() will reenable the transmitter/receiver
  878.      * and by pulling it out of reset it will also restart the EDMA channel.
  879.      */
  880.     if (chan->mode == INPUT) {
  881.         MCASP_resetRcv(port->hMcasp);
  882.     }
  883.     else {
  884.         MCASP_resetXmt(port->hMcasp);
  885.     }
  886.     return (IOM_COMPLETED);
  887. }
  888. /*
  889.  * ======== mdSubmitChan ========
  890.  * This function transmits a buffer to or from the McASP using the EDMA.
  891.  */
  892. static Int mdSubmitChan(Ptr chanp, IOM_Packet *packet)
  893. {
  894.     ChanHandle chan = (ChanHandle) chanp;
  895.     PortHandle port = chan->port;
  896.     Uns imask;
  897.     /* No packets can be submitted while abort or flush is active */
  898.     if (chan->flushPacket || chan->abortPacket) {
  899.         return (IOM_EBADIO);
  900.     }
  901.     /*
  902.      * Check to see if an abort command has been issued. Note that
  903.      * flushing the input channel is handled the same as abort.
  904.      */
  905.     if ((packet->cmd == IOM_FLUSH && chan->mode == INPUT) ||
  906.         packet->cmd == IOM_ABORT) {
  907.         /* Disable interrupts to protect submitCount */
  908.         imask = HWI_disable();
  909.         /* Store the abort packet for the ISR to check */
  910.         if (chan->submitCount > 0) {
  911.             chan->abortPacket = packet;
  912.             /*
  913.              * Disable the EDMA channel while linking the currently
  914.              * executing job while linking it with the Loop job to make
  915.              * sure the currently executing job doesn't complete before
  916.              * the link is complete.
  917.              */
  918.             EDMA_disableChannel(chan->xferPram);
  919.             EDMA_link(chan->xferPram, chan->loophEdma);
  920.             EDMA_enableChannel(chan->xferPram);
  921.         }
  922.         /* Reenable interrupts */
  923.         HWI_restore(imask);
  924.         if (chan->abortPacket) {
  925.             return(IOM_PENDING);
  926.         }
  927.         /* If there were no buffers in the channel, return synchronously */
  928.         packet->status = IOM_COMPLETED;
  929.         return (IOM_COMPLETED);
  930.     }
  931.     /* Check to see if the submitted packet is an output flush packet */
  932.     if (packet->cmd == IOM_FLUSH && chan->mode == OUTPUT) {
  933.         /* Disable interrupts to protect submitCount */
  934.         imask = HWI_disable();
  935.         /* Store the flush packet for the ISR to check */
  936.         if (chan->submitCount > 0) {
  937.             chan->flushPacket = packet;
  938.         }
  939.         /* Reenable interrupts */
  940.         HWI_restore(imask);
  941.         if (chan->flushPacket) {
  942.             return(IOM_PENDING);
  943.         }
  944.         /* If there were no buffers in the channel, return synchronously */
  945.         packet->status = IOM_COMPLETED;
  946.         return (IOM_COMPLETED);
  947.     }
  948.     if (packet->cmd != IOM_READ && packet->cmd != IOM_WRITE) {
  949.         /* Unsupported command passed */
  950.         return (IOM_ENOTIMPL);
  951.     }
  952.     /* maintain cache coherency */
  953.     if (chan->mode == INPUT) {
  954.         /* CACHE uses words, and packet->size is in nmaus (bytes on c6x) */
  955.         if (port->cacheCalls) {
  956.             CACHE_clean(CACHE_L2, packet->addr, packet->size >> 2);
  957.         }
  958.     }
  959.     else {
  960.         /* CACHE uses words, and packet->size is in nmaus (bytes on c6x) */
  961.         if (port->cacheCalls) {
  962.             CACHE_flush(CACHE_L2, packet->addr, packet->size >> 2);
  963.         }
  964.     }
  965.     /* Disable interrupts to protect submitCount */
  966.     imask = HWI_disable();
  967.     /*
  968.      * If there is no space available for the new packet, put it on a
  969.      * queue to be linked in when space is available. Otherwise link it in.
  970.      */
  971.     if (chan->submitCount >= MAXLINKCNT) {
  972.         QUE_enqueue(&chan->packetQueue, packet);
  973.     }
  974.     else {
  975.         linkPacket(chan, packet);
  976.     }
  977.     chan->submitCount++;
  978.     HWI_restore(imask);
  979.     return (IOM_PENDING);
  980. }
  981. /*
  982.  * ======== mdUnBindDev ========
  983.  * This function frees a port and all it's associated resources.
  984.  */
  985. static Int mdUnBindDev(Ptr devp)
  986. {
  987.     PortHandle port = (PortHandle) devp;
  988.     port->inUse = FALSE;
  989.     /* Close the McASP */
  990.     MCASP_close(port->hMcasp);
  991.     return (IOM_COMPLETED);
  992. }
  993. /*
  994.  * ======== C6X1X_EDMA_MCASP_init ========
  995.  * This function initializes the driver's data structures.
  996.  */
  997. #pragma CODE_SECTION(C6X1X_EDMA_MCASP_init, ".text:init");
  998. Void C6X1X_EDMA_MCASP_init()
  999. {
  1000.     PortHandle port;
  1001.     ChanHandle chan;
  1002.     Int i, j;
  1003.     /* Make sure the initialization only happens once for thid driver */
  1004.     static Bool curInit = FALSE;
  1005.     if (curInit) {
  1006.         return;
  1007.     }
  1008.     curInit = TRUE;
  1009.     for (i=0; i<NUMPORTS; i++) {
  1010.         port = &ports[i];
  1011.         port->inUse = FALSE;
  1012.         for (j=0; j<NUMCHANS; j++) {
  1013.             chan = &port->chans[j];
  1014.             chan->inUse = FALSE;
  1015.         }
  1016.     }
  1017. }