| plan 9 kernel history: overview | file list | diff list |
2001/1027/pc/devlml.c (diff list | history)
| pc/devlml.c on 1999/0422 | ||
| 1999/0422 | #include "u.h" #include "../port/lib.h" #include "mem.h" #include "dat.h" #include "fns.h" #include "../port/error.h" #include "io.h" #include "devlml.h" | |
| 1999/0520 | static void * pciPhysBaseAddr; static ulong pciBaseAddr; static Pcidev * pcidev; | |
| 1999/0515 | ||
| 2001/1012 | #define DBGREAD 0x01 #define DBGWRIT 0x02 | |
| 1999/0526 | #define DBGINTR 0x04 #define DBGINTS 0x08 | |
| 1999/0520 | ||
| 2001/0527 | int debug = -1; | |
| 1999/0520 | ||
| 1999/0422 | // Lml 22 driver enum{ | |
| 1999/0513 | Qdir, | |
| 1999/0610 | Qjpg, // Qraw, | |
| 1999/0422 | }; | |
| 1999/0513 | static Dirtab lmldir[]={ | |
| 2001/0630 | ".", {Qdir, 0, QTDIR}, 0, DMDIR|0555, "lmljpg", {Qjpg}, 0, 0444, // "lmlraw", {Qraw}, 0, 0444, | |
| 1999/0422 | }; | |
| 1999/0610 | static CodeData * codeData; | |
| 1999/0422 | ||
| 1999/0610 | static ulong jpgframeno; //static ulong rawframeno; //static FrameHeader rawheader; static FrameHeader jpgheader[NBUF] = { { MRK_SOI, MRK_APP3, (sizeof(FrameHeader)-4) << 8, { 'L', 'M', 'L', '\0'}, -1, 0, 0, 0, 0 }, { MRK_SOI, MRK_APP3, (sizeof(FrameHeader)-4) << 8, { 'L', 'M', 'L', '\0'}, -1, 0, 0, 0, 0 }, { MRK_SOI, MRK_APP3, (sizeof(FrameHeader)-4) << 8, { 'L', 'M', 'L', '\0'}, -1, 0, 0, 0, 0 }, { MRK_SOI, MRK_APP3, (sizeof(FrameHeader)-4) << 8, { 'L', 'M', 'L', '\0'}, -1, 0, 0, 0, 0 } }; | |
| 1999/0513 | int frameNo; | |
| 2001/1027 | Rendez sleepjpg; | |
| 1999/0610 | //Rendez sleepraw; | |
| 1999/0513 | int singleFrame; | |
| 1999/0610 | int jpgopens; //int rawopens; | |
| 1999/0424 | ||
| 1999/0525 | #define writel(v, a) *(ulong *)(a) = (v) #define readl(a) *(ulong*)(a) | |
| 1999/0515 | ||
| 1999/0423 | static int | |
| 1999/0526 | getbuffer(void){ static last = NBUF-1; int l = last; | |
| 1999/0423 | ||
| 1999/0526 | for (;;) { last = (last+1) % NBUF; if (codeData->statCom[last] & STAT_BIT) return last; if (last == l) | |
| 1999/0610 | sleep(&sleepjpg, return0, 0); | |
| 1999/0423 | } | |
| 1999/0526 | return 0; | |
| 1999/0423 | } | |
| 1999/0526 | static long | |
| 1999/0610 | jpgread(Chan *, void *va, long nbytes, vlong) { int bufno; | |
| 1999/0423 | ||
| 1999/0610 | // reads should be of size 1 or sizeof(FrameHeader) // Frameno is the number of the buffer containing the data bufno = getbuffer(); if (nbytes == sizeof(FrameHeader)) { memmove(va, &jpgheader[bufno], sizeof jpgheader[bufno]); return sizeof jpgheader[bufno]; } if (nbytes == 1) { *(char *)va = bufno; return 1; } return 0; | |
| 1999/0424 | } | |
| 1999/0610 | /* static long rawread(Chan *, void *va, long nbytes, vlong) { // reads should be at least sizeof(FrameHeader) long // Frameno is the number of the buffer containing the data if (nbytes < sizeof(FrameHeader)) return 0; sleep(&sleepraw, return0, 0); memmove(va, &rawheader, sizeof rawheader); return sizeof rawheader; } */ | |
| 1999/0423 | static void lmlintr(Ureg *, void *); static void | |
| 1999/0610 | prepbuf(void) { int i; for (i = 0; i < NBUF; i++) { codeData->statCom[i] = PADDR(&(codeData->fragdesc[i])); codeData->fragdesc[i].addr = PADDR(&(codeData->frag[i])); // Length is in double words, in position 1..20 codeData->fragdesc[i].leng = ((sizeof codeData->frag[i]) >> 1) | FRAGM_FINAL_B; } } static void | |
| 1999/0513 | lmlreset(void) | |
| 1999/0422 | { | |
| 1999/0522 | Physseg segbuf; Physseg segreg; | |
| 1999/0527 | Physseg seggrab; | |
| 1999/0422 | ulong regpa; | |
| 1999/0525 | ulong cdsize; | |
| 1999/0529 | void *grabbuf; | |
| 1999/0527 | ulong grablen; | |
| 2001/1026 | ISAConf isa; | |
| 1999/0422 | ||
| 2001/1012 | if(isaconfig("lml", 0, &isa) == 0) { if (debug) print("lml not in plan9.ini\n"); return; } | |
| 1999/0423 | pcidev = pcimatch(nil, PCI_VENDOR_ZORAN, PCI_DEVICE_ZORAN_36067); if (pcidev == nil) { return; } | |
| 1999/0529 | cdsize = CODEDATASIZE; | |
| 2001/1027 | codeData = (CodeData*)(((ulong)xalloc(cdsize+ BY2PG) + BY2PG-1) & ~(BY2PG-1)); | |
| 1999/0422 | if (codeData == nil) { | |
| 2001/1019 | print("devlml: xalloc(%lux, %ux, 0)\n", cdsize, BY2PG); | |
| 1999/0422 | return; } | |
| 1999/0529 | grablen = GRABDATASIZE; | |
| 2001/1027 | grabbuf = (void*)(((ulong)xalloc(grablen+ BY2PG) + BY2PG-1) & ~(BY2PG-1)); | |
| 1999/0529 | if (grabbuf == nil) { | |
| 2001/1019 | print("devlml: xalloc(%lux, %ux, 0)\n", grablen, BY2PG); | |
| 1999/0527 | return; } | |
| 2001/1026 | print("Installing Motion JPEG driver %s, irq %d\n", MJPG_VERSION, pcidev->intl); | |
| 1999/0527 | print("MJPG buffer at 0x%.8lux, size 0x%.8lux\n", codeData, cdsize); | |
| 1999/0529 | print("Grab buffer at 0x%.8lux, size 0x%.8lux\n", grabbuf, grablen); | |
| 1999/0422 | // Get access to DMA memory buffer | |
| 1999/0529 | codeData->pamjpg = PADDR(codeData->statCom); codeData->pagrab = PADDR(grabbuf); | |
| 1999/0422 | ||
| 1999/0610 | prepbuf(); | |
| 1999/0423 | pciPhysBaseAddr = (void *)(pcidev->mem[0].bar & ~0x0F); | |
| 1999/0422 | ||
| 1999/0513 | print("zr36067 found at 0x%.8lux", pciPhysBaseAddr); | |
| 1999/0422 | ||
| 1999/0423 | regpa = upamalloc(pcidev->mem[0].bar & ~0x0F, pcidev->mem[0].size, 0); | |
| 1999/0422 | if (regpa == 0) { print("lml: failed to map registers\n"); return; } | |
| 1999/0423 | pciBaseAddr = (ulong)KADDR(regpa); | |
| 1999/0513 | print(", mapped at 0x%.8lux\n", pciBaseAddr); | |
| 1999/0422 | ||
| 1999/0522 | memset(&segbuf, 0, sizeof(segbuf)); segbuf.attr = SG_PHYSICAL; | |
| 2001/0630 | kstrdup(&segbuf.name, "lmlmjpg"); | |
| 1999/0522 | segbuf.pa = PADDR(codeData); | |
| 1999/0525 | segbuf.size = cdsize; if (addphysseg(&segbuf) == -1) { print("lml: physsegment: lmlmjpg\n"); return; } | |
| 1999/0522 | memset(&segreg, 0, sizeof(segreg)); segreg.attr = SG_PHYSICAL; | |
| 2001/0630 | kstrdup(&segreg.name, "lmlregs"); | |
| 1999/0522 | segreg.pa = (ulong)regpa; segreg.size = pcidev->mem[0].size; | |
| 1999/0525 | if (addphysseg(&segreg) == -1) { | |
| 1999/0527 | print("lml: physsegment: lmlregs\n"); return; } memset(&seggrab, 0, sizeof(seggrab)); seggrab.attr = SG_PHYSICAL; | |
| 2001/0630 | kstrdup(&seggrab.name, "lmlgrab"); | |
| 1999/0529 | seggrab.pa = PADDR(grabbuf); | |
| 1999/0527 | seggrab.size = grablen; if (addphysseg(&seggrab) == -1) { print("lml: physsegment: lmlgrab\n"); | |
| 1999/0525 | return; } | |
| 1999/0601 | // Interrupt handler | |
| 1999/0819 | intrenable(pcidev->intl, lmlintr, nil, pcidev->tbdf, "lml"); | |
| 1999/0601 | ||
| 1999/0529 | return; | |
| 1999/0422 | } static Chan* | |
| 1999/0513 | lmlattach(char *spec) | |
| 1999/0422 | { return devattach('V', spec); } | |
| 2001/0630 | static Walkqid* lmlwalk(Chan *c, Chan *nc, char **name, int nname) | |
| 1999/0422 | { | |
| 2001/0630 | return devwalk(c, nc, name, nname, lmldir, nelem(lmldir), devgen); | |
| 1999/0422 | } | |
| 2001/0630 | static int lmlstat(Chan *c, uchar *db, int n) | |
| 1999/0422 | { | |
| 2001/0630 | return devstat(c, db, n, lmldir, nelem(lmldir), devgen); | |
| 1999/0422 | } static Chan* | |
| 1999/0518 | lmlopen(Chan *c, int omode) { | |
| 1999/0517 | ||
| 1999/0422 | c->aux = 0; | |
| 2001/0630 | switch((ulong)c->qid.path){ | |
| 1999/0610 | case Qjpg: | |
| 1999/0601 | // allow one open | |
| 1999/0610 | if (jpgopens) | |
| 1999/0424 | error(Einuse); | |
| 1999/0610 | jpgopens = 1; jpgframeno = 0; prepbuf(); | |
| 1999/0422 | break; | |
| 1999/0610 | /* case Qraw: // allow one open if (rawopens) error(Einuse); rawopens = 1; rawframeno = 0; break; */ | |
| 1999/0422 | } | |
| 1999/0513 | return devopen(c, omode, lmldir, nelem(lmldir), devgen); | |
| 1999/0422 | } static void | |
| 1999/0518 | lmlclose(Chan *c) { | |
| 2001/0630 | switch((ulong)c->qid.path){ | |
| 1999/0610 | case Qjpg: jpgopens = 0; break; /* case Qraw: rawopens = 0; break; */ | |
| 1999/0422 | } } static long | |
| 1999/0513 | lmlread(Chan *c, void *va, long n, vlong voff) { | |
| 1999/0424 | uchar *buf = va; | |
| 1999/0513 | long off = voff; | |
| 1999/0423 | ||
| 2001/0630 | switch((ulong)c->qid.path){ | |
| 1999/0513 | case Qdir: return devdirread(c, (char *)buf, n, lmldir, nelem(lmldir), devgen); | |
| 1999/0610 | case Qjpg: return jpgread(c, buf, n, off); /* case Qraw: return rawread(c, buf, n, off); */ | |
| 1999/0422 | } } static long | |
| 1999/0601 | lmlwrite(Chan *, void *, long, vlong) { | |
| 1999/0423 | ||
| 1999/0601 | error(Eperm); return 0; | |
| 1999/0422 | } | |
| 1999/0513 | Dev lmldevtab = { | |
| 1999/0422 | 'V', "video", | |
| 1999/0513 | lmlreset, | |
| 1999/0422 | devinit, | |
| 1999/0513 | lmlattach, lmlwalk, lmlstat, lmlopen, | |
| 1999/0422 | devcreate, | |
| 1999/0513 | lmlclose, lmlread, | |
| 1999/0422 | devbread, | |
| 1999/0513 | lmlwrite, | |
| 1999/0422 | devbwrite, devremove, devwstat, }; static void | |
| 1999/0424 | lmlintr(Ureg *, void *) { | |
| 1999/0610 | ulong fstart, fno; | |
| 1999/0520 | ulong flags = readl(pciBaseAddr+INTR_STAT); | |
| 1999/0424 | // Reset all interrupts from 067 | |
| 1999/0520 | writel(0xff000000, pciBaseAddr + INTR_STAT); | |
| 1999/0423 | ||
| 1999/0520 | if(flags & INTR_JPEGREP) { | |
| 1999/0610 | vlong thetime; | |
| 2000/0716 | if(debug&(DBGINTR)) print("MjpgDrv_intrHandler stat=0x%.8lux\n", flags); | |
| 1999/0610 | fstart = jpgframeno & 0x00000003; for (;;) { jpgframeno++; fno = jpgframeno & 0x00000003; if (codeData->statCom[fno] & STAT_BIT) break; if (fno == fstart) { if (debug & DBGINTR) print("Spurious lml jpg intr?\n"); return; } } thetime = todget(nil); jpgheader[fno].sec = (ulong)(thetime / 1000000000LL); | |
| 1999/0909 | jpgheader[fno].nsec = (ulong)(thetime % 1000000000LL); | |
| 1999/0610 | jpgheader[fno].frameSize = (codeData->statCom[fno] & 0x00ffffff) >> 1; jpgheader[fno].frameSeqNo = codeData->statCom[fno] >> 24; jpgheader[fno].frameNo = jpgframeno; wakeup(&sleepjpg); | |
| 1999/0515 | } | |
| 1999/0424 | return; | |
| 1999/0422 | } | |