/* * This file is part of the UCB release of Plan 9. It is subject to the license * terms in the LICENSE file found in the top-level directory of this * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No * part of the UCB release of Plan 9, including this file, may be copied, * modified, propagated, or distributed except according to the terms contained * in the LICENSE file. */ /* * Lml 22 driver */#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" #define DBGREAD 0x01#define DBGWRIT 0x02#define DBGINTR 0x04#define DBGINTS 0x08#define DBGFS 0x10 int debug = DBGREAD|DBGWRIT|DBGFS; enum{ Qdir, Qctl0, Qjpg0, Qraw0, Qctl1, Qjpg1, Qraw1,}; static Dirtab lmldir[] = { ".", {Qdir, 0, QTDIR}, 0, 0555, "lml0ctl", {Qctl0}, 0, 0666, "lml0jpg", {Qjpg0}, 0, 0444, "lml0raw", {Qraw0}, 0, 0444, "lml1ctl", {Qctl1}, 0, 0666, "lml1jpg", {Qjpg1}, 0, 0444, "lml1raw", {Qraw1}, 0, 0444,}; typedef struct LML LML; struct LML { /* Hardware */ Pcidev *pcidev; ulong pciBaseAddr; /* Allocated memory */ CodeData *codedata; /* Software state */ ulong jpgframeno; int frameNo; Rendez sleepjpg; int jpgopens;} lmls[NLML]; int nlml; static FrameHeader jpgheader = { MRK_SOI, MRK_APP3, (sizeof(FrameHeader)-4) << 8, { 'L', 'M', 'L', '\0'}, -1, 0, 0, 0}; #define writel(v, a) *(ulong *)(a) = (v)#define readl(a) *(ulong*)(a) static intgetbuffer(void *x){ static last = NBUF-1; int l = last; LML *lml; lml = x; for(;;){ last = (last+1) % NBUF; if(lml->codedata->statCom[last] & STAT_BIT) return last + 1; if(last == l) return 0; }} static longjpgread(LML *lml, void *va, long nbytes, vlong, int dosleep){ int bufno; FrameHeader *jpgheader; /* * reads should be of size 1 or sizeof(FrameHeader). * Frameno is the number of the buffer containing the data. */ while((bufno = getbuffer(lml)) == 0 && dosleep) sleep(&lml->sleepjpg, getbuffer, lml); if(--bufno < 0) return 0; jpgheader = (FrameHeader*)(lml->codedata->frag[bufno].hdr+2); if(nbytes == sizeof(FrameHeader)){ memmove(va, jpgheader, sizeof(FrameHeader)); return sizeof(FrameHeader); } if(nbytes == 1){ *(char *)va = bufno; return 1; } return 0;} static void lmlintr(Ureg *, void *); static voidprepbuf(LML *lml){ int i; CodeData *cd; cd = lml->codedata; for(i = 0; i < NBUF; i++){ cd->statCom[i] = PADDR(&(cd->fragdesc[i])); cd->fragdesc[i].addr = PADDR(cd->frag[i].fb); /* Length is in double words, in position 1..20 */ cd->fragdesc[i].leng = FRAGSIZE >> 1 | FRAGM_FINAL_B; memmove(cd->frag[i].hdr+2, &jpgheader, sizeof(FrameHeader)-2); }} static voidlmlreset(void){ ulong regpa; char name[32]; void *regva; LML *lml; Pcidev *pcidev; Physseg segbuf; pcidev = nil; for(nlml = 0; nlml < NLML && (pcidev = pcimatch(pcidev, VENDOR_ZORAN, ZORAN_36067)); nlml++){ lml = &lmls[nlml]; lml->pcidev = pcidev; lml->codedata = (CodeData*)(((ulong)xalloc(Codedatasize+ BY2PG) + BY2PG-1) & ~(BY2PG-1)); if(lml->codedata == nil){ print("devlml: xalloc(%ux, %ux, 0)\n", Codedatasize, BY2PG); return; } print("Installing Motion JPEG driver %s, irq %d\n", MJPG_VERSION, pcidev->intl); print("MJPG buffer at 0x%.8p, size 0x%.8ux\n", lml->codedata, Codedatasize); /* Get access to DMA memory buffer */ lml->codedata->pamjpg = PADDR(lml->codedata->statCom); prepbuf(lml); print("zr36067 found at 0x%.8lux", pcidev->mem[0].bar & ~0x0F); regpa = pcidev->mem[0].bar & ~0x0F; regva = vmap(regpa, pcidev->mem[0].size); if(regva == 0){ print("lml: failed to map registers\n"); return; } lml->pciBaseAddr = (ulong)regva; print(", mapped at 0x%.8lux\n", lml->pciBaseAddr); memset(&segbuf, 0, sizeof(segbuf)); segbuf.attr = SG_PHYSICAL; sprint(name, "lml%d.mjpg", nlml); kstrdup(&segbuf.name, name); segbuf.pa = PADDR(lml->codedata); segbuf.size = Codedatasize; if(addphysseg(&segbuf) == -1){ print("lml: physsegment: %s\n", name); return; } memset(&segbuf, 0, sizeof(segbuf)); segbuf.attr = SG_PHYSICAL; sprint(name, "lml%d.regs", nlml); kstrdup(&segbuf.name, name); segbuf.pa = (ulong)regpa; segbuf.size = pcidev->mem[0].size; if(addphysseg(&segbuf) == -1){ print("lml: physsegment: %s\n", name); return; } /* set up interrupt handler */ intrenable(pcidev->intl, lmlintr, lml, pcidev->tbdf, "lml"); }} static Chan*lmlattach(char *spec){ if(debug&DBGFS) print("lmlattach\n"); return devattach(L'Λ', spec);} static Walkqid*lmlwalk(Chan *c, Chan *nc, char **name, int nname){ if(debug&DBGFS) print("lmlwalk\n"); return devwalk(c, nc, name, nname, lmldir, 3*nlml+1, devgen);} static intlmlstat(Chan *c, uchar *db, int n){ if(debug&DBGFS) print("lmlstat\n"); return devstat(c, db, n, lmldir, 3*nlml+1, devgen);} static Chan*lmlopen(Chan *c, int omode){ int i; LML *lml; if(debug&DBGFS) print("lmlopen\n"); if(omode != OREAD) error(Eperm); c->aux = 0; i = 0; switch((ulong)c->qid.path){ case Qctl1: i++; /* fall through */ case Qctl0: if(i >= nlml) error(Eio); break; case Qjpg1: case Qraw1: i++; /* fall through */ case Qjpg0: case Qraw0: /* allow one open */ if(i >= nlml) error(Eio); lml = lmls+i; if(lml->jpgopens) error(Einuse); lml->jpgopens = 1; lml->jpgframeno = 0; prepbuf(lml); break; } return devopen(c, omode, lmldir, 3*nlml+1, devgen);} static voidlmlclose(Chan *c){ int i; if(debug&DBGFS) print("lmlclose\n"); i = 0; switch((ulong)c->qid.path){ case Qjpg1: case Qraw1: i++; /* fall through */ case Qjpg0: case Qraw0: lmls[i].jpgopens = 0; break; }} static longlmlread(Chan *c, void *va, long n, vlong voff){ int i, len; long off = voff; uchar *buf = va; LML *lml; static char lmlinfo[1024]; i = 0; switch((ulong)c->qid.path){ case Qdir: n = devdirread(c, (char *)buf, n, lmldir, 3*nlml+1, devgen); if(debug&(DBGFS|DBGREAD)) print("lmlread %ld\n", n); return n; case Qctl1: i++; /* fall through */ case Qctl0: if(i >= nlml) error(Eio); lml = lmls+i; len = snprint(lmlinfo, sizeof lmlinfo, "lml%djpg lml%draw\nlml%d.regs 0x%lux 0x%ux\nlml%d.mjpg 0x%lux 0x%ux\n", i, i, i, lml->pcidev->mem[0].bar & ~0x0F, lml->pcidev->mem[0].size, i, PADDR(lml->codedata), Codedatasize); if(voff > len) return 0; if(n > len - voff) n = len - voff; memmove(va, lmlinfo+voff, n); return n; case Qjpg1: i++; /* fall through */ case Qjpg0: if(i >= nlml) error(Eio); return jpgread(lmls+i, buf, n, off, 1); case Qraw1: i++; /* fall through */ case Qraw0: if(i >= nlml) error(Eio); return jpgread(lmls+i, buf, n, off, 0); } return -1;} static longlmlwrite(Chan *, void *, long, vlong){ error(Eperm); return 0;} Dev lmldevtab = { L'Λ', "video", lmlreset, devinit, devshutdown, lmlattach, lmlwalk, lmlstat, lmlopen, devcreate, lmlclose, lmlread, devbread, lmlwrite, devbwrite, devremove, devwstat,}; static voidlmlintr(Ureg *, void *x){ ulong fstart, fno, flags, statcom; FrameHeader *jpgheader; LML *lml; lml = x; flags = readl(lml->pciBaseAddr+INTR_STAT); /* Reset all interrupts from 067 */ writel(0xff000000, lml->pciBaseAddr + INTR_STAT); if(flags & INTR_JPEGREP){ if(debug&DBGINTR) print("MjpgDrv_intrHandler stat=0x%.8lux\n", flags); fstart = lml->jpgframeno & 3; for(;;){ lml->jpgframeno++; fno = lml->jpgframeno & 3; if(lml->codedata->statCom[fno] & STAT_BIT) break; if(fno == fstart){ if(debug & DBGINTR) print("Spurious lml jpg intr?\n"); return; } } statcom = lml->codedata->statCom[fno]; jpgheader = (FrameHeader *)(lml->codedata->frag[fno].hdr + 2); jpgheader->frameNo = lml->jpgframeno; jpgheader->ftime = todget(nil); jpgheader->frameSize = (statcom & 0x00ffffff) >> 1; jpgheader->frameSeqNo = statcom >> 24; wakeup(&lml->sleepjpg); }}
/*
* This file is part of the UCB release of Plan 9. It is subject to the license
* terms in the LICENSE file found in the top-level directory of this
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
* part of the UCB release of Plan 9, including this file, may be copied,
* modified, propagated, or distributed except according to the terms contained
* in the LICENSE file.
*/
/*
* Lml 22 driver
*/
#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"
#define DBGREAD 0x01
#define DBGWRIT 0x02
#define DBGINTR 0x04
#define DBGINTS 0x08
#define DBGFS 0x10
int debug = DBGREAD|DBGWRIT|DBGFS;
enum{
Qdir,
Qctl0,
Qjpg0,
Qraw0,
Qctl1,
Qjpg1,
Qraw1,
};
static Dirtab lmldir[] = {
".", {Qdir, 0, QTDIR}, 0, 0555,
"lml0ctl", {Qctl0}, 0, 0666,
"lml0jpg", {Qjpg0}, 0, 0444,
"lml0raw", {Qraw0}, 0, 0444,
"lml1ctl", {Qctl1}, 0, 0666,
"lml1jpg", {Qjpg1}, 0, 0444,
"lml1raw", {Qraw1}, 0, 0444,
};
typedef struct LML LML;
struct LML {
/* Hardware */
Pcidev *pcidev;
ulong pciBaseAddr;
/* Allocated memory */
CodeData *codedata;
/* Software state */
ulong jpgframeno;
int frameNo;
Rendez sleepjpg;
int jpgopens;
} lmls[NLML];
int nlml;
static FrameHeader jpgheader = {
MRK_SOI, MRK_APP3, (sizeof(FrameHeader)-4) << 8,
{ 'L', 'M', 'L', '\0'},
-1, 0, 0, 0
};
#define writel(v, a) *(ulong *)(a) = (v)
#define readl(a) *(ulong*)(a)
static int
getbuffer(void *x)
{
static last = NBUF-1;
int l = last;
LML *lml;
lml = x;
for(;;){
last = (last+1) % NBUF;
if(lml->codedata->statCom[last] & STAT_BIT)
return last + 1;
if(last == l)
return 0;
}
}
static long
jpgread(LML *lml, void *va, long nbytes, vlong, int dosleep)
{
int bufno;
FrameHeader *jpgheader;
/*
* reads should be of size 1 or sizeof(FrameHeader).
* Frameno is the number of the buffer containing the data.
*/
while((bufno = getbuffer(lml)) == 0 && dosleep)
sleep(&lml->sleepjpg, getbuffer, lml);
if(--bufno < 0)
return 0;
jpgheader = (FrameHeader*)(lml->codedata->frag[bufno].hdr+2);
if(nbytes == sizeof(FrameHeader)){
memmove(va, jpgheader, sizeof(FrameHeader));
return sizeof(FrameHeader);
}
if(nbytes == 1){
*(char *)va = bufno;
return 1;
}
return 0;
}
static void lmlintr(Ureg *, void *);
static void
prepbuf(LML *lml)
{
int i;
CodeData *cd;
cd = lml->codedata;
for(i = 0; i < NBUF; i++){
cd->statCom[i] = PADDR(&(cd->fragdesc[i]));
cd->fragdesc[i].addr = PADDR(cd->frag[i].fb);
/* Length is in double words, in position 1..20 */
cd->fragdesc[i].leng = FRAGSIZE >> 1 | FRAGM_FINAL_B;
memmove(cd->frag[i].hdr+2, &jpgheader, sizeof(FrameHeader)-2);
}
}
static void
lmlreset(void)
{
ulong regpa;
char name[32];
void *regva;
LML *lml;
Pcidev *pcidev;
Physseg segbuf;
pcidev = nil;
for(nlml = 0; nlml < NLML && (pcidev = pcimatch(pcidev, VENDOR_ZORAN,
ZORAN_36067)); nlml++){
lml = &lmls[nlml];
lml->pcidev = pcidev;
lml->codedata = (CodeData*)(((ulong)xalloc(Codedatasize+ BY2PG)
+ BY2PG-1) & ~(BY2PG-1));
if(lml->codedata == nil){
print("devlml: xalloc(%ux, %ux, 0)\n", Codedatasize, BY2PG);
return;
}
print("Installing Motion JPEG driver %s, irq %d\n",
MJPG_VERSION, pcidev->intl);
print("MJPG buffer at 0x%.8p, size 0x%.8ux\n", lml->codedata,
Codedatasize);
/* Get access to DMA memory buffer */
lml->codedata->pamjpg = PADDR(lml->codedata->statCom);
prepbuf(lml);
print("zr36067 found at 0x%.8lux", pcidev->mem[0].bar & ~0x0F);
regpa = pcidev->mem[0].bar & ~0x0F;
regva = vmap(regpa, pcidev->mem[0].size);
if(regva == 0){
print("lml: failed to map registers\n");
return;
}
lml->pciBaseAddr = (ulong)regva;
print(", mapped at 0x%.8lux\n", lml->pciBaseAddr);
memset(&segbuf, 0, sizeof(segbuf));
segbuf.attr = SG_PHYSICAL;
sprint(name, "lml%d.mjpg", nlml);
kstrdup(&segbuf.name, name);
segbuf.pa = PADDR(lml->codedata);
segbuf.size = Codedatasize;
if(addphysseg(&segbuf) == -1){
print("lml: physsegment: %s\n", name);
return;
}
memset(&segbuf, 0, sizeof(segbuf));
segbuf.attr = SG_PHYSICAL;
sprint(name, "lml%d.regs", nlml);
kstrdup(&segbuf.name, name);
segbuf.pa = (ulong)regpa;
segbuf.size = pcidev->mem[0].size;
if(addphysseg(&segbuf) == -1){
print("lml: physsegment: %s\n", name);
return;
}
/* set up interrupt handler */
intrenable(pcidev->intl, lmlintr, lml, pcidev->tbdf, "lml");
}
}
static Chan*
lmlattach(char *spec)
{
if(debug&DBGFS)
print("lmlattach\n");
return devattach(L'Λ', spec);
}
static Walkqid*
lmlwalk(Chan *c, Chan *nc, char **name, int nname)
{
if(debug&DBGFS)
print("lmlwalk\n");
return devwalk(c, nc, name, nname, lmldir, 3*nlml+1, devgen);
}
static int
lmlstat(Chan *c, uchar *db, int n)
{
if(debug&DBGFS)
print("lmlstat\n");
return devstat(c, db, n, lmldir, 3*nlml+1, devgen);
}
static Chan*
lmlopen(Chan *c, int omode)
{
int i;
LML *lml;
if(debug&DBGFS)
print("lmlopen\n");
if(omode != OREAD)
error(Eperm);
c->aux = 0;
i = 0;
switch((ulong)c->qid.path){
case Qctl1:
i++;
/* fall through */
case Qctl0:
if(i >= nlml)
error(Eio);
break;
case Qjpg1:
case Qraw1:
i++;
/* fall through */
case Qjpg0:
case Qraw0:
/* allow one open */
if(i >= nlml)
error(Eio);
lml = lmls+i;
if(lml->jpgopens)
error(Einuse);
lml->jpgopens = 1;
lml->jpgframeno = 0;
prepbuf(lml);
break;
}
return devopen(c, omode, lmldir, 3*nlml+1, devgen);
}
static void
lmlclose(Chan *c)
{
int i;
if(debug&DBGFS)
print("lmlclose\n");
i = 0;
switch((ulong)c->qid.path){
case Qjpg1:
case Qraw1:
i++;
/* fall through */
case Qjpg0:
case Qraw0:
lmls[i].jpgopens = 0;
break;
}
}
static long
lmlread(Chan *c, void *va, long n, vlong voff)
{
int i, len;
long off = voff;
uchar *buf = va;
LML *lml;
static char lmlinfo[1024];
i = 0;
switch((ulong)c->qid.path){
case Qdir:
n = devdirread(c, (char *)buf, n, lmldir, 3*nlml+1, devgen);
if(debug&(DBGFS|DBGREAD))
print("lmlread %ld\n", n);
return n;
case Qctl1:
i++;
/* fall through */
case Qctl0:
if(i >= nlml)
error(Eio);
lml = lmls+i;
len = snprint(lmlinfo, sizeof lmlinfo, "lml%djpg lml%draw\nlml%d.regs 0x%lux 0x%ux\nlml%d.mjpg 0x%lux 0x%ux\n",
i, i,
i, lml->pcidev->mem[0].bar & ~0x0F, lml->pcidev->mem[0].size,
i, PADDR(lml->codedata), Codedatasize);
if(voff > len)
return 0;
if(n > len - voff)
n = len - voff;
memmove(va, lmlinfo+voff, n);
return n;
case Qjpg1:
i++;
/* fall through */
case Qjpg0:
if(i >= nlml)
error(Eio);
return jpgread(lmls+i, buf, n, off, 1);
case Qraw1:
i++;
/* fall through */
case Qraw0:
if(i >= nlml)
error(Eio);
return jpgread(lmls+i, buf, n, off, 0);
}
return -1;
}
static long
lmlwrite(Chan *, void *, long, vlong)
{
error(Eperm);
return 0;
}
Dev lmldevtab = {
L'Λ',
"video",
lmlreset,
devinit,
devshutdown,
lmlattach,
lmlwalk,
lmlstat,
lmlopen,
devcreate,
lmlclose,
lmlread,
devbread,
lmlwrite,
devbwrite,
devremove,
devwstat,
};
static void
lmlintr(Ureg *, void *x)
{
ulong fstart, fno, flags, statcom;
FrameHeader *jpgheader;
LML *lml;
lml = x;
flags = readl(lml->pciBaseAddr+INTR_STAT);
/* Reset all interrupts from 067 */
writel(0xff000000, lml->pciBaseAddr + INTR_STAT);
if(flags & INTR_JPEGREP){
if(debug&DBGINTR)
print("MjpgDrv_intrHandler stat=0x%.8lux\n", flags);
fstart = lml->jpgframeno & 3;
for(;;){
lml->jpgframeno++;
fno = lml->jpgframeno & 3;
if(lml->codedata->statCom[fno] & STAT_BIT)
break;
if(fno == fstart){
if(debug & DBGINTR)
print("Spurious lml jpg intr?\n");
return;
}
}
statcom = lml->codedata->statCom[fno];
jpgheader = (FrameHeader *)(lml->codedata->frag[fno].hdr + 2);
jpgheader->frameNo = lml->jpgframeno;
jpgheader->ftime = todget(nil);
jpgheader->frameSize = (statcom & 0x00ffffff) >> 1;
jpgheader->frameSeqNo = statcom >> 24;
wakeup(&lml->sleepjpg);
}
}