summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/dev/firewire/firewire.c42
-rw-r--r--sys/dev/firewire/firewirereg.h2
-rw-r--r--sys/dev/firewire/fwdev.c9
-rw-r--r--sys/dev/firewire/fwohci.c63
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;
}
}
OpenPOWER on IntegriCloud