FreeBSD/Linux Kernel Cross Reference
sys/pc/devlml.c
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 }
Cache object: a8f9906997ea716c79fcf8a71e97114c
|