Minimal fix for DV part.
- Don't panic on contigmalloc failure. - Calculate timestamp by feedforward rather than feedback which depends on unreliable interrupt timing. - Overwrite timestamp in CIP header correctly. - Add debug code for timestamp synchronization. - Add comments.
This commit is contained in:
parent
d0035474c3
commit
0aaa9a23cd
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=109179
@ -129,7 +129,7 @@ fw_tbuf_update(struct firewire_comm *fc, int sub, int flag){
|
||||
struct fw_xferq *it;
|
||||
int s, err = 0, i, j, chtag;
|
||||
struct fw_pkt *fp;
|
||||
u_int64_t tmpsync, dvsync;
|
||||
u_int64_t cycle, dvsync;
|
||||
|
||||
it = fc->it[sub];
|
||||
|
||||
@ -193,17 +193,27 @@ fw_tbuf_update(struct firewire_comm *fc, int sub, int flag){
|
||||
}else{
|
||||
return err;
|
||||
}
|
||||
/*
|
||||
* Insert least significant 12 bits timestamp value by computation.
|
||||
* Highest significant 4 bits is insert at just before packet sending.
|
||||
*/
|
||||
fp = (struct fw_pkt *)(it->stproc->buf);
|
||||
/* XXX: Parameter relies on NTSC type DV video */
|
||||
tmpsync = (u_int64_t)3072 * 8000 * 100 / 2997;
|
||||
tmpsync *= it->dvsync;
|
||||
dvsync = tmpsync;
|
||||
dvsync %= 0xc00;
|
||||
fp->mode.ld[2] = htonl(0x80000000 | (dvsync % 0xc00));
|
||||
#if 1
|
||||
#define DVSEC 100
|
||||
#define DVFRAC 2997 /* NTSC: 29.97 Hz (2997 = 29.97 * 100) */
|
||||
#define DVDIFF 203 /* 203 = (8000/250 - 29.97) * 100 */
|
||||
#else
|
||||
#define DVSEC 3
|
||||
#define DVFRAC 75 /* PAL: 25 Hz (1875 = 25 * 3) */
|
||||
#define DVDIFF 5 /* 125 = (8000/300 - 25) * 3 */
|
||||
#endif
|
||||
#define CYCLEFRAC 0xc00
|
||||
cycle = (u_int64_t) 8000 * DVSEC * it->dvsync;
|
||||
/* least significant 12 bits */
|
||||
dvsync = (cycle * CYCLEFRAC / DVFRAC) % CYCLEFRAC;
|
||||
/* most significat 4 bits */
|
||||
cycle = (cycle / DVFRAC + it->dvoffset) & 0xf;
|
||||
fp = (struct fw_pkt *)(it->dvdma->buf);
|
||||
#if 1
|
||||
fp->mode.ld[2] = htonl(0x80000000 | (cycle << 12) | dvsync);
|
||||
#else
|
||||
fp->mode.ld[2] = htonl(0x80000000 | dvsync);
|
||||
#endif
|
||||
it->dvsync ++;
|
||||
it->dvsync %= 2997;
|
||||
|
||||
@ -219,14 +229,6 @@ fw_tbuf_update(struct firewire_comm *fc, int sub, int flag){
|
||||
it->dvdbc %= 256;
|
||||
it->queued ++;
|
||||
j++;
|
||||
/* XXX: Parameter relies on NTSC type DV video */
|
||||
#if 1
|
||||
#define DVDIFF 203
|
||||
#define DVFRAC 2997
|
||||
#else
|
||||
#define DVDIFF 127
|
||||
#define DVFRAC 1875
|
||||
#endif
|
||||
it->dvdiff += DVDIFF;
|
||||
if(it->dvdiff >= DVFRAC){
|
||||
it->dvdiff %= DVFRAC;
|
||||
|
@ -176,7 +176,7 @@ struct firewire_comm{
|
||||
struct fw_bulkxfer *stdma2;
|
||||
struct fw_bulkxfer *stproc;
|
||||
u_int procptr;
|
||||
int dvdbc, dvdiff, dvsync;
|
||||
int dvdbc, dvdiff, dvsync, dvoffset;
|
||||
struct fw_dvbuf *dvbuf;
|
||||
STAILQ_HEAD(, fw_dvbuf) dvvalid;
|
||||
STAILQ_HEAD(, fw_dvbuf) dvfree;
|
||||
|
@ -383,8 +383,10 @@ fw_write (dev_t dev, struct uio *uio, int ioflag)
|
||||
return err;
|
||||
}
|
||||
}
|
||||
#if 0 /* What's this for? (overwritten by the following uiomove)*/
|
||||
fp = (struct fw_pkt *)(it->stproc->buf + it->queued * it->psize);
|
||||
fp->mode.stream.len = htons(uio->uio_resid - sizeof(u_int32_t));
|
||||
#endif
|
||||
err = uiomove(it->stproc->buf + it->queued * it->psize,
|
||||
uio->uio_resid, uio);
|
||||
it->queued ++;
|
||||
@ -422,8 +424,10 @@ fw_write (dev_t dev, struct uio *uio, int ioflag)
|
||||
return err;
|
||||
}
|
||||
}
|
||||
#if 0 /* What's this for? (it->dvptr? overwritten by the following uiomove)*/
|
||||
fp = (struct fw_pkt *)(it->dvproc->buf + it->queued * it->psize);
|
||||
fp->mode.stream.len = htons(uio->uio_resid - sizeof(u_int32_t));
|
||||
#endif
|
||||
err = uiomove(it->dvproc->buf + it->dvptr,
|
||||
uio->uio_resid, uio);
|
||||
it->dvptr += it->psize;
|
||||
@ -564,7 +568,7 @@ fw_ioctl (dev_t dev, u_long cmd, caddr_t data, int flag, fw_proc *td)
|
||||
err = ENOMEM;
|
||||
break;
|
||||
}
|
||||
#define FWDVPACKET 250
|
||||
#define FWDVPACKET 250 /* NTSC (300 for PAL) */
|
||||
#define FWDVPMAX 512
|
||||
ibufreq->rx.nchunk = 8;
|
||||
ibufreq->rx.npacket = 50;
|
||||
@ -582,11 +586,13 @@ fw_ioctl (dev_t dev, u_long cmd, caddr_t data, int flag, fw_proc *td)
|
||||
sc->fc->it[sub]->dvproc = NULL;
|
||||
sc->fc->it[sub]->dvdma = NULL;
|
||||
sc->fc->it[sub]->flag |= FWXFERQ_DV;
|
||||
/* XXX check malloc failure */
|
||||
sc->fc->it[sub]->dvbuf
|
||||
= (struct fw_dvbuf *)malloc(sizeof(struct fw_dvbuf) * NDVCHUNK, M_DEVBUF, M_DONTWAIT);
|
||||
STAILQ_INIT(&sc->fc->it[sub]->dvvalid);
|
||||
STAILQ_INIT(&sc->fc->it[sub]->dvfree);
|
||||
for( i = 0 ; i < NDVCHUNK ; i++){
|
||||
/* XXX check malloc failure */
|
||||
sc->fc->it[sub]->dvbuf[i].buf
|
||||
= malloc(FWDVPMAX * sc->fc->it[sub]->dvpacket, M_DEVBUF, M_DONTWAIT);
|
||||
STAILQ_INSERT_TAIL(&sc->fc->it[sub]->dvfree,
|
||||
@ -663,6 +669,7 @@ fw_ioctl (dev_t dev, u_long cmd, caddr_t data, int flag, fw_proc *td)
|
||||
it->dvdbc = 0;
|
||||
it->dvdiff = 0;
|
||||
it->dvsync = 0;
|
||||
it->dvoffset = 0;
|
||||
|
||||
STAILQ_INIT(&ir->stvalid);
|
||||
STAILQ_INIT(&ir->stfree);
|
||||
|
@ -74,6 +74,8 @@
|
||||
#include <dev/firewire/fwohcivar.h>
|
||||
#include <dev/firewire/firewire_phy.h>
|
||||
|
||||
#include <dev/firewire/iec68113.h>
|
||||
|
||||
#undef OHCI_DEBUG
|
||||
|
||||
static char dbcode[16][0x10]={"OUTM", "OUTL","INPM","INPL",
|
||||
@ -1248,6 +1250,8 @@ fwohci_irxpp_enable(struct firewire_comm *fc, int dmach)
|
||||
sc->ir[dmach].xferq.psize = FWPMAX_S400;
|
||||
sc->ir[dmach].ndesc = 1;
|
||||
fwohci_db_init(&sc->ir[dmach]);
|
||||
if ((sc->ir[dmach].flags & FWOHCI_DBCH_INIT) == 0)
|
||||
return ENOMEM;
|
||||
err = fwohci_rx_enable(sc, &sc->ir[dmach]);
|
||||
}
|
||||
if(err){
|
||||
@ -1414,11 +1418,13 @@ fwohci_itxbuf_enable(struct firewire_comm *fc, int dmach)
|
||||
tag = (sc->it[dmach].xferq.flag >> 6) & 3;
|
||||
ich = sc->it[dmach].xferq.flag & 0x3f;
|
||||
dbch = &sc->it[dmach];
|
||||
if(dbch->ndb == 0){
|
||||
if ((dbch->flags & FWOHCI_DBCH_INIT) == 0) {
|
||||
dbch->xferq.queued = 0;
|
||||
dbch->ndb = dbch->xferq.bnpacket * dbch->xferq.bnchunk;
|
||||
dbch->ndesc = 3;
|
||||
fwohci_db_init(dbch);
|
||||
if ((dbch->flags & FWOHCI_DBCH_INIT) == 0)
|
||||
return ENOMEM;
|
||||
err = fwohci_tx_enable(sc, dbch);
|
||||
}
|
||||
if(err)
|
||||
@ -1469,8 +1475,12 @@ fwohci_itxbuf_enable(struct firewire_comm *fc, int dmach)
|
||||
if(dbch->xferq.flag & FWXFERQ_DV){
|
||||
db_tr = (struct fwohcidb_tr *)dbch->xferq.stdma->start;
|
||||
fp = (struct fw_pkt *)db_tr->buf;
|
||||
fp->mode.ld[2] = htonl(0x80000000 +
|
||||
((fc->cyctimer(fc) + 0x3000) & 0xf000));
|
||||
dbch->xferq.dvoffset =
|
||||
((fc->cyctimer(fc) >> 12) + 4) & 0xf;
|
||||
#if 0
|
||||
printf("dvoffset: %d\n", dbch->xferq.dvoffset);
|
||||
#endif
|
||||
fp->mode.ld[2] |= htonl(dbch->xferq.dvoffset << 12);
|
||||
}
|
||||
|
||||
OWRITE(sc, OHCI_ITCTL(dmach), OHCI_CNTL_DMA_RUN);
|
||||
@ -1503,6 +1513,8 @@ fwohci_irxbuf_enable(struct firewire_comm *fc, int dmach)
|
||||
}
|
||||
sc->ir[dmach].ndesc = 2;
|
||||
fwohci_db_init(&sc->ir[dmach]);
|
||||
if ((sc->ir[dmach].flags & FWOHCI_DBCH_INIT) == 0)
|
||||
return ENOMEM;
|
||||
err = fwohci_rx_enable(sc, &sc->ir[dmach]);
|
||||
}
|
||||
if(err)
|
||||
@ -1890,40 +1902,71 @@ fwohci_tbuf_update(struct fwohci_softc *sc, int dmach)
|
||||
struct fwohcidb_tr *db_tr;
|
||||
|
||||
dbch = &sc->it[dmach];
|
||||
#if 0 /* XXX OHCI interrupt before the last packet is really on the wire */
|
||||
if((dbch->xferq.flag & FWXFERQ_DV) && (dbch->xferq.stdma2 != NULL)){
|
||||
db_tr = (struct fwohcidb_tr *)dbch->xferq.stdma2->start;
|
||||
/*
|
||||
* Overwrite highest significant 4 bits timestamp information
|
||||
*/
|
||||
fp = (struct fw_pkt *)db_tr->buf;
|
||||
fp->mode.ld[2] |= htonl(0x80000000 |
|
||||
((fc->cyctimer(fc) + 0x4000) & 0xf000));
|
||||
fp->mode.ld[2] &= htonl(0xffff0fff);
|
||||
fp->mode.ld[2] |= htonl((fc->cyctimer(fc) + 0x4000) & 0xf000);
|
||||
}
|
||||
#endif
|
||||
stat = OREAD(sc, OHCI_ITCTL(dmach)) & 0x1f;
|
||||
switch(stat){
|
||||
case FWOHCIEV_ACKCOMPL:
|
||||
#if 1
|
||||
if (dbch->xferq.flag & FWXFERQ_DV) {
|
||||
struct ciphdr *ciph;
|
||||
int timer, timestamp, cycl, diff;
|
||||
static int last_timer=0;
|
||||
|
||||
timer = (fc->cyctimer(fc) >> 12) & 0xffff;
|
||||
db_tr = (struct fwohcidb_tr *)dbch->xferq.stdma->start;
|
||||
fp = (struct fw_pkt *)db_tr->buf;
|
||||
ciph = (struct ciphdr *) &fp->mode.ld[1];
|
||||
timestamp = db_tr->db[2].db.desc.count & 0xffff;
|
||||
cycl = ntohs(ciph->fdf.dv.cyc) >> 12;
|
||||
diff = cycl - (timestamp & 0xf) - 1;
|
||||
if (diff < 0)
|
||||
diff += 16;
|
||||
if (diff > 8)
|
||||
diff -= 16;
|
||||
if (firewire_debug)
|
||||
printf("dbc: %3d timer: 0x%04x packet: 0x%04x"
|
||||
" cyc: 0x%x diff: %+1d\n",
|
||||
ciph->dbc, last_timer, timestamp, cycl, diff);
|
||||
last_timer = timer;
|
||||
/* XXX adjust dbch->xferq.dvoffset if diff != 0 or 1 */
|
||||
}
|
||||
#endif
|
||||
fw_tbuf_update(fc, dmach, 1);
|
||||
break;
|
||||
default:
|
||||
device_printf(fc->dev, "Isochronous transmit err %02x\n", stat);
|
||||
fw_tbuf_update(fc, dmach, 0);
|
||||
break;
|
||||
}
|
||||
fwohci_itxbuf_enable(&sc->fc, dmach);
|
||||
fwohci_itxbuf_enable(fc, dmach);
|
||||
}
|
||||
|
||||
static void
|
||||
fwohci_rbuf_update(struct fwohci_softc *sc, int dmach)
|
||||
{
|
||||
struct firewire_comm *fc = &sc->fc;
|
||||
int stat;
|
||||
|
||||
stat = OREAD(sc, OHCI_IRCTL(dmach)) & 0x1f;
|
||||
switch(stat){
|
||||
case FWOHCIEV_ACKCOMPL:
|
||||
fw_rbuf_update(&sc->fc, dmach, 1);
|
||||
wakeup(sc->fc.ir[dmach]);
|
||||
fwohci_irx_enable(&sc->fc, dmach);
|
||||
fw_rbuf_update(fc, dmach, 1);
|
||||
wakeup(fc->ir[dmach]);
|
||||
fwohci_irx_enable(fc, dmach);
|
||||
break;
|
||||
default:
|
||||
device_printf(sc->fc.dev, "Isochronous receive err %02x\n", stat);
|
||||
device_printf(fc->dev, "Isochronous receive err %02x\n",
|
||||
stat);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user