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