118}; 119 120#endif /* FB_INSTALL_CDEV */ 121 122static void 123gdc_identify(driver_t *driver, device_t parent) 124{ 125 BUS_ADD_CHILD(parent, ISA_ORDER_SPECULATIVE, DRIVER_NAME, 0); 126} 127 128static int 129gdcprobe(device_t dev) 130{ 131 int error; 132 133 /* Check isapnp ids */ 134 if (isa_get_vendorid(dev)) 135 return (ENXIO); 136 137 device_set_desc(dev, "Generic GDC"); 138 139 error = gdc_alloc_resource(dev); 140 if (error) 141 return (error); 142 143 error = gdc_probe_unit(device_get_unit(dev), 144 device_get_softc(dev), 145 device_get_flags(dev)); 146 147 gdc_release_resource(dev); 148 149 return (error); 150} 151 152static int 153gdc_attach(device_t dev) 154{ 155 gdc_softc_t *sc; 156 int error; 157 158 error = gdc_alloc_resource(dev); 159 if (error) 160 return (error); 161 162 sc = device_get_softc(dev); 163 error = gdc_attach_unit(device_get_unit(dev), 164 sc, 165 device_get_flags(dev)); 166 if (error) { 167 gdc_release_resource(dev); 168 return error; 169 } 170 171#ifdef FB_INSTALL_CDEV 172 /* attach a virtual frame buffer device */ 173 error = fb_attach(makedev(0, GDC_MKMINOR(device_get_unit(dev))), 174 sc->adp, &gdc_cdevsw); 175 if (error) { 176 gdc_release_resource(dev); 177 return error; 178 } 179#endif /* FB_INSTALL_CDEV */ 180 181 if (bootverbose) 182 (*vidsw[sc->adp->va_index]->diag)(sc->adp, bootverbose); 183 184 return 0; 185} 186 187static int 188gdc_probe_unit(int unit, gdc_softc_t *sc, int flags) 189{ 190 video_switch_t *sw; 191 192 sw = vid_get_switch(DRIVER_NAME); 193 if (sw == NULL) 194 return ENXIO; 195 return (*sw->probe)(unit, &sc->adp, NULL, flags); 196} 197 198static int 199gdc_attach_unit(int unit, gdc_softc_t *sc, int flags) 200{ 201 video_switch_t *sw; 202 203 sw = vid_get_switch(DRIVER_NAME); 204 if (sw == NULL) 205 return ENXIO; 206 return (*sw->init)(unit, sc->adp, flags); 207} 208 209 210static int 211gdc_alloc_resource(device_t dev) 212{ 213 int rid; 214 gdc_softc_t *sc; 215 216 sc = device_get_softc(dev); 217 218 /* TEXT GDC */ 219 rid = 0; 220 bus_set_resource(dev, SYS_RES_IOPORT, rid, TEXT_GDC, 1); 221 sc->res_tgdc = isa_alloc_resourcev(dev, SYS_RES_IOPORT, &rid, 222 gdc_iat, 8, RF_ACTIVE); 223 if (sc->res_tgdc == NULL) { 224 gdc_release_resource(dev); 225 return (ENXIO); 226 } 227 isa_load_resourcev(sc->res_tgdc, gdc_iat, 8); 228 229 /* GRAPHIC GDC */ 230 rid = 8; 231 bus_set_resource(dev, SYS_RES_IOPORT, rid, GRAPHIC_GDC, 1); 232 sc->res_ggdc = isa_alloc_resourcev(dev, SYS_RES_IOPORT, &rid, 233 gdc_iat, 8, RF_ACTIVE); 234 if (sc->res_ggdc == NULL) { 235 gdc_release_resource(dev); 236 return (ENXIO); 237 } 238 isa_load_resourcev(sc->res_ggdc, gdc_iat, 8); 239 240 /* EGC */ 241 rid = 16; 242 bus_set_resource(dev, SYS_RES_IOPORT, rid, 0x4a0, 1); 243 sc->res_egc = isa_alloc_resourcev(dev, SYS_RES_IOPORT, &rid, 244 gdc_iat, 8, RF_ACTIVE); 245 if (sc->res_egc == NULL) { 246 gdc_release_resource(dev); 247 return (ENXIO); 248 } 249 isa_load_resourcev(sc->res_egc, gdc_iat, 8); 250 251 /* PEGC */ 252 rid = 24; 253 bus_set_resource(dev, SYS_RES_IOPORT, rid, 0x9a0, 1); 254 sc->res_pegc = isa_alloc_resourcev(dev, SYS_RES_IOPORT, &rid, 255 gdc_iat, 8, RF_ACTIVE); 256 if (sc->res_pegc == NULL) { 257 gdc_release_resource(dev); 258 return (ENXIO); 259 } 260 isa_load_resourcev(sc->res_pegc, gdc_iat, 8); 261 262 /* CRTC/GRCG */ 263 rid = 32; 264 bus_set_resource(dev, SYS_RES_IOPORT, rid, 0x70, 1); 265 sc->res_grcg = isa_alloc_resourcev(dev, SYS_RES_IOPORT, &rid, 266 gdc_iat, 8, RF_ACTIVE); 267 if (sc->res_grcg == NULL) { 268 gdc_release_resource(dev); 269 return (ENXIO); 270 } 271 isa_load_resourcev(sc->res_grcg, gdc_iat, 8); 272 273 /* KCG */ 274 rid = 40; 275 bus_set_resource(dev, SYS_RES_IOPORT, rid, 0xa1, 1); 276 sc->res_kcg = isa_alloc_resourcev(dev, SYS_RES_IOPORT, &rid, 277 gdc_iat, 8, RF_ACTIVE); 278 if (sc->res_kcg == NULL) { 279 gdc_release_resource(dev); 280 return (ENXIO); 281 } 282 isa_load_resourcev(sc->res_kcg, gdc_iat, 8); 283 284 285 /* TEXT Memory */ 286 rid = 0; 287 sc->res_tmem = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, 288 0xa0000, 0xa4fff, 0x5000, RF_ACTIVE); 289 if (sc->res_tmem == NULL) { 290 gdc_release_resource(dev); 291 return (ENXIO); 292 } 293 294 /* GRAPHIC Memory */ 295 rid = 1; 296 sc->res_gmem1 = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, 297 0xa8000, 0xbffff, 0x18000, 298 RF_ACTIVE); 299 if (sc->res_gmem1 == NULL) { 300 gdc_release_resource(dev); 301 return (ENXIO); 302 } 303 rid = 2; 304 sc->res_gmem2 = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, 305 0xe0000, 0xe7fff, 0x8000, 306 RF_ACTIVE); 307 if (sc->res_gmem2 == NULL) { 308 gdc_release_resource(dev); 309 return (ENXIO); 310 } 311 312 return (0); 313} 314 315static int 316gdc_release_resource(device_t dev) 317{ 318 gdc_softc_t *sc; 319 320 sc = device_get_softc(dev); 321 322 if (sc->res_tgdc) 323 bus_release_resource(dev, SYS_RES_IOPORT, 0, sc->res_tgdc); 324 if (sc->res_ggdc) 325 bus_release_resource(dev, SYS_RES_IOPORT, 8, sc->res_ggdc); 326 if (sc->res_egc) 327 bus_release_resource(dev, SYS_RES_IOPORT, 16, sc->res_egc); 328 if (sc->res_pegc) 329 bus_release_resource(dev, SYS_RES_IOPORT, 24, sc->res_pegc); 330 if (sc->res_grcg) 331 bus_release_resource(dev, SYS_RES_IOPORT, 32, sc->res_grcg); 332 if (sc->res_kcg) 333 bus_release_resource(dev, SYS_RES_IOPORT, 40, sc->res_kcg); 334 335 if (sc->res_tmem) 336 bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->res_tmem); 337 if (sc->res_gmem1) 338 bus_release_resource(dev, SYS_RES_MEMORY, 1, sc->res_gmem1); 339 if (sc->res_gmem2) 340 bus_release_resource(dev, SYS_RES_MEMORY, 2, sc->res_gmem2); 341 342 return (0); 343} 344 345/* cdev driver functions */ 346 347#ifdef FB_INSTALL_CDEV 348 349static int 350gdcopen(dev_t dev, int flag, int mode, struct thread *td) 351{ 352 gdc_softc_t *sc; 353 354 sc = GDC_SOFTC(GDC_UNIT(dev)); 355 if (sc == NULL) 356 return ENXIO; 357 if (mode & (O_CREAT | O_APPEND | O_TRUNC)) 358 return ENODEV; 359 360 return genfbopen(&sc->gensc, sc->adp, flag, mode, td); 361} 362 363static int 364gdcclose(dev_t dev, int flag, int mode, struct thread *td) 365{ 366 gdc_softc_t *sc; 367 368 sc = GDC_SOFTC(GDC_UNIT(dev)); 369 return genfbclose(&sc->gensc, sc->adp, flag, mode, td); 370} 371 372static int 373gdcread(dev_t dev, struct uio *uio, int flag) 374{ 375 gdc_softc_t *sc; 376 377 sc = GDC_SOFTC(GDC_UNIT(dev)); 378 return genfbread(&sc->gensc, sc->adp, uio, flag); 379} 380 381static int 382gdcwrite(dev_t dev, struct uio *uio, int flag) 383{ 384 gdc_softc_t *sc; 385 386 sc = GDC_SOFTC(GDC_UNIT(dev)); 387 return genfbread(&sc->gensc, sc->adp, uio, flag); 388} 389 390static int 391gdcioctl(dev_t dev, u_long cmd, caddr_t arg, int flag, struct thread *td) 392{ 393 gdc_softc_t *sc; 394 395 sc = GDC_SOFTC(GDC_UNIT(dev)); 396 return genfbioctl(&sc->gensc, sc->adp, cmd, arg, flag, td); 397} 398 399static int 400gdcmmap(dev_t dev, vm_offset_t offset, vm_offset_t *paddr, int prot) 401{ 402 gdc_softc_t *sc; 403 404 sc = GDC_SOFTC(GDC_UNIT(dev)); 405 return genfbmmap(&sc->gensc, sc->adp, offset, paddr, prot); 406} 407 408#endif /* FB_INSTALL_CDEV */ 409 410static device_method_t gdc_methods[] = { 411 DEVMETHOD(device_identify, gdc_identify), 412 DEVMETHOD(device_probe, gdcprobe), 413 DEVMETHOD(device_attach, gdc_attach), 414 { 0, 0 } 415}; 416 417static driver_t gdcdriver = { 418 DRIVER_NAME, 419 gdc_methods, 420 sizeof(gdc_softc_t), 421}; 422 423DRIVER_MODULE(gdc, isa, gdcdriver, gdc_devclass, 0, 0); 424 425/* LOW-LEVEL */ 426 427 428#include <pc98/pc98/30line.h> 429 430#define TEXT_BUF_BASE 0x000a0000 431#define TEXT_BUF_SIZE 0x00008000 432#define GRAPHICS_BUF_BASE 0x000a8000 433#define GRAPHICS_BUF_SIZE 0x00040000 434#define VIDEO_BUF_BASE 0x000a0000 435#define VIDEO_BUF_SIZE 0x00048000 436 437#define probe_done(adp) ((adp)->va_flags & V_ADP_PROBED) 438#define init_done(adp) ((adp)->va_flags & V_ADP_INITIALIZED) 439#define config_done(adp) ((adp)->va_flags & V_ADP_REGISTERED) 440 441/* 442 * NOTE: `va_window' should have a virtual address, but is initialized 443 * with a physical address in the following table, they will be 444 * converted at run-time. 445 */ 446static video_adapter_t adapter_init_value[] = { 447 { 0, 448 KD_PC98, "gdc", /* va_type, va_name */ 449 0, 0, /* va_unit, va_minor */ 450 V_ADP_COLOR | V_ADP_MODECHANGE | V_ADP_BORDER, 451 TEXT_GDC, 16, TEXT_GDC, /* va_io*, XXX */ 452 VIDEO_BUF_BASE, VIDEO_BUF_SIZE, /* va_mem* */ 453 TEXT_BUF_BASE, TEXT_BUF_SIZE, TEXT_BUF_SIZE, 0, /* va_window* */ 454 0, 0, /* va_buffer, va_buffer_size */ 455 0, M_PC98_80x25, 0, /* va_*mode* */ 456 }, 457}; 458 459static video_adapter_t biosadapter[1]; 460 461/* video driver declarations */ 462static int gdc_configure(int flags); 463static int gdc_err(video_adapter_t *adp, ...); 464static vi_probe_t gdc_probe; 465static vi_init_t gdc_init; 466static vi_get_info_t gdc_get_info; 467static vi_query_mode_t gdc_query_mode; 468static vi_set_mode_t gdc_set_mode; 469static vi_set_border_t gdc_set_border; 470static vi_save_state_t gdc_save_state; 471static vi_load_state_t gdc_load_state; 472static vi_read_hw_cursor_t gdc_read_hw_cursor; 473static vi_set_hw_cursor_t gdc_set_hw_cursor; 474static vi_set_hw_cursor_shape_t gdc_set_hw_cursor_shape; 475static vi_blank_display_t gdc_blank_display; 476static vi_mmap_t gdc_mmap_buf; 477static vi_ioctl_t gdc_dev_ioctl; 478static vi_clear_t gdc_clear; 479static vi_fill_rect_t gdc_fill_rect; 480static vi_bitblt_t gdc_bitblt; 481static vi_diag_t gdc_diag; 482static vi_save_palette_t gdc_save_palette; 483static vi_load_palette_t gdc_load_palette; 484static vi_set_win_org_t gdc_set_origin; 485 486static video_switch_t gdcvidsw = { 487 gdc_probe, 488 gdc_init, 489 gdc_get_info, 490 gdc_query_mode, 491 gdc_set_mode, 492 (vi_save_font_t *)gdc_err, 493 (vi_load_font_t *)gdc_err, 494 (vi_show_font_t *)gdc_err, 495 gdc_save_palette, 496 gdc_load_palette, 497 gdc_set_border, 498 gdc_save_state, 499 gdc_load_state, 500 gdc_set_origin, 501 gdc_read_hw_cursor, 502 gdc_set_hw_cursor, 503 gdc_set_hw_cursor_shape, 504 gdc_blank_display, 505 gdc_mmap_buf, 506 gdc_dev_ioctl, 507 gdc_clear, 508 gdc_fill_rect, 509 gdc_bitblt, 510 (int (*)(void))gdc_err, 511 (int (*)(void))gdc_err, 512 gdc_diag, 513}; 514 515VIDEO_DRIVER(gdc, gdcvidsw, gdc_configure); 516 517/* GDC BIOS standard video modes */ 518#define EOT (-1) 519#define NA (-2) 520 521static video_info_t bios_vmode[] = { 522 { M_PC98_80x25, V_INFO_COLOR, 80, 25, 8, 16, 4, 1, 523 TEXT_BUF_BASE, TEXT_BUF_SIZE, TEXT_BUF_SIZE, 0, 0, V_INFO_MM_TEXT }, 524#ifdef LINE30 525 { M_PC98_80x30, V_INFO_COLOR, 80, 30, 8, 16, 4, 1, 526 TEXT_BUF_BASE, TEXT_BUF_SIZE, TEXT_BUF_SIZE, 0, 0, V_INFO_MM_TEXT }, 527#endif 528#ifndef GDC_NOGRAPHICS 529 { M_PC98_EGC640x400, V_INFO_COLOR | V_INFO_GRAPHICS, 530 640, 400, 8, 16, 4, 4, 531 GRAPHICS_BUF_BASE, GRAPHICS_BUF_SIZE, GRAPHICS_BUF_SIZE, 0, 0, 532 V_INFO_MM_OTHER }, 533 { M_PC98_PEGC640x400, V_INFO_COLOR | V_INFO_GRAPHICS | V_INFO_VESA, 534 640, 400, 8, 16, 8, 1, 535 GRAPHICS_BUF_BASE, 0x00008000, 0x00008000, 0, 0, 536 V_INFO_MM_PACKED, 1 }, 537#ifdef LINE30 538 { M_PC98_PEGC640x480, V_INFO_COLOR | V_INFO_GRAPHICS | V_INFO_VESA, 539 640, 480, 8, 16, 8, 1, 540 GRAPHICS_BUF_BASE, 0x00008000, 0x00008000, 0, 0, 541 V_INFO_MM_PACKED, 1 }, 542#endif 543#endif 544 { EOT }, 545}; 546 547static int gdc_init_done = FALSE; 548 549/* local functions */ 550static int map_gen_mode_num(int type, int color, int mode); 551static int probe_adapters(void); 552 553#define prologue(adp, flag, err) \ 554 if (!gdc_init_done || !((adp)->va_flags & (flag))) \ 555 return (err) 556 557/* a backdoor for the console driver */ 558static int 559gdc_configure(int flags) 560{ 561 probe_adapters(); 562 biosadapter[0].va_flags |= V_ADP_INITIALIZED; 563 if (!config_done(&biosadapter[0])) { 564 if (vid_register(&biosadapter[0]) < 0) 565 return 1; 566 biosadapter[0].va_flags |= V_ADP_REGISTERED; 567 } 568 569 return 1; 570} 571 572/* local subroutines */ 573 574/* map a generic video mode to a known mode number */ 575static int 576map_gen_mode_num(int type, int color, int mode) 577{ 578 static struct { 579 int from; 580 int to; 581 } mode_map[] = { 582 { M_TEXT_80x25, M_PC98_80x25, }, 583#ifdef LINE30 584 { M_TEXT_80x30, M_PC98_80x30, }, 585#endif 586 }; 587 int i; 588 589 for (i = 0; i < sizeof(mode_map)/sizeof(mode_map[0]); ++i) { 590 if (mode_map[i].from == mode) 591 return mode_map[i].to; 592 } 593 return mode; 594} 595 596static int 597verify_adapter(video_adapter_t *adp) 598{ 599#ifndef GDC_NOGRAPHICS 600 int i; 601 602 if (PC98_SYSTEM_PARAMETER(0x45c) & 0x40) { /* PEGC exists */ 603 adp->va_flags |= V_ADP_VESA; /* XXX */ 604 } else { 605 for (i = 0; bios_vmode[i].vi_mode != EOT; ++i) { 606 if (bios_vmode[i].vi_flags & V_INFO_VESA) 607 bios_vmode[i].vi_mode = NA; 608 } 609 } 610#endif 611 return 0; 612} 613 614/* probe video adapters and return the number of detected adapters */ 615static int 616probe_adapters(void) 617{ 618 video_info_t info; 619 620 /* do this test only once */ 621 if (gdc_init_done) 622 return 1; 623 gdc_init_done = TRUE; 624 625 biosadapter[0] = adapter_init_value[0]; 626 biosadapter[0].va_flags |= V_ADP_PROBED; 627 biosadapter[0].va_mode = 628 biosadapter[0].va_initial_mode = biosadapter[0].va_initial_bios_mode; 629 630 if ((PC98_SYSTEM_PARAMETER(0x597) & 0x80) || 631 (PC98_SYSTEM_PARAMETER(0x458) & 0x80)) { 632 gdc_FH = (inb(0x9a8) & 1) ? _31KHZ : _24KHZ; 633 } else { 634 gdc_FH = _24KHZ; 635 } 636 637 gdc_get_info(&biosadapter[0], biosadapter[0].va_initial_mode, &info); 638 initialize_gdc(T25_G400, info.vi_flags & V_INFO_GRAPHICS); 639 640 biosadapter[0].va_window = BIOS_PADDRTOVADDR(info.vi_window); 641 biosadapter[0].va_window_size = info.vi_window_size; 642 biosadapter[0].va_window_gran = info.vi_window_gran; 643 biosadapter[0].va_buffer = 0; 644 biosadapter[0].va_buffer_size = 0; 645 if (info.vi_flags & V_INFO_GRAPHICS) { 646 switch (info.vi_depth/info.vi_planes) { 647 case 1: 648 biosadapter[0].va_line_width = info.vi_width/8; 649 break; 650 case 2: 651 biosadapter[0].va_line_width = info.vi_width/4; 652 break; 653 case 4: 654 biosadapter[0].va_line_width = info.vi_width/2; 655 break; 656 case 8: 657 default: /* shouldn't happen */ 658 biosadapter[0].va_line_width = info.vi_width; 659 break; 660 } 661 } else { 662 biosadapter[0].va_line_width = info.vi_width; 663 } 664 bcopy(&info, &biosadapter[0].va_info, sizeof(info)); 665 666 verify_adapter(&biosadapter[0]); 667 668 return 1; 669} 670 671static void master_gdc_cmd(unsigned int cmd) 672{ 673 while ( (inb(TEXT_GDC) & 2) != 0); 674 outb(TEXT_GDC+2, cmd); 675} 676 677static void master_gdc_prm(unsigned int pmtr) 678{ 679 while ( (inb(TEXT_GDC) & 2) != 0); 680 outb(TEXT_GDC, pmtr); 681} 682 683static void master_gdc_word_prm(unsigned int wpmtr) 684{ 685 master_gdc_prm(wpmtr & 0x00ff); 686 master_gdc_prm((wpmtr >> 8) & 0x00ff); 687} 688 689#ifdef LINE30 690static void master_gdc_fifo_empty(void) 691{ 692 while ( (inb(TEXT_GDC) & 4) == 0); 693} 694#endif 695 696static void master_gdc_wait_vsync(void) 697{ 698 while ( (inb(TEXT_GDC) & 0x20) != 0); 699 while ( (inb(TEXT_GDC) & 0x20) == 0); 700} 701 702static void gdc_cmd(unsigned int cmd) 703{ 704 while ( (inb(GRAPHIC_GDC) & 2) != 0); 705 outb( GRAPHIC_GDC+2, cmd); 706} 707 708#ifdef LINE30 709static void gdc_prm(unsigned int pmtr) 710{ 711 while ( (inb(GRAPHIC_GDC) & 2) != 0); 712 outb( GRAPHIC_GDC, pmtr); 713} 714 715static void gdc_word_prm(unsigned int wpmtr) 716{ 717 gdc_prm(wpmtr & 0x00ff); 718 gdc_prm((wpmtr >> 8) & 0x00ff); 719} 720 721static void gdc_fifo_empty(void) 722{ 723 while ( (inb(GRAPHIC_GDC) & 0x04) == 0); 724} 725#endif 726 727static void gdc_wait_vsync(void) 728{ 729 while ( (inb(GRAPHIC_GDC) & 0x20) != 0); 730 while ( (inb(GRAPHIC_GDC) & 0x20) == 0); 731} 732 733#ifdef LINE30 734static int check_gdc_clock(void) 735{ 736 if ((inb(IO_SYSPORT) & 0x80) == 0){ 737 return _5MHZ; 738 } else { 739 return _2_5MHZ; 740 } 741} 742#endif 743 744static void initialize_gdc(unsigned int mode, int isGraph) 745{ 746#ifdef LINE30 747 /* start 30line initialize */ 748 int m_mode, s_mode, gdc_clock, hsync_clock; 749 750 gdc_clock = check_gdc_clock(); 751 m_mode = (mode == T25_G400) ? _25L : _30L; 752 s_mode = 2*mode+gdc_clock; 753 gdc_INFO = m_mode; 754 755 master_gdc_wait_vsync(); 756 757 if ((PC98_SYSTEM_PARAMETER(0x597) & 0x80) || 758 (PC98_SYSTEM_PARAMETER(0x458) & 0x80)) { 759 if (PC98_SYSTEM_PARAMETER(0x481) & 0x08) { 760 hsync_clock = (m_mode == _25L) ? gdc_FH : _31KHZ; 761 outb(0x9a8, (hsync_clock == _31KHZ) ? 1 : 0); 762 } else { 763 hsync_clock = gdc_FH; 764 } 765 } else { 766 hsync_clock = _24KHZ; 767 } 768 769 if ((gdc_clock == _2_5MHZ) && 770 (slave_param[hsync_clock][s_mode][GDC_LF] > 400)) { 771 outb(0x6a, 0x83); 772 outb(0x6a, 0x85); 773 gdc_clock = _5MHZ; 774 s_mode = 2*mode+gdc_clock; 775 } 776 777 master_gdc_cmd(_GDC_RESET); 778 master_gdc_cmd(_GDC_MASTER); 779 gdc_cmd(_GDC_RESET); 780 gdc_cmd(_GDC_SLAVE); 781 782 /* GDC Master */ 783 master_gdc_cmd(_GDC_SYNC); 784 master_gdc_prm(0x00); /* flush less */ /* text & graph */ 785 master_gdc_prm(master_param[hsync_clock][m_mode][GDC_CR]); 786 master_gdc_word_prm(((master_param[hsync_clock][m_mode][GDC_HFP] << 10) 787 + (master_param[hsync_clock][m_mode][GDC_VS] << 5) 788 + master_param[hsync_clock][m_mode][GDC_HS])); 789 master_gdc_prm(master_param[hsync_clock][m_mode][GDC_HBP]); 790 master_gdc_prm(master_param[hsync_clock][m_mode][GDC_VFP]); 791 master_gdc_word_prm(((master_param[hsync_clock][m_mode][GDC_VBP] << 10) 792 + (master_param[hsync_clock][m_mode][GDC_LF]))); 793 master_gdc_fifo_empty(); 794 master_gdc_cmd(_GDC_PITCH); 795 master_gdc_prm(MasterPCH); 796 master_gdc_fifo_empty(); 797 798 /* GDC slave */ 799 gdc_cmd(_GDC_SYNC); 800 gdc_prm(0x06); 801 gdc_prm(slave_param[hsync_clock][s_mode][GDC_CR]); 802 gdc_word_prm((slave_param[hsync_clock][s_mode][GDC_HFP] << 10) 803 + (slave_param[hsync_clock][s_mode][GDC_VS] << 5) 804 + (slave_param[hsync_clock][s_mode][GDC_HS])); 805 gdc_prm(slave_param[hsync_clock][s_mode][GDC_HBP]); 806 gdc_prm(slave_param[hsync_clock][s_mode][GDC_VFP]); 807 gdc_word_prm((slave_param[hsync_clock][s_mode][GDC_VBP] << 10) 808 + (slave_param[hsync_clock][s_mode][GDC_LF])); 809 gdc_fifo_empty(); 810 gdc_cmd(_GDC_PITCH); 811 gdc_prm(SlavePCH[gdc_clock]); 812 gdc_fifo_empty(); 813 814 /* set Master GDC scroll param */ 815 master_gdc_wait_vsync(); 816 master_gdc_wait_vsync(); 817 master_gdc_wait_vsync(); 818 master_gdc_cmd(_GDC_SCROLL); 819 master_gdc_word_prm(0); 820 master_gdc_word_prm((master_param[hsync_clock][m_mode][GDC_LF] << 4) 821 | 0x0000); 822 master_gdc_fifo_empty(); 823 824 /* set Slave GDC scroll param */ 825 gdc_wait_vsync(); 826 gdc_cmd(_GDC_SCROLL); 827 gdc_word_prm(0); 828 if (gdc_clock == _5MHZ) { 829 gdc_word_prm((SlaveScrlLF[mode] << 4) | 0x4000); 830 } else { 831 gdc_word_prm(SlaveScrlLF[mode] << 4); 832 } 833 gdc_fifo_empty(); 834 835 gdc_word_prm(0); 836 if (gdc_clock == _5MHZ) { 837 gdc_word_prm((SlaveScrlLF[mode] << 4) | 0x4000); 838 } else { 839 gdc_word_prm(SlaveScrlLF[mode] << 4); 840 } 841 gdc_fifo_empty(); 842 843 /* sync start */ 844 gdc_cmd(isGraph ? _GDC_START : _GDC_STOP); 845 846 gdc_wait_vsync(); 847 gdc_wait_vsync(); 848 gdc_wait_vsync(); 849 850 master_gdc_cmd(isGraph ? _GDC_STOP : _GDC_START); 851#else 852 master_gdc_wait_vsync(); 853 master_gdc_cmd(isGraph ? _GDC_STOP : _GDC_START); /* text */ 854 gdc_wait_vsync(); 855 gdc_cmd(isGraph ? _GDC_START : _GDC_STOP); /* graphics */ 856#endif 857} 858 859#ifndef GDC_NOGRAPHICS 860static u_char b_palette[] = { 861 /* R G B */ 862 0x00, 0x00, 0x00, /* 0 */ 863 0x00, 0x00, 0x7f, /* 1 */ 864 0x7f, 0x00, 0x00, /* 2 */ 865 0x7f, 0x00, 0x7f, /* 3 */ 866 0x00, 0x7f, 0x00, /* 4 */ 867 0x00, 0x7f, 0x7f, /* 5 */ 868 0x7f, 0x7f, 0x00, /* 6 */ 869 0x7f, 0x7f, 0x7f, /* 7 */ 870 0x40, 0x40, 0x40, /* 8 */ 871 0x00, 0x00, 0xff, /* 9 */ 872 0xff, 0x00, 0x00, /* 10 */ 873 0xff, 0x00, 0xff, /* 11 */ 874 0x00, 0xff, 0x00, /* 12 */ 875 0x00, 0xff, 0xff, /* 13 */ 876 0xff, 0xff, 0x00, /* 14 */ 877 0xff, 0xff, 0xff, /* 15 */ 878}; 879#endif 880 881static int 882gdc_load_palette(video_adapter_t *adp, u_char *palette) 883{ 884#ifndef GDC_NOGRAPHICS 885 int i; 886 887 if (adp->va_info.vi_flags & V_INFO_VESA) { 888 gdc_wait_vsync(); 889 for (i = 0; i < 256; ++i) { 890 outb(0xa8, i); 891 outb(0xac, *palette++); /* R */ 892 outb(0xaa, *palette++); /* G */ 893 outb(0xae, *palette++); /* B */ 894 } 895 } else { 896 /* 897 * XXX - Even though PC-98 text color is independent of palette, 898 * we should set palette in text mode. 899 * Because the background color of text mode is palette 0's one. 900 */ 901 outb(0x6a, 1); /* 16 colors mode */ 902 bcopy(palette, b_palette, sizeof(b_palette)); 903 904 gdc_wait_vsync(); 905 for (i = 0; i < 16; ++i) { 906 outb(0xa8, i); 907 outb(0xac, *palette++ >> 4); /* R */ 908 outb(0xaa, *palette++ >> 4); /* G */ 909 outb(0xae, *palette++ >> 4); /* B */ 910 } 911 } 912#endif 913 return 0; 914} 915 916static int 917gdc_save_palette(video_adapter_t *adp, u_char *palette) 918{ 919#ifndef GDC_NOGRAPHICS 920 int i; 921 922 if (adp->va_info.vi_flags & V_INFO_VESA) { 923 for (i = 0; i < 256; ++i) { 924 outb(0xa8, i); 925 *palette++ = inb(0xac); /* R */ 926 *palette++ = inb(0xaa); /* G */ 927 *palette++ = inb(0xae); /* B */ 928 } 929 } else { 930 bcopy(b_palette, palette, sizeof(b_palette)); 931 } 932#endif 933 return 0; 934} 935 936static int 937gdc_set_origin(video_adapter_t *adp, off_t offset) 938{ 939#ifndef GDC_NOGRAPHICS 940 if (adp->va_info.vi_flags & V_INFO_VESA) { 941 writew(BIOS_PADDRTOVADDR(0x000e0004), offset >> 15); 942 } 943#endif 944 return 0; 945} 946 947/* entry points */ 948 949static int 950gdc_err(video_adapter_t *adp, ...) 951{ 952 return ENODEV; 953} 954 955static int 956gdc_probe(int unit, video_adapter_t **adpp, void *arg, int flags) 957{ 958 probe_adapters(); 959 if (unit >= 1) 960 return ENXIO; 961 962 *adpp = &biosadapter[unit]; 963 964 return 0; 965} 966 967static int 968gdc_init(int unit, video_adapter_t *adp, int flags) 969{ 970 if ((unit >= 1) || (adp == NULL) || !probe_done(adp)) 971 return ENXIO; 972 973 if (!init_done(adp)) { 974 /* nothing to do really... */ 975 adp->va_flags |= V_ADP_INITIALIZED; 976 } 977 978 if (!config_done(adp)) { 979 if (vid_register(adp) < 0) 980 return ENXIO; 981 adp->va_flags |= V_ADP_REGISTERED; 982 } 983 984 return 0; 985} 986 987/* 988 * get_info(): 989 * Return the video_info structure of the requested video mode. 990 */ 991static int 992gdc_get_info(video_adapter_t *adp, int mode, video_info_t *info) 993{ 994 int i; 995 996 if (!gdc_init_done) 997 return ENXIO; 998 999 mode = map_gen_mode_num(adp->va_type, adp->va_flags & V_ADP_COLOR, mode); 1000 for (i = 0; bios_vmode[i].vi_mode != EOT; ++i) { 1001 if (bios_vmode[i].vi_mode == NA) 1002 continue; 1003 if (mode == bios_vmode[i].vi_mode) { 1004 *info = bios_vmode[i]; 1005 info->vi_buffer_size = info->vi_window_size*info->vi_planes; 1006 return 0; 1007 } 1008 } 1009 return EINVAL; 1010} 1011 1012/* 1013 * query_mode(): 1014 * Find a video mode matching the requested parameters. 1015 * Fields filled with 0 are considered "don't care" fields and 1016 * match any modes. 1017 */ 1018static int 1019gdc_query_mode(video_adapter_t *adp, video_info_t *info) 1020{ 1021 int i; 1022 1023 if (!gdc_init_done) 1024 return ENXIO; 1025 1026 for (i = 0; bios_vmode[i].vi_mode != EOT; ++i) { 1027 if (bios_vmode[i].vi_mode == NA) 1028 continue; 1029 1030 if ((info->vi_width != 0) 1031 && (info->vi_width != bios_vmode[i].vi_width)) 1032 continue; 1033 if ((info->vi_height != 0) 1034 && (info->vi_height != bios_vmode[i].vi_height)) 1035 continue; 1036 if ((info->vi_cwidth != 0) 1037 && (info->vi_cwidth != bios_vmode[i].vi_cwidth)) 1038 continue; 1039 if ((info->vi_cheight != 0) 1040 && (info->vi_cheight != bios_vmode[i].vi_cheight)) 1041 continue; 1042 if ((info->vi_depth != 0) 1043 && (info->vi_depth != bios_vmode[i].vi_depth)) 1044 continue; 1045 if ((info->vi_planes != 0) 1046 && (info->vi_planes != bios_vmode[i].vi_planes)) 1047 continue; 1048 /* XXX: should check pixel format, memory model */ 1049 if ((info->vi_flags != 0) 1050 && (info->vi_flags != bios_vmode[i].vi_flags)) 1051 continue; 1052 1053 /* verify if this mode is supported on this adapter */ 1054 if (gdc_get_info(adp, bios_vmode[i].vi_mode, info)) 1055 continue; 1056 return 0; 1057 } 1058 return ENODEV; 1059} 1060 1061/* 1062 * set_mode(): 1063 * Change the video mode. 1064 */ 1065static int 1066gdc_set_mode(video_adapter_t *adp, int mode) 1067{ 1068 video_info_t info; 1069 1070 prologue(adp, V_ADP_MODECHANGE, ENODEV); 1071 1072 mode = map_gen_mode_num(adp->va_type, 1073 adp->va_flags & V_ADP_COLOR, mode); 1074 if (gdc_get_info(adp, mode, &info)) 1075 return EINVAL; 1076 1077 switch (info.vi_mode) { 1078#ifndef GDC_NOGRAPHICS 1079 case M_PC98_PEGC640x480: /* PEGC 640x480 */ 1080 initialize_gdc(T30_G480, info.vi_flags & V_INFO_GRAPHICS); 1081 break; 1082 case M_PC98_PEGC640x400: /* PEGC 640x400 */ 1083 case M_PC98_EGC640x400: /* EGC GRAPHICS */ 1084#endif 1085 case M_PC98_80x25: /* VGA TEXT */ 1086 initialize_gdc(T25_G400, info.vi_flags & V_INFO_GRAPHICS); 1087 break; 1088 case M_PC98_80x30: /* VGA TEXT */ 1089 initialize_gdc(T30_G400, info.vi_flags & V_INFO_GRAPHICS); 1090 break; 1091 default: 1092 break; 1093 } 1094 1095#ifndef GDC_NOGRAPHICS 1096 if (info.vi_flags & V_INFO_VESA) { 1097 outb(0x6a, 0x07); /* enable mode F/F change */ 1098 outb(0x6a, 0x21); /* enhanced graphics */ 1099 if (info.vi_height > 400) 1100 outb(0x6a, 0x69); /* 800 lines */ 1101 writeb(BIOS_PADDRTOVADDR(0x000e0100), 0); /* packed pixel */ 1102 } else { 1103 if (adp->va_flags & V_ADP_VESA) { 1104 outb(0x6a, 0x07); /* enable mode F/F change */ 1105 outb(0x6a, 0x20); /* normal graphics */ 1106 outb(0x6a, 0x68); /* 400 lines */ 1107 } 1108 outb(0x6a, 1); /* 16 colors */ 1109 } 1110#endif 1111 1112 adp->va_mode = mode; 1113 adp->va_flags &= ~V_ADP_COLOR; 1114 adp->va_flags |= 1115 (info.vi_flags & V_INFO_COLOR) ? V_ADP_COLOR : 0; 1116#if 0 1117 adp->va_crtc_addr = 1118 (adp->va_flags & V_ADP_COLOR) ? COLOR_CRTC : MONO_CRTC; 1119#endif 1120 adp->va_window = BIOS_PADDRTOVADDR(info.vi_window); 1121 adp->va_window_size = info.vi_window_size; 1122 adp->va_window_gran = info.vi_window_gran; 1123 if (info.vi_buffer_size == 0) { 1124 adp->va_buffer = 0; 1125 adp->va_buffer_size = 0; 1126 } else { 1127 adp->va_buffer = BIOS_PADDRTOVADDR(info.vi_buffer); 1128 adp->va_buffer_size = info.vi_buffer_size; 1129 } 1130 if (info.vi_flags & V_INFO_GRAPHICS) { 1131 switch (info.vi_depth/info.vi_planes) { 1132 case 1: 1133 adp->va_line_width = info.vi_width/8; 1134 break; 1135 case 2: 1136 adp->va_line_width = info.vi_width/4; 1137 break; 1138 case 4: 1139 adp->va_line_width = info.vi_width/2; 1140 break; 1141 case 8: 1142 default: /* shouldn't happen */ 1143 adp->va_line_width = info.vi_width; 1144 break; 1145 } 1146 } else { 1147 adp->va_line_width = info.vi_width; 1148 } 1149 bcopy(&info, &adp->va_info, sizeof(info)); 1150 1151 /* move hardware cursor out of the way */ 1152 (*vidsw[adp->va_index]->set_hw_cursor)(adp, -1, -1); 1153 1154 return 0; 1155} 1156 1157/* 1158 * set_border(): 1159 * Change the border color. 1160 */ 1161static int 1162gdc_set_border(video_adapter_t *adp, int color) 1163{ 1164 outb(0x6c, color << 4); 1165 return 0; 1166} 1167 1168/* 1169 * save_state(): 1170 * Read video card register values. 1171 */ 1172static int 1173gdc_save_state(video_adapter_t *adp, void *p, size_t size) 1174{ 1175 return ENODEV; 1176} 1177 1178/* 1179 * load_state(): 1180 * Set video card registers at once. 1181 */ 1182static int 1183gdc_load_state(video_adapter_t *adp, void *p) 1184{ 1185 return ENODEV; 1186} 1187 1188/* 1189 * read_hw_cursor(): 1190 * Read the position of the hardware text cursor. 1191 */ 1192static int 1193gdc_read_hw_cursor(video_adapter_t *adp, int *col, int *row) 1194{ 1195 u_int16_t off; 1196 int s; 1197 1198 if (!gdc_init_done) 1199 return ENXIO; 1200 1201 if (adp->va_info.vi_flags & V_INFO_GRAPHICS) 1202 return ENODEV; 1203 1204 s = spltty(); 1205 master_gdc_cmd(0xe0); /* _GDC_CSRR */ 1206 while((inb(TEXT_GDC + 0) & 0x1) == 0) {} /* GDC wait */ 1207 off = inb(TEXT_GDC + 2); /* EADl */ 1208 off |= (inb(TEXT_GDC + 2) << 8); /* EADh */ 1209 inb(TEXT_GDC + 2); /* dummy */ 1210 inb(TEXT_GDC + 2); /* dummy */ 1211 inb(TEXT_GDC + 2); /* dummy */ 1212 splx(s); 1213 1214 if (off >= ROW*COL) 1215 off = 0; 1216 *row = off / adp->va_info.vi_width; 1217 *col = off % adp->va_info.vi_width; 1218 1219 return 0; 1220} 1221 1222/* 1223 * set_hw_cursor(): 1224 * Move the hardware text cursor. If col and row are both -1, 1225 * the cursor won't be shown. 1226 */ 1227static int 1228gdc_set_hw_cursor(video_adapter_t *adp, int col, int row) 1229{ 1230 u_int16_t off; 1231 int s; 1232 1233 if (!gdc_init_done) 1234 return ENXIO; 1235 1236 if ((col == -1) && (row == -1)) { 1237 off = -1; 1238 } else { 1239 if (adp->va_info.vi_flags & V_INFO_GRAPHICS) 1240 return ENODEV; 1241 off = row*adp->va_info.vi_width + col; 1242 } 1243 1244 s = spltty(); 1245 master_gdc_cmd(0x49); /* _GDC_CSRW */ 1246 master_gdc_word_prm(off); 1247 splx(s); 1248 1249 return 0; 1250} 1251 1252/* 1253 * set_hw_cursor_shape(): 1254 * Change the shape of the hardware text cursor. If the height is zero 1255 * or negative, the cursor won't be shown. 1256 */ 1257static int 1258gdc_set_hw_cursor_shape(video_adapter_t *adp, int base, int height, 1259 int celsize, int blink) 1260{ 1261 int start; 1262 int end; 1263 int s; 1264 1265 if (!gdc_init_done) 1266 return ENXIO; 1267 1268 start = celsize - (base + height); 1269 end = celsize - base - 1; 1270 1271#if 0 1272 /* 1273 * muPD7220 GDC has anomaly that if end == celsize - 1 then start 1274 * must be 0, otherwise the cursor won't be correctly shown 1275 * in the first row in the screen. We shall set end to celsize - 2; 1276 * if end == celsize -1 && start > 0. XXX 1277 */ 1278 if ((end == celsize - 1) && (start > 0) && (start < end)) 1279 --end; 1280#endif 1281 1282 s = spltty(); 1283 master_gdc_cmd(0x4b); /* _GDC_CSRFORM */ 1284 master_gdc_prm(((height > 0) ? 0x80 : 0) /* cursor on/off */ 1285 | ((celsize - 1) & 0x1f)); /* cel size */ 1286 master_gdc_word_prm(((end & 0x1f) << 11) /* end line */ 1287 | (12 << 6) /* blink rate */ 1288 | (blink ? 0 : 0x20) /* blink on/off */ 1289 | (start & 0x1f)); /* start line */ 1290 splx(s); 1291 1292 return 0; 1293} 1294 1295/* 1296 * blank_display() 1297 * Put the display in power save/power off mode. 1298 */ 1299static int 1300gdc_blank_display(video_adapter_t *adp, int mode) 1301{ 1302 int s; 1303 static int standby = 0; 1304 1305 if (!gdc_init_done) 1306 return ENXIO; 1307 1308 s = splhigh(); 1309 switch (mode) { 1310 case V_DISPLAY_SUSPEND: 1311 case V_DISPLAY_STAND_BY: 1312 outb(0x09a2, 0x80 | 0x40); /* V/H-SYNC mask */ 1313 if (inb(0x09a2) == (0x80 | 0x40)) 1314 standby = 1; 1315 /* FALLTHROUGH */ 1316 1317 case V_DISPLAY_BLANK: 1318 if (epson_machine_id == 0x20) { 1319 outb(0x43f, 0x42); 1320 outb(0xc17, inb(0xc17) & ~0x08); /* turn off side light */ 1321 outb(0xc16, inb(0xc16) & ~0x02); /* turn off back light */ 1322 outb(0x43f, 0x40); 1323 } else { 1324 while (!(inb(TEXT_GDC) & 0x20)) /* V-SYNC wait */ 1325 ; 1326 outb(TEXT_GDC + 8, 0x0e); /* DISP off */ 1327 } 1328 break; 1329 1330 case V_DISPLAY_ON: 1331 if (epson_machine_id == 0x20) { 1332 outb(0x43f, 0x42); 1333 outb(0xc17, inb(0xc17) | 0x08); 1334 outb(0xc16, inb(0xc16) | 0x02); 1335 outb(0x43f, 0x40); 1336 } else { 1337 while (!(inb(TEXT_GDC) & 0x20)) /* V-SYNC wait */ 1338 ; 1339 outb(TEXT_GDC + 8, 0x0f); /* DISP on */ 1340 } 1341 if (standby) { 1342 outb(0x09a2, 0x00); /* V/H-SYNC unmask */ 1343 standby = 0; 1344 } 1345 break; 1346 } 1347 splx(s); 1348 return 0; 1349} 1350 1351/* 1352 * mmap(): 1353 * Mmap frame buffer. 1354 */ 1355static int 1356gdc_mmap_buf(video_adapter_t *adp, vm_offset_t offset, vm_offset_t *paddr, 1357 int prot) 1358{ 1359 /* FIXME: is this correct? XXX */ 1360 if (offset > VIDEO_BUF_SIZE - PAGE_SIZE) 1361 return -1; 1362 *paddr = adp->va_info.vi_window + offset; 1363 return 0; 1364} 1365 1366static int 1367gdc_clear(video_adapter_t *adp) 1368{ 1369 /* FIXME */ 1370 return ENODEV; 1371} 1372 1373static int 1374gdc_fill_rect(video_adapter_t *adp, int val, int x, int y, int cx, int cy) 1375{ 1376 return ENODEV; 1377} 1378 1379static int 1380gdc_bitblt(video_adapter_t *adp,...) 1381{ 1382 /* FIXME */ 1383 return ENODEV; 1384} 1385 1386static int 1387gdc_dev_ioctl(video_adapter_t *adp, u_long cmd, caddr_t arg) 1388{ 1389 switch (cmd) { 1390 case FBIO_GETWINORG: /* get frame buffer window origin */ 1391 *(u_int *)arg = 0; 1392 return 0; 1393 1394 case FBIO_SETWINORG: /* set frame buffer window origin */ 1395 case FBIO_SETDISPSTART: /* set display start address */ 1396 case FBIO_SETLINEWIDTH: /* set scan line length in pixel */ 1397 case FBIO_GETPALETTE: /* get color palette */ 1398 case FBIO_SETPALETTE: /* set color palette */ 1399 case FBIOGETCMAP: /* get color palette */ 1400 case FBIOPUTCMAP: /* set color palette */ 1401 return ENODEV; 1402 1403 case FBIOGTYPE: /* get frame buffer type info. */ 1404 ((struct fbtype *)arg)->fb_type = fb_type(adp->va_type); 1405 ((struct fbtype *)arg)->fb_height = adp->va_info.vi_height; 1406 ((struct fbtype *)arg)->fb_width = adp->va_info.vi_width; 1407 ((struct fbtype *)arg)->fb_depth = adp->va_info.vi_depth; 1408 if ((adp->va_info.vi_depth <= 1) || (adp->va_info.vi_depth > 8)) 1409 ((struct fbtype *)arg)->fb_cmsize = 0; 1410 else 1411 ((struct fbtype *)arg)->fb_cmsize = 1 << adp->va_info.vi_depth; 1412 ((struct fbtype *)arg)->fb_size = adp->va_buffer_size; 1413 return 0; 1414 1415 default: 1416 return fb_commonioctl(adp, cmd, arg); 1417 } 1418} 1419 1420/* 1421 * diag(): 1422 * Print some information about the video adapter and video modes, 1423 * with requested level of details. 1424 */ 1425static int 1426gdc_diag(video_adapter_t *adp, int level) 1427{ 1428#if FB_DEBUG > 1 1429 int i; 1430#endif 1431 1432 if (!gdc_init_done) 1433 return ENXIO; 1434 1435 fb_dump_adp_info(DRIVER_NAME, adp, level); 1436 1437#if FB_DEBUG > 1 1438 for (i = 0; bios_vmode[i].vi_mode != EOT; ++i) { 1439 if (bios_vmode[i].vi_mode == NA) 1440 continue; 1441 if (get_mode_param(bios_vmode[i].vi_mode) == NULL) 1442 continue; 1443 fb_dump_mode_info(DRIVER_NAME, adp, &bios_vmode[i], level); 1444 } 1445#endif 1446 1447 return 0; 1448}
| 113}; 114 115#endif /* FB_INSTALL_CDEV */ 116 117static void 118gdc_identify(driver_t *driver, device_t parent) 119{ 120 BUS_ADD_CHILD(parent, ISA_ORDER_SPECULATIVE, DRIVER_NAME, 0); 121} 122 123static int 124gdcprobe(device_t dev) 125{ 126 int error; 127 128 /* Check isapnp ids */ 129 if (isa_get_vendorid(dev)) 130 return (ENXIO); 131 132 device_set_desc(dev, "Generic GDC"); 133 134 error = gdc_alloc_resource(dev); 135 if (error) 136 return (error); 137 138 error = gdc_probe_unit(device_get_unit(dev), 139 device_get_softc(dev), 140 device_get_flags(dev)); 141 142 gdc_release_resource(dev); 143 144 return (error); 145} 146 147static int 148gdc_attach(device_t dev) 149{ 150 gdc_softc_t *sc; 151 int error; 152 153 error = gdc_alloc_resource(dev); 154 if (error) 155 return (error); 156 157 sc = device_get_softc(dev); 158 error = gdc_attach_unit(device_get_unit(dev), 159 sc, 160 device_get_flags(dev)); 161 if (error) { 162 gdc_release_resource(dev); 163 return error; 164 } 165 166#ifdef FB_INSTALL_CDEV 167 /* attach a virtual frame buffer device */ 168 error = fb_attach(makedev(0, GDC_MKMINOR(device_get_unit(dev))), 169 sc->adp, &gdc_cdevsw); 170 if (error) { 171 gdc_release_resource(dev); 172 return error; 173 } 174#endif /* FB_INSTALL_CDEV */ 175 176 if (bootverbose) 177 (*vidsw[sc->adp->va_index]->diag)(sc->adp, bootverbose); 178 179 return 0; 180} 181 182static int 183gdc_probe_unit(int unit, gdc_softc_t *sc, int flags) 184{ 185 video_switch_t *sw; 186 187 sw = vid_get_switch(DRIVER_NAME); 188 if (sw == NULL) 189 return ENXIO; 190 return (*sw->probe)(unit, &sc->adp, NULL, flags); 191} 192 193static int 194gdc_attach_unit(int unit, gdc_softc_t *sc, int flags) 195{ 196 video_switch_t *sw; 197 198 sw = vid_get_switch(DRIVER_NAME); 199 if (sw == NULL) 200 return ENXIO; 201 return (*sw->init)(unit, sc->adp, flags); 202} 203 204 205static int 206gdc_alloc_resource(device_t dev) 207{ 208 int rid; 209 gdc_softc_t *sc; 210 211 sc = device_get_softc(dev); 212 213 /* TEXT GDC */ 214 rid = 0; 215 bus_set_resource(dev, SYS_RES_IOPORT, rid, TEXT_GDC, 1); 216 sc->res_tgdc = isa_alloc_resourcev(dev, SYS_RES_IOPORT, &rid, 217 gdc_iat, 8, RF_ACTIVE); 218 if (sc->res_tgdc == NULL) { 219 gdc_release_resource(dev); 220 return (ENXIO); 221 } 222 isa_load_resourcev(sc->res_tgdc, gdc_iat, 8); 223 224 /* GRAPHIC GDC */ 225 rid = 8; 226 bus_set_resource(dev, SYS_RES_IOPORT, rid, GRAPHIC_GDC, 1); 227 sc->res_ggdc = isa_alloc_resourcev(dev, SYS_RES_IOPORT, &rid, 228 gdc_iat, 8, RF_ACTIVE); 229 if (sc->res_ggdc == NULL) { 230 gdc_release_resource(dev); 231 return (ENXIO); 232 } 233 isa_load_resourcev(sc->res_ggdc, gdc_iat, 8); 234 235 /* EGC */ 236 rid = 16; 237 bus_set_resource(dev, SYS_RES_IOPORT, rid, 0x4a0, 1); 238 sc->res_egc = isa_alloc_resourcev(dev, SYS_RES_IOPORT, &rid, 239 gdc_iat, 8, RF_ACTIVE); 240 if (sc->res_egc == NULL) { 241 gdc_release_resource(dev); 242 return (ENXIO); 243 } 244 isa_load_resourcev(sc->res_egc, gdc_iat, 8); 245 246 /* PEGC */ 247 rid = 24; 248 bus_set_resource(dev, SYS_RES_IOPORT, rid, 0x9a0, 1); 249 sc->res_pegc = isa_alloc_resourcev(dev, SYS_RES_IOPORT, &rid, 250 gdc_iat, 8, RF_ACTIVE); 251 if (sc->res_pegc == NULL) { 252 gdc_release_resource(dev); 253 return (ENXIO); 254 } 255 isa_load_resourcev(sc->res_pegc, gdc_iat, 8); 256 257 /* CRTC/GRCG */ 258 rid = 32; 259 bus_set_resource(dev, SYS_RES_IOPORT, rid, 0x70, 1); 260 sc->res_grcg = isa_alloc_resourcev(dev, SYS_RES_IOPORT, &rid, 261 gdc_iat, 8, RF_ACTIVE); 262 if (sc->res_grcg == NULL) { 263 gdc_release_resource(dev); 264 return (ENXIO); 265 } 266 isa_load_resourcev(sc->res_grcg, gdc_iat, 8); 267 268 /* KCG */ 269 rid = 40; 270 bus_set_resource(dev, SYS_RES_IOPORT, rid, 0xa1, 1); 271 sc->res_kcg = isa_alloc_resourcev(dev, SYS_RES_IOPORT, &rid, 272 gdc_iat, 8, RF_ACTIVE); 273 if (sc->res_kcg == NULL) { 274 gdc_release_resource(dev); 275 return (ENXIO); 276 } 277 isa_load_resourcev(sc->res_kcg, gdc_iat, 8); 278 279 280 /* TEXT Memory */ 281 rid = 0; 282 sc->res_tmem = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, 283 0xa0000, 0xa4fff, 0x5000, RF_ACTIVE); 284 if (sc->res_tmem == NULL) { 285 gdc_release_resource(dev); 286 return (ENXIO); 287 } 288 289 /* GRAPHIC Memory */ 290 rid = 1; 291 sc->res_gmem1 = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, 292 0xa8000, 0xbffff, 0x18000, 293 RF_ACTIVE); 294 if (sc->res_gmem1 == NULL) { 295 gdc_release_resource(dev); 296 return (ENXIO); 297 } 298 rid = 2; 299 sc->res_gmem2 = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, 300 0xe0000, 0xe7fff, 0x8000, 301 RF_ACTIVE); 302 if (sc->res_gmem2 == NULL) { 303 gdc_release_resource(dev); 304 return (ENXIO); 305 } 306 307 return (0); 308} 309 310static int 311gdc_release_resource(device_t dev) 312{ 313 gdc_softc_t *sc; 314 315 sc = device_get_softc(dev); 316 317 if (sc->res_tgdc) 318 bus_release_resource(dev, SYS_RES_IOPORT, 0, sc->res_tgdc); 319 if (sc->res_ggdc) 320 bus_release_resource(dev, SYS_RES_IOPORT, 8, sc->res_ggdc); 321 if (sc->res_egc) 322 bus_release_resource(dev, SYS_RES_IOPORT, 16, sc->res_egc); 323 if (sc->res_pegc) 324 bus_release_resource(dev, SYS_RES_IOPORT, 24, sc->res_pegc); 325 if (sc->res_grcg) 326 bus_release_resource(dev, SYS_RES_IOPORT, 32, sc->res_grcg); 327 if (sc->res_kcg) 328 bus_release_resource(dev, SYS_RES_IOPORT, 40, sc->res_kcg); 329 330 if (sc->res_tmem) 331 bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->res_tmem); 332 if (sc->res_gmem1) 333 bus_release_resource(dev, SYS_RES_MEMORY, 1, sc->res_gmem1); 334 if (sc->res_gmem2) 335 bus_release_resource(dev, SYS_RES_MEMORY, 2, sc->res_gmem2); 336 337 return (0); 338} 339 340/* cdev driver functions */ 341 342#ifdef FB_INSTALL_CDEV 343 344static int 345gdcopen(dev_t dev, int flag, int mode, struct thread *td) 346{ 347 gdc_softc_t *sc; 348 349 sc = GDC_SOFTC(GDC_UNIT(dev)); 350 if (sc == NULL) 351 return ENXIO; 352 if (mode & (O_CREAT | O_APPEND | O_TRUNC)) 353 return ENODEV; 354 355 return genfbopen(&sc->gensc, sc->adp, flag, mode, td); 356} 357 358static int 359gdcclose(dev_t dev, int flag, int mode, struct thread *td) 360{ 361 gdc_softc_t *sc; 362 363 sc = GDC_SOFTC(GDC_UNIT(dev)); 364 return genfbclose(&sc->gensc, sc->adp, flag, mode, td); 365} 366 367static int 368gdcread(dev_t dev, struct uio *uio, int flag) 369{ 370 gdc_softc_t *sc; 371 372 sc = GDC_SOFTC(GDC_UNIT(dev)); 373 return genfbread(&sc->gensc, sc->adp, uio, flag); 374} 375 376static int 377gdcwrite(dev_t dev, struct uio *uio, int flag) 378{ 379 gdc_softc_t *sc; 380 381 sc = GDC_SOFTC(GDC_UNIT(dev)); 382 return genfbread(&sc->gensc, sc->adp, uio, flag); 383} 384 385static int 386gdcioctl(dev_t dev, u_long cmd, caddr_t arg, int flag, struct thread *td) 387{ 388 gdc_softc_t *sc; 389 390 sc = GDC_SOFTC(GDC_UNIT(dev)); 391 return genfbioctl(&sc->gensc, sc->adp, cmd, arg, flag, td); 392} 393 394static int 395gdcmmap(dev_t dev, vm_offset_t offset, vm_offset_t *paddr, int prot) 396{ 397 gdc_softc_t *sc; 398 399 sc = GDC_SOFTC(GDC_UNIT(dev)); 400 return genfbmmap(&sc->gensc, sc->adp, offset, paddr, prot); 401} 402 403#endif /* FB_INSTALL_CDEV */ 404 405static device_method_t gdc_methods[] = { 406 DEVMETHOD(device_identify, gdc_identify), 407 DEVMETHOD(device_probe, gdcprobe), 408 DEVMETHOD(device_attach, gdc_attach), 409 { 0, 0 } 410}; 411 412static driver_t gdcdriver = { 413 DRIVER_NAME, 414 gdc_methods, 415 sizeof(gdc_softc_t), 416}; 417 418DRIVER_MODULE(gdc, isa, gdcdriver, gdc_devclass, 0, 0); 419 420/* LOW-LEVEL */ 421 422 423#include <pc98/pc98/30line.h> 424 425#define TEXT_BUF_BASE 0x000a0000 426#define TEXT_BUF_SIZE 0x00008000 427#define GRAPHICS_BUF_BASE 0x000a8000 428#define GRAPHICS_BUF_SIZE 0x00040000 429#define VIDEO_BUF_BASE 0x000a0000 430#define VIDEO_BUF_SIZE 0x00048000 431 432#define probe_done(adp) ((adp)->va_flags & V_ADP_PROBED) 433#define init_done(adp) ((adp)->va_flags & V_ADP_INITIALIZED) 434#define config_done(adp) ((adp)->va_flags & V_ADP_REGISTERED) 435 436/* 437 * NOTE: `va_window' should have a virtual address, but is initialized 438 * with a physical address in the following table, they will be 439 * converted at run-time. 440 */ 441static video_adapter_t adapter_init_value[] = { 442 { 0, 443 KD_PC98, "gdc", /* va_type, va_name */ 444 0, 0, /* va_unit, va_minor */ 445 V_ADP_COLOR | V_ADP_MODECHANGE | V_ADP_BORDER, 446 TEXT_GDC, 16, TEXT_GDC, /* va_io*, XXX */ 447 VIDEO_BUF_BASE, VIDEO_BUF_SIZE, /* va_mem* */ 448 TEXT_BUF_BASE, TEXT_BUF_SIZE, TEXT_BUF_SIZE, 0, /* va_window* */ 449 0, 0, /* va_buffer, va_buffer_size */ 450 0, M_PC98_80x25, 0, /* va_*mode* */ 451 }, 452}; 453 454static video_adapter_t biosadapter[1]; 455 456/* video driver declarations */ 457static int gdc_configure(int flags); 458static int gdc_err(video_adapter_t *adp, ...); 459static vi_probe_t gdc_probe; 460static vi_init_t gdc_init; 461static vi_get_info_t gdc_get_info; 462static vi_query_mode_t gdc_query_mode; 463static vi_set_mode_t gdc_set_mode; 464static vi_set_border_t gdc_set_border; 465static vi_save_state_t gdc_save_state; 466static vi_load_state_t gdc_load_state; 467static vi_read_hw_cursor_t gdc_read_hw_cursor; 468static vi_set_hw_cursor_t gdc_set_hw_cursor; 469static vi_set_hw_cursor_shape_t gdc_set_hw_cursor_shape; 470static vi_blank_display_t gdc_blank_display; 471static vi_mmap_t gdc_mmap_buf; 472static vi_ioctl_t gdc_dev_ioctl; 473static vi_clear_t gdc_clear; 474static vi_fill_rect_t gdc_fill_rect; 475static vi_bitblt_t gdc_bitblt; 476static vi_diag_t gdc_diag; 477static vi_save_palette_t gdc_save_palette; 478static vi_load_palette_t gdc_load_palette; 479static vi_set_win_org_t gdc_set_origin; 480 481static video_switch_t gdcvidsw = { 482 gdc_probe, 483 gdc_init, 484 gdc_get_info, 485 gdc_query_mode, 486 gdc_set_mode, 487 (vi_save_font_t *)gdc_err, 488 (vi_load_font_t *)gdc_err, 489 (vi_show_font_t *)gdc_err, 490 gdc_save_palette, 491 gdc_load_palette, 492 gdc_set_border, 493 gdc_save_state, 494 gdc_load_state, 495 gdc_set_origin, 496 gdc_read_hw_cursor, 497 gdc_set_hw_cursor, 498 gdc_set_hw_cursor_shape, 499 gdc_blank_display, 500 gdc_mmap_buf, 501 gdc_dev_ioctl, 502 gdc_clear, 503 gdc_fill_rect, 504 gdc_bitblt, 505 (int (*)(void))gdc_err, 506 (int (*)(void))gdc_err, 507 gdc_diag, 508}; 509 510VIDEO_DRIVER(gdc, gdcvidsw, gdc_configure); 511 512/* GDC BIOS standard video modes */ 513#define EOT (-1) 514#define NA (-2) 515 516static video_info_t bios_vmode[] = { 517 { M_PC98_80x25, V_INFO_COLOR, 80, 25, 8, 16, 4, 1, 518 TEXT_BUF_BASE, TEXT_BUF_SIZE, TEXT_BUF_SIZE, 0, 0, V_INFO_MM_TEXT }, 519#ifdef LINE30 520 { M_PC98_80x30, V_INFO_COLOR, 80, 30, 8, 16, 4, 1, 521 TEXT_BUF_BASE, TEXT_BUF_SIZE, TEXT_BUF_SIZE, 0, 0, V_INFO_MM_TEXT }, 522#endif 523#ifndef GDC_NOGRAPHICS 524 { M_PC98_EGC640x400, V_INFO_COLOR | V_INFO_GRAPHICS, 525 640, 400, 8, 16, 4, 4, 526 GRAPHICS_BUF_BASE, GRAPHICS_BUF_SIZE, GRAPHICS_BUF_SIZE, 0, 0, 527 V_INFO_MM_OTHER }, 528 { M_PC98_PEGC640x400, V_INFO_COLOR | V_INFO_GRAPHICS | V_INFO_VESA, 529 640, 400, 8, 16, 8, 1, 530 GRAPHICS_BUF_BASE, 0x00008000, 0x00008000, 0, 0, 531 V_INFO_MM_PACKED, 1 }, 532#ifdef LINE30 533 { M_PC98_PEGC640x480, V_INFO_COLOR | V_INFO_GRAPHICS | V_INFO_VESA, 534 640, 480, 8, 16, 8, 1, 535 GRAPHICS_BUF_BASE, 0x00008000, 0x00008000, 0, 0, 536 V_INFO_MM_PACKED, 1 }, 537#endif 538#endif 539 { EOT }, 540}; 541 542static int gdc_init_done = FALSE; 543 544/* local functions */ 545static int map_gen_mode_num(int type, int color, int mode); 546static int probe_adapters(void); 547 548#define prologue(adp, flag, err) \ 549 if (!gdc_init_done || !((adp)->va_flags & (flag))) \ 550 return (err) 551 552/* a backdoor for the console driver */ 553static int 554gdc_configure(int flags) 555{ 556 probe_adapters(); 557 biosadapter[0].va_flags |= V_ADP_INITIALIZED; 558 if (!config_done(&biosadapter[0])) { 559 if (vid_register(&biosadapter[0]) < 0) 560 return 1; 561 biosadapter[0].va_flags |= V_ADP_REGISTERED; 562 } 563 564 return 1; 565} 566 567/* local subroutines */ 568 569/* map a generic video mode to a known mode number */ 570static int 571map_gen_mode_num(int type, int color, int mode) 572{ 573 static struct { 574 int from; 575 int to; 576 } mode_map[] = { 577 { M_TEXT_80x25, M_PC98_80x25, }, 578#ifdef LINE30 579 { M_TEXT_80x30, M_PC98_80x30, }, 580#endif 581 }; 582 int i; 583 584 for (i = 0; i < sizeof(mode_map)/sizeof(mode_map[0]); ++i) { 585 if (mode_map[i].from == mode) 586 return mode_map[i].to; 587 } 588 return mode; 589} 590 591static int 592verify_adapter(video_adapter_t *adp) 593{ 594#ifndef GDC_NOGRAPHICS 595 int i; 596 597 if (PC98_SYSTEM_PARAMETER(0x45c) & 0x40) { /* PEGC exists */ 598 adp->va_flags |= V_ADP_VESA; /* XXX */ 599 } else { 600 for (i = 0; bios_vmode[i].vi_mode != EOT; ++i) { 601 if (bios_vmode[i].vi_flags & V_INFO_VESA) 602 bios_vmode[i].vi_mode = NA; 603 } 604 } 605#endif 606 return 0; 607} 608 609/* probe video adapters and return the number of detected adapters */ 610static int 611probe_adapters(void) 612{ 613 video_info_t info; 614 615 /* do this test only once */ 616 if (gdc_init_done) 617 return 1; 618 gdc_init_done = TRUE; 619 620 biosadapter[0] = adapter_init_value[0]; 621 biosadapter[0].va_flags |= V_ADP_PROBED; 622 biosadapter[0].va_mode = 623 biosadapter[0].va_initial_mode = biosadapter[0].va_initial_bios_mode; 624 625 if ((PC98_SYSTEM_PARAMETER(0x597) & 0x80) || 626 (PC98_SYSTEM_PARAMETER(0x458) & 0x80)) { 627 gdc_FH = (inb(0x9a8) & 1) ? _31KHZ : _24KHZ; 628 } else { 629 gdc_FH = _24KHZ; 630 } 631 632 gdc_get_info(&biosadapter[0], biosadapter[0].va_initial_mode, &info); 633 initialize_gdc(T25_G400, info.vi_flags & V_INFO_GRAPHICS); 634 635 biosadapter[0].va_window = BIOS_PADDRTOVADDR(info.vi_window); 636 biosadapter[0].va_window_size = info.vi_window_size; 637 biosadapter[0].va_window_gran = info.vi_window_gran; 638 biosadapter[0].va_buffer = 0; 639 biosadapter[0].va_buffer_size = 0; 640 if (info.vi_flags & V_INFO_GRAPHICS) { 641 switch (info.vi_depth/info.vi_planes) { 642 case 1: 643 biosadapter[0].va_line_width = info.vi_width/8; 644 break; 645 case 2: 646 biosadapter[0].va_line_width = info.vi_width/4; 647 break; 648 case 4: 649 biosadapter[0].va_line_width = info.vi_width/2; 650 break; 651 case 8: 652 default: /* shouldn't happen */ 653 biosadapter[0].va_line_width = info.vi_width; 654 break; 655 } 656 } else { 657 biosadapter[0].va_line_width = info.vi_width; 658 } 659 bcopy(&info, &biosadapter[0].va_info, sizeof(info)); 660 661 verify_adapter(&biosadapter[0]); 662 663 return 1; 664} 665 666static void master_gdc_cmd(unsigned int cmd) 667{ 668 while ( (inb(TEXT_GDC) & 2) != 0); 669 outb(TEXT_GDC+2, cmd); 670} 671 672static void master_gdc_prm(unsigned int pmtr) 673{ 674 while ( (inb(TEXT_GDC) & 2) != 0); 675 outb(TEXT_GDC, pmtr); 676} 677 678static void master_gdc_word_prm(unsigned int wpmtr) 679{ 680 master_gdc_prm(wpmtr & 0x00ff); 681 master_gdc_prm((wpmtr >> 8) & 0x00ff); 682} 683 684#ifdef LINE30 685static void master_gdc_fifo_empty(void) 686{ 687 while ( (inb(TEXT_GDC) & 4) == 0); 688} 689#endif 690 691static void master_gdc_wait_vsync(void) 692{ 693 while ( (inb(TEXT_GDC) & 0x20) != 0); 694 while ( (inb(TEXT_GDC) & 0x20) == 0); 695} 696 697static void gdc_cmd(unsigned int cmd) 698{ 699 while ( (inb(GRAPHIC_GDC) & 2) != 0); 700 outb( GRAPHIC_GDC+2, cmd); 701} 702 703#ifdef LINE30 704static void gdc_prm(unsigned int pmtr) 705{ 706 while ( (inb(GRAPHIC_GDC) & 2) != 0); 707 outb( GRAPHIC_GDC, pmtr); 708} 709 710static void gdc_word_prm(unsigned int wpmtr) 711{ 712 gdc_prm(wpmtr & 0x00ff); 713 gdc_prm((wpmtr >> 8) & 0x00ff); 714} 715 716static void gdc_fifo_empty(void) 717{ 718 while ( (inb(GRAPHIC_GDC) & 0x04) == 0); 719} 720#endif 721 722static void gdc_wait_vsync(void) 723{ 724 while ( (inb(GRAPHIC_GDC) & 0x20) != 0); 725 while ( (inb(GRAPHIC_GDC) & 0x20) == 0); 726} 727 728#ifdef LINE30 729static int check_gdc_clock(void) 730{ 731 if ((inb(IO_SYSPORT) & 0x80) == 0){ 732 return _5MHZ; 733 } else { 734 return _2_5MHZ; 735 } 736} 737#endif 738 739static void initialize_gdc(unsigned int mode, int isGraph) 740{ 741#ifdef LINE30 742 /* start 30line initialize */ 743 int m_mode, s_mode, gdc_clock, hsync_clock; 744 745 gdc_clock = check_gdc_clock(); 746 m_mode = (mode == T25_G400) ? _25L : _30L; 747 s_mode = 2*mode+gdc_clock; 748 gdc_INFO = m_mode; 749 750 master_gdc_wait_vsync(); 751 752 if ((PC98_SYSTEM_PARAMETER(0x597) & 0x80) || 753 (PC98_SYSTEM_PARAMETER(0x458) & 0x80)) { 754 if (PC98_SYSTEM_PARAMETER(0x481) & 0x08) { 755 hsync_clock = (m_mode == _25L) ? gdc_FH : _31KHZ; 756 outb(0x9a8, (hsync_clock == _31KHZ) ? 1 : 0); 757 } else { 758 hsync_clock = gdc_FH; 759 } 760 } else { 761 hsync_clock = _24KHZ; 762 } 763 764 if ((gdc_clock == _2_5MHZ) && 765 (slave_param[hsync_clock][s_mode][GDC_LF] > 400)) { 766 outb(0x6a, 0x83); 767 outb(0x6a, 0x85); 768 gdc_clock = _5MHZ; 769 s_mode = 2*mode+gdc_clock; 770 } 771 772 master_gdc_cmd(_GDC_RESET); 773 master_gdc_cmd(_GDC_MASTER); 774 gdc_cmd(_GDC_RESET); 775 gdc_cmd(_GDC_SLAVE); 776 777 /* GDC Master */ 778 master_gdc_cmd(_GDC_SYNC); 779 master_gdc_prm(0x00); /* flush less */ /* text & graph */ 780 master_gdc_prm(master_param[hsync_clock][m_mode][GDC_CR]); 781 master_gdc_word_prm(((master_param[hsync_clock][m_mode][GDC_HFP] << 10) 782 + (master_param[hsync_clock][m_mode][GDC_VS] << 5) 783 + master_param[hsync_clock][m_mode][GDC_HS])); 784 master_gdc_prm(master_param[hsync_clock][m_mode][GDC_HBP]); 785 master_gdc_prm(master_param[hsync_clock][m_mode][GDC_VFP]); 786 master_gdc_word_prm(((master_param[hsync_clock][m_mode][GDC_VBP] << 10) 787 + (master_param[hsync_clock][m_mode][GDC_LF]))); 788 master_gdc_fifo_empty(); 789 master_gdc_cmd(_GDC_PITCH); 790 master_gdc_prm(MasterPCH); 791 master_gdc_fifo_empty(); 792 793 /* GDC slave */ 794 gdc_cmd(_GDC_SYNC); 795 gdc_prm(0x06); 796 gdc_prm(slave_param[hsync_clock][s_mode][GDC_CR]); 797 gdc_word_prm((slave_param[hsync_clock][s_mode][GDC_HFP] << 10) 798 + (slave_param[hsync_clock][s_mode][GDC_VS] << 5) 799 + (slave_param[hsync_clock][s_mode][GDC_HS])); 800 gdc_prm(slave_param[hsync_clock][s_mode][GDC_HBP]); 801 gdc_prm(slave_param[hsync_clock][s_mode][GDC_VFP]); 802 gdc_word_prm((slave_param[hsync_clock][s_mode][GDC_VBP] << 10) 803 + (slave_param[hsync_clock][s_mode][GDC_LF])); 804 gdc_fifo_empty(); 805 gdc_cmd(_GDC_PITCH); 806 gdc_prm(SlavePCH[gdc_clock]); 807 gdc_fifo_empty(); 808 809 /* set Master GDC scroll param */ 810 master_gdc_wait_vsync(); 811 master_gdc_wait_vsync(); 812 master_gdc_wait_vsync(); 813 master_gdc_cmd(_GDC_SCROLL); 814 master_gdc_word_prm(0); 815 master_gdc_word_prm((master_param[hsync_clock][m_mode][GDC_LF] << 4) 816 | 0x0000); 817 master_gdc_fifo_empty(); 818 819 /* set Slave GDC scroll param */ 820 gdc_wait_vsync(); 821 gdc_cmd(_GDC_SCROLL); 822 gdc_word_prm(0); 823 if (gdc_clock == _5MHZ) { 824 gdc_word_prm((SlaveScrlLF[mode] << 4) | 0x4000); 825 } else { 826 gdc_word_prm(SlaveScrlLF[mode] << 4); 827 } 828 gdc_fifo_empty(); 829 830 gdc_word_prm(0); 831 if (gdc_clock == _5MHZ) { 832 gdc_word_prm((SlaveScrlLF[mode] << 4) | 0x4000); 833 } else { 834 gdc_word_prm(SlaveScrlLF[mode] << 4); 835 } 836 gdc_fifo_empty(); 837 838 /* sync start */ 839 gdc_cmd(isGraph ? _GDC_START : _GDC_STOP); 840 841 gdc_wait_vsync(); 842 gdc_wait_vsync(); 843 gdc_wait_vsync(); 844 845 master_gdc_cmd(isGraph ? _GDC_STOP : _GDC_START); 846#else 847 master_gdc_wait_vsync(); 848 master_gdc_cmd(isGraph ? _GDC_STOP : _GDC_START); /* text */ 849 gdc_wait_vsync(); 850 gdc_cmd(isGraph ? _GDC_START : _GDC_STOP); /* graphics */ 851#endif 852} 853 854#ifndef GDC_NOGRAPHICS 855static u_char b_palette[] = { 856 /* R G B */ 857 0x00, 0x00, 0x00, /* 0 */ 858 0x00, 0x00, 0x7f, /* 1 */ 859 0x7f, 0x00, 0x00, /* 2 */ 860 0x7f, 0x00, 0x7f, /* 3 */ 861 0x00, 0x7f, 0x00, /* 4 */ 862 0x00, 0x7f, 0x7f, /* 5 */ 863 0x7f, 0x7f, 0x00, /* 6 */ 864 0x7f, 0x7f, 0x7f, /* 7 */ 865 0x40, 0x40, 0x40, /* 8 */ 866 0x00, 0x00, 0xff, /* 9 */ 867 0xff, 0x00, 0x00, /* 10 */ 868 0xff, 0x00, 0xff, /* 11 */ 869 0x00, 0xff, 0x00, /* 12 */ 870 0x00, 0xff, 0xff, /* 13 */ 871 0xff, 0xff, 0x00, /* 14 */ 872 0xff, 0xff, 0xff, /* 15 */ 873}; 874#endif 875 876static int 877gdc_load_palette(video_adapter_t *adp, u_char *palette) 878{ 879#ifndef GDC_NOGRAPHICS 880 int i; 881 882 if (adp->va_info.vi_flags & V_INFO_VESA) { 883 gdc_wait_vsync(); 884 for (i = 0; i < 256; ++i) { 885 outb(0xa8, i); 886 outb(0xac, *palette++); /* R */ 887 outb(0xaa, *palette++); /* G */ 888 outb(0xae, *palette++); /* B */ 889 } 890 } else { 891 /* 892 * XXX - Even though PC-98 text color is independent of palette, 893 * we should set palette in text mode. 894 * Because the background color of text mode is palette 0's one. 895 */ 896 outb(0x6a, 1); /* 16 colors mode */ 897 bcopy(palette, b_palette, sizeof(b_palette)); 898 899 gdc_wait_vsync(); 900 for (i = 0; i < 16; ++i) { 901 outb(0xa8, i); 902 outb(0xac, *palette++ >> 4); /* R */ 903 outb(0xaa, *palette++ >> 4); /* G */ 904 outb(0xae, *palette++ >> 4); /* B */ 905 } 906 } 907#endif 908 return 0; 909} 910 911static int 912gdc_save_palette(video_adapter_t *adp, u_char *palette) 913{ 914#ifndef GDC_NOGRAPHICS 915 int i; 916 917 if (adp->va_info.vi_flags & V_INFO_VESA) { 918 for (i = 0; i < 256; ++i) { 919 outb(0xa8, i); 920 *palette++ = inb(0xac); /* R */ 921 *palette++ = inb(0xaa); /* G */ 922 *palette++ = inb(0xae); /* B */ 923 } 924 } else { 925 bcopy(b_palette, palette, sizeof(b_palette)); 926 } 927#endif 928 return 0; 929} 930 931static int 932gdc_set_origin(video_adapter_t *adp, off_t offset) 933{ 934#ifndef GDC_NOGRAPHICS 935 if (adp->va_info.vi_flags & V_INFO_VESA) { 936 writew(BIOS_PADDRTOVADDR(0x000e0004), offset >> 15); 937 } 938#endif 939 return 0; 940} 941 942/* entry points */ 943 944static int 945gdc_err(video_adapter_t *adp, ...) 946{ 947 return ENODEV; 948} 949 950static int 951gdc_probe(int unit, video_adapter_t **adpp, void *arg, int flags) 952{ 953 probe_adapters(); 954 if (unit >= 1) 955 return ENXIO; 956 957 *adpp = &biosadapter[unit]; 958 959 return 0; 960} 961 962static int 963gdc_init(int unit, video_adapter_t *adp, int flags) 964{ 965 if ((unit >= 1) || (adp == NULL) || !probe_done(adp)) 966 return ENXIO; 967 968 if (!init_done(adp)) { 969 /* nothing to do really... */ 970 adp->va_flags |= V_ADP_INITIALIZED; 971 } 972 973 if (!config_done(adp)) { 974 if (vid_register(adp) < 0) 975 return ENXIO; 976 adp->va_flags |= V_ADP_REGISTERED; 977 } 978 979 return 0; 980} 981 982/* 983 * get_info(): 984 * Return the video_info structure of the requested video mode. 985 */ 986static int 987gdc_get_info(video_adapter_t *adp, int mode, video_info_t *info) 988{ 989 int i; 990 991 if (!gdc_init_done) 992 return ENXIO; 993 994 mode = map_gen_mode_num(adp->va_type, adp->va_flags & V_ADP_COLOR, mode); 995 for (i = 0; bios_vmode[i].vi_mode != EOT; ++i) { 996 if (bios_vmode[i].vi_mode == NA) 997 continue; 998 if (mode == bios_vmode[i].vi_mode) { 999 *info = bios_vmode[i]; 1000 info->vi_buffer_size = info->vi_window_size*info->vi_planes; 1001 return 0; 1002 } 1003 } 1004 return EINVAL; 1005} 1006 1007/* 1008 * query_mode(): 1009 * Find a video mode matching the requested parameters. 1010 * Fields filled with 0 are considered "don't care" fields and 1011 * match any modes. 1012 */ 1013static int 1014gdc_query_mode(video_adapter_t *adp, video_info_t *info) 1015{ 1016 int i; 1017 1018 if (!gdc_init_done) 1019 return ENXIO; 1020 1021 for (i = 0; bios_vmode[i].vi_mode != EOT; ++i) { 1022 if (bios_vmode[i].vi_mode == NA) 1023 continue; 1024 1025 if ((info->vi_width != 0) 1026 && (info->vi_width != bios_vmode[i].vi_width)) 1027 continue; 1028 if ((info->vi_height != 0) 1029 && (info->vi_height != bios_vmode[i].vi_height)) 1030 continue; 1031 if ((info->vi_cwidth != 0) 1032 && (info->vi_cwidth != bios_vmode[i].vi_cwidth)) 1033 continue; 1034 if ((info->vi_cheight != 0) 1035 && (info->vi_cheight != bios_vmode[i].vi_cheight)) 1036 continue; 1037 if ((info->vi_depth != 0) 1038 && (info->vi_depth != bios_vmode[i].vi_depth)) 1039 continue; 1040 if ((info->vi_planes != 0) 1041 && (info->vi_planes != bios_vmode[i].vi_planes)) 1042 continue; 1043 /* XXX: should check pixel format, memory model */ 1044 if ((info->vi_flags != 0) 1045 && (info->vi_flags != bios_vmode[i].vi_flags)) 1046 continue; 1047 1048 /* verify if this mode is supported on this adapter */ 1049 if (gdc_get_info(adp, bios_vmode[i].vi_mode, info)) 1050 continue; 1051 return 0; 1052 } 1053 return ENODEV; 1054} 1055 1056/* 1057 * set_mode(): 1058 * Change the video mode. 1059 */ 1060static int 1061gdc_set_mode(video_adapter_t *adp, int mode) 1062{ 1063 video_info_t info; 1064 1065 prologue(adp, V_ADP_MODECHANGE, ENODEV); 1066 1067 mode = map_gen_mode_num(adp->va_type, 1068 adp->va_flags & V_ADP_COLOR, mode); 1069 if (gdc_get_info(adp, mode, &info)) 1070 return EINVAL; 1071 1072 switch (info.vi_mode) { 1073#ifndef GDC_NOGRAPHICS 1074 case M_PC98_PEGC640x480: /* PEGC 640x480 */ 1075 initialize_gdc(T30_G480, info.vi_flags & V_INFO_GRAPHICS); 1076 break; 1077 case M_PC98_PEGC640x400: /* PEGC 640x400 */ 1078 case M_PC98_EGC640x400: /* EGC GRAPHICS */ 1079#endif 1080 case M_PC98_80x25: /* VGA TEXT */ 1081 initialize_gdc(T25_G400, info.vi_flags & V_INFO_GRAPHICS); 1082 break; 1083 case M_PC98_80x30: /* VGA TEXT */ 1084 initialize_gdc(T30_G400, info.vi_flags & V_INFO_GRAPHICS); 1085 break; 1086 default: 1087 break; 1088 } 1089 1090#ifndef GDC_NOGRAPHICS 1091 if (info.vi_flags & V_INFO_VESA) { 1092 outb(0x6a, 0x07); /* enable mode F/F change */ 1093 outb(0x6a, 0x21); /* enhanced graphics */ 1094 if (info.vi_height > 400) 1095 outb(0x6a, 0x69); /* 800 lines */ 1096 writeb(BIOS_PADDRTOVADDR(0x000e0100), 0); /* packed pixel */ 1097 } else { 1098 if (adp->va_flags & V_ADP_VESA) { 1099 outb(0x6a, 0x07); /* enable mode F/F change */ 1100 outb(0x6a, 0x20); /* normal graphics */ 1101 outb(0x6a, 0x68); /* 400 lines */ 1102 } 1103 outb(0x6a, 1); /* 16 colors */ 1104 } 1105#endif 1106 1107 adp->va_mode = mode; 1108 adp->va_flags &= ~V_ADP_COLOR; 1109 adp->va_flags |= 1110 (info.vi_flags & V_INFO_COLOR) ? V_ADP_COLOR : 0; 1111#if 0 1112 adp->va_crtc_addr = 1113 (adp->va_flags & V_ADP_COLOR) ? COLOR_CRTC : MONO_CRTC; 1114#endif 1115 adp->va_window = BIOS_PADDRTOVADDR(info.vi_window); 1116 adp->va_window_size = info.vi_window_size; 1117 adp->va_window_gran = info.vi_window_gran; 1118 if (info.vi_buffer_size == 0) { 1119 adp->va_buffer = 0; 1120 adp->va_buffer_size = 0; 1121 } else { 1122 adp->va_buffer = BIOS_PADDRTOVADDR(info.vi_buffer); 1123 adp->va_buffer_size = info.vi_buffer_size; 1124 } 1125 if (info.vi_flags & V_INFO_GRAPHICS) { 1126 switch (info.vi_depth/info.vi_planes) { 1127 case 1: 1128 adp->va_line_width = info.vi_width/8; 1129 break; 1130 case 2: 1131 adp->va_line_width = info.vi_width/4; 1132 break; 1133 case 4: 1134 adp->va_line_width = info.vi_width/2; 1135 break; 1136 case 8: 1137 default: /* shouldn't happen */ 1138 adp->va_line_width = info.vi_width; 1139 break; 1140 } 1141 } else { 1142 adp->va_line_width = info.vi_width; 1143 } 1144 bcopy(&info, &adp->va_info, sizeof(info)); 1145 1146 /* move hardware cursor out of the way */ 1147 (*vidsw[adp->va_index]->set_hw_cursor)(adp, -1, -1); 1148 1149 return 0; 1150} 1151 1152/* 1153 * set_border(): 1154 * Change the border color. 1155 */ 1156static int 1157gdc_set_border(video_adapter_t *adp, int color) 1158{ 1159 outb(0x6c, color << 4); 1160 return 0; 1161} 1162 1163/* 1164 * save_state(): 1165 * Read video card register values. 1166 */ 1167static int 1168gdc_save_state(video_adapter_t *adp, void *p, size_t size) 1169{ 1170 return ENODEV; 1171} 1172 1173/* 1174 * load_state(): 1175 * Set video card registers at once. 1176 */ 1177static int 1178gdc_load_state(video_adapter_t *adp, void *p) 1179{ 1180 return ENODEV; 1181} 1182 1183/* 1184 * read_hw_cursor(): 1185 * Read the position of the hardware text cursor. 1186 */ 1187static int 1188gdc_read_hw_cursor(video_adapter_t *adp, int *col, int *row) 1189{ 1190 u_int16_t off; 1191 int s; 1192 1193 if (!gdc_init_done) 1194 return ENXIO; 1195 1196 if (adp->va_info.vi_flags & V_INFO_GRAPHICS) 1197 return ENODEV; 1198 1199 s = spltty(); 1200 master_gdc_cmd(0xe0); /* _GDC_CSRR */ 1201 while((inb(TEXT_GDC + 0) & 0x1) == 0) {} /* GDC wait */ 1202 off = inb(TEXT_GDC + 2); /* EADl */ 1203 off |= (inb(TEXT_GDC + 2) << 8); /* EADh */ 1204 inb(TEXT_GDC + 2); /* dummy */ 1205 inb(TEXT_GDC + 2); /* dummy */ 1206 inb(TEXT_GDC + 2); /* dummy */ 1207 splx(s); 1208 1209 if (off >= ROW*COL) 1210 off = 0; 1211 *row = off / adp->va_info.vi_width; 1212 *col = off % adp->va_info.vi_width; 1213 1214 return 0; 1215} 1216 1217/* 1218 * set_hw_cursor(): 1219 * Move the hardware text cursor. If col and row are both -1, 1220 * the cursor won't be shown. 1221 */ 1222static int 1223gdc_set_hw_cursor(video_adapter_t *adp, int col, int row) 1224{ 1225 u_int16_t off; 1226 int s; 1227 1228 if (!gdc_init_done) 1229 return ENXIO; 1230 1231 if ((col == -1) && (row == -1)) { 1232 off = -1; 1233 } else { 1234 if (adp->va_info.vi_flags & V_INFO_GRAPHICS) 1235 return ENODEV; 1236 off = row*adp->va_info.vi_width + col; 1237 } 1238 1239 s = spltty(); 1240 master_gdc_cmd(0x49); /* _GDC_CSRW */ 1241 master_gdc_word_prm(off); 1242 splx(s); 1243 1244 return 0; 1245} 1246 1247/* 1248 * set_hw_cursor_shape(): 1249 * Change the shape of the hardware text cursor. If the height is zero 1250 * or negative, the cursor won't be shown. 1251 */ 1252static int 1253gdc_set_hw_cursor_shape(video_adapter_t *adp, int base, int height, 1254 int celsize, int blink) 1255{ 1256 int start; 1257 int end; 1258 int s; 1259 1260 if (!gdc_init_done) 1261 return ENXIO; 1262 1263 start = celsize - (base + height); 1264 end = celsize - base - 1; 1265 1266#if 0 1267 /* 1268 * muPD7220 GDC has anomaly that if end == celsize - 1 then start 1269 * must be 0, otherwise the cursor won't be correctly shown 1270 * in the first row in the screen. We shall set end to celsize - 2; 1271 * if end == celsize -1 && start > 0. XXX 1272 */ 1273 if ((end == celsize - 1) && (start > 0) && (start < end)) 1274 --end; 1275#endif 1276 1277 s = spltty(); 1278 master_gdc_cmd(0x4b); /* _GDC_CSRFORM */ 1279 master_gdc_prm(((height > 0) ? 0x80 : 0) /* cursor on/off */ 1280 | ((celsize - 1) & 0x1f)); /* cel size */ 1281 master_gdc_word_prm(((end & 0x1f) << 11) /* end line */ 1282 | (12 << 6) /* blink rate */ 1283 | (blink ? 0 : 0x20) /* blink on/off */ 1284 | (start & 0x1f)); /* start line */ 1285 splx(s); 1286 1287 return 0; 1288} 1289 1290/* 1291 * blank_display() 1292 * Put the display in power save/power off mode. 1293 */ 1294static int 1295gdc_blank_display(video_adapter_t *adp, int mode) 1296{ 1297 int s; 1298 static int standby = 0; 1299 1300 if (!gdc_init_done) 1301 return ENXIO; 1302 1303 s = splhigh(); 1304 switch (mode) { 1305 case V_DISPLAY_SUSPEND: 1306 case V_DISPLAY_STAND_BY: 1307 outb(0x09a2, 0x80 | 0x40); /* V/H-SYNC mask */ 1308 if (inb(0x09a2) == (0x80 | 0x40)) 1309 standby = 1; 1310 /* FALLTHROUGH */ 1311 1312 case V_DISPLAY_BLANK: 1313 if (epson_machine_id == 0x20) { 1314 outb(0x43f, 0x42); 1315 outb(0xc17, inb(0xc17) & ~0x08); /* turn off side light */ 1316 outb(0xc16, inb(0xc16) & ~0x02); /* turn off back light */ 1317 outb(0x43f, 0x40); 1318 } else { 1319 while (!(inb(TEXT_GDC) & 0x20)) /* V-SYNC wait */ 1320 ; 1321 outb(TEXT_GDC + 8, 0x0e); /* DISP off */ 1322 } 1323 break; 1324 1325 case V_DISPLAY_ON: 1326 if (epson_machine_id == 0x20) { 1327 outb(0x43f, 0x42); 1328 outb(0xc17, inb(0xc17) | 0x08); 1329 outb(0xc16, inb(0xc16) | 0x02); 1330 outb(0x43f, 0x40); 1331 } else { 1332 while (!(inb(TEXT_GDC) & 0x20)) /* V-SYNC wait */ 1333 ; 1334 outb(TEXT_GDC + 8, 0x0f); /* DISP on */ 1335 } 1336 if (standby) { 1337 outb(0x09a2, 0x00); /* V/H-SYNC unmask */ 1338 standby = 0; 1339 } 1340 break; 1341 } 1342 splx(s); 1343 return 0; 1344} 1345 1346/* 1347 * mmap(): 1348 * Mmap frame buffer. 1349 */ 1350static int 1351gdc_mmap_buf(video_adapter_t *adp, vm_offset_t offset, vm_offset_t *paddr, 1352 int prot) 1353{ 1354 /* FIXME: is this correct? XXX */ 1355 if (offset > VIDEO_BUF_SIZE - PAGE_SIZE) 1356 return -1; 1357 *paddr = adp->va_info.vi_window + offset; 1358 return 0; 1359} 1360 1361static int 1362gdc_clear(video_adapter_t *adp) 1363{ 1364 /* FIXME */ 1365 return ENODEV; 1366} 1367 1368static int 1369gdc_fill_rect(video_adapter_t *adp, int val, int x, int y, int cx, int cy) 1370{ 1371 return ENODEV; 1372} 1373 1374static int 1375gdc_bitblt(video_adapter_t *adp,...) 1376{ 1377 /* FIXME */ 1378 return ENODEV; 1379} 1380 1381static int 1382gdc_dev_ioctl(video_adapter_t *adp, u_long cmd, caddr_t arg) 1383{ 1384 switch (cmd) { 1385 case FBIO_GETWINORG: /* get frame buffer window origin */ 1386 *(u_int *)arg = 0; 1387 return 0; 1388 1389 case FBIO_SETWINORG: /* set frame buffer window origin */ 1390 case FBIO_SETDISPSTART: /* set display start address */ 1391 case FBIO_SETLINEWIDTH: /* set scan line length in pixel */ 1392 case FBIO_GETPALETTE: /* get color palette */ 1393 case FBIO_SETPALETTE: /* set color palette */ 1394 case FBIOGETCMAP: /* get color palette */ 1395 case FBIOPUTCMAP: /* set color palette */ 1396 return ENODEV; 1397 1398 case FBIOGTYPE: /* get frame buffer type info. */ 1399 ((struct fbtype *)arg)->fb_type = fb_type(adp->va_type); 1400 ((struct fbtype *)arg)->fb_height = adp->va_info.vi_height; 1401 ((struct fbtype *)arg)->fb_width = adp->va_info.vi_width; 1402 ((struct fbtype *)arg)->fb_depth = adp->va_info.vi_depth; 1403 if ((adp->va_info.vi_depth <= 1) || (adp->va_info.vi_depth > 8)) 1404 ((struct fbtype *)arg)->fb_cmsize = 0; 1405 else 1406 ((struct fbtype *)arg)->fb_cmsize = 1 << adp->va_info.vi_depth; 1407 ((struct fbtype *)arg)->fb_size = adp->va_buffer_size; 1408 return 0; 1409 1410 default: 1411 return fb_commonioctl(adp, cmd, arg); 1412 } 1413} 1414 1415/* 1416 * diag(): 1417 * Print some information about the video adapter and video modes, 1418 * with requested level of details. 1419 */ 1420static int 1421gdc_diag(video_adapter_t *adp, int level) 1422{ 1423#if FB_DEBUG > 1 1424 int i; 1425#endif 1426 1427 if (!gdc_init_done) 1428 return ENXIO; 1429 1430 fb_dump_adp_info(DRIVER_NAME, adp, level); 1431 1432#if FB_DEBUG > 1 1433 for (i = 0; bios_vmode[i].vi_mode != EOT; ++i) { 1434 if (bios_vmode[i].vi_mode == NA) 1435 continue; 1436 if (get_mode_param(bios_vmode[i].vi_mode) == NULL) 1437 continue; 1438 fb_dump_mode_info(DRIVER_NAME, adp, &bios_vmode[i], level); 1439 } 1440#endif 1441 1442 return 0; 1443}
|