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