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