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

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. /* DSP/BIOS standard include files */
  10. #include <std.h>
  11. #include <mem.h>
  12. #include <que.h>     
  13. #include <tsk.h>    
  14. #include <hwi.h>          
  15. #include <clk.h>
  16. /* Chip-support library include files */
  17. #include <csl.h>
  18. #include <csl_edma.h>
  19. #include <csl_vphal.h>         
  20. #include <csl_irq.h>
  21. #include <csl_cache.h>
  22. /* IOM/GIO driver model include files */
  23. #include <iom.h>
  24. #include <fvid.h>                       
  25. /* video driver specific include files */
  26. #include <vport.h>
  27. #include <vportcap.h>
  28. #include <edc.h>
  29. #include "_vport.h"
  30. /* debug include files */
  31. /* to minimize code size and cycle count overhead of the driver */             
  32. /* error checking is only performed at debug time               */
  33. #include <assert.h>
  34. /* type defines and data structures */
  35. /**************************************************************
  36.  *     data structure for video port object                   *
  37.  **************************************************************/
  38. typedef struct PortObj{
  39.     /* port status register, contains information on whether */
  40.     /* port is opened, configured, etc.                      */
  41.     Int     status;
  42.     /* vp base address for all register access */
  43.     Int     base;
  44.     
  45.     /* two channel objects for channel A & B.  */
  46.     /* This is only for capture operation      */
  47.     _VPORT_ChanObj chanObj[2];
  48. } PortObj;
  49. /* mini-driver API functions */
  50. static Int mdBindDev(Ptr *devp, Int devid, Ptr devParams);
  51. static Int mdControlChan(Ptr chanp, Uns cmd, Ptr args);
  52. static Int mdCreateChan(Ptr *chanp, Ptr devp, String name, Int mode,
  53.         Ptr chanParams, IOM_TiomCallback cbFxn, Ptr cbArg);
  54. static Int mdDeleteChan(Ptr chanp);
  55. static Int mdSubmitChan(Ptr chanp, IOM_Packet *packet);
  56. /* local functions */
  57. static void captureEdmaISR(Int tcc);
  58. static void captureISR(Int portNum);
  59. static Int _configCh(Ptr chanp, VPORTCAP_Params *params);
  60. static Int _configChan(Ptr chanp, Ptr args);     
  61. static Int _configPort(Ptr chanp, Ptr args);    
  62. static Int _configTransfer(Ptr chanp,VPORTCAP_Params *params);  
  63. static Int _covrRecover(Ptr chanp);
  64. static Int _setVIntCb(Ptr chanp, Ptr args);
  65. static Int _startVPCapture(Ptr chanp);
  66. static Int _stopVPCapture(Ptr chanp);   
  67. /* global and static variables */
  68. IOM_Fxns VPORTCAP_Fxns = {
  69.     mdBindDev,    
  70.     (IOM_TmdUnBindDev)IOM_mdNotImpl,
  71.     mdControlChan,
  72.     mdCreateChan,
  73.     mdDeleteChan,
  74.     mdSubmitChan
  75. };
  76. /**************************************************************
  77.  * Static allocation and initialization of port objects       *
  78.  **************************************************************/
  79. static PortObj portObjs[_VP_PORT_CNT] = {
  80.     /* video port 0 */
  81.     {0, _VP_BASE_PORT0,
  82.     /* channel A */  
  83.         {{0, 0, 0, _VP_BASE_CHAPORT0, EDMA_CHA_VP0EVTYA, EDMA_CHA_VP0EVTUA, 
  84.         EDMA_CHA_VP0EVTVA, _VP_YSRCA0_ADDR, _VP_CBSRCA0_ADDR, 
  85.         _VP_CRSRCA0_ADDR }, 
  86.     /* channel B */  
  87.         {0, 0, 1, _VP_BASE_CHBPORT0, EDMA_CHA_VP0EVTYB, EDMA_CHA_VP0EVTUB, 
  88.         EDMA_CHA_VP0EVTVB,  _VP_YSRCB0_ADDR, _VP_CBSRCB0_ADDR, 
  89.         _VP_CRSRCB0_ADDR}}},
  90.     /* video port 1 */
  91.     {0, _VP_BASE_PORT1, 
  92.     /* channel A */  
  93.         {{0, 1, 0, _VP_BASE_CHAPORT1, EDMA_CHA_VP1EVTYA, EDMA_CHA_VP1EVTUA, 
  94.         EDMA_CHA_VP1EVTVA, _VP_YSRCA1_ADDR, _VP_CBSRCA1_ADDR, 
  95.         _VP_CRSRCA1_ADDR }, 
  96.     /* channel B */  
  97.         {0, 1, 1, _VP_BASE_CHBPORT1, EDMA_CHA_VP1EVTYB, EDMA_CHA_VP1EVTUB, 
  98.         EDMA_CHA_VP1EVTVB, _VP_YSRCB1_ADDR, _VP_CBSRCB1_ADDR, 
  99.         _VP_CRSRCB1_ADDR}}},
  100.     /* video port 2 */
  101.     {0, _VP_BASE_PORT2,
  102.     /* channel A */  
  103.         {{0, 2, 0, _VP_BASE_CHAPORT2, EDMA_CHA_VP2EVTYA, EDMA_CHA_VP2EVTUA, 
  104.          EDMA_CHA_VP2EVTVA, _VP_YSRCA2_ADDR, _VP_CBSRCA2_ADDR, 
  105.          _VP_CRSRCA2_ADDR  }, 
  106.     /* channel B */  
  107.         {0, 2, 1, _VP_BASE_CHBPORT2, EDMA_CHA_VP2EVTYB, EDMA_CHA_VP2EVTUB, 
  108.          EDMA_CHA_VP2EVTVB,  _VP_YSRCB2_ADDR, _VP_CBSRCB2_ADDR, 
  109.          _VP_CRSRCB2_ADDR }}}
  110. };
  111. /*
  112.  *  =================== mdBindDev ============================
  113.  *  Register all external devices to video port capture driver 
  114.  */
  115. static Int mdBindDev(Ptr *devp, Int devid, Ptr devParams)
  116. {
  117.     Int portNum = devid;         
  118.     volatile Int i;
  119.     volatile Int* base = (volatile Int *)portObjs[portNum].base;                       
  120.    
  121.     assert(portNum < _VP_PORT_CNT);
  122.     base[_VP_VPCTL_OFFSET] = 
  123.              VP_VPCTL_VPRST_RESET << _VP_VPCTL_VPRST_SHIFT;
  124.     for(i = 0; i < 100000; i ++);             
  125.    
  126.     *devp = &portObjs[portNum];                                                                                           
  127.     return mdControlChan(&portObjs[portNum], VPORT_CMD_CONFIG_PORT, devParams); 
  128. }
  129. /*
  130.  *  ======== mdControlChan ========
  131.  */
  132. static Int mdControlChan(Ptr chanp, Uns cmd, Ptr args)
  133. {
  134.     Int retVal = IOM_EBADMODE;
  135.     _VPORT_ChanObj* chan = (_VPORT_ChanObj* )chanp;
  136.     PortObj* port = &portObjs[chan->portNum];
  137.     switch (cmd) {
  138.         case VPORT_CMD_START:
  139.         retVal = _startVPCapture(chanp);
  140.         break;
  141.         case VPORT_CMD_STOP:
  142.         retVal = _stopVPCapture(chanp);
  143.         break;
  144.         case VPORT_CMD_SET_VINTCB:
  145.         retVal = _setVIntCb(chanp, args);
  146.         break;
  147.         case VPORT_CMD_CONFIG_PORT:
  148.         retVal = _configPort(chanp, args);
  149.         break;
  150.         case VPORT_CMD_COVR_RECOVER:
  151.         retVal = _covrRecover(chanp);
  152.         break;
  153.         case VPORT_CMD_CONFIG_CHAN:
  154.         if(! (port->status & _VPORT_CFGED)) {
  155.             retVal = _configChan(chanp, args);
  156.         }
  157.         break;
  158.         default: 
  159.         if(chan->edcFxns!=INV){
  160.             retVal = chan->edcFxns->ctrl(chan->edcHandle, 
  161.                 cmd-VPORT_CMD_EDC_BASE,(Arg)args);
  162.         }else {
  163.             retVal = IOM_ENOTIMPL;
  164.         } 
  165.         break;   
  166.     }
  167.     return retVal;
  168. }              
  169. /*
  170.  *  =================== mdCreateChan ============================
  171.  *  create a capture channel
  172.  */
  173. static Int  mdCreateChan(Ptr *chanp, Ptr devp, String name, Int mode,
  174.                       Ptr chanParams, IOM_TiomCallback cbFxn, Ptr cbArg)
  175. {
  176.     Int chanNum;           
  177.     volatile Int* base;
  178.     PortObj* port;
  179.     Int retVal = IOM_COMPLETED;       
  180.      
  181.     if(mode != IOM_INPUT){
  182.         return IOM_EBADARGS;
  183.     }
  184.     if(*name ++ != '/') {
  185.         return IOM_EBADARGS;
  186.     }
  187.     chanNum = *name ++ - 'A';
  188.     assert(chanNum < _VPORT_CHAN_CNT);
  189.     
  190.     port = (PortObj *)devp;
  191.     if(port->chanObj[chanNum].edcFxns != INV) {
  192.         /* open external device */
  193.         port->chanObj[chanNum].edcHandle 
  194.            = port->chanObj[chanNum].edcFxns->open(name, (Arg)INV);
  195.     } 
  196.     if(! (port->status & _VPORT_OPENED)) {
  197.         port->status |= _VPORT_OPENED;
  198.         base = (volatile Int *)port->base;                       
  199.         
  200.         /* reset both channels */
  201.         base[_VP_VCACTL_OFFSET] |= 
  202.             VP_VCACTL_RSTCH_RESET << _VP_VCACTL_RSTCH_SHIFT;
  203.         base[_VP_VCBCTL_OFFSET] |= 
  204.             VP_VCBCTL_RSTCH_RESET << _VP_VCBCTL_RSTCH_SHIFT;
  205.     } /* if(!port->opened)  */
  206.     /* initialize the channel object */
  207.     if(! (port->chanObj[chanNum].status & _VPORT_OPENED)) {
  208.         Int j;
  209.         _VPORT_ChanObj *chan = &port->chanObj[chanNum];       
  210.         chan->status |= _VPORT_OPENED;
  211.         chan->vIntMask = 0;
  212.         QUE_new(&chan->qIn);
  213.         chan->cbFxn = cbFxn;
  214.         chan->vIntFxn = (VPORT_IntCallBack)INV;
  215.         chan->queEmpty = FALSE;   
  216.         chan->cbArg = (Arg)cbArg;
  217.         chan->mrViop = INV;
  218.         chan->packetIOM = INV;     
  219.         chan->numFrms = 0;
  220.         chan->vIntCbArg = (Int)INV;
  221.         chan->bufSz = 0;
  222.         for(j = 0; j < _VPORT_NUM_EDMA_CHANS && retVal == IOM_COMPLETED; j ++){
  223.             
  224.             if( (chan->hEdma[j] = EDMA_open(chan->edmaChanNum[j], 
  225.                 EDMA_OPEN_RESET))==EDMA_HINV
  226.             ||  (chan->hRld[4 * j] = EDMA_allocTable(-1))==EDMA_HINV
  227.             ||  (chan->hRld[4 * j + 1] = EDMA_allocTable(-1))==EDMA_HINV
  228.             ||  (chan->hRld[4 * j + 2] = EDMA_allocTable(-1))==EDMA_HINV
  229.             ||  (chan->hRld[4 * j + 3] = EDMA_allocTable(-1))==EDMA_HINV
  230.             ||  (chan->tcc[j] = EDMA_intAlloc(chan->edmaChanNum[j])) == -1){
  231.                 retVal = IOM_EALLOC;
  232.             }/* if((port->...*/ 
  233.         }/* for(j = 0; j < NUM_EDMA_CHANS; j++) {...*/
  234.         if( retVal == IOM_COMPLETED && (void *)chanParams != INV) {
  235.             retVal = mdControlChan(&port->chanObj[chanNum], 
  236.                 VPORT_CMD_CONFIG_CHAN, chanParams); 
  237.         }
  238.         if(retVal == IOM_COMPLETED) {
  239.              /* configure the channel */
  240.              *chanp = &port->chanObj[chanNum];
  241.         }else {
  242.             mdDeleteChan(&port->chanObj);
  243.             *chanp = INV;                     
  244.         }               
  245.     } /*if(!chan->opened) */
  246.     return retVal;
  247. }               
  248. /*
  249.  *  =================== mdDeleteChan ============================
  250.  *  delete the capture channel
  251.  */
  252. static Int  mdDeleteChan(Ptr chanp)
  253. {
  254.     _VPORT_ChanObj* chan = (_VPORT_ChanObj* )chanp;
  255.     PortObj* port = &portObjs[chan->portNum];
  256.     Int j;
  257.     volatile Int* base;
  258.     
  259.     if(chan->status & _VPORT_OPENED) {
  260.         chan->status = 0;
  261.         mdControlChan(chanp, VPORT_CMD_STOP, NULL);
  262.         for(j = 0; j < _VPORT_NUM_EDMA_CHANS; j ++) {
  263.             EDMA_disableChannel(chan->hEdma[j]);
  264.             EDMA_clearChannel(chan->hEdma[j]);
  265.             EDMA_close(chan->hEdma[j]);
  266.             EDMA_freeTable(chan->hRld[4 * j]);
  267.             EDMA_freeTable(chan->hRld[4 * j + 1]);
  268.             EDMA_freeTable(chan->hRld[4 * j + 2]);
  269.             EDMA_freeTable(chan->hRld[4 * j + 3]);
  270.             EDMA_intFree(chan->tcc[j]);
  271.         }
  272.         for(j = 0; j < chan->numFrms ; j ++) {
  273.             MEM_free(chan->segId, chan->viops[j].frame.iFrm.y1, chan->bufSz);
  274.         }        
  275.         /* close external device */
  276.         if(chan->edcFxns != INV) {
  277.             chan->edcFxns->close(chan->edcHandle);
  278.         }
  279.     }    
  280.     
  281.     if(! (port->chanObj[0].status & _VPORT_OPENED) 
  282.        && ! (port->chanObj[1].status & _VPORT_OPENED)) {
  283.         base = (volatile Int *)port->base;
  284.         /* reset both channels */
  285.         base[_VP_VCACTL_OFFSET] |= 
  286.             VP_VCACTL_RSTCH_RESET << _VP_VCACTL_RSTCH_SHIFT;
  287.         base[_VP_VCBCTL_OFFSET] |= 
  288.             VP_VCBCTL_RSTCH_RESET << _VP_VCBCTL_RSTCH_SHIFT;
  289.         /* reset video port */
  290.         base[_VP_VPCTL_OFFSET] |= 
  291.             VP_VPCTL_VPRST_RESET << _VP_VPCTL_VPRST_SHIFT;
  292.         port->status = 0;
  293.     }
  294.     return IOM_COMPLETED;
  295. }
  296. /*
  297.  *  ======== mdSubmitChan ========
  298.  */
  299. static Int  mdSubmitChan(Ptr chanp, IOM_Packet *packet)
  300. {
  301.     _VPORT_ChanObj* chan = (_VPORT_ChanObj *)chanp;
  302.     FVID_Frame* viop;                             
  303.     Uint32 gie = IRQ_globalDisable();
  304.     Int retVal = IOM_PENDING;  
  305.     Int offset = chan->nextEDMARlds << 1;
  306.     Bool nextViopChanged = FALSE;             
  307.     Bool notToLate = TRUE;
  308.     volatile Int* cBase = (volatile Int *)chan->base;
  309.     Int capStatReg = cBase[_VP_VCASTAT_OFFSETA];
  310.     short lineNum;
  311.     
  312.      
  313.     /* get the current line number being captured */
  314.     lineNum = (capStatReg & _VP_VCASTAT_VCYPOS_MASK)
  315.                            >> _VP_VCASTAT_VCYPOS_SHIFT;
  316.             
  317.     /* account for field/frame operation modes */ 
  318.     lineNum += chan->numLinesFld1 
  319.         * ((capStatReg & _VP_VCASTAT_VCFLD_MASK) >> _VP_VCASTAT_VCFLD_SHIFT);    
  320.     /* make sure we are not too close to the end of a frame */
  321.     notToLate = (lineNum < (chan->lastLineNum - 5));
  322.     assert(chan->status & _VPORT_READY);
  323.     if(packet->cmd != FVID_ALLOC 
  324.         && packet->cmd != FVID_FREE 
  325.         && packet->cmd != FVID_EXCHANGE){    
  326.         /* other commands not supported */
  327.         return IOM_ENOTIMPL;    
  328.     }
  329.     
  330.     if(packet->cmd != FVID_ALLOC) {/* FVID_FREE or FVID_EXCHANGE */
  331.         viop = *(void **)packet->addr; /* pointer of a video I/O packet */
  332.         if(chan->queEmpty && notToLate) {
  333.             /* don't put it into queue, update the rld register directly */
  334.             chan->nextViop = viop; 
  335.             nextViopChanged = TRUE;
  336.         } 
  337.         else {               
  338.             QUE_enqueue(&chan->qIn, (QUE_Handle)viop);    
  339.         }
  340.         chan->queEmpty = FALSE;
  341.         retVal = packet->status = IOM_COMPLETED;
  342.     }
  343.     if(packet->cmd != FVID_FREE) {/* FVID_ALLOC or FVID_EXCHANGE */
  344.         if(chan->mrViop != INV) {
  345.             /* only when there is no outstanding pending request */
  346.             if(chan->packetIOM == INV){
  347.                 if(chan->nextViop != chan->mrViop){
  348.                     *(void **)packet->addr = (void *)chan->mrViop;
  349.                     chan->mrViop = INV;
  350.                     packet->size = sizeof(FVID_Frame);
  351.                     retVal = packet->status = IOM_COMPLETED;                
  352.                 } else {
  353.                     if (notToLate) {
  354.                         *(void **)packet->addr = (void *)chan->mrViop;
  355.                         chan->mrViop = INV;
  356.                         packet->size = sizeof(FVID_Frame);
  357.                         retVal = packet->status = IOM_COMPLETED;
  358.                         /* If queue is already empty, it means the driver currently*/
  359.                         /* only owns one frame, which is the current frame. So make*/
  360.                         /* the next frame the same as the current one              */
  361.                         chan->nextViop = chan->curViop;
  362.                     } else {
  363.                         chan->mrViop = INV; /* too late, just recycle the mrViop */                    
  364.                         chan->packetIOM = packet;
  365.                         retVal = packet->status = IOM_PENDING;
  366.                     }
  367.                 }
  368.             }
  369.             else retVal = IOM_EINUSE;    
  370.         } else {
  371.             chan->packetIOM = packet;
  372.             retVal = packet->status = IOM_PENDING;
  373.         }        
  374.     }    
  375.     if(nextViopChanged) {
  376.         /* now modify the EDMA rld entries */
  377.         if(chan->mergeFlds){
  378.             EDMA_RSETH(chan->hRld[offset], DST, 
  379.                 chan->nextViop->frame.iFrm.y1);
  380.             EDMA_RSETH(chan->hRld[offset + 1], DST, 
  381.                 chan->nextViop->frame.iFrm.y2);
  382.             EDMA_RSETH(chan->hRld[4 + offset], DST, 
  383.                 chan->nextViop->frame.iFrm.cb1);     
  384.             EDMA_RSETH(chan->hRld[5 + offset], DST, 
  385.                 chan->nextViop->frame.iFrm.cb2);                         
  386.             EDMA_RSETH(chan->hRld[8 + offset], DST, 
  387.                 chan->nextViop->frame.iFrm.cr1);     
  388.             EDMA_RSETH(chan->hRld[9 + offset], DST, 
  389.                 chan->nextViop->frame.iFrm.cr2);              
  390.         } else {
  391.             EDMA_RSETH(chan->hRld[offset], DST, 
  392.                 chan->nextViop->frame.iFrm.y1);
  393.             EDMA_RSETH(chan->hRld[4 + offset], DST, 
  394.                 chan->nextViop->frame.iFrm.cb1);     
  395.             EDMA_RSETH(chan->hRld[8 + offset], DST, 
  396.                 chan->nextViop->frame.iFrm.cr1);                         
  397.         } /* if(chan->mergeFlds) */            
  398.     }    
  399.     IRQ_globalRestore(gie);
  400.     return retVal;
  401. }
  402. /*
  403.  *  ======== _captureEdmaISR ========
  404.  *  EDMA ISR
  405.  */
  406. static void captureEdmaISR(Int tcc) 
  407. {
  408.     Int i, j;
  409.     Int offset;
  410.     FVID_Frame *viop, *curViop;      
  411.     
  412.     
  413.     /* find out the source of the edma interrupt */
  414.     for(j = 0; j < _VP_PORT_CNT; j ++) {
  415.         for(i = 0; i < _VPORT_CHAN_CNT; i ++ ){ /* loop through two channels */
  416.             _VPORT_ChanObj* chan = &portObjs[j].chanObj[i];    
  417.             if((chan->status & _VPORT_READY)
  418.               && (tcc == chan->tcc[0] || tcc == chan->tcc[1])){
  419.                 /* re-sync tcc with activeEDMARlds */
  420.                 /* they may be out of sync after interrupt over-run */
  421.                 /* e.g. execution is halted at break-point */
  422.                 chan->nextEDMARlds = (tcc == chan->tcc[0]) ? 0 : 1;
  423.                 offset = chan->nextEDMARlds << 1;
  424.                 /* update the current and next viop pointers */
  425.                 curViop = chan->curViop;
  426.                 chan->curViop = chan->nextViop;             
  427.                 
  428.                 /* update the most recent viop */
  429.                 if(curViop != chan->mrViop  && chan->mrViop != INV) {
  430.                       QUE_enqueue(&chan->qIn, chan->mrViop);
  431.                 } 
  432.                 chan->mrViop = curViop;
  433.                 if((viop = (FVID_Frame *)QUE_dequeue(&chan->qIn))
  434.                     !=(FVID_Frame *)&chan->qIn) {
  435.                     /* queue IS not empty */
  436.                     chan->nextViop = viop;
  437.                 }else {
  438.                     if(chan->packetIOM == INV) {
  439.                         /* in queue is empty, but no request is pending */
  440.                         /* recycle the current VIOP back                */
  441.                         /* but still set it as the most recent VIOP     */
  442.                         chan->nextViop = curViop;
  443.                     }
  444.                     chan->queEmpty = TRUE;
  445.                 }                              
  446.                 /* call the channel's callback function */
  447.                 if(curViop != chan->curViop) {
  448.                     if(chan->packetIOM != INV) {
  449.                          /* call the channel's callback function */
  450.                          *(void **)chan->packetIOM->addr = curViop;             
  451.                          chan->packetIOM->size = sizeof(FVID_Frame);
  452.                          chan->cbFxn((Ptr)chan->cbArg, chan->packetIOM);   
  453.                          chan->packetIOM = INV;
  454.                          chan->mrViop = INV;
  455.                     }else if(chan->queEmpty){
  456.                         chan->nextViop = chan->mrViop;
  457.                     }
  458.                 }else {
  459.                     chan->mrViop = INV;
  460.                 }        
  461.                 /* Update the EDMA reload entry  */
  462.                 if(chan->mergeFlds){
  463.                     EDMA_RSETH(chan->hRld[offset], DST, 
  464.                         chan->nextViop->frame.iFrm.y1);
  465.                     EDMA_RSETH(chan->hRld[offset + 1], DST, 
  466.                         chan->nextViop->frame.iFrm.y2);
  467.                     EDMA_RSETH(chan->hRld[4 + offset], DST, 
  468.                         chan->nextViop->frame.iFrm.cb1);     
  469.                     EDMA_RSETH(chan->hRld[5 + offset], DST, 
  470.                         chan->nextViop->frame.iFrm.cb2);                         
  471.                     EDMA_RSETH(chan->hRld[8 + offset], DST, 
  472.                         chan->nextViop->frame.iFrm.cr1);     
  473.                     EDMA_RSETH(chan->hRld[9 + offset], DST, 
  474.                         chan->nextViop->frame.iFrm.cr2);                         
  475.                 }else {
  476.                     EDMA_RSETH(chan->hRld[offset], DST, 
  477.                         chan->nextViop->frame.iFrm.y1);
  478.                     EDMA_RSETH(chan->hRld[offset + 4], DST, 
  479.                         chan->nextViop->frame.iFrm.cb1);
  480.                     EDMA_RSETH(chan->hRld[offset + 8], DST, 
  481.                         chan->nextViop->frame.iFrm.cr1);
  482.                 }/* if(chan->mergeFlds) {*/
  483.             }    
  484.         }
  485.     }
  486. }
  487. /*
  488.  *  ======== _configCh ========
  489.  *  configure video port channel settings
  490.  */
  491. static Int _configCh(
  492.         Ptr                 chanp, 
  493.         VPORTCAP_Params  *params
  494.         )
  495. {
  496.     _VPORT_ChanObj* chan= (_VPORT_ChanObj *)chanp;
  497.     volatile Int vpCtl, vcCtl, fld1Strt, fld2Strt, fld1Stop, fld2Stop;
  498.     volatile Int* base = (volatile Int *)chan->base;                         
  499.     Int retVal = IOM_COMPLETED;
  500.     Int numPixels, numLines, numCPixels;  
  501.     
  502.     
  503.     if(chan->status & _VPORT_OPENED) {
  504.         /* configure channel A capture settings  */
  505.         vcCtl = VP_VCACTL_RMK(0,1,0,params->fldInv, 
  506.             params->extCtl, params->fldDect, params->vCtRst,
  507.             params->hCtRst, 0, params->bpk10Bit, 0, 0, 
  508.             params->resmpl,params->scale,1,
  509.             ((params->fldOp & 4) >> 2), 
  510.             ((params->fldOp & 2) >> 1), 
  511.             (params->fldOp & 1), 
  512.             params->cmode);
  513.         fld1Strt = params->fldXStrt1 + (params->fldYStrt1 << 16);
  514.         fld1Stop = params->fldXStop1 + (params->fldYStop1 << 16);
  515.         fld2Strt = params->fldXStrt2 + (params->fldYStrt2 << 16);
  516.         fld2Stop = params->fldXStop2 + (params->fldYStop2 << 16);
  517.         if(params->fldOp == VPORT_FLDOP_FRAME) {
  518.             assert(params->fldXStop1 == params->fldXStop2);
  519.             assert(params->fldXStrt1 == params->fldXStrt2);
  520.         }   
  521.         base[_VP_VCACTL_OFFSETA]   = vcCtl;
  522.         base[_VP_VCASTRT1_OFFSETA] = fld1Strt;
  523.         base[_VP_VCASTOP1_OFFSETA] = fld1Stop;
  524.         base[_VP_VCASTRT2_OFFSETA] = fld2Strt;
  525.         base[_VP_VCASTOP2_OFFSETA] = fld2Stop;
  526.         numPixels = params->fldXStop1 - params->fldXStrt1 + 1;/* line size */
  527.         numLines = 0;
  528.         
  529.         if(params->fldOp != VPORT_FLDOP_FLD2){
  530.             numLines += params->fldYStop1 - params->fldYStrt1 + 1;
  531.         }
  532.         chan->numLinesFld1 = numLines;
  533.         
  534.         if(params->fldOp == VPORT_FLDOP_FLD2
  535.           || params->fldOp == VPORT_FLDOP_FRAME){
  536.             numLines += params->fldYStop2 - params->fldYStrt2 + 1;
  537.         }
  538.         chan->resmpl = params->resmpl;
  539.         chan->scale = params->scale;
  540.         chan->numLines = numLines;
  541.         numPixels >>= params->scale;
  542.         numCPixels = numPixels >> 1;
  543.         /* set both field1 and field2 threshold to the line size */
  544.         chan->numPixels = numPixels;
  545.         chan->lastLineNum = chan->numLines;        
  546.         if(params->cmode & _VPORT_MASK_10BIT){
  547.             /* 10-bit BT.656 or 20-bit Y/C mode */
  548.             if( params->bpk10Bit == VPORTCAP_BPK_10BIT_ZERO_EXTENDED
  549.              || params->bpk10Bit == VPORTCAP_BPK_10BIT_SIGN_EXTENDED){
  550.                 chan->yPitch = (numPixels * 2 + 7) & (~ 7);
  551.                 chan->cPitch = (numCPixels * 2 + 7) & (~ 7);
  552.             }else {
  553.                 chan->yPitch = (numPixels * 4 / 3 + 7) & (~ 7);
  554.                 chan->cPitch = (numCPixels* 4 / 3 + 7) & (~ 7);
  555.             }
  556.         } else {/* 8-bit BT.656 or 16-bit Y/C mode */
  557.             chan->yPitch = (numPixels + 7) & (~ 7);
  558.             chan->cPitch = (numCPixels + 7) & (~ 7);
  559.         }     
  560.         chan->yThrld = params->thrld;
  561.         if(params->mergeFlds && params->fldOp == VPORT_FLDOP_FRAME) { 
  562.             /* merge field comments */
  563.             /* frame capture and merge 2 fields into one frame */
  564.             /* set threshold is same as line size */
  565.             chan->yThrld = chan->yPitch >> 3;
  566.             chan->numEventsFld1 = chan->numLinesFld1;
  567.             chan->numEvents = chan->numLines;
  568.             chan->mergeFlds = TRUE;  
  569.         }else {            
  570.             assert(((chan->yPitch*chan->numLinesFld1) / (chan->yThrld << 3)) 
  571.                 *(chan->yThrld << 3) == (chan->yPitch * chan->numLinesFld1));
  572.             assert(((chan->yPitch * chan->numLines) / (chan->yThrld << 3)) 
  573.                 *(chan->yThrld << 3) == (chan->yPitch * chan->numLines));
  574.             chan->numEventsFld1 = 
  575.                 chan->yPitch * chan->numLinesFld1 / (chan->yThrld << 3);
  576.             chan->numEvents = 
  577.                 chan->yPitch * chan->numLines / (chan->yThrld << 3);
  578.             chan->mergeFlds = FALSE;
  579.         }            
  580.         chan->cThrld = (chan->yThrld + 1) >> 1;
  581.         base[_VP_VCATHRLD_OFFSETA] = VP_VCATHRLD_RMK(chan->yThrld,chan->yThrld);
  582.         base[_VP_VCAEVTCT_OFFSETA] = VP_VCAEVTCT_RMK(
  583.             (chan->numEvents-chan->numEventsFld1), chan->numEventsFld1 );  
  584.         
  585.         chan->status|=_VPORT_CFGED;
  586.         retVal = IOM_COMPLETED;
  587.     }    
  588.     return retVal;
  589. }
  590. /*
  591.  *  ======== _configChan ========
  592.  *  configure channel settings
  593.  */
  594. static Int _configChan(Ptr chanp, Ptr args)
  595. {
  596.     VPORTCAP_Params*   params = (VPORTCAP_Params*)args; 
  597.     
  598.     
  599.     /* configure video port channel A/B control register */
  600.     _configCh(chanp, params);
  601.     /* configure EDMA and frame buffer */
  602.     _configTransfer(chanp, params);
  603.     return IOM_COMPLETED;
  604. }
  605. /*
  606.  *  ======== _configPort ========
  607.  *  configure port level registers
  608.  */
  609. static Int _configPort(Ptr chanp, Ptr args)
  610. {
  611.     PortObj* port = (PortObj *)chanp;
  612.     volatile Int *base = (volatile Int *)port->base; 
  613.     /* configure video port control register */
  614.     VPORT_PortParams* portParams = (VPORT_PortParams*)args; 
  615.     
  616.     
  617.     /* enable video port */
  618.     base[_VP_PCR_OFFSET] |= VP_PCR_PEREN_ENABLE << _VP_PCR_PEREN_SHIFT;
  619.                 
  620.     /* reset video port */
  621.     base[_VP_VPCTL_OFFSET] |= 
  622.         VP_VPCTL_VPRST_RESET << _VP_VPCTL_VPRST_SHIFT;
  623.     base[_VP_VPCTL_OFFSET] = VP_VPCTL_RMK(0,0,0,portParams->vc3Polarity,
  624.         portParams->vc2Polarity,portParams->vc1Polarity,0,0,
  625.         portParams->dualChanEnable);
  626.     
  627.     /* enable video port */
  628.     base[_VP_VPCTL_OFFSET] |= (VP_VPCTL_VPHLT_CLEAR << _VP_VPCTL_VPHLT_SHIFT);
  629.     port->chanObj[0].edcFxns = portParams->edcTbl[0];
  630.     port->chanObj[1].edcFxns = portParams->edcTbl[1];
  631.     
  632.     IRQ_clear(IRQ_EVT_EDMAINT);
  633.     return IOM_COMPLETED;
  634. }
  635. /*
  636.  *  ======== _configTransfer ========
  637.  *  configure channel EDMA settings
  638.  */
  639. static Int _configTransfer(
  640.         Ptr                 chanp, 
  641.         VPORTCAP_Params  *params
  642.         )
  643. {
  644.     _VPORT_ChanObj* chan = (_VPORT_ChanObj *)chanp;
  645.     Int i;
  646.     EDMA_Config  cfgEdma;
  647.     Int thrld;
  648.     Int8* curAddr;
  649.     
  650.     if(chan->status & _VPORT_CFGED) {
  651.      
  652.         assert(params->numFrmBufs >= 2 && params->numFrmBufs 
  653.                 <= VPORT_MAX_NUM_FRMBUFS);
  654.         QUE_new(&chan->qIn);     
  655.         chan->queEmpty = FALSE;   
  656.         chan->mrViop = INV;
  657.         chan->packetIOM = INV;     
  658.         chan->segId = params->segId;
  659.         
  660.         EDMA_intDisable(chan->tcc[0]);
  661.         EDMA_intDisable(chan->tcc[1]);
  662.         
  663.         if(chan->numFrms == 0) {
  664.             chan->numFrms = params->numFrmBufs;
  665.             /* allocate frame buffer */
  666.             chan->bufSz = chan->yPitch * chan->numLines 
  667.                   + chan->cPitch * chan->numLines * 2;
  668.             for(i = 0; i < chan->numFrms; i ++) {                    
  669.                 if((curAddr = MEM_calloc(params->segId,chan->bufSz, 
  670.                     params->alignment)) == MEM_ILLEGAL){
  671.                     return IOM_EALLOC;
  672.                 }    
  673.                 /* field 1 */
  674.                 chan->viops[i].frame.iFrm.y1 = curAddr;
  675.                 curAddr += chan->numLines*chan->yPitch;
  676.                 chan->viops[i].frame.iFrm.cb1 = curAddr;
  677.                 curAddr += chan->numLines*chan->cPitch;
  678.                 chan->viops[i].frame.iFrm.cr1 = curAddr;
  679.                 curAddr += chan->numLines*chan->cPitch;
  680.                 /* field 2 */    
  681.                 if(params->fldOp == VPORT_FLDOP_FLD2) {
  682.                     chan->viops[i].frame.iFrm.y2 = 
  683.                         chan->viops[i].frame.iFrm.y1;
  684.                     chan->viops[i].frame.iFrm.cb2 = 
  685.                         chan->viops[i].frame.iFrm.cb1;
  686.                     chan->viops[i].frame.iFrm.cr2 = 
  687.                         chan->viops[i].frame.iFrm.cr1;
  688.                 }
  689.                 else if(! chan->mergeFlds) {
  690.                     chan->viops[i].frame.iFrm.y2 = 
  691.                       chan->viops[i].frame.iFrm.y1
  692.                         + chan->numLinesFld1*chan->yPitch;
  693.                     chan->viops[i].frame.iFrm.cb2 = 
  694.                       chan->viops[i].frame.iFrm.cb1
  695.                         + (chan->numLinesFld1*chan->cPitch);
  696.                     chan->viops[i].frame.iFrm.cr2 = 
  697.                       chan->viops[i].frame.iFrm.cr1
  698.                         + (chan->numLinesFld1*chan->cPitch);
  699.                 }else {
  700.                     chan->viops[i].frame.iFrm.y2 = 
  701.                       chan->viops[i].frame.iFrm.y1 + chan->yPitch;
  702.                     chan->viops[i].frame.iFrm.cb2 = 
  703.                       chan->viops[i].frame.iFrm.cb1 + chan->cPitch;
  704.                     chan->viops[i].frame.iFrm.cr2 = 
  705.                       chan->viops[i].frame.iFrm.cr1 + chan->cPitch;            
  706.                 }    
  707.                 if(i > 1) {
  708.                     /* don't put the first 2 viop into the queue */
  709.                     QUE_enqueue(&chan->qIn, (QUE_Handle)&chan->viops[i]);
  710.                 }
  711.             }
  712.         }    
  713.         CACHE_clean(CACHE_L2ALL, 0, 0);
  714.         chan->curViop = &chan->viops[0];
  715.         chan->nextViop = &chan->viops[1]; 
  716.         for(i = 0; i < _VPORT_NUM_EDMA_CHANS; i ++) {
  717.             Int optFld1 = EDMA_OPT_RMK(
  718.                 params->edmaPri,
  719.                 EDMA_OPT_ESIZE_32BIT,
  720.                 EDMA_OPT_2DS_NO,
  721.                 EDMA_OPT_SUM_NONE,
  722.                 EDMA_OPT_2DD_YES,
  723.                 EDMA_OPT_DUM_INC,
  724.                 EDMA_OPT_TCINT_NO,
  725.                 EDMA_OPT_TCC_OF(0), 
  726.                 EDMA_OPT_TCCM_OF(0),
  727.                 EDMA_OPT_ATCINT_NO,    
  728.                 EDMA_OPT_ATCC_DEFAULT,
  729.                 EDMA_OPT_PDTS_DISABLE,
  730.                 EDMA_OPT_PDTD_DISABLE,
  731.                 EDMA_OPT_LINK_YES,
  732.                 EDMA_OPT_FS_NO
  733.             );
  734.     
  735.             Int optFld2a = EDMA_OPT_RMK(
  736.                 params->edmaPri,
  737.                 EDMA_OPT_ESIZE_32BIT,
  738.                 EDMA_OPT_2DS_NO,
  739.                 EDMA_OPT_SUM_NONE,
  740.                 EDMA_OPT_2DD_YES,
  741.                 EDMA_OPT_DUM_INC,
  742.                 (i == 0 ? EDMA_OPT_TCINT_YES:EDMA_OPT_TCINT_NO),
  743.                 EDMA_OPT_TCC_OF(i == 0 ? chan->tcc[0] & 0x0f : 0), 
  744.                 EDMA_OPT_TCCM_OF(i == 0 ? chan->tcc[0] >> 4 : 0),
  745.                 EDMA_OPT_ATCINT_NO,    
  746.                 EDMA_OPT_ATCC_DEFAULT,
  747.                 EDMA_OPT_PDTS_DISABLE,
  748.                 EDMA_OPT_PDTD_DISABLE,
  749.                 EDMA_OPT_LINK_YES,
  750.                 EDMA_OPT_FS_NO
  751.             );
  752.             Int optFld2b = EDMA_OPT_RMK(
  753.                 params->edmaPri,
  754.                 EDMA_OPT_ESIZE_32BIT,
  755.                 EDMA_OPT_2DS_NO,
  756.                 EDMA_OPT_SUM_NONE,
  757.                 EDMA_OPT_2DD_YES,
  758.                 EDMA_OPT_DUM_INC,
  759.                 (i == 0 ? EDMA_OPT_TCINT_YES:EDMA_OPT_TCINT_NO),
  760.                 EDMA_OPT_TCC_OF(i == 0 ? chan->tcc[1] & 0x0f : 0), 
  761.                 EDMA_OPT_TCCM_OF(i == 0 ? chan->tcc[1] >> 4 : 0),
  762.                 EDMA_OPT_ATCINT_NO,    
  763.                 EDMA_OPT_ATCC_DEFAULT,
  764.                 EDMA_OPT_PDTS_DISABLE,
  765.                 EDMA_OPT_PDTD_DISABLE,
  766.                 EDMA_OPT_LINK_YES,
  767.                 EDMA_OPT_FS_NO
  768.             );
  769.             thrld = (i == 0) ? chan->yThrld : chan->cThrld;
  770.             cfgEdma.src = EDMA_SRC_RMK(chan->edmaAddr[i]);
  771.             if(chan->mergeFlds) {
  772.                 /* to merge the two fields together */
  773.                 /* EDMA is configured to transfer only field 1 initially */
  774.                 /* line pitch is twice the line size */
  775.                 /* this requires that the threlhold is the same as line size */
  776.                 
  777.                 /* first field */
  778.                 cfgEdma.cnt = 
  779.                   EDMA_CNT_RMK((chan->numEventsFld1) - 1, (thrld << 1));
  780.                 cfgEdma.idx = EDMA_IDX_RMK(thrld << 4, 0);
  781.     
  782.                 /* hard code the first two frames as current and reload buffers */                
  783.                 /* first field */
  784.                 cfgEdma.rld = EDMA_RLD_RMK(0, chan->hRld[4 * i + 1]);
  785.                 cfgEdma.opt = optFld1;
  786.                 cfgEdma.dst = 
  787.                   EDMA_DST_RMK(*((Int *)(&chan->viops[0].frame.iFrm.y1) + i));
  788.                 EDMA_config(chan->hEdma[i], &cfgEdma);
  789.                 EDMA_config(chan->hRld[4 * i], &cfgEdma); 
  790.                 cfgEdma.dst = 
  791.                   EDMA_DST_RMK(*((Int *)(&chan->viops[1].frame.iFrm.y1) + i));
  792.                 cfgEdma.rld = EDMA_RLD_RMK(0, chan->hRld[4 * i + 3]);
  793.                 EDMA_config(chan->hRld[4 * i + 2], &cfgEdma);
  794.                 /* second field */
  795.                 cfgEdma.opt = optFld2a;
  796.                 cfgEdma.cnt = 
  797.                   EDMA_CNT_RMK((chan->numEvents-chan->numEventsFld1) - 1, 
  798.                    (thrld << 1));
  799.                 cfgEdma.dst = 
  800.                   EDMA_DST_RMK(*((Int *)(&chan->viops[0].frame.iFrm.y2) + i));
  801.                 cfgEdma.rld = EDMA_RLD_RMK(0, chan->hRld[4 * i + 2]);
  802.                 EDMA_config(chan->hRld[4 * i + 1], &cfgEdma); 
  803.                 cfgEdma.opt = optFld2b;
  804.                 cfgEdma.dst = 
  805.                   EDMA_DST_RMK(*((Int *)(&chan->viops[1].frame.iFrm.y2) + i));
  806.                 cfgEdma.rld = EDMA_RLD_RMK(0, chan->hRld[4 * i]);
  807.                 EDMA_config(chan->hRld[4 * i + 3], &cfgEdma);
  808.                 
  809.             }else {/* if fields are not merged, configure EDMA to transfer */
  810.                    /* for both field1 and field 2                          */
  811.                    /* the line pitch is just the line size                 */
  812.                 cfgEdma.opt = optFld2a;
  813.                 cfgEdma.cnt = EDMA_CNT_RMK((chan->numEvents) - 1, (thrld << 1));
  814.                 cfgEdma.idx = EDMA_IDX_RMK(thrld << 3, 0);
  815.                 cfgEdma.rld = EDMA_RLD_RMK(0, chan->hRld[4 * i + 2]);
  816.                 /* hard code the first and second frame buffer as current  */
  817.                 /* and reload buffers */
  818.                 cfgEdma.dst = EDMA_DST_RMK(
  819.                     *((Int *)(&chan->viops[0].frame.iFrm.y1) + i));
  820.                 EDMA_config(chan->hEdma[i], &cfgEdma);
  821.                 EDMA_config(chan->hRld[4 * i], &cfgEdma);
  822.                 cfgEdma.opt = optFld2b;
  823.                 cfgEdma.rld = EDMA_RLD_RMK(0, chan->hRld[4 * i]);
  824.                 cfgEdma.dst = EDMA_DST_RMK(
  825.                     *((Int *)(&chan->viops[1].frame.iFrm.y1) + i));
  826.                 EDMA_config(chan->hRld[4 * i + 2], &cfgEdma);
  827.             }
  828.         }
  829.         chan->nextEDMARlds = 1;        
  830.         /* enable EDMA channel */
  831.         /*
  832.          * The EDMA interrupt dispatcher will be called by the
  833.          * BIOS HWI interrupt dispatcher.
  834.          */
  835.         IRQ_map(IRQ_EVT_EDMAINT, params->irqId);
  836.         HWI_dispatchPlug(params->irqId, (Fxn)EDMA_intDispatcher, -1, NULL);
  837.         
  838.         EDMA_intClear(chan->tcc[0]);
  839.         EDMA_intHook(chan->tcc[0], captureEdmaISR);       
  840.         EDMA_intEnable(chan->tcc[0]);
  841.         EDMA_intClear(chan->tcc[1]);
  842.         EDMA_intHook(chan->tcc[1], captureEdmaISR);       
  843.         EDMA_intEnable(chan->tcc[1]);
  844.         for(i = 0; i < _VPORT_NUM_EDMA_CHANS; i ++) {
  845.             EDMA_disableChannel(chan->hEdma[i]);
  846.             EDMA_clearChannel(chan->hEdma[i]);
  847.             EDMA_enableChannel(chan->hEdma[i]);
  848.         }    
  849.         chan->status |= _VPORT_READY;
  850.         IRQ_enable(IRQ_EVT_EDMAINT);
  851.         
  852.     }   
  853.     return IOM_COMPLETED;
  854. }
  855. /*
  856.  *  ======== _covrRecover ========
  857.  *  force recover from FIFO over-run
  858.  */
  859. static Int _covrRecover(Ptr chanp)
  860. {
  861.     _VPORT_ChanObj* chan = (_VPORT_ChanObj* )chanp;
  862.     PortObj* port = &portObjs[chan->portNum];
  863.     volatile Int *base = (volatile Int *)port->base;
  864.     volatile Int *cbase = (volatile Int *)chan->base;    
  865.     Int numEvents;
  866.     volatile Int i;                                            
  867.     
  868.     
  869.     /* disable over-run interrupt */
  870.     base[_VP_VPIE_OFFSET] &= ~(_VP_VPIE_COVRA_MASK<<(chan->chanNum*16));
  871.     /* block capture events */
  872.     cbase[_VP_VCACTL_OFFSETA] |= _VP_VCACTL_BLKCAP_MASK;
  873.     /* Disable the edmas before settings them up */
  874.     EDMA_intDisable(chan->tcc[0]);
  875.     EDMA_intDisable(chan->tcc[1]);
  876.     for(i = 0; i < _VPORT_NUM_EDMA_CHANS; i ++) {
  877.         EDMA_disableChannel(chan->hEdma[i]);
  878.         EDMA_clearChannel(chan->hEdma[i]);
  879.     }
  880.     if(chan->mergeFlds) {
  881.         numEvents = chan->numEventsFld1;        
  882.     } else {
  883.         numEvents = chan->numEvents;
  884.     }
  885.     /* set up DMA parameters again */
  886.     EDMA_RSETH(chan->hEdma[0], DST, chan->curViop->frame.iFrm.y1);
  887.     EDMA_RSETH(chan->hEdma[1], DST, chan->curViop->frame.iFrm.cb1);
  888.     EDMA_RSETH(chan->hEdma[2], DST, chan->curViop->frame.iFrm.cr1);
  889.     EDMA_RSETH(chan->hEdma[0], CNT, EDMA_CNT_RMK(numEvents - 1, 
  890.         (chan->yThrld << 1)));
  891.     EDMA_RSETH(chan->hEdma[1], CNT, EDMA_CNT_RMK(numEvents - 1, 
  892.         (chan->cThrld << 1)));
  893.     EDMA_RSETH(chan->hEdma[2], CNT, EDMA_CNT_RMK(numEvents - 1, 
  894.         (chan->cThrld<<1)));
  895.     /* enable the edma events again before settings them up */
  896.     EDMA_intEnable(chan->tcc[0]);
  897.     EDMA_intEnable(chan->tcc[1]);
  898.     for(i = 0;i < 3;i ++) {
  899.         EDMA_enableChannel(chan->hEdma[i]);
  900.     }
  901.     /* delay */
  902.     for(i = 0; i < 100000; i ++);
  903.     /* clear any pending over-run interrupt */
  904.     if(chan->chanNum == 0) {
  905.         base[_VP_VPIS_OFFSET] |= _VP_VPIS_COVRA_MASK;
  906.     }else {
  907.         base[_VP_VPIS_OFFSET] |= _VP_VPIS_COVRB_MASK;
  908.     }    
  909.     /* enable event generation */
  910.     cbase[_VP_VCACTL_OFFSETA] &= ~(_VP_VCACTL_BLKCAP_MASK);
  911.     /* enable over-run interrupt */
  912.     base[_VP_VPIE_OFFSET] |= _VP_VPIE_COVRA_MASK << (chan->chanNum * 16);
  913.     return IOM_COMPLETED;
  914. }
  915. /*
  916.  *  ======== _setVIntCb ========
  917.  *  setup video port interrupt call-back
  918.  */
  919. static Int _setVIntCb(Ptr chanp, Ptr args)
  920. {      
  921.     _VPORT_ChanObj* chan = (_VPORT_ChanObj* )chanp;
  922.     PortObj* port = &portObjs[chan->portNum];
  923.     volatile Int *base = (volatile Int *)port->base;
  924.     volatile Int *cBase = (volatile Int *)chan->base;
  925.     VPORT_VIntCbParams* vIntCbParams = (void *)args;
  926.     Int mask = vIntCbParams->vIntMask;
  927.     Uns vif2 = 0, vInt2 = 0, vif1 = 0, vInt1 = 0, fscl2 = 0;
  928.     
  929.     
  930.     /* check to see if vertical interrupt is enabled */
  931.     if(mask & VPORT_INT_VINT1) {
  932.         vif1 = 1;
  933.         vInt1 = vIntCbParams->vIntLine;
  934.     }
  935.     if(mask & VPORT_INT_VINT2) {
  936.         vif2 = 1;
  937.         vInt2 = vIntCbParams->vIntLine;    
  938.     }
  939.     fscl2 = vif2 & (~ vif1);
  940.     /* setup vertical interrupt */
  941.     cBase[_VP_VCAVINT_OFFSETA] = VP_VCAVINT_RMK(vif2,fscl2, 
  942.         vInt2, vif1, vInt1);
  943.     
  944.     if(chan->chanNum == 1) {
  945.         mask <<= 16;    /* channel B */
  946.     }
  947.     chan->vIntMask = mask;
  948.     if(mask) {
  949.         mask |= 1; /* turn on video port interrupt */
  950.         IRQ_map(IRQ_EVT_VINT0 + chan->portNum, vIntCbParams->irqId);    
  951.         HWI_dispatchPlug(vIntCbParams->irqId, (Fxn)captureISR, -1, NULL);
  952.         IRQ_disable(IRQ_EVT_VINT0 + chan->portNum);
  953.         IRQ_clear(IRQ_EVT_VINT0 + chan->portNum);
  954.     }
  955.     base[_VP_VPIE_OFFSET] |= mask;  /* register write */    
  956.     chan->vIntFxn = vIntCbParams->vIntCbFxn;    
  957.     chan->vIntCbArg = vIntCbParams->cbArg;
  958.     return IOM_COMPLETED;   
  959. }      
  960. static void _delay(Int delayTime)
  961. {
  962.     asm("loop1: BDEC loop1, A4");
  963.     asm(" NOP 5");
  964. }
  965. /*
  966.  *  ======== _startVPCapture ========
  967.  *  start video port capture operation
  968.  */
  969. static Int _startVPCapture(Ptr chanp)
  970. {
  971.     _VPORT_ChanObj* chan = (_VPORT_ChanObj* )chanp;
  972.     PortObj* port = &portObjs[chan->portNum];
  973.     volatile Int *base = (volatile Int *)port->base;
  974.     volatile Int *cbase = (volatile Int *)chan->base;    
  975.     /* enable channel */
  976.     cbase[_VP_VCACTL_OFFSETA] |= VP_VCACTL_VCEN_ENABLE << _VP_VCACTL_VCEN_SHIFT;
  977.     _delay(20000000);
  978.     /* clear the block capture event mask bit to enable */
  979.     /* generating capture events                        */
  980.     cbase[_VP_VCACTL_OFFSETA] &= ~ (_VP_VCACTL_BLKCAP_MASK);
  981.     /* enable interrupt generation in video port level */
  982.     base[_VP_VPIE_OFFSET] |= VP_VPIE_VIE_ENABLE << _VP_VPIE_VIE_SHIFT;
  983.     base[_VP_VPIS_OFFSET] |= 0XFFFFFFFF;
  984.     /* clear any pending video port interrupt */
  985.     IRQ_clear(IRQ_EVT_VINT0 + chan->portNum);
  986.     /* enable corresponding video port interrupt in chip-level*/
  987.     IRQ_enable(IRQ_EVT_VINT0 + chan->portNum);
  988.     
  989.     return IOM_COMPLETED;
  990. }
  991. /*
  992.  *  ======== _stopVPCapture ========
  993.  *  stop video port capture operation
  994.  */
  995. static Int _stopVPCapture(Ptr chanp)
  996. {
  997.     _VPORT_ChanObj* chan = (_VPORT_ChanObj* )chanp;
  998.     PortObj* port = &portObjs[chan->portNum];
  999.     volatile Int *cbase = (volatile Int *)chan->base;    
  1000.     volatile Int *base = (volatile Int *)port->base;
  1001.     /* block events generation */
  1002.     cbase[_VP_VCACTL_OFFSETA] &= (_VP_VCACTL_BLKCAP_MASK);
  1003.     /* disable channel */
  1004.     cbase[_VP_VCACTL_OFFSETA] &= 
  1005.         ~ (VP_VCACTL_VCEN_ENABLE << _VP_VCACTL_VCEN_SHIFT);
  1006.     /* disable interrupt generation in video port level */
  1007.     base[_VP_VPIE_OFFSET] &= ~ (VP_VPIE_VIE_ENABLE << _VP_VPIE_VIE_SHIFT);
  1008.     base[_VP_VPIS_OFFSET] |= 0XFFFFFFFF;
  1009.     
  1010.     /* disble corresponding video port interrupt in chip-level*/
  1011.     IRQ_disable(IRQ_EVT_VINT0 + chan->portNum);
  1012.     /* clear any pending video port interrupt */
  1013.     IRQ_clear(IRQ_EVT_VINT0 + chan->portNum);
  1014.     
  1015.     EDMA_intDisable(chan->tcc[0]);
  1016.     EDMA_intClear(chan->tcc[0]);
  1017.     EDMA_intDisable(chan->tcc[1]);
  1018.     EDMA_intClear(chan->tcc[1]);
  1019.     return IOM_COMPLETED;
  1020. }
  1021. /*
  1022.  *  ======== captureISR ========
  1023.  */
  1024. static void captureISR(Int portNum)
  1025. {
  1026.     volatile Int *base =  
  1027.         (volatile Int *)portObjs[portNum].base;
  1028.     Int vpis = base[_VP_VPIS_OFFSET];
  1029.     Int mask = vpis;
  1030.     _VPORT_ChanObj* chanObjs = portObjs[portNum].chanObj;
  1031.         
  1032.     if(vpis & chanObjs[0].vIntMask && chanObjs[0].vIntFxn != INV) {
  1033.         chanObjs[0].vIntFxn(chanObjs[0].vIntCbArg, vpis);
  1034.         mask &=  chanObjs[0].vIntMask;
  1035.     }else if(vpis & chanObjs[1].vIntMask && chanObjs[1].vIntFxn != INV) {
  1036.         chanObjs[1].vIntFxn(chanObjs[1].vIntCbArg, (vpis >> 16));
  1037.         mask &=  chanObjs[1].vIntMask;
  1038.     }
  1039.     /* clear interrupts that has been handled */
  1040.     base[_VP_VPIS_OFFSET] |= mask;
  1041. }