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