?? vportcap.c
字號:
/*
* Copyright 2004 by Texas Instruments Incorporated.
* All rights reserved. Property of Texas Instruments Incorporated.
* Restricted rights to use, duplicate or disclose this code are
* granted through contract.
*
*/
/* August 2004 */
/**************************************************************************/
/* vportcap.c file */
/**************************************************************************/
/* DSP/BIOS standard include files */
#include <std.h>
#include <mem.h>
#include <que.h>
#include <tsk.h>
#include <hwi.h>
#include <clk.h>
/* Chip-support library include files */
#include <csl.h>
#include <csl_edma.h>
#include <csl_vphal.h>
#include <csl_irq.h>
#include <csl_cache.h>
/* IOM/GIO driver model include files */
#include <iom.h>
#include <fvid.h>
/* video driver specific include files */
#include <vport.h>
#include <vportcap.h>
#include <edc.h>
#include "_vport.h"
/* debug include files */
/* to minimize code size and cycle count overhead of the driver */
/* error checking is only performed at debug time */
#include <assert.h>
/* type defines and data structures */
/**************************************************************
* data structure for video port object *
**************************************************************/
typedef struct PortObj{
/* port status register, contains information on whether */
/* port is opened, configured, etc. */
Int status;
/* vp base address for all register access */
Int base;
/* two channel objects for channel A & B. */
/* This is only for capture operation */
_VPORT_ChanObj chanObj[2];
} PortObj;
/* mini-driver API functions */
static Int mdBindDev(Ptr *devp, Int devid, Ptr devParams);
static Int mdControlChan(Ptr chanp, Uns cmd, Ptr args);
static Int mdCreateChan(Ptr *chanp, Ptr devp, String name, Int mode,
Ptr chanParams, IOM_TiomCallback cbFxn, Ptr cbArg);
static Int mdDeleteChan(Ptr chanp);
static Int mdSubmitChan(Ptr chanp, IOM_Packet *packet);
/* local functions */
static void captureEdmaISR(Int tcc);
static void captureISR(Int portNum);
static Int _configCh(Ptr chanp, VPORTCAP_Params *params);
static Int _configChan(Ptr chanp, Ptr args);
static Int _configPort(Ptr chanp, Ptr args);
static Int _configTransfer(Ptr chanp,VPORTCAP_Params *params);
static Int _covrRecover(Ptr chanp);
static Int _setVIntCb(Ptr chanp, Ptr args);
static Int _startVPCapture(Ptr chanp);
static Int _stopVPCapture(Ptr chanp);
static void _delay(Int delayTime);
static void _autoSync(_VPORT_ChanObj* chan);
static Int _getNumPendingIORqsts(Ptr chanp, Ptr args);
/* global and static variables */
IOM_Fxns VPORTCAP_Fxns = {
mdBindDev,
(IOM_TmdUnBindDev)IOM_mdNotImpl,
mdControlChan,
mdCreateChan,
mdDeleteChan,
mdSubmitChan
};
/**************************************************************
* Static allocation and initialization of port objects *
**************************************************************/
static PortObj portObjs[_VP_PORT_CNT] = {
/* video port 0 */
{0, _VP_BASE_PORT0,
/* channel A */
{{0, 0, 0, _VP_BASE_CHAPORT0, EDMA_CHA_VP0EVTYA, EDMA_CHA_VP0EVTUA,
EDMA_CHA_VP0EVTVA, _VP_YSRCA0_ADDR, _VP_CBSRCA0_ADDR,
_VP_CRSRCA0_ADDR },
/* channel B */
{0, 0, 1, _VP_BASE_CHBPORT0, EDMA_CHA_VP0EVTYB, EDMA_CHA_VP0EVTUB,
EDMA_CHA_VP0EVTVB, _VP_YSRCB0_ADDR, _VP_CBSRCB0_ADDR,
_VP_CRSRCB0_ADDR}}},
/* video port 1 */
{0, _VP_BASE_PORT1,
/* channel A */
{{0, 1, 0, _VP_BASE_CHAPORT1, EDMA_CHA_VP1EVTYA, EDMA_CHA_VP1EVTUA,
EDMA_CHA_VP1EVTVA, _VP_YSRCA1_ADDR, _VP_CBSRCA1_ADDR,
_VP_CRSRCA1_ADDR },
/* channel B */
{0, 1, 1, _VP_BASE_CHBPORT1, EDMA_CHA_VP1EVTYB, EDMA_CHA_VP1EVTUB,
EDMA_CHA_VP1EVTVB, _VP_YSRCB1_ADDR, _VP_CBSRCB1_ADDR,
_VP_CRSRCB1_ADDR}}},
/* video port 2 */
{0, _VP_BASE_PORT2,
/* channel A */
{{0, 2, 0, _VP_BASE_CHAPORT2, EDMA_CHA_VP2EVTYA, EDMA_CHA_VP2EVTUA,
EDMA_CHA_VP2EVTVA, _VP_YSRCA2_ADDR, _VP_CBSRCA2_ADDR,
_VP_CRSRCA2_ADDR },
/* channel B */
{0, 2, 1, _VP_BASE_CHBPORT2, EDMA_CHA_VP2EVTYB, EDMA_CHA_VP2EVTUB,
EDMA_CHA_VP2EVTVB, _VP_YSRCB2_ADDR, _VP_CBSRCB2_ADDR,
_VP_CRSRCB2_ADDR }}}
};
/*
* =================== mdBindDev ============================
* Register all external devices to video port capture driver
*/
static Int mdBindDev(Ptr *devp, Int devid, Ptr devParams)
{
Int portNum = devid;
volatile Int i;
volatile Int* base = (volatile Int *)portObjs[portNum].base;
assert(portNum < _VP_PORT_CNT);
base[_VP_VPCTL_OFFSET] =
VP_VPCTL_VPRST_RESET << _VP_VPCTL_VPRST_SHIFT;
for(i = 0; i < 100000; i ++);
*devp = &portObjs[portNum];
return mdControlChan(&portObjs[portNum], VPORT_CMD_CONFIG_PORT, devParams);
}
/*
* ======== mdControlChan ========
*/
static Int mdControlChan(Ptr chanp, Uns cmd, Ptr args)
{
Int retVal = IOM_EBADMODE;
_VPORT_ChanObj* chan = (_VPORT_ChanObj* )chanp;
switch (cmd) {
case VPORT_CMD_START:
retVal = _startVPCapture(chanp);
break;
case VPORT_CMD_STOP:
retVal = _stopVPCapture(chanp);
break;
case VPORT_CMD_SET_VINTCB:
retVal = _setVIntCb(chanp, args);
break;
case VPORT_CMD_CONFIG_PORT:
retVal = _configPort(chanp, args);
break;
case VPORT_CMD_COVR_RECOVER:
retVal = _covrRecover(chanp);
break;
case VPORT_CMD_CONFIG_CHAN:
retVal = _configChan(chanp, args);
break;
case VPORT_CMD_GET_NUM_IORQST_PENDING:
retVal = _getNumPendingIORqsts(chanp, args);
break;
default:
if(chan->edcFxns!=INV){
retVal = chan->edcFxns->ctrl(chan->edcHandle,
cmd-VPORT_CMD_EDC_BASE,(Arg)args);
}else {
retVal = IOM_ENOTIMPL;
}
break;
}
return retVal;
}
/*
* =================== mdCreateChan ============================
* create a capture channel
*/
static Int mdCreateChan(Ptr *chanp, Ptr devp, String name, Int mode,
Ptr chanParams, IOM_TiomCallback cbFxn, Ptr cbArg)
{
Int chanNum;
volatile Int* base;
PortObj* port;
Int retVal = IOM_COMPLETED;
if(mode != IOM_INPUT){
return IOM_EBADARGS;
}
if(*name ++ != '/') {
return IOM_EBADARGS;
}
chanNum = *name ++ - 'A';
assert(chanNum < _VPORT_CHAN_CNT);
port = (PortObj *)devp;
if(port->chanObj[chanNum].edcFxns != INV) {
/* open external device */
port->chanObj[chanNum].edcHandle
= port->chanObj[chanNum].edcFxns->open(name, (Arg)INV);
}
if(! (port->status & _VPORT_OPENED)) {
port->status |= _VPORT_OPENED;
base = (volatile Int *)port->base;
/* reset both channels */
base[_VP_VCACTL_OFFSET] |=
VP_VCACTL_RSTCH_RESET << _VP_VCACTL_RSTCH_SHIFT;
base[_VP_VCBCTL_OFFSET] |=
VP_VCBCTL_RSTCH_RESET << _VP_VCBCTL_RSTCH_SHIFT;
} /* if(!port->opened) */
/* initialize the channel object */
if(! (port->chanObj[chanNum].status & _VPORT_OPENED)) {
Int j;
_VPORT_ChanObj *chan = &port->chanObj[chanNum];
chan->status |= _VPORT_OPENED;
chan->cbFxn = cbFxn;
chan->cbArg = (Arg)cbArg;
chan->numFrms = 0;
for(j = 0; j < _VPORT_NUM_EDMA_CHANS && retVal == IOM_COMPLETED; j ++){
if( (chan->hEdma[j] = EDMA_open(chan->edmaChanNum[j],
EDMA_OPEN_RESET))==EDMA_HINV
|| (chan->hRld[4 * j] = EDMA_allocTable(-1))==EDMA_HINV
|| (chan->hRld[4 * j + 1] = EDMA_allocTable(-1))==EDMA_HINV
|| (chan->hRld[4 * j + 2] = EDMA_allocTable(-1))==EDMA_HINV
|| (chan->hRld[4 * j + 3] = EDMA_allocTable(-1))==EDMA_HINV
|| (chan->tcc[j] = EDMA_intAlloc(chan->edmaChanNum[j])) == -1){
retVal = IOM_EALLOC;
}/* if((port->...*/
}/* for(j = 0; j < NUM_EDMA_CHANS; j++) {...*/
if( retVal == IOM_COMPLETED && (void *)chanParams != INV) {
retVal = mdControlChan(&port->chanObj[chanNum],
VPORT_CMD_CONFIG_CHAN, chanParams);
}
if(retVal == IOM_COMPLETED) {
/* configure the channel */
*chanp = &port->chanObj[chanNum];
}else {
mdDeleteChan(&port->chanObj);
*chanp = INV;
}
} /*if(!chan->opened) */
return retVal;
}
/*
* =================== mdDeleteChan ============================
* delete the capture channel
*/
static Int mdDeleteChan(Ptr chanp)
{
_VPORT_ChanObj* chan = (_VPORT_ChanObj* )chanp;
PortObj* port = &portObjs[chan->portNum];
Int j;
if(chan->status & _VPORT_OPENED) {
chan->status = 0;
mdControlChan(chanp, VPORT_CMD_STOP, NULL);
for(j = 0; j < _VPORT_NUM_EDMA_CHANS; j ++) {
EDMA_disableChannel(chan->hEdma[j]);
EDMA_clearChannel(chan->hEdma[j]);
EDMA_close(chan->hEdma[j]);
EDMA_freeTable(chan->hRld[4 * j]);
EDMA_freeTable(chan->hRld[4 * j + 1]);
EDMA_freeTable(chan->hRld[4 * j + 2]);
EDMA_freeTable(chan->hRld[4 * j + 3]);
EDMA_intFree(chan->tcc[j]);
}
for(j = 0; j < chan->numFrms ; j ++) {
MEM_free(chan->segId, chan->viops[j].frame.iFrm.y1, chan->bufSz);
}
/* close external device */
if(chan->edcFxns != INV) {
chan->edcFxns->close(chan->edcHandle);
}
}
if(! (port->chanObj[0].status & _VPORT_OPENED)
&& ! (port->chanObj[1].status & _VPORT_OPENED)) {
port->status = 0;
}
return IOM_COMPLETED;
}
/*
* ======== mdSubmitChan ========
*/
static Int mdSubmitChan(Ptr chanp, IOM_Packet *packet)
{
_VPORT_ChanObj* chan = (_VPORT_ChanObj *)chanp;
FVID_Frame* viop;
Uint32 gie = IRQ_globalDisable();
Int retVal = IOM_PENDING;
Int offset = chan->nextEDMARlds << 1;
Bool nextViopChanged = FALSE;
Bool notToLate = TRUE;
volatile Int* cBase = (volatile Int *)chan->base;
Int capStatReg = cBase[_VP_VCASTAT_OFFSETA];
short lineNum;
/* get the current line number being captured */
lineNum = (capStatReg & _VP_VCASTAT_VCYPOS_MASK)
>> _VP_VCASTAT_VCYPOS_SHIFT;
/* account for field/frame operation modes */
lineNum += chan->numLinesFld1
* ((capStatReg & _VP_VCASTAT_VCFLD_MASK) >> _VP_VCASTAT_VCFLD_SHIFT);
/* make sure we are not too close to the end of a frame */
notToLate = (lineNum < (chan->lastLineNum - 5));
assert(chan->status & _VPORT_READY);
if(packet->cmd != FVID_ALLOC
&& packet->cmd != FVID_FREE
&& packet->cmd != FVID_EXCHANGE){
/* other commands not supported */
return IOM_ENOTIMPL;
}
if(packet->cmd != FVID_ALLOC) {/* FVID_FREE or FVID_EXCHANGE */
viop = *(void **)packet->addr; /* pointer of a video I/O packet */
if(chan->queEmpty && notToLate) {
/* don't put it into queue, update the rld register directly */
chan->nextViop = viop;
nextViopChanged = TRUE;
}
else {
QUE_enqueue(&chan->qIn, (QUE_Handle)viop);
}
chan->queEmpty = FALSE;
retVal = packet->status = IOM_COMPLETED;
}
if(packet->cmd != FVID_FREE) {/* FVID_ALLOC or FVID_EXCHANGE */
if(chan->mrViop != INV) {
/* only when there is no outstanding pending request */
if(chan->packetIOM == INV){
if(chan->nextViop != chan->mrViop){
*(void **)packet->addr = (void *)chan->mrViop;
chan->mrViop = INV;
packet->size = sizeof(FVID_Frame);
retVal = packet->status = IOM_COMPLETED;
} else {
if (notToLate) {
*(void **)packet->addr = (void *)chan->mrViop;
chan->mrViop = INV;
packet->size = sizeof(FVID_Frame);
retVal = packet->status = IOM_COMPLETED;
/* If queue is already empty, it means the driver currently*/
/* only owns one frame, which is the current frame. So make*/
/* the next frame the same as the current one */
chan->nextViop = chan->curViop;
} else {
chan->mrViop = INV; /* too late, just recycle the mrViop */
chan->packetIOM = packet;
retVal = packet->status = IOM_PENDING;
}
}
}
else retVal = IOM_EINUSE;
} else {
chan->packetIOM = packet;
retVal = packet->status = IOM_PENDING;
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -