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
Xfb_intr(chan,arg)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
fbwait()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
fbstart(fbp,wait)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
fbstart(fbp,wait)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
fbcint(arg)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*/
fbopen(dev,flag)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*/
fbclose(dev,flag)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
fbioctl(dev,cmd,data,flag)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
fbmmap(dev,off,prot)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
fblock()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
fbunlock(error)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
fbinit(fbp)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
fbreset(fbp)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