412 lines · 7.9 KB · C
RawDownload
/*  * 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);	}}