1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* Copyright (c) 1990, 1991 UNIX System Laboratories, Inc. */ 28 /* Copyright (c) 1984, 1986, 1987, 1988, 1989, 1990 AT&T */ 29 /* All Rights Reserved */ 30 31 #include <sys/errno.h> 32 #include <sys/types.h> 33 #include <sys/conf.h> 34 #include <sys/kmem.h> 35 #include <sys/visual_io.h> 36 #include <sys/font.h> 37 #include <sys/fbio.h> 38 #include <sys/ddi.h> 39 #include <sys/stat.h> 40 #include <sys/sunddi.h> 41 #include <sys/open.h> 42 #include <sys/modctl.h> 43 #include <sys/pci.h> 44 #include <sys/kd.h> 45 #include <sys/ddi_impldefs.h> 46 #include <sys/gfx_private.h> 47 #include "gfxp_fb.h" 48 49 #define MYNAME "gfxp_vgatext" 50 51 typedef enum pc_colors { 52 pc_black = 0, 53 pc_blue = 1, 54 pc_green = 2, 55 pc_cyan = 3, 56 pc_red = 4, 57 pc_magenta = 5, 58 pc_brown = 6, 59 pc_white = 7, 60 pc_grey = 8, 61 pc_brt_blue = 9, 62 pc_brt_green = 10, 63 pc_brt_cyan = 11, 64 pc_brt_red = 12, 65 pc_brt_magenta = 13, 66 pc_yellow = 14, 67 pc_brt_white = 15 68 } pc_colors_t; 69 70 static const unsigned char solaris_color_to_pc_color[16] = { 71 pc_brt_white, /* 0 - brt_white */ 72 pc_black, /* 1 - black */ 73 pc_blue, /* 2 - blue */ 74 pc_green, /* 3 - green */ 75 pc_cyan, /* 4 - cyan */ 76 pc_red, /* 5 - red */ 77 pc_magenta, /* 6 - magenta */ 78 pc_brown, /* 7 - brown */ 79 pc_white, /* 8 - white */ 80 pc_grey, /* 9 - gery */ 81 pc_brt_blue, /* 10 - brt_blue */ 82 pc_brt_green, /* 11 - brt_green */ 83 pc_brt_cyan, /* 12 - brt_cyan */ 84 pc_brt_red, /* 13 - brt_red */ 85 pc_brt_magenta, /* 14 - brt_magenta */ 86 pc_yellow /* 15 - yellow */ 87 }; 88 89 static ddi_device_acc_attr_t dev_attr = { 90 DDI_DEVICE_ATTR_V0, 91 DDI_NEVERSWAP_ACC, 92 DDI_STRICTORDER_ACC, 93 }; 94 95 /* default structure for FBIOGATTR ioctl */ 96 static struct fbgattr vgatext_attr = { 97 /* real_type owner */ 98 FBTYPE_SUNFAST_COLOR, 0, 99 /* fbtype: type h w depth cms size */ 100 { FBTYPE_SUNFAST_COLOR, VGA_TEXT_ROWS, VGA_TEXT_COLS, 1, 256, 0 }, 101 /* fbsattr: flags emu_type dev_specific */ 102 { 0, FBTYPE_SUN4COLOR, { 0 } }, 103 /* emu_types */ 104 { -1 } 105 }; 106 107 static struct vis_identifier gfxp_vgatext_ident = { "illumos_text" }; 108 109 static int vgatext_devinit(struct gfxp_fb_softc *, struct vis_devinit *data); 110 static void vgatext_cons_copy(struct gfxp_fb_softc *, 111 struct vis_conscopy *); 112 static void vgatext_cons_display(struct gfxp_fb_softc *, 113 struct vis_consdisplay *); 114 static int vgatext_cons_clear(struct gfxp_fb_softc *, 115 struct vis_consclear *); 116 static void vgatext_cons_cursor(struct gfxp_fb_softc *, 117 struct vis_conscursor *); 118 static void vgatext_polled_copy(struct vis_polledio_arg *, 119 struct vis_conscopy *); 120 static void vgatext_polled_display(struct vis_polledio_arg *, 121 struct vis_consdisplay *); 122 static void vgatext_polled_cursor(struct vis_polledio_arg *, 123 struct vis_conscursor *); 124 static void vgatext_init(struct gfxp_fb_softc *); 125 static void vgatext_set_text(struct gfxp_fb_softc *); 126 127 static void vgatext_get_text(struct gfxp_fb_softc *softc); 128 static void vgatext_save_text(struct gfxp_fb_softc *softc); 129 static void vgatext_kdsettext(struct gfxp_fb_softc *softc); 130 static int vgatext_suspend(struct gfxp_fb_softc *softc); 131 static void vgatext_resume(struct gfxp_fb_softc *softc); 132 static int vgatext_devmap(dev_t, devmap_cookie_t, offset_t, size_t, 133 size_t *, uint_t, void *); 134 135 #if defined(USE_BORDERS) 136 static void vgatext_init_graphics(struct gfxp_fb_softc *); 137 #endif 138 139 static int vgatext_kdsetmode(struct gfxp_fb_softc *softc, int mode); 140 static void vgatext_setfont(struct gfxp_fb_softc *softc); 141 static void vgatext_get_cursor(struct gfxp_fb_softc *softc, 142 screen_pos_t *row, screen_pos_t *col); 143 static void vgatext_set_cursor(struct gfxp_fb_softc *softc, int row, int col); 144 static void vgatext_hide_cursor(struct gfxp_fb_softc *softc); 145 static void vgatext_save_colormap(struct gfxp_fb_softc *softc); 146 static void vgatext_restore_colormap(struct gfxp_fb_softc *softc); 147 static int vgatext_get_pci_reg_index(dev_info_t *const devi, 148 unsigned long himask, unsigned long hival, unsigned long addr, 149 off_t *offset); 150 static int vgatext_get_isa_reg_index(dev_info_t *const devi, 151 unsigned long hival, unsigned long addr, off_t *offset); 152 153 static struct gfxp_ops gfxp_vgatext_ops = { 154 .ident = &gfxp_vgatext_ident, 155 .kdsetmode = vgatext_kdsetmode, 156 .devinit = vgatext_devinit, 157 .cons_copy = vgatext_cons_copy, 158 .cons_display = vgatext_cons_display, 159 .cons_cursor = vgatext_cons_cursor, 160 .cons_clear = vgatext_cons_clear, 161 .suspend = vgatext_suspend, 162 .resume = vgatext_resume, 163 .devmap = vgatext_devmap 164 }; 165 166 #define STREQ(a, b) (strcmp((a), (b)) == 0) 167 168 int 169 gfxp_vga_attach(dev_info_t *devi, struct gfxp_fb_softc *softc) 170 { 171 int unit = ddi_get_instance(devi); 172 int error; 173 char *parent_type = NULL; 174 int reg_rnumber; 175 off_t reg_offset; 176 off_t mem_offset; 177 char *cons; 178 struct gfx_vga *vga; 179 180 181 softc->polledio.display = vgatext_polled_display; 182 softc->polledio.copy = vgatext_polled_copy; 183 softc->polledio.cursor = vgatext_polled_cursor; 184 softc->gfxp_ops = &gfxp_vgatext_ops; 185 softc->fbgattr = &vgatext_attr; 186 vga = kmem_zalloc(sizeof (*vga), KM_SLEEP); 187 softc->console = (union gfx_console *)vga; 188 189 error = ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_get_parent(devi), 190 DDI_PROP_DONTPASS, "device_type", &parent_type); 191 if (error != DDI_SUCCESS) { 192 cmn_err(CE_WARN, MYNAME ": can't determine parent type."); 193 goto fail; 194 } 195 196 /* Not enable AGP and DRM by default */ 197 if (STREQ(parent_type, "isa") || STREQ(parent_type, "eisa")) { 198 reg_rnumber = vgatext_get_isa_reg_index(devi, 1, VGA_REG_ADDR, 199 ®_offset); 200 if (reg_rnumber < 0) { 201 cmn_err(CE_WARN, 202 MYNAME 203 ": can't find reg entry for registers"); 204 error = DDI_FAILURE; 205 goto fail; 206 } 207 vga->fb_regno = vgatext_get_isa_reg_index(devi, 0, 208 VGA_MEM_ADDR, &mem_offset); 209 if (vga->fb_regno < 0) { 210 cmn_err(CE_WARN, 211 MYNAME ": can't find reg entry for memory"); 212 error = DDI_FAILURE; 213 goto fail; 214 } 215 } else if (STREQ(parent_type, "pci") || STREQ(parent_type, "pciex")) { 216 reg_rnumber = vgatext_get_pci_reg_index(devi, 217 PCI_REG_ADDR_M|PCI_REG_REL_M, 218 PCI_ADDR_IO|PCI_RELOCAT_B, VGA_REG_ADDR, 219 ®_offset); 220 if (reg_rnumber < 0) { 221 cmn_err(CE_WARN, 222 MYNAME ": can't find reg entry for registers"); 223 error = DDI_FAILURE; 224 goto fail; 225 } 226 vga->fb_regno = vgatext_get_pci_reg_index(devi, 227 PCI_REG_ADDR_M|PCI_REG_REL_M, 228 PCI_ADDR_MEM32|PCI_RELOCAT_B, VGA_MEM_ADDR, 229 &mem_offset); 230 if (vga->fb_regno < 0) { 231 cmn_err(CE_WARN, 232 MYNAME ": can't find reg entry for memory"); 233 error = DDI_FAILURE; 234 goto fail; 235 } 236 } else { 237 cmn_err(CE_WARN, MYNAME ": unknown parent type \"%s\".", 238 parent_type); 239 error = DDI_FAILURE; 240 goto fail; 241 } 242 ddi_prop_free(parent_type); 243 parent_type = NULL; 244 245 error = ddi_regs_map_setup(devi, reg_rnumber, 246 (caddr_t *)&vga->regs.addr, reg_offset, VGA_REG_SIZE, 247 &dev_attr, &vga->regs.handle); 248 if (error != DDI_SUCCESS) 249 goto fail; 250 vga->regs.mapped = B_TRUE; 251 252 vga->fb_size = VGA_MEM_SIZE; 253 254 error = ddi_regs_map_setup(devi, vga->fb_regno, 255 (caddr_t *)&vga->fb.addr, mem_offset, vga->fb_size, &dev_attr, 256 &vga->fb.handle); 257 if (error != DDI_SUCCESS) 258 goto fail; 259 vga->fb.mapped = B_TRUE; 260 261 if (ddi_get8(vga->regs.handle, 262 vga->regs.addr + VGA_MISC_R) & VGA_MISC_IOA_SEL) 263 vga->text_base = (caddr_t)vga->fb.addr + VGA_COLOR_BASE; 264 else 265 vga->text_base = (caddr_t)vga->fb.addr + VGA_MONO_BASE; 266 267 if (ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_root_node(), 268 DDI_PROP_DONTPASS, "console", &cons) == DDI_SUCCESS) { 269 if (strcmp(cons, "graphics") == 0) { 270 softc->happyface_boot = 1; 271 softc->silent = 1; 272 vga->current_base = vga->shadow; 273 } else { 274 vga->current_base = vga->text_base; 275 } 276 ddi_prop_free(cons); 277 } else { 278 vga->current_base = vga->text_base; 279 } 280 281 /* Set cursor info. */ 282 vga->cursor.visible = fb_info.cursor.visible; 283 vga->cursor.row = fb_info.cursor.pos.y; 284 vga->cursor.col = fb_info.cursor.pos.x; 285 286 error = ddi_prop_create(makedevice(DDI_MAJOR_T_UNKNOWN, unit), 287 devi, DDI_PROP_CANSLEEP, DDI_KERNEL_IOCTL, NULL, 0); 288 if (error != DDI_SUCCESS) 289 goto fail; 290 291 /* only do this if not in graphics mode */ 292 if ((softc->silent == 0) && (GFXP_IS_CONSOLE(softc))) { 293 vgatext_init(softc); 294 vgatext_save_colormap(softc); 295 } 296 297 return (DDI_SUCCESS); 298 299 fail: 300 kmem_free(vga, sizeof (*vga)); 301 if (parent_type != NULL) 302 ddi_prop_free(parent_type); 303 return (error); 304 } 305 306 int 307 gfxp_vga_detach(dev_info_t *devi __unused, struct gfxp_fb_softc *softc) 308 { 309 if (softc->console->vga.fb.mapped) 310 ddi_regs_map_free(&softc->console->vga.fb.handle); 311 if (softc->console->vga.regs.mapped) 312 ddi_regs_map_free(&softc->console->vga.regs.handle); 313 kmem_free(softc->console, sizeof (struct gfx_vga)); 314 return (DDI_SUCCESS); 315 } 316 317 /* 318 * vgatext_save_text 319 * vgatext_suspend 320 * vgatext_resume 321 * 322 * Routines to save and restore contents of the VGA text area 323 * Mostly, this is to support Suspend/Resume operation for graphics 324 * device drivers. Here in the VGAtext common code, we simply squirrel 325 * away the contents of the hardware's text area during Suspend and then 326 * put it back during Resume 327 */ 328 static void 329 vgatext_save_text(struct gfxp_fb_softc *softc) 330 { 331 union gfx_console *console = softc->console; 332 unsigned i; 333 334 for (i = 0; i < sizeof (console->vga.shadow); i++) 335 console->vga.shadow[i] = console->vga.current_base[i]; 336 } 337 338 static int 339 vgatext_suspend(struct gfxp_fb_softc *softc) 340 { 341 switch (softc->mode) { 342 case KD_TEXT: 343 vgatext_save_text(softc); 344 break; 345 346 case KD_GRAPHICS: 347 break; 348 349 default: 350 cmn_err(CE_WARN, MYNAME ": unknown mode in vgatext_suspend."); 351 return (DDI_FAILURE); 352 } 353 return (DDI_SUCCESS); 354 } 355 356 static void 357 vgatext_resume(struct gfxp_fb_softc *softc) 358 { 359 360 switch (softc->mode) { 361 case KD_TEXT: 362 vgatext_kdsettext(softc); 363 break; 364 365 case KD_GRAPHICS: 366 367 /* 368 * Upon RESUME, the graphics device will always actually 369 * be in TEXT mode even though the Xorg server did not 370 * make that mode change itself (the suspend code did). 371 * We want first, therefore, to restore textmode 372 * operation fully, and then the Xorg server will 373 * do the rest to restore the device to its 374 * (hi resolution) graphics mode 375 */ 376 vgatext_kdsettext(softc); 377 #if defined(USE_BORDERS) 378 vgatext_init_graphics(softc); 379 #endif 380 break; 381 default: 382 cmn_err(CE_WARN, MYNAME ": unknown mode in vgatext_resume."); 383 break; 384 } 385 } 386 387 static void 388 vgatext_progressbar_stop(struct gfxp_fb_softc *softc) 389 { 390 extern void progressbar_stop(void); 391 392 if (softc->silent == 1) { 393 softc->silent = 0; 394 progressbar_stop(); 395 } 396 } 397 398 static void 399 vgatext_kdsettext(struct gfxp_fb_softc *softc) 400 { 401 union gfx_console *console = softc->console; 402 int i; 403 404 vgatext_init(softc); 405 for (i = 0; i < sizeof (console->vga.shadow); i++) { 406 console->vga.text_base[i] = console->vga.shadow[i]; 407 } 408 console->vga.current_base = console->vga.text_base; 409 if (console->vga.cursor.visible) { 410 vgatext_set_cursor(softc, 411 console->vga.cursor.row, 412 console->vga.cursor.col); 413 } 414 vgatext_restore_colormap(softc); 415 } 416 417 static void 418 vgatext_kdsetgraphics(struct gfxp_fb_softc *softc) 419 { 420 vgatext_progressbar_stop(softc); 421 vgatext_save_text(softc); 422 softc->console->vga.current_base = softc->console->vga.shadow; 423 vgatext_get_text(softc); 424 #if defined(USE_BORDERS) 425 vgatext_init_graphics(softc); 426 #endif 427 } 428 429 static int 430 vgatext_kdsetmode(struct gfxp_fb_softc *softc, int mode) 431 { 432 switch (mode) { 433 case KD_TEXT: 434 if (softc->blt_ops.setmode != NULL) 435 softc->blt_ops.setmode(KD_TEXT); 436 vgatext_kdsettext(softc); 437 break; 438 439 case KD_GRAPHICS: 440 vgatext_kdsetgraphics(softc); 441 if (softc->blt_ops.setmode != NULL) 442 softc->blt_ops.setmode(KD_GRAPHICS); 443 break; 444 445 case KD_RESETTEXT: 446 /* 447 * In order to avoid racing with a starting X server, 448 * this needs to be a test and set that is performed in 449 * a single (softc->lock protected) ioctl into this driver. 450 */ 451 if (softc->mode == KD_TEXT && softc->silent == 1) { 452 vgatext_progressbar_stop(softc); 453 vgatext_kdsettext(softc); 454 } 455 mode = KD_TEXT; 456 break; 457 458 default: 459 return (EINVAL); 460 } 461 462 softc->mode = mode; 463 return (0); 464 } 465 466 /*ARGSUSED*/ 467 static int 468 vgatext_devmap(dev_t dev, devmap_cookie_t dhp, offset_t off, size_t len, 469 size_t *maplen, uint_t model, void *ptr) 470 { 471 struct gfxp_fb_softc *softc = (struct gfxp_fb_softc *)ptr; 472 union gfx_console *console; 473 int err; 474 size_t length; 475 476 477 if (softc == NULL) { 478 cmn_err(CE_WARN, "vgatext: Can't find softstate"); 479 return (-1); 480 } 481 console = softc->console; 482 483 if (!(off >= VGA_MEM_ADDR && 484 off < VGA_MEM_ADDR + console->vga.fb_size)) { 485 cmn_err(CE_WARN, "vgatext: Can't map offset 0x%llx", off); 486 return (-1); 487 } 488 489 if (off + len > VGA_MEM_ADDR + console->vga.fb_size) 490 length = VGA_MEM_ADDR + console->vga.fb_size - off; 491 else 492 length = len; 493 494 if ((err = devmap_devmem_setup(dhp, softc->devi, 495 NULL, console->vga.fb_regno, off - VGA_MEM_ADDR, 496 length, PROT_ALL, 0, &dev_attr)) < 0) { 497 return (err); 498 } 499 500 501 *maplen = length; 502 return (0); 503 } 504 505 506 static int 507 vgatext_devinit(struct gfxp_fb_softc *softc, struct vis_devinit *data) 508 { 509 /* initialize console instance */ 510 data->version = VIS_CONS_REV; 511 data->width = VGA_TEXT_COLS; 512 data->height = VGA_TEXT_ROWS; 513 data->linebytes = VGA_TEXT_COLS; 514 data->color_map = NULL; 515 data->depth = 4; 516 data->mode = VIS_TEXT; 517 data->polledio = &softc->polledio; 518 519 vgatext_save_text(softc); /* save current console */ 520 vgatext_hide_cursor(softc); 521 return (0); 522 } 523 524 /* 525 * display a string on the screen at (row, col) 526 * assume it has been cropped to fit. 527 */ 528 529 static void 530 vgatext_cons_display(struct gfxp_fb_softc *softc, struct vis_consdisplay *da) 531 { 532 unsigned char *string; 533 int i; 534 unsigned char attr; 535 struct cgatext { 536 unsigned char ch; 537 unsigned char attr; 538 }; 539 struct cgatext *addr; 540 541 /* 542 * Sanity checks. This is a last-ditch effort to avoid damage 543 * from brokenness or maliciousness above. 544 */ 545 if (da->row < 0 || da->row >= VGA_TEXT_ROWS || 546 da->col < 0 || da->col >= VGA_TEXT_COLS || 547 da->col + da->width > VGA_TEXT_COLS) 548 return; 549 550 /* 551 * To be fully general, we should copyin the data. This is not 552 * really relevant for this text-only driver, but a graphical driver 553 * should support these ioctls from userland to enable simple 554 * system startup graphics. 555 */ 556 attr = (solaris_color_to_pc_color[da->bg_color & 0xf] << 4) 557 | solaris_color_to_pc_color[da->fg_color & 0xf]; 558 string = da->data; 559 addr = (struct cgatext *)softc->console->vga.current_base 560 + (da->row * VGA_TEXT_COLS + da->col); 561 for (i = 0; i < da->width; i++) { 562 addr->ch = string[i]; 563 addr->attr = attr; 564 addr++; 565 } 566 } 567 568 static void 569 vgatext_polled_display( 570 struct vis_polledio_arg *arg, 571 struct vis_consdisplay *da) 572 { 573 vgatext_cons_display((struct gfxp_fb_softc *)arg, da); 574 } 575 576 /* 577 * screen-to-screen copy 578 */ 579 580 static void 581 vgatext_cons_copy(struct gfxp_fb_softc *softc, struct vis_conscopy *ma) 582 { 583 unsigned short *from; 584 unsigned short *to; 585 int cnt; 586 screen_size_t chars_per_row; 587 unsigned short *to_row_start; 588 unsigned short *from_row_start; 589 screen_size_t rows_to_move; 590 unsigned short *base; 591 592 /* 593 * Sanity checks. Note that this is a last-ditch effort to avoid 594 * damage caused by broken-ness or maliciousness above. 595 */ 596 if (ma->s_col < 0 || ma->s_col >= VGA_TEXT_COLS || 597 ma->s_row < 0 || ma->s_row >= VGA_TEXT_ROWS || 598 ma->e_col < 0 || ma->e_col >= VGA_TEXT_COLS || 599 ma->e_row < 0 || ma->e_row >= VGA_TEXT_ROWS || 600 ma->t_col < 0 || ma->t_col >= VGA_TEXT_COLS || 601 ma->t_row < 0 || ma->t_row >= VGA_TEXT_ROWS || 602 ma->s_col > ma->e_col || 603 ma->s_row > ma->e_row) 604 return; 605 606 /* 607 * Remember we're going to copy shorts because each 608 * character/attribute pair is 16 bits. 609 */ 610 chars_per_row = ma->e_col - ma->s_col + 1; 611 rows_to_move = ma->e_row - ma->s_row + 1; 612 613 /* More sanity checks. */ 614 if (ma->t_row + rows_to_move > VGA_TEXT_ROWS || 615 ma->t_col + chars_per_row > VGA_TEXT_COLS) 616 return; 617 618 base = (unsigned short *)softc->console->vga.current_base; 619 620 to_row_start = base + ((ma->t_row * VGA_TEXT_COLS) + ma->t_col); 621 from_row_start = base + ((ma->s_row * VGA_TEXT_COLS) + ma->s_col); 622 623 if (to_row_start < from_row_start) { 624 while (rows_to_move-- > 0) { 625 to = to_row_start; 626 from = from_row_start; 627 to_row_start += VGA_TEXT_COLS; 628 from_row_start += VGA_TEXT_COLS; 629 for (cnt = chars_per_row; cnt-- > 0; ) 630 *to++ = *from++; 631 } 632 } else { 633 /* 634 * Offset to the end of the region and copy backwards. 635 */ 636 cnt = rows_to_move * VGA_TEXT_COLS + chars_per_row; 637 to_row_start += cnt; 638 from_row_start += cnt; 639 640 while (rows_to_move-- > 0) { 641 to_row_start -= VGA_TEXT_COLS; 642 from_row_start -= VGA_TEXT_COLS; 643 to = to_row_start; 644 from = from_row_start; 645 for (cnt = chars_per_row; cnt-- > 0; ) 646 *--to = *--from; 647 } 648 } 649 } 650 651 static void 652 vgatext_polled_copy( 653 struct vis_polledio_arg *arg, 654 struct vis_conscopy *ca) 655 { 656 vgatext_cons_copy((struct gfxp_fb_softc *)arg, ca); 657 } 658 659 /*ARGSUSED*/ 660 static int 661 vgatext_cons_clear(struct gfxp_fb_softc *softc, struct vis_consclear *ca) 662 { 663 uint16_t val, fg, *base; 664 int i; 665 666 if (ca->bg_color == 0) /* bright white */ 667 fg = 1; /* black */ 668 else 669 fg = 8; 670 671 val = (solaris_color_to_pc_color[ca->bg_color & 0xf] << 4) | 672 solaris_color_to_pc_color[fg]; 673 val = (val << 8) | ' '; 674 675 base = (uint16_t *)softc->console->vga.current_base; 676 for (i = 0; i < VGA_TEXT_ROWS * VGA_TEXT_COLS; i++) 677 base[i] = val; 678 679 return (0); 680 } 681 682 static void 683 vgatext_cons_cursor(struct gfxp_fb_softc *softc, struct vis_conscursor *ca) 684 { 685 if (softc->silent) 686 return; 687 688 switch (ca->action) { 689 case VIS_HIDE_CURSOR: 690 softc->console->vga.cursor.visible = B_FALSE; 691 if (softc->console->vga.current_base == 692 softc->console->vga.text_base) 693 vgatext_hide_cursor(softc); 694 break; 695 case VIS_DISPLAY_CURSOR: 696 /* 697 * Sanity check. This is a last-ditch effort to avoid 698 * damage from brokenness or maliciousness above. 699 */ 700 if (ca->col < 0 || ca->col >= VGA_TEXT_COLS || 701 ca->row < 0 || ca->row >= VGA_TEXT_ROWS) 702 return; 703 704 softc->console->vga.cursor.visible = B_TRUE; 705 softc->console->vga.cursor.col = ca->col; 706 softc->console->vga.cursor.row = ca->row; 707 if (softc->console->vga.current_base == 708 softc->console->vga.text_base) 709 vgatext_set_cursor(softc, ca->row, ca->col); 710 break; 711 case VIS_GET_CURSOR: 712 if (softc->console->vga.current_base == 713 softc->console->vga.text_base) { 714 vgatext_get_cursor(softc, &ca->row, &ca->col); 715 } 716 break; 717 } 718 } 719 720 static void 721 vgatext_polled_cursor( 722 struct vis_polledio_arg *arg, 723 struct vis_conscursor *ca) 724 { 725 vgatext_cons_cursor((struct gfxp_fb_softc *)arg, ca); 726 } 727 728 static void 729 vgatext_hide_cursor(struct gfxp_fb_softc *softc) 730 { 731 union gfx_console *console = softc->console; 732 uint8_t msl, s; 733 734 if (softc->silent) 735 return; 736 737 msl = vga_get_crtc(&console->vga.regs, VGA_CRTC_MAX_S_LN) & 0x1f; 738 s = vga_get_crtc(&console->vga.regs, VGA_CRTC_CSSL) & 0xc0; 739 s |= (1 << 5); 740 741 /* disable cursor */ 742 vga_set_crtc(&console->vga.regs, VGA_CRTC_CSSL, s); 743 vga_set_crtc(&console->vga.regs, VGA_CRTC_CESL, msl); 744 } 745 746 static void 747 vgatext_set_cursor(struct gfxp_fb_softc *softc, int row, int col) 748 { 749 union gfx_console *console = softc->console; 750 short addr; 751 uint8_t msl, s; 752 753 if (softc->silent) 754 return; 755 756 msl = vga_get_crtc(&console->vga.regs, VGA_CRTC_MAX_S_LN) & 0x1f; 757 s = vga_get_crtc(&console->vga.regs, VGA_CRTC_CSSL) & 0xc0; 758 759 addr = row * VGA_TEXT_COLS + col; 760 761 vga_set_crtc(&console->vga.regs, VGA_CRTC_CLAH, addr >> 8); 762 vga_set_crtc(&console->vga.regs, VGA_CRTC_CLAL, addr & 0xff); 763 764 /* enable cursor */ 765 vga_set_crtc(&console->vga.regs, VGA_CRTC_CSSL, s); 766 vga_set_crtc(&console->vga.regs, VGA_CRTC_CESL, msl); 767 } 768 769 static void 770 vgatext_get_cursor(struct gfxp_fb_softc *softc, 771 screen_pos_t *row, screen_pos_t *col) 772 { 773 union gfx_console *console = softc->console; 774 short addr; 775 776 addr = (vga_get_crtc(&console->vga.regs, VGA_CRTC_CLAH) << 8) + 777 vga_get_crtc(&console->vga.regs, VGA_CRTC_CLAL); 778 779 *row = addr / VGA_TEXT_COLS; 780 *col = addr % VGA_TEXT_COLS; 781 } 782 783 static void 784 vgatext_get_text(struct gfxp_fb_softc *softc) 785 { 786 union gfx_console *console = softc->console; 787 struct vgareg *vga_reg; 788 struct vgaregmap *regs; 789 int i; 790 791 regs = &console->vga.regs; 792 vga_reg = &console->vga.vga_reg; 793 794 vga_reg->vga_misc = vga_get_reg(regs, VGA_MISC_R); 795 796 /* get crt controller registers */ 797 for (i = 0; i < NUM_CRTC_REG; i++) { 798 vga_reg->vga_crtc[i] = vga_get_crtc(regs, i); 799 } 800 801 /* get attribute registers */ 802 for (i = 0; i < NUM_ATR_REG; i++) { 803 vga_reg->vga_atr[i] = vga_get_atr(regs, i); 804 } 805 806 /* get graphics controller registers */ 807 for (i = 0; i < NUM_GRC_REG; i++) { 808 vga_reg->vga_grc[i] = vga_get_grc(regs, i); 809 } 810 811 /* get sequencer registers */ 812 for (i = 1; i < NUM_SEQ_REG; i++) { 813 vga_reg->vga_seq[i] = vga_get_seq(regs, i); 814 } 815 } 816 817 /* 818 * This code is experimental. It's only enabled if console is 819 * set to graphics, a preliminary implementation of happyface boot. 820 */ 821 static void 822 vgatext_set_text(struct gfxp_fb_softc *softc) 823 { 824 union gfx_console *console = softc->console; 825 struct vgareg *vga_reg; 826 struct vgaregmap *regs; 827 int i; 828 829 regs = &console->vga.regs; 830 vga_reg = &console->vga.vga_reg; 831 832 vgatext_get_text(softc); 833 834 /* 835 * Set output register bits for text mode. 836 * Make sure the VGA adapter is not in monochrome emulation mode. 837 */ 838 vga_set_reg(regs, VGA_MISC_W, VGA_MISC_HSP | VGA_MISC_PGSL | 839 VGA_MISC_VCLK1 | VGA_MISC_ENB_RAM | VGA_MISC_IOA_SEL); 840 841 /* set sequencer registers */ 842 vga_set_seq(regs, VGA_SEQ_RST_SYN, 843 (vga_get_seq(regs, VGA_SEQ_RST_SYN) & 844 ~VGA_SEQ_RST_SYN_NO_SYNC_RESET)); 845 for (i = 1; i < NUM_SEQ_REG; i++) { 846 vga_set_seq(regs, i, VGA_SEQ_TEXT[i]); 847 } 848 vga_set_seq(regs, VGA_SEQ_RST_SYN, 849 (vga_get_seq(regs, VGA_SEQ_RST_SYN) | 850 VGA_SEQ_RST_SYN_NO_ASYNC_RESET | 851 VGA_SEQ_RST_SYN_NO_SYNC_RESET)); 852 853 /* set crt controller registers */ 854 vga_set_crtc(regs, VGA_CRTC_VRE, 855 (vga_reg->vga_crtc[VGA_CRTC_VRE] & ~VGA_CRTC_VRE_LOCK)); 856 for (i = 0; i < NUM_CRTC_REG; i++) { 857 vga_set_crtc(regs, i, VGA_CRTC_TEXT[i]); 858 } 859 860 /* set graphics controller registers */ 861 for (i = 0; i < NUM_GRC_REG; i++) { 862 vga_set_grc(regs, i, VGA_GRC_TEXT[i]); 863 } 864 865 /* set attribute registers */ 866 for (i = 0; i < NUM_ATR_REG; i++) { 867 vga_set_atr(regs, i, VGA_ATR_TEXT[i]); 868 } 869 870 /* set palette */ 871 for (i = 0; i < VGA_TEXT_CMAP_ENTRIES; i++) { 872 vga_put_cmap(regs, i, 873 VGA_TEXT_PALETTES[i][0] << 2, 874 VGA_TEXT_PALETTES[i][1] << 2, 875 VGA_TEXT_PALETTES[i][2] << 2); 876 } 877 for (i = VGA_TEXT_CMAP_ENTRIES; i < VGA8_CMAP_ENTRIES; i++) { 878 vga_put_cmap(regs, i, 0, 0, 0); 879 } 880 } 881 882 static void 883 vgatext_init(struct gfxp_fb_softc *softc) 884 { 885 union gfx_console *console = softc->console; 886 unsigned char atr_mode; 887 888 atr_mode = vga_get_atr(&console->vga.regs, VGA_ATR_MODE); 889 if (atr_mode & VGA_ATR_MODE_GRAPH) 890 vgatext_set_text(softc); 891 atr_mode = vga_get_atr(&console->vga.regs, VGA_ATR_MODE); 892 atr_mode &= ~VGA_ATR_MODE_BLINK; 893 atr_mode &= ~VGA_ATR_MODE_9WIDE; 894 vga_set_atr(&console->vga.regs, VGA_ATR_MODE, atr_mode); 895 #if defined(USE_BORDERS) 896 vga_set_atr(&console->vga.regs, VGA_ATR_BDR_CLR, 897 vga_get_atr(&console->vga.regs, pc_brt_white)); 898 #else 899 vga_set_atr(&console->vga.regs, VGA_ATR_BDR_CLR, 900 vga_get_atr(&console->vga.regs, pc_black)); 901 #endif 902 vgatext_setfont(softc); /* need selectable font? */ 903 } 904 905 #if defined(USE_BORDERS) 906 static void 907 vgatext_init_graphics(struct gfxp_fb_softc *softc) 908 { 909 vga_set_atr(&softc->console->vga.regs, VGA_ATR_BDR_CLR, 910 vga_get_atr(&softc->console->vga.regs, VGA_BLACK)); 911 } 912 #endif 913 914 static void 915 vgatext_setfont(struct gfxp_fb_softc *softc) 916 { 917 union gfx_console *console = softc->console; 918 static uchar_t fsreg[8] = {0x0, 0x30, 0x5, 0x35, 0xa, 0x3a, 0xf, 0x3f}; 919 920 uchar_t *from; 921 uchar_t volatile *to; 922 int i, j, s; 923 int bpc, f_offset; 924 925 /* Sync-reset the sequencer registers */ 926 vga_set_seq(&console->vga.regs, 0x00, 0x01); 927 /* 928 * enable write to plane2, since fonts 929 * could only be loaded into plane2 930 */ 931 vga_set_seq(&console->vga.regs, 0x02, 0x04); 932 /* 933 * sequentially access data in the bit map being 934 * selected by MapMask register (index 0x02) 935 */ 936 vga_set_seq(&console->vga.regs, 0x04, 0x07); 937 /* Sync-reset ended, and allow the sequencer to operate */ 938 vga_set_seq(&console->vga.regs, 0x00, 0x03); 939 940 /* 941 * select plane 2 on Read Mode 0 942 */ 943 vga_set_grc(&console->vga.regs, 0x04, 0x02); 944 /* 945 * system addresses sequentially access data, follow 946 * Memory Mode register bit 2 in the sequencer 947 */ 948 vga_set_grc(&console->vga.regs, 0x05, 0x00); 949 /* 950 * set range of host memory addresses decoded by VGA 951 * hardware -- A0000h-BFFFFh (128K region) 952 */ 953 vga_set_grc(&console->vga.regs, 0x06, 0x00); 954 955 /* 956 * This assumes 8x16 characters, which yield the traditional 80x25 957 * screen. It really should support other character heights. 958 */ 959 bpc = 16; 960 s = console->vga.vga_fontslot; 961 f_offset = s * 8 * 1024; 962 for (i = 0; i < 256; i++) { 963 from = font_data_8x16.encoding[i]; 964 to = (unsigned char *)console->vga.fb.addr + f_offset + 965 i * 0x20; 966 for (j = 0; j < bpc; j++) 967 *to++ = *from++; 968 } 969 970 /* Sync-reset the sequencer registers */ 971 vga_set_seq(&console->vga.regs, 0x00, 0x01); 972 /* enable write to plane 0 and 1 */ 973 vga_set_seq(&console->vga.regs, 0x02, 0x03); 974 /* 975 * enable character map selection 976 * and odd/even addressing 977 */ 978 vga_set_seq(&console->vga.regs, 0x04, 0x03); 979 /* 980 * select font map 981 */ 982 vga_set_seq(&console->vga.regs, 0x03, fsreg[s]); 983 /* Sync-reset ended, and allow the sequencer to operate */ 984 vga_set_seq(&console->vga.regs, 0x00, 0x03); 985 986 /* restore graphic registers */ 987 988 /* select plane 0 */ 989 vga_set_grc(&console->vga.regs, 0x04, 0x00); 990 /* enable odd/even addressing mode */ 991 vga_set_grc(&console->vga.regs, 0x05, 0x10); 992 /* 993 * range of host memory addresses decoded by VGA 994 * hardware -- B8000h-BFFFFh (32K region) 995 */ 996 vga_set_grc(&console->vga.regs, 0x06, 0x0e); 997 /* enable all color plane */ 998 vga_set_atr(&console->vga.regs, 0x12, 0x0f); 999 1000 } 1001 1002 static void 1003 vgatext_save_colormap(struct gfxp_fb_softc *softc) 1004 { 1005 union gfx_console *console = softc->console; 1006 int i; 1007 1008 for (i = 0; i < VGA_ATR_NUM_PLT; i++) { 1009 console->vga.attrib_palette[i] = 1010 vga_get_atr(&console->vga.regs, i); 1011 } 1012 for (i = 0; i < VGA8_CMAP_ENTRIES; i++) { 1013 vga_get_cmap(&console->vga.regs, i, 1014 &console->vga.colormap[i].red, 1015 &console->vga.colormap[i].green, 1016 &console->vga.colormap[i].blue); 1017 } 1018 } 1019 1020 static void 1021 vgatext_restore_colormap(struct gfxp_fb_softc *softc) 1022 { 1023 union gfx_console *console = softc->console; 1024 int i; 1025 1026 for (i = 0; i < VGA_ATR_NUM_PLT; i++) { 1027 vga_set_atr(&console->vga.regs, i, 1028 console->vga.attrib_palette[i]); 1029 } 1030 for (i = 0; i < VGA8_CMAP_ENTRIES; i++) { 1031 vga_put_cmap(&console->vga.regs, i, 1032 console->vga.colormap[i].red, 1033 console->vga.colormap[i].green, 1034 console->vga.colormap[i].blue); 1035 } 1036 } 1037 1038 /* 1039 * search the entries of the "reg" property for one which has the desired 1040 * combination of phys_hi bits and contains the desired address. 1041 * 1042 * This version searches a PCI-style "reg" property. It was prompted by 1043 * issues surrounding the presence or absence of an entry for the ROM: 1044 * (a) a transition problem with PowerPC Virtual Open Firmware 1045 * (b) uncertainty as to whether an entry will be included on a device 1046 * with ROM support (and so an "active" ROM base address register), 1047 * but no ROM actually installed. 1048 * 1049 * See the note below on vgatext_get_isa_reg_index for the reasons for 1050 * returning the offset. 1051 * 1052 * Note that this routine may not be fully general; it is intended for the 1053 * specific purpose of finding a couple of particular VGA reg entries and 1054 * may not be suitable for all reg-searching purposes. 1055 */ 1056 static int 1057 vgatext_get_pci_reg_index( 1058 dev_info_t *const devi, 1059 unsigned long himask, 1060 unsigned long hival, 1061 unsigned long addr, 1062 off_t *offset) 1063 { 1064 1065 int length, index; 1066 pci_regspec_t *reg; 1067 1068 if (ddi_getlongprop(DDI_DEV_T_ANY, devi, DDI_PROP_DONTPASS, 1069 "reg", (caddr_t)®, &length) != DDI_PROP_SUCCESS) { 1070 return (-1); 1071 } 1072 1073 for (index = 0; index < length / sizeof (pci_regspec_t); index++) { 1074 if ((reg[index].pci_phys_hi & himask) != hival) 1075 continue; 1076 if (reg[index].pci_size_hi != 0) 1077 continue; 1078 if (reg[index].pci_phys_mid != 0) 1079 continue; 1080 if (reg[index].pci_phys_low > addr) 1081 continue; 1082 if (reg[index].pci_phys_low + reg[index].pci_size_low <= addr) 1083 continue; 1084 1085 *offset = addr - reg[index].pci_phys_low; 1086 kmem_free(reg, (size_t)length); 1087 return (index); 1088 } 1089 kmem_free(reg, (size_t)length); 1090 1091 return (-1); 1092 } 1093 1094 /* 1095 * search the entries of the "reg" property for one which has the desired 1096 * combination of phys_hi bits and contains the desired address. 1097 * 1098 * This version searches a ISA-style "reg" property. It was prompted by 1099 * issues surrounding 8514/A support. By IEEE 1275 compatibility conventions, 1100 * 8514/A registers should have been added after all standard VGA registers. 1101 * Unfortunately, the Solaris/Intel device configuration framework 1102 * (a) lists the 8514/A registers before the video memory, and then 1103 * (b) also sorts the entries so that I/O entries come before memory 1104 * entries. 1105 * 1106 * It returns the "reg" index and offset into that register set. 1107 * The offset is needed because there exist (broken?) BIOSes that 1108 * report larger ranges enclosing the standard ranges. One reports 1109 * 0x3bf for 0x21 instead of 0x3c0 for 0x20, for instance. Using the 1110 * offset adjusts for this difference in the base of the register set. 1111 * 1112 * Note that this routine may not be fully general; it is intended for the 1113 * specific purpose of finding a couple of particular VGA reg entries and 1114 * may not be suitable for all reg-searching purposes. 1115 */ 1116 static int 1117 vgatext_get_isa_reg_index( 1118 dev_info_t *const devi, 1119 unsigned long hival, 1120 unsigned long addr, 1121 off_t *offset) 1122 { 1123 1124 int length, index; 1125 struct regspec *reg; 1126 1127 if (ddi_getlongprop(DDI_DEV_T_ANY, devi, DDI_PROP_DONTPASS, 1128 "reg", (caddr_t)®, &length) != DDI_PROP_SUCCESS) { 1129 return (-1); 1130 } 1131 1132 for (index = 0; index < length / sizeof (struct regspec); index++) { 1133 if (reg[index].regspec_bustype != hival) 1134 continue; 1135 if (reg[index].regspec_addr > addr) 1136 continue; 1137 if (reg[index].regspec_addr + reg[index].regspec_size <= addr) 1138 continue; 1139 1140 *offset = addr - reg[index].regspec_addr; 1141 kmem_free(reg, (size_t)length); 1142 return (index); 1143 } 1144 kmem_free(reg, (size_t)length); 1145 1146 return (-1); 1147 } 1148 1149 /* 1150 * This vgatext function is used to return the fb, and reg pointers 1151 * and handles for peer graphics drivers. 1152 */ 1153 1154 void 1155 vgatext_return_pointers(struct gfxp_fb_softc *softc, struct vgaregmap *fbs, 1156 struct vgaregmap *regss) 1157 { 1158 1159 fbs->addr = softc->console->vga.fb.addr; 1160 fbs->handle = softc->console->vga.fb.handle; 1161 fbs->mapped = softc->console->vga.fb.mapped; 1162 regss->addr = softc->console->vga.regs.addr; 1163 regss->handle = softc->console->vga.regs.handle; 1164 regss->mapped = softc->console->vga.regs.mapped; 1165 } 1166