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 goto fail; 406 } 407 softc->fb_regno = vgatext_get_isa_reg_index(devi, 0, 408 VGA_MEM_ADDR, &mem_offset); 409 if (softc->fb_regno < 0) { 410 cmn_err(CE_WARN, 411 MYNAME ": can't find reg entry for memory"); 412 goto fail; 413 } 414 } else if (STREQ(parent_type, "pci") || STREQ(parent_type, "pciex")) { 415 reg_rnumber = vgatext_get_pci_reg_index(devi, 416 PCI_REG_ADDR_M|PCI_REG_REL_M, 417 PCI_ADDR_IO|PCI_RELOCAT_B, VGA_REG_ADDR, 418 ®_offset); 419 if (reg_rnumber < 0) { 420 cmn_err(CE_WARN, 421 MYNAME ": can't find reg entry for registers"); 422 goto fail; 423 } 424 softc->fb_regno = vgatext_get_pci_reg_index(devi, 425 PCI_REG_ADDR_M|PCI_REG_REL_M, 426 PCI_ADDR_MEM32|PCI_RELOCAT_B, VGA_MEM_ADDR, 427 &mem_offset); 428 if (softc->fb_regno < 0) { 429 cmn_err(CE_WARN, 430 MYNAME ": can't find reg entry for memory"); 431 goto fail; 432 } 433 softc->agp_master = (agp_master_softc_t *) 434 kmem_zalloc(sizeof (agp_master_softc_t), KM_SLEEP); 435 } else { 436 cmn_err(CE_WARN, MYNAME ": unknown parent type \"%s\".", 437 parent_type); 438 goto fail; 439 } 440 ddi_prop_free(parent_type); 441 parent_type = NULL; 442 443 error = ddi_regs_map_setup(devi, reg_rnumber, 444 (caddr_t *)&softc->regs.addr, reg_offset, VGA_REG_SIZE, 445 &dev_attr, &softc->regs.handle); 446 if (error != DDI_SUCCESS) 447 goto fail; 448 softc->regs.mapped = B_TRUE; 449 450 softc->fb_size = VGA_MEM_SIZE; 451 452 error = ddi_regs_map_setup(devi, softc->fb_regno, 453 (caddr_t *)&softc->fb.addr, 454 mem_offset, softc->fb_size, 455 &dev_attr, &softc->fb.handle); 456 if (error != DDI_SUCCESS) 457 goto fail; 458 softc->fb.mapped = B_TRUE; 459 460 if (ddi_get8(softc->regs.handle, 461 softc->regs.addr + VGA_MISC_R) & VGA_MISC_IOA_SEL) 462 softc->text_base = (caddr_t)softc->fb.addr + VGA_COLOR_BASE; 463 else 464 softc->text_base = (caddr_t)softc->fb.addr + VGA_MONO_BASE; 465 softc->current_base = softc->text_base; 466 467 (void) sprintf(buf, "text-%d", unit); 468 error = ddi_create_minor_node(devi, buf, S_IFCHR, 469 INST2NODE1(unit), DDI_NT_DISPLAY, NULL); 470 if (error != DDI_SUCCESS) 471 goto fail; 472 473 error = ddi_prop_create(makedevice(DDI_MAJOR_T_UNKNOWN, unit), 474 devi, DDI_PROP_CANSLEEP, DDI_KERNEL_IOCTL, NULL, 0); 475 if (error != DDI_SUCCESS) 476 goto fail; 477 478 if (ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_root_node(), 479 DDI_PROP_DONTPASS, "console", &cons) == DDI_SUCCESS) { 480 if (strcmp(cons, "graphics") == 0) { 481 happyface_boot = 1; 482 vgatext_silent = 1; 483 } 484 ddi_prop_free(cons); 485 } 486 487 /* only do this if not in graphics mode */ 488 if (vgatext_silent == 0) { 489 vgatext_init(softc); 490 vgatext_save_colormap(softc); 491 } 492 493 if (softc->agp_master != NULL) { /* is PCI */ 494 if (agp_master_init(softc) != 0) { /* unsuccessful */ 495 kmem_free(softc->agp_master, 496 sizeof (agp_master_softc_t)); 497 softc->agp_master = NULL; 498 499 } 500 } 501 502 return (DDI_SUCCESS); 503 504 fail: 505 if (parent_type != NULL) 506 ddi_prop_free(parent_type); 507 (void) vgatext_detach(devi, DDI_DETACH); 508 return (error); 509 } 510 511 static int 512 vgatext_detach(dev_info_t *devi, ddi_detach_cmd_t cmd) 513 { 514 int instance = ddi_get_instance(devi); 515 struct vgatext_softc *softc = getsoftc(instance); 516 517 518 switch (cmd) { 519 case DDI_DETACH: 520 if (softc->agp_master != NULL) { /* agp initiated */ 521 agp_master_end(softc->agp_master); 522 523 kmem_free(softc->agp_master, 524 sizeof (agp_master_softc_t)); 525 softc->agp_master = NULL; 526 527 } 528 529 if (softc->fb.mapped) 530 ddi_regs_map_free(&softc->fb.handle); 531 if (softc->regs.mapped) 532 ddi_regs_map_free(&softc->regs.handle); 533 ddi_remove_minor_node(devi, NULL); 534 (void) ddi_soft_state_free(vgatext_softc_head, instance); 535 return (DDI_SUCCESS); 536 537 default: 538 cmn_err(CE_WARN, "vgatext_detach: unknown cmd 0x%x\n", cmd); 539 return (DDI_FAILURE); 540 } 541 } 542 543 /*ARGSUSED*/ 544 static int 545 vgatext_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) 546 { 547 dev_t dev; 548 int error; 549 int instance; 550 struct vgatext_softc *softc; 551 552 error = DDI_SUCCESS; 553 554 dev = (dev_t)arg; 555 instance = DEV2INST(dev); 556 softc = getsoftc(instance); 557 558 switch (infocmd) { 559 case DDI_INFO_DEVT2DEVINFO: 560 if (softc == NULL || softc->devi == NULL) { 561 error = DDI_FAILURE; 562 } else { 563 *result = (void *) softc->devi; 564 error = DDI_SUCCESS; 565 } 566 break; 567 case DDI_INFO_DEVT2INSTANCE: 568 *result = (void *)(uintptr_t)instance; 569 error = DDI_SUCCESS; 570 break; 571 default: 572 error = DDI_FAILURE; 573 break; 574 } 575 return (error); 576 } 577 578 579 /*ARGSUSED*/ 580 static int 581 vgatext_open(dev_t *devp, int flag, int otyp, cred_t *cred) 582 { 583 struct vgatext_softc *softc = getsoftc(DEV2INST(*devp)); 584 585 if (softc == NULL || otyp == OTYP_BLK) 586 return (ENXIO); 587 588 return (0); 589 } 590 591 /*ARGSUSED*/ 592 static int 593 vgatext_close(dev_t devp, int flag, int otyp, cred_t *cred) 594 { 595 return (0); 596 } 597 598 /*ARGSUSED*/ 599 static int 600 vgatext_ioctl( 601 dev_t dev, 602 int cmd, 603 intptr_t data, 604 int mode, 605 cred_t *cred, 606 int *rval) 607 { 608 struct vgatext_softc *softc = getsoftc(DEV2INST(dev)); 609 static char kernel_only[] = "vgatext_ioctl: %s is a kernel only ioctl"; 610 int err; 611 int kd_mode; 612 613 switch (cmd) { 614 case KDSETMODE: 615 return (vgatext_kdsetmode(softc, (int)data)); 616 617 case KDGETMODE: 618 kd_mode = softc->mode; 619 if (ddi_copyout(&kd_mode, (void *)data, sizeof (int), mode)) 620 return (EFAULT); 621 break; 622 623 case VIS_GETIDENTIFIER: 624 if (ddi_copyout(&text_ident, (void *)data, 625 sizeof (struct vis_identifier), mode)) 626 return (EFAULT); 627 break; 628 629 case VIS_DEVINIT: 630 631 if (!(mode & FKIOCTL)) { 632 cmn_err(CE_CONT, kernel_only, "VIS_DEVINIT"); 633 return (ENXIO); 634 } 635 636 err = vgatext_devinit(softc, (struct vis_devinit *)data); 637 if (err != 0) { 638 cmn_err(CE_WARN, 639 "vgatext_ioctl: could not initialize console"); 640 return (err); 641 } 642 break; 643 644 case VIS_CONSCOPY: /* move */ 645 { 646 struct vis_conscopy pma; 647 648 if (ddi_copyin((void *)data, &pma, 649 sizeof (struct vis_conscopy), mode)) 650 return (EFAULT); 651 652 vgatext_cons_copy(softc, &pma); 653 break; 654 } 655 656 case VIS_CONSDISPLAY: /* display */ 657 { 658 struct vis_consdisplay display_request; 659 660 if (ddi_copyin((void *)data, &display_request, 661 sizeof (display_request), mode)) 662 return (EFAULT); 663 664 vgatext_cons_display(softc, &display_request); 665 break; 666 } 667 668 case VIS_CONSCURSOR: 669 { 670 struct vis_conscursor cursor_request; 671 672 if (ddi_copyin((void *)data, &cursor_request, 673 sizeof (cursor_request), mode)) 674 return (EFAULT); 675 676 vgatext_cons_cursor(softc, &cursor_request); 677 678 if (cursor_request.action == VIS_GET_CURSOR && 679 ddi_copyout(&cursor_request, (void *)data, 680 sizeof (cursor_request), mode)) 681 return (EFAULT); 682 break; 683 } 684 685 case VIS_GETCMAP: 686 case VIS_PUTCMAP: 687 case FBIOPUTCMAP: 688 case FBIOGETCMAP: 689 /* 690 * At the moment, text mode is not considered to have 691 * a color map. 692 */ 693 return (EINVAL); 694 695 case FBIOGATTR: 696 if (copyout(&vgatext_attr, (void *)data, 697 sizeof (struct fbgattr))) 698 return (EFAULT); 699 break; 700 701 case FBIOGTYPE: 702 if (copyout(&vgatext_attr.fbtype, (void *)data, 703 sizeof (struct fbtype))) 704 return (EFAULT); 705 break; 706 707 #if 0 708 case GLY_LD_GLYPH: 709 { 710 temstat_t *ap; 711 da_t da; 712 struct glyph g; 713 int size; 714 uchar_t *c; 715 716 if (ddi_copyin(arg, &g, sizeof (g), flag)) 717 return (EFAULT); 718 719 size = g.width * g.height; 720 c = kmem_alloc(size, KM_SLEEP); 721 722 if (ddi_copyin(g.raster, c, size, flag)) { 723 kmem_free(c, size); 724 return (EFAULT); 725 } 726 ap = (temstat_t *)something; 727 da.data = c; 728 da.width = g.width; 729 da.height = g.height; 730 da.col = g.x_dest; 731 da.row = g.y_dest; 732 ap->a_fp.f_ad_display(ap->a_private, &da); 733 kmem_free(c, size); 734 return (0); 735 } 736 #endif 737 case DEVICE_DETECT: 738 { 739 agp_master_softc_t *agp_master; 740 741 if (!(mode & FKIOCTL)) { 742 cmn_err(CE_CONT, kernel_only, "DEVICE_DETECT"); 743 return (ENXIO); 744 } 745 agp_master = softc->agp_master; 746 ASSERT(agp_master); 747 748 if (!agp_master) 749 return (EINVAL); 750 751 if (ddi_copyout(&agp_master->agpm_dev_type, 752 (void *)data, sizeof (int), mode)) 753 return (EFAULT); 754 break; 755 } 756 case I8XX_GET_INFO: 757 { 758 agp_master_softc_t *agp_master; 759 760 if (!(mode & FKIOCTL)) { 761 cmn_err(CE_CONT, kernel_only, "I8XX_GET_INFO"); 762 return (ENXIO); 763 } 764 agp_master = softc->agp_master; 765 ASSERT(agp_master); 766 767 if (!agp_master) 768 return (EINVAL); 769 ASSERT(IS_IGD(agp_master)); 770 771 if (!IS_IGD(agp_master)) 772 return (EINVAL); 773 774 if (ddi_copyout(&agp_master->agpm_data.agpm_gtt.gtt_info, 775 (void *)data, sizeof (igd_info_t), mode)) 776 return (EFAULT); 777 break; 778 } 779 case I810_SET_GTT_BASE: 780 { 781 uint32_t base; 782 uint32_t addr; 783 agp_master_softc_t *agp_master; 784 785 if (!(mode & FKIOCTL)) { 786 cmn_err(CE_CONT, kernel_only, "I8XX_SET_GTT_ADDR"); 787 return (ENXIO); 788 } 789 agp_master = softc->agp_master; 790 ASSERT(agp_master); 791 if (!agp_master) 792 return (EINVAL); 793 ASSERT(agp_master->agpm_dev_type == DEVICE_IS_I810); 794 795 if (agp_master->agpm_dev_type != DEVICE_IS_I810) 796 return (EINVAL); 797 798 if (ddi_copyin((void *)data, &base, sizeof (uint32_t), mode)) 799 return (EFAULT); 800 801 /* enables page table */ 802 addr = (base & GTT_BASE_MASK) | GTT_TABLE_VALID; 803 804 ddi_put32(agp_master->agpm_data.agpm_gtt.gtt_mmio_handle, 805 (uint32_t *)(agp_master->agpm_data.agpm_gtt.gtt_mmio_base + 806 I8XX_PGTBL_CTL), 807 addr); 808 break; 809 } 810 case I8XX_ADD2GTT: 811 { 812 igd_gtt_seg_t seg; 813 agp_master_softc_t *agp_master; 814 815 if (!(mode & FKIOCTL)) { 816 cmn_err(CE_CONT, kernel_only, "I8XX_ADD2GTT"); 817 return (ENXIO); 818 } 819 agp_master = softc->agp_master; 820 ASSERT(agp_master); 821 if (!agp_master) 822 return (EINVAL); 823 ASSERT(IS_IGD(agp_master)); 824 825 if (!IS_IGD(agp_master)) 826 return (EINVAL); 827 828 if (ddi_copyin((void *)data, &seg, 829 sizeof (igd_gtt_seg_t), mode)) 830 return (EFAULT); 831 832 if (i8xx_add_to_gtt(&agp_master->agpm_data.agpm_gtt, seg)) 833 return (EINVAL); 834 break; 835 } 836 case I8XX_REM_GTT: 837 { 838 igd_gtt_seg_t seg; 839 agp_master_softc_t *agp_master; 840 841 if (!(mode & FKIOCTL)) { 842 cmn_err(CE_CONT, kernel_only, "I8XX_REM_GTT"); 843 return (ENXIO); 844 } 845 agp_master = softc->agp_master; 846 ASSERT(agp_master); 847 if (!agp_master) 848 return (EINVAL); 849 ASSERT(IS_IGD(agp_master)); 850 851 if (!IS_IGD(agp_master)) 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(IS_IGD(agp_master)); 874 875 if (!IS_IGD(agp_master)) 876 return (EINVAL); 877 878 if (agp_master->agpm_dev_type == DEVICE_IS_I810) 879 ddi_put32( 880 agp_master->agpm_data.agpm_gtt.gtt_mmio_handle, 881 (uint32_t *) 882 (agp_master->agpm_data.agpm_gtt.gtt_mmio_base + 883 I8XX_PGTBL_CTL), 884 0); 885 /* 886 * may clear all gtt entries here for i830, 887 * but may not be necessary 888 */ 889 break; 890 } 891 case AGP_MASTER_GETINFO: 892 { 893 agp_info_t info; 894 uint32_t value; 895 off_t cap; 896 agp_master_softc_t *agp_master; 897 898 if (!(mode & FKIOCTL)) { 899 cmn_err(CE_CONT, kernel_only, "AGP_MASTER_GETINFO"); 900 return (ENXIO); 901 } 902 agp_master = softc->agp_master; 903 ASSERT(agp_master); 904 if (!agp_master) 905 return (EINVAL); 906 ASSERT(agp_master->agpm_dev_type == DEVICE_IS_AGP); 907 if (agp_master->agpm_dev_type != DEVICE_IS_AGP) 908 return (EINVAL); 909 910 ASSERT(agp_master->agpm_data.agpm_acaptr); 911 if (agp_master->agpm_data.agpm_acaptr == 0) 912 return (EINVAL); 913 914 cap = agp_master->agpm_data.agpm_acaptr; 915 value = pci_config_get32(agp_master->agpm_acc_hdl, cap); 916 info.agpi_version.agpv_major = (uint16_t)((value >> 20) & 0xf); 917 info.agpi_version.agpv_minor = (uint16_t)((value >> 16) & 0xf); 918 info.agpi_devid = agp_master->agpm_id; 919 info.agpi_mode = pci_config_get32( 920 agp_master->agpm_acc_hdl, cap + AGP_CONF_STATUS); 921 922 if (ddi_copyout(&info, (void *)data, 923 sizeof (agp_info_t), mode)) 924 return (EFAULT); 925 break; 926 } 927 case AGP_MASTER_SETCMD: 928 { 929 uint32_t command; 930 agp_master_softc_t *agp_master; 931 932 if (!(mode & FKIOCTL)) { 933 cmn_err(CE_CONT, kernel_only, "AGP_MASTER_SETCMD"); 934 return (ENXIO); 935 } 936 agp_master = softc->agp_master; 937 ASSERT(agp_master); 938 if (!agp_master) 939 return (EINVAL); 940 ASSERT(agp_master->agpm_dev_type == DEVICE_IS_AGP); 941 if (agp_master->agpm_dev_type != DEVICE_IS_AGP) 942 return (EINVAL); 943 944 ASSERT(agp_master->agpm_data.agpm_acaptr); 945 if (agp_master->agpm_data.agpm_acaptr == 0) 946 return (EINVAL); 947 948 if (ddi_copyin((void *)data, &command, 949 sizeof (uint32_t), mode)) 950 return (EFAULT); 951 952 pci_config_put32(agp_master->agpm_acc_hdl, 953 agp_master->agpm_data.agpm_acaptr + AGP_CONF_COMMAND, 954 command); 955 break; 956 957 } 958 default: 959 return (ENXIO); 960 } 961 return (0); 962 } 963 964 static int 965 vgatext_kdsetmode(struct vgatext_softc *softc, int mode) 966 { 967 int i; 968 969 if (mode == softc->mode) 970 return (0); 971 972 switch (mode) { 973 case KD_TEXT: 974 vgatext_init(softc); 975 for (i = 0; i < sizeof (softc->shadow); i++) { 976 softc->text_base[i] = softc->shadow[i]; 977 } 978 softc->current_base = softc->text_base; 979 if (softc->cursor.visible) { 980 vgatext_set_cursor(softc, 981 softc->cursor.row, softc->cursor.col); 982 } 983 vgatext_restore_colormap(softc); 984 break; 985 986 case KD_GRAPHICS: 987 if (vgatext_silent == 1) { 988 extern void progressbar_stop(void); 989 990 vgatext_silent = 0; 991 progressbar_stop(); 992 } 993 for (i = 0; i < sizeof (softc->shadow); i++) { 994 softc->shadow[i] = softc->text_base[i]; 995 } 996 softc->current_base = softc->shadow; 997 #if defined(USE_BORDERS) 998 vgatext_init_graphics(softc); 999 #endif 1000 break; 1001 1002 default: 1003 return (EINVAL); 1004 } 1005 softc->mode = mode; 1006 return (0); 1007 } 1008 1009 /*ARGSUSED*/ 1010 static int 1011 vgatext_devmap(dev_t dev, devmap_cookie_t dhp, offset_t off, size_t len, 1012 size_t *maplen, uint_t model) 1013 { 1014 struct vgatext_softc *softc; 1015 int err; 1016 size_t length; 1017 1018 1019 softc = getsoftc(DEV2INST(dev)); 1020 if (softc == NULL) { 1021 cmn_err(CE_WARN, "vgatext: Can't find softstate"); 1022 return (-1); 1023 } 1024 1025 if (!(off >= VGA_MMAP_FB_BASE && 1026 off < VGA_MMAP_FB_BASE + softc->fb_size)) { 1027 cmn_err(CE_WARN, "vgatext: Can't map offset 0x%llx", off); 1028 return (-1); 1029 } 1030 1031 if (off + len > VGA_MMAP_FB_BASE + softc->fb_size) 1032 length = VGA_MMAP_FB_BASE + softc->fb_size - off; 1033 else 1034 length = len; 1035 1036 if ((err = devmap_devmem_setup(dhp, softc->devi, NULL, softc->fb_regno, 1037 off - VGA_MMAP_FB_BASE, 1038 length, PROT_ALL, 0, &dev_attr)) < 0) { 1039 return (err); 1040 } 1041 1042 1043 *maplen = length; 1044 return (0); 1045 } 1046 1047 1048 static int 1049 vgatext_devinit(struct vgatext_softc *softc, struct vis_devinit *data) 1050 { 1051 /* initialize console instance */ 1052 data->version = VIS_CONS_REV; 1053 data->width = TEXT_COLS; 1054 data->height = TEXT_ROWS; 1055 data->linebytes = TEXT_COLS; 1056 data->depth = 4; 1057 data->mode = VIS_TEXT; 1058 data->polledio = &softc->polledio; 1059 1060 return (0); 1061 } 1062 1063 /* 1064 * display a string on the screen at (row, col) 1065 * assume it has been cropped to fit. 1066 */ 1067 1068 static void 1069 vgatext_cons_display(struct vgatext_softc *softc, struct vis_consdisplay *da) 1070 { 1071 unsigned char *string; 1072 int i; 1073 unsigned char attr; 1074 struct cgatext { 1075 unsigned char ch; 1076 unsigned char attr; 1077 }; 1078 struct cgatext *addr; 1079 1080 if (vgatext_silent) 1081 return; 1082 /* 1083 * Sanity checks. This is a last-ditch effort to avoid damage 1084 * from brokenness or maliciousness above. 1085 */ 1086 if (da->row < 0 || da->row >= TEXT_ROWS || 1087 da->col < 0 || da->col >= TEXT_COLS || 1088 da->col + da->width > TEXT_COLS) 1089 return; 1090 1091 /* 1092 * To be fully general, we should copyin the data. This is not 1093 * really relevant for this text-only driver, but a graphical driver 1094 * should support these ioctls from userland to enable simple 1095 * system startup graphics. 1096 */ 1097 attr = (solaris_color_to_pc_color[da->bg_color & 0xf] << 4) 1098 | solaris_color_to_pc_color[da->fg_color & 0xf]; 1099 string = da->data; 1100 addr = (struct cgatext *)softc->current_base 1101 + (da->row * TEXT_COLS + da->col); 1102 for (i = 0; i < da->width; i++) { 1103 addr->ch = string[i]; 1104 addr->attr = attr; 1105 addr++; 1106 } 1107 } 1108 1109 static void 1110 vgatext_polled_display( 1111 struct vis_polledio_arg *arg, 1112 struct vis_consdisplay *da) 1113 { 1114 vgatext_cons_display((struct vgatext_softc *)arg, da); 1115 } 1116 1117 /* 1118 * screen-to-screen copy 1119 */ 1120 1121 static void 1122 vgatext_cons_copy(struct vgatext_softc *softc, struct vis_conscopy *ma) 1123 { 1124 unsigned short *from; 1125 unsigned short *to; 1126 int cnt; 1127 screen_size_t chars_per_row; 1128 unsigned short *to_row_start; 1129 unsigned short *from_row_start; 1130 screen_size_t rows_to_move; 1131 unsigned short *base; 1132 1133 if (vgatext_silent) 1134 return; 1135 1136 /* 1137 * Sanity checks. Note that this is a last-ditch effort to avoid 1138 * damage caused by broken-ness or maliciousness above. 1139 */ 1140 if (ma->s_col < 0 || ma->s_col >= TEXT_COLS || 1141 ma->s_row < 0 || ma->s_row >= TEXT_ROWS || 1142 ma->e_col < 0 || ma->e_col >= TEXT_COLS || 1143 ma->e_row < 0 || ma->e_row >= TEXT_ROWS || 1144 ma->t_col < 0 || ma->t_col >= TEXT_COLS || 1145 ma->t_row < 0 || ma->t_row >= TEXT_ROWS || 1146 ma->s_col > ma->e_col || 1147 ma->s_row > ma->e_row) 1148 return; 1149 1150 /* 1151 * Remember we're going to copy shorts because each 1152 * character/attribute pair is 16 bits. 1153 */ 1154 chars_per_row = ma->e_col - ma->s_col + 1; 1155 rows_to_move = ma->e_row - ma->s_row + 1; 1156 1157 /* More sanity checks. */ 1158 if (ma->t_row + rows_to_move > TEXT_ROWS || 1159 ma->t_col + chars_per_row > TEXT_COLS) 1160 return; 1161 1162 base = (unsigned short *)softc->current_base; 1163 1164 to_row_start = base + ((ma->t_row * TEXT_COLS) + ma->t_col); 1165 from_row_start = base + ((ma->s_row * TEXT_COLS) + ma->s_col); 1166 1167 if (to_row_start < from_row_start) { 1168 while (rows_to_move-- > 0) { 1169 to = to_row_start; 1170 from = from_row_start; 1171 to_row_start += TEXT_COLS; 1172 from_row_start += TEXT_COLS; 1173 for (cnt = chars_per_row; cnt-- > 0; ) 1174 *to++ = *from++; 1175 } 1176 } else { 1177 /* 1178 * Offset to the end of the region and copy backwards. 1179 */ 1180 cnt = rows_to_move * TEXT_COLS + chars_per_row; 1181 to_row_start += cnt; 1182 from_row_start += cnt; 1183 1184 while (rows_to_move-- > 0) { 1185 to_row_start -= TEXT_COLS; 1186 from_row_start -= TEXT_COLS; 1187 to = to_row_start; 1188 from = from_row_start; 1189 for (cnt = chars_per_row; cnt-- > 0; ) 1190 *--to = *--from; 1191 } 1192 } 1193 } 1194 1195 static void 1196 vgatext_polled_copy( 1197 struct vis_polledio_arg *arg, 1198 struct vis_conscopy *ca) 1199 { 1200 vgatext_cons_copy((struct vgatext_softc *)arg, ca); 1201 } 1202 1203 1204 static void 1205 vgatext_cons_cursor(struct vgatext_softc *softc, struct vis_conscursor *ca) 1206 { 1207 if (vgatext_silent) 1208 return; 1209 1210 switch (ca->action) { 1211 case VIS_HIDE_CURSOR: 1212 softc->cursor.visible = B_FALSE; 1213 if (softc->current_base == softc->text_base) 1214 vgatext_hide_cursor(softc); 1215 break; 1216 case VIS_DISPLAY_CURSOR: 1217 /* 1218 * Sanity check. This is a last-ditch effort to avoid 1219 * damage from brokenness or maliciousness above. 1220 */ 1221 if (ca->col < 0 || ca->col >= TEXT_COLS || 1222 ca->row < 0 || ca->row >= TEXT_ROWS) 1223 return; 1224 1225 softc->cursor.visible = B_TRUE; 1226 softc->cursor.col = ca->col; 1227 softc->cursor.row = ca->row; 1228 if (softc->current_base == softc->text_base) 1229 vgatext_set_cursor(softc, ca->row, ca->col); 1230 break; 1231 case VIS_GET_CURSOR: 1232 if (softc->current_base == softc->text_base) { 1233 vgatext_get_cursor(softc, &ca->row, &ca->col); 1234 } 1235 break; 1236 } 1237 } 1238 1239 static void 1240 vgatext_polled_cursor( 1241 struct vis_polledio_arg *arg, 1242 struct vis_conscursor *ca) 1243 { 1244 vgatext_cons_cursor((struct vgatext_softc *)arg, ca); 1245 } 1246 1247 1248 1249 /*ARGSUSED*/ 1250 static void 1251 vgatext_hide_cursor(struct vgatext_softc *softc) 1252 { 1253 /* Nothing at present */ 1254 } 1255 1256 static void 1257 vgatext_set_cursor(struct vgatext_softc *softc, int row, int col) 1258 { 1259 short addr; 1260 1261 if (vgatext_silent) 1262 return; 1263 1264 addr = row * TEXT_COLS + col; 1265 1266 vga_set_crtc(&softc->regs, VGA_CRTC_CLAH, addr >> 8); 1267 vga_set_crtc(&softc->regs, VGA_CRTC_CLAL, addr & 0xff); 1268 } 1269 1270 static int vga_row, vga_col; 1271 1272 static void 1273 vgatext_get_cursor(struct vgatext_softc *softc, 1274 screen_pos_t *row, screen_pos_t *col) 1275 { 1276 short addr; 1277 1278 addr = (vga_get_crtc(&softc->regs, VGA_CRTC_CLAH) << 8) + 1279 vga_get_crtc(&softc->regs, VGA_CRTC_CLAL); 1280 1281 vga_row = *row = addr / TEXT_COLS; 1282 vga_col = *col = addr % TEXT_COLS; 1283 } 1284 1285 /* 1286 * This code is experimental. It's only enabled if console is 1287 * set to graphics, a preliminary implementation of happyface boot. 1288 */ 1289 static void 1290 vgatext_set_text(struct vgatext_softc *softc) 1291 { 1292 int i; 1293 1294 if (happyface_boot == 0) 1295 return; 1296 1297 /* we are in graphics mode, set to text 80X25 mode */ 1298 1299 /* set misc registers */ 1300 vga_set_reg(&softc->regs, VGA_MISC_W, VGA_MISC_TEXT); 1301 1302 /* set sequencer registers */ 1303 vga_set_seq(&softc->regs, VGA_SEQ_RST_SYN, 1304 (vga_get_seq(&softc->regs, VGA_SEQ_RST_SYN) & 1305 ~VGA_SEQ_RST_SYN_NO_SYNC_RESET)); 1306 for (i = 1; i < NUM_SEQ_REG; i++) { 1307 vga_set_seq(&softc->regs, i, VGA_SEQ_TEXT[i]); 1308 } 1309 vga_set_seq(&softc->regs, VGA_SEQ_RST_SYN, 1310 (vga_get_seq(&softc->regs, VGA_SEQ_RST_SYN) | 1311 VGA_SEQ_RST_SYN_NO_ASYNC_RESET | 1312 VGA_SEQ_RST_SYN_NO_SYNC_RESET)); 1313 1314 /* set crt controller registers */ 1315 vga_set_crtc(&softc->regs, VGA_CRTC_VRE, 1316 (vga_get_crtc(&softc->regs, VGA_CRTC_VRE) & 1317 ~VGA_CRTC_VRE_LOCK)); 1318 for (i = 0; i < NUM_CRTC_REG; i++) { 1319 vga_set_crtc(&softc->regs, i, VGA_CRTC_TEXT[i]); 1320 } 1321 1322 /* set graphics controller registers */ 1323 for (i = 0; i < NUM_GRC_REG; i++) { 1324 vga_set_grc(&softc->regs, i, VGA_GRC_TEXT[i]); 1325 } 1326 1327 /* set attribute registers */ 1328 for (i = 0; i < NUM_ATR_REG; i++) { 1329 vga_set_atr(&softc->regs, i, VGA_ATR_TEXT[i]); 1330 } 1331 1332 /* set palette */ 1333 for (i = 0; i < VGA_TEXT_CMAP_ENTRIES; i++) { 1334 vga_put_cmap(&softc->regs, i, VGA_TEXT_PALETTES[i][0] << 2, 1335 VGA_TEXT_PALETTES[i][1] << 2, 1336 VGA_TEXT_PALETTES[i][2] << 2); 1337 } 1338 for (i = VGA_TEXT_CMAP_ENTRIES; i < VGA8_CMAP_ENTRIES; i++) { 1339 vga_put_cmap(&softc->regs, i, 0, 0, 0); 1340 } 1341 1342 vgatext_save_colormap(softc); 1343 } 1344 1345 static void 1346 vgatext_init(struct vgatext_softc *softc) 1347 { 1348 unsigned char atr_mode; 1349 1350 atr_mode = vga_get_atr(&softc->regs, VGA_ATR_MODE); 1351 if (atr_mode & VGA_ATR_MODE_GRAPH) 1352 vgatext_set_text(softc); 1353 atr_mode = vga_get_atr(&softc->regs, VGA_ATR_MODE); 1354 atr_mode &= ~VGA_ATR_MODE_BLINK; 1355 atr_mode &= ~VGA_ATR_MODE_9WIDE; 1356 vga_set_atr(&softc->regs, VGA_ATR_MODE, atr_mode); 1357 #if defined(USE_BORDERS) 1358 vga_set_atr(&softc->regs, VGA_ATR_BDR_CLR, 1359 vga_get_atr(&softc->regs, VGA_BRIGHT_WHITE)); 1360 #else 1361 vga_set_atr(&softc->regs, VGA_ATR_BDR_CLR, 1362 vga_get_atr(&softc->regs, VGA_BLACK)); 1363 #endif 1364 vgatext_setfont(softc); /* need selectable font? */ 1365 } 1366 1367 #if defined(USE_BORDERS) 1368 static void 1369 vgatext_init_graphics(struct vgatext_softc *softc) 1370 { 1371 vga_set_atr(&softc->regs, VGA_ATR_BDR_CLR, 1372 vga_get_atr(&softc->regs, VGA_BLACK)); 1373 } 1374 #endif 1375 1376 static char vga_fontslot = 0; 1377 1378 static void 1379 vgatext_setfont(struct vgatext_softc *softc) 1380 { 1381 static uchar_t fsreg[8] = {0x0, 0x30, 0x5, 0x35, 0xa, 0x3a, 0xf, 0x3f}; 1382 1383 extern unsigned char *ENCODINGS[]; 1384 uchar_t *from; 1385 uchar_t volatile *to; 1386 int i, j, s; 1387 int bpc, f_offset; 1388 1389 /* Sync-reset the sequencer registers */ 1390 vga_set_seq(&softc->regs, 0x00, 0x01); 1391 /* 1392 * enable write to plane2, since fonts 1393 * could only be loaded into plane2 1394 */ 1395 vga_set_seq(&softc->regs, 0x02, 0x04); 1396 /* 1397 * sequentially access data in the bit map being 1398 * selected by MapMask register (index 0x02) 1399 */ 1400 vga_set_seq(&softc->regs, 0x04, 0x07); 1401 /* Sync-reset ended, and allow the sequencer to operate */ 1402 vga_set_seq(&softc->regs, 0x00, 0x03); 1403 1404 /* 1405 * select plane 2 on Read Mode 0 1406 */ 1407 vga_set_grc(&softc->regs, 0x04, 0x02); 1408 /* 1409 * system addresses sequentially access data, follow 1410 * Memory Mode register bit 2 in the sequencer 1411 */ 1412 vga_set_grc(&softc->regs, 0x05, 0x00); 1413 /* 1414 * set range of host memory addresses decoded by VGA 1415 * hardware -- A0000h-BFFFFh (128K region) 1416 */ 1417 vga_set_grc(&softc->regs, 0x06, 0x00); 1418 1419 /* 1420 * This assumes 8x16 characters, which yield the traditional 80x25 1421 * screen. It really should support other character heights. 1422 */ 1423 bpc = 16; 1424 s = vga_fontslot; 1425 f_offset = s * 8 * 1024; 1426 for (i = 0; i < 256; i++) { 1427 from = ENCODINGS[i]; 1428 to = (unsigned char *)softc->fb.addr + f_offset + i * 0x20; 1429 for (j = 0; j < bpc; j++) 1430 *to++ = *from++; 1431 } 1432 1433 /* Sync-reset the sequencer registers */ 1434 vga_set_seq(&softc->regs, 0x00, 0x01); 1435 /* enable write to plane 0 and 1 */ 1436 vga_set_seq(&softc->regs, 0x02, 0x03); 1437 /* 1438 * enable character map selection 1439 * and odd/even addressing 1440 */ 1441 vga_set_seq(&softc->regs, 0x04, 0x03); 1442 /* 1443 * select font map 1444 */ 1445 vga_set_seq(&softc->regs, 0x03, fsreg[s]); 1446 /* Sync-reset ended, and allow the sequencer to operate */ 1447 vga_set_seq(&softc->regs, 0x00, 0x03); 1448 1449 /* restore graphic registers */ 1450 1451 /* select plane 0 */ 1452 vga_set_grc(&softc->regs, 0x04, 0x00); 1453 /* enable odd/even addressing mode */ 1454 vga_set_grc(&softc->regs, 0x05, 0x10); 1455 /* 1456 * range of host memory addresses decoded by VGA 1457 * hardware -- B8000h-BFFFFh (32K region) 1458 */ 1459 vga_set_grc(&softc->regs, 0x06, 0x0e); 1460 /* enable all color plane */ 1461 vga_set_atr(&softc->regs, 0x12, 0x0f); 1462 1463 } 1464 1465 static void 1466 vgatext_save_colormap(struct vgatext_softc *softc) 1467 { 1468 int i; 1469 1470 for (i = 0; i < VGA_ATR_NUM_PLT; i++) { 1471 softc->attrib_palette[i] = vga_get_atr(&softc->regs, i); 1472 } 1473 for (i = 0; i < VGA8_CMAP_ENTRIES; i++) { 1474 vga_get_cmap(&softc->regs, i, 1475 &softc->colormap[i].red, 1476 &softc->colormap[i].green, 1477 &softc->colormap[i].blue); 1478 } 1479 } 1480 1481 static void 1482 vgatext_restore_colormap(struct vgatext_softc *softc) 1483 { 1484 int i; 1485 1486 for (i = 0; i < VGA_ATR_NUM_PLT; i++) { 1487 vga_set_atr(&softc->regs, i, softc->attrib_palette[i]); 1488 } 1489 for (i = 0; i < VGA8_CMAP_ENTRIES; i++) { 1490 vga_put_cmap(&softc->regs, i, 1491 softc->colormap[i].red, 1492 softc->colormap[i].green, 1493 softc->colormap[i].blue); 1494 } 1495 } 1496 1497 /* 1498 * search the entries of the "reg" property for one which has the desired 1499 * combination of phys_hi bits and contains the desired address. 1500 * 1501 * This version searches a PCI-style "reg" property. It was prompted by 1502 * issues surrounding the presence or absence of an entry for the ROM: 1503 * (a) a transition problem with PowerPC Virtual Open Firmware 1504 * (b) uncertainty as to whether an entry will be included on a device 1505 * with ROM support (and so an "active" ROM base address register), 1506 * but no ROM actually installed. 1507 * 1508 * See the note below on vgatext_get_isa_reg_index for the reasons for 1509 * returning the offset. 1510 * 1511 * Note that this routine may not be fully general; it is intended for the 1512 * specific purpose of finding a couple of particular VGA reg entries and 1513 * may not be suitable for all reg-searching purposes. 1514 */ 1515 static int 1516 vgatext_get_pci_reg_index( 1517 dev_info_t *const devi, 1518 unsigned long himask, 1519 unsigned long hival, 1520 unsigned long addr, 1521 off_t *offset) 1522 { 1523 1524 int length, index; 1525 pci_regspec_t *reg; 1526 1527 if (ddi_getlongprop(DDI_DEV_T_ANY, devi, DDI_PROP_DONTPASS, 1528 "reg", (caddr_t)®, &length) != DDI_PROP_SUCCESS) { 1529 return (-1); 1530 } 1531 1532 for (index = 0; index < length / sizeof (pci_regspec_t); index++) { 1533 if ((reg[index].pci_phys_hi & himask) != hival) 1534 continue; 1535 if (reg[index].pci_size_hi != 0) 1536 continue; 1537 if (reg[index].pci_phys_mid != 0) 1538 continue; 1539 if (reg[index].pci_phys_low > addr) 1540 continue; 1541 if (reg[index].pci_phys_low + reg[index].pci_size_low <= addr) 1542 continue; 1543 1544 *offset = addr - reg[index].pci_phys_low; 1545 kmem_free(reg, (size_t)length); 1546 return (index); 1547 } 1548 kmem_free(reg, (size_t)length); 1549 1550 return (-1); 1551 } 1552 1553 /* 1554 * search the entries of the "reg" property for one which has the desired 1555 * combination of phys_hi bits and contains the desired address. 1556 * 1557 * This version searches a ISA-style "reg" property. It was prompted by 1558 * issues surrounding 8514/A support. By IEEE 1275 compatibility conventions, 1559 * 8514/A registers should have been added after all standard VGA registers. 1560 * Unfortunately, the Solaris/Intel device configuration framework 1561 * (a) lists the 8514/A registers before the video memory, and then 1562 * (b) also sorts the entries so that I/O entries come before memory 1563 * entries. 1564 * 1565 * It returns the "reg" index and offset into that register set. 1566 * The offset is needed because there exist (broken?) BIOSes that 1567 * report larger ranges enclosing the standard ranges. One reports 1568 * 0x3bf for 0x21 instead of 0x3c0 for 0x20, for instance. Using the 1569 * offset adjusts for this difference in the base of the register set. 1570 * 1571 * Note that this routine may not be fully general; it is intended for the 1572 * specific purpose of finding a couple of particular VGA reg entries and 1573 * may not be suitable for all reg-searching purposes. 1574 */ 1575 static int 1576 vgatext_get_isa_reg_index( 1577 dev_info_t *const devi, 1578 unsigned long hival, 1579 unsigned long addr, 1580 off_t *offset) 1581 { 1582 1583 int length, index; 1584 struct regspec *reg; 1585 1586 if (ddi_getlongprop(DDI_DEV_T_ANY, devi, DDI_PROP_DONTPASS, 1587 "reg", (caddr_t)®, &length) != DDI_PROP_SUCCESS) { 1588 return (-1); 1589 } 1590 1591 for (index = 0; index < length / sizeof (struct regspec); index++) { 1592 if (reg[index].regspec_bustype != hival) 1593 continue; 1594 if (reg[index].regspec_addr > addr) 1595 continue; 1596 if (reg[index].regspec_addr + reg[index].regspec_size <= addr) 1597 continue; 1598 1599 *offset = addr - reg[index].regspec_addr; 1600 kmem_free(reg, (size_t)length); 1601 return (index); 1602 } 1603 kmem_free(reg, (size_t)length); 1604 1605 return (-1); 1606 } 1607 1608 /* 1609 * If AGP cap pointer is successfully found, none-zero value is returned. 1610 * Otherwise 0 is returned. 1611 */ 1612 static off_t 1613 agp_master_cap_find(ddi_acc_handle_t acc_handle) 1614 { 1615 off_t nextcap; 1616 uint32_t ncapid; 1617 uint8_t value; 1618 1619 /* check if this device supports capibility pointer */ 1620 value = (uint8_t)(pci_config_get16(acc_handle, PCI_CONF_STAT) 1621 & PCI_CONF_CAP_MASK); 1622 1623 if (!value) 1624 return (0); 1625 /* get the offset of the first capability pointer from CAPPTR */ 1626 nextcap = (off_t)(pci_config_get8(acc_handle, AGP_CONF_CAPPTR)); 1627 1628 /* check AGP capability from the first capability pointer */ 1629 while (nextcap) { 1630 ncapid = pci_config_get32(acc_handle, nextcap); 1631 if ((ncapid & PCI_CONF_CAPID_MASK) 1632 == AGP_CAP_ID) /* find AGP cap */ 1633 break; 1634 1635 nextcap = (off_t)((ncapid & PCI_CONF_NCAPID_MASK) >> 8); 1636 } 1637 1638 return (nextcap); 1639 1640 } 1641 1642 /* 1643 * If i8xx device is successfully detected, 0 is returned. 1644 * Otherwise -1 is returned. 1645 */ 1646 static int 1647 detect_i8xx_device(agp_master_softc_t *master_softc) 1648 { 1649 1650 switch (master_softc->agpm_id) { 1651 case INTEL_IGD_810: 1652 case INTEL_IGD_810DC: 1653 case INTEL_IGD_810E: 1654 case INTEL_IGD_815: 1655 master_softc->agpm_dev_type = DEVICE_IS_I810; 1656 break; 1657 case INTEL_IGD_830M: 1658 case INTEL_IGD_845G: 1659 case INTEL_IGD_855GM: 1660 case INTEL_IGD_865G: 1661 case INTEL_IGD_910: 1662 case INTEL_IGD_910M: 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 if ((agp_master->agpm_id == INTEL_IGD_910) || 1727 (agp_master->agpm_id == INTEL_IGD_910M)) { 1728 status = ddi_regs_map_setup(devi, I915_GTTADDR_BAR, 1729 &agp_master->agpm_data.agpm_gtt.gtt_mmio_base, 1730 0, 0, &i8xx_dev_access, 1731 &agp_master->agpm_data.agpm_gtt.gtt_mmio_handle); 1732 1733 } else { 1734 status = ddi_regs_map_setup(devi, I8XX_MMIO_REGSET, 1735 &agp_master->agpm_data.agpm_gtt.gtt_mmio_base, 1736 0, 0, &i8xx_dev_access, 1737 &agp_master->agpm_data.agpm_gtt.gtt_mmio_handle); 1738 } 1739 1740 if (status != DDI_SUCCESS) { 1741 cmn_err(CE_WARN, 1742 "agp_master_init: ddi_regs_map_setup failed"); 1743 agp_master_end(agp_master); 1744 return (-1); 1745 } 1746 /* get GTT range base offset */ 1747 if ((agp_master->agpm_id == INTEL_IGD_910) || 1748 (agp_master->agpm_id == INTEL_IGD_910M)) { 1749 agp_master->agpm_data.agpm_gtt.gtt_addr = 1750 agp_master->agpm_data.agpm_gtt.gtt_mmio_base; 1751 } else 1752 agp_master->agpm_data.agpm_gtt.gtt_addr = 1753 agp_master->agpm_data.agpm_gtt.gtt_mmio_base + 1754 I8XX_PTE_OFFSET; 1755 1756 /* get graphics memory size */ 1757 if ((agp_master->agpm_id == INTEL_IGD_910) || 1758 (agp_master->agpm_id == INTEL_IGD_910M)) { 1759 status = ddi_dev_regsize(devi, I915_FB_REGSET, 1760 ®_size); 1761 } else 1762 status = ddi_dev_regsize(devi, I8XX_FB_REGSET, 1763 ®_size); 1764 /* 1765 * if memory size is smaller than a certain value, it means 1766 * the register set number for graphics memory range might 1767 * be wrong 1768 */ 1769 if (status != DDI_SUCCESS || reg_size < 0x400000) { 1770 cmn_err(CE_WARN, 1771 "agp_master_init: ddi_dev_regsize error"); 1772 agp_master_end(agp_master); 1773 return (-1); 1774 } 1775 1776 agp_master->agpm_data.agpm_gtt.gtt_info.igd_apersize = 1777 BYTES2MB(reg_size); 1778 1779 if ((agp_master->agpm_id == INTEL_IGD_910) || 1780 (agp_master->agpm_id == INTEL_IGD_910M)) 1781 value = pci_config_get32(agp_master->agpm_acc_hdl, 1782 I915_CONF_GMADR); 1783 else 1784 value = pci_config_get32(agp_master->agpm_acc_hdl, 1785 I8XX_CONF_GMADR); 1786 agp_master->agpm_data.agpm_gtt.gtt_info.igd_aperbase = 1787 value & GTT_BASE_MASK; 1788 agp_master->agpm_data.agpm_gtt.gtt_info.igd_devid = 1789 agp_master->agpm_id; 1790 } else if (detect_agp_devcice(agp_master)) { 1791 /* 1792 * non IGD or AGP devices, not error 1793 */ 1794 agp_master_end(agp_master); 1795 return (-1); 1796 } 1797 1798 /* create extra minor node for IGD or AGP device */ 1799 status = ddi_create_minor_node(softc->devi, AGPMASTER_NAME, 1800 S_IFCHR, INST2NODE2(instance), DDI_NT_AGP_MASTER, 0); 1801 1802 if (status != DDI_SUCCESS) { 1803 cmn_err(CE_WARN, 1804 "agp_master_init: create agpmaster node failed"); 1805 agp_master_end(agp_master); 1806 return (-1); 1807 } 1808 1809 return (0); 1810 } 1811 1812 /* 1813 * Minor node is not removed here, since vgatext_detach is responsible 1814 * for removing all nodes. 1815 */ 1816 static void 1817 agp_master_end(agp_master_softc_t *master_softc) 1818 { 1819 ASSERT(master_softc); 1820 1821 /* intel integrated device */ 1822 if (IS_IGD(master_softc)) { 1823 if (master_softc->agpm_data.agpm_gtt.gtt_mmio_handle != NULL) { 1824 ddi_regs_map_free( 1825 &master_softc->agpm_data.agpm_gtt.gtt_mmio_handle); 1826 } 1827 } 1828 if (master_softc->agpm_acc_hdl != NULL) { 1829 pci_config_teardown(&master_softc->agpm_acc_hdl); 1830 } 1831 1832 bzero(master_softc, sizeof (agp_master_softc_t)); 1833 return; 1834 1835 } 1836 1837 /* 1838 * Please refer to GART and GTT entry format table in agpdefs.h for 1839 * intel GTT entry format. 1840 */ 1841 static int 1842 phys2entry(uint32_t type, uint32_t physaddr, uint32_t *entry) 1843 { 1844 uint32_t value; 1845 1846 switch (type) { 1847 case AGP_PHYSICAL: 1848 case AGP_NORMAL: 1849 value = (physaddr & GTT_PTE_MASK) | GTT_PTE_VALID; 1850 break; 1851 default: 1852 return (-1); 1853 } 1854 1855 *entry = value; 1856 1857 return (0); 1858 } 1859 1860 static int 1861 i8xx_add_to_gtt(gtt_impl_t *gtt, igd_gtt_seg_t seg) 1862 { 1863 int i; 1864 uint32_t *paddr; 1865 uint32_t entry; 1866 uint32_t maxpages; 1867 1868 maxpages = gtt->gtt_info.igd_apersize; 1869 maxpages = GTT_MB_TO_PAGES(maxpages); 1870 1871 paddr = seg.igs_phyaddr; 1872 1873 /* 1874 * check if gtt max pages reached 1875 */ 1876 if ((seg.igs_pgstart + seg.igs_npage) > maxpages) 1877 return (-1); 1878 1879 paddr = seg.igs_phyaddr; 1880 for (i = seg.igs_pgstart; i < (seg.igs_pgstart + seg.igs_npage); 1881 i++, paddr++) { 1882 if (phys2entry(seg.igs_type, *paddr, &entry)) 1883 return (-1); 1884 ddi_put32(gtt->gtt_mmio_handle, 1885 (uint32_t *)(gtt->gtt_addr + i * sizeof (uint32_t)), 1886 entry); 1887 } 1888 1889 return (0); 1890 } 1891 1892 static void 1893 i8xx_remove_from_gtt(gtt_impl_t *gtt, igd_gtt_seg_t seg) 1894 { 1895 int i; 1896 uint32_t maxpages; 1897 1898 maxpages = gtt->gtt_info.igd_apersize; 1899 maxpages = GTT_MB_TO_PAGES(maxpages); 1900 1901 /* 1902 * check if gtt max pages reached 1903 */ 1904 if ((seg.igs_pgstart + seg.igs_npage) > maxpages) 1905 return; 1906 1907 for (i = seg.igs_pgstart; i < (seg.igs_pgstart + seg.igs_npage); i++) { 1908 ddi_put32(gtt->gtt_mmio_handle, 1909 (uint32_t *)(gtt->gtt_addr + 1910 i * sizeof (uint32_t)), 1911 0); 1912 } 1913 } 1914