xref: /plan9/sys/src/9/pc/devlml.c (revision f9e1cf08d3be51592e03e639fc848a68dc31a55e)
1 /*
2  * Lml 22 driver
3  */
4 #include	"u.h"
5 #include	"../port/lib.h"
6 #include	"mem.h"
7 #include	"dat.h"
8 #include	"fns.h"
9 #include	"../port/error.h"
10 #include	"io.h"
11 
12 #include	"devlml.h"
13 
14 #define DBGREAD	0x01
15 #define DBGWRIT	0x02
16 #define DBGINTR	0x04
17 #define DBGINTS	0x08
18 
19 int debug = 0;
20 
21 enum{
22 	Qdir,
23 	Qctl0,
24 	Qjpg0,
25 	Qraw0,
26 	Qctl1,
27 	Qjpg1,
28 	Qraw1,
29 };
30 
31 #define	QID(q)		((ulong)(q).path)
32 #define	QIDLML(q)	((((ulong)(q).path)-1)>>1)
33 
34 static Dirtab lmldir[] = {
35 	".",		{Qdir, 0, QTDIR},	0,	DMDIR|0555,
36 	"lml0ctl",	{Qctl0},		0,	0666,
37 	"lml0jpg",	{Qjpg0},		0,	0444,
38 	"lml0raw",	{Qraw0},		0,	0444,
39 	"lml1ctl",	{Qctl1},		0,	0666,
40 	"lml1jpg",	{Qjpg1},		0,	0444,
41 	"lml1raw",	{Qraw1},		0,	0444,
42 };
43 
44 typedef struct LML LML;
45 
46 struct LML {
47 	/* Hardware */
48 	Pcidev	*pcidev;
49 	ulong	pciBaseAddr;
50 
51 	/* Allocated memory */
52 	CodeData *codedata;
53 
54 	/* Software state */
55 	ulong	jpgframeno;
56 	int	frameNo;
57 	Rendez	sleepjpg;
58 	int	jpgopens;
59 } lmls[NLML];
60 
61 int nlml;
62 
63 static FrameHeader jpgheader = {
64 	MRK_SOI, MRK_APP3, (sizeof(FrameHeader)-4) << 8,
65 	{ 'L', 'M', 'L', '\0'},
66 	-1, 0, 0,  0
67 };
68 
69 #define writel(v, a) *(ulong *)(a) = (v)
70 #define readl(a) *(ulong*)(a)
71 
72 static int
73 getbuffer(void *x)
74 {
75 	static last = NBUF-1;
76 	int l = last;
77 	LML *lml;
78 
79 	lml = x;
80 	for (;;) {
81 		last = (last+1) % NBUF;
82 		if (lml->codedata->statCom[last] & STAT_BIT)
83 			return last + 1;
84 		if (last == l)
85 			return 0;
86 	}
87 	return 0;
88 }
89 
90 static long
91 jpgread(LML *lml, void *va, long nbytes, vlong, int dosleep)
92 {
93 	int bufno;
94 	FrameHeader *jpgheader;
95 
96 	/*
97 	 * reads should be of size 1 or sizeof(FrameHeader).
98 	 * Frameno is the number of the buffer containing the data.
99 	 */
100 	while ((bufno = getbuffer(lml)) == 0 && dosleep)
101 		sleep(&lml->sleepjpg, getbuffer, lml);
102 	if (--bufno < 0)
103 		return 0;
104 
105 	jpgheader = (FrameHeader*)(lml->codedata->frag[bufno].hdr+2);
106 	if (nbytes == sizeof(FrameHeader)) {
107 		memmove(va, jpgheader, sizeof(FrameHeader));
108 		return sizeof(FrameHeader);
109 	}
110 	if (nbytes == 1) {
111 		*(char *)va = bufno;
112 		return 1;
113 	}
114 	return 0;
115 }
116 
117 static void lmlintr(Ureg *, void *);
118 
119 static void
120 prepbuf(LML *lml)
121 {
122 	int i;
123 	CodeData *cd;
124 
125 	cd = lml->codedata;
126 	for (i = 0; i < NBUF; i++) {
127 		cd->statCom[i] = PADDR(&(cd->fragdesc[i]));
128 		cd->fragdesc[i].addr = PADDR(cd->frag[i].fb);
129 		/* Length is in double words, in position 1..20 */
130 		cd->fragdesc[i].leng = FRAGSIZE >> 1 | FRAGM_FINAL_B;
131 		memmove(cd->frag[i].hdr+2, &jpgheader, sizeof(FrameHeader)-2);
132 	}
133 }
134 
135 static void
136 lmlreset(void)
137 {
138 	ulong regpa;
139 	char name[32];
140 	void *regva;
141 	ISAConf isa;
142 	LML *lml;
143 	Pcidev *pcidev;
144 	Physseg segbuf;
145 
146 	pcidev = nil;
147 
148 	for (nlml = 0; nlml < NLML && (pcidev = pcimatch(pcidev, VENDOR_ZORAN,
149 	    ZORAN_36067)); nlml++){
150 		if(isaconfig("lml", nlml, &isa) == 0) {
151 			if (debug) print("lml %d not in plan9.ini\n", nlml);
152 			break;
153 		}
154 		lml = &lmls[nlml];
155 		lml->pcidev = pcidev;
156 		lml->codedata = (CodeData*)(((ulong)xalloc(Codedatasize+ BY2PG)
157 			+ BY2PG-1) & ~(BY2PG-1));
158 		if (lml->codedata == nil) {
159 			print("devlml: xalloc(%ux, %ux, 0)\n", Codedatasize, BY2PG);
160 			return;
161 		}
162 
163 		print("Installing Motion JPEG driver %s, irq %d\n",
164 			MJPG_VERSION, pcidev->intl);
165 		print("MJPG buffer at 0x%.8lux, size 0x%.8ux\n", lml->codedata,
166 			Codedatasize);
167 
168 		/* Get access to DMA memory buffer */
169 		lml->codedata->pamjpg = PADDR(lml->codedata->statCom);
170 
171 		prepbuf(lml);
172 
173 		print("zr36067 found at 0x%.8lux", pcidev->mem[0].bar & ~0x0F);
174 
175 		regpa = pcidev->mem[0].bar & ~0x0F;
176 		regva = vmap(regpa, pcidev->mem[0].size);
177 		if (regva == 0) {
178 			print("lml: failed to map registers\n");
179 			return;
180 		}
181 		lml->pciBaseAddr = (ulong)regva;
182 		print(", mapped at 0x%.8lux\n", lml->pciBaseAddr);
183 
184 		memset(&segbuf, 0, sizeof(segbuf));
185 		segbuf.attr = SG_PHYSICAL;
186 		sprint(name, "lml%d.mjpg", nlml);
187 		kstrdup(&segbuf.name, name);
188 		segbuf.pa = PADDR(lml->codedata);
189 		segbuf.size = Codedatasize;
190 		if (addphysseg(&segbuf) == -1) {
191 			print("lml: physsegment: %s\n", name);
192 			return;
193 		}
194 
195 		memset(&segbuf, 0, sizeof(segbuf));
196 		segbuf.attr = SG_PHYSICAL;
197 		sprint(name, "lml%d.regs", nlml);
198 		kstrdup(&segbuf.name, name);
199 		segbuf.pa = (ulong)regpa;
200 		segbuf.size = pcidev->mem[0].size;
201 		if (addphysseg(&segbuf) == -1) {
202 			print("lml: physsegment: %s\n", name);
203 			return;
204 		}
205 
206 		/* set up interrupt handler */
207 		intrenable(pcidev->intl, lmlintr, lml, pcidev->tbdf, "lml");
208 	}
209 }
210 
211 static Chan*
212 lmlattach(char *spec)
213 {
214 	return devattach('V', spec);
215 }
216 
217 static Walkqid*
218 lmlwalk(Chan *c, Chan *nc, char **name, int nname)
219 {
220 	return devwalk(c, nc, name, nname, lmldir, nelem(lmldir), devgen);
221 }
222 
223 static int
224 lmlstat(Chan *c, uchar *db, int n)
225 {
226 	return devstat(c, db, n, lmldir, nelem(lmldir), devgen);
227 }
228 
229 static Chan*
230 lmlopen(Chan *c, int omode)
231 {
232 	int i;
233 	LML *lml;
234 
235 	if (omode != OREAD)
236 		error(Eperm);
237 	c->aux = 0;
238 	i = 0;
239 	switch((ulong)c->qid.path){
240 	case Qctl1:
241 		i++;
242 		/* fall through */
243 	case Qctl0:
244 		if (i >= nlml)
245 			error(Eio);
246 		break;
247 	case Qjpg1:
248 	case Qraw1:
249 		i++;
250 		/* fall through */
251 	case Qjpg0:
252 	case Qraw0:
253 		/* allow one open */
254 		if (i >= nlml)
255 			error(Eio);
256 		lml = lmls+i;
257 		if (lml->jpgopens)
258 			error(Einuse);
259 		lml->jpgopens = 1;
260 		lml->jpgframeno = 0;
261 		prepbuf(lml);
262 		break;
263 	}
264 	return devopen(c, omode, lmldir, nelem(lmldir), devgen);
265 }
266 
267 static void
268 lmlclose(Chan *c)
269 {
270 	int i;
271 
272 	i = 0;
273 	switch((ulong)c->qid.path){
274 	case Qjpg1:
275 	case Qraw1:
276 		i++;
277 		/* fall through */
278 	case Qjpg0:
279 	case Qraw0:
280 		lmls[i].jpgopens = 0;
281 		break;
282 	}
283 }
284 
285 static long
286 lmlread(Chan *c, void *va, long n, vlong voff)
287 {
288 	int i, len;
289 	long off = voff;
290 	uchar *buf = va;
291 	LML *lml;
292 	static char lmlinfo[1024];
293 
294 	i = 0;
295 	switch((ulong)c->qid.path){
296 	case Qdir:
297 		return devdirread(c, (char *)buf, n, lmldir, nelem(lmldir), devgen);
298 	case Qctl1:
299 		i++;
300 		/* fall through */
301 	case Qctl0:
302 		if (i >= nlml)
303 			error(Eio);
304 		lml = lmls+i;
305 		len = snprint(lmlinfo, sizeof lmlinfo, "lml%djpg	lml%draw\nlml%d.regs	0x%lux	0x%ux\nlml%d.mjpg	0x%lux	0x%ux\n",
306 			i, i,
307 			i, lml->pcidev->mem[0].bar & ~0x0F, lml->pcidev->mem[0].size,
308 			i, PADDR(lml->codedata), Codedatasize);
309 		if (voff > len)
310 			return 0;
311 		if (n > len - voff)
312 			n = len - voff;
313 		memmove(va, lmlinfo+voff, n);
314 		return n;
315 	case Qjpg1:
316 		i++;
317 		/* fall through */
318 	case Qjpg0:
319 		if (i >= nlml)
320 			error(Eio);
321 		return jpgread(lmls+i, buf, n, off, 1);
322 	case Qraw1:
323 		i++;
324 		/* fall through */
325 	case Qraw0:
326 		if (i >= nlml)
327 			error(Eio);
328 		return jpgread(lmls+i, buf, n, off, 0);
329 	}
330 }
331 
332 static long
333 lmlwrite(Chan *, void *, long, vlong)
334 {
335 	error(Eperm);
336 	return 0;
337 }
338 
339 Dev lmldevtab = {
340 	'V',
341 	"video",
342 
343 	lmlreset,
344 	devinit,
345 	devshutdown,
346 	lmlattach,
347 	lmlwalk,
348 	lmlstat,
349 	lmlopen,
350 	devcreate,
351 	lmlclose,
352 	lmlread,
353 	devbread,
354 	lmlwrite,
355 	devbwrite,
356 	devremove,
357 	devwstat,
358 };
359 
360 static void
361 lmlintr(Ureg *, void *x)
362 {
363 	ulong fstart, fno, flags, statcom;
364 	FrameHeader *jpgheader;
365 	LML *lml;
366 
367 	lml = x;
368 	flags = readl(lml->pciBaseAddr+INTR_STAT);
369 	/* Reset all interrupts from 067 */
370 	writel(0xff000000, lml->pciBaseAddr + INTR_STAT);
371 
372 	if(flags & INTR_JPEGREP) {
373 
374 		if(debug&(DBGINTR))
375 			print("MjpgDrv_intrHandler stat=0x%.8lux\n", flags);
376 
377 		fstart = lml->jpgframeno & 3;
378 		for (;;) {
379 			lml->jpgframeno++;
380 			fno = lml->jpgframeno & 3;
381 			if (lml->codedata->statCom[fno] & STAT_BIT)
382 				break;
383 			if (fno == fstart) {
384 				if (debug & DBGINTR)
385 					print("Spurious lml jpg intr?\n");
386 				return;
387 			}
388 		}
389 		statcom = lml->codedata->statCom[fno];
390 		jpgheader = (FrameHeader *)(lml->codedata->frag[fno].hdr + 2);
391 		jpgheader->frameNo = lml->jpgframeno;
392 		jpgheader->ftime  = todget(nil);
393 		jpgheader->frameSize = (statcom & 0x00ffffff) >> 1;
394 		jpgheader->frameSeqNo = statcom >> 24;
395 		wakeup(&lml->sleepjpg);
396 	}
397 }
398