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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 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 2005 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_io_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 #pragma weak progressbar_stop 495 void 496 progressbar_stop(void) 497 {} 498 499 static int 500 vgatext_kdsetmode(struct vgatext_softc *softc, int mode) 501 { 502 int i; 503 504 if (mode == softc->mode) 505 return (0); 506 507 switch (mode) { 508 case KD_TEXT: 509 vgatext_init(softc); 510 for (i = 0; i < sizeof (softc->shadow); i++) { 511 softc->text_base[i] = softc->shadow[i]; 512 } 513 softc->current_base = softc->text_base; 514 if (softc->cursor.visible) { 515 vgatext_set_cursor(softc, 516 softc->cursor.row, softc->cursor.col); 517 } 518 vgatext_restore_colormap(softc); 519 break; 520 521 case KD_GRAPHICS: 522 if (vgatext_silent == 1) { 523 extern void progressbar_stop(void); 524 525 vgatext_silent = 0; 526 progressbar_stop(); 527 } 528 for (i = 0; i < sizeof (softc->shadow); i++) { 529 softc->shadow[i] = softc->text_base[i]; 530 } 531 softc->current_base = softc->shadow; 532 #if defined(USE_BORDERS) 533 vgatext_init_graphics(softc); 534 #endif 535 break; 536 537 default: 538 return (EINVAL); 539 } 540 softc->mode = mode; 541 return (0); 542 } 543 544 /*ARGSUSED*/ 545 static int 546 gfxp_vgatext_devmap(dev_t dev, devmap_cookie_t dhp, offset_t off, size_t len, 547 size_t *maplen, uint_t model, void *ptr) 548 { 549 struct vgatext_softc *softc = (struct vgatext_softc *)ptr; 550 int err; 551 size_t length; 552 553 554 if (softc == NULL) { 555 cmn_err(CE_WARN, "vgatext: Can't find softstate"); 556 return (-1); 557 } 558 559 if (!(off >= VGA_MMAP_FB_BASE && 560 off < VGA_MMAP_FB_BASE + softc->fb_size)) { 561 cmn_err(CE_WARN, "vgatext: Can't map offset 0x%llx", off); 562 return (-1); 563 } 564 565 if (off + len > VGA_MMAP_FB_BASE + softc->fb_size) 566 length = VGA_MMAP_FB_BASE + softc->fb_size - off; 567 else 568 length = len; 569 570 if ((err = devmap_devmem_setup(dhp, softc->devi, NULL, softc->fb_regno, 571 off - VGA_MMAP_FB_BASE, 572 length, PROT_ALL, 0, &dev_attr)) < 0) { 573 return (err); 574 } 575 576 577 *maplen = length; 578 return (0); 579 } 580 581 582 static int 583 vgatext_devinit(struct vgatext_softc *softc, struct vis_devinit *data) 584 { 585 /* initialize console instance */ 586 data->version = VIS_CONS_REV; 587 data->width = TEXT_COLS; 588 data->height = TEXT_ROWS; 589 data->linebytes = TEXT_COLS; 590 data->depth = 4; 591 data->mode = VIS_TEXT; 592 data->polledio = &softc->polledio; 593 594 return (0); 595 } 596 597 /* 598 * display a string on the screen at (row, col) 599 * assume it has been cropped to fit. 600 */ 601 602 static void 603 vgatext_cons_display(struct vgatext_softc *softc, struct vis_consdisplay *da) 604 { 605 unsigned char *string; 606 int i; 607 unsigned char attr; 608 struct cgatext { 609 unsigned char ch; 610 unsigned char attr; 611 }; 612 struct cgatext *addr; 613 614 if (vgatext_silent) 615 return; 616 /* 617 * Sanity checks. This is a last-ditch effort to avoid damage 618 * from brokenness or maliciousness above. 619 */ 620 if (da->row < 0 || da->row >= TEXT_ROWS || 621 da->col < 0 || da->col >= TEXT_COLS || 622 da->col + da->width > TEXT_COLS) 623 return; 624 625 /* 626 * To be fully general, we should copyin the data. This is not 627 * really relevant for this text-only driver, but a graphical driver 628 * should support these ioctls from userland to enable simple 629 * system startup graphics. 630 */ 631 attr = (solaris_color_to_pc_color[da->bg_color & 0xf] << 4) 632 | solaris_color_to_pc_color[da->fg_color & 0xf]; 633 string = da->data; 634 addr = (struct cgatext *)softc->current_base 635 + (da->row * TEXT_COLS + da->col); 636 for (i = 0; i < da->width; i++) { 637 addr->ch = string[i]; 638 addr->attr = attr; 639 addr++; 640 } 641 } 642 643 static void 644 vgatext_polled_display( 645 struct vis_polledio_arg *arg, 646 struct vis_consdisplay *da) 647 { 648 vgatext_cons_display((struct vgatext_softc *)arg, da); 649 } 650 651 /* 652 * screen-to-screen copy 653 */ 654 655 static void 656 vgatext_cons_copy(struct vgatext_softc *softc, struct vis_conscopy *ma) 657 { 658 unsigned short *from; 659 unsigned short *to; 660 int cnt; 661 screen_size_t chars_per_row; 662 unsigned short *to_row_start; 663 unsigned short *from_row_start; 664 screen_size_t rows_to_move; 665 unsigned short *base; 666 667 if (vgatext_silent) 668 return; 669 670 /* 671 * Sanity checks. Note that this is a last-ditch effort to avoid 672 * damage caused by broken-ness or maliciousness above. 673 */ 674 if (ma->s_col < 0 || ma->s_col >= TEXT_COLS || 675 ma->s_row < 0 || ma->s_row >= TEXT_ROWS || 676 ma->e_col < 0 || ma->e_col >= TEXT_COLS || 677 ma->e_row < 0 || ma->e_row >= TEXT_ROWS || 678 ma->t_col < 0 || ma->t_col >= TEXT_COLS || 679 ma->t_row < 0 || ma->t_row >= TEXT_ROWS || 680 ma->s_col > ma->e_col || 681 ma->s_row > ma->e_row) 682 return; 683 684 /* 685 * Remember we're going to copy shorts because each 686 * character/attribute pair is 16 bits. 687 */ 688 chars_per_row = ma->e_col - ma->s_col + 1; 689 rows_to_move = ma->e_row - ma->s_row + 1; 690 691 /* More sanity checks. */ 692 if (ma->t_row + rows_to_move > TEXT_ROWS || 693 ma->t_col + chars_per_row > TEXT_COLS) 694 return; 695 696 base = (unsigned short *)softc->current_base; 697 698 to_row_start = base + ((ma->t_row * TEXT_COLS) + ma->t_col); 699 from_row_start = base + ((ma->s_row * TEXT_COLS) + ma->s_col); 700 701 if (to_row_start < from_row_start) { 702 while (rows_to_move-- > 0) { 703 to = to_row_start; 704 from = from_row_start; 705 to_row_start += TEXT_COLS; 706 from_row_start += TEXT_COLS; 707 for (cnt = chars_per_row; cnt-- > 0; ) 708 *to++ = *from++; 709 } 710 } else { 711 /* 712 * Offset to the end of the region and copy backwards. 713 */ 714 cnt = rows_to_move * TEXT_COLS + chars_per_row; 715 to_row_start += cnt; 716 from_row_start += cnt; 717 718 while (rows_to_move-- > 0) { 719 to_row_start -= TEXT_COLS; 720 from_row_start -= TEXT_COLS; 721 to = to_row_start; 722 from = from_row_start; 723 for (cnt = chars_per_row; cnt-- > 0; ) 724 *--to = *--from; 725 } 726 } 727 } 728 729 static void 730 vgatext_polled_copy( 731 struct vis_polledio_arg *arg, 732 struct vis_conscopy *ca) 733 { 734 vgatext_cons_copy((struct vgatext_softc *)arg, ca); 735 } 736 737 738 static void 739 vgatext_cons_cursor(struct vgatext_softc *softc, struct vis_conscursor *ca) 740 { 741 if (vgatext_silent) 742 return; 743 744 switch (ca->action) { 745 case VIS_HIDE_CURSOR: 746 softc->cursor.visible = B_FALSE; 747 if (softc->current_base == softc->text_base) 748 vgatext_hide_cursor(softc); 749 break; 750 case VIS_DISPLAY_CURSOR: 751 /* 752 * Sanity check. This is a last-ditch effort to avoid 753 * damage from brokenness or maliciousness above. 754 */ 755 if (ca->col < 0 || ca->col >= TEXT_COLS || 756 ca->row < 0 || ca->row >= TEXT_ROWS) 757 return; 758 759 softc->cursor.visible = B_TRUE; 760 softc->cursor.col = ca->col; 761 softc->cursor.row = ca->row; 762 if (softc->current_base == softc->text_base) 763 vgatext_set_cursor(softc, ca->row, ca->col); 764 break; 765 case VIS_GET_CURSOR: 766 if (softc->current_base == softc->text_base) { 767 vgatext_get_cursor(softc, &ca->row, &ca->col); 768 } 769 break; 770 } 771 } 772 773 static void 774 vgatext_polled_cursor( 775 struct vis_polledio_arg *arg, 776 struct vis_conscursor *ca) 777 { 778 vgatext_cons_cursor((struct vgatext_softc *)arg, ca); 779 } 780 781 782 783 /*ARGSUSED*/ 784 static void 785 vgatext_hide_cursor(struct vgatext_softc *softc) 786 { 787 /* Nothing at present */ 788 } 789 790 static void 791 vgatext_set_cursor(struct vgatext_softc *softc, int row, int col) 792 { 793 short addr; 794 795 if (vgatext_silent) 796 return; 797 798 addr = row * TEXT_COLS + col; 799 800 vga_set_crtc(&softc->regs, VGA_CRTC_CLAH, addr >> 8); 801 vga_set_crtc(&softc->regs, VGA_CRTC_CLAL, addr & 0xff); 802 } 803 804 static int vga_row, vga_col; 805 806 static void 807 vgatext_get_cursor(struct vgatext_softc *softc, 808 screen_pos_t *row, screen_pos_t *col) 809 { 810 short addr; 811 812 addr = (vga_get_crtc(&softc->regs, VGA_CRTC_CLAH) << 8) + 813 vga_get_crtc(&softc->regs, VGA_CRTC_CLAL); 814 815 vga_row = *row = addr / TEXT_COLS; 816 vga_col = *col = addr % TEXT_COLS; 817 } 818 819 /* 820 * This code is experimental. It's only enabled if console is 821 * set to graphics, a preliminary implementation of happyface boot. 822 */ 823 static void 824 vgatext_set_text(struct vgatext_softc *softc) 825 { 826 int i; 827 828 if (happyface_boot == 0) 829 return; 830 831 /* we are in graphics mode, set to text 80X25 mode */ 832 833 /* set misc registers */ 834 vga_set_reg(&softc->regs, VGA_MISC_W, VGA_MISC_TEXT); 835 836 /* set sequencer registers */ 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_SYNC_RESET)); 840 for (i = 1; i < NUM_SEQ_REG; i++) { 841 vga_set_seq(&softc->regs, i, VGA_SEQ_TEXT[i]); 842 } 843 vga_set_seq(&softc->regs, VGA_SEQ_RST_SYN, 844 (vga_get_seq(&softc->regs, VGA_SEQ_RST_SYN) | 845 VGA_SEQ_RST_SYN_NO_ASYNC_RESET | 846 VGA_SEQ_RST_SYN_NO_SYNC_RESET)); 847 848 /* set crt controller registers */ 849 vga_set_crtc(&softc->regs, VGA_CRTC_VRE, 850 (vga_get_crtc(&softc->regs, VGA_CRTC_VRE) & 851 ~VGA_CRTC_VRE_LOCK)); 852 for (i = 0; i < NUM_CRTC_REG; i++) { 853 vga_set_crtc(&softc->regs, i, VGA_CRTC_TEXT[i]); 854 } 855 856 /* set graphics controller registers */ 857 for (i = 0; i < NUM_GRC_REG; i++) { 858 vga_set_grc(&softc->regs, i, VGA_GRC_TEXT[i]); 859 } 860 861 /* set attribute registers */ 862 for (i = 0; i < NUM_ATR_REG; i++) { 863 vga_set_atr(&softc->regs, i, VGA_ATR_TEXT[i]); 864 } 865 866 /* set palette */ 867 for (i = 0; i < VGA_TEXT_CMAP_ENTRIES; i++) { 868 vga_put_cmap(&softc->regs, i, VGA_TEXT_PALETTES[i][0] << 2, 869 VGA_TEXT_PALETTES[i][1] << 2, 870 VGA_TEXT_PALETTES[i][2] << 2); 871 } 872 for (i = VGA_TEXT_CMAP_ENTRIES; i < VGA8_CMAP_ENTRIES; i++) { 873 vga_put_cmap(&softc->regs, i, 0, 0, 0); 874 } 875 876 vgatext_save_colormap(softc); 877 } 878 879 static void 880 vgatext_init(struct vgatext_softc *softc) 881 { 882 unsigned char atr_mode; 883 884 atr_mode = vga_get_atr(&softc->regs, VGA_ATR_MODE); 885 if (atr_mode & VGA_ATR_MODE_GRAPH) 886 vgatext_set_text(softc); 887 atr_mode = vga_get_atr(&softc->regs, VGA_ATR_MODE); 888 atr_mode &= ~VGA_ATR_MODE_BLINK; 889 atr_mode &= ~VGA_ATR_MODE_9WIDE; 890 vga_set_atr(&softc->regs, VGA_ATR_MODE, atr_mode); 891 #if defined(USE_BORDERS) 892 vga_set_atr(&softc->regs, VGA_ATR_BDR_CLR, 893 vga_get_atr(&softc->regs, VGA_BRIGHT_WHITE)); 894 #else 895 vga_set_atr(&softc->regs, VGA_ATR_BDR_CLR, 896 vga_get_atr(&softc->regs, VGA_BLACK)); 897 #endif 898 vgatext_setfont(softc); /* need selectable font? */ 899 } 900 901 #if defined(USE_BORDERS) 902 static void 903 vgatext_init_graphics(struct vgatext_softc *softc) 904 { 905 vga_set_atr(&softc->regs, VGA_ATR_BDR_CLR, 906 vga_get_atr(&softc->regs, VGA_BLACK)); 907 } 908 #endif 909 910 static void 911 vgatext_setfont(struct vgatext_softc *softc) 912 { 913 extern unsigned char *ENCODINGS[]; 914 unsigned char *from; 915 unsigned char *to; 916 int i; 917 int j; 918 int bpc; 919 920 /* 921 * The newboot code to use font plane 2 breaks NVIDIA 922 * (and some ATI) behavior. Revert back to the S10 923 * code. 924 */ 925 926 /* 927 * I'm embarassed to say that I don't know what these magic 928 * sequences do, other than at the high level of "set the 929 * memory window to allow font setup". I stole them straight 930 * from "kd"... 931 */ 932 vga_set_seq(&softc->regs, 0x02, 0x04); 933 vga_set_seq(&softc->regs, 0x04, 0x06); 934 vga_set_grc(&softc->regs, 0x05, 0x00); 935 vga_set_grc(&softc->regs, 0x06, 0x04); 936 937 /* 938 * This assumes 8x16 characters, which yield the traditional 80x25 939 * screen. It really should support other character heights. 940 */ 941 bpc = 16; 942 for (i = 0; i < 256; i++) { 943 from = ENCODINGS[i]; 944 to = (unsigned char *)softc->fb.addr + i * 0x20; 945 for (j = 0; j < bpc; j++) 946 *to++ = *from++; 947 } 948 949 vga_set_seq(&softc->regs, 0x02, 0x03); 950 vga_set_seq(&softc->regs, 0x04, 0x02); 951 vga_set_grc(&softc->regs, 0x04, 0x00); 952 vga_set_grc(&softc->regs, 0x05, 0x10); 953 vga_set_grc(&softc->regs, 0x06, 0x0e); 954 955 } 956 957 static void 958 vgatext_save_colormap(struct vgatext_softc *softc) 959 { 960 int i; 961 962 for (i = 0; i < VGA_ATR_NUM_PLT; i++) { 963 softc->attrib_palette[i] = vga_get_atr(&softc->regs, i); 964 } 965 for (i = 0; i < VGA8_CMAP_ENTRIES; i++) { 966 vga_get_cmap(&softc->regs, i, 967 &softc->colormap[i].red, 968 &softc->colormap[i].green, 969 &softc->colormap[i].blue); 970 } 971 } 972 973 static void 974 vgatext_restore_colormap(struct vgatext_softc *softc) 975 { 976 int i; 977 978 for (i = 0; i < VGA_ATR_NUM_PLT; i++) { 979 vga_set_atr(&softc->regs, i, softc->attrib_palette[i]); 980 } 981 for (i = 0; i < VGA8_CMAP_ENTRIES; i++) { 982 vga_put_cmap(&softc->regs, i, 983 softc->colormap[i].red, 984 softc->colormap[i].green, 985 softc->colormap[i].blue); 986 } 987 } 988 989 /* 990 * search the entries of the "reg" property for one which has the desired 991 * combination of phys_hi bits and contains the desired address. 992 * 993 * This version searches a PCI-style "reg" property. It was prompted by 994 * issues surrounding the presence or absence of an entry for the ROM: 995 * (a) a transition problem with PowerPC Virtual Open Firmware 996 * (b) uncertainty as to whether an entry will be included on a device 997 * with ROM support (and so an "active" ROM base address register), 998 * but no ROM actually installed. 999 * 1000 * See the note below on vgatext_get_isa_reg_index for the reasons for 1001 * returning the offset. 1002 * 1003 * Note that this routine may not be fully general; it is intended for the 1004 * specific purpose of finding a couple of particular VGA reg entries and 1005 * may not be suitable for all reg-searching purposes. 1006 */ 1007 static int 1008 vgatext_get_pci_reg_index( 1009 dev_info_t *const devi, 1010 unsigned long himask, 1011 unsigned long hival, 1012 unsigned long addr, 1013 off_t *offset) 1014 { 1015 1016 int length, index; 1017 pci_regspec_t *reg; 1018 1019 if (ddi_getlongprop(DDI_DEV_T_ANY, devi, DDI_PROP_DONTPASS, 1020 "reg", (caddr_t)®, &length) != DDI_PROP_SUCCESS) { 1021 return (-1); 1022 } 1023 1024 for (index = 0; index < length / sizeof (pci_regspec_t); index++) { 1025 if ((reg[index].pci_phys_hi & himask) != hival) 1026 continue; 1027 if (reg[index].pci_size_hi != 0) 1028 continue; 1029 if (reg[index].pci_phys_mid != 0) 1030 continue; 1031 if (reg[index].pci_phys_low > addr) 1032 continue; 1033 if (reg[index].pci_phys_low + reg[index].pci_size_low <= addr) 1034 continue; 1035 1036 *offset = addr - reg[index].pci_phys_low; 1037 kmem_free(reg, (size_t)length); 1038 return (index); 1039 } 1040 kmem_free(reg, (size_t)length); 1041 1042 return (-1); 1043 } 1044 1045 /* 1046 * search the entries of the "reg" property for one which has the desired 1047 * combination of phys_hi bits and contains the desired address. 1048 * 1049 * This version searches a ISA-style "reg" property. It was prompted by 1050 * issues surrounding 8514/A support. By IEEE 1275 compatibility conventions, 1051 * 8514/A registers should have been added after all standard VGA registers. 1052 * Unfortunately, the Solaris/Intel device configuration framework 1053 * (a) lists the 8514/A registers before the video memory, and then 1054 * (b) also sorts the entries so that I/O entries come before memory 1055 * entries. 1056 * 1057 * It returns the "reg" index and offset into that register set. 1058 * The offset is needed because there exist (broken?) BIOSes that 1059 * report larger ranges enclosing the standard ranges. One reports 1060 * 0x3bf for 0x21 instead of 0x3c0 for 0x20, for instance. Using the 1061 * offset adjusts for this difference in the base of the register set. 1062 * 1063 * Note that this routine may not be fully general; it is intended for the 1064 * specific purpose of finding a couple of particular VGA reg entries and 1065 * may not be suitable for all reg-searching purposes. 1066 */ 1067 static int 1068 vgatext_get_isa_reg_index( 1069 dev_info_t *const devi, 1070 unsigned long hival, 1071 unsigned long addr, 1072 off_t *offset) 1073 { 1074 1075 int length, index; 1076 struct regspec *reg; 1077 1078 if (ddi_getlongprop(DDI_DEV_T_ANY, devi, DDI_PROP_DONTPASS, 1079 "reg", (caddr_t)®, &length) != DDI_PROP_SUCCESS) { 1080 return (-1); 1081 } 1082 1083 for (index = 0; index < length / sizeof (struct regspec); index++) { 1084 if (reg[index].regspec_bustype != hival) 1085 continue; 1086 if (reg[index].regspec_addr > addr) 1087 continue; 1088 if (reg[index].regspec_addr + reg[index].regspec_size <= addr) 1089 continue; 1090 1091 *offset = addr - reg[index].regspec_addr; 1092 kmem_free(reg, (size_t)length); 1093 return (index); 1094 } 1095 kmem_free(reg, (size_t)length); 1096 1097 return (-1); 1098 } 1099