]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/pc/devlml.c
ether82563: fix multicast for i210
[plan9front.git] / sys / src / 9 / 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 #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
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
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
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
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) == nil){
183                         print("lml: physsegment: %s\n", name);
184                         return;
185                 }
186
187                 memset(&segbuf, 0, sizeof(segbuf));
188                 segbuf.attr = SG_PHYSICAL | SG_DEVICE | SG_NOEXEC;
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) == nil){
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*
204 lmlattach(char *spec)
205 {
206         if(debug&DBGFS)
207                 print("lmlattach\n");
208         return devattach(L'Λ', spec);
209 }
210
211 static Walkqid*
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
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*
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
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
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
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
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 }