shithub: nix

Download patch

ref: bfc9136801651ac4921c78e5b9b3a71cf382f26d
parent: 3e66836a5bee73986b30e86805baf12abc8bb4c2
author: glenda <glenda@cirno>
date: Sun May 5 21:31:40 EDT 2024

first import of devnix.c, based on devlml.c

--- /dev/null
+++ b/sys/src/nix/pc64/devnix.c
@@ -1,0 +1,404 @@
+/*
+ * 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	"../port/pci.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;
+	uintptr	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)
+{
+	uvlong 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 = (uintptr)regva;
+		print(", mapped at %#p\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) == nil){
+			print("lml: physsegment: %s\n", name);
+			return;
+		}
+
+		memset(&segbuf, 0, sizeof(segbuf));
+		segbuf.attr = SG_PHYSICAL | SG_DEVICE | SG_NOEXEC;
+		sprint(name, "lml%d.regs", nlml);
+		kstrdup(&segbuf.name, name);
+		segbuf.pa = (uintptr)regpa;
+		segbuf.size = pcidev->mem[0].size;
+		if(addphysseg(&segbuf) == nil){
+			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);
+	}
+}