xref: /netbsd-src/sys/dev/sun/fb.c (revision 08c81a9c2dc8c7300e893321eb65c0925d60871c)
1 /*	$NetBSD: fb.c,v 1.8 2002/09/06 13:18:43 gehenna Exp $ */
2 
3 /*
4  * Copyright (c) 1992, 1993
5  *	The Regents of the University of California.  All rights reserved.
6  *
7  * This software was developed by the Computer Systems Engineering group
8  * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
9  * contributed to Berkeley.
10  *
11  * All advertising materials mentioning features or use of this software
12  * must display the following acknowledgement:
13  *	This product includes software developed by the University of
14  *	California, Lawrence Berkeley Laboratory.
15  *
16  * Redistribution and use in source and binary forms, with or without
17  * modification, are permitted provided that the following conditions
18  * are met:
19  * 1. Redistributions of source code must retain the above copyright
20  *    notice, this list of conditions and the following disclaimer.
21  * 2. Redistributions in binary form must reproduce the above copyright
22  *    notice, this list of conditions and the following disclaimer in the
23  *    documentation and/or other materials provided with the distribution.
24  * 3. All advertising materials mentioning features or use of this software
25  *    must display the following acknowledgement:
26  *	This product includes software developed by the University of
27  *	California, Berkeley and its contributors.
28  * 4. Neither the name of the University nor the names of its contributors
29  *    may be used to endorse or promote products derived from this software
30  *    without specific prior written permission.
31  *
32  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
33  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
34  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
35  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
36  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
37  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
38  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
39  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
40  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
41  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
42  * SUCH DAMAGE.
43  *
44  *	@(#)fb.c	8.1 (Berkeley) 6/11/93
45  */
46 
47 /*
48  * /dev/fb (indirect frame buffer driver).  This is gross; we should
49  * just build cdevsw[] dynamically.
50  */
51 
52 #include <sys/cdefs.h>
53 __KERNEL_RCSID(0, "$NetBSD: fb.c,v 1.8 2002/09/06 13:18:43 gehenna Exp $");
54 
55 #include <sys/param.h>
56 #include <sys/systm.h>
57 #include <sys/device.h>
58 #include <sys/proc.h>
59 #include <sys/conf.h>
60 
61 #include <machine/autoconf.h>
62 #include <machine/kbd.h>
63 #include <machine/eeprom.h>
64 #include <sparc/dev/cons.h>
65 
66 #include <dev/sun/fbio.h>
67 #include <dev/sun/fbvar.h>
68 
69 #include "kbd.h"
70 #include "pfour.h"
71 
72 static struct fbdevice *devfb;
73 
74 dev_type_open(fbopen);
75 dev_type_close(fbclose);
76 dev_type_ioctl(fbioctl);
77 dev_type_poll(fbpoll);
78 dev_type_mmap(fbmmap);
79 
80 const struct cdevsw fb_cdevsw = {
81 	fbopen, fbclose, noread, nowrite, fbioctl,
82 	nostop, notty, fbpoll, fbmmap,
83 };
84 
85 void
86 fb_unblank()
87 {
88 
89 	if (devfb)
90 		(*devfb->fb_driver->fbd_unblank)(devfb->fb_device);
91 }
92 
93 /*
94  * Helper function for frame buffer devices. Decides whether
95  * the device can be the console output device according to
96  * PROM info. The result from this function may not be conclusive
97  * on machines with old PROMs; in that case, drivers should consult
98  * other sources of configuration information (e.g. EEPROM entries).
99  */
100 #if defined(SUN4U)
101 /* Temporary special case for sun4u */
102 int
103 fb_is_console(node)
104 	int node;
105 {
106 	extern int fbnode;
107 	return (node == fbnode);
108 }
109 #else
110 int
111 fb_is_console(node)
112 	int node;
113 {
114 	int fbnode;
115 
116 	switch (prom_version()) {
117 	case PROM_OLDMON:
118 		/* `node' is not valid; just check for any fb device */
119 		return (prom_stdout() == PROMDEV_SCREEN);
120 
121 	case PROM_OBP_V0:
122 		/*
123 		 * First, check if prom_stdout() represents a frame buffer,
124 		 * then match on the `fb' property on the root node, if any.
125 		 */
126 		if (prom_stdout() != PROMDEV_SCREEN)
127 			return (0);
128 
129 		fbnode = PROM_getpropint(findroot(), "fb", 0);
130 		return (fbnode == 0 || node == fbnode);
131 
132 	case PROM_OBP_V2:
133 	case PROM_OBP_V3:
134 	case PROM_OPENFIRM:
135 		/* Just match the nodes */
136 		return (node == prom_stdout_node);
137 	}
138 
139 	return (0);
140 }
141 #endif /* SUN4U */
142 
143 void
144 fb_attach(fb, isconsole)
145 	struct fbdevice *fb;
146 	int isconsole;
147 {
148 	static int no_replace, seen_force;
149 
150 	/*
151 	 * We've already had a framebuffer forced into /dev/fb.  Don't
152 	 * allow any more, even if this is the console.
153 	 */
154 	if (seen_force) {
155 		if (devfb) {	/* sanity */
156 			printf("%s: /dev/fb already full\n",
157 				fb->fb_device->dv_xname);
158 			return;
159 		} else
160 			seen_force = 0;
161 	}
162 
163 	/*
164 	 * Check to see if we're being forced into /dev/fb.
165 	 */
166 	if (fb->fb_flags & FB_FORCE) {
167 		if (devfb)
168 			printf("%s: forcefully replacing %s\n",
169 				fb->fb_device->dv_xname,
170 				devfb->fb_device->dv_xname);
171 		devfb = fb;
172 		seen_force = no_replace = 1;
173 		goto attached;
174 	}
175 
176 	/*
177 	 * Check to see if we're the console.  If we are, then replace
178 	 * any currently existing framebuffer.
179 	 */
180 	if (isconsole) {
181 		if (devfb)
182 			printf("%s: replacing %s\n", fb->fb_device->dv_xname,
183 				devfb->fb_device->dv_xname);
184 		devfb = fb;
185 		no_replace = 1;
186 		goto attached;
187 	}
188 
189 	/*
190 	 * For the final case, we check to see if we can replace an
191 	 * existing framebuffer, if not, say so and return.
192 	 */
193 	if (no_replace) {
194 		if (devfb) {	/* sanity */
195 			printf("%s: /dev/fb already full\n",
196 				fb->fb_device->dv_xname);
197 			return;
198 		} else
199 			no_replace = 0;
200 	}
201 
202 	if (devfb)
203 		printf("%s: replacing %s\n", fb->fb_device->dv_xname,
204 			devfb->fb_device->dv_xname);
205 	devfb = fb;
206 
207  attached:
208 	printf("%s: attached to /dev/fb\n", devfb->fb_device->dv_xname);
209 }
210 
211 int
212 fbopen(dev, flags, mode, p)
213 	dev_t dev;
214 	int flags, mode;
215 	struct proc *p;
216 {
217 
218 	if (devfb == NULL)
219 		return (ENXIO);
220 	return (devfb->fb_driver->fbd_open)(dev, flags, mode, p);
221 }
222 
223 int
224 fbclose(dev, flags, mode, p)
225 	dev_t dev;
226 	int flags, mode;
227 	struct proc *p;
228 {
229 
230 	return (devfb->fb_driver->fbd_close)(dev, flags, mode, p);
231 }
232 
233 int
234 fbioctl(dev, cmd, data, flags, p)
235 	dev_t dev;
236 	u_long cmd;
237 	caddr_t data;
238 	int flags;
239 	struct proc *p;
240 {
241 
242 	return (devfb->fb_driver->fbd_ioctl)(dev, cmd, data, flags, p);
243 }
244 
245 int
246 fbpoll(dev, events, p)
247 	dev_t dev;
248 	int events;
249 	struct proc *p;
250 {
251 
252 	return (devfb->fb_driver->fbd_poll)(dev, events, p);
253 }
254 
255 paddr_t
256 fbmmap(dev, off, prot)
257 	dev_t dev;
258 	off_t off;
259 	int prot;
260 {
261 	paddr_t (*map)__P((dev_t, off_t, int)) = devfb->fb_driver->fbd_mmap;
262 
263 	if (map == NULL)
264 		return (-1);
265 	return (map(dev, off, prot));
266 }
267 
268 void
269 fb_setsize_obp(fb, depth, def_width, def_height, node)
270 	struct fbdevice *fb;
271 	int depth, def_width, def_height, node;
272 {
273 	fb->fb_type.fb_width = PROM_getpropint(node, "width", def_width);
274 	fb->fb_type.fb_height = PROM_getpropint(node, "height", def_height);
275 	fb->fb_linebytes = PROM_getpropint(node, "linebytes",
276 				     (fb->fb_type.fb_width * depth) / 8);
277 }
278 
279 void
280 fb_setsize_eeprom(fb, depth, def_width, def_height)
281 	struct fbdevice *fb;
282 	int depth, def_width, def_height;
283 {
284 #if !defined(SUN4U)
285 	struct eeprom *eep = (struct eeprom *)eeprom_va;
286 
287 	if (!CPU_ISSUN4) {
288 		printf("fb_setsize_eeprom: not sun4\n");
289 		return;
290 	}
291 
292 	/* Set up some defaults. */
293 	fb->fb_type.fb_width = def_width;
294 	fb->fb_type.fb_height = def_height;
295 
296 	if (fb->fb_flags & FB_PFOUR) {
297 #if NPFOUR > 0
298 		fb_setsize_pfour(fb);
299 #endif
300 	} else if (eep != NULL) {
301 		switch (eep->eeScreenSize) {
302 		case EE_SCR_1152X900:
303 			fb->fb_type.fb_width = 1152;
304 			fb->fb_type.fb_height = 900;
305 			break;
306 
307 		case EE_SCR_1024X1024:
308 			fb->fb_type.fb_width = 1024;
309 			fb->fb_type.fb_height = 1024;
310 			break;
311 
312 		case EE_SCR_1600X1280:
313 			fb->fb_type.fb_width = 1600;
314 			fb->fb_type.fb_height = 1280;
315 			break;
316 
317 		case EE_SCR_1440X1440:
318 			fb->fb_type.fb_width = 1440;
319 			fb->fb_type.fb_height = 1440;
320 			break;
321 
322 		default:
323 			/*
324 			 * XXX: Do nothing, I guess.
325 			 * Should we print a warning about
326 			 * an unknown value? --thorpej
327 			 */
328 			break;
329 		}
330 	}
331 
332 	fb->fb_linebytes = (fb->fb_type.fb_width * depth) / 8;
333 #endif /* !SUN4U */
334 }
335 
336 
337 
338 #ifdef RASTERCONSOLE
339 #include <machine/kbd.h>
340 
341 static void fb_bell __P((int));
342 
343 #if !defined(RASTERCONS_FULLSCREEN)
344 static int a2int __P((char *, int));
345 
346 static int
347 a2int(cp, deflt)
348 	register char *cp;
349 	register int deflt;
350 {
351 	register int i = 0;
352 
353 	if (*cp == '\0')
354 		return (deflt);
355 	while (*cp != '\0')
356 		i = i * 10 + *cp++ - '0';
357 	return (i);
358 }
359 #endif
360 
361 static void
362 fb_bell(on)
363 	int on;
364 {
365 #if NKBD > 0
366 	(void)kbd_docmd(on?KBD_CMD_BELL:KBD_CMD_NOBELL, 0);
367 #endif
368 }
369 
370 void
371 fbrcons_init(fb)
372 	struct fbdevice *fb;
373 {
374 	struct rconsole	*rc = &fb->fb_rcons;
375 	struct rasops_info *ri = &fb->fb_rinfo;
376 	int maxrow, maxcol;
377 #if !defined(RASTERCONS_FULLSCREEN)
378 	int *row, *col;
379 #endif
380 
381 	/* Set up what rasops needs to know about */
382 	bzero(ri, sizeof *ri);
383 	ri->ri_stride = fb->fb_linebytes;
384 	ri->ri_bits = (caddr_t)fb->fb_pixels;
385 	ri->ri_depth = fb->fb_type.fb_depth;
386 	ri->ri_width = fb->fb_type.fb_width;
387 	ri->ri_height = fb->fb_type.fb_height;
388 	maxrow = 5000;
389 	maxcol = 5000;
390 
391 #if !defined(RASTERCONS_FULLSCREEN)
392 #if !defined(SUN4U)
393 	if (CPU_ISSUN4) {
394 		struct eeprom *eep = (struct eeprom *)eeprom_va;
395 
396 		if (eep == NULL) {
397 			maxcol = 80;
398 			maxrow = 34;
399 		} else {
400 			maxcol = eep->eeTtyCols;
401 			maxrow = eep->eeTtyRows;
402 		}
403 	}
404 #endif /* !SUN4U */
405 	if (!CPU_ISSUN4) {
406 		maxcol =
407 		    a2int(PROM_getpropstring(optionsnode, "screen-#columns"), 80);
408 		maxrow =
409 		    a2int(PROM_getpropstring(optionsnode, "screen-#rows"), 34);
410 	}
411 #endif /* !RASTERCONS_FULLSCREEN */
412 	/*
413 	 * - force monochrome output
414 	 * - eraserows() hack to clear the *entire* display
415 	 * - cursor is currently enabled
416 	 * - center output
417 	 */
418 	ri->ri_flg = RI_FULLCLEAR | RI_CURSOR | RI_CENTER;
419 
420 	/* Get operations set and connect to rcons */
421 	if (rasops_init(ri, maxrow, maxcol))
422 		panic("fbrcons_init: rasops_init failed!");
423 
424 	if (ri->ri_depth == 8) {
425 		int i;
426 		for (i = 0; i < 16; i++) {
427 
428 			/*
429 			 * Cmap entries are repeated four times in the
430 			 * 32 bit wide `devcmap' entries for optimization
431 			 * purposes; see rasops(9)
432 			 */
433 #define I_TO_DEVCMAP(i)	((i) | ((i)<<8) | ((i)<<16) | ((i)<<24))
434 
435 			/*
436 			 * Use existing colormap entries for black and white
437 			 */
438 			if ((i & 7) == WSCOL_BLACK) {
439 				ri->ri_devcmap[i] = I_TO_DEVCMAP(255);
440 				continue;
441 			}
442 
443 			if ((i & 7) == WSCOL_WHITE) {
444 				ri->ri_devcmap[i] = I_TO_DEVCMAP(0);
445 				continue;
446 			}
447 			/*
448 			 * Other entries refer to ANSI map, which for now
449 			 * is setup in bt_subr.c
450 			 */
451 			ri->ri_devcmap[i] = I_TO_DEVCMAP(i + 1);
452 #undef I_TO_DEVCMAP
453 		}
454 	}
455 
456 	rc->rc_row = rc->rc_col = 0;
457 #if !defined(RASTERCONS_FULLSCREEN)
458 	/* Determine addresses of prom emulator row and column */
459 	if (!CPU_ISSUN4 && !romgetcursoraddr(&row, &col)) {
460 		rc->rc_row = *row;
461 		rc->rc_col = *col;
462 	}
463 #endif
464 	ri->ri_crow = rc->rc_row;
465 	ri->ri_ccol = rc->rc_col;
466 
467 	rc->rc_ops = &ri->ri_ops;
468 	rc->rc_cookie = ri;
469 	rc->rc_bell = fb_bell;
470 	rc->rc_maxcol = ri->ri_cols;
471 	rc->rc_maxrow = ri->ri_rows;
472 	rc->rc_width = ri->ri_emuwidth;
473 	rc->rc_height = ri->ri_emuheight;
474 	rc->rc_deffgcolor = WSCOL_BLACK;
475 	rc->rc_defbgcolor = WSCOL_WHITE;
476 	rcons_init(rc, 0);
477 
478 	/* Hook up virtual console */
479 	v_putc = rcons_cnputc;
480 }
481 
482 int
483 fbrcons_rows()
484 {
485 	return (devfb ? devfb->fb_rcons.rc_maxrow : 0);
486 }
487 
488 int
489 fbrcons_cols()
490 {
491 	return (devfb ? devfb->fb_rcons.rc_maxcol : 0);
492 }
493 #endif /* RASTERCONSOLE */
494