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