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