xref: /inferno-os/os/pc/devmpeg.c (revision 7ef44d652ae9e5e1f5b3465d73684e4a54de73c0)
1 /*
2  *  Boffin MPEG decoder
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	"zoran.h"
11 #include	"crystal.h"
12 #include	"io.h"
13 
14 enum
15 {
16 
17 	CPUACCCTRL      = 0x20,	/* Trident Window Chip control registers */
18 	CPUACCMD        = 0x21,
19 	BNKADR          = 0x22,
20 	SYSCONFIG       = 0x23,
21 	VGACOMP         = 0x24,
22 	VGAMASK         = 0x25,
23 	VIDCOMPL        = 0x26,
24 	VIDCOMPH        = 0x27,
25 	MOS             = 0x28,
26 	DISPCTRL        = 0x29,
27 	CAPCTRL         = 0x2a,
28 	OVLKT           = 0x2b,
29 	OVLWINHSTRT     = 0x2c,
30 	OVLWINVSTRT     = 0x2d,
31 	OVLWINHEND      = 0x2e,
32 	OVLWINVEND      = 0x2f,
33 	RESERVED1       = 0x30,
34 	RESERVED2       = 0x31,
35 	DISPWINVSTRT1   = 0x32,
36 	DISPWINVSTRT2   = 0x33,
37 	DISPWINVEND     = 0x34,
38 	DISPWINHSTRT1   = 0x35,
39 	DISPWINHSTRT2   = 0x36,
40 	DISPWINHEND     = 0x37,
41 	CAPWINVSTRT     = 0x38,
42 	CAPWINHSTRT     = 0x39,
43 	CAPWINVMF       = 0x3a,
44 	CAPWINHMF       = 0x3b,
45 	RESERVED3       = 0x3c,
46 	CAPMASK         = 0x3d,
47 	BNKPOLATION     = 0x3e,
48 	SYNCPOL         = 0x3f,
49 	DISPVTOTAL      = 0x40,
50 	DISPHTOTAL      = 0x41,
51 	DISPVSTRT       = 0x42,
52 	DISPVEND        = 0x43,
53 	DISPHSTRT       = 0x44,
54 	DISPHEND        = 0x45,
55 	DISPSYNCW       = 0x46,
56 	DISPCRTCCTRL    = 0x47,
57 	CAPVTOTAL       = 0x48,
58 	CAPHTOTAL       = 0x49,
59 	CAPVSTRT        = 0x4a,
60 	CAPVEND         = 0x4b,
61 	CAPHSTRT        = 0x4c,
62 	CAPHEND         = 0x4d,
63 	CAPSYNCW        = 0x4e,
64 	CAPCRTCCTRL     = 0x4f,
65 	VIDLUTDACRW     = 0x50,
66 	VIDLUTDACRW0    = (VIDLUTDACRW),
67 	VIDLUTDACRW1    = (VIDLUTDACRW+1),
68 	VIDLUTDACRW2    = (VIDLUTDACRW+2),
69 	VIDLUTDACRW3    = (VIDLUTDACRW+3),
70 	VIDLUTDACRW4    = (VIDLUTDACRW+4),
71 	VIDLUTDACRW5    = (VIDLUTDACRW+5),
72 	VIDLUTDACRW6    = (VIDLUTDACRW+6),
73 	VIDLUTDACRW7    = (VIDLUTDACRW+7),
74 	VGALUTDACRW     = 0x58,
75 	VGALUTDACRW0    = (VGALUTDACRW),
76 	VGALUTDACRW1    = (VGALUTDACRW+1),
77 	VGALUTDACRW2    = (VGALUTDACRW+2),
78 	VGALUTDACRW3    = (VGALUTDACRW+3),
79 	VGALUTDACRW4    = (VGALUTDACRW+4),
80 	VGALUTDACRW5    = (VGALUTDACRW+5),
81 	VGALUTDACRW6    = (VGALUTDACRW+6),
82 	VGALUTDACRW7    = (VGALUTDACRW+7),
83 	HZOOMF          = 0x60,
84 	VZOOMF          = 0x61,
85 	DELAY1          = 0x62,
86 	DELAY2          = 0x63,
87 
88 	TRILO      	= 0,
89 	TRIHI     	= 1,
90 	TRIINDEX    	= 2,
91 
92 	SCL             = 0x02,
93 	SDA             = 0x01,
94 	I2CR		= 0x2B,
95 	SAA7110		= 0x9c,
96 	WRITE_C		= 0x00,
97 	I2DLY		= 5,
98 };
99 
100 enum
101 {
102 	ZR36100		= 0x1e0,
103 	ZRIRQ		= 15,
104 	ZRDMA		= 6,
105 
106 	ZRIDREG		= 4,				/* offset */
107 	ZRMACH210   	= 6,				/* offset */
108 	ZRREG0      	= 8,				/* offset */
109 	ZRREG1		= 10,				/* offset */
110 	ZRSR		= ZRREG1,			/* offset */
111 	ZRRDY		= (1<<3),
112 	ZRIDLE		= (1<<2),
113 	ZRREG2		= 12,				/* offset */
114 	ZRREG3		= 14,				/* offset */
115 
116 	SIFwidth	= 320,
117 	SIFheight	= 240,
118 
119 	IDPCOUNT	= 3064,
120 	PMDPCOUNT	= 2048,
121 	SVMDPCOUNT	= 2048,
122 
123 	HIWAT		= 2*128*1024,
124 	DMABLK		= 16384,
125 };
126 
127 static struct {
128 	int	zrport;
129 	int	irq;
130 	int	dma;
131 	int	trport;
132 } mpegconf;
133 
134 static	char Evmode[] = "video format not supported";
135 static	char Eaudio[] = "invalid audio layer";
136 static	char Earate[] = "bad audio sample rate";
137 
138 /* Status bits depend on board revision */
139 static	short	STDBY;
140 static	short	VIDSEL;
141 static	short	VSNIRQn;
142 static	short	INTENAn;
143 static	short	DSPBOOT;
144 static	short	DSPRST;
145 static	short	MPGRST;
146 static	int	machsr;
147 static	int	dopen;
148 static	int	started;
149 static	int	stop;
150 static	int	pause;
151 static	int	sp2br;
152 static	int	sp2cd;
153 static	char	properties[] = "video mpeg1,sif\naudio musicam,I musicam,II\n";
154 static	void	inittrident(void);
155 static	int	initzoran(void);
156 static	void	initcrystal(void);
157 static	void	mpegintr(Ureg*, void*);
158 static	void	setwindow(int, char**);
159 static	void	freebufs(void);
160 static	int	mkbuf(char*, int);
161 
162 typedef struct Buf Buf;
163 struct Buf
164 {
165 	int	nchar;
166 	uchar*	ptr;
167 	Buf*	link;
168 	uchar	data[1];
169 };
170 
171 static struct
172 {
173 	Lock;
174 	int	qlen;
175 	Buf*	head;
176 	Buf*	tail;
177 	Rendez	flow;
178 } bqueue;
179 
180 static int
181 zrstatus(void)
182 {
183 	return ins(mpegconf.zrport+ZRSR) & 0xf;
184 }
185 
186 static int
187 zrwaitrdy(int timo, char *msg)
188 {
189 	int i;
190 
191 	for(i = 0; i < timo; i++)
192 		if(ins(mpegconf.zrport+ZRSR) & ZRRDY)
193 			return 0;
194 
195 	print("devmpeg: device not ready %s\n", msg);
196 	return 1;
197 }
198 
199 static void
200 zrdma(Buf *b)
201 {
202 	int n;
203 
204 	n = dmasetup(mpegconf.dma, b->ptr, b->nchar, 0);
205 	b->ptr += n;
206 	b->nchar -= n;
207 	bqueue.qlen -= n;
208 }
209 
210 static void
211 triwr(int reg, int val)
212 {
213 	outb(mpegconf.trport+TRIINDEX, reg);
214 	outb(mpegconf.trport+TRILO, val);
215 	outb(mpegconf.trport+TRIHI, val>>8);
216 }
217 
218 static int
219 trird(int reg)
220 {
221 	int v;
222 
223 	outb(mpegconf.trport+TRIINDEX, reg);
224 	v = inb(mpegconf.trport+TRILO);
225 	v |= inb(mpegconf.trport+TRIHI)<<8;
226 
227 	return v;
228 }
229 
230 enum
231 {
232 	Qdir,
233 	Qdata,
234 	Qctl,
235 };
236 static Dirtab mpegtab[]=
237 {
238 	"mpeg",		{Qdata, 0},	0,	0666,
239 	"mpegctl",	{Qctl,  0},	0,	0666,
240 };
241 
242 static void
243 mpegreset(void)
244 {
245 	ISAConf isa;
246 
247 	mpegconf.zrport = ZR36100;
248 	mpegconf.irq = ZRIRQ;
249 	mpegconf.dma = ZRDMA;
250 
251 	memset(&isa, 0, sizeof(isa));
252 	if(isaconfig("mpeg", 0, &isa) == 0)
253 		return;
254 	if(isa.port)
255 		mpegconf.zrport = isa.port;
256 	if(isa.irq)
257 		mpegconf.irq = isa.irq;
258 	if(isa.dma)
259 		mpegconf.dma = isa.dma;
260 	dmainit(mpegconf.dma, 64*1024);
261 	print("mpeg0: port 0x%uX, irq %d, dma %d\n",
262 		mpegconf.zrport, mpegconf.irq, mpegconf.dma);
263 	mpegconf.trport = mpegconf.zrport+0x100;
264 	intrenable(VectorPIC+mpegconf.irq, mpegintr, 0, BUSUNKNOWN);
265 }
266 
267 static void
268 mpeginit(void)
269 {
270 	if(mpegconf.trport == 0)
271 		return;
272 
273 	inittrident();
274 	setwindow(0, 0);
275 }
276 
277 static Chan*
278 mpegattach(char *spec)
279 {
280 	if(mpegconf.trport == 0)
281 		error(Enodev);
282 
283 	return devattach('E', spec);
284 }
285 
286 static int
287 mpegwalk(Chan *c, char *name)
288 {
289 	return devwalk(c, name, mpegtab, nelem(mpegtab), devgen);
290 }
291 
292 static void
293 mpegstat(Chan *c, char *db)
294 {
295 	devstat(c, db, mpegtab, nelem(mpegtab), devgen);
296 }
297 
298 static Chan*
299 mpegopen(Chan *c, int omode)
300 {
301 	switch(c->qid.path) {
302 	default:
303 		break;
304 	case Qdata:
305 		if(dopen)
306 			error(Einuse);
307 		dopen = 1;
308 		break;
309 	}
310 	return devopen(c, omode, mpegtab, nelem(mpegtab), devgen);
311 }
312 
313 static void
314 mpegclose(Chan *c)
315 {
316 	int i;
317 
318 	switch(c->qid.path) {
319 	default:
320 		break;
321 	case Qdata:
322 		if((c->flag & COPEN) == 0)
323 			break;
324 		if(started) {
325 			for(i = 0; i < 50; i++) {
326 				if(ins(mpegconf.zrport+ZRSR) & ZRIDLE)
327 					break;
328 				tsleep(&up->sleep, return0, 0, 100);
329 			}
330 		}
331 		if(stop != 0)
332 			outs(mpegconf.zrport+ZRREG1, 0x1000);
333 		microdelay(15);
334 		outs(mpegconf.zrport+ZRREG1, 0x8000);
335 		freebufs();
336 		dopen = 0;
337 	}
338 }
339 
340 static long
341 mpegread(Chan *c, void *a, long n, ulong off)
342 {
343 	switch(c->qid.path & ~CHDIR){
344 	default:
345 		error(Eperm);
346 	case Qdir:
347 		return devdirread(c, a, n, mpegtab, nelem(mpegtab), devgen);
348 	case Qctl:
349 		return readstr(off, a, n, properties);
350 	}
351 	return 0;
352 }
353 
354 #define SCALE(a, b)	((((a)<<10)/(b))-1024)
355 enum
356 {
357 	CWINVF = 0x3ff,
358 	CWINHF = 0x1da,
359 };
360 
361 static void
362 setwindow(int nf, char **field)
363 {
364 	int minx, miny, maxx, maxy, width, height;
365 
366 	if(field == 0) {
367 		minx = 0;
368 		miny = 0;
369 		maxx = 0;
370 		maxy = 0;
371 	}
372 	else {
373 		if(nf != 5)
374 			error(Ebadarg);
375 
376 		minx = strtoul(field[1], 0, 0);
377 		miny = strtoul(field[2], 0, 0);
378 		maxx = strtoul(field[3], 0, 0) + 8;
379 		maxy = strtoul(field[4], 0, 0);
380 	}
381 
382 	triwr(OVLWINHSTRT, minx);
383 	triwr(OVLWINVSTRT, miny);
384 	triwr(OVLWINHEND, maxx+12);
385 	triwr(OVLWINVEND, maxy);
386 
387 	width = maxx - minx;
388 	height = maxy - miny;
389 	if(width >= SIFwidth) {
390 		triwr(HZOOMF, SCALE(width, SIFwidth));
391 		triwr(CAPWINHMF, CWINHF);
392 	}
393 	else {
394 		triwr(HZOOMF, SCALE(SIFwidth, SIFwidth));
395 		triwr(CAPWINHMF, width*CWINHF/SIFwidth);
396 	}
397 	if(height >= SIFheight) {
398 		triwr(VZOOMF, SCALE(height, SIFheight));
399 		triwr(CAPWINVMF, CWINVF);
400 	}
401 	else {
402 		triwr(VZOOMF, SCALE(SIFheight, SIFheight));
403 		triwr(CAPWINVMF, height*CWINVF/SIFheight);
404 	}
405 }
406 
407 static int
408 mpegflow(void*)
409 {
410 	return bqueue.qlen < HIWAT || stop;
411 }
412 
413 static int
414 mkbuf(char *d, int n)
415 {
416 	Buf *b;
417 
418 	b = malloc(sizeof(Buf)+n);
419 	if(b == 0)
420 		return 0;
421 
422 	memmove(b->data, d, n);
423 	b->ptr = b->data;
424 	b->nchar = n;
425 	b->link = 0;
426 
427 	ilock(&bqueue);
428 	bqueue.qlen += n;
429 	if(bqueue.head)
430 		bqueue.tail->link = b;
431 	else
432 		bqueue.head = b;
433 	bqueue.tail = b;
434 	iunlock(&bqueue);
435 
436 	return 1;
437 }
438 
439 static void
440 freebufs(void)
441 {
442 	Buf *next;
443 
444 	ilock(&bqueue);
445 	bqueue.qlen = 0;
446 	while(bqueue.head) {
447 		next = bqueue.head->link;
448 		free(bqueue.head);
449 		bqueue.head = next;
450 	}
451 	iunlock(&bqueue);
452 }
453 
454 typedef struct Audio Audio;
455 struct Audio {
456 	int rate;
457 	int cd;
458 	int br;
459 };
460 
461 static Audio AudioclkI[] =
462 {
463 	 64000, 0x000000bb, 0x00071797,
464 	 96000, 0x0000007d, 0x00071c71,
465 	128000, 0x0000005d, 0x00070de1,
466 	160000, 0x0000004b, 0x00071c71,
467 	192000, 0x0000003e, 0x00070de1,
468 	224000, 0x00000035, 0x00070906,
469 	256000, 0x0000002e, 0x0006fa76,
470 	288000, 0x00000029, 0x0006ff51,
471 	320000, 0x00000025, 0x0007042b,
472 	352000, 0x00000022, 0x00071797,
473 	384000, 0x0000001f, 0x00070de1,
474 	416000, 0x0000001c, 0x0006e70b,
475 	448000, 0x0000001a, 0x0006e70b,
476 };
477 
478 static Audio  AudioclkII[] =
479 {
480 	 48000, 0x000000fa, 0x00071c71,
481 	 56000, 0x000000d6, 0x00071a04,
482 	 64000, 0x000000bb, 0x00071797,
483 	 80000, 0x00000096, 0x00071c71,
484 	 96000, 0x0000007d, 0x00071c71,
485 	112000, 0x0000006b, 0x00071a04,
486 	128000, 0x0000005d, 0x00070de1,
487 	160000, 0x0000004b, 0x00071c71,
488 	192000, 0x0000003e, 0x00070de1,
489 	224000, 0x00000035, 0x00070906,
490 	256000, 0x0000002e, 0x0006fa76,
491 	320000, 0x00000025, 0x0007042b,
492 	384000, 0x0000001f, 0x00070de1,
493 };
494 
495 static long
496 mpegwrite(Chan *c, char *a, long n, vlong)
497 {
498 	Audio *t;
499 	int i, nf, l, x;
500 	char buf[128], *field[10];
501 
502 	switch(c->qid.path & ~CHDIR) {
503 	case Qctl:
504 		if(n > sizeof(buf)-1)
505 			n = sizeof(buf)-1;
506 		memmove(buf, a, n);
507 		buf[n] = '\0';
508 
509 		nf = getfields(buf, field, nelem(field), 1, " \t\n");
510 		if(nf < 1)
511 			error(Ebadarg);
512 
513 		if(strcmp(field[0], "stop") == 0) {
514 			if(started == 0)
515 				error("not started");
516 			if(pause) {
517 				pause = 0;
518 				outs(mpegconf.zrport+ZRREG1, 0x9000);
519 			}
520 			stop = 1;
521 			outs(mpegconf.zrport+ZRREG1, 0x1000);
522 			microdelay(15);
523 			outs(mpegconf.zrport+ZRREG1, 0x8000);
524 			wakeup(&bqueue.flow);
525 			return n;
526 		}
527 		if(strcmp(field[0], "pause") == 0) {
528 			if(started == 0)
529 				error("not started");
530 			if(pause == 0) {
531 				pause = 1;
532 				outs(mpegconf.zrport+ZRREG1, 0x1000);
533 			}
534 			else {
535 				pause = 0;
536 				outs(mpegconf.zrport+ZRREG1, 0x9000);
537 			}
538 			return n;
539 		}
540 		if(strcmp(field[0], "window") == 0) {
541 			setwindow(nf, field);
542 			return n;
543 		}
544 		if(strcmp(field[0], "audio") == 0) {
545 			if(nf < 3)
546 				error(Ebadarg);
547 			t = 0;
548 			if(strcmp(field[1], "musicam,I") == 0)
549 				t = AudioclkI;
550 			else
551 			if(strcmp(field[1], "musicam,II") == 0)
552 				t = AudioclkII;
553 			else
554 				error(Eaudio);
555 			x = strtoul(field[2], 0, 0);
556 			for(i = 0; t[i].rate != 0; i++) {
557 				if(t[i].rate == x) {
558 					sp2cd = t[i].cd;
559 					sp2br = t[i].br;
560 					return n;
561 				}
562 			}
563 			error(Earate);
564 		}
565 		if(strcmp(field[0], "video") == 0) {
566 			if(nf != 3)
567 				error(Ebadarg);
568 			if(strcmp(field[1], "iso11172") != 0)
569 				error(Evmode);
570 			if(strcmp(field[2], "mpeg1,sif") != 0)
571 				error(Evmode);
572 			return n;
573 		}
574 		if(strcmp(field[0], "init") == 0) {
575 			inittrident();
576 			for(i = 0; i < 3; i++)
577 				if(initzoran() != -1)
578 					break;
579 			initcrystal();
580 			started = 0;
581 			stop = 0;
582 			pause = 0;
583 			return n;
584 		}
585 		error(Ebadarg);
586 	case Qdata:
587 		if(n & 1)
588 			error("odd write");
589 
590 		while(!mpegflow(0))
591 			sleep(&bqueue.flow, mpegflow, 0);
592 
593 		if(stop)
594 			error("stopped");
595 
596 		x = n;
597 		while(x) {
598 			l = x;
599 			if(l > DMABLK)
600 				l = DMABLK;
601 			if(mkbuf(a, l) == 0)
602 				error(Enomem);
603 			x -= l;
604 			a += l;
605 		}
606 		if(started || bqueue.qlen < (HIWAT*3)/4)
607 			break;
608 
609 		zrdma(bqueue.head);
610 		outs(mpegconf.zrport+ZRREG1, 0x0000);
611 		outs(mpegconf.zrport+ZRREG1, 0x0000);
612 		started = 1;
613 		break;
614 	default:
615 		error(Ebadusefd);
616 	}
617 	return n;
618 }
619 
620 Dev mpegdevtab = {
621 	'E',
622 	"mpeg",
623 
624 	mpegreset,
625 	mpeginit,
626 	mpegattach,
627 	devdetach,
628 	devclone,
629 	mpegwalk,
630 	mpegstat,
631 	mpegopen,
632 	devcreate,
633 	mpegclose,
634 	mpegread,
635 	devbread,
636 	mpegwrite,
637 	devbwrite,
638 	devremove,
639 	devwstat,
640 };
641 
642 static void
643 initctl(void)
644 {
645 	int boardid;
646 	static int done;
647 
648 	if(done)
649 		return;
650 
651 	boardid = ins(mpegconf.zrport+ZRIDREG);
652 	if(boardid == 0xE3E3) {		/* REV c/d */
653 		STDBY   = 0x0000;
654 		VIDSEL  = 0x2020;
655 		VSNIRQn = 0x1010;
656 		INTENAn = 0x0808;
657 		DSPBOOT = 0x0404;
658 		DSPRST  = 0x0202;
659 		MPGRST  = 0x0101;
660 	}
661 	else {				/* REV b */
662 		STDBY   = 0x0404;
663 		VIDSEL  = 0x1010;
664 		VSNIRQn = 0x8080;
665 		INTENAn = 0x4040;
666 		DSPBOOT = 0x0202;
667 		DSPRST  = 0x0101;
668 		MPGRST  = 0x2020;
669 	}
670 	done = 1;
671 
672 }
673 
674 /*
675  * nbl (reg 0x1[ab]) was 0x0022, nblf (reg 1[cd]) was 0x0006
676  */
677 static uchar
678 zrparam[] =
679 {
680 /* 00 */  0xEF, 0x01, 0x01, 0x01, 0x80, 0x0E, 0x31, 0x00,
681 /* 08 */  0x01, 0x60, 0x00, 0x00, 0x03, 0x5A, 0x00, 0x7A,
682 /* 10 */  0x00, 0x10, 0x00, 0x08, 0x00, 0xF0, 0x00, 0x00,
683 /* 18 */  0x02, 0x0D, 0x00, 0x1e, 0x00, 0x0a, 0x00, 0x02,
684 /* 20 */  0x40, 0x06, 0x80, 0x00, 0x80, 0x00, 0x05, 0x9B,
685 /* 28 */  0x07, 0x16, 0xFD, 0x25, 0xFE, 0xA0, 0x00, 0x00,
686 /* 30 */  0x00, 0x07, 0x0d, 0xe1, 0x00, 0x00, 0x00, 0x3E,
687 /* 38 */  0x00, 0x00, 0x09, 0x51, 0x00, 0x00, 0xCD, 0xFE,
688 /* 40 */  0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
689 /* 48 */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
690 /* 50 */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
691 /* 58 */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
692 /* 60 */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
693 /* 68 */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
694 /* 70 */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
695 /* 78 */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
696 };
697 
698 static int
699 initzoran(void)
700 {
701 	int i, nbytes, zrs;
702 
703 	initctl();
704 	freebufs();
705 
706 	machsr = DSPRST|VSNIRQn;
707 	outs(mpegconf.zrport+ZRMACH210, machsr);
708 	microdelay(4000);
709 
710 	machsr |= STDBY;
711 	outs(mpegconf.zrport+ZRMACH210, machsr);
712 	microdelay(4000);
713 
714 	machsr |= MPGRST;
715 	outs(mpegconf.zrport+ZRMACH210, machsr);
716 	microdelay(4000);
717 	machsr &= ~MPGRST;
718 	outs(mpegconf.zrport+ZRMACH210, machsr);
719 	microdelay(4000);
720 	machsr |= MPGRST;
721 	outs(mpegconf.zrport+ZRMACH210, machsr);
722 	microdelay(4000);
723 
724 	if(zrwaitrdy(2000, "load IDP"))
725 		return -1;
726 
727 	for(i = 0; i < IDPCOUNT; i++)
728 		outb(mpegconf.zrport+ZRREG2, zrmpeg1[i]);
729 
730 	if(((zrs = zrstatus()) & 3) != 3) {
731 /*		print("devmpeg: error loading IDP sr=%2.2ux\n", zrs);	*/
732 		USED(zrs);
733 		return -1;
734 	}
735 
736 	if(zrwaitrdy(2000, "load PMDP"))
737 		return -1;
738 
739 	for(i = 0; i < PMDPCOUNT; i++)
740 		outb(mpegconf.zrport+ZRREG3, zrmpeg2[i]);
741 
742 	if(((zrs = zrstatus()) & 3) != 3) {
743 /*		print("devmpeg: error loading PMDP sr=%2.2ux\n", zrs);	*/
744 		USED(zrs);
745 		return -1;
746 	}
747 
748 	zrparam[0x36] = sp2cd>>8;
749 	zrparam[0x37] = sp2cd>>0;
750 	zrparam[0x31] = sp2br>>16;
751 	zrparam[0x32] = sp2br>>8;
752 	zrparam[0x33] = sp2br>>0;
753 
754 	nbytes = 16;
755 	for(i = 0; i < 128; i++) {
756 		if(nbytes >= 16) {
757 			if(zrwaitrdy(2000, "load parameters"))
758 				return -1;
759 			nbytes = 0;
760 		}
761 		outb(mpegconf.zrport+ZRREG0, zrparam[i]);
762 		nbytes++;
763 	}
764 
765 	if(zrwaitrdy(2000, "load SVMDP"))
766 		return -1;
767 
768 	for(i = 0; i < SVMDPCOUNT; i++)
769 		outb(mpegconf.zrport+ZRREG3, zrmpeg3s[i]);
770 
771 	if(((zrs = zrstatus()) & 3) != 3) {
772 /*		print("devmpeg: error loading SVMDP sr=%2.2ux\n", zrs);	*/
773 		USED(zrs);
774 		return -1;
775 	}
776 	return 0;
777 }
778 
779 static struct
780 {
781 	short	reg;
782 	ushort	val;
783 } trireg[] =
784 {
785 	0x20, 0x0400,
786 	0x21, 0x00e9,
787 	0x22, 0x0000,
788 	0x23, 0x07ee,
789 	0x24, 0x0005,
790 	0x25, 0xff00,
791 	0x26, 0x0000,
792 	0x27, 0x7fff,
793 	0x28, 0x0004,
794 	0x29, 0x88a0,
795 	0x2a, 0x0011,
796 	0x2b, 0x8540,
797 	0x2c, 0x00c4,
798 	0x2d, 0x00ac,
799 	0x2e, 0x020f,
800 	0x2f, 0x019d,
801 	0x30, 0x00bd,
802 	0x31, 0x00ff,
803 	0x32, 0x0000,
804 	0x33, 0x0000,
805 	0x34, 0x03ff,
806 	0x35, 0x0000,
807 	0x36, 0x0000,
808 	0x37, 0x03ff,
809 	0x38, 0x0000,
810 	0x39, 0x0000,
811 	0x3a, 0x03ff,
812 	0x3b, 0x01da,
813 	0x3c, 0xe8ce,
814 	0x3d, 0x2ac0,
815 	0x3e, 0x891f,
816 	0x3f, 0x3e25,
817 	0x40, 0x03ff,
818 	0x41, 0x01ff,
819 	0x42, 0x001f,
820 	0x43, 0x01ff,
821 	0x44, 0x003b,
822 	0x45, 0x0186,
823 	0x46, 0x1d06,
824 	0x47, 0x1a4f,
825 	0x48, 0x020d,
826 	0x49, 0x01ad,
827 	0x4a, 0x001b,
828 	0x4b, 0x01fd,
829 	0x4c, 0x003a,
830 	0x4d, 0x034b,
831 	0x4e, 0x2006,
832 	0x4f, 0x0083,
833 	0x50, 0xef08,
834 	0x51, 0xef3a,
835 	0x52, 0xefff,
836 	0x53, 0xef08,
837 	0x54, 0xef08,
838 	0x55, 0xef15,
839 	0x56, 0xefc0,
840 	0x57, 0xef08,
841 	0x58, 0xefef,
842 	0x59, 0xefef,
843 	0x5a, 0xefef,
844 	0x5b, 0xefef,
845 	0x5c, 0xefef,
846 	0x5d, 0xefef,
847 	0x5e, 0xefef,
848 	0x5f, 0xefef,
849 	0x60, 0x0000,
850 	0x61, 0x0004,
851 	0x62, 0x0020,
852 	0x63, 0x8080,
853 	0x64, 0x0300,
854 	-1
855 };
856 
857 static void
858 clrI2C(uchar b)
859 {
860 	uchar t;
861 
862 	outb(mpegconf.trport+TRIINDEX, I2CR);
863 	t = inb(mpegconf.trport+TRIHI);
864 	t &= ~b;
865 	outb(mpegconf.trport+TRIHI, t);
866 }
867 
868 static void
869 setI2C(uchar b)
870 {
871 	uchar t;
872 
873 	outb(mpegconf.trport+TRIINDEX, I2CR);
874 	t = inb(mpegconf.trport+TRIHI);
875 	t |= b;
876 	outb(mpegconf.trport+TRIHI, t);
877 }
878 
879 static void
880 startI2C(void)
881 {
882 	setI2C(SDA);
883 	setI2C(SCL);
884 	microdelay(I2DLY);
885 	clrI2C(SDA);
886 	microdelay(I2DLY);
887 	clrI2C(SCL);
888 	microdelay(I2DLY);
889 }
890 
891 static void
892 endI2C(void)
893 {
894 	clrI2C(SDA);
895 	clrI2C(SCL);
896 	microdelay(I2DLY);
897 	setI2C(SCL);
898 	microdelay(I2DLY);
899 	setI2C(SDA);
900 	microdelay(I2DLY);
901 }
902 
903 static void
904 wrI2Cbit(uchar b)
905 {
906 	clrI2C(SDA);
907 	clrI2C(SCL);
908 	microdelay(I2DLY);
909 	if(b & 1) {
910 		setI2C(SDA);
911 		microdelay(I2DLY);
912 		setI2C(SCL);
913 		microdelay(I2DLY);
914 		clrI2C(SCL);
915 		microdelay(I2DLY);
916 		clrI2C(SDA);
917 		microdelay(I2DLY);
918 	}
919 	else {
920 		setI2C(SCL);
921 		microdelay(I2DLY);
922 		clrI2C(SCL);
923 		microdelay(I2DLY);
924 	}
925 }
926 
927 static void
928 wrI2CB(unsigned char data)
929 {
930 	int i;
931 
932 	for(i = 0; i < 8; i++)
933 		wrI2Cbit(data >>(7-i));
934 }
935 
936 static int
937 rdI2CBit(void)
938 {
939 	int bit = 1;
940 
941 	setI2C(SDA);
942 	clrI2C(SCL);
943 	setI2C(SCL);
944 	outb(mpegconf.trport+TRIINDEX, I2CR);
945 	if(inb(mpegconf.trport+TRIHI) & SDA)
946 		bit = 0;
947 	clrI2C(SDA);
948 	clrI2C(SCL);
949 
950 	return bit;
951 }
952 
953 static int
954 wrI2CD(uchar data)
955 {
956 	int r;
957 	ulong s;
958 
959 	s = splhi();
960 	wrI2CB(data);
961 	r = rdI2CBit();
962 	splx(s);
963 	return r;
964 }
965 
966 static uchar
967 setupSAA7110[] =
968 {
969 	/* Digital */
970 	0x4c, 0x3c, 0x0d, 0xef, 0xbd, 0xf0, 0x40, 0x03,
971 	0xf8, 0xf8, 0x90, 0x90, 0x00, 0x02, 0x10, 0x77,
972 	0x00, 0x2c, 0x40, 0x40, 0x3b, 0x10, 0xfc, 0xd2,
973 	0xf0, 0x80,
974 
975 	/* Analog */
976 	0xd9, 0x16, 0x40, 0x40, 0x80, 0x40, 0x80, 0x4f,
977 	0xfe, 0x01, 0xcf, 0x0f, 0x03, 0x01, 0x81, 0x0a,
978 	0x40, 0x35, 0x02, 0x8c, 0x03
979 };
980 
981 static void
982 addrI2CB(int addr, int val)
983 {
984 	ulong s;
985 
986 	s = splhi();
987 	startI2C();
988 	wrI2CD(SAA7110|WRITE_C);
989 	wrI2CD(addr);
990 	wrI2CD(val);
991 	endI2C();
992 	splx(s);
993 }
994 
995 static void
996 inittrident(void)
997 {
998 	int i;
999 
1000 	for(i = 0; trireg[i].reg != -1; i++)
1001 		triwr(trireg[i].reg, trireg[i].val);
1002 
1003 	for(i = 0; i < 47; i++)
1004 		addrI2CB(i, setupSAA7110[i]);
1005 }
1006 
1007 static void
1008 initcrystal(void)
1009 {
1010 	int i;
1011 	static int done;
1012 
1013 	if(done)
1014 		return;
1015 
1016 	done = 1;
1017 
1018 	initctl();
1019 
1020 	/* Reboot the Musicam decoder */
1021 	clrI2C(SCL);
1022 	clrI2C(SDA);
1023 	machsr |= DSPRST;
1024 	outs(mpegconf.zrport+ZRMACH210, machsr);
1025 	machsr |= DSPBOOT;
1026 	outs(mpegconf.zrport+ZRMACH210, machsr);
1027 	machsr &= ~DSPRST;
1028 	outs(mpegconf.zrport+ZRMACH210, machsr);
1029 	machsr |= DSPRST;
1030 	outs(mpegconf.zrport+ZRMACH210, machsr);
1031 	machsr &= ~DSPBOOT;
1032 	outs(mpegconf.zrport+ZRMACH210, machsr);
1033 
1034 	startI2C();
1035 	wrI2CD(0);
1036 	for(i = 0; i < sizeof(crystal); i++ )
1037 		wrI2CD(crystal[i]);
1038 	endI2C();
1039 }
1040 
1041 static void
1042 mpegintr(Ureg*, void*)
1043 {
1044 	Buf *b;
1045 
1046 	b = bqueue.head;
1047 	if(b == 0 || dmadone(mpegconf.dma) == 0)
1048 		return;
1049 
1050 	dmaend(mpegconf.dma);
1051 	if(b->nchar == 0) {
1052 		bqueue.head = b->link;
1053 		free(b);
1054 
1055 		b = bqueue.head;
1056 		if(b == 0) {
1057 			started = 0;
1058 			return;
1059 		}
1060 	}
1061 	zrdma(b);
1062 	wakeup(&bqueue.flow);
1063 }
1064