1 /* $NetBSD: fb.c,v 1.7 2002/03/22 00:14:37 fredette 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.7 2002/03/22 00:14:37 fredette 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/conf.h> 64 #include <machine/eeprom.h> 65 #include <sparc/dev/cons.h> 66 67 #include <dev/sun/fbio.h> 68 #include <dev/sun/fbvar.h> 69 70 #include "kbd.h" 71 #include "pfour.h" 72 73 static struct fbdevice *devfb; 74 75 void 76 fb_unblank() 77 { 78 79 if (devfb) 80 (*devfb->fb_driver->fbd_unblank)(devfb->fb_device); 81 } 82 83 /* 84 * Helper function for frame buffer devices. Decides whether 85 * the device can be the console output device according to 86 * PROM info. The result from this function may not be conclusive 87 * on machines with old PROMs; in that case, drivers should consult 88 * other sources of configuration information (e.g. EEPROM entries). 89 */ 90 #if defined(SUN4U) 91 /* Temporary special case for sun4u */ 92 int 93 fb_is_console(node) 94 int node; 95 { 96 extern int fbnode; 97 return (node == fbnode); 98 } 99 #else 100 int 101 fb_is_console(node) 102 int node; 103 { 104 int fbnode; 105 106 switch (prom_version()) { 107 case PROM_OLDMON: 108 /* `node' is not valid; just check for any fb device */ 109 return (prom_stdout() == PROMDEV_SCREEN); 110 111 case PROM_OBP_V0: 112 /* 113 * First, check if prom_stdout() represents a frame buffer, 114 * then match on the `fb' property on the root node, if any. 115 */ 116 if (prom_stdout() != PROMDEV_SCREEN) 117 return (0); 118 119 fbnode = PROM_getpropint(findroot(), "fb", 0); 120 return (fbnode == 0 || node == fbnode); 121 122 case PROM_OBP_V2: 123 case PROM_OBP_V3: 124 case PROM_OPENFIRM: 125 /* Just match the nodes */ 126 return (node == prom_stdout_node); 127 } 128 129 return (0); 130 } 131 #endif /* SUN4U */ 132 133 void 134 fb_attach(fb, isconsole) 135 struct fbdevice *fb; 136 int isconsole; 137 { 138 static int no_replace, seen_force; 139 140 /* 141 * We've already had a framebuffer forced into /dev/fb. Don't 142 * allow any more, even if this is the console. 143 */ 144 if (seen_force) { 145 if (devfb) { /* sanity */ 146 printf("%s: /dev/fb already full\n", 147 fb->fb_device->dv_xname); 148 return; 149 } else 150 seen_force = 0; 151 } 152 153 /* 154 * Check to see if we're being forced into /dev/fb. 155 */ 156 if (fb->fb_flags & FB_FORCE) { 157 if (devfb) 158 printf("%s: forcefully replacing %s\n", 159 fb->fb_device->dv_xname, 160 devfb->fb_device->dv_xname); 161 devfb = fb; 162 seen_force = no_replace = 1; 163 goto attached; 164 } 165 166 /* 167 * Check to see if we're the console. If we are, then replace 168 * any currently existing framebuffer. 169 */ 170 if (isconsole) { 171 if (devfb) 172 printf("%s: replacing %s\n", fb->fb_device->dv_xname, 173 devfb->fb_device->dv_xname); 174 devfb = fb; 175 no_replace = 1; 176 goto attached; 177 } 178 179 /* 180 * For the final case, we check to see if we can replace an 181 * existing framebuffer, if not, say so and return. 182 */ 183 if (no_replace) { 184 if (devfb) { /* sanity */ 185 printf("%s: /dev/fb already full\n", 186 fb->fb_device->dv_xname); 187 return; 188 } else 189 no_replace = 0; 190 } 191 192 if (devfb) 193 printf("%s: replacing %s\n", fb->fb_device->dv_xname, 194 devfb->fb_device->dv_xname); 195 devfb = fb; 196 197 attached: 198 printf("%s: attached to /dev/fb\n", devfb->fb_device->dv_xname); 199 } 200 201 int 202 fbopen(dev, flags, mode, p) 203 dev_t dev; 204 int flags, mode; 205 struct proc *p; 206 { 207 208 if (devfb == NULL) 209 return (ENXIO); 210 return (devfb->fb_driver->fbd_open)(dev, flags, mode, p); 211 } 212 213 int 214 fbclose(dev, flags, mode, p) 215 dev_t dev; 216 int flags, mode; 217 struct proc *p; 218 { 219 220 return (devfb->fb_driver->fbd_close)(dev, flags, mode, p); 221 } 222 223 int 224 fbioctl(dev, cmd, data, flags, p) 225 dev_t dev; 226 u_long cmd; 227 caddr_t data; 228 int flags; 229 struct proc *p; 230 { 231 232 return (devfb->fb_driver->fbd_ioctl)(dev, cmd, data, flags, p); 233 } 234 235 int 236 fbpoll(dev, events, p) 237 dev_t dev; 238 int events; 239 struct proc *p; 240 { 241 242 return (devfb->fb_driver->fbd_poll)(dev, events, p); 243 } 244 245 paddr_t 246 fbmmap(dev, off, prot) 247 dev_t dev; 248 off_t off; 249 int prot; 250 { 251 paddr_t (*map)__P((dev_t, off_t, int)) = devfb->fb_driver->fbd_mmap; 252 253 if (map == NULL) 254 return (-1); 255 return (map(dev, off, prot)); 256 } 257 258 void 259 fb_setsize_obp(fb, depth, def_width, def_height, node) 260 struct fbdevice *fb; 261 int depth, def_width, def_height, node; 262 { 263 fb->fb_type.fb_width = PROM_getpropint(node, "width", def_width); 264 fb->fb_type.fb_height = PROM_getpropint(node, "height", def_height); 265 fb->fb_linebytes = PROM_getpropint(node, "linebytes", 266 (fb->fb_type.fb_width * depth) / 8); 267 } 268 269 void 270 fb_setsize_eeprom(fb, depth, def_width, def_height) 271 struct fbdevice *fb; 272 int depth, def_width, def_height; 273 { 274 #if !defined(SUN4U) 275 struct eeprom *eep = (struct eeprom *)eeprom_va; 276 277 if (!CPU_ISSUN4) { 278 printf("fb_setsize_eeprom: not sun4\n"); 279 return; 280 } 281 282 /* Set up some defaults. */ 283 fb->fb_type.fb_width = def_width; 284 fb->fb_type.fb_height = def_height; 285 286 if (fb->fb_flags & FB_PFOUR) { 287 #if NPFOUR > 0 288 fb_setsize_pfour(fb); 289 #endif 290 } else if (eep != NULL) { 291 switch (eep->eeScreenSize) { 292 case EE_SCR_1152X900: 293 fb->fb_type.fb_width = 1152; 294 fb->fb_type.fb_height = 900; 295 break; 296 297 case EE_SCR_1024X1024: 298 fb->fb_type.fb_width = 1024; 299 fb->fb_type.fb_height = 1024; 300 break; 301 302 case EE_SCR_1600X1280: 303 fb->fb_type.fb_width = 1600; 304 fb->fb_type.fb_height = 1280; 305 break; 306 307 case EE_SCR_1440X1440: 308 fb->fb_type.fb_width = 1440; 309 fb->fb_type.fb_height = 1440; 310 break; 311 312 default: 313 /* 314 * XXX: Do nothing, I guess. 315 * Should we print a warning about 316 * an unknown value? --thorpej 317 */ 318 break; 319 } 320 } 321 322 fb->fb_linebytes = (fb->fb_type.fb_width * depth) / 8; 323 #endif /* !SUN4U */ 324 } 325 326 327 328 #ifdef RASTERCONSOLE 329 #include <machine/kbd.h> 330 331 static void fb_bell __P((int)); 332 333 #if !defined(RASTERCONS_FULLSCREEN) 334 static int a2int __P((char *, int)); 335 336 static int 337 a2int(cp, deflt) 338 register char *cp; 339 register int deflt; 340 { 341 register int i = 0; 342 343 if (*cp == '\0') 344 return (deflt); 345 while (*cp != '\0') 346 i = i * 10 + *cp++ - '0'; 347 return (i); 348 } 349 #endif 350 351 static void 352 fb_bell(on) 353 int on; 354 { 355 #if NKBD > 0 356 (void)kbd_docmd(on?KBD_CMD_BELL:KBD_CMD_NOBELL, 0); 357 #endif 358 } 359 360 void 361 fbrcons_init(fb) 362 struct fbdevice *fb; 363 { 364 struct rconsole *rc = &fb->fb_rcons; 365 struct rasops_info *ri = &fb->fb_rinfo; 366 int maxrow, maxcol; 367 #if !defined(RASTERCONS_FULLSCREEN) 368 int *row, *col; 369 #endif 370 371 /* Set up what rasops needs to know about */ 372 bzero(ri, sizeof *ri); 373 ri->ri_stride = fb->fb_linebytes; 374 ri->ri_bits = (caddr_t)fb->fb_pixels; 375 ri->ri_depth = fb->fb_type.fb_depth; 376 ri->ri_width = fb->fb_type.fb_width; 377 ri->ri_height = fb->fb_type.fb_height; 378 maxrow = 5000; 379 maxcol = 5000; 380 381 #if !defined(RASTERCONS_FULLSCREEN) 382 #if !defined(SUN4U) 383 if (CPU_ISSUN4) { 384 struct eeprom *eep = (struct eeprom *)eeprom_va; 385 386 if (eep == NULL) { 387 maxcol = 80; 388 maxrow = 34; 389 } else { 390 maxcol = eep->eeTtyCols; 391 maxrow = eep->eeTtyRows; 392 } 393 } 394 #endif /* !SUN4U */ 395 if (!CPU_ISSUN4) { 396 maxcol = 397 a2int(PROM_getpropstring(optionsnode, "screen-#columns"), 80); 398 maxrow = 399 a2int(PROM_getpropstring(optionsnode, "screen-#rows"), 34); 400 } 401 #endif /* !RASTERCONS_FULLSCREEN */ 402 /* 403 * - force monochrome output 404 * - eraserows() hack to clear the *entire* display 405 * - cursor is currently enabled 406 * - center output 407 */ 408 ri->ri_flg = RI_FULLCLEAR | RI_CURSOR | RI_CENTER; 409 410 /* Get operations set and connect to rcons */ 411 if (rasops_init(ri, maxrow, maxcol)) 412 panic("fbrcons_init: rasops_init failed!"); 413 414 if (ri->ri_depth == 8) { 415 int i; 416 for (i = 0; i < 16; i++) { 417 418 /* 419 * Cmap entries are repeated four times in the 420 * 32 bit wide `devcmap' entries for optimization 421 * purposes; see rasops(9) 422 */ 423 #define I_TO_DEVCMAP(i) ((i) | ((i)<<8) | ((i)<<16) | ((i)<<24)) 424 425 /* 426 * Use existing colormap entries for black and white 427 */ 428 if ((i & 7) == WSCOL_BLACK) { 429 ri->ri_devcmap[i] = I_TO_DEVCMAP(255); 430 continue; 431 } 432 433 if ((i & 7) == WSCOL_WHITE) { 434 ri->ri_devcmap[i] = I_TO_DEVCMAP(0); 435 continue; 436 } 437 /* 438 * Other entries refer to ANSI map, which for now 439 * is setup in bt_subr.c 440 */ 441 ri->ri_devcmap[i] = I_TO_DEVCMAP(i + 1); 442 #undef I_TO_DEVCMAP 443 } 444 } 445 446 rc->rc_row = rc->rc_col = 0; 447 #if !defined(RASTERCONS_FULLSCREEN) 448 /* Determine addresses of prom emulator row and column */ 449 if (!CPU_ISSUN4 && !romgetcursoraddr(&row, &col)) { 450 rc->rc_row = *row; 451 rc->rc_col = *col; 452 } 453 #endif 454 ri->ri_crow = rc->rc_row; 455 ri->ri_ccol = rc->rc_col; 456 457 rc->rc_ops = &ri->ri_ops; 458 rc->rc_cookie = ri; 459 rc->rc_bell = fb_bell; 460 rc->rc_maxcol = ri->ri_cols; 461 rc->rc_maxrow = ri->ri_rows; 462 rc->rc_width = ri->ri_emuwidth; 463 rc->rc_height = ri->ri_emuheight; 464 rc->rc_deffgcolor = WSCOL_BLACK; 465 rc->rc_defbgcolor = WSCOL_WHITE; 466 rcons_init(rc, 0); 467 468 /* Hook up virtual console */ 469 v_putc = rcons_cnputc; 470 } 471 472 int 473 fbrcons_rows() 474 { 475 return (devfb ? devfb->fb_rcons.rc_maxrow : 0); 476 } 477 478 int 479 fbrcons_cols() 480 { 481 return (devfb ? devfb->fb_rcons.rc_maxcol : 0); 482 } 483 #endif /* RASTERCONSOLE */ 484