📄 devtv.c
字号:
dev = DEV(c->qid); switch (TYPE(c->qid)) { case Qdir: if (i == DEVDOTDOT) { mkqid(&qid, Qdir, 0, QTDIR); devdir(c, qid, "#V", 0, eve, 0555, dp); return 1; } if (i >= ntvs) return -1; mkqid(&qid, QID(i, Qsubdir), 0, QTDIR); snprint(up->genbuf, sizeof(up->genbuf), "tv%d", i); devdir(c, qid, up->genbuf, 0, eve, 0555, dp); return 1; case Qsubdir: if (i == DEVDOTDOT) { mkqid(&qid, QID(dev, Qdir), 0, QTDIR); snprint(up->genbuf, sizeof(up->genbuf), "tv%d", dev); devdir(c, qid, up->genbuf, 0, eve, 0555, dp); return 1; } return tv1gen(c, i + Qsubbase, dp); case Qvdata: case Qadata: case Qctl: case Qregs: return tv1gen(c, TYPE(c->qid), dp); default: return -1; }}static Walkqid *tvwalk(Chan *c, Chan *nc, char **name, int nname){ return devwalk(c, nc, name, nname, 0, 0, tvgen);}static inttvstat(Chan *c, uchar *db, int n){ return devstat(c, db, n, 0, 0, tvgen);}static Chan*tvopen(Chan *c, int omode){ if (omode != OREAD && TYPE(c->qid) != Qctl && TYPE(c->qid) != Qvdata) error(Eperm); switch (TYPE(c->qid)) { case Qdir: return devopen(c, omode, nil, 0, tvgen); case Qadata: if (tvs[DEV(c->qid)].bt878 == nil) error(Enonexist); break; } c->mode = openmode(omode); c->flag |= COPEN; c->offset = 0; if (TYPE(c->qid) == Qadata) c->aux = nil; return c;}static voidtvclose(Chan *){}static intaudioblock(void *){ return 1;} static longtvread(Chan *c, void *a, long n, vlong offset){ static char regs[10 * K]; static int regslen; Tv *tv; char *e, *p; uchar *src; USED(offset); switch(TYPE(c->qid)) { case Qdir: case Qsubdir: return devdirread(c, a, n, 0, 0, tvgen); case Qvdata: { int bpf, nb; tv = &tvs[DEV(c->qid)]; bpf = ntsc_hactive * ntsc_vactive * getbitspp(tv) / 8; if (offset >= bpf) return 0; nb = n; if (offset + nb > bpf) nb = bpf - offset; ilock(tv); if (tv->frames == nil || tv->lvframe >= tv->nframes || tv->frames[tv->lvframe].fbase == nil) { iunlock(tv); return 0; } src = tv->frames[tv->lvframe].fbase; incref(&tv->fref); iunlock(tv); memmove(a, src + offset, nb); decref(&tv->fref); return nb; } case Qadata: { ulong uablock = (ulong)c->aux, bnum, tvablock; int boffs, nbytes; tv = &tvs[DEV(c->qid)]; if (tv->bt878 == nil) error("#V: No audio device"); if (tv->absize == 0) error("#V: audio not initialized"); bnum = offset / tv->absize; boffs = offset % tv->absize; nbytes = tv->absize - boffs; incref(&tv->aref); while (1) { tvablock = tv->narblocks; // Current tv block. if (uablock == 0) uablock = tvablock - 1; if (tvablock >= uablock + bnum + tv->narblocks) uablock = tvablock - 1 - bnum; if (uablock + bnum == tvablock) { sleep(tv, audioblock, nil); continue; } break; } print("uablock %ld, bnum %ld, boffs %d, nbytes %d, tvablock %ld\n", uablock, bnum, boffs, nbytes, tvablock); src = tv->abuf + ((uablock + bnum) % tv->nablocks) * tv->absize; print("copying from %.8ulX (abuf %.8ulX), nbytes %d (block %ld.%ld)\n", src + boffs, tv->abuf, nbytes, uablock, bnum); memmove(a, src + boffs, nbytes); decref(&tv->aref); uablock += (boffs + nbytes) % tv->absize; c->aux = (void*)uablock; return nbytes; } case Qctl: { char str[128]; tv = &tvs[DEV(c->qid)]; snprint(str, sizeof str, "%dx%dx%d %s channel %d %s\n", ntsc_hactive, ntsc_vactive, getbitspp(tv), getcolormode(tv->cfmt), tv->channel, tv->ainfo); return readstr(offset, a, strlen(str) + 1, str); } case Qregs: if (offset == 0) { Bt848 *bt848; int i; tv = &tvs[DEV(c->qid)]; bt848 = tv->bt848; e = regs + sizeof(regs); p = regs; for (i = 0; i < 0x300 >> 2; i++) p = seprint(p, e, "%.3X %.8ulX\n", i << 2, ((ulong *)bt848)[i]); if (tv->bt878) { bt848 = tv->bt878; for (i = 0; i < 0x300 >> 2; i++) p = seprint(p, e, "%.3X %.8ulX\n", i << 2, ((ulong *)bt848)[i]); } regslen = p - regs; } if (offset >= regslen) return 0; if (offset + n > regslen) n = regslen - offset; return readstr(offset, a, n, ®s[offset]); default: n = 0; break; } return n;}static longtvwrite(Chan *c, void *a, long n, vlong){ Cmdbuf *cb; Cmdtab *ct; Tv *tv; tv = &tvs[DEV(c->qid)]; switch(TYPE(c->qid)) { case Qctl: cb = parsecmd(a, n); if(waserror()){ free(cb); nexterror(); } ct = lookupcmd(cb, tvctlmsg, nelem(tvctlmsg)); switch (ct->index) { case CMvstart: vstart(tv, (int)strtol(cb->f[1], (char **)nil, 0), ntsc_hactive, ntsc_vactive, ntsc_hactive); break; case CMastart: astart(tv, cb->f[1], (uint)strtol(cb->f[2], (char **)nil, 0), (uint)strtol(cb->f[3], (char **)nil, 0), (uint)strtol(cb->f[4], (char **)nil, 0)); break; case CMastop: astop(tv); break; case CMvgastart: vgastart(tv, strtoul(cb->f[1], (char **)nil, 0), (int)strtoul(cb->f[2], (char **)nil, 0)); break; case CMvstop: vstop(tv); break; case CMchannel: frequency(tv, (int)strtol(cb->f[1], (char **)nil, 0), (int)strtol(cb->f[2], (char **)nil, 0)); break; case CMcolormode: colormode(tv, cb->f[1]); break; case CMvolume: if (!tv->msp) error("#V: No volume control"); mspvolume(tv, 0, (int)strtol(cb->f[1], (char **)nil, 0), (int)strtol(cb->f[2], (char **)nil, 0)); break; case CMmute: if (!tv->msp) error("#V: No volume control"); mspvolume(tv, 1, 0, 0); break; } poperror(); free(cb); break; default: error(Eio); } return n;}Dev tvdevtab = { 'V', "tv", devreset, tvinit, devshutdown, tvattach, tvwalk, tvstat, tvopen, devcreate, tvclose, tvread, devbread, tvwrite, devbwrite, devremove, devwstat,};static voidtvinterrupt(Ureg *, Tv *tv){ Bt848 *bt848 = tv->bt848, *bt878 = tv->bt878; while (1) { ulong vstat, astat; uchar fnum; vstat = bt848->intstat; fnum = (vstat >> intstat_riscstatshift) & 0xf; vstat &= bt848->intmask; if (bt878) astat = bt878->intstat & bt878->intmask; else astat = 0; if (vstat == 0 && astat == 0) break; if (astat) print("vstat %.8luX, astat %.8luX\n", vstat, astat); bt848->intstat = vstat; if (bt878) bt878->intstat = astat; if ((vstat & intstat_fmtchg) == intstat_fmtchg) { iprint("int: fmtchg\n"); vstat &= ~intstat_fmtchg; } if ((vstat & intstat_vpress) == intstat_vpress) {// iprint("int: vpress\n"); vstat &= ~intstat_vpress; } if ((vstat & intstat_vsync) == intstat_vsync) { vstat &= ~intstat_vsync; } if ((vstat & intstat_scerr) == intstat_scerr) { iprint("int: scerr\n"); bt848->gpiodmactl &= ~(gpiodmactl_riscenable|gpiodmactl_fifoenable); bt848->gpiodmactl |= gpiodmactl_fifoenable; bt848->gpiodmactl |= gpiodmactl_riscenable; vstat &= ~intstat_scerr; } if ((vstat & intstat_risci) == intstat_risci) { tv->lvframe = fnum; vstat &= ~intstat_risci; } if ((vstat & intstat_ocerr) == intstat_ocerr) { iprint("int: ocerr\n"); vstat &= ~intstat_ocerr; } if ((vstat & intstat_fbus) == intstat_fbus) { iprint("int: fbus\n"); vstat &= ~intstat_fbus; } if (vstat) iprint("int: (v) ignored interrupts %.8ulX\n", vstat); if ((astat & intstat_risci) == intstat_risci) { tv->narblocks++; if ((tv->narblocks % 100) == 0) print("a"); wakeup(tv); astat &= ~intstat_risci; } if ((astat & intstat_fdsr) == intstat_fdsr) { iprint("int: (a) fdsr\n"); bt848->gpiodmactl &= ~(gpiodmactl_acapenable | gpiodmactl_riscenable | gpiodmactl_fifoenable); astat &= ~intstat_fdsr; } if (astat) iprint("int: (a) ignored interrupts %.8ulX\n", astat); }}static inti2cread(Tv *tv, uchar off, uchar *v){ Bt848 *bt848 = tv->bt848; ulong intstat; int i; bt848->intstat = intstat_i2cdone; bt848->i2c = (off << 24) | tv->i2ccmd; intstat = -1; for (i = 0; i != 1000; i++) { if ((intstat = bt848->intstat) & intstat_i2cdone) break; microdelay(1000); } if (i == 1000) { print("i2cread: timeout\n"); return 0; } if ((intstat & intstat_i2crack) == 0) return 0; *v = bt848->i2c >> 8; return 1;}static inti2cwrite(Tv *tv, uchar addr, uchar sub, uchar data, int both){ Bt848 *bt848 = tv->bt848; ulong intstat, d; int i; bt848->intstat = intstat_i2cdone; d = (addr << 24) | (sub << 16) | tv->i2ccmd; if (both) d |= (data << 8) | i2c_bt848w3b; bt848->i2c = d; intstat = 0; for (i = 0; i != 1000; i++) { if ((intstat = bt848->intstat) & intstat_i2cdone) break; microdelay(1000); } if (i == i2c_timeout) { print("i2cwrite: timeout\n"); return 0; } if ((intstat & intstat_i2crack) == 0) return 0; return 1;}static ulong *riscpacked(ulong pa, int fnum, int w, int h, int stride, ulong **lastjmp){ ulong *p, *pbase; int i; pbase = p = (ulong *)malloc((h + 6) * 2 * sizeof(ulong)); assert(p); assert(w <= 0x7FF); *p++ = riscsync | riscsync_resync | riscsync_vre; *p++ = 0; *p++ = riscsync | riscsync_fm1; *p++ = 0; for (i = 0; i != h / 2; i++) { *p++ = riscwrite | w | riscwrite_sol | riscwrite_eol; *p++ = pa + i * 2 * stride; } *p++ = riscsync | riscsync_resync | riscsync_vro; *p++ = 0; *p++ = riscsync | riscsync_fm1; *p++ = 0; for (i = 0; i != h / 2; i++) { *p++ = riscwrite | w | riscwrite_sol | riscwrite_eol; *p++ = pa + (i * 2 + 1) * stride; } // reset status. you really need two instructions ;-(. *p++ = riscjmp | (0xf << risclabelshift_reset); *p++ = PADDR(p); *p++ = riscjmp | riscirq | (fnum << risclabelshift_set); *lastjmp = p; return pbase;}static ulong *riscplanar411(ulong pa, int fnum, int w, int h, ulong **lastjmp){ ulong *p, *pbase, Cw, Yw, Ch; uchar *Ybase, *Cbbase, *Crbase; int i, bitspp; bitspp = 6; assert(w * bitspp / 8 <= 0x7FF); pbase = p = (ulong *)malloc((h + 6) * 5 * sizeof(ulong)); assert(p); Yw = w; Ybase = (uchar *)pa; Cw = w >> 1; Ch = h >> 1; Cbbase = Ybase + Yw * h; Crbase = Cbbase + Cw * Ch; *p++ = riscsync | riscsync_resync | riscsync_vre; *p++ = 0; *p++ = riscsync | riscsync_fm3; *p++ = 0; for (i = 0; i != h / 2; i++) { *p++ = riscwrite123 | Yw | riscwrite_sol | riscwrite_eol; *p++ = (Cw << 16) | Cw; *p++ = (ulong)(Ybase + i * 2 * Yw); *p++ = (ulong)(Cbbase + i * Cw); // Do not interlace *p++ = (ulong)(Crbase + i * Cw); } *p++ = riscsync | riscsync_resync | riscsync_vro; *p++ = 0; *p++ = riscsync | riscsync_fm3; *p++ = 0; for (i = 0; i != h / 2; i++) { *p++ = riscwrite1s23 | Yw | riscwrite_sol | riscwrite_eol; *p++ = (Cw << 16) | Cw; *p++ = (ulong)(Ybase + (i * 2 + 1) * Yw); } // reset status. you really need two instructions ;-(. *p++ = riscjmp | (0xf << risclabelshift_reset); *p++ = PADDR(p); *p++ = riscjmp | riscirq | (fnum << risclabelshift_set); *lastjmp = p; return pbase;}static ulong *riscplanar422(ulong pa, int fnum, int w, int h, ulong **lastjmp){ ulong *p, *pbase, Cw, Yw; uchar *Ybase, *Cbbase, *Crbase; int i, bpp; bpp = 2; assert(w * bpp <= 0x7FF); pbase = p = (ulong *)malloc((h + 6) * 5 * sizeof(ulong)); assert(p); Yw = w; Ybase = (uchar *)pa; Cw = w >> 1; Cbbase = Ybase + Yw * h; Crbase = Cbbase + Cw * h; *p++ = riscsync | riscsync_resync | riscsync_vre; *p++ = 0; *p++ = riscsync | riscsync_fm3; *p++ = 0; for (i = 0; i != h / 2; i++) { *p++ = riscwrite123 | Yw | riscwrite_sol | riscwrite_eol; *p++ = (Cw << 16) | Cw; *p++ = (ulong)(Ybase + i * 2 * Yw); *p++ = (ulong)(Cbbase + i * 2 * Cw); *p++ = (ulong)(Crbase + i * 2 * Cw); } *p++ = riscsync | riscsync_resync | riscsync_vro; *p++ = 0; *p++ = riscsync | riscsync_fm3; *p++ = 0; for (i = 0; i != h / 2; i++) { *p++ = riscwrite123 | Yw | riscwrite_sol | riscwrite_eol; *p++ = (Cw << 16) | Cw; *p++ = (ulong)(Ybase + (i * 2 + 1) * Yw); *p++ = (ulong)(Cbbase + (i * 2 + 1) * Cw); *p++ = (ulong)(Crbase + (i * 2 + 1) * Cw); } // reset status. you really need two instructions ;-(. *p++ = riscjmp | (0xf << risclabelshift_reset); *p++ = PADDR(p); *p++ = riscjmp | riscirq | (fnum << risclabelshift_set); *lastjmp = p; return pbase;}static ulong *riscaudio(ulong pa, int nblocks, int bsize){ ulong *p, *pbase; int i; pbase = p = (ulong *)malloc((nblocks + 3) * 2 * sizeof(ulong)); assert(p); *p++ = riscsync|riscsync_fm1; *p++ = 0; for (i = 0; i != nblocks; i++) { *p++ = riscwrite | riscwrite_sol | riscwrite_eol | bsize | riscirq | ((i & 0xf) << risclabelshift_set) | ((~i & 0xf) << risclabelshift_reset); *p++ = pa + i * bsize; } *p++ = riscsync | riscsync_vro; *p++ = 0; *p++ = riscjmp; *p++ = PADDR(pbase); USED(p); return pbase;}static voidvactivate(Tv *tv, Frame *frames, int nframes){ Bt848 *bt848 = tv->bt848; ilock(tv); if (tv->frames) { iunlock(tv); error(Einuse); } poperror(); tv->frames = frames; tv->nframes = nframes; bt848->riscstrtadd = PADDR(tv->frames[0].fstart); bt848->capctl |= capctl_captureodd|capctl_captureeven; bt848->gpiodmactl |= gpiodmactl_fifoenable; bt848->gpiodmactl |= gpiodmactl_riscenable; iunlock(tv);}static voidvstart(Tv *tv, int nframes, int w, int h, int stride){ Frame *frames; int bitspp, i, bpf; if (nframes >= 0x10) error(Ebadarg); bitspp = getbitspp(tv); bpf = w * h * bitspp / 8; // Add one as a spare. frames = (Frame *)malloc(nframes * sizeof(Frame)); assert(frames); if (waserror()) { for (i = 0; i != nframes; i++) if (frames[i].fbase) free(frames[i].fbase); free(frames); nexterror(); } memset(frames, 0, nframes * sizeof(Frame)); for (i = 0; i != nframes; i++) { if ((frames[i].fbase = (uchar *)malloc(bpf)) == nil) error(Enomem); switch (tv->cfmt) { case colorfmt_YCbCr422: frames[i].fstart = riscplanar422(PADDR(frames[i].fbase), i, w, h, &frames[i].fjmp); break; case colorfmt_YCbCr411: frames[i].fstart = riscplanar411(PADDR(frames[i].fbase), i, w, h, &frames[i].fjmp); break; case colorfmt_rgb16: frames[i].fstart = riscpacked(PADDR(frames[i].fbase), i, w * bitspp / 8, h, stride * bitspp / 8, &frames[i].fjmp); break; default: panic("vstart: Unsupport colorformat\n"); } } for (i = 0; i != nframes; i++) *frames[i].fjmp = PADDR((i == nframes - 1)? frames[0].fstart: frames[i + 1].fstart); vactivate(tv, frames, nframes);}static voidastart(Tv *tv, char *input, uint rate, uint nab, uint nasz){ Bt848 *bt878 = tv->bt878; ulong *arisc; int selector;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -