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