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