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