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