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