diff options
Diffstat (limited to 'os/pc/devmpeg.c')
| -rw-r--r-- | os/pc/devmpeg.c | 1063 |
1 files changed, 1063 insertions, 0 deletions
diff --git a/os/pc/devmpeg.c b/os/pc/devmpeg.c new file mode 100644 index 00000000..038cfa6c --- /dev/null +++ b/os/pc/devmpeg.c @@ -0,0 +1,1063 @@ +/* + * Boffin MPEG decoder + */ +#include "u.h" +#include "../port/lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "../port/error.h" +#include "zoran.h" +#include "crystal.h" +#include "io.h" + +enum +{ + + CPUACCCTRL = 0x20, /* Trident Window Chip control registers */ + CPUACCMD = 0x21, + BNKADR = 0x22, + SYSCONFIG = 0x23, + VGACOMP = 0x24, + VGAMASK = 0x25, + VIDCOMPL = 0x26, + VIDCOMPH = 0x27, + MOS = 0x28, + DISPCTRL = 0x29, + CAPCTRL = 0x2a, + OVLKT = 0x2b, + OVLWINHSTRT = 0x2c, + OVLWINVSTRT = 0x2d, + OVLWINHEND = 0x2e, + OVLWINVEND = 0x2f, + RESERVED1 = 0x30, + RESERVED2 = 0x31, + DISPWINVSTRT1 = 0x32, + DISPWINVSTRT2 = 0x33, + DISPWINVEND = 0x34, + DISPWINHSTRT1 = 0x35, + DISPWINHSTRT2 = 0x36, + DISPWINHEND = 0x37, + CAPWINVSTRT = 0x38, + CAPWINHSTRT = 0x39, + CAPWINVMF = 0x3a, + CAPWINHMF = 0x3b, + RESERVED3 = 0x3c, + CAPMASK = 0x3d, + BNKPOLATION = 0x3e, + SYNCPOL = 0x3f, + DISPVTOTAL = 0x40, + DISPHTOTAL = 0x41, + DISPVSTRT = 0x42, + DISPVEND = 0x43, + DISPHSTRT = 0x44, + DISPHEND = 0x45, + DISPSYNCW = 0x46, + DISPCRTCCTRL = 0x47, + CAPVTOTAL = 0x48, + CAPHTOTAL = 0x49, + CAPVSTRT = 0x4a, + CAPVEND = 0x4b, + CAPHSTRT = 0x4c, + CAPHEND = 0x4d, + CAPSYNCW = 0x4e, + CAPCRTCCTRL = 0x4f, + VIDLUTDACRW = 0x50, + VIDLUTDACRW0 = (VIDLUTDACRW), + VIDLUTDACRW1 = (VIDLUTDACRW+1), + VIDLUTDACRW2 = (VIDLUTDACRW+2), + VIDLUTDACRW3 = (VIDLUTDACRW+3), + VIDLUTDACRW4 = (VIDLUTDACRW+4), + VIDLUTDACRW5 = (VIDLUTDACRW+5), + VIDLUTDACRW6 = (VIDLUTDACRW+6), + VIDLUTDACRW7 = (VIDLUTDACRW+7), + VGALUTDACRW = 0x58, + VGALUTDACRW0 = (VGALUTDACRW), + VGALUTDACRW1 = (VGALUTDACRW+1), + VGALUTDACRW2 = (VGALUTDACRW+2), + VGALUTDACRW3 = (VGALUTDACRW+3), + VGALUTDACRW4 = (VGALUTDACRW+4), + VGALUTDACRW5 = (VGALUTDACRW+5), + VGALUTDACRW6 = (VGALUTDACRW+6), + VGALUTDACRW7 = (VGALUTDACRW+7), + HZOOMF = 0x60, + VZOOMF = 0x61, + DELAY1 = 0x62, + DELAY2 = 0x63, + + TRILO = 0, + TRIHI = 1, + TRIINDEX = 2, + + SCL = 0x02, + SDA = 0x01, + I2CR = 0x2B, + SAA7110 = 0x9c, + WRITE_C = 0x00, + I2DLY = 5, +}; + +enum +{ + ZR36100 = 0x1e0, + ZRIRQ = 15, + ZRDMA = 6, + + ZRIDREG = 4, /* offset */ + ZRMACH210 = 6, /* offset */ + ZRREG0 = 8, /* offset */ + ZRREG1 = 10, /* offset */ + ZRSR = ZRREG1, /* offset */ + ZRRDY = (1<<3), + ZRIDLE = (1<<2), + ZRREG2 = 12, /* offset */ + ZRREG3 = 14, /* offset */ + + SIFwidth = 320, + SIFheight = 240, + + IDPCOUNT = 3064, + PMDPCOUNT = 2048, + SVMDPCOUNT = 2048, + + HIWAT = 2*128*1024, + DMABLK = 16384, +}; + +static struct { + int zrport; + int irq; + int dma; + int trport; +} mpegconf; + +static char Evmode[] = "video format not supported"; +static char Eaudio[] = "invalid audio layer"; +static char Earate[] = "bad audio sample rate"; + +/* Status bits depend on board revision */ +static short STDBY; +static short VIDSEL; +static short VSNIRQn; +static short INTENAn; +static short DSPBOOT; +static short DSPRST; +static short MPGRST; +static int machsr; +static int dopen; +static int started; +static int stop; +static int pause; +static int sp2br; +static int sp2cd; +static char properties[] = "video mpeg1,sif\naudio musicam,I musicam,II\n"; +static void inittrident(void); +static int initzoran(void); +static void initcrystal(void); +static void mpegintr(Ureg*, void*); +static void setwindow(int, char**); +static void freebufs(void); +static int mkbuf(char*, int); + +typedef struct Buf Buf; +struct Buf +{ + int nchar; + uchar* ptr; + Buf* link; + uchar data[1]; +}; + +static struct +{ + Lock; + int qlen; + Buf* head; + Buf* tail; + Rendez flow; +} bqueue; + +static int +zrstatus(void) +{ + return ins(mpegconf.zrport+ZRSR) & 0xf; +} + +static int +zrwaitrdy(int timo, char *msg) +{ + int i; + + for(i = 0; i < timo; i++) + if(ins(mpegconf.zrport+ZRSR) & ZRRDY) + return 0; + + print("devmpeg: device not ready %s\n", msg); + return 1; +} + +static void +zrdma(Buf *b) +{ + int n; + + n = dmasetup(mpegconf.dma, b->ptr, b->nchar, 0); + b->ptr += n; + b->nchar -= n; + bqueue.qlen -= n; +} + +static void +triwr(int reg, int val) +{ + outb(mpegconf.trport+TRIINDEX, reg); + outb(mpegconf.trport+TRILO, val); + outb(mpegconf.trport+TRIHI, val>>8); +} + +static int +trird(int reg) +{ + int v; + + outb(mpegconf.trport+TRIINDEX, reg); + v = inb(mpegconf.trport+TRILO); + v |= inb(mpegconf.trport+TRIHI)<<8; + + return v; +} + +enum +{ + Qdir, + Qdata, + Qctl, +}; +static Dirtab mpegtab[]= +{ + "mpeg", {Qdata, 0}, 0, 0666, + "mpegctl", {Qctl, 0}, 0, 0666, +}; + +static void +mpegreset(void) +{ + ISAConf isa; + + mpegconf.zrport = ZR36100; + mpegconf.irq = ZRIRQ; + mpegconf.dma = ZRDMA; + + memset(&isa, 0, sizeof(isa)); + if(isaconfig("mpeg", 0, &isa) == 0) + return; + if(isa.port) + mpegconf.zrport = isa.port; + if(isa.irq) + mpegconf.irq = isa.irq; + if(isa.dma) + mpegconf.dma = isa.dma; + dmainit(mpegconf.dma, 64*1024); + print("mpeg0: port 0x%uX, irq %d, dma %d\n", + mpegconf.zrport, mpegconf.irq, mpegconf.dma); + mpegconf.trport = mpegconf.zrport+0x100; + intrenable(VectorPIC+mpegconf.irq, mpegintr, 0, BUSUNKNOWN); +} + +static void +mpeginit(void) +{ + if(mpegconf.trport == 0) + return; + + inittrident(); + setwindow(0, 0); +} + +static Chan* +mpegattach(char *spec) +{ + if(mpegconf.trport == 0) + error(Enodev); + + return devattach('E', spec); +} + +static int +mpegwalk(Chan *c, char *name) +{ + return devwalk(c, name, mpegtab, nelem(mpegtab), devgen); +} + +static void +mpegstat(Chan *c, char *db) +{ + devstat(c, db, mpegtab, nelem(mpegtab), devgen); +} + +static Chan* +mpegopen(Chan *c, int omode) +{ + switch(c->qid.path) { + default: + break; + case Qdata: + if(dopen) + error(Einuse); + dopen = 1; + break; + } + return devopen(c, omode, mpegtab, nelem(mpegtab), devgen); +} + +static void +mpegclose(Chan *c) +{ + int i; + + switch(c->qid.path) { + default: + break; + case Qdata: + if((c->flag & COPEN) == 0) + break; + if(started) { + for(i = 0; i < 50; i++) { + if(ins(mpegconf.zrport+ZRSR) & ZRIDLE) + break; + tsleep(&up->sleep, return0, 0, 100); + } + } + if(stop != 0) + outs(mpegconf.zrport+ZRREG1, 0x1000); + microdelay(15); + outs(mpegconf.zrport+ZRREG1, 0x8000); + freebufs(); + dopen = 0; + } +} + +static long +mpegread(Chan *c, void *a, long n, ulong off) +{ + switch(c->qid.path & ~CHDIR){ + default: + error(Eperm); + case Qdir: + return devdirread(c, a, n, mpegtab, nelem(mpegtab), devgen); + case Qctl: + return readstr(off, a, n, properties); + } + return 0; +} + +#define SCALE(a, b) ((((a)<<10)/(b))-1024) +enum +{ + CWINVF = 0x3ff, + CWINHF = 0x1da, +}; + +static void +setwindow(int nf, char **field) +{ + int minx, miny, maxx, maxy, width, height; + + if(field == 0) { + minx = 0; + miny = 0; + maxx = 0; + maxy = 0; + } + else { + if(nf != 5) + error(Ebadarg); + + minx = strtoul(field[1], 0, 0); + miny = strtoul(field[2], 0, 0); + maxx = strtoul(field[3], 0, 0) + 8; + maxy = strtoul(field[4], 0, 0); + } + + triwr(OVLWINHSTRT, minx); + triwr(OVLWINVSTRT, miny); + triwr(OVLWINHEND, maxx+12); + triwr(OVLWINVEND, maxy); + + width = maxx - minx; + height = maxy - miny; + if(width >= SIFwidth) { + triwr(HZOOMF, SCALE(width, SIFwidth)); + triwr(CAPWINHMF, CWINHF); + } + else { + triwr(HZOOMF, SCALE(SIFwidth, SIFwidth)); + triwr(CAPWINHMF, width*CWINHF/SIFwidth); + } + if(height >= SIFheight) { + triwr(VZOOMF, SCALE(height, SIFheight)); + triwr(CAPWINVMF, CWINVF); + } + else { + triwr(VZOOMF, SCALE(SIFheight, SIFheight)); + triwr(CAPWINVMF, height*CWINVF/SIFheight); + } +} + +static int +mpegflow(void*) +{ + return bqueue.qlen < HIWAT || stop; +} + +static int +mkbuf(char *d, int n) +{ + Buf *b; + + b = malloc(sizeof(Buf)+n); + if(b == 0) + return 0; + + memmove(b->data, d, n); + b->ptr = b->data; + b->nchar = n; + b->link = 0; + + ilock(&bqueue); + bqueue.qlen += n; + if(bqueue.head) + bqueue.tail->link = b; + else + bqueue.head = b; + bqueue.tail = b; + iunlock(&bqueue); + + return 1; +} + +static void +freebufs(void) +{ + Buf *next; + + ilock(&bqueue); + bqueue.qlen = 0; + while(bqueue.head) { + next = bqueue.head->link; + free(bqueue.head); + bqueue.head = next; + } + iunlock(&bqueue); +} + +typedef struct Audio Audio; +struct Audio { + int rate; + int cd; + int br; +}; + +static Audio AudioclkI[] = +{ + 64000, 0x000000bb, 0x00071797, + 96000, 0x0000007d, 0x00071c71, + 128000, 0x0000005d, 0x00070de1, + 160000, 0x0000004b, 0x00071c71, + 192000, 0x0000003e, 0x00070de1, + 224000, 0x00000035, 0x00070906, + 256000, 0x0000002e, 0x0006fa76, + 288000, 0x00000029, 0x0006ff51, + 320000, 0x00000025, 0x0007042b, + 352000, 0x00000022, 0x00071797, + 384000, 0x0000001f, 0x00070de1, + 416000, 0x0000001c, 0x0006e70b, + 448000, 0x0000001a, 0x0006e70b, +}; + +static Audio AudioclkII[] = +{ + 48000, 0x000000fa, 0x00071c71, + 56000, 0x000000d6, 0x00071a04, + 64000, 0x000000bb, 0x00071797, + 80000, 0x00000096, 0x00071c71, + 96000, 0x0000007d, 0x00071c71, + 112000, 0x0000006b, 0x00071a04, + 128000, 0x0000005d, 0x00070de1, + 160000, 0x0000004b, 0x00071c71, + 192000, 0x0000003e, 0x00070de1, + 224000, 0x00000035, 0x00070906, + 256000, 0x0000002e, 0x0006fa76, + 320000, 0x00000025, 0x0007042b, + 384000, 0x0000001f, 0x00070de1, +}; + +static long +mpegwrite(Chan *c, char *a, long n, vlong) +{ + Audio *t; + int i, nf, l, x; + char buf[128], *field[10]; + + switch(c->qid.path & ~CHDIR) { + case Qctl: + if(n > sizeof(buf)-1) + n = sizeof(buf)-1; + memmove(buf, a, n); + buf[n] = '\0'; + + nf = getfields(buf, field, nelem(field), 1, " \t\n"); + if(nf < 1) + error(Ebadarg); + + if(strcmp(field[0], "stop") == 0) { + if(started == 0) + error("not started"); + if(pause) { + pause = 0; + outs(mpegconf.zrport+ZRREG1, 0x9000); + } + stop = 1; + outs(mpegconf.zrport+ZRREG1, 0x1000); + microdelay(15); + outs(mpegconf.zrport+ZRREG1, 0x8000); + wakeup(&bqueue.flow); + return n; + } + if(strcmp(field[0], "pause") == 0) { + if(started == 0) + error("not started"); + if(pause == 0) { + pause = 1; + outs(mpegconf.zrport+ZRREG1, 0x1000); + } + else { + pause = 0; + outs(mpegconf.zrport+ZRREG1, 0x9000); + } + return n; + } + if(strcmp(field[0], "window") == 0) { + setwindow(nf, field); + return n; + } + if(strcmp(field[0], "audio") == 0) { + if(nf < 3) + error(Ebadarg); + t = 0; + if(strcmp(field[1], "musicam,I") == 0) + t = AudioclkI; + else + if(strcmp(field[1], "musicam,II") == 0) + t = AudioclkII; + else + error(Eaudio); + x = strtoul(field[2], 0, 0); + for(i = 0; t[i].rate != 0; i++) { + if(t[i].rate == x) { + sp2cd = t[i].cd; + sp2br = t[i].br; + return n; + } + } + error(Earate); + } + if(strcmp(field[0], "video") == 0) { + if(nf != 3) + error(Ebadarg); + if(strcmp(field[1], "iso11172") != 0) + error(Evmode); + if(strcmp(field[2], "mpeg1,sif") != 0) + error(Evmode); + return n; + } + if(strcmp(field[0], "init") == 0) { + inittrident(); + for(i = 0; i < 3; i++) + if(initzoran() != -1) + break; + initcrystal(); + started = 0; + stop = 0; + pause = 0; + return n; + } + error(Ebadarg); + case Qdata: + if(n & 1) + error("odd write"); + + while(!mpegflow(0)) + sleep(&bqueue.flow, mpegflow, 0); + + if(stop) + error("stopped"); + + x = n; + while(x) { + l = x; + if(l > DMABLK) + l = DMABLK; + if(mkbuf(a, l) == 0) + error(Enomem); + x -= l; + a += l; + } + if(started || bqueue.qlen < (HIWAT*3)/4) + break; + + zrdma(bqueue.head); + outs(mpegconf.zrport+ZRREG1, 0x0000); + outs(mpegconf.zrport+ZRREG1, 0x0000); + started = 1; + break; + default: + error(Ebadusefd); + } + return n; +} + +Dev mpegdevtab = { + 'E', + "mpeg", + + mpegreset, + mpeginit, + mpegattach, + devdetach, + devclone, + mpegwalk, + mpegstat, + mpegopen, + devcreate, + mpegclose, + mpegread, + devbread, + mpegwrite, + devbwrite, + devremove, + devwstat, +}; + +static void +initctl(void) +{ + int boardid; + static int done; + + if(done) + return; + + boardid = ins(mpegconf.zrport+ZRIDREG); + if(boardid == 0xE3E3) { /* REV c/d */ + STDBY = 0x0000; + VIDSEL = 0x2020; + VSNIRQn = 0x1010; + INTENAn = 0x0808; + DSPBOOT = 0x0404; + DSPRST = 0x0202; + MPGRST = 0x0101; + } + else { /* REV b */ + STDBY = 0x0404; + VIDSEL = 0x1010; + VSNIRQn = 0x8080; + INTENAn = 0x4040; + DSPBOOT = 0x0202; + DSPRST = 0x0101; + MPGRST = 0x2020; + } + done = 1; + +} + +/* + * nbl (reg 0x1[ab]) was 0x0022, nblf (reg 1[cd]) was 0x0006 + */ +static uchar +zrparam[] = +{ +/* 00 */ 0xEF, 0x01, 0x01, 0x01, 0x80, 0x0E, 0x31, 0x00, +/* 08 */ 0x01, 0x60, 0x00, 0x00, 0x03, 0x5A, 0x00, 0x7A, +/* 10 */ 0x00, 0x10, 0x00, 0x08, 0x00, 0xF0, 0x00, 0x00, +/* 18 */ 0x02, 0x0D, 0x00, 0x1e, 0x00, 0x0a, 0x00, 0x02, +/* 20 */ 0x40, 0x06, 0x80, 0x00, 0x80, 0x00, 0x05, 0x9B, +/* 28 */ 0x07, 0x16, 0xFD, 0x25, 0xFE, 0xA0, 0x00, 0x00, +/* 30 */ 0x00, 0x07, 0x0d, 0xe1, 0x00, 0x00, 0x00, 0x3E, +/* 38 */ 0x00, 0x00, 0x09, 0x51, 0x00, 0x00, 0xCD, 0xFE, +/* 40 */ 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 48 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 50 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 58 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 60 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 68 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 70 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 78 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +static int +initzoran(void) +{ + int i, nbytes, zrs; + + initctl(); + freebufs(); + + machsr = DSPRST|VSNIRQn; + outs(mpegconf.zrport+ZRMACH210, machsr); + microdelay(4000); + + machsr |= STDBY; + outs(mpegconf.zrport+ZRMACH210, machsr); + microdelay(4000); + + machsr |= MPGRST; + outs(mpegconf.zrport+ZRMACH210, machsr); + microdelay(4000); + machsr &= ~MPGRST; + outs(mpegconf.zrport+ZRMACH210, machsr); + microdelay(4000); + machsr |= MPGRST; + outs(mpegconf.zrport+ZRMACH210, machsr); + microdelay(4000); + + if(zrwaitrdy(2000, "load IDP")) + return -1; + + for(i = 0; i < IDPCOUNT; i++) + outb(mpegconf.zrport+ZRREG2, zrmpeg1[i]); + + if(((zrs = zrstatus()) & 3) != 3) { +/* print("devmpeg: error loading IDP sr=%2.2ux\n", zrs); */ + USED(zrs); + return -1; + } + + if(zrwaitrdy(2000, "load PMDP")) + return -1; + + for(i = 0; i < PMDPCOUNT; i++) + outb(mpegconf.zrport+ZRREG3, zrmpeg2[i]); + + if(((zrs = zrstatus()) & 3) != 3) { +/* print("devmpeg: error loading PMDP sr=%2.2ux\n", zrs); */ + USED(zrs); + return -1; + } + + zrparam[0x36] = sp2cd>>8; + zrparam[0x37] = sp2cd>>0; + zrparam[0x31] = sp2br>>16; + zrparam[0x32] = sp2br>>8; + zrparam[0x33] = sp2br>>0; + + nbytes = 16; + for(i = 0; i < 128; i++) { + if(nbytes >= 16) { + if(zrwaitrdy(2000, "load parameters")) + return -1; + nbytes = 0; + } + outb(mpegconf.zrport+ZRREG0, zrparam[i]); + nbytes++; + } + + if(zrwaitrdy(2000, "load SVMDP")) + return -1; + + for(i = 0; i < SVMDPCOUNT; i++) + outb(mpegconf.zrport+ZRREG3, zrmpeg3s[i]); + + if(((zrs = zrstatus()) & 3) != 3) { +/* print("devmpeg: error loading SVMDP sr=%2.2ux\n", zrs); */ + USED(zrs); + return -1; + } + return 0; +} + +static struct +{ + short reg; + ushort val; +} trireg[] = +{ + 0x20, 0x0400, + 0x21, 0x00e9, + 0x22, 0x0000, + 0x23, 0x07ee, + 0x24, 0x0005, + 0x25, 0xff00, + 0x26, 0x0000, + 0x27, 0x7fff, + 0x28, 0x0004, + 0x29, 0x88a0, + 0x2a, 0x0011, + 0x2b, 0x8540, + 0x2c, 0x00c4, + 0x2d, 0x00ac, + 0x2e, 0x020f, + 0x2f, 0x019d, + 0x30, 0x00bd, + 0x31, 0x00ff, + 0x32, 0x0000, + 0x33, 0x0000, + 0x34, 0x03ff, + 0x35, 0x0000, + 0x36, 0x0000, + 0x37, 0x03ff, + 0x38, 0x0000, + 0x39, 0x0000, + 0x3a, 0x03ff, + 0x3b, 0x01da, + 0x3c, 0xe8ce, + 0x3d, 0x2ac0, + 0x3e, 0x891f, + 0x3f, 0x3e25, + 0x40, 0x03ff, + 0x41, 0x01ff, + 0x42, 0x001f, + 0x43, 0x01ff, + 0x44, 0x003b, + 0x45, 0x0186, + 0x46, 0x1d06, + 0x47, 0x1a4f, + 0x48, 0x020d, + 0x49, 0x01ad, + 0x4a, 0x001b, + 0x4b, 0x01fd, + 0x4c, 0x003a, + 0x4d, 0x034b, + 0x4e, 0x2006, + 0x4f, 0x0083, + 0x50, 0xef08, + 0x51, 0xef3a, + 0x52, 0xefff, + 0x53, 0xef08, + 0x54, 0xef08, + 0x55, 0xef15, + 0x56, 0xefc0, + 0x57, 0xef08, + 0x58, 0xefef, + 0x59, 0xefef, + 0x5a, 0xefef, + 0x5b, 0xefef, + 0x5c, 0xefef, + 0x5d, 0xefef, + 0x5e, 0xefef, + 0x5f, 0xefef, + 0x60, 0x0000, + 0x61, 0x0004, + 0x62, 0x0020, + 0x63, 0x8080, + 0x64, 0x0300, + -1 +}; + +static void +clrI2C(uchar b) +{ + uchar t; + + outb(mpegconf.trport+TRIINDEX, I2CR); + t = inb(mpegconf.trport+TRIHI); + t &= ~b; + outb(mpegconf.trport+TRIHI, t); +} + +static void +setI2C(uchar b) +{ + uchar t; + + outb(mpegconf.trport+TRIINDEX, I2CR); + t = inb(mpegconf.trport+TRIHI); + t |= b; + outb(mpegconf.trport+TRIHI, t); +} + +static void +startI2C(void) +{ + setI2C(SDA); + setI2C(SCL); + microdelay(I2DLY); + clrI2C(SDA); + microdelay(I2DLY); + clrI2C(SCL); + microdelay(I2DLY); +} + +static void +endI2C(void) +{ + clrI2C(SDA); + clrI2C(SCL); + microdelay(I2DLY); + setI2C(SCL); + microdelay(I2DLY); + setI2C(SDA); + microdelay(I2DLY); +} + +static void +wrI2Cbit(uchar b) +{ + clrI2C(SDA); + clrI2C(SCL); + microdelay(I2DLY); + if(b & 1) { + setI2C(SDA); + microdelay(I2DLY); + setI2C(SCL); + microdelay(I2DLY); + clrI2C(SCL); + microdelay(I2DLY); + clrI2C(SDA); + microdelay(I2DLY); + } + else { + setI2C(SCL); + microdelay(I2DLY); + clrI2C(SCL); + microdelay(I2DLY); + } +} + +static void +wrI2CB(unsigned char data) +{ + int i; + + for(i = 0; i < 8; i++) + wrI2Cbit(data >>(7-i)); +} + +static int +rdI2CBit(void) +{ + int bit = 1; + + setI2C(SDA); + clrI2C(SCL); + setI2C(SCL); + outb(mpegconf.trport+TRIINDEX, I2CR); + if(inb(mpegconf.trport+TRIHI) & SDA) + bit = 0; + clrI2C(SDA); + clrI2C(SCL); + + return bit; +} + +static int +wrI2CD(uchar data) +{ + int r; + ulong s; + + s = splhi(); + wrI2CB(data); + r = rdI2CBit(); + splx(s); + return r; +} + +static uchar +setupSAA7110[] = +{ + /* Digital */ + 0x4c, 0x3c, 0x0d, 0xef, 0xbd, 0xf0, 0x40, 0x03, + 0xf8, 0xf8, 0x90, 0x90, 0x00, 0x02, 0x10, 0x77, + 0x00, 0x2c, 0x40, 0x40, 0x3b, 0x10, 0xfc, 0xd2, + 0xf0, 0x80, + + /* Analog */ + 0xd9, 0x16, 0x40, 0x40, 0x80, 0x40, 0x80, 0x4f, + 0xfe, 0x01, 0xcf, 0x0f, 0x03, 0x01, 0x81, 0x0a, + 0x40, 0x35, 0x02, 0x8c, 0x03 +}; + +static void +addrI2CB(int addr, int val) +{ + ulong s; + + s = splhi(); + startI2C(); + wrI2CD(SAA7110|WRITE_C); + wrI2CD(addr); + wrI2CD(val); + endI2C(); + splx(s); +} + +static void +inittrident(void) +{ + int i; + + for(i = 0; trireg[i].reg != -1; i++) + triwr(trireg[i].reg, trireg[i].val); + + for(i = 0; i < 47; i++) + addrI2CB(i, setupSAA7110[i]); +} + +static void +initcrystal(void) +{ + int i; + static int done; + + if(done) + return; + + done = 1; + + initctl(); + + /* Reboot the Musicam decoder */ + clrI2C(SCL); + clrI2C(SDA); + machsr |= DSPRST; + outs(mpegconf.zrport+ZRMACH210, machsr); + machsr |= DSPBOOT; + outs(mpegconf.zrport+ZRMACH210, machsr); + machsr &= ~DSPRST; + outs(mpegconf.zrport+ZRMACH210, machsr); + machsr |= DSPRST; + outs(mpegconf.zrport+ZRMACH210, machsr); + machsr &= ~DSPBOOT; + outs(mpegconf.zrport+ZRMACH210, machsr); + + startI2C(); + wrI2CD(0); + for(i = 0; i < sizeof(crystal); i++ ) + wrI2CD(crystal[i]); + endI2C(); +} + +static void +mpegintr(Ureg*, void*) +{ + Buf *b; + + b = bqueue.head; + if(b == 0 || dmadone(mpegconf.dma) == 0) + return; + + dmaend(mpegconf.dma); + if(b->nchar == 0) { + bqueue.head = b->link; + free(b); + + b = bqueue.head; + if(b == 0) { + started = 0; + return; + } + } + zrdma(b); + wakeup(&bqueue.flow); +} |
