📄 vportcap.c
字号:
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];
volatile Int* base = (volatile Int *)portObjs[chan->portNum].base;
Int vpis = base[_VP_VPIS_OFFSET];
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;
}
}
if(nextViopChanged) {
/* now modify the EDMA rld entries */
if(chan->interlaced){
EDMA_RSETH(chan->hRld[offset], DST,
chan->nextViop->frame.iFrm.y1);
EDMA_RSETH(chan->hRld[offset + 1], DST,
chan->nextViop->frame.iFrm.y2);
EDMA_RSETH(chan->hRld[4 + offset], DST,
chan->nextViop->frame.iFrm.cb1);
EDMA_RSETH(chan->hRld[5 + offset], DST,
chan->nextViop->frame.iFrm.cb2);
EDMA_RSETH(chan->hRld[8 + offset], DST,
chan->nextViop->frame.iFrm.cr1);
EDMA_RSETH(chan->hRld[9 + offset], DST,
chan->nextViop->frame.iFrm.cr2);
} else {
EDMA_RSETH(chan->hRld[offset], DST,
chan->nextViop->frame.iFrm.y1);
EDMA_RSETH(chan->hRld[4 + offset], DST,
chan->nextViop->frame.iFrm.cb1);
EDMA_RSETH(chan->hRld[8 + offset], DST,
chan->nextViop->frame.iFrm.cr1);
} /* if(chan->interlaced) */
}
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 ++) {
for(i = 0; i < _VPORT_CHAN_CNT; i ++ ){ /* loop through two channels */
_VPORT_ChanObj* chan = &portObjs[j].chanObj[i];
if((chan->status & _VPORT_READY)
&& (tcc == chan->tcc[0] || tcc == chan->tcc[1])){
if(chan->autoSyncEnable) {
_autoSync(chan);
}
/* re-sync tcc with activeEDMARlds */
/* they may be out of sync after interrupt over-run */
/* e.g. execution is halted at break-point */
chan->nextEDMARlds = (tcc == chan->tcc[0]) ? 0 : 1;
offset = chan->nextEDMARlds << 1;
/* update the current and next viop pointers */
curViop = chan->curViop;
chan->curViop = chan->nextViop;
/* update the most recent viop */
if(curViop != chan->mrViop && chan->mrViop != INV) {
QUE_enqueue(&chan->qIn, chan->mrViop);
}
chan->mrViop = curViop;
if((viop = (FVID_Frame *)QUE_dequeue(&chan->qIn))
!=(FVID_Frame *)&chan->qIn) {
/* queue IS not empty */
chan->nextViop = viop;
}else {
if(chan->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 */
chan->nextViop = curViop;
}
chan->queEmpty = TRUE;
}
/* call the channel's callback function */
if(curViop != chan->curViop) {
if(chan->packetIOM != INV) {
/* call the channel's callback function */
*(void **)chan->packetIOM->addr = curViop;
chan->packetIOM->size = sizeof(FVID_Frame);
chan->packetIOM->status = IOM_COMPLETED;
chan->cbFxn((Ptr)chan->cbArg, chan->packetIOM);
chan->packetIOM = INV;
chan->mrViop = INV;
}else if(chan->queEmpty){
chan->nextViop = chan->mrViop;
}
}else {
chan->mrViop = INV;
}
/* Update the EDMA reload entry */
if(chan->interlaced){
EDMA_RSETH(chan->hRld[offset], DST,
chan->nextViop->frame.iFrm.y1);
EDMA_RSETH(chan->hRld[offset + 1], DST,
chan->nextViop->frame.iFrm.y2);
if(!(chan->mode & _VPORT_MASK_RAW)){
EDMA_RSETH(chan->hRld[4 + offset], DST,
chan->nextViop->frame.iFrm.cb1);
EDMA_RSETH(chan->hRld[5 + offset], DST,
chan->nextViop->frame.iFrm.cb2);
EDMA_RSETH(chan->hRld[8 + offset], DST,
chan->nextViop->frame.iFrm.cr1);
EDMA_RSETH(chan->hRld[9 + offset], DST,
chan->nextViop->frame.iFrm.cr2);
}
}else {
EDMA_RSETH(chan->hRld[offset], DST,
chan->nextViop->frame.iFrm.y1);
if(!(chan->mode & _VPORT_MASK_RAW)){
EDMA_RSETH(chan->hRld[offset + 4], DST,
chan->nextViop->frame.iFrm.cb1);
EDMA_RSETH(chan->hRld[offset + 8], DST,
chan->nextViop->frame.iFrm.cr1);
}
}/* if(chan->interlaced) {*/
}
}
}
}
/*
* ======== _configCh ========
* configure video port channel settings
*/
static Int _configCh(
Ptr chanp,
VPORTCAP_Params *params
)
{
_VPORT_ChanObj* chan= (_VPORT_ChanObj *)chanp;
volatile Int vpCtl, vcCtl, fld1Strt, fld2Strt, fld1Stop, fld2Stop;
volatile Int* base = (volatile Int *)chan->base;
Int retVal = IOM_COMPLETED;
Int numPixels, numLines, numCPixels;
if(chan->status & _VPORT_OPENED) {
chan->vIntMask = 0;
QUE_new(&chan->qIn);
chan->vIntFxn = (VPORT_IntCallBack)INV;
chan->queEmpty = FALSE;
chan->mrViop = INV;
chan->packetIOM = INV;
chan->vIntCbArg = (Int)INV;
chan->bufSz = 0;
chan->mode = params->cmode;
if(chan->mode & _VPORT_MASK_RAW) {
chan->autoSyncEnable = FALSE; // no auto-sync in raw mode
} else {
chan->autoSyncEnable = params->autoSyncEnable;
}
if(!(chan->mode & _VPORT_MASK_RAW)) {
/* configure channel A capture settings */
vcCtl = VP_VCACTL_RMK(0,1,0,params->fldInv,
params->extCtl, params->fldDect, params->vCtRst,
params->hCtRst, 0, params->bpk10Bit,1,1,
params->resmpl,params->scale,1,
((params->fldOp & 4) >> 2),
((params->fldOp & 2) >> 1),
(params->fldOp & 1),
params->cmode);
fld1Strt = params->fldXStrt1 + (params->fldYStrt1 << 16);
fld1Stop = params->fldXStop1 + (params->fldYStop1 << 16);
fld2Strt = params->fldXStrt2 + (params->fldYStrt2 << 16);
fld2Stop = params->fldXStop2 + (params->fldYStop2 << 16);
if(params->fldOp == VPORT_FLDOP_FRAME) {
assert(params->fldXStop1 == params->fldXStop2);
assert(params->fldXStrt1 == params->fldXStrt2);
}
/* 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;
}
chan->numLinesFld1 = numLines;
chan->numTotalLinesFld1 = params->fldYStop1;
if(params->fldOp == VPORT_FLDOP_FLD2
|| params->fldOp == VPORT_FLDOP_FRAME){
numLines += params->fldYStop2 - params->fldYStrt2 + 1;
}
chan->resmpl = params->resmpl;
chan->scale = params->scale;
chan->numLines = numLines;
numPixels >>= params->scale;
numCPixels = numPixels >> 1;
/* set both field1 and field2 threshold to the line size */
chan->numPixels = numPixels;
chan->lastLineNum = chan->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){
chan->yPitch = (numPixels * 2 + 7) & (~ 7);
chan->cPitch = (numCPixels * 2 + 7) & (~ 7);
}else {
chan->yPitch = (numPixels * 4 / 3 + 7) & (~ 7);
chan->cPitch = (numCPixels* 4 / 3 + 7) & (~ 7);
}
} else {/* 8-bit BT.656 or 16-bit Y/C mode */
chan->yPitch = (numPixels + 7) & (~ 7);
chan->cPitch = (numCPixels + 7) & (~ 7);
}
chan->yThrld = params->thrld;
chan->interlaced = TRUE;
if(params->fldOp == VPORT_FLDOP_FRAME && params->mergeFlds) {
/* merge field comments */
/* frame capture and merge 2 fields into one frame */
/* set threshold is same as line size */
chan->yThrld = chan->yPitch >> 3;
chan->numEventsFld1 = chan->numLinesFld1;
chan->numEvents = chan->numLines;
}else {
assert(((chan->yPitch*chan->numLinesFld1) / (chan->yThrld << 3))
*(chan->yThrld << 3) == (chan->yPitch * chan->numLinesFld1));
assert(((chan->yPitch * chan->numLines) / (chan->yThrld << 3))
*(chan->yThrld << 3) == (chan->yPitch * chan->numLines));
chan->numEventsFld1 =
chan->yPitch * chan->numLinesFld1 / (chan->yThrld << 3);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -