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:
Hidetoshi Shimokawa 2003-01-13 16:08:09 +00:00
parent d0035474c3
commit 0aaa9a23cd
4 changed files with 84 additions and 32 deletions

View File

@ -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;

View File

@ -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;

View File

@ -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);

View File

@ -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;
}
}