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