1 /* $NetBSD: fb.c,v 1.31 2009/03/18 10:22:41 cegger Exp $ */
4 * Copyright (c) 1992, 1993
5 * The Regents of the University of California. All rights reserved.
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.
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.
16 * Redistribution and use in source and binary forms, with or without
17 * modification, are permitted provided that the following conditions
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. Neither the name of the University nor the names of its contributors
25 * may be used to endorse or promote products derived from this software
26 * without specific prior written permission.
28 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
29 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
32 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
36 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
37 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
40 * @(#)fb.c 8.1 (Berkeley) 6/11/93
44 * /dev/fb (indirect frame buffer driver). This is gross; we should
45 * just build cdevsw[] dynamically.
48 #include <sys/cdefs.h>
49 __KERNEL_RCSID(0, "$NetBSD: fb.c,v 1.31 2009/03/18 10:22:41 cegger Exp $");
51 #include <sys/param.h>
52 #include <sys/systm.h>
53 #include <sys/device.h>
56 #include <sys/malloc.h>
57 #include <sys/types.h>
59 #include <machine/promlib.h>
60 #include <machine/autoconf.h>
61 #include <machine/kbd.h>
62 #include <machine/eeprom.h>
63 #include <sparc/dev/cons.h>
65 #include <dev/sun/fbio.h>
66 #include <dev/sun/fbvar.h>
73 struct fbdevice
*fb_dev
;
74 struct fbdevlist
*fb_next
;
77 static struct fbdevlist fblist
= {
82 dev_type_open(fbopen
);
83 dev_type_close(fbclose
);
84 dev_type_ioctl(fbioctl
);
85 dev_type_poll(fbpoll
);
86 dev_type_mmap(fbmmap
);
87 dev_type_kqfilter(fbkqfilter
);
89 const struct cdevsw fb_cdevsw
= {
90 fbopen
, fbclose
, noread
, nowrite
, fbioctl
,
91 nostop
, notty
, fbpoll
, fbmmap
, fbkqfilter
, D_OTHER
98 struct fbdevlist
*fbl
= &fblist
;
100 while (fbl
!= NULL
&& fbl
->fb_dev
!= NULL
) {
101 (*fbl
->fb_dev
->fb_driver
->fbd_unblank
)(fbl
->fb_dev
->fb_device
);
107 * Helper function for frame buffer devices. Decides whether
108 * the device can be the console output device according to
109 * PROM info. The result from this function may not be conclusive
110 * on machines with old PROMs; in that case, drivers should consult
111 * other sources of configuration information (e.g. EEPROM entries).
114 fb_is_console(int node
)
119 switch (prom_version()) {
121 /* `node' is not valid; just check for any fb device */
122 return (prom_stdout() == PROMDEV_SCREEN
);
126 * First, check if prom_stdout() represents a frame buffer,
127 * then match on the `fb' property on the root node, if any.
129 if (prom_stdout() != PROMDEV_SCREEN
)
132 fbnode
= prom_getpropint(findroot(), "fb", 0);
133 return (fbnode
== 0 || node
== fbnode
);
138 /* Just match the nodes */
139 return (node
== prom_stdout_node
);
144 return (node
== prom_stdout_node
);
149 fb_attach(struct fbdevice
*fb
, int isconsole
)
151 static int seen_force
= 0;
153 struct fbdevlist
*fbl
= &fblist
;
156 * Check to see if we're being forced into /dev/fb0, or if we're
157 * the console. If we are, then move/replace the current fb0.
159 if ((fb
->fb_flags
& FB_FORCE
|| (isconsole
&& !seen_force
)) &&
160 fblist
.fb_dev
!= NULL
) {
161 while (fbl
->fb_next
!= NULL
) {
165 if ((fbl
->fb_next
= malloc(sizeof (struct fbdevlist
),
166 M_DEVBUF
, M_NOWAIT
)) == NULL
)
167 printf("%s: replacing %s at /dev/fb0\n",
168 device_xname(fb
->fb_device
),
169 device_xname(fblist
.fb_dev
->fb_device
));
173 fbl
->fb_dev
= fblist
.fb_dev
;
175 printf("%s: moved to /dev/fb%d\n",
176 device_xname(fbl
->fb_dev
->fb_device
), nfb
);
177 printf("%s: attached to /dev/fb0\n",
178 device_xname(fb
->fb_device
));
181 if (fb
->fb_flags
& FB_FORCE
)
183 /* Add to end of fb list. */
185 if (fblist
.fb_dev
!= NULL
) {
186 while (fbl
->fb_next
!= NULL
) {
190 if ((fbl
->fb_next
= malloc(sizeof (struct fbdevlist
),
191 M_DEVBUF
, M_NOWAIT
)) == NULL
) {
192 aprint_error_dev(fb
->fb_device
, "no space to attach after /dev/fb%d\n",
201 printf("%s: attached to /dev/fb%d\n",
202 device_xname(fbl
->fb_dev
->fb_device
), nfb
);
207 fbopen(dev_t dev
, int flags
, int mode
, struct lwp
*l
)
210 struct fbdevlist
*fbl
= &fblist
;
213 while (unit
-- && fbl
!= NULL
)
215 if (fbl
== NULL
|| fbl
->fb_dev
== NULL
)
218 nunit
= device_unit(fbl
->fb_dev
->fb_device
);
219 return (fbl
->fb_dev
->fb_driver
->fbd_open
)(makedev(0, nunit
), flags
,
224 fbclose(dev_t dev
, int flags
, int mode
, struct lwp
*l
)
227 struct fbdevlist
*fbl
= &fblist
;
230 while (unit
-- && fbl
!= NULL
)
232 if (fbl
== NULL
|| fbl
->fb_dev
== NULL
)
235 nunit
= device_unit(fbl
->fb_dev
->fb_device
);
236 return (fbl
->fb_dev
->fb_driver
->fbd_close
)(makedev(0, nunit
), flags
,
241 fbioctl(dev_t dev
, u_long cmd
, void *data
, int flags
, struct lwp
*l
)
244 struct fbdevlist
*fbl
= &fblist
;
247 while (unit
-- && fbl
!= NULL
)
249 if (fbl
== NULL
|| fbl
->fb_dev
== NULL
)
252 nunit
= device_unit(fbl
->fb_dev
->fb_device
);
253 return (fbl
->fb_dev
->fb_driver
->fbd_ioctl
)(makedev(0, nunit
), cmd
,
258 fbpoll(dev_t dev
, int events
, struct lwp
*l
)
261 struct fbdevlist
*fbl
= &fblist
;
264 while (unit
-- && fbl
!= NULL
)
266 if (fbl
== NULL
|| fbl
->fb_dev
== NULL
)
269 nunit
= device_unit(fbl
->fb_dev
->fb_device
);
270 return (fbl
->fb_dev
->fb_driver
->fbd_poll
)(makedev(0, nunit
), events
,
275 fbkqfilter(dev_t dev
, struct knote
*kn
)
278 struct fbdevlist
*fbl
= &fblist
;
281 while (unit
-- && fbl
!= NULL
)
283 if (fbl
== NULL
|| fbl
->fb_dev
== NULL
)
286 nunit
= device_unit(fbl
->fb_dev
->fb_device
);
287 return (fbl
->fb_dev
->fb_driver
->fbd_kqfilter
)(makedev(0, nunit
), kn
);
291 fbmmap(dev_t dev
, off_t off
, int prot
)
294 struct fbdevlist
*fbl
= &fblist
;
297 while (unit
-- && fbl
!= NULL
)
299 if (fbl
== NULL
|| fbl
->fb_dev
== NULL
)
302 nunit
= device_unit(fbl
->fb_dev
->fb_device
);
303 paddr_t (*map
)(dev_t
, off_t
, int) = fbl
->fb_dev
->fb_driver
->fbd_mmap
;
307 return (map(makedev(0, nunit
), off
, prot
));
311 fb_setsize_obp(struct fbdevice
*fb
, int depth
, int def_width
, int def_height
, int node
)
313 fb
->fb_type
.fb_width
= prom_getpropint(node
, "width", def_width
);
314 fb
->fb_type
.fb_height
= prom_getpropint(node
, "height", def_height
);
315 fb
->fb_linebytes
= prom_getpropint(node
, "linebytes",
316 (fb
->fb_type
.fb_width
* depth
) / 8);
320 fb_setsize_eeprom(struct fbdevice
*fb
, int depth
, int def_width
, int def_height
)
323 struct eeprom
*eep
= (struct eeprom
*)eeprom_va
;
326 printf("fb_setsize_eeprom: not sun4\n");
330 /* Set up some defaults. */
331 fb
->fb_type
.fb_width
= def_width
;
332 fb
->fb_type
.fb_height
= def_height
;
334 if (fb
->fb_flags
& FB_PFOUR
) {
336 fb_setsize_pfour(fb
);
338 } else if (eep
!= NULL
) {
339 switch (eep
->eeScreenSize
) {
340 case EE_SCR_1152X900
:
341 fb
->fb_type
.fb_width
= 1152;
342 fb
->fb_type
.fb_height
= 900;
345 case EE_SCR_1024X1024
:
346 fb
->fb_type
.fb_width
= 1024;
347 fb
->fb_type
.fb_height
= 1024;
350 case EE_SCR_1600X1280
:
351 fb
->fb_type
.fb_width
= 1600;
352 fb
->fb_type
.fb_height
= 1280;
355 case EE_SCR_1440X1440
:
356 fb
->fb_type
.fb_width
= 1440;
357 fb
->fb_type
.fb_height
= 1440;
362 * XXX: Do nothing, I guess.
363 * Should we print a warning about
364 * an unknown value? --thorpej
370 fb
->fb_linebytes
= (fb
->fb_type
.fb_width
* depth
) / 8;
377 static void fb_bell(int);
388 fbrcons_init(struct fbdevice
*fb
)
390 struct rconsole
*rc
= &fb
->fb_rcons
;
391 struct rasops_info
*ri
= &fb
->fb_rinfo
;
393 #if !defined(RASTERCONS_FULLSCREEN)
397 /* Set up what rasops needs to know about */
398 memset(ri
, 0, sizeof *ri
);
399 ri
->ri_stride
= fb
->fb_linebytes
;
400 ri
->ri_bits
= (void *)fb
->fb_pixels
;
401 ri
->ri_depth
= fb
->fb_type
.fb_depth
;
402 ri
->ri_width
= fb
->fb_type
.fb_width
;
403 ri
->ri_height
= fb
->fb_type
.fb_height
;
407 #if !defined(RASTERCONS_FULLSCREEN)
410 struct eeprom
*eep
= (struct eeprom
*)eeprom_va
;
416 maxcol
= eep
->eeTtyCols
;
417 maxrow
= eep
->eeTtyRows
;
422 char buf
[6+1]; /* Enough for six digits */
423 maxcol
= (prom_getoption("screen-#columns", buf
, sizeof buf
) == 0)
424 ? strtoul(buf
, NULL
, 10)
427 maxrow
= (prom_getoption("screen-#rows", buf
, sizeof buf
) != 0)
428 ? strtoul(buf
, NULL
, 10)
432 #endif /* !RASTERCONS_FULLSCREEN */
434 * - force monochrome output
435 * - eraserows() hack to clear the *entire* display
436 * - cursor is currently enabled
439 ri
->ri_flg
= RI_FULLCLEAR
| RI_CURSOR
| RI_CENTER
;
441 /* Get operations set and connect to rcons */
442 if (rasops_init(ri
, maxrow
, maxcol
))
443 panic("fbrcons_init: rasops_init failed!");
445 if (ri
->ri_depth
== 8) {
447 for (i
= 0; i
< 16; i
++) {
450 * Cmap entries are repeated four times in the
451 * 32 bit wide `devcmap' entries for optimization
452 * purposes; see rasops(9)
454 #define I_TO_DEVCMAP(i) ((i) | ((i)<<8) | ((i)<<16) | ((i)<<24))
457 * Use existing colormap entries for black and white
459 if ((i
& 7) == WSCOL_BLACK
) {
460 ri
->ri_devcmap
[i
] = I_TO_DEVCMAP(255);
464 if ((i
& 7) == WSCOL_WHITE
) {
465 ri
->ri_devcmap
[i
] = I_TO_DEVCMAP(0);
469 * Other entries refer to ANSI map, which for now
470 * is setup in bt_subr.c
472 ri
->ri_devcmap
[i
] = I_TO_DEVCMAP(i
+ 1);
477 rc
->rc_row
= rc
->rc_col
= 0;
478 #if !defined(RASTERCONS_FULLSCREEN)
479 /* Determine addresses of prom emulator row and column */
480 if (!CPU_ISSUN4
&& !romgetcursoraddr(&row
, &col
)) {
485 ri
->ri_crow
= rc
->rc_row
;
486 ri
->ri_ccol
= rc
->rc_col
;
488 rc
->rc_ops
= &ri
->ri_ops
;
490 rc
->rc_bell
= fb_bell
;
491 rc
->rc_maxcol
= ri
->ri_cols
;
492 rc
->rc_maxrow
= ri
->ri_rows
;
493 rc
->rc_width
= ri
->ri_emuwidth
;
494 rc
->rc_height
= ri
->ri_emuheight
;
495 rc
->rc_deffgcolor
= WSCOL_BLACK
;
496 rc
->rc_defbgcolor
= WSCOL_WHITE
;
499 /* Hook up virtual console */
500 v_putc
= rcons_cnputc
;
506 return ((fblist
.fb_dev
!= NULL
) ?
507 fblist
.fb_dev
->fb_rcons
.rc_maxrow
: 0);
513 return ((fblist
.fb_dev
!= NULL
) ?
514 fblist
.fb_dev
->fb_rcons
.rc_maxcol
: 0);
516 #endif /* RASTERCONSOLE */