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 } 398