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