xref: /original-bsd/sys/news3400/iop/fb.c (revision 160e36b4)
1 /*
2  * Copyright (c) 1992 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * This code is derived from software contributed to Berkeley by
6  * Sony Corp. and Kazumasa Utashiro of Software Research Associates, Inc.
7  *
8  * %sccs.include.redist.c%
9  *
10  * from: $Hdr: fb.c,v 4.300 91/06/27 20:43:06 root Rel41 $ SONY
11  *
12  *	@(#)fb.c	7.2 (Berkeley) 12/17/92
13  */
14 
15 #include <machine/fix_machine_type.h>
16 
17 #include "fb.h"
18 #if NFB > 0
19 /*
20  * Frame buffer driver
21  */
22 
23 #include <sys/types.h>
24 #include <machine/pte.h>
25 #include <machine/cpu.h>
26 
27 #include <sys/param.h>
28 #include <sys/proc.h>
29 #include <sys/user.h>
30 #include <sys/buf.h>
31 #include <vm/vm.h>
32 #include <sys/systm.h>
33 #include <sys/map.h>
34 #include <sys/uio.h>
35 #include <sys/kernel.h>
36 
37 #include <news3400/iop/framebuf.h>
38 #include <news3400/iop/fbreg.h>
39 #include <news3400/iodev/ioptohb.h>
40 
41 #ifdef CPU_SINGLE
42 #include <news3400/hbdev/hbvar.h>
43 
44 #define ipc_phys(x)	(caddr_t)((int)(x))
45 #define ipc_log(x)	(caddr_t)((int)(x) | 0x80000000)
46 
47 #define iop_driver	hb_driver
48 #define iop_device	hb_device
49 
50 extern rop_xint();
51 #else /* CPU_SINGLE */
52 #include <news3400/iop/iopvar.h>
53 
54 #ifdef IPC_MRX
55 #include "../ipc/newsipc.h"
56 
57 #ifdef mips
58 #define ipc_phys(x)	K0_TT0(x)
59 #define ipc_log(x)	TT0_K0(x)
60 #else
61 #define	ipc_phys(x)	(caddr_t)((int)(x) & ~0x80000000)
62 #define	ipc_log(x)	(caddr_t)((int)(x) | 0x80000000)
63 #endif
64 
65 static int port_fb, port_fb_iop;
66 #endif /* IPC_MRX */
67 #endif /* CPU_SINGLE */
68 
69 #define FB_USED		1
70 #define VIDEO_USED	2
71 
72 /*
73  * driver definition
74  */
75 int fbprobe(), fbattach();
76 
77 struct iop_device *fbinfo[NFB];
78 struct iop_driver fbdriver =
79 #ifdef CPU_SINGLE
80 	{ fbprobe, 0, fbattach, 0, 0, "fb", fbinfo, "fbc", 0, 0 };
81 #else
82 	{ fbprobe, 0, fbattach, 0, "fb", fbinfo };
83 #endif
84 
85 /* static */
86 static struct fb_softc fb_softc[NFB];
87 static struct fbreg	fbreg[NFB];
88 static int fbstate;
89 static struct fbreg	*last_fb;
90 
91 static char *devname[] = {
92 /* 0*/	"",
93 /* 1*/	"NWB-512",
94 /* 2*/	"NWB-225",
95 /* 3*/	"POP-MONO",
96 /* 4*/	"POP-COLOR",
97 /* 5*/	"NWB-514",
98 /* 6*/	"NWB-251",
99 /* 7*/	"LCD-MONO",
100 /* 8*/	"LDC-COLOR",
101 /* 9*/	"NWB-518",
102 /*10*/	"NWB-252",
103 /*11*/	"NWB-253",
104 /*12*/	"NWB-254",
105 /*13*/	"NWB-255",
106 /*14*/	"SLB-101",
107 /*15*/	"NWB-256",
108 /*16*/	"NWB-257",
109 };
110 
111 static void	fblock(), fbunlock(), fbreset();
112 static int	fbinit();
113 
114 #ifdef CPU_DOUBLE
115 #ifdef USE_RAW_INTR
116 
117 #include "../mrx/h/ipc.h"
118 
119 #ifdef mips
120 # define	FB_ADDR		&IPC_ARG(&ipc_block, ARG_CPU, 4)
121 #else
122 # define	FB_ADDR		&IPC_ARG(&ipc_block, ARG_CPU0, 4)
123 # define	volatile
124 #endif
125 
126 typedef struct fbreg *fbregp;
127 int fb_waiting;
128 
129 Xfb_intr(chan, arg)
130 	int chan;
131 	int arg;
132 {
133 
134 	intrcnt[INTR_BITMAP]++;
135 	if (fb_waiting) {
136 		fb_waiting = 0;
137 		wakeup((caddr_t)&fb_waiting);
138 	}
139 }
140 
141 static void
142 fbwait()
143 {
144 	int s = splfb();
145 
146 	while (*(volatile fbregp *)FB_ADDR) {
147 		fb_waiting = 1;
148 		sleep((caddr_t)&fb_waiting, FBPRI);
149 	}
150 	(void) splx(s);
151 }
152 
153 void
154 fbstart(fbp, wait)
155 	struct fbreg *fbp;
156 	int wait;
157 {
158 
159 	fbwait();
160 	*(volatile fbregp *)FB_ADDR =
161 #ifdef mips
162 	    (volatile fbregp)ipc_phys(MACH_UNCACHED_TO_CACHED(fbp));
163 #else
164 	    (volatile fbregp)ipc_phys(fbp);
165 #endif
166 	if (wait)
167 		fbwait();
168 }
169 
170 #else /* USE_RAW_INTR */
171 
172 void
173 fbstart(fbp, wait)
174 	register struct fbreg *fbp;
175 	int wait;
176 {
177 	int s = splfb();
178 
179 #ifdef IPC_MRX
180 	msg_send(port_fb_iop, port_fb, fbp, sizeof(*fbp), MSG_INDIRECT);
181 #endif
182 
183 	last_fb = fbp;
184 	if (wait) {
185 		fbstate |= FB_WAIT;
186 		sleep((caddr_t)fbreg, FBPRI);
187 	} else {
188 		fbstate |= FB_DELAY;
189 	}
190 	splx(s);
191 }
192 
193 void
194 fbcint(arg)
195 	int arg;
196 {
197 
198 	intrcnt[INTR_BITMAP]++;
199 
200 #ifdef IPC_MRX
201 	msg_recv(arg, NULL, NULL, NULL, 0);
202 #ifdef mips
203 	clean_dcache((caddr_t)last_fb, sizeof(struct fbreg));
204 #endif
205 #endif /* IPC_MRX */
206 
207 	if (fbstate & FB_WAIT) {
208 		fbstate &= ~FB_WAIT;
209 		wakeup((caddr_t)fbreg);
210 	} else if (fbstate & FB_DELAY) {
211 		fbstate &= ~FB_DELAY;
212 	} else if (fbstate & FB_DELAY2) {
213 		fbstate &= ~(FB_BUSY|FB_DELAY2);
214 		if (fbstate & FB_WANTED) {
215 			fbstate &= ~FB_WANTED;
216 			wakeup((caddr_t)&fbstate);
217 		}
218 	}
219 	return;
220 }
221 #endif /* USE_RAW_INTR */
222 #endif /* CPU_DOUBLE */
223 
224 /* ARGSUSED */
225 fbprobe(ii)
226 	struct iop_device *ii;
227 {
228 	register int unit = ii->ii_unit;
229 	register struct fb_softc *fb = &fb_softc[unit];
230 #if defined(IPC_MRX) && defined(mips)
231 	register struct fbreg *fbp =
232 	    (struct fbreg *)MACH_CACHED_TO_UNCACHED(&fbreg[unit]);
233 #else
234 	register struct fbreg *fbp = &fbreg[unit];
235 #endif
236 
237 #ifdef CPU_SINGLE
238 	if (unit == 0)
239 		register_hb_intr2(rop_xint, ii->ii_unit, ii->ii_intr);
240 #endif
241 
242 #ifdef IPC_MRX
243 	if (port_fb_iop <= 0) {
244 #ifdef USE_RAW_INTR
245 		register_ipcintr(4, Xfb_intr);
246 #endif
247 		port_fb_iop = object_query("framebuf");
248 		if (port_fb_iop <= 0) {
249 			return (0);
250 		}
251 #ifndef USE_RAW_INTR
252 		port_fb = port_create("@port_fb", fbcint, -1);
253 #endif
254 	}
255 #endif /* IPC_MRX */
256 
257 	fbp->fb_command = FB_CPROBE;
258 	fbp->fb_device = 0;
259 	fbp->fb_unit = unit;
260 	fbp->fb_data = -1;
261 	fbstart(fbp, 1);
262 
263 	if ((fb->fbs_device = fbp->fb_data) == -1)
264 		return (0);
265 	else
266 		return (-1);
267 }
268 
269 /* ARGSUSED */
270 fbattach(ii)
271 	struct iop_device *ii;
272 {
273 	register int unit = ii->ii_unit;
274 	register struct fb_softc *fb = &fb_softc[unit];
275 #if defined(IPC_MRX) && defined(mips)
276 	register struct fbreg *fbp =
277 	    (struct fbreg *)MACH_CACHED_TO_UNCACHED(&fbreg[unit]);
278 #else
279 	register struct fbreg *fbp = &fbreg[unit];
280 #endif
281 
282 	fbp->fb_command = FB_CATTACH;
283 	fbp->fb_device = fb->fbs_device;
284 	fbstart(fbp, 1);
285 	fb->fbs_type = fbp->fb_scrtype;
286 
287 	if (fb->fbs_type.type) {
288 		fb->fbs_state = 0;
289 		fb->fbs_flag = 0;
290 		printf("fb%d: %s", unit,
291 			(fb->fbs_type.type < sizeof(devname)/sizeof(*devname))
292 				? devname[fb->fbs_type.type] : "UNKNOWN");
293 		printf(" (%d x %d %d plane)\n",
294 				fb->fbs_type.visiblerect.extent.x,
295 				fb->fbs_type.visiblerect.extent.y,
296 				fb->fbs_type.plane);
297 	}
298 }
299 
300 /*ARGSUSED*/
301 fbopen(dev, flag)
302 	dev_t dev;
303 	int flag;
304 {
305 	register int unit = FBUNIT(dev);
306 	register struct fb_softc *fb = &fb_softc[unit];
307 	register struct iop_device *ii;
308 #if defined(IPC_MRX) && defined(mips)
309 	register struct fbreg *fbp =
310 	    (struct fbreg *)MACH_CACHED_TO_UNCACHED(&fbreg[unit]);
311 #else
312 	register struct fbreg *fbp = &fbreg[unit];
313 #endif
314 
315 	if (unit >= NFB || (ii = fbinfo[unit]) == 0 || ii->ii_alive == 0)
316 		return (ENXIO);
317 	if (fb->fbs_flag && !FBVIDEO(dev))
318 		return (EBUSY);
319 
320 	if (fb->fbs_state == 0) {
321 		fbp->fb_device = fb->fbs_device;
322 		if(fbinit(fbp))
323 			return (EBUSY);
324 	}
325 
326         fb->fbs_state |= FBVIDEO(dev) ? VIDEO_USED : FB_USED;
327 
328 	return (0);
329 }
330 
331 /*ARGSUSED*/
332 fbclose(dev, flag)
333 	dev_t dev;
334 	int flag;
335 {
336 	register int unit = FBUNIT(dev);
337 	register struct fb_softc *fb = &fb_softc[unit];
338 	register struct iop_device *ii;
339 #if defined(IPC_MRX) && defined(mips)
340 	register struct fbreg *fbp =
341 	    (struct fbreg *)MACH_CACHED_TO_UNCACHED(&fbreg[unit]);
342 #else
343 	register struct fbreg *fbp = &fbreg[unit];
344 #endif
345 
346 	if (unit >= NFB || (ii = fbinfo[unit]) == 0 || ii->ii_alive == 0)
347 		return (ENXIO);
348 
349 	if (fb->fbs_state == 0)
350 		return(0);
351 
352 	if(!FBVIDEO(dev))
353 		fb->fbs_flag = 0;
354 
355 	fb->fbs_state &= ~(FBVIDEO(dev) ? VIDEO_USED : FB_USED);
356 
357 	if (fb->fbs_state == 0) {
358 		fbp->fb_device = fb->fbs_device;
359 		fbreset(fbp);
360 	}
361 
362 	return (0);
363 }
364 
365 fbioctl(dev, cmd, data, flag)
366 	dev_t dev;
367 	caddr_t data;
368 {
369 	register int unit = FBUNIT(dev);
370 	register struct fb_softc *fb = &fb_softc[unit];
371 	register struct iop_device *ii;
372 	register int error = 0;
373 #if defined(IPC_MRX) && defined(mips)
374 	register struct fbreg *fbp =
375 	    (struct fbreg *)MACH_CACHED_TO_UNCACHED(&fbreg[unit]);
376 #else
377 	register struct fbreg *fbp = &fbreg[unit];
378 #endif
379 
380 	if (unit >= NFB || (ii = fbinfo[unit]) == 0 || ii->ii_alive == 0)
381 		return (ENXIO);
382 
383 	fblock();
384 
385 	fbp->fb_device = fb->fbs_device;
386 
387 	switch (cmd) {
388 	case FBIOCENABLE:
389 		fb->fbs_flag = 0;
390 		break;
391 	case FBIOCDISABLE:
392 		fb->fbs_flag = 1;
393 		break;
394 	case FBIOCAUTODIM:
395 		fbp->fb_command = FB_CAUTODIM;
396 		fbp->fb_data = *((int *)data);
397 		fbstart(fbp, 0);
398 		break;
399 	case FBIOCSETDIM:
400 		fbp->fb_command = FB_CSETDIM;
401 		fbp->fb_data = *((int*)data);
402 		fbstart(fbp, 0);
403 		break;
404 	case FBIOCGETDIM:
405 		fbp->fb_command = FB_CGETDIM;
406 		fbstart(fbp, 1);
407 		*((int*)data) = fbp->fb_data;
408 		break;
409 	case FBIOCBITBLT:
410 		error = fbbitblt(fbp, (sBitblt *)data);
411 		break;
412 	case FBIOCNBITBLT:
413 		error = fbnbitblt(fbp, (lBitblt *)data, UIO_USERSPACE);
414 		break;
415 	case FBIOCBATCHBITBLT:
416 		error = fbbatchbitblt(fbp, (sBatchBitblt*)data, UIO_USERSPACE);
417 		break;
418 	case FBIOCNBATCHBITBLT:
419 		error = fbnbatchbitblt(fbp, (lBatchBitblt*)data, UIO_USERSPACE);
420 		break;
421 	case FBIOCTILEBITBLT:
422 		error = fbtilebitblt(fbp, (sTileBitblt *)data);
423 		break;
424 	case FBIOCNTILEBITBLT:
425 		error = fbntilebitblt(fbp, (lTileBitblt *)data);
426 		break;
427 	case FBIOCBITBLT3:
428 		error = fbbitblt3(fbp, (sBitblt3 *)data);
429 		break;
430 	case FBIOCNBITBLT3:
431 		error = fbnbitblt3(fbp, (lBitblt3 *)data);
432 		break;
433 	case FBIOCPOLYLINE:
434 		error = fbpolyline(fbp, (sPrimLine *)data, 0);
435 		break;
436 	case FBIOCNPOLYLINE:
437 		error = fbnpolyline(fbp, (lPrimLine *)data, 0, UIO_USERSPACE);
438 		break;
439 	case FBIOCDJPOLYLINE:
440 		error = fbpolyline(fbp, (sPrimLine *)data, 1);
441 		break;
442 	case FBIOCNDJPOLYLINE:
443 		error = fbnpolyline(fbp, (lPrimLine *)data, 1, UIO_USERSPACE);
444 		break;
445 	case FBIOCPOLYMARKER:
446 		error = fbpolymarker(fbp, (sPrimMarker *)data);
447 		break;
448 	case FBIOCNPOLYMARKER:
449 		error = fbnpolymarker(fbp, (lPrimMarker *)data, UIO_USERSPACE);
450 		break;
451 	case FBIOCRECTANGLE:
452 		error = fbrectangle(fbp, (sPrimRect *)data);
453 		break;
454 	case FBIOCNRECTANGLE:
455 		error = fbnrectangle(fbp, (lPrimRect *)data);
456 		break;
457 	case FBIOCFILLSCAN:
458 		error = fbfillscan(fbp, (sPrimFill *)data);
459 		break;
460 	case FBIOCNFILLSCAN:
461 		error = fbnfillscan(fbp, (lPrimFill *)data, UIO_USERSPACE);
462 		break;
463 	case FBIOCTEXT:
464 		error = fbtext(fbp, (sPrimText *)data);
465 		break;
466 	case FBIOCNTEXT:
467 		error = fbntext(fbp, (lPrimText *)data);
468 		break;
469 	case FBIOCPOLYDOT:
470 		error = fbpolydot(fbp, (sPrimDot *)data);
471 		break;
472 	case FBIOCNPOLYDOT:
473 		error = fbnpolydot(fbp, (lPrimDot *)data, UIO_USERSPACE);
474 		break;
475 
476 	case FBIOCGETSCRTYPE:
477 		fbgetscrtype(fbp, (sScrType *)data);
478 		break;
479 	case FBIOCNGETSCRTYPE:
480 		fbp->fb_command = FB_CGETSCRTYPE;
481 		fbstart(fbp, 1);
482 		*((lScrType*)data) = fbp->fb_scrtype;
483 		break;
484 	case FBIOCSETPALETTE:
485 		fbsetpalette(fbp, (sPalette *)data);
486 		break;
487 	case FBIOCNSETPALETTE:
488 		error = fbnsetpalette(fbp, (lPalette *)data);
489 		break;
490 	case FBIOCGETPALETTE:
491 		fbgetpalette(fbp, (sPalette *)data);
492 		break;
493 	case FBIOCNGETPALETTE:
494 		error = fbngetpalette(fbp, (lPalette *)data);
495 		break;
496 	case FBIOCSETCURSOR:
497 		fbsetcursor(fbp, (sCursor *)data);
498 		break;
499 	case FBIOCNSETCURSOR:
500 		fbnsetcursor(fbp, (lCursor *)data);
501 		break;
502 	case FBIOCNSETCURSOR2:
503 		fbp->fb_command = FB_CSETCURSOR;
504 		fbp->fb_cursor = *((lCursor2 *)data);
505 		fbstart(fbp, 0);
506 		break;
507 	case FBIOCUNSETCURSOR:
508 		fbp->fb_command = FB_CUNSETCURSOR;
509 		fbstart(fbp, 0);
510 		break;
511 	case FBIOCNUNSETCURSOR:
512 		fbp->fb_command = FB_CUNSETCURSOR;
513 		fbstart(fbp, 0);
514 		break;
515 	case FBIOCSHOWCURSOR:
516 		fbp->fb_command = FB_CSHOWCURSOR;
517 		fbstart(fbp, 0);
518 		break;
519 	case FBIOCNSHOWCURSOR:
520 		fbp->fb_command = FB_CSHOWCURSOR;
521 		fbstart(fbp, 0);
522 		break;
523 	case FBIOCHIDECURSOR:
524 		fbp->fb_command = FB_CHIDECURSOR;
525 		fbstart(fbp, 0);
526 		break;
527 	case FBIOCNHIDECURSOR:
528 		fbp->fb_command = FB_CHIDECURSOR;
529 		fbstart(fbp, 0);
530 		break;
531 	case FBIOCSETXY:
532 		fbsetxy(fbp, (sPoint *)data);
533 		break;
534 	case FBIOCNSETXY:
535 		fbp->fb_command = FB_CSETXY;
536 		fbp->fb_point = *((lPoint *)data);
537 		fbstart(fbp, 0);
538 		break;
539 	case FBIOCNSETPALETTEMODE:
540 		fbp->fb_command = FB_CSETPMODE;
541 		fbp->fb_data = *((int*)data);
542 		fbstart(fbp, 0);
543 		break;
544 	case FBIOCNGETPALETTEMODE:
545 		fbp->fb_command = FB_CGETPMODE;
546 		fbstart(fbp, 1);
547 		*((int*)data) = fbp->fb_data;
548 		break;
549 	case FBIOCNSETVIDEO:
550 		fbp->fb_command = FB_CSETVIDEO;
551 		fbp->fb_videoctl = *((lVideoCtl*)data);
552 		fbstart(fbp, 0);
553 		break;
554 	case FBIOCNGETVIDEO:
555 		fbp->fb_command = FB_CGETVIDEO;
556 		fbp->fb_videostatus.request = VIDEO_STATUS;
557 		fbstart(fbp, 1);
558 		*((lVideoStatus*)data) = fbp->fb_videostatus;
559 		error = fbp->fb_result;
560 		break;
561 	case FBIOCNIOCTL:
562 		fbp->fb_command = FB_CIOCTL;
563 		fbp->fb_fbioctl = *((lFbIoctl*)data);
564 		fbstart(fbp, 1);
565 		*((lFbIoctl*)data) = fbp->fb_fbioctl;
566 		if (fbp->fb_result == FB_RERROR)
567 			error = EINVAL;
568 		break;
569 
570 	default:
571 		error = ENXIO;
572 		break;
573 	}
574 
575 	fbunlock(error);
576 
577 	return (error);
578 }
579 
580 fbmmap(dev, off, prot)
581 	dev_t dev;
582 	off_t off;
583 	int prot;
584 {
585 	register int unit = FBUNIT(dev);
586 	register struct fb_softc *fb = &fb_softc[unit];
587 	register struct iop_device *ii;
588 	register int page;
589 	register struct fbreg *fbp = &fbreg[unit];
590 
591 	if (unit >= NFB || (ii = fbinfo[unit]) == 0 || ii->ii_alive == 0)
592 		return (-1);
593 
594 	fblock();
595 	fbp->fb_device = fb->fbs_device;
596 	fbp->fb_command = FB_CGETPAGE;
597 	fbp->fb_data = off;
598 	fbstart(fbp, 1);
599 	page = fbp->fb_data;
600 	if (fbp->fb_result == FB_RERROR)
601 		page = -1;
602 	else
603 		fb->fbs_flag = 1;
604 	fbunlock(fbp->fb_result);
605 
606 	return (page);
607 }
608 
609 static void
610 fblock()
611 {
612 	int s;
613 
614 #ifdef USE_RAW_INTR
615 	fbwait();
616 #endif
617 	s = splfb();
618 	while (fbstate & FB_BUSY) {
619 		fbstate |= FB_WANTED;
620 		sleep((caddr_t)&fbstate, FBPRI);
621 	}
622 	fbstate |= FB_BUSY;
623 	splx(s);
624 }
625 
626 static void
627 fbunlock(error)
628 	int error;
629 {
630 	int s = splfb();
631 
632 #ifdef CPU_SINGLE
633 	fbstate &= ~FB_BUSY;
634 	if (fbstate & FB_WANTED) {
635 		fbstate &= ~FB_WANTED;
636 		wakeup((caddr_t)&fbstate);
637 	}
638 #else
639 #ifdef USE_RAW_INTR
640 	fbstate &= ~FB_BUSY;
641 	if (fbstate & FB_WANTED) {
642 		fbstate &= ~FB_WANTED;
643 		wakeup((caddr_t)&fbstate);
644 	}
645 #else
646 	if (error || (fbstate & FB_DELAY) == 0) {
647 		fbstate &= ~(FB_BUSY | FB_WAIT | FB_DELAY);
648 		if (fbstate & FB_WANTED) {
649 			fbstate &= ~FB_WANTED;
650 			wakeup((caddr_t)&fbstate);
651 		}
652 	}
653 	if (fbstate & FB_DELAY) {
654 		fbstate &= ~FB_DELAY;
655 		fbstate |= FB_DELAY2;
656 	}
657 #endif
658 #endif /* CPU_SINGLE */
659 	splx(s);
660 }
661 
662 static int
663 fbinit(fbp)
664 	struct fbreg *fbp;
665 {
666 	fblock();
667 
668 	fbp->fb_command = FB_COPEN;
669 	fbstart(fbp, 1);
670 	if (fbp->fb_result != FB_ROK) {
671 		fbunlock(0);
672 		return (FB_RERROR);
673 	}
674 
675 	fbp->fb_command = FB_CUNSETCURSOR;
676 	fbstart(fbp, 0);
677 
678 	fbunlock(0);
679 
680 	return (FB_ROK);
681 }
682 
683 static void
684 fbreset(fbp)
685 	struct fbreg *fbp;
686 {
687 	fblock();
688 
689 	fbp->fb_command = FB_CUNSETCURSOR;
690 	fbstart(fbp, 1);
691 
692 	fbp->fb_command = FB_CCLOSE;
693 	fbstart(fbp, 0);
694 
695 	fbunlock(0);
696 }
697 #endif /* NFB */
698