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