diff options
-rw-r--r-- | sys/dev/firewire/firewire.c | 42 | ||||
-rw-r--r-- | sys/dev/firewire/firewirereg.h | 2 | ||||
-rw-r--r-- | sys/dev/firewire/fwdev.c | 9 | ||||
-rw-r--r-- | sys/dev/firewire/fwohci.c | 63 |
4 files changed, 84 insertions, 32 deletions
diff --git a/sys/dev/firewire/firewire.c b/sys/dev/firewire/firewire.c index 7ed2fd1..ec67f71 100644 --- a/sys/dev/firewire/firewire.c +++ b/sys/dev/firewire/firewire.c @@ -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 @@ dvloop: }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 @@ dvloop: 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; diff --git a/sys/dev/firewire/firewirereg.h b/sys/dev/firewire/firewirereg.h index bfa7256..20ba318 100644 --- a/sys/dev/firewire/firewirereg.h +++ b/sys/dev/firewire/firewirereg.h @@ -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; diff --git a/sys/dev/firewire/fwdev.c b/sys/dev/firewire/fwdev.c index c6e7c58..d0f6371 100644 --- a/sys/dev/firewire/fwdev.c +++ b/sys/dev/firewire/fwdev.c @@ -383,8 +383,10 @@ isoloop: 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 @@ dvloop: 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); diff --git a/sys/dev/firewire/fwohci.c b/sys/dev/firewire/fwohci.c index 4fbdcad..b4c1b20 100644 --- a/sys/dev/firewire/fwohci.c +++ b/sys/dev/firewire/fwohci.c @@ -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; } } |