1 /* $NetBSD: fb.c,v 1.19 2004/03/19 16:05:25 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. 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. 27 * 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 38 * SUCH DAMAGE. 39 * 40 * @(#)fb.c 8.1 (Berkeley) 6/11/93 41 */ 42 43 /* 44 * /dev/fb (indirect frame buffer driver). This is gross; we should 45 * just build cdevsw[] dynamically. 46 */ 47 48 #include <sys/cdefs.h> 49 __KERNEL_RCSID(0, "$NetBSD: fb.c,v 1.19 2004/03/19 16:05:25 pk Exp $"); 50 51 #include <sys/param.h> 52 #include <sys/systm.h> 53 #include <sys/device.h> 54 #include <sys/proc.h> 55 #include <sys/conf.h> 56 57 #include <machine/promlib.h> 58 #include <machine/autoconf.h> 59 #include <machine/kbd.h> 60 #include <machine/eeprom.h> 61 #include <sparc/dev/cons.h> 62 63 #include <dev/sun/fbio.h> 64 #include <dev/sun/fbvar.h> 65 66 #include "kbd.h" 67 #include "pfour.h" 68 69 static struct fbdevice *devfb; 70 71 dev_type_open(fbopen); 72 dev_type_close(fbclose); 73 dev_type_ioctl(fbioctl); 74 dev_type_poll(fbpoll); 75 dev_type_mmap(fbmmap); 76 dev_type_kqfilter(fbkqfilter); 77 78 const struct cdevsw fb_cdevsw = { 79 fbopen, fbclose, noread, nowrite, fbioctl, 80 nostop, notty, fbpoll, fbmmap, fbkqfilter, 81 }; 82 83 void 84 fb_unblank() 85 { 86 87 if (devfb) 88 (*devfb->fb_driver->fbd_unblank)(devfb->fb_device); 89 } 90 91 /* 92 * Helper function for frame buffer devices. Decides whether 93 * the device can be the console output device according to 94 * PROM info. The result from this function may not be conclusive 95 * on machines with old PROMs; in that case, drivers should consult 96 * other sources of configuration information (e.g. EEPROM entries). 97 */ 98 int 99 fb_is_console(node) 100 int node; 101 { 102 #if !defined(SUN4U) 103 int fbnode; 104 105 switch (prom_version()) { 106 case PROM_OLDMON: 107 /* `node' is not valid; just check for any fb device */ 108 return (prom_stdout() == PROMDEV_SCREEN); 109 110 case PROM_OBP_V0: 111 /* 112 * First, check if prom_stdout() represents a frame buffer, 113 * then match on the `fb' property on the root node, if any. 114 */ 115 if (prom_stdout() != PROMDEV_SCREEN) 116 return (0); 117 118 fbnode = prom_getpropint(findroot(), "fb", 0); 119 return (fbnode == 0 || node == fbnode); 120 121 case PROM_OBP_V2: 122 case PROM_OBP_V3: 123 case PROM_OPENFIRM: 124 /* Just match the nodes */ 125 return (node == prom_stdout_node); 126 } 127 128 return (0); 129 #else 130 return (node == prom_stdout_node); 131 #endif 132 } 133 134 void 135 fb_attach(fb, isconsole) 136 struct fbdevice *fb; 137 int isconsole; 138 { 139 static int no_replace, seen_force; 140 141 /* 142 * We've already had a framebuffer forced into /dev/fb. Don't 143 * allow any more, even if this is the console. 144 */ 145 if (seen_force) { 146 if (devfb) { /* sanity */ 147 printf("%s: /dev/fb already full\n", 148 fb->fb_device->dv_xname); 149 return; 150 } else 151 seen_force = 0; 152 } 153 154 /* 155 * Check to see if we're being forced into /dev/fb. 156 */ 157 if (fb->fb_flags & FB_FORCE) { 158 if (devfb) 159 printf("%s: forcefully replacing %s\n", 160 fb->fb_device->dv_xname, 161 devfb->fb_device->dv_xname); 162 devfb = fb; 163 seen_force = no_replace = 1; 164 goto attached; 165 } 166 167 /* 168 * Check to see if we're the console. If we are, then replace 169 * any currently existing framebuffer. 170 */ 171 if (isconsole) { 172 if (devfb) 173 printf("%s: replacing %s\n", fb->fb_device->dv_xname, 174 devfb->fb_device->dv_xname); 175 devfb = fb; 176 no_replace = 1; 177 goto attached; 178 } 179 180 /* 181 * For the final case, we check to see if we can replace an 182 * existing framebuffer, if not, say so and return. 183 */ 184 if (no_replace) { 185 if (devfb) { /* sanity */ 186 printf("%s: /dev/fb already full\n", 187 fb->fb_device->dv_xname); 188 return; 189 } else 190 no_replace = 0; 191 } 192 193 if (devfb) 194 printf("%s: replacing %s\n", fb->fb_device->dv_xname, 195 devfb->fb_device->dv_xname); 196 devfb = fb; 197 198 attached: 199 printf("%s: attached to /dev/fb\n", devfb->fb_device->dv_xname); 200 } 201 202 int 203 fbopen(dev, flags, mode, p) 204 dev_t dev; 205 int flags, mode; 206 struct proc *p; 207 { 208 209 if (devfb == NULL) 210 return (ENXIO); 211 return (devfb->fb_driver->fbd_open)(dev, flags, mode, p); 212 } 213 214 int 215 fbclose(dev, flags, mode, p) 216 dev_t dev; 217 int flags, mode; 218 struct proc *p; 219 { 220 221 return (devfb->fb_driver->fbd_close)(dev, flags, mode, p); 222 } 223 224 int 225 fbioctl(dev, cmd, data, flags, p) 226 dev_t dev; 227 u_long cmd; 228 caddr_t data; 229 int flags; 230 struct proc *p; 231 { 232 233 return (devfb->fb_driver->fbd_ioctl)(dev, cmd, data, flags, p); 234 } 235 236 int 237 fbpoll(dev, events, p) 238 dev_t dev; 239 int events; 240 struct proc *p; 241 { 242 243 return (devfb->fb_driver->fbd_poll)(dev, events, p); 244 } 245 246 int 247 fbkqfilter(dev, kn) 248 dev_t dev; 249 struct knote *kn; 250 { 251 252 return (devfb->fb_driver->fbd_kqfilter)(dev, kn); 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 static void 344 fb_bell(on) 345 int on; 346 { 347 #if NKBD > 0 348 kbd_bell(on); 349 #endif 350 } 351 352 void 353 fbrcons_init(fb) 354 struct fbdevice *fb; 355 { 356 struct rconsole *rc = &fb->fb_rcons; 357 struct rasops_info *ri = &fb->fb_rinfo; 358 int maxrow, maxcol; 359 #if !defined(RASTERCONS_FULLSCREEN) 360 int *row, *col; 361 #endif 362 363 /* Set up what rasops needs to know about */ 364 bzero(ri, sizeof *ri); 365 ri->ri_stride = fb->fb_linebytes; 366 ri->ri_bits = (caddr_t)fb->fb_pixels; 367 ri->ri_depth = fb->fb_type.fb_depth; 368 ri->ri_width = fb->fb_type.fb_width; 369 ri->ri_height = fb->fb_type.fb_height; 370 maxrow = 5000; 371 maxcol = 5000; 372 373 #if !defined(RASTERCONS_FULLSCREEN) 374 #if !defined(SUN4U) 375 if (CPU_ISSUN4) { 376 struct eeprom *eep = (struct eeprom *)eeprom_va; 377 378 if (eep == NULL) { 379 maxcol = 80; 380 maxrow = 34; 381 } else { 382 maxcol = eep->eeTtyCols; 383 maxrow = eep->eeTtyRows; 384 } 385 } 386 #endif /* !SUN4U */ 387 if (!CPU_ISSUN4) { 388 char buf[6+1]; /* Enough for six digits */ 389 maxcol = (prom_getoption("screen-#columns", buf, sizeof buf) == 0) 390 ? strtoul(buf, NULL, 10) 391 : 80; 392 393 maxrow = (prom_getoption("screen-#rows", buf, sizeof buf) != 0) 394 ? strtoul(buf, NULL, 10) 395 : 34; 396 397 } 398 #endif /* !RASTERCONS_FULLSCREEN */ 399 /* 400 * - force monochrome output 401 * - eraserows() hack to clear the *entire* display 402 * - cursor is currently enabled 403 * - center output 404 */ 405 ri->ri_flg = RI_FULLCLEAR | RI_CURSOR | RI_CENTER; 406 407 /* Get operations set and connect to rcons */ 408 if (rasops_init(ri, maxrow, maxcol)) 409 panic("fbrcons_init: rasops_init failed!"); 410 411 if (ri->ri_depth == 8) { 412 int i; 413 for (i = 0; i < 16; i++) { 414 415 /* 416 * Cmap entries are repeated four times in the 417 * 32 bit wide `devcmap' entries for optimization 418 * purposes; see rasops(9) 419 */ 420 #define I_TO_DEVCMAP(i) ((i) | ((i)<<8) | ((i)<<16) | ((i)<<24)) 421 422 /* 423 * Use existing colormap entries for black and white 424 */ 425 if ((i & 7) == WSCOL_BLACK) { 426 ri->ri_devcmap[i] = I_TO_DEVCMAP(255); 427 continue; 428 } 429 430 if ((i & 7) == WSCOL_WHITE) { 431 ri->ri_devcmap[i] = I_TO_DEVCMAP(0); 432 continue; 433 } 434 /* 435 * Other entries refer to ANSI map, which for now 436 * is setup in bt_subr.c 437 */ 438 ri->ri_devcmap[i] = I_TO_DEVCMAP(i + 1); 439 #undef I_TO_DEVCMAP 440 } 441 } 442 443 rc->rc_row = rc->rc_col = 0; 444 #if !defined(RASTERCONS_FULLSCREEN) 445 /* Determine addresses of prom emulator row and column */ 446 if (!CPU_ISSUN4 && !romgetcursoraddr(&row, &col)) { 447 rc->rc_row = *row; 448 rc->rc_col = *col; 449 } 450 #endif 451 ri->ri_crow = rc->rc_row; 452 ri->ri_ccol = rc->rc_col; 453 454 rc->rc_ops = &ri->ri_ops; 455 rc->rc_cookie = ri; 456 rc->rc_bell = fb_bell; 457 rc->rc_maxcol = ri->ri_cols; 458 rc->rc_maxrow = ri->ri_rows; 459 rc->rc_width = ri->ri_emuwidth; 460 rc->rc_height = ri->ri_emuheight; 461 rc->rc_deffgcolor = WSCOL_BLACK; 462 rc->rc_defbgcolor = WSCOL_WHITE; 463 rcons_init(rc, 0); 464 465 /* Hook up virtual console */ 466 v_putc = rcons_cnputc; 467 } 468 469 int 470 fbrcons_rows() 471 { 472 return (devfb ? devfb->fb_rcons.rc_maxrow : 0); 473 } 474 475 int 476 fbrcons_cols() 477 { 478 return (devfb ? devfb->fb_rcons.rc_maxcol : 0); 479 } 480 #endif /* RASTERCONSOLE */ 481