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) == -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* 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 } 404