1 #include "u.h" 2 #include "../port/lib.h" 3 #include "mem.h" 4 #include "dat.h" 5 #include "fns.h" 6 #include "../port/error.h" 7 #include "io.h" 8 9 #include "devlml.h" 10 11 #define DBGREAD 0x01 12 #define DBGWRIT 0x02 13 #define DBGINTR 0x04 14 #define DBGINTS 0x08 15 16 int debug = 0; 17 18 // Lml 22 driver 19 20 enum{ 21 Qdir, 22 Qctl0, 23 Qjpg0, 24 Qraw0, 25 Qctl1, 26 Qjpg1, 27 Qraw1, 28 }; 29 30 #define QID(q) ((ulong)(q).path) 31 #define QIDLML(q) ((((ulong)(q).path)-1)>>1) 32 33 static Dirtab lmldir[]={ 34 ".", {Qdir, 0, QTDIR}, 0, DMDIR|0555, 35 "lml0ctl", {Qctl0}, 0, 0666, 36 "lml0jpg", {Qjpg0}, 0, 0444, 37 "lml0raw", {Qraw0}, 0, 0444, 38 "lml1ctl", {Qctl1}, 0, 0666, 39 "lml1jpg", {Qjpg1}, 0, 0444, 40 "lml1raw", {Qraw1}, 0, 0444, 41 }; 42 43 typedef struct LML LML; 44 45 struct LML { 46 // Hardware 47 Pcidev * pcidev; 48 ulong pciBaseAddr; 49 // Allocated memory 50 CodeData * codedata; 51 // Software state 52 ulong jpgframeno; 53 int frameNo; 54 Rendez sleepjpg; 55 int jpgopens; 56 } lmls[NLML]; 57 58 int nlml; 59 60 static FrameHeader jpgheader = { 61 MRK_SOI, MRK_APP3, (sizeof(FrameHeader)-4) << 8, 62 { 'L', 'M', 'L', '\0'}, 63 -1, 0, 0, 0 64 }; 65 66 #define writel(v, a) *(ulong *)(a) = (v) 67 #define readl(a) *(ulong*)(a) 68 69 static int 70 getbuffer(void *x){ 71 static last = NBUF-1; 72 int l = last; 73 LML *lml; 74 75 lml = x; 76 for (;;) { 77 last = (last+1) % NBUF; 78 if (lml->codedata->statCom[last] & STAT_BIT) 79 return last + 1; 80 if (last == l) 81 return 0; 82 } 83 return 0; 84 } 85 86 static long 87 jpgread(LML *lml, void *va, long nbytes, vlong, int dosleep) { 88 int bufno; 89 FrameHeader *jpgheader; 90 91 // reads should be of size 1 or sizeof(FrameHeader) 92 // Frameno is the number of the buffer containing the data 93 while ((bufno = getbuffer(lml)) == 0 && dosleep) 94 sleep(&lml->sleepjpg, getbuffer, lml); 95 if (--bufno < 0) 96 return 0; 97 98 jpgheader = (FrameHeader*)(lml->codedata->frag[bufno].hdr+2); 99 if (nbytes == sizeof(FrameHeader)) { 100 memmove(va, jpgheader, sizeof(FrameHeader)); 101 return sizeof(FrameHeader); 102 } 103 if (nbytes == 1) { 104 *(char *)va = bufno; 105 return 1; 106 } 107 return 0; 108 } 109 110 static void lmlintr(Ureg *, void *); 111 112 static void 113 prepbuf(LML *lml) { 114 int i; 115 116 for (i = 0; i < NBUF; i++) { 117 lml->codedata->statCom[i] = PADDR(&(lml->codedata->fragdesc[i])); 118 lml->codedata->fragdesc[i].addr = PADDR(lml->codedata->frag[i].fb); 119 // Length is in double words, in position 1..20 120 lml->codedata->fragdesc[i].leng = (FRAGSIZE >> 1) | FRAGM_FINAL_B; 121 memmove(lml->codedata->frag[i].hdr+2, &jpgheader, sizeof(FrameHeader)-2); 122 } 123 } 124 125 static void 126 lmlreset(void) 127 { 128 Physseg segbuf; 129 ulong regpa; 130 void *regva; 131 ISAConf isa; 132 char name[32]; 133 Pcidev *pcidev; 134 LML *lml; 135 136 pcidev = nil; 137 138 for (nlml = 0; nlml < NLML && (pcidev = pcimatch(pcidev, VENDOR_ZORAN, ZORAN_36067)); nlml++){ 139 if(isaconfig("lml", nlml, &isa) == 0) { 140 if (debug) print("lml %d not in plan9.ini\n", nlml); 141 break; 142 } 143 lml = &lmls[nlml]; 144 lml->pcidev = pcidev; 145 lml->codedata = (CodeData*)(((ulong)xalloc(Codedatasize+ BY2PG) + BY2PG-1) & ~(BY2PG-1)); 146 if (lml->codedata == nil) { 147 print("devlml: xalloc(%ux, %ux, 0)\n", Codedatasize, BY2PG); 148 return; 149 } 150 151 print("Installing Motion JPEG driver %s, irq %d\n", MJPG_VERSION, pcidev->intl); 152 print("MJPG buffer at 0x%.8lux, size 0x%.8ux\n", lml->codedata, Codedatasize); 153 154 // Get access to DMA memory buffer 155 lml->codedata->pamjpg = PADDR(lml->codedata->statCom); 156 157 prepbuf(lml); 158 159 print("zr36067 found at 0x%.8lux", pcidev->mem[0].bar & ~0x0F); 160 161 regpa = pcidev->mem[0].bar & ~0x0F; 162 regva = vmap(regpa, pcidev->mem[0].size); 163 if (regva == 0) { 164 print("lml: failed to map registers\n"); 165 return; 166 } 167 lml->pciBaseAddr = (ulong)regva; 168 print(", mapped at 0x%.8lux\n", lml->pciBaseAddr); 169 170 memset(&segbuf, 0, sizeof(segbuf)); 171 segbuf.attr = SG_PHYSICAL; 172 sprint(name, "lml%d.mjpg", nlml); 173 kstrdup(&segbuf.name, name); 174 segbuf.pa = PADDR(lml->codedata); 175 segbuf.size = Codedatasize; 176 if (addphysseg(&segbuf) == -1) { 177 print("lml: physsegment: %s\n", name); 178 return; 179 } 180 181 memset(&segbuf, 0, sizeof(segbuf)); 182 segbuf.attr = SG_PHYSICAL; 183 sprint(name, "lml%d.regs", nlml); 184 kstrdup(&segbuf.name, name); 185 segbuf.pa = (ulong)regpa; 186 segbuf.size = pcidev->mem[0].size; 187 if (addphysseg(&segbuf) == -1) { 188 print("lml: physsegment: %s\n", name); 189 return; 190 } 191 192 // Interrupt handler 193 intrenable(pcidev->intl, lmlintr, lml, pcidev->tbdf, "lml"); 194 } 195 return; 196 } 197 198 static Chan* 199 lmlattach(char *spec) 200 { 201 return devattach('V', spec); 202 } 203 204 static Walkqid* 205 lmlwalk(Chan *c, Chan *nc, char **name, int nname) 206 { 207 return devwalk(c, nc, name, nname, lmldir, nelem(lmldir), devgen); 208 } 209 210 static int 211 lmlstat(Chan *c, uchar *db, int n) 212 { 213 return devstat(c, db, n, lmldir, nelem(lmldir), devgen); 214 } 215 216 static Chan* 217 lmlopen(Chan *c, int omode) { 218 int i; 219 LML *lml; 220 221 if (omode != OREAD) 222 error(Eperm); 223 c->aux = 0; 224 i = 0; 225 switch((ulong)c->qid.path){ 226 case Qctl1: 227 i++; 228 case Qctl0: 229 if (i >= nlml) 230 error(Eio); 231 break; 232 case Qjpg1: 233 case Qraw1: 234 i++; 235 case Qjpg0: 236 case Qraw0: 237 // allow one open 238 if (i >= nlml) 239 error(Eio); 240 lml = lmls+i; 241 if (lml->jpgopens) 242 error(Einuse); 243 lml->jpgopens = 1; 244 lml->jpgframeno = 0; 245 prepbuf(lml); 246 break; 247 } 248 return devopen(c, omode, lmldir, nelem(lmldir), devgen); 249 } 250 251 static void 252 lmlclose(Chan *c) { 253 int i; 254 255 i = 0; 256 switch((ulong)c->qid.path){ 257 case Qjpg1: 258 case Qraw1: 259 i++; 260 case Qjpg0: 261 case Qraw0: 262 lmls[i].jpgopens = 0; 263 break; 264 } 265 } 266 267 static long 268 lmlread(Chan *c, void *va, long n, vlong voff) { 269 int i; 270 uchar *buf = va; 271 long off = voff; 272 LML *lml; 273 static char lmlinfo[1024]; 274 int len; 275 276 i = 0; 277 switch((ulong)c->qid.path){ 278 case Qdir: 279 return devdirread(c, (char *)buf, n, lmldir, nelem(lmldir), devgen); 280 case Qctl1: 281 i++; 282 case Qctl0: 283 if (i >= nlml) 284 error(Eio); 285 lml = lmls+i; 286 len = snprint(lmlinfo, sizeof lmlinfo, "lml%djpg lml%draw\nlml%d.regs 0x%lux 0x%ux\nlml%d.mjpg 0x%lux 0x%ux\n", 287 i, i, 288 i, lml->pcidev->mem[0].bar & ~0x0F, lml->pcidev->mem[0].size, 289 i, PADDR(lml->codedata), Codedatasize); 290 if (voff > len) 291 return 0; 292 if (n > len - voff) 293 n = len - voff; 294 memmove(va, lmlinfo+voff, n); 295 return n; 296 case Qjpg1: 297 i++; 298 case Qjpg0: 299 if (i >= nlml) 300 error(Eio); 301 return jpgread(lmls+i, buf, n, off, 1); 302 case Qraw1: 303 i++; 304 case Qraw0: 305 if (i >= nlml) 306 error(Eio); 307 return jpgread(lmls+i, buf, n, off, 0); 308 } 309 } 310 311 static long 312 lmlwrite(Chan *, void *, long, vlong) { 313 314 error(Eperm); 315 return 0; 316 } 317 318 Dev lmldevtab = { 319 'V', 320 "video", 321 322 lmlreset, 323 devinit, 324 devshutdown, 325 lmlattach, 326 lmlwalk, 327 lmlstat, 328 lmlopen, 329 devcreate, 330 lmlclose, 331 lmlread, 332 devbread, 333 lmlwrite, 334 devbwrite, 335 devremove, 336 devwstat, 337 }; 338 339 static void 340 lmlintr(Ureg *, void *x) { 341 FrameHeader *jpgheader; 342 ulong fstart, fno, flags, statcom; 343 LML *lml; 344 345 lml = x; 346 flags = readl(lml->pciBaseAddr+INTR_STAT); 347 // Reset all interrupts from 067 348 writel(0xff000000, lml->pciBaseAddr + INTR_STAT); 349 350 if(flags & INTR_JPEGREP) { 351 352 if(debug&(DBGINTR)) 353 print("MjpgDrv_intrHandler stat=0x%.8lux\n", flags); 354 355 fstart = lml->jpgframeno & 0x00000003; 356 for (;;) { 357 lml->jpgframeno++; 358 fno = lml->jpgframeno & 0x00000003; 359 if (lml->codedata->statCom[fno] & STAT_BIT) 360 break; 361 if (fno == fstart) { 362 if (debug & DBGINTR) 363 print("Spurious lml jpg intr?\n"); 364 return; 365 } 366 } 367 statcom = lml->codedata->statCom[fno]; 368 jpgheader = (FrameHeader *)(lml->codedata->frag[fno].hdr+2); 369 jpgheader->frameNo = lml->jpgframeno; 370 jpgheader->ftime = todget(nil); 371 jpgheader->frameSize = (statcom & 0x00ffffff) >> 1; 372 jpgheader->frameSeqNo = statcom >> 24; 373 wakeup(&lml->sleepjpg); 374 } 375 return; 376 } 377