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 /* 27 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 28 * Use is subject to license terms. 29 */ 30 31 #pragma ident "%Z%%M% %I% %E% SMI" 32 33 #include <sys/errno.h> 34 #include <sys/types.h> 35 #include <sys/conf.h> 36 #include <sys/kmem.h> 37 #include <sys/visual_io.h> 38 #include <sys/font.h> 39 #include <sys/fbio.h> 40 41 #include <sys/ddi.h> 42 #include <sys/stat.h> 43 #include <sys/sunddi.h> 44 #include <sys/file.h> 45 #include <sys/open.h> 46 #include <sys/modctl.h> 47 #include <sys/vgareg.h> 48 #include <sys/vgasubr.h> 49 #include <sys/pci.h> 50 #include <sys/kd.h> 51 #include <sys/ddi_impldefs.h> 52 #include <sys/sunldi.h> 53 #include <sys/agpgart.h> 54 #include <sys/agp/agpdefs.h> 55 #include <sys/agp/agpmaster_io.h> 56 57 #define MYNAME "vgatext" 58 59 /* 60 * agp support macros 61 */ 62 #define I8XX_MMIO_REGSET 2 63 #define I8XX_FB_REGSET 1 64 #define I8XX_PTE_OFFSET 0x10000 65 #define I8XX_PGTBL_CTL 0x2020 66 #define DEV2INST(dev) (getminor(dev) >> 1) 67 #define INST2NODE1(inst) ((inst) << 1) 68 #define INST2NODE2(inst) (((inst) << 1) + 1) 69 70 /* I don't know exactly where these should be defined, but this is a */ 71 /* heck of a lot better than constants in the code. */ 72 #define TEXT_ROWS 25 73 #define TEXT_COLS 80 74 75 #define VGA_BRIGHT_WHITE 0x0f 76 #define VGA_BLACK 0x00 77 78 #define VGA_REG_ADDR 0x3c0 79 #define VGA_REG_SIZE 0x20 80 81 #define VGA_MEM_ADDR 0xa0000 82 #define VGA_MEM_SIZE 0x20000 83 84 #define VGA_MMAP_FB_BASE VGA_MEM_ADDR 85 86 static int vgatext_open(dev_t *, int, int, cred_t *); 87 static int vgatext_close(dev_t, int, int, cred_t *); 88 static int vgatext_ioctl(dev_t, int, intptr_t, int, cred_t *, int *); 89 static int vgatext_devmap(dev_t, devmap_cookie_t, offset_t, size_t, 90 size_t *, uint_t); 91 92 static struct cb_ops cb_vgatext_ops = { 93 vgatext_open, /* cb_open */ 94 vgatext_close, /* cb_close */ 95 nodev, /* cb_strategy */ 96 nodev, /* cb_print */ 97 nodev, /* cb_dump */ 98 nodev, /* cb_read */ 99 nodev, /* cb_write */ 100 vgatext_ioctl, /* cb_ioctl */ 101 vgatext_devmap, /* cb_devmap */ 102 nodev, /* cb_mmap */ 103 ddi_devmap_segmap, /* cb_segmap */ 104 nochpoll, /* cb_chpoll */ 105 ddi_prop_op, /* cb_prop_op */ 106 0, /* cb_stream */ 107 D_NEW | D_MTSAFE /* cb_flag */ 108 }; 109 110 111 static int vgatext_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, 112 void **result); 113 static int vgatext_attach(dev_info_t *, ddi_attach_cmd_t); 114 static int vgatext_detach(dev_info_t *, ddi_detach_cmd_t); 115 116 static struct vis_identifier text_ident = { "SUNWtext" }; 117 118 static struct dev_ops vgatext_ops = { 119 DEVO_REV, /* devo_rev */ 120 0, /* devo_refcnt */ 121 vgatext_info, /* devo_getinfo */ 122 nulldev, /* devo_identify */ 123 nulldev, /* devo_probe */ 124 vgatext_attach, /* devo_attach */ 125 vgatext_detach, /* devo_detach */ 126 nodev, /* devo_reset */ 127 &cb_vgatext_ops, /* devo_cb_ops */ 128 (struct bus_ops *)NULL, /* devo_bus_ops */ 129 NULL /* power */ 130 }; 131 132 133 /* 134 * agp support data structures 135 */ 136 typedef struct gtt_impl { 137 ddi_acc_handle_t gtt_mmio_handle; /* mmaped graph registers */ 138 caddr_t gtt_mmio_base; /* pointer to register base */ 139 caddr_t gtt_addr; /* pointer to gtt */ 140 igd_info_t gtt_info; /* for I8XX_GET_INFO ioctl */ 141 } gtt_impl_t; 142 143 typedef struct agp_master_softc { 144 uint32_t agpm_id; /* agp master device id */ 145 ddi_acc_handle_t agpm_acc_hdl; /* agp master pci conf handle */ 146 int agpm_dev_type; /* which agp device type */ 147 union { 148 off_t agpm_acaptr; /* AGP capability reg pointer */ 149 gtt_impl_t agpm_gtt; /* for gtt table */ 150 } agpm_data; 151 } agp_master_softc_t; 152 153 154 155 struct vgatext_softc { 156 struct vgaregmap regs; 157 struct vgaregmap fb; 158 off_t fb_size; 159 int fb_regno; 160 dev_info_t *devi; 161 int mode; /* KD_TEXT or KD_GRAPHICS */ 162 caddr_t text_base; /* hardware text base */ 163 char shadow[TEXT_ROWS*TEXT_COLS*2]; 164 caddr_t current_base; /* hardware or shadow */ 165 struct { 166 boolean_t visible; 167 int row; 168 int col; 169 } cursor; 170 struct vis_polledio polledio; 171 struct { 172 unsigned char red; 173 unsigned char green; 174 unsigned char blue; 175 } colormap[VGA8_CMAP_ENTRIES]; 176 unsigned char attrib_palette[VGA_ATR_NUM_PLT]; 177 agp_master_softc_t *agp_master; /* NULL mean not PCI, for AGP */ 178 }; 179 180 static int vgatext_devinit(struct vgatext_softc *, struct vis_devinit *data); 181 static void vgatext_cons_copy(struct vgatext_softc *, 182 struct vis_conscopy *); 183 static void vgatext_cons_display(struct vgatext_softc *, 184 struct vis_consdisplay *); 185 static void vgatext_cons_cursor(struct vgatext_softc *, 186 struct vis_conscursor *); 187 static void vgatext_polled_copy(struct vis_polledio_arg *, 188 struct vis_conscopy *); 189 static void vgatext_polled_display(struct vis_polledio_arg *, 190 struct vis_consdisplay *); 191 static void vgatext_polled_cursor(struct vis_polledio_arg *, 192 struct vis_conscursor *); 193 static void vgatext_init(struct vgatext_softc *); 194 static void vgatext_set_text(struct vgatext_softc *); 195 #if defined(USE_BORDERS) 196 static void vgatext_init_graphics(struct vgatext_softc *); 197 #endif 198 static int vgatext_kdsetmode(struct vgatext_softc *softc, int mode); 199 static void vgatext_setfont(struct vgatext_softc *softc); 200 static void vgatext_get_cursor(struct vgatext_softc *softc, 201 screen_pos_t *row, screen_pos_t *col); 202 static void vgatext_set_cursor(struct vgatext_softc *softc, int row, int col); 203 static void vgatext_hide_cursor(struct vgatext_softc *softc); 204 static void vgatext_save_colormap(struct vgatext_softc *softc); 205 static void vgatext_restore_colormap(struct vgatext_softc *softc); 206 static int vgatext_get_pci_reg_index(dev_info_t *const devi, 207 unsigned long himask, unsigned long hival, unsigned long addr, 208 off_t *offset); 209 static int vgatext_get_isa_reg_index(dev_info_t *const devi, 210 unsigned long hival, unsigned long addr, off_t *offset); 211 /* 212 * agp support functions prototype 213 */ 214 static off_t agp_master_cap_find(ddi_acc_handle_t); 215 static int detect_i8xx_device(agp_master_softc_t *); 216 static int detect_agp_devcice(agp_master_softc_t *); 217 static int agp_master_init(struct vgatext_softc *); 218 static void agp_master_end(agp_master_softc_t *); 219 static int phys2entry(uint32_t, uint32_t, uint32_t *); 220 static int i8xx_add_to_gtt(gtt_impl_t *, igd_gtt_seg_t); 221 static void i8xx_remove_from_gtt(gtt_impl_t *, igd_gtt_seg_t); 222 223 static void *vgatext_softc_head; 224 static char vgatext_silent; 225 static char happyface_boot; 226 227 /* Loadable Driver stuff */ 228 229 static struct modldrv modldrv = { 230 &mod_driverops, /* Type of module. This one is a driver */ 231 "VGA text driver v%I%", /* Name of the module. */ 232 &vgatext_ops, /* driver ops */ 233 }; 234 235 static struct modlinkage modlinkage = { 236 MODREV_1, (void *) &modldrv, NULL 237 }; 238 239 typedef enum pc_colors { 240 pc_black = 0, 241 pc_blue = 1, 242 pc_green = 2, 243 pc_cyan = 3, 244 pc_red = 4, 245 pc_magenta = 5, 246 pc_brown = 6, 247 pc_white = 7, 248 pc_grey = 8, 249 pc_brt_blue = 9, 250 pc_brt_green = 10, 251 pc_brt_cyan = 11, 252 pc_brt_red = 12, 253 pc_brt_magenta = 13, 254 pc_yellow = 14, 255 pc_brt_white = 15 256 } pc_colors_t; 257 258 static const unsigned char solaris_color_to_pc_color[16] = { 259 pc_brt_white, /* 0 - brt_white */ 260 pc_black, /* 1 - black */ 261 pc_blue, /* 2 - blue */ 262 pc_green, /* 3 - green */ 263 pc_cyan, /* 4 - cyan */ 264 pc_red, /* 5 - red */ 265 pc_magenta, /* 6 - magenta */ 266 pc_brown, /* 7 - brown */ 267 pc_white, /* 8 - white */ 268 pc_grey, /* 9 - gery */ 269 pc_brt_blue, /* 10 - brt_blue */ 270 pc_brt_green, /* 11 - brt_green */ 271 pc_brt_cyan, /* 12 - brt_cyan */ 272 pc_brt_red, /* 13 - brt_red */ 273 pc_brt_magenta, /* 14 - brt_magenta */ 274 pc_yellow /* 15 - yellow */ 275 }; 276 277 static ddi_device_acc_attr_t i8xx_dev_access = { 278 DDI_DEVICE_ATTR_V0, 279 DDI_NEVERSWAP_ACC, 280 DDI_STRICTORDER_ACC 281 }; 282 283 static ddi_device_acc_attr_t dev_attr = { 284 DDI_DEVICE_ATTR_V0, 285 DDI_NEVERSWAP_ACC, 286 DDI_STRICTORDER_ACC, 287 }; 288 289 int 290 _init(void) 291 { 292 int e; 293 294 if ((e = ddi_soft_state_init(&vgatext_softc_head, 295 sizeof (struct vgatext_softc), 1)) != 0) { 296 return (e); 297 } 298 299 e = mod_install(&modlinkage); 300 301 if (e) { 302 ddi_soft_state_fini(&vgatext_softc_head); 303 } 304 return (e); 305 } 306 307 int 308 _fini(void) 309 { 310 int e; 311 312 if ((e = mod_remove(&modlinkage)) != 0) 313 return (e); 314 315 ddi_soft_state_fini(&vgatext_softc_head); 316 317 return (0); 318 } 319 320 int 321 _info(struct modinfo *modinfop) 322 { 323 return (mod_info(&modlinkage, modinfop)); 324 } 325 326 /* default structure for FBIOGATTR ioctl */ 327 static struct fbgattr vgatext_attr = { 328 /* real_type owner */ 329 FBTYPE_SUNFAST_COLOR, 0, 330 /* fbtype: type h w depth cms size */ 331 { FBTYPE_SUNFAST_COLOR, TEXT_ROWS, TEXT_COLS, 1, 256, 0 }, 332 /* fbsattr: flags emu_type dev_specific */ 333 { 0, FBTYPE_SUN4COLOR, { 0 } }, 334 /* emu_types */ 335 { -1 } 336 }; 337 338 /* 339 * handy macros 340 */ 341 342 #define getsoftc(instance) ((struct vgatext_softc *) \ 343 ddi_get_soft_state(vgatext_softc_head, (instance))) 344 345 static int 346 vgatext_attach(dev_info_t *devi, ddi_attach_cmd_t cmd) 347 { 348 struct vgatext_softc *softc; 349 int unit = ddi_get_instance(devi); 350 int error; 351 char *parent_type = NULL; 352 int reg_rnumber; 353 off_t reg_offset; 354 off_t mem_offset; 355 char buf[80], *cons; 356 357 358 switch (cmd) { 359 case DDI_ATTACH: 360 break; 361 362 case DDI_RESUME: 363 return (DDI_SUCCESS); 364 default: 365 return (DDI_FAILURE); 366 } 367 368 /* DDI_ATTACH */ 369 370 /* Allocate softc struct */ 371 if (ddi_soft_state_zalloc(vgatext_softc_head, unit) != DDI_SUCCESS) { 372 return (DDI_FAILURE); 373 } 374 softc = getsoftc(unit); 375 376 /* link it in */ 377 softc->devi = devi; 378 ddi_set_driver_private(devi, softc); 379 380 softc->polledio.arg = (struct vis_polledio_arg *)softc; 381 softc->polledio.display = vgatext_polled_display; 382 softc->polledio.copy = vgatext_polled_copy; 383 softc->polledio.cursor = vgatext_polled_cursor; 384 385 error = ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_get_parent(devi), 386 DDI_PROP_DONTPASS, "device_type", &parent_type); 387 if (error != DDI_SUCCESS) { 388 cmn_err(CE_WARN, MYNAME ": can't determine parent type."); 389 goto fail; 390 } 391 392 #define STREQ(a, b) (strcmp((a), (b)) == 0) 393 if (STREQ(parent_type, "isa") || STREQ(parent_type, "eisa")) { 394 reg_rnumber = vgatext_get_isa_reg_index(devi, 1, VGA_REG_ADDR, 395 ®_offset); 396 if (reg_rnumber < 0) { 397 cmn_err(CE_WARN, 398 MYNAME ": can't find reg entry for registers"); 399 goto fail; 400 } 401 softc->fb_regno = vgatext_get_isa_reg_index(devi, 0, 402 VGA_MEM_ADDR, &mem_offset); 403 if (softc->fb_regno < 0) { 404 cmn_err(CE_WARN, 405 MYNAME ": can't find reg entry for memory"); 406 goto fail; 407 } 408 } else if (STREQ(parent_type, "pci") || STREQ(parent_type, "pciex")) { 409 reg_rnumber = vgatext_get_pci_reg_index(devi, 410 PCI_REG_ADDR_M|PCI_REG_REL_M, 411 PCI_ADDR_IO|PCI_RELOCAT_B, VGA_REG_ADDR, 412 ®_offset); 413 if (reg_rnumber < 0) { 414 cmn_err(CE_WARN, 415 MYNAME ": can't find reg entry for registers"); 416 goto fail; 417 } 418 softc->fb_regno = vgatext_get_pci_reg_index(devi, 419 PCI_REG_ADDR_M|PCI_REG_REL_M, 420 PCI_ADDR_MEM32|PCI_RELOCAT_B, VGA_MEM_ADDR, 421 &mem_offset); 422 if (softc->fb_regno < 0) { 423 cmn_err(CE_WARN, 424 MYNAME ": can't find reg entry for memory"); 425 goto fail; 426 } 427 softc->agp_master = (agp_master_softc_t *) 428 kmem_zalloc(sizeof (agp_master_softc_t), KM_SLEEP); 429 } else { 430 cmn_err(CE_WARN, MYNAME ": unknown parent type \"%s\".", 431 parent_type); 432 goto fail; 433 } 434 ddi_prop_free(parent_type); 435 parent_type = NULL; 436 437 error = ddi_regs_map_setup(devi, reg_rnumber, 438 (caddr_t *)&softc->regs.addr, reg_offset, VGA_REG_SIZE, 439 &dev_attr, &softc->regs.handle); 440 if (error != DDI_SUCCESS) 441 goto fail; 442 softc->regs.mapped = B_TRUE; 443 444 softc->fb_size = VGA_MEM_SIZE; 445 446 error = ddi_regs_map_setup(devi, softc->fb_regno, 447 (caddr_t *)&softc->fb.addr, 448 mem_offset, softc->fb_size, 449 &dev_attr, &softc->fb.handle); 450 if (error != DDI_SUCCESS) 451 goto fail; 452 softc->fb.mapped = B_TRUE; 453 454 if (ddi_get8(softc->regs.handle, 455 softc->regs.addr + VGA_MISC_R) & VGA_MISC_IOA_SEL) 456 softc->text_base = (caddr_t)softc->fb.addr + VGA_COLOR_BASE; 457 else 458 softc->text_base = (caddr_t)softc->fb.addr + VGA_MONO_BASE; 459 softc->current_base = softc->text_base; 460 461 (void) sprintf(buf, "text-%d", unit); 462 error = ddi_create_minor_node(devi, buf, S_IFCHR, 463 INST2NODE1(unit), DDI_NT_DISPLAY, NULL); 464 if (error != DDI_SUCCESS) 465 goto fail; 466 467 error = ddi_prop_create(makedevice(DDI_MAJOR_T_UNKNOWN, unit), 468 devi, DDI_PROP_CANSLEEP, DDI_KERNEL_IOCTL, NULL, 0); 469 if (error != DDI_SUCCESS) 470 goto fail; 471 472 if (ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_root_node(), 473 DDI_PROP_DONTPASS, "console", &cons) == DDI_SUCCESS) { 474 if (strcmp(cons, "graphics") == 0) { 475 happyface_boot = 1; 476 vgatext_silent = 1; 477 } 478 ddi_prop_free(cons); 479 } 480 481 /* only do this if not in graphics mode */ 482 if (vgatext_silent == 0) { 483 vgatext_init(softc); 484 vgatext_save_colormap(softc); 485 } 486 487 if (softc->agp_master != NULL) { /* is PCI */ 488 if (agp_master_init(softc) != 0) { /* unsuccessful */ 489 kmem_free(softc->agp_master, 490 sizeof (agp_master_softc_t)); 491 softc->agp_master = NULL; 492 493 } 494 } 495 496 return (DDI_SUCCESS); 497 498 fail: 499 if (parent_type != NULL) 500 ddi_prop_free(parent_type); 501 (void) vgatext_detach(devi, DDI_DETACH); 502 return (error); 503 } 504 505 static int 506 vgatext_detach(dev_info_t *devi, ddi_detach_cmd_t cmd) 507 { 508 int instance = ddi_get_instance(devi); 509 struct vgatext_softc *softc = getsoftc(instance); 510 511 512 switch (cmd) { 513 case DDI_DETACH: 514 if (softc->agp_master != NULL) { /* agp initiated */ 515 agp_master_end(softc->agp_master); 516 517 kmem_free(softc->agp_master, 518 sizeof (agp_master_softc_t)); 519 softc->agp_master = NULL; 520 521 } 522 523 if (softc->fb.mapped) 524 ddi_regs_map_free(&softc->fb.handle); 525 if (softc->regs.mapped) 526 ddi_regs_map_free(&softc->regs.handle); 527 ddi_remove_minor_node(devi, NULL); 528 (void) ddi_soft_state_free(vgatext_softc_head, instance); 529 return (DDI_SUCCESS); 530 531 default: 532 cmn_err(CE_WARN, "vgatext_detach: unknown cmd 0x%x\n", cmd); 533 return (DDI_FAILURE); 534 } 535 } 536 537 /*ARGSUSED*/ 538 static int 539 vgatext_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) 540 { 541 dev_t dev; 542 int error; 543 int instance; 544 struct vgatext_softc *softc; 545 546 error = DDI_SUCCESS; 547 548 dev = (dev_t)arg; 549 instance = DEV2INST(dev); 550 softc = getsoftc(instance); 551 552 switch (infocmd) { 553 case DDI_INFO_DEVT2DEVINFO: 554 if (softc == NULL || softc->devi == NULL) { 555 error = DDI_FAILURE; 556 } else { 557 *result = (void *) softc->devi; 558 error = DDI_SUCCESS; 559 } 560 break; 561 case DDI_INFO_DEVT2INSTANCE: 562 *result = (void *)(uintptr_t)instance; 563 error = DDI_SUCCESS; 564 break; 565 default: 566 error = DDI_FAILURE; 567 break; 568 } 569 return (error); 570 } 571 572 573 /*ARGSUSED*/ 574 static int 575 vgatext_open(dev_t *devp, int flag, int otyp, cred_t *cred) 576 { 577 struct vgatext_softc *softc = getsoftc(DEV2INST(*devp)); 578 579 if (softc == NULL || otyp == OTYP_BLK) 580 return (ENXIO); 581 582 return (0); 583 } 584 585 /*ARGSUSED*/ 586 static int 587 vgatext_close(dev_t devp, int flag, int otyp, cred_t *cred) 588 { 589 return (0); 590 } 591 592 /*ARGSUSED*/ 593 static int 594 vgatext_ioctl( 595 dev_t dev, 596 int cmd, 597 intptr_t data, 598 int mode, 599 cred_t *cred, 600 int *rval) 601 { 602 struct vgatext_softc *softc = getsoftc(DEV2INST(dev)); 603 static char kernel_only[] = "vgatext_ioctl: %s is a kernel only ioctl"; 604 int err; 605 int kd_mode; 606 607 switch (cmd) { 608 case KDSETMODE: 609 return (vgatext_kdsetmode(softc, (int)data)); 610 611 case KDGETMODE: 612 kd_mode = softc->mode; 613 if (ddi_copyout(&kd_mode, (void *)data, sizeof (int), mode)) 614 return (EFAULT); 615 break; 616 617 case VIS_GETIDENTIFIER: 618 if (ddi_copyout(&text_ident, (void *)data, 619 sizeof (struct vis_identifier), mode)) 620 return (EFAULT); 621 break; 622 623 case VIS_DEVINIT: 624 625 if (!(mode & FKIOCTL)) { 626 cmn_err(CE_CONT, kernel_only, "VIS_DEVINIT"); 627 return (ENXIO); 628 } 629 630 err = vgatext_devinit(softc, (struct vis_devinit *)data); 631 if (err != 0) { 632 cmn_err(CE_WARN, 633 "vgatext_ioctl: could not initialize console"); 634 return (err); 635 } 636 break; 637 638 case VIS_CONSCOPY: /* move */ 639 { 640 struct vis_conscopy pma; 641 642 if (ddi_copyin((void *)data, &pma, 643 sizeof (struct vis_conscopy), mode)) 644 return (EFAULT); 645 646 vgatext_cons_copy(softc, &pma); 647 break; 648 } 649 650 case VIS_CONSDISPLAY: /* display */ 651 { 652 struct vis_consdisplay display_request; 653 654 if (ddi_copyin((void *)data, &display_request, 655 sizeof (display_request), mode)) 656 return (EFAULT); 657 658 vgatext_cons_display(softc, &display_request); 659 break; 660 } 661 662 case VIS_CONSCURSOR: 663 { 664 struct vis_conscursor cursor_request; 665 666 if (ddi_copyin((void *)data, &cursor_request, 667 sizeof (cursor_request), mode)) 668 return (EFAULT); 669 670 vgatext_cons_cursor(softc, &cursor_request); 671 672 if (cursor_request.action == VIS_GET_CURSOR && 673 ddi_copyout(&cursor_request, (void *)data, 674 sizeof (cursor_request), mode)) 675 return (EFAULT); 676 break; 677 } 678 679 case VIS_GETCMAP: 680 case VIS_PUTCMAP: 681 case FBIOPUTCMAP: 682 case FBIOGETCMAP: 683 /* 684 * At the moment, text mode is not considered to have 685 * a color map. 686 */ 687 return (EINVAL); 688 689 case FBIOGATTR: 690 if (copyout(&vgatext_attr, (void *)data, 691 sizeof (struct fbgattr))) 692 return (EFAULT); 693 break; 694 695 case FBIOGTYPE: 696 if (copyout(&vgatext_attr.fbtype, (void *)data, 697 sizeof (struct fbtype))) 698 return (EFAULT); 699 break; 700 701 #if 0 702 case GLY_LD_GLYPH: 703 { 704 temstat_t *ap; 705 da_t da; 706 struct glyph g; 707 int size; 708 uchar_t *c; 709 710 if (ddi_copyin(arg, &g, sizeof (g), flag)) 711 return (EFAULT); 712 713 size = g.width * g.height; 714 c = kmem_alloc(size, KM_SLEEP); 715 716 if (ddi_copyin(g.raster, c, size, flag)) { 717 kmem_free(c, size); 718 return (EFAULT); 719 } 720 ap = (temstat_t *)something; 721 da.data = c; 722 da.width = g.width; 723 da.height = g.height; 724 da.col = g.x_dest; 725 da.row = g.y_dest; 726 ap->a_fp.f_ad_display(ap->a_private, &da); 727 kmem_free(c, size); 728 return (0); 729 } 730 #endif 731 case DEVICE_DETECT: 732 { 733 agp_master_softc_t *agp_master; 734 735 if (!(mode & FKIOCTL)) { 736 cmn_err(CE_CONT, kernel_only, "DEVICE_DETECT"); 737 return (ENXIO); 738 } 739 agp_master = softc->agp_master; 740 ASSERT(agp_master); 741 742 if (!agp_master) 743 return (EINVAL); 744 745 if (ddi_copyout(&agp_master->agpm_dev_type, 746 (void *)data, sizeof (int), mode)) 747 return (EFAULT); 748 break; 749 } 750 case I8XX_GET_INFO: 751 { 752 agp_master_softc_t *agp_master; 753 754 if (!(mode & FKIOCTL)) { 755 cmn_err(CE_CONT, kernel_only, "I8XX_GET_INFO"); 756 return (ENXIO); 757 } 758 agp_master = softc->agp_master; 759 ASSERT(agp_master); 760 761 if (!agp_master) 762 return (EINVAL); 763 ASSERT((agp_master->agpm_dev_type == DEVICE_IS_I810) || 764 (agp_master->agpm_dev_type == DEVICE_IS_I830)); 765 766 if ((agp_master->agpm_dev_type != DEVICE_IS_I810) && 767 (agp_master->agpm_dev_type != DEVICE_IS_I830)) 768 return (EINVAL); 769 770 if (ddi_copyout(&agp_master->agpm_data.agpm_gtt.gtt_info, 771 (void *)data, 772 sizeof (igd_info_t), mode)) 773 return (EFAULT); 774 break; 775 } 776 case I810_SET_GTT_BASE: 777 { 778 uint32_t base; 779 uint32_t addr; 780 agp_master_softc_t *agp_master; 781 782 if (!(mode & FKIOCTL)) { 783 cmn_err(CE_CONT, kernel_only, "I8XX_SET_GTT_ADDR"); 784 return (ENXIO); 785 } 786 agp_master = softc->agp_master; 787 ASSERT(agp_master); 788 if (!agp_master) 789 return (EINVAL); 790 ASSERT(agp_master->agpm_dev_type == DEVICE_IS_I810); 791 if (agp_master->agpm_dev_type != DEVICE_IS_I810) 792 return (EINVAL); 793 794 if (ddi_copyin((void *)data, &base, sizeof (uint32_t), mode)) 795 return (EFAULT); 796 797 /* enables page table */ 798 addr = (base & GTT_BASE_MASK) | GTT_TABLE_VALID; 799 800 ddi_put32(agp_master->agpm_data.agpm_gtt.gtt_mmio_handle, 801 (uint32_t *)(agp_master->agpm_data.agpm_gtt.gtt_mmio_base + 802 I8XX_PGTBL_CTL), 803 addr); 804 break; 805 } 806 case I8XX_ADD2GTT: 807 { 808 igd_gtt_seg_t seg; 809 agp_master_softc_t *agp_master; 810 811 if (!(mode & FKIOCTL)) { 812 cmn_err(CE_CONT, kernel_only, "I8XX_ADD2GTT"); 813 return (ENXIO); 814 } 815 agp_master = softc->agp_master; 816 ASSERT(agp_master); 817 if (!agp_master) 818 return (EINVAL); 819 ASSERT((agp_master->agpm_dev_type == DEVICE_IS_I810) || 820 (agp_master->agpm_dev_type == DEVICE_IS_I830)); 821 822 if ((agp_master->agpm_dev_type != DEVICE_IS_I810) && 823 (agp_master->agpm_dev_type != DEVICE_IS_I830)) 824 return (EINVAL); 825 826 if (ddi_copyin((void *)data, &seg, 827 sizeof (igd_gtt_seg_t), mode)) 828 return (EFAULT); 829 830 if (i8xx_add_to_gtt(&agp_master->agpm_data.agpm_gtt, seg)) 831 return (EINVAL); 832 break; 833 } 834 case I8XX_REM_GTT: 835 { 836 igd_gtt_seg_t seg; 837 agp_master_softc_t *agp_master; 838 839 if (!(mode & FKIOCTL)) { 840 cmn_err(CE_CONT, kernel_only, "I8XX_REM_GTT"); 841 return (ENXIO); 842 } 843 agp_master = softc->agp_master; 844 ASSERT(agp_master); 845 if (!agp_master) 846 return (EINVAL); 847 ASSERT((agp_master->agpm_dev_type == DEVICE_IS_I810) || 848 (agp_master->agpm_dev_type == DEVICE_IS_I830)); 849 850 if ((agp_master->agpm_dev_type != DEVICE_IS_I810) && 851 (agp_master->agpm_dev_type != DEVICE_IS_I830)) 852 return (EINVAL); 853 854 if (ddi_copyin((void *)data, &seg, 855 sizeof (igd_gtt_seg_t), mode)) 856 return (EFAULT); 857 858 i8xx_remove_from_gtt(&agp_master->agpm_data.agpm_gtt, seg); 859 break; 860 } 861 case I8XX_UNCONFIG: 862 { 863 agp_master_softc_t *agp_master; 864 865 if (!(mode & FKIOCTL)) { 866 cmn_err(CE_CONT, kernel_only, "I8XX_UNCONFIG"); 867 return (ENXIO); 868 } 869 agp_master = softc->agp_master; 870 ASSERT(agp_master); 871 if (!agp_master) 872 return (EINVAL); 873 ASSERT((agp_master->agpm_dev_type == DEVICE_IS_I810) || 874 (agp_master->agpm_dev_type == DEVICE_IS_I830)); 875 876 if ((agp_master->agpm_dev_type != DEVICE_IS_I810) && 877 (agp_master->agpm_dev_type != DEVICE_IS_I830)) 878 return (EINVAL); 879 880 if (agp_master->agpm_dev_type == DEVICE_IS_I810) 881 ddi_put32( 882 agp_master->agpm_data.agpm_gtt.gtt_mmio_handle, 883 (uint32_t *) 884 (agp_master->agpm_data.agpm_gtt.gtt_mmio_base + 885 I8XX_PGTBL_CTL), 886 0); 887 /* 888 * may clear all gtt entries here for i830, 889 * but may not be necessary 890 */ 891 break; 892 } 893 case AGP_MASTER_GETINFO: 894 { 895 agp_info_t info; 896 uint32_t value; 897 off_t cap; 898 agp_master_softc_t *agp_master; 899 900 if (!(mode & FKIOCTL)) { 901 cmn_err(CE_CONT, kernel_only, "AGP_MASTER_GETINFO"); 902 return (ENXIO); 903 } 904 agp_master = softc->agp_master; 905 ASSERT(agp_master); 906 if (!agp_master) 907 return (EINVAL); 908 ASSERT(agp_master->agpm_dev_type == DEVICE_IS_AGP); 909 if (agp_master->agpm_dev_type != DEVICE_IS_AGP) 910 return (EINVAL); 911 912 ASSERT(agp_master->agpm_data.agpm_acaptr); 913 if (agp_master->agpm_data.agpm_acaptr == 0) 914 return (EINVAL); 915 916 cap = agp_master->agpm_data.agpm_acaptr; 917 value = pci_config_get32(agp_master->agpm_acc_hdl, cap); 918 info.agpi_version.agpv_major = (uint16_t)((value >> 20) & 0xf); 919 info.agpi_version.agpv_minor = (uint16_t)((value >> 16) & 0xf); 920 info.agpi_devid = agp_master->agpm_id; 921 info.agpi_mode = pci_config_get32( 922 agp_master->agpm_acc_hdl, cap + AGP_CONF_STATUS); 923 924 if (ddi_copyout(&info, (void *)data, 925 sizeof (agp_info_t), mode)) 926 return (EFAULT); 927 break; 928 } 929 case AGP_MASTER_SETCMD: 930 { 931 uint32_t command; 932 agp_master_softc_t *agp_master; 933 934 if (!(mode & FKIOCTL)) { 935 cmn_err(CE_CONT, kernel_only, "AGP_MASTER_SETCMD"); 936 return (ENXIO); 937 } 938 agp_master = softc->agp_master; 939 ASSERT(agp_master); 940 if (!agp_master) 941 return (EINVAL); 942 ASSERT(agp_master->agpm_dev_type == DEVICE_IS_AGP); 943 if (agp_master->agpm_dev_type != DEVICE_IS_AGP) 944 return (EINVAL); 945 946 ASSERT(agp_master->agpm_data.agpm_acaptr); 947 if (agp_master->agpm_data.agpm_acaptr == 0) 948 return (EINVAL); 949 950 if (ddi_copyin((void *)data, &command, 951 sizeof (uint32_t), mode)) 952 return (EFAULT); 953 954 pci_config_put32(agp_master->agpm_acc_hdl, 955 agp_master->agpm_data.agpm_acaptr + AGP_CONF_COMMAND, 956 command); 957 break; 958 959 } 960 default: 961 return (ENXIO); 962 } 963 return (0); 964 } 965 966 static int 967 vgatext_kdsetmode(struct vgatext_softc *softc, int mode) 968 { 969 int i; 970 971 if (mode == softc->mode) 972 return (0); 973 974 switch (mode) { 975 case KD_TEXT: 976 vgatext_init(softc); 977 for (i = 0; i < sizeof (softc->shadow); i++) { 978 softc->text_base[i] = softc->shadow[i]; 979 } 980 softc->current_base = softc->text_base; 981 if (softc->cursor.visible) { 982 vgatext_set_cursor(softc, 983 softc->cursor.row, softc->cursor.col); 984 } 985 vgatext_restore_colormap(softc); 986 break; 987 988 case KD_GRAPHICS: 989 if (vgatext_silent == 1) { 990 extern void progressbar_stop(void); 991 992 vgatext_silent = 0; 993 progressbar_stop(); 994 } 995 for (i = 0; i < sizeof (softc->shadow); i++) { 996 softc->shadow[i] = softc->text_base[i]; 997 } 998 softc->current_base = softc->shadow; 999 #if defined(USE_BORDERS) 1000 vgatext_init_graphics(softc); 1001 #endif 1002 break; 1003 1004 default: 1005 return (EINVAL); 1006 } 1007 softc->mode = mode; 1008 return (0); 1009 } 1010 1011 /*ARGSUSED*/ 1012 static int 1013 vgatext_devmap(dev_t dev, devmap_cookie_t dhp, offset_t off, size_t len, 1014 size_t *maplen, uint_t model) 1015 { 1016 struct vgatext_softc *softc; 1017 int err; 1018 size_t length; 1019 1020 1021 softc = getsoftc(DEV2INST(dev)); 1022 if (softc == NULL) { 1023 cmn_err(CE_WARN, "vgatext: Can't find softstate"); 1024 return (-1); 1025 } 1026 1027 if (!(off >= VGA_MMAP_FB_BASE && 1028 off < VGA_MMAP_FB_BASE + softc->fb_size)) { 1029 cmn_err(CE_WARN, "vgatext: Can't map offset 0x%llx", off); 1030 return (-1); 1031 } 1032 1033 if (off + len > VGA_MMAP_FB_BASE + softc->fb_size) 1034 length = VGA_MMAP_FB_BASE + softc->fb_size - off; 1035 else 1036 length = len; 1037 1038 if ((err = devmap_devmem_setup(dhp, softc->devi, NULL, softc->fb_regno, 1039 off - VGA_MMAP_FB_BASE, 1040 length, PROT_ALL, 0, &dev_attr)) < 0) { 1041 return (err); 1042 } 1043 1044 1045 *maplen = length; 1046 return (0); 1047 } 1048 1049 1050 static int 1051 vgatext_devinit(struct vgatext_softc *softc, struct vis_devinit *data) 1052 { 1053 /* initialize console instance */ 1054 data->version = VIS_CONS_REV; 1055 data->width = TEXT_COLS; 1056 data->height = TEXT_ROWS; 1057 data->linebytes = TEXT_COLS; 1058 data->depth = 4; 1059 data->mode = VIS_TEXT; 1060 data->polledio = &softc->polledio; 1061 1062 return (0); 1063 } 1064 1065 /* 1066 * display a string on the screen at (row, col) 1067 * assume it has been cropped to fit. 1068 */ 1069 1070 static void 1071 vgatext_cons_display(struct vgatext_softc *softc, struct vis_consdisplay *da) 1072 { 1073 unsigned char *string; 1074 int i; 1075 unsigned char attr; 1076 struct cgatext { 1077 unsigned char ch; 1078 unsigned char attr; 1079 }; 1080 struct cgatext *addr; 1081 1082 if (vgatext_silent) 1083 return; 1084 /* 1085 * Sanity checks. This is a last-ditch effort to avoid damage 1086 * from brokenness or maliciousness above. 1087 */ 1088 if (da->row < 0 || da->row >= TEXT_ROWS || 1089 da->col < 0 || da->col >= TEXT_COLS || 1090 da->col + da->width > TEXT_COLS) 1091 return; 1092 1093 /* 1094 * To be fully general, we should copyin the data. This is not 1095 * really relevant for this text-only driver, but a graphical driver 1096 * should support these ioctls from userland to enable simple 1097 * system startup graphics. 1098 */ 1099 attr = (solaris_color_to_pc_color[da->bg_color & 0xf] << 4) 1100 | solaris_color_to_pc_color[da->fg_color & 0xf]; 1101 string = da->data; 1102 addr = (struct cgatext *)softc->current_base 1103 + (da->row * TEXT_COLS + da->col); 1104 for (i = 0; i < da->width; i++) { 1105 addr->ch = string[i]; 1106 addr->attr = attr; 1107 addr++; 1108 } 1109 } 1110 1111 static void 1112 vgatext_polled_display( 1113 struct vis_polledio_arg *arg, 1114 struct vis_consdisplay *da) 1115 { 1116 vgatext_cons_display((struct vgatext_softc *)arg, da); 1117 } 1118 1119 /* 1120 * screen-to-screen copy 1121 */ 1122 1123 static void 1124 vgatext_cons_copy(struct vgatext_softc *softc, struct vis_conscopy *ma) 1125 { 1126 unsigned short *from; 1127 unsigned short *to; 1128 int cnt; 1129 screen_size_t chars_per_row; 1130 unsigned short *to_row_start; 1131 unsigned short *from_row_start; 1132 screen_size_t rows_to_move; 1133 unsigned short *base; 1134 1135 if (vgatext_silent) 1136 return; 1137 1138 /* 1139 * Sanity checks. Note that this is a last-ditch effort to avoid 1140 * damage caused by broken-ness or maliciousness above. 1141 */ 1142 if (ma->s_col < 0 || ma->s_col >= TEXT_COLS || 1143 ma->s_row < 0 || ma->s_row >= TEXT_ROWS || 1144 ma->e_col < 0 || ma->e_col >= TEXT_COLS || 1145 ma->e_row < 0 || ma->e_row >= TEXT_ROWS || 1146 ma->t_col < 0 || ma->t_col >= TEXT_COLS || 1147 ma->t_row < 0 || ma->t_row >= TEXT_ROWS || 1148 ma->s_col > ma->e_col || 1149 ma->s_row > ma->e_row) 1150 return; 1151 1152 /* 1153 * Remember we're going to copy shorts because each 1154 * character/attribute pair is 16 bits. 1155 */ 1156 chars_per_row = ma->e_col - ma->s_col + 1; 1157 rows_to_move = ma->e_row - ma->s_row + 1; 1158 1159 /* More sanity checks. */ 1160 if (ma->t_row + rows_to_move > TEXT_ROWS || 1161 ma->t_col + chars_per_row > TEXT_COLS) 1162 return; 1163 1164 base = (unsigned short *)softc->current_base; 1165 1166 to_row_start = base + ((ma->t_row * TEXT_COLS) + ma->t_col); 1167 from_row_start = base + ((ma->s_row * TEXT_COLS) + ma->s_col); 1168 1169 if (to_row_start < from_row_start) { 1170 while (rows_to_move-- > 0) { 1171 to = to_row_start; 1172 from = from_row_start; 1173 to_row_start += TEXT_COLS; 1174 from_row_start += TEXT_COLS; 1175 for (cnt = chars_per_row; cnt-- > 0; ) 1176 *to++ = *from++; 1177 } 1178 } else { 1179 /* 1180 * Offset to the end of the region and copy backwards. 1181 */ 1182 cnt = rows_to_move * TEXT_COLS + chars_per_row; 1183 to_row_start += cnt; 1184 from_row_start += cnt; 1185 1186 while (rows_to_move-- > 0) { 1187 to_row_start -= TEXT_COLS; 1188 from_row_start -= TEXT_COLS; 1189 to = to_row_start; 1190 from = from_row_start; 1191 for (cnt = chars_per_row; cnt-- > 0; ) 1192 *--to = *--from; 1193 } 1194 } 1195 } 1196 1197 static void 1198 vgatext_polled_copy( 1199 struct vis_polledio_arg *arg, 1200 struct vis_conscopy *ca) 1201 { 1202 vgatext_cons_copy((struct vgatext_softc *)arg, ca); 1203 } 1204 1205 1206 static void 1207 vgatext_cons_cursor(struct vgatext_softc *softc, struct vis_conscursor *ca) 1208 { 1209 if (vgatext_silent) 1210 return; 1211 1212 switch (ca->action) { 1213 case VIS_HIDE_CURSOR: 1214 softc->cursor.visible = B_FALSE; 1215 if (softc->current_base == softc->text_base) 1216 vgatext_hide_cursor(softc); 1217 break; 1218 case VIS_DISPLAY_CURSOR: 1219 /* 1220 * Sanity check. This is a last-ditch effort to avoid 1221 * damage from brokenness or maliciousness above. 1222 */ 1223 if (ca->col < 0 || ca->col >= TEXT_COLS || 1224 ca->row < 0 || ca->row >= TEXT_ROWS) 1225 return; 1226 1227 softc->cursor.visible = B_TRUE; 1228 softc->cursor.col = ca->col; 1229 softc->cursor.row = ca->row; 1230 if (softc->current_base == softc->text_base) 1231 vgatext_set_cursor(softc, ca->row, ca->col); 1232 break; 1233 case VIS_GET_CURSOR: 1234 if (softc->current_base == softc->text_base) { 1235 vgatext_get_cursor(softc, &ca->row, &ca->col); 1236 } 1237 break; 1238 } 1239 } 1240 1241 static void 1242 vgatext_polled_cursor( 1243 struct vis_polledio_arg *arg, 1244 struct vis_conscursor *ca) 1245 { 1246 vgatext_cons_cursor((struct vgatext_softc *)arg, ca); 1247 } 1248 1249 1250 1251 /*ARGSUSED*/ 1252 static void 1253 vgatext_hide_cursor(struct vgatext_softc *softc) 1254 { 1255 /* Nothing at present */ 1256 } 1257 1258 static void 1259 vgatext_set_cursor(struct vgatext_softc *softc, int row, int col) 1260 { 1261 short addr; 1262 1263 if (vgatext_silent) 1264 return; 1265 1266 addr = row * TEXT_COLS + col; 1267 1268 vga_set_crtc(&softc->regs, VGA_CRTC_CLAH, addr >> 8); 1269 vga_set_crtc(&softc->regs, VGA_CRTC_CLAL, addr & 0xff); 1270 } 1271 1272 static int vga_row, vga_col; 1273 1274 static void 1275 vgatext_get_cursor(struct vgatext_softc *softc, 1276 screen_pos_t *row, screen_pos_t *col) 1277 { 1278 short addr; 1279 1280 addr = (vga_get_crtc(&softc->regs, VGA_CRTC_CLAH) << 8) + 1281 vga_get_crtc(&softc->regs, VGA_CRTC_CLAL); 1282 1283 vga_row = *row = addr / TEXT_COLS; 1284 vga_col = *col = addr % TEXT_COLS; 1285 } 1286 1287 /* 1288 * This code is experimental. It's only enabled if console is 1289 * set to graphics, a preliminary implementation of happyface boot. 1290 */ 1291 static void 1292 vgatext_set_text(struct vgatext_softc *softc) 1293 { 1294 int i; 1295 1296 if (happyface_boot == 0) 1297 return; 1298 1299 /* we are in graphics mode, set to text 80X25 mode */ 1300 1301 /* set misc registers */ 1302 vga_set_reg(&softc->regs, VGA_MISC_W, VGA_MISC_TEXT); 1303 1304 /* set sequencer registers */ 1305 vga_set_seq(&softc->regs, VGA_SEQ_RST_SYN, 1306 (vga_get_seq(&softc->regs, VGA_SEQ_RST_SYN) & 1307 ~VGA_SEQ_RST_SYN_NO_SYNC_RESET)); 1308 for (i = 1; i < NUM_SEQ_REG; i++) { 1309 vga_set_seq(&softc->regs, i, VGA_SEQ_TEXT[i]); 1310 } 1311 vga_set_seq(&softc->regs, VGA_SEQ_RST_SYN, 1312 (vga_get_seq(&softc->regs, VGA_SEQ_RST_SYN) | 1313 VGA_SEQ_RST_SYN_NO_ASYNC_RESET | 1314 VGA_SEQ_RST_SYN_NO_SYNC_RESET)); 1315 1316 /* set crt controller registers */ 1317 vga_set_crtc(&softc->regs, VGA_CRTC_VRE, 1318 (vga_get_crtc(&softc->regs, VGA_CRTC_VRE) & 1319 ~VGA_CRTC_VRE_LOCK)); 1320 for (i = 0; i < NUM_CRTC_REG; i++) { 1321 vga_set_crtc(&softc->regs, i, VGA_CRTC_TEXT[i]); 1322 } 1323 1324 /* set graphics controller registers */ 1325 for (i = 0; i < NUM_GRC_REG; i++) { 1326 vga_set_grc(&softc->regs, i, VGA_GRC_TEXT[i]); 1327 } 1328 1329 /* set attribute registers */ 1330 for (i = 0; i < NUM_ATR_REG; i++) { 1331 vga_set_atr(&softc->regs, i, VGA_ATR_TEXT[i]); 1332 } 1333 1334 /* set palette */ 1335 for (i = 0; i < VGA_TEXT_CMAP_ENTRIES; i++) { 1336 vga_put_cmap(&softc->regs, i, VGA_TEXT_PALETTES[i][0] << 2, 1337 VGA_TEXT_PALETTES[i][1] << 2, 1338 VGA_TEXT_PALETTES[i][2] << 2); 1339 } 1340 for (i = VGA_TEXT_CMAP_ENTRIES; i < VGA8_CMAP_ENTRIES; i++) { 1341 vga_put_cmap(&softc->regs, i, 0, 0, 0); 1342 } 1343 1344 vgatext_save_colormap(softc); 1345 } 1346 1347 static void 1348 vgatext_init(struct vgatext_softc *softc) 1349 { 1350 unsigned char atr_mode; 1351 1352 atr_mode = vga_get_atr(&softc->regs, VGA_ATR_MODE); 1353 if (atr_mode & VGA_ATR_MODE_GRAPH) 1354 vgatext_set_text(softc); 1355 atr_mode = vga_get_atr(&softc->regs, VGA_ATR_MODE); 1356 atr_mode &= ~VGA_ATR_MODE_BLINK; 1357 atr_mode &= ~VGA_ATR_MODE_9WIDE; 1358 vga_set_atr(&softc->regs, VGA_ATR_MODE, atr_mode); 1359 #if defined(USE_BORDERS) 1360 vga_set_atr(&softc->regs, VGA_ATR_BDR_CLR, 1361 vga_get_atr(&softc->regs, VGA_BRIGHT_WHITE)); 1362 #else 1363 vga_set_atr(&softc->regs, VGA_ATR_BDR_CLR, 1364 vga_get_atr(&softc->regs, VGA_BLACK)); 1365 #endif 1366 vgatext_setfont(softc); /* need selectable font? */ 1367 } 1368 1369 #if defined(USE_BORDERS) 1370 static void 1371 vgatext_init_graphics(struct vgatext_softc *softc) 1372 { 1373 vga_set_atr(&softc->regs, VGA_ATR_BDR_CLR, 1374 vga_get_atr(&softc->regs, VGA_BLACK)); 1375 } 1376 #endif 1377 1378 static char vga_fontslot = 0; 1379 1380 static void 1381 vgatext_setfont(struct vgatext_softc *softc) 1382 { 1383 static uchar_t fsreg[8] = {0x0, 0x30, 0x5, 0x35, 0xa, 0x3a, 0xf, 0x3f}; 1384 1385 extern unsigned char *ENCODINGS[]; 1386 uchar_t *from; 1387 uchar_t volatile *to; 1388 int i, j, s; 1389 int bpc, f_offset; 1390 1391 /* Sync-reset the sequencer registers */ 1392 vga_set_seq(&softc->regs, 0x00, 0x01); 1393 /* 1394 * enable write to plane2, since fonts 1395 * could only be loaded into plane2 1396 */ 1397 vga_set_seq(&softc->regs, 0x02, 0x04); 1398 /* 1399 * sequentially access data in the bit map being 1400 * selected by MapMask register (index 0x02) 1401 */ 1402 vga_set_seq(&softc->regs, 0x04, 0x07); 1403 /* Sync-reset ended, and allow the sequencer to operate */ 1404 vga_set_seq(&softc->regs, 0x00, 0x03); 1405 1406 /* 1407 * select plane 2 on Read Mode 0 1408 */ 1409 vga_set_grc(&softc->regs, 0x04, 0x02); 1410 /* 1411 * system addresses sequentially access data, follow 1412 * Memory Mode register bit 2 in the sequencer 1413 */ 1414 vga_set_grc(&softc->regs, 0x05, 0x00); 1415 /* 1416 * set range of host memory addresses decoded by VGA 1417 * hardware -- A0000h-BFFFFh (128K region) 1418 */ 1419 vga_set_grc(&softc->regs, 0x06, 0x00); 1420 1421 /* 1422 * This assumes 8x16 characters, which yield the traditional 80x25 1423 * screen. It really should support other character heights. 1424 */ 1425 bpc = 16; 1426 s = vga_fontslot; 1427 f_offset = s * 8 * 1024; 1428 for (i = 0; i < 256; i++) { 1429 from = ENCODINGS[i]; 1430 to = (unsigned char *)softc->fb.addr + f_offset + i * 0x20; 1431 for (j = 0; j < bpc; j++) 1432 *to++ = *from++; 1433 } 1434 1435 /* Sync-reset the sequencer registers */ 1436 vga_set_seq(&softc->regs, 0x00, 0x01); 1437 /* enable write to plane 0 and 1 */ 1438 vga_set_seq(&softc->regs, 0x02, 0x03); 1439 /* 1440 * enable character map selection 1441 * and odd/even addressing 1442 */ 1443 vga_set_seq(&softc->regs, 0x04, 0x03); 1444 /* 1445 * select font map 1446 */ 1447 vga_set_seq(&softc->regs, 0x03, fsreg[s]); 1448 /* Sync-reset ended, and allow the sequencer to operate */ 1449 vga_set_seq(&softc->regs, 0x00, 0x03); 1450 1451 /* restore graphic registers */ 1452 1453 /* select plane 0 */ 1454 vga_set_grc(&softc->regs, 0x04, 0x00); 1455 /* enable odd/even addressing mode */ 1456 vga_set_grc(&softc->regs, 0x05, 0x10); 1457 /* 1458 * range of host memory addresses decoded by VGA 1459 * hardware -- B8000h-BFFFFh (32K region) 1460 */ 1461 vga_set_grc(&softc->regs, 0x06, 0x0e); 1462 /* enable all color plane */ 1463 vga_set_atr(&softc->regs, 0x12, 0x0f); 1464 1465 } 1466 1467 static void 1468 vgatext_save_colormap(struct vgatext_softc *softc) 1469 { 1470 int i; 1471 1472 for (i = 0; i < VGA_ATR_NUM_PLT; i++) { 1473 softc->attrib_palette[i] = vga_get_atr(&softc->regs, i); 1474 } 1475 for (i = 0; i < VGA8_CMAP_ENTRIES; i++) { 1476 vga_get_cmap(&softc->regs, i, 1477 &softc->colormap[i].red, 1478 &softc->colormap[i].green, 1479 &softc->colormap[i].blue); 1480 } 1481 } 1482 1483 static void 1484 vgatext_restore_colormap(struct vgatext_softc *softc) 1485 { 1486 int i; 1487 1488 for (i = 0; i < VGA_ATR_NUM_PLT; i++) { 1489 vga_set_atr(&softc->regs, i, softc->attrib_palette[i]); 1490 } 1491 for (i = 0; i < VGA8_CMAP_ENTRIES; i++) { 1492 vga_put_cmap(&softc->regs, i, 1493 softc->colormap[i].red, 1494 softc->colormap[i].green, 1495 softc->colormap[i].blue); 1496 } 1497 } 1498 1499 /* 1500 * search the entries of the "reg" property for one which has the desired 1501 * combination of phys_hi bits and contains the desired address. 1502 * 1503 * This version searches a PCI-style "reg" property. It was prompted by 1504 * issues surrounding the presence or absence of an entry for the ROM: 1505 * (a) a transition problem with PowerPC Virtual Open Firmware 1506 * (b) uncertainty as to whether an entry will be included on a device 1507 * with ROM support (and so an "active" ROM base address register), 1508 * but no ROM actually installed. 1509 * 1510 * See the note below on vgatext_get_isa_reg_index for the reasons for 1511 * returning the offset. 1512 * 1513 * Note that this routine may not be fully general; it is intended for the 1514 * specific purpose of finding a couple of particular VGA reg entries and 1515 * may not be suitable for all reg-searching purposes. 1516 */ 1517 static int 1518 vgatext_get_pci_reg_index( 1519 dev_info_t *const devi, 1520 unsigned long himask, 1521 unsigned long hival, 1522 unsigned long addr, 1523 off_t *offset) 1524 { 1525 1526 int length, index; 1527 pci_regspec_t *reg; 1528 1529 if (ddi_getlongprop(DDI_DEV_T_ANY, devi, DDI_PROP_DONTPASS, 1530 "reg", (caddr_t)®, &length) != DDI_PROP_SUCCESS) { 1531 return (-1); 1532 } 1533 1534 for (index = 0; index < length / sizeof (pci_regspec_t); index++) { 1535 if ((reg[index].pci_phys_hi & himask) != hival) 1536 continue; 1537 if (reg[index].pci_size_hi != 0) 1538 continue; 1539 if (reg[index].pci_phys_mid != 0) 1540 continue; 1541 if (reg[index].pci_phys_low > addr) 1542 continue; 1543 if (reg[index].pci_phys_low + reg[index].pci_size_low <= addr) 1544 continue; 1545 1546 *offset = addr - reg[index].pci_phys_low; 1547 kmem_free(reg, (size_t)length); 1548 return (index); 1549 } 1550 kmem_free(reg, (size_t)length); 1551 1552 return (-1); 1553 } 1554 1555 /* 1556 * search the entries of the "reg" property for one which has the desired 1557 * combination of phys_hi bits and contains the desired address. 1558 * 1559 * This version searches a ISA-style "reg" property. It was prompted by 1560 * issues surrounding 8514/A support. By IEEE 1275 compatibility conventions, 1561 * 8514/A registers should have been added after all standard VGA registers. 1562 * Unfortunately, the Solaris/Intel device configuration framework 1563 * (a) lists the 8514/A registers before the video memory, and then 1564 * (b) also sorts the entries so that I/O entries come before memory 1565 * entries. 1566 * 1567 * It returns the "reg" index and offset into that register set. 1568 * The offset is needed because there exist (broken?) BIOSes that 1569 * report larger ranges enclosing the standard ranges. One reports 1570 * 0x3bf for 0x21 instead of 0x3c0 for 0x20, for instance. Using the 1571 * offset adjusts for this difference in the base of the register set. 1572 * 1573 * Note that this routine may not be fully general; it is intended for the 1574 * specific purpose of finding a couple of particular VGA reg entries and 1575 * may not be suitable for all reg-searching purposes. 1576 */ 1577 static int 1578 vgatext_get_isa_reg_index( 1579 dev_info_t *const devi, 1580 unsigned long hival, 1581 unsigned long addr, 1582 off_t *offset) 1583 { 1584 1585 int length, index; 1586 struct regspec *reg; 1587 1588 if (ddi_getlongprop(DDI_DEV_T_ANY, devi, DDI_PROP_DONTPASS, 1589 "reg", (caddr_t)®, &length) != DDI_PROP_SUCCESS) { 1590 return (-1); 1591 } 1592 1593 for (index = 0; index < length / sizeof (struct regspec); index++) { 1594 if (reg[index].regspec_bustype != hival) 1595 continue; 1596 if (reg[index].regspec_addr > addr) 1597 continue; 1598 if (reg[index].regspec_addr + reg[index].regspec_size <= addr) 1599 continue; 1600 1601 *offset = addr - reg[index].regspec_addr; 1602 kmem_free(reg, (size_t)length); 1603 return (index); 1604 } 1605 kmem_free(reg, (size_t)length); 1606 1607 return (-1); 1608 } 1609 1610 /* 1611 * If AGP cap pointer is successfully found, none-zero value is returned. 1612 * Otherwise 0 is returned. 1613 */ 1614 static off_t 1615 agp_master_cap_find(ddi_acc_handle_t acc_handle) 1616 { 1617 off_t nextcap; 1618 uint32_t ncapid; 1619 uint8_t value; 1620 1621 /* check if this device supports capibility pointer */ 1622 value = (uint8_t)(pci_config_get16(acc_handle, PCI_CONF_STAT) 1623 & PCI_CONF_CAP_MASK); 1624 1625 if (!value) 1626 return (0); 1627 /* get the offset of the first capability pointer from CAPPTR */ 1628 nextcap = (off_t)(pci_config_get8(acc_handle, AGP_CONF_CAPPTR)); 1629 1630 /* check AGP capability from the first capability pointer */ 1631 while (nextcap) { 1632 ncapid = pci_config_get32(acc_handle, nextcap); 1633 if ((ncapid & PCI_CONF_CAPID_MASK) 1634 == AGP_CAP_ID) /* find AGP cap */ 1635 break; 1636 1637 nextcap = (off_t)((ncapid & PCI_CONF_NCAPID_MASK) >> 8); 1638 } 1639 1640 return (nextcap); 1641 1642 } 1643 1644 /* 1645 * If i8xx device is successfully detected, 0 is returned. 1646 * Otherwise -1 is returned. 1647 */ 1648 static int 1649 detect_i8xx_device(agp_master_softc_t *master_softc) 1650 { 1651 1652 switch (master_softc->agpm_id) { 1653 case INTEL_IGD_810: 1654 case INTEL_IGD_810DC: 1655 case INTEL_IGD_810E: 1656 case INTEL_IGD_815: 1657 master_softc->agpm_dev_type = DEVICE_IS_I810; 1658 break; 1659 case INTEL_IGD_830M: 1660 case INTEL_IGD_845G: 1661 case INTEL_IGD_855GM: 1662 case INTEL_IGD_865G: 1663 master_softc->agpm_dev_type = DEVICE_IS_I830; 1664 break; 1665 default: /* unknown id */ 1666 return (-1); 1667 } 1668 1669 return (0); 1670 } 1671 1672 /* 1673 * If agp master is succssfully detected, 0 is returned. 1674 * Otherwise -1 is returned. 1675 */ 1676 static int 1677 detect_agp_devcice(agp_master_softc_t *master_softc) 1678 { 1679 off_t cap; 1680 1681 cap = agp_master_cap_find(master_softc->agpm_acc_hdl); 1682 if (cap) { 1683 master_softc->agpm_dev_type = DEVICE_IS_AGP; 1684 master_softc->agpm_data.agpm_acaptr = cap; 1685 return (0); 1686 } else { 1687 return (-1); 1688 } 1689 1690 } 1691 1692 /* 1693 * If agp master is successfully initialized, 0 is returned. 1694 * Otherwise -1 is returned. 1695 */ 1696 static int 1697 agp_master_init(struct vgatext_softc *softc) 1698 { 1699 dev_info_t *devi; 1700 int instance; 1701 int status; 1702 agp_master_softc_t *agp_master; 1703 uint32_t value; 1704 off_t reg_size; 1705 1706 1707 ASSERT(softc); 1708 agp_master = softc->agp_master; 1709 1710 devi = softc->devi; 1711 1712 instance = ddi_get_instance(devi); 1713 1714 status = pci_config_setup(devi, &agp_master->agpm_acc_hdl); 1715 1716 if (status != DDI_SUCCESS) { 1717 cmn_err(CE_WARN, "agp_master_init: pci_config_setup failed"); 1718 return (-1); 1719 } 1720 1721 agp_master->agpm_id = 1722 pci_config_get32(agp_master->agpm_acc_hdl, PCI_CONF_VENID); 1723 1724 if (!detect_i8xx_device(agp_master)) { 1725 /* map mmio register set */ 1726 status = ddi_regs_map_setup(devi, I8XX_MMIO_REGSET, 1727 &agp_master->agpm_data.agpm_gtt.gtt_mmio_base, 1728 0, 0, &i8xx_dev_access, 1729 &agp_master->agpm_data.agpm_gtt.gtt_mmio_handle); 1730 1731 if (status != DDI_SUCCESS) { 1732 cmn_err(CE_WARN, 1733 "agp_master_init: ddi_regs_map_setup failed"); 1734 agp_master_end(agp_master); 1735 return (-1); 1736 } 1737 /* get GTT range base offset */ 1738 agp_master->agpm_data.agpm_gtt.gtt_addr = 1739 agp_master->agpm_data.agpm_gtt.gtt_mmio_base + 1740 I8XX_PTE_OFFSET; 1741 /* get graphics memory size */ 1742 status = ddi_dev_regsize(devi, I8XX_FB_REGSET, 1743 ®_size); 1744 /* 1745 * if memory size is smaller than a certain value, it means 1746 * the register set number for graphics memory range might 1747 * be wrong 1748 */ 1749 if (status != DDI_SUCCESS || reg_size < 0x400000) { 1750 cmn_err(CE_WARN, 1751 "agp_master_init: ddi_dev_regsize error"); 1752 agp_master_end(agp_master); 1753 return (-1); 1754 } 1755 1756 agp_master->agpm_data.agpm_gtt.gtt_info.igd_apersize = 1757 BYTES2MB(reg_size); 1758 value = pci_config_get32(agp_master->agpm_acc_hdl, 1759 I8XX_CONF_GMADR); 1760 agp_master->agpm_data.agpm_gtt.gtt_info.igd_aperbase = 1761 value & GTT_BASE_MASK; 1762 agp_master->agpm_data.agpm_gtt.gtt_info.igd_devid = 1763 agp_master->agpm_id; 1764 } else if (detect_agp_devcice(agp_master)) { 1765 /* 1766 * non IGD or AGP devices, not error 1767 */ 1768 agp_master_end(agp_master); 1769 return (-1); 1770 } 1771 1772 /* create extra minor node for IGD or AGP device */ 1773 status = ddi_create_minor_node(softc->devi, AGPMASTER_NAME, 1774 S_IFCHR, INST2NODE2(instance), DDI_NT_AGP_MASTER, 0); 1775 1776 if (status != DDI_SUCCESS) { 1777 cmn_err(CE_WARN, 1778 "agp_master_init: create agpmaster node failed"); 1779 agp_master_end(agp_master); 1780 return (-1); 1781 } 1782 1783 return (0); 1784 } 1785 1786 /* 1787 * Minor node is not removed here, since vgatext_detach is responsible 1788 * for removing all nodes. 1789 */ 1790 static void 1791 agp_master_end(agp_master_softc_t *master_softc) 1792 { 1793 ASSERT(master_softc); 1794 1795 /* intel integrated device */ 1796 if ((master_softc->agpm_dev_type == DEVICE_IS_I810) || 1797 (master_softc->agpm_dev_type == DEVICE_IS_I830)) { 1798 if (master_softc->agpm_data.agpm_gtt.gtt_mmio_handle != NULL) { 1799 ddi_regs_map_free( 1800 &master_softc->agpm_data.agpm_gtt.gtt_mmio_handle); 1801 } 1802 } 1803 if (master_softc->agpm_acc_hdl != NULL) { 1804 pci_config_teardown(&master_softc->agpm_acc_hdl); 1805 } 1806 1807 bzero(master_softc, sizeof (agp_master_softc_t)); 1808 return; 1809 1810 } 1811 1812 /* 1813 * Please refer to GART and GTT entry format table in agpdefs.h for 1814 * intel GTT entry format. 1815 */ 1816 static int 1817 phys2entry(uint32_t type, uint32_t physaddr, uint32_t *entry) 1818 { 1819 uint32_t value; 1820 1821 switch (type) { 1822 case AGP_PHYSICAL: 1823 case AGP_NORMAL: 1824 value = (physaddr & GTT_PTE_MASK) | GTT_PTE_VALID; 1825 break; 1826 default: 1827 return (-1); 1828 } 1829 1830 *entry = value; 1831 1832 return (0); 1833 } 1834 1835 static int 1836 i8xx_add_to_gtt(gtt_impl_t *gtt, igd_gtt_seg_t seg) 1837 { 1838 int i; 1839 uint32_t *paddr; 1840 uint32_t entry; 1841 uint32_t maxpages; 1842 1843 maxpages = gtt->gtt_info.igd_apersize; 1844 maxpages = GTT_MB_TO_PAGES(maxpages); 1845 1846 paddr = seg.igs_phyaddr; 1847 1848 /* 1849 * check if gtt max pages reached 1850 */ 1851 if ((seg.igs_pgstart + seg.igs_npage) > maxpages) 1852 return (-1); 1853 1854 paddr = seg.igs_phyaddr; 1855 for (i = seg.igs_pgstart; i < (seg.igs_pgstart + seg.igs_npage); 1856 i++, paddr++) { 1857 if (phys2entry(seg.igs_type, *paddr, &entry)) 1858 return (-1); 1859 ddi_put32(gtt->gtt_mmio_handle, 1860 (uint32_t *)(gtt->gtt_addr + i * sizeof (uint32_t)), 1861 entry); 1862 } 1863 1864 return (0); 1865 } 1866 1867 static void 1868 i8xx_remove_from_gtt(gtt_impl_t *gtt, igd_gtt_seg_t seg) 1869 { 1870 int i; 1871 uint32_t maxpages; 1872 1873 maxpages = gtt->gtt_info.igd_apersize; 1874 maxpages = GTT_MB_TO_PAGES(maxpages); 1875 1876 /* 1877 * check if gtt max pages reached 1878 */ 1879 if ((seg.igs_pgstart + seg.igs_npage) > maxpages) 1880 return; 1881 1882 for (i = seg.igs_pgstart; i < (seg.igs_pgstart + seg.igs_npage); i++) { 1883 ddi_put32(gtt->gtt_mmio_handle, 1884 (uint32_t *)(gtt->gtt_addr + 1885 i * sizeof (uint32_t)), 1886 0); 1887 } 1888 } 1889