📄 copy of vportcap.c
字号:
/*
* ======== mdSubmitChan ========
*/
static Int mdSubmitChan(Ptr chanp, IOM_Packet *packet)
{
_VPORT_ChanObj *pChan = (_VPORT_ChanObj*)chanp;
FVID_Frame *viop;
Uint32 gie = IRQ_globalDisable();
Int retVal = IOM_PENDING;
Int offset = pChan->nextEDMARlds << 1;
Bool nextViopChanged = FALSE;
Bool notTooLate = TRUE;
volatile Int *chBase = (volatile Int*)pChan->base;
Int capStatReg;
volatile Int* base = (volatile Int *)gsPortObjs[pChan->portNum].base;
Int vpis = base[_VP_VPIS_OFFSET];
short lineNum;
if (pChan->chanNum == 0)
{ /*channel A*/
capStatReg = chBase[_VP_VCASTAT_OFFSETA];
/* get the current line number being captured */
lineNum = (capStatReg & _VP_VCASTAT_VCYPOS_MASK)
>> _VP_VCASTAT_VCYPOS_SHIFT;
/* account for field/frame operation modes */
lineNum += pChan->numLinesFld1
* ((capStatReg & _VP_VCASTAT_VCFLD_MASK) >> _VP_VCASTAT_VCFLD_SHIFT);
}
else if (pChan->chanNum == 1)
{ /*channel B*/
capStatReg = chBase[_VP_VCBSTAT_OFFSETB];
/* get the current line number being captured */
lineNum = (capStatReg & _VP_VCBSTAT_VCYPOS_MASK)
>> _VP_VCBSTAT_VCYPOS_SHIFT;
/* account for field/frame operation modes */
lineNum += pChan->numLinesFld1
* ((capStatReg & _VP_VCBSTAT_VCFLD_MASK) >> _VP_VCBSTAT_VCFLD_SHIFT);
}
/* make sure we are not too close to the end of a frame */
notTooLate = (lineNum < (pChan->lastLineNum - 5));
if (!(pChan->status & _VPORT_READY))
{
assert(pChan->status & _VPORT_READY);
}
if (packet->cmd != FVID_ALLOC && packet->cmd != FVID_FREE && packet->cmd != FVID_EXCHANGE)
{
IRQ_globalRestore(gie);
/* 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 (pChan->queEmpty && notTooLate)
{
/* don't put it into queue, update the rld register directly */
pChan->nextViop = viop;
nextViopChanged = TRUE;
}
else
{
QUE_enqueue(&pChan->qIn, (QUE_Handle)viop);
}
pChan->queEmpty = FALSE;
retVal = packet->status = IOM_COMPLETED;
}
if (packet->cmd != FVID_FREE)
{/* FVID_ALLOC or FVID_EXCHANGE */
if (pChan->mrViop != INV)
{
/* only when there is no outstanding pending request */
if (pChan->packetIOM == INV)
{
if (pChan->nextViop != pChan->mrViop)
{
*(void**)packet->addr = (void*)pChan->mrViop;
pChan->mrViop = INV;
packet->size = sizeof(FVID_Frame);
retVal = packet->status = IOM_COMPLETED;
}
else
{
if (notTooLate)
{
*(void**)packet->addr = (void*)pChan->mrViop;
pChan->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 */
pChan->nextViop = pChan->curViop;
}
else
{
pChan->mrViop = INV; /* too late, just recycle the mrViop */
pChan->packetIOM = packet;
retVal = packet->status = IOM_PENDING;
}
}
}
else
retVal = IOM_EINUSE;
}
else
{
pChan->packetIOM = packet;
retVal = packet->status = IOM_PENDING;
}
}
if (nextViopChanged)
{
/* now modify the EDMA rld entries */
if(pChan->mergeFlds)
{
EDMA_RSETH(pChan->hRld[offset], DST,
pChan->nextViop->frame.iFrm.y1);
EDMA_RSETH(pChan->hRld[offset + 1], DST,
pChan->nextViop->frame.iFrm.y2);
EDMA_RSETH(pChan->hRld[4 + offset], DST,
pChan->nextViop->frame.iFrm.cb1);
EDMA_RSETH(pChan->hRld[5 + offset], DST,
pChan->nextViop->frame.iFrm.cb2);
EDMA_RSETH(pChan->hRld[8 + offset], DST,
pChan->nextViop->frame.iFrm.cr1);
EDMA_RSETH(pChan->hRld[9 + offset], DST,
pChan->nextViop->frame.iFrm.cr2);
}
else
{
EDMA_RSETH(pChan->hRld[offset], DST,
pChan->nextViop->frame.iFrm.y1);
EDMA_RSETH(pChan->hRld[4 + offset], DST,
pChan->nextViop->frame.iFrm.cb1);
EDMA_RSETH(pChan->hRld[8 + offset], DST,
pChan->nextViop->frame.iFrm.cr1);
} /* if(pChan->mergeFlds) */
}
if (vpis & 0x40)
{/* short field detected, re-sync */
_covrRecover(chanp);
}
IRQ_globalRestore(gie);
return retVal;
}
/*
* ======== _captureEdmaISR ========
* EDMA ISR
*/
static void captureEdmaISR(Int tcc)
{
Int i, j;
Int offset;
FVID_Frame *viop, *curViop;
/* find out the source of the edma interrupt */
for (j = 0; j < _VP_PORT_CNT; j ++)
{ /*_VP_PORT_CNT = 3*/
for (i = 0; i < _VPORT_CHAN_CNT; i ++ )
{ /* _VPORT_CHAN_CNT = 2 defined in _vport.h, loop through two channels */
_VPORT_ChanObj *pChan = &gsPortObjs[j].chanObj[i];
if ((pChan->status & _VPORT_READY) && (tcc == pChan->tcc[0] || tcc == pChan->tcc[1]))
{
if (pChan->autoSyncEnable)
{
_autoSync(pChan);
}
/* re-sync tcc with activeEDMARlds */
/* they may be out of sync after interrupt over-run */
/* e.g. execution is halted at break-point */
pChan->nextEDMARlds = (tcc == pChan->tcc[0]) ? 0 : 1;
offset = pChan->nextEDMARlds << 1;
/* update the current and next viop pointers */
curViop = pChan->curViop;
pChan->curViop = pChan->nextViop;
/* update the most recent viop */
if (curViop != pChan->mrViop && pChan->mrViop != INV)
{
QUE_enqueue(&pChan->qIn, pChan->mrViop);
}
pChan->mrViop = curViop;
if ((viop = (FVID_Frame*)QUE_dequeue(&pChan->qIn))
!= (FVID_Frame*)&pChan->qIn)
{
/* queue IS not empty */
pChan->nextViop = viop;
}
else
{
if(pChan->packetIOM == INV)
{
/* in queue is empty, but no request is pending */
/* recycle the current VIOP back */
/* but still set it as the most recent VIOP */
pChan->nextViop = curViop;
}
pChan->queEmpty = TRUE;
}
/* call the channel's callback function */
if (curViop != pChan->curViop)
{
if (pChan->packetIOM != INV)
{
/* call the channel's callback function */
*(void **)pChan->packetIOM->addr = curViop;
pChan->packetIOM->size = sizeof(FVID_Frame);
pChan->cbFxn((Ptr)pChan->cbArg, pChan->packetIOM);
pChan->packetIOM = INV;
pChan->mrViop = INV;
}
else if(pChan->queEmpty)
{
pChan->nextViop = pChan->mrViop;
}
}
else
{
pChan->mrViop = INV;
}
/* Update the EDMA reload entry */
if (pChan->mergeFlds)
{
EDMA_RSETH(pChan->hRld[offset], DST,
pChan->nextViop->frame.iFrm.y1);
EDMA_RSETH(pChan->hRld[offset + 1], DST,
pChan->nextViop->frame.iFrm.y2);
EDMA_RSETH(pChan->hRld[offset + 4], DST,
pChan->nextViop->frame.iFrm.cb1);
EDMA_RSETH(pChan->hRld[offset + 5], DST,
pChan->nextViop->frame.iFrm.cb2);
EDMA_RSETH(pChan->hRld[offset + 8], DST,
pChan->nextViop->frame.iFrm.cr1);
EDMA_RSETH(pChan->hRld[offset + 9], DST,
pChan->nextViop->frame.iFrm.cr2);
}
else
{
EDMA_RSETH(pChan->hRld[offset], DST,
pChan->nextViop->frame.iFrm.y1);
EDMA_RSETH(pChan->hRld[offset + 4], DST,
pChan->nextViop->frame.iFrm.cb1);
EDMA_RSETH(pChan->hRld[offset + 8], DST,
pChan->nextViop->frame.iFrm.cr1);
}/* if(pChan->mergeFlds) {*/
}
}
}
}
/*
* ======== ConfigChannel ========
* configure video port channel settings
*/
static Int ConfigChannel(Ptr chanp, VPChanCap_Params *params)
{
_VPORT_ChanObj *pChan= (_VPORT_ChanObj*)chanp;
volatile Int vpCtl, vcCtl, fld1Strt, fld2Strt, fld1Stop, fld2Stop;
volatile Int *base = (volatile Int*)pChan->base;
Int retVal = IOM_EBADIO;
Int numPixels, numLines, numCPixels;
if (!(pChan->status & _VPORT_OPENED))
return retVal;
pChan->autoSyncEnable = params->autoSyncEnable;
if (pChan->chanNum == 0)
{ /*channel A*/
/* control register */
vcCtl = VP_VCACTL_RMK(0,1,0,params->fldInv,
params->extCtl, params->fldDect, params->vCtRst,
params->hCtRst, 0, params->bpk10Bit, 0, 0,
params->resmpl,params->scale,1,
((params->fldOp & 4) >> 2),
((params->fldOp & 2) >> 1),
(params->fldOp & 1),
params->cmode);
/*YStart1 value will be put from the 16th bits in VCASTRT1 register*/
fld1Strt = params->fldXStrt1 + (params->fldYStrt1 << 16);
/*YStop1 value will be put from the 16th bits in VCASTOP1 register*/
fld1Stop = params->fldXStop1 + (params->fldYStop1 << 16);
/*YStart2 value will be put from the 16th bits in VCASTRT2 register*/
fld2Strt = params->fldXStrt2 + (params->fldYStrt2 << 16);
/*YStop2 value will be put from the 16th bits in VCASTOP2 register*/
fld2Stop = params->fldXStop2 + (params->fldYStop2 << 16);
if(params->fldOp == VPORT_FLDOP_FRAME)
{
assert(params->fldXStrt1 == params->fldXStrt2);
assert(params->fldXStop1 == params->fldXStop2);
}
/* reset channel */
base[_VP_VCACTL_OFFSETA] |=
VP_VCACTL_RSTCH_RESET << _VP_VCACTL_RSTCH_SHIFT;
_delay(2000);
base[_VP_VCACTL_OFFSETA] = vcCtl;
base[_VP_VCASTRT1_OFFSETA] = fld1Strt;
base[_VP_VCASTOP1_OFFSETA] = fld1Stop;
base[_VP_VCASTRT2_OFFSETA] = fld2Strt;
base[_VP_VCASTOP2_OFFSETA] = fld2Stop;
numPixels = params->fldXStop1 - params->fldXStrt1 + 1;/* line size */
numLines = 0;
if(params->fldOp != VPORT_FLDOP_FLD2)
{
numLines += params->fldYStop1 - params->fldYStrt1 + 1;
}
pChan->numLinesFld1 = numLines;
pChan->numTotalLinesFld1 = params->fldYStop1;
if(params->fldOp == VPORT_FLDOP_FLD2
|| params->fldOp == VPORT_FLDOP_FRAME)
{
numLines += params->fldYStop2 - params->fldYStrt2 + 1;
}
pChan->resmpl = params->resmpl;
pChan->scale = params->scale;
pChan->numLines = numLines;
numPixels >>= params->scale;
numCPixels = numPixels >> 1;
/* set both field1 and field2 threshold to the line size */
pChan->numPixels = numPixels;
pChan->lastLineNum = pChan->numLines;
if(params->cmode & _VPORT_MASK_10BIT)
{
/* 10-bit BT.656 or 20-bit Y/C mode */
if( params->bpk10Bit == VPORTCAP_BPK_10BIT_ZERO_EXTENDED
|| params->bpk10Bit == VPORTCAP_BPK_10BIT_SIGN_EXTENDED)
{
pChan->yPitch = (numPixels * 2 + 7) & (~ 7);
pChan->cPitch = (numCPixels * 2 + 7) & (~ 7);
}
else
{
pChan->yPitch = (numPixels * 4 / 3 + 7) & (~ 7);
pChan->cPitch = (numCPixels* 4 / 3 + 7) & (~ 7);
}
}
else
{/* 8-bit BT.656 or 16-bit Y/C mode */
pChan->yPitch = (numPixels + 7) & (~ 7);
pChan->cPitch = (numCPixels + 7) & (~ 7);
}
pChan->yThrld = params->thrld; /* thrld = 88 , number of doublewords threshold in the FIFO*/
pChan->interlaced = TRUE;
if(params->mergeFlds && params->fldOp == VPORT_FLDOP_FRAME)
{
/* merge field comments */
/* frame capture and merge 2 fields into one frame */
/* set threshold is same as line size */
pChan->yThrld = pChan->yPitch >> 3;
pChan->numEventsFld1 = pChan->numLinesFld1;
pChan->numEvents = pChan->numLines;
pChan->mergeFlds = TRUE;
}
else
{
assert(((pChan->yPitch * pChan->numLinesFld1) / (pChan->yThrld << 3))
*(pChan->yThrld << 3) == (pChan->yPitch * pChan->numLinesFld1));
assert(((pChan->yPitch * pChan->numLines) / (pChan->yThrld << 3))
*(pChan->yThrld << 3) == (pChan->yPitch * pChan->numLines));
pChan->numEventsFld1 =
pChan->yPitch * pChan->numLinesFld1 / (pChan->yThrld << 3);
pChan->numEvents =
pChan->yPitch * pChan->numLines / (pChan->yThrld << 3);
pChan->mergeFlds = FALSE;
if (params->fldOp != VPORT_FLDOP_FRAME)
pChan->interlaced = FALSE;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -