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