From 2e31dce2831e9088118a1e4363cc100bbe93d816 Mon Sep 17 00:00:00 2001 From: David du Colombier <0intro@gmail.com> Date: Wed, 30 Jan 2002 00:00:00 +0000 Subject: [PATCH] Plan 9 from Bell Labs 2002-01-30 --- pc/devtv.c | 287 ++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 197 insertions(+), 90 deletions(-) diff --git a/pc/devtv.c b/pc/devtv.c index 2d1fc4a5563f5f8e2c8146e7d5ebac276dac0c22..3542a6a568aa0e004ce5705a5639fff4000764df 100644 --- a/pc/devtv.c +++ b/pc/devtv.c @@ -1,6 +1,5 @@ /* - * Driver for Bt848 TV tuner. WARNING, I used the Linux driver as - * documentation. + * Driver for Bt848 TV tuner. * */ #include "u.h" @@ -16,7 +15,6 @@ enum { Qdata, Qctl, Qregs, - Qdbuf, Brooktree_vid = 0x109e, Brooktree_848_did = 0x0350, @@ -26,6 +24,8 @@ enum { K = 1024, M = K * K, + Numring = 16, + ntsc_rawpixels = 910, ntsc_sqpixels = 780, // Including blanking & inactive ntsc_hactive = 640, @@ -75,7 +75,8 @@ enum { capctl_captureeven = 1 << 0, vbipacksize = 0x190, // 0E0 - intstat_i2crack = 1 << 25, // 100 + intstat_riscstatshift = 28, // 100 + intstat_i2crack = 1 << 25, intstat_scerr = 1 << 19, intstat_ocerr = 1 << 18, intstat_fbus = 1 << 12, @@ -112,6 +113,8 @@ enum { riscsync_vre = fifo_vre << 0, riscsync_vro = fifo_vro << 0, riscsync_fm1 = fifo_fm1 << 0, + risclabelshift_set = 16, + risclabelshift_reset = 20, }; typedef struct { @@ -202,21 +205,28 @@ typedef struct { ushort offs; } Tuner; +typedef struct { + ulong *fstart; + ulong *fjmp; + uchar *fbase; +} Frame; + typedef struct { Lock; Bt848 *bt848; Variant *variant; Tuner *tuner; Pcidev *pci; - ulong *program; // Current DMA program uchar i2ctuneraddr; - uchar i2ccmd; // I2C command - int board; // What board is this? + uchar i2ccmd; // I2C command + int board; // What board is this? - uchar *dbuf; + Ref fref; // Copying images? + int nframes; // Number of frames to capture. + Frame *frames; // DMA program + int lframe; // Last frame DMAed } Tv; -// Tuner related. enum { TemicPAL = 0, PhilipsPAL, @@ -260,12 +270,14 @@ static Tuner tuners[] = { enum { CMvstart, + CMvgastart, CMvstop, CMchannel, }; static Cmdtab tvctlmsg[] = { - CMvstart, "vstart", 3, + CMvstart, "vstart", 2, + CMvgastart, "vgastart", 3, CMvstop, "vstop", 1, CMchannel, "channel", 3, }; @@ -275,7 +287,6 @@ static Dirtab tvtab[]={ "tv", { Qdata, 0 }, 0, 0600, "tvctl", { Qctl, 0 }, 0, 0600, "tvregs", { Qregs, 0 }, 0, 0400, - "tvdbuf", { Qdbuf, 0 }, 0, 0400, }; static Variant variant[] = { @@ -292,9 +303,11 @@ static Tv *tv; static int i2cread(Tv *, uchar, uchar *); static int i2cwrite(Tv *, uchar, uchar, uchar, int); static void tvinterrupt(Ureg *, Tv *); -static void vstart(Tv *, ulong, int); +static void vgastart(Tv *, ulong, int); +static void vstart(Tv *, int, int, int, int); static void vstop(Tv *); static void frequency(Tv *, int, int); +static int getbpp(Tv *); static void tvinit(void) @@ -302,9 +315,6 @@ tvinit(void) Pcidev *pci; ulong intmask; - if (!getconf("tv0")) - return; - // Test for a triton memory controller. intmask = 0; if (pcimatch(nil, Intel_vid, Intel_82437_did)) @@ -435,9 +445,6 @@ tvinit(void) intrenable(pci->intl, (void (*)(Ureg *, void *))tvinterrupt, tv, pci->tbdf, "tv"); - - tv->dbuf = (uchar *)malloc(ntsc_hactive * ntsc_vactive * sizeof(ushort)); - memset(tv->dbuf, 0, ntsc_hactive * ntsc_vactive * sizeof(ushort)); } } @@ -462,7 +469,15 @@ tvstat(Chan *c, uchar *db, int n) static Chan* tvopen(Chan *c, int omode) { - return devopen(c, omode, tvtab, nelem(tvtab), devgen); + switch ((int)c->qid.path) { + case Qdir: + return devopen(c, omode, tvtab, nelem(tvtab), devgen); + } + + c->mode = openmode(omode); + c->flag |= COPEN; + c->offset = 0; + return c; } static void @@ -475,15 +490,49 @@ tvread(Chan *c, void *a, long n, vlong offset) static char regs[10 * K]; static int regslen; char *e, *p; - int nbytes; USED(offset); switch((int)c->qid.path) { case Qdir: return devdirread(c, a, n, tvtab, nelem(tvtab), devgen); - case Qdata: - error(Eio); + + case Qdata: { + uchar *src; + int bpf, nb; + + bpf = ntsc_hactive * ntsc_vactive * getbpp(tv); + + if (offset >= bpf) + return 0; + + nb = n; + if (offset + nb > bpf) + nb = bpf - offset; + + ilock(tv); + if (tv->frames == nil || tv->lframe >= tv->nframes) { + iunlock(tv); + return 0; + } + + src = tv->frames[tv->lframe].fbase; + incref(&tv->fref); + iunlock(tv); + + memmove(a, src + offset, nb); + decref(&tv->fref); + return nb; + } + + case Qctl: { + char str[128]; + + snprint(str, sizeof str, "%dx%dx%d\n", + ntsc_hactive, ntsc_vactive, getbpp(tv)); + return readstr(offset, a, n, str); + } + case Qregs: if (offset == 0) { Bt848 *bt848 = tv->bt848; @@ -503,20 +552,6 @@ tvread(Chan *c, void *a, long n, vlong offset) return readstr(offset, a, n, ®s[offset]); - case Qdbuf: - if (offset > ntsc_hactive * ntsc_vactive * sizeof(ushort)) { - memset(tv->dbuf, 0xaa, - ntsc_hactive * ntsc_vactive * sizeof(ushort)); - return 0; - } - - if (offset + n > ntsc_hactive * ntsc_vactive * sizeof(ushort)) - nbytes = ntsc_hactive * ntsc_vactive * sizeof(ushort) - offset; - else - nbytes = n; - memmove(a, tv->dbuf + offset, nbytes); - return nbytes; - default: n=0; break; @@ -540,12 +575,19 @@ tvwrite(Chan *c, void *a, long n, vlong) ct = lookupcmd(cb, tvctlmsg, nelem(tvctlmsg)); switch (ct->index) { case CMvstart: - vstart(tv, strtoul(cb->f[1], (char **)nil, 0), + vstart(tv, (int)strtol(cb->f[1], (char **)nil, 0), + ntsc_hactive, ntsc_vactive, ntsc_hactive); + 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)); @@ -585,9 +627,18 @@ static void tvinterrupt(Ureg *, Tv *tv) { Bt848 *bt848 = tv->bt848; - ulong status; - while ((status = bt848->intstat & bt848->intmask) != 0) { + while (1) { + ulong status; + uchar fnum; + + status = bt848->intstat; + fnum = (status >> intstat_riscstatshift) & 0xf; + status &= bt848->intmask; + + if (status == 0) + break; + bt848->intstat = status; if ((status & intstat_fmtchg) == intstat_fmtchg) { @@ -613,7 +664,7 @@ tvinterrupt(Ureg *, Tv *tv) } if ((status & intstat_risci) == intstat_risci) { - iprint("int: risci\n"); + tv->lframe = fnum; status &= ~intstat_risci; } @@ -692,17 +743,16 @@ i2cwrite(Tv *tv, uchar off, uchar d1, uchar d2, int both) return 1; } - static ulong * -riscprogram(ulong paddr, int stride, int bpp) +riscframe(ulong paddr, int fnum, int w, int h, int stride, ulong **lastjmp) { ulong *p, *pbase; int i; - pbase = p = (ulong *)malloc((ntsc_vactive + 5) * 2 * sizeof(ulong)); + pbase = p = (ulong *)malloc((h + 6) * 2 * sizeof(ulong)); assert(p); - assert(ntsc_hactive * bpp <= 0x7FF); + assert(w <= 0x7FF); *p++ = riscsync | riscsync_resync | riscsync_vre; *p++ = 0; @@ -710,9 +760,9 @@ riscprogram(ulong paddr, int stride, int bpp) *p++ = riscsync | riscsync_fm1; *p++ = 0; - for (i = 0; i != ntsc_vactive / 2; i++) { - *p++ = riscwrite | ntsc_hactive * bpp | riscwrite_sol | riscwrite_eol; - *p++ = paddr + i * 2 * stride * bpp; + for (i = 0; i != h / 2; i++) { + *p++ = riscwrite | w | riscwrite_sol | riscwrite_eol; + *p++ = paddr + i * 2 * stride; } *p++ = riscsync | riscsync_resync | riscsync_vro; @@ -721,85 +771,129 @@ riscprogram(ulong paddr, int stride, int bpp) *p++ = riscsync | riscsync_fm1; *p++ = 0; - for (i = 0; i != ntsc_vactive / 2; i++) { - *p++ = riscwrite | ntsc_hactive * bpp | riscwrite_sol | riscwrite_eol; - *p++ = paddr + (i * 2 + 1) * stride * bpp; + for (i = 0; i != h / 2; i++) { + *p++ = riscwrite | w | riscwrite_sol | riscwrite_eol; + *p++ = paddr + (i * 2 + 1) * stride; } - *p++ = riscjmp; - *p++ = PADDR(pbase); - USED(p); + // 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 void -vstart(Tv *tv, ulong paddr, int stride) +vactivate(Tv *tv, Frame *frames, int nframes) { Bt848 *bt848 = tv->bt848; - ulong *program, cfmt; - int bpp; - - cfmt = bt848->colorfmt; - bpp = -1; - switch (cfmt) { - case colorfmt_rgb16: - bpp = 2; - break; - default: - panic("render: Unsupport color format\n"); - } - - program = riscprogram(paddr, stride, bpp); -// program = riscprogram(PADDR(tv->dbuf), ntsc_hactive * bpp, bpp); ilock(tv); - if (waserror()) { + if (tv->frames) { iunlock(tv); - free(program); - nexterror(); - } - - if (tv->program) error(Einuse); + } + poperror(); - if (cfmt != bt848->colorfmt) - error(Eio); + tv->frames = frames; + tv->nframes = nframes; - tv->program = program; - bt848->riscstrtadd = PADDR(tv->program); + bt848->riscstrtadd = PADDR(tv->frames[0].fstart); bt848->capctl |= capctl_captureodd|capctl_captureeven; bt848->gpiodmactl |= gpiodmactl_fifoenable; bt848->gpiodmactl |= gpiodmactl_riscenable; - poperror(); iunlock(tv); } +static void +vstart(Tv *tv, int nframes, int w, int h, int stride) +{ + Frame *frames; + int bpp, i, bpf; + + if (nframes >= 0x10) + error(Ebadarg); + + bpp = getbpp(tv); + bpf = w * h * bpp; + + // 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); + + frames[i].fstart = riscframe(PADDR(frames[i].fbase), i, + w * bpp, h, stride * bpp, + &frames[i].fjmp); + } + + 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 void +vgastart(Tv *tv, ulong paddr, int stride) +{ + Frame *frame; + + frame = (Frame *)malloc(sizeof(Frame)); + assert(frame); + if (waserror()) { + free(frame); + nexterror(); + } + + frame->fbase = nil; + frame->fstart = + riscframe(paddr, 0, ntsc_hactive * getbpp(tv), ntsc_vactive, + stride * getbpp(tv), + &frame->fjmp); + *frame->fjmp = PADDR(frame->fstart); + + vactivate(tv, frame, 1); +} + static void vstop(Tv *tv) { Bt848 *bt848 = tv->bt848; ilock(tv); - if (waserror()) { - - if (tv->program) - free(tv->program); + if (tv->fref.ref > 0) { iunlock(tv); - nexterror(); + error(Einuse); } - if (tv->program) { + if (tv->frames) { + int i; + bt848->gpiodmactl &= ~gpiodmactl_riscenable; bt848->gpiodmactl &= ~gpiodmactl_fifoenable; bt848->capctl &= ~(capctl_captureodd|capctl_captureeven); - free(tv->program); - tv->program = nil; + for (i = 0; i != tv->nframes; i++) + if (tv->frames[i].fbase) + free(tv->frames[i].fbase); + free(tv->frames); + tv->frames = nil; } - - poperror(); iunlock(tv); } @@ -852,3 +946,16 @@ frequency(Tv *tv, int channel, int finetune) error(Eio); } +static int +getbpp(Tv *tv) +{ + switch (tv->bt848->colorfmt) { + case colorfmt_rgb16: + return 2; + default: + error("getbpp: Unsupport color format\n"); + } + return -1; +} + +