1367466Sdim/*- 2260684Skaiw * Copyright (c) 1999 FreeBSD(98) port team. 3260684Skaiw * All rights reserved. 4260684Skaiw * 5260684Skaiw * Redistribution and use in source and binary forms, with or without 6260684Skaiw * modification, are permitted provided that the following conditions 7260684Skaiw * are met: 8260684Skaiw * 1. Redistributions of source code must retain the above copyright 9260684Skaiw * notice, this list of conditions and the following disclaimer as 10260684Skaiw * the first lines of this file unmodified. 11260684Skaiw * 2. Redistributions in binary form must reproduce the above copyright 12260684Skaiw * notice, this list of conditions and the following disclaimer in the 13260684Skaiw * documentation and/or other materials provided with the distribution. 14260684Skaiw * 3. The name of the author may not be used to endorse or promote products 15260684Skaiw * derived from this software without specific prior written permission. 16260684Skaiw * 17260684Skaiw * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18260684Skaiw * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19260684Skaiw * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20260684Skaiw * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21260684Skaiw * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22260684Skaiw * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23260684Skaiw * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24367466Sdim * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25260684Skaiw * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26367466Sdim * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27367466Sdim * 28260684Skaiw * $FreeBSD$ 29260684Skaiw */ 30260684Skaiw 31260684Skaiw#include "opt_gdc.h" 32260684Skaiw#include "opt_fb.h" 33260684Skaiw#include "opt_syscons.h" 34260684Skaiw 35260684Skaiw#include <sys/param.h> 36260684Skaiw#include <sys/systm.h> 37260684Skaiw#include <sys/kernel.h> 38260684Skaiw#include <sys/module.h> 39367466Sdim#include <sys/conf.h> 40260684Skaiw#include <sys/bus.h> 41367466Sdim#include <machine/bus.h> 42260684Skaiw#include <sys/rman.h> 43367466Sdim#include <machine/resource.h> 44260684Skaiw 45367466Sdim#include <sys/fbio.h> 46260684Skaiw#include <sys/fcntl.h> 47260684Skaiw 48260684Skaiw#include <vm/vm.h> 49260684Skaiw#include <vm/pmap.h> 50260684Skaiw#include <vm/vm_param.h> 51260684Skaiw 52367466Sdim#include <machine/md_var.h> 53260684Skaiw#include <machine/pc/bios.h> 54260684Skaiw 55260684Skaiw#include <dev/fb/fbreg.h> 56260684Skaiw 57260684Skaiw#ifdef LINE30 58260684Skaiw#include <pc98/cbus/cbus.h> 59367466Sdim#endif 60260684Skaiw#include <pc98/pc98/pc98_machdep.h> 61260684Skaiw#include <isa/isavar.h> 62260684Skaiw 63260684Skaiw#define TEXT_GDC 0x60 64367466Sdim#define GRAPHIC_GDC 0xa0 65260684Skaiw#define ROW 25 66260684Skaiw#define COL 80 67367466Sdim 68367466Sdim#define DRIVER_NAME "gdc" 69367466Sdim 70367466Sdim/* cdev driver declaration */ 71367466Sdim 72260684Skaiw#define GDC_UNIT(dev) dev2unit(dev) 73260684Skaiw#define GDC_MKMINOR(unit) (unit) 74260684Skaiw 75260684Skaiwtypedef struct gdc_softc { 76260684Skaiw video_adapter_t *adp; 77260684Skaiw struct resource *res_tgdc, *res_ggdc; 78260684Skaiw struct resource *res_egc, *res_pegc, *res_grcg, *res_kcg; 79260684Skaiw struct resource *res_tmem, *res_gmem1, *res_gmem2; 80260684Skaiw#ifdef FB_INSTALL_CDEV 81260684Skaiw genfb_softc_t gensc; 82260684Skaiw#endif 83260684Skaiw} gdc_softc_t; 84260684Skaiw 85260684Skaiw#define GDC_SOFTC(unit) \ 86260684Skaiw ((gdc_softc_t *)devclass_get_softc(gdc_devclass, unit)) 87260684Skaiw 88260684Skaiwstatic bus_addr_t gdc_iat[] = {0, 2, 4, 6, 8, 10, 12, 14}; 89260684Skaiw 90260684Skaiwstatic devclass_t gdc_devclass; 91260684Skaiw 92260684Skaiwstatic int gdc_probe_unit(int unit, gdc_softc_t *sc, int flags); 93260684Skaiwstatic int gdc_attach_unit(int unit, gdc_softc_t *sc, int flags); 94260684Skaiwstatic int gdc_alloc_resource(device_t dev); 95260684Skaiwstatic int gdc_release_resource(device_t dev); 96260684Skaiw 97260684Skaiw#ifdef FB_INSTALL_CDEV 98260684Skaiw 99260684Skaiwstatic d_open_t gdcopen; 100260684Skaiwstatic d_close_t gdcclose; 101260684Skaiwstatic d_read_t gdcread; 102260684Skaiwstatic d_write_t gdcwrite; 103260684Skaiwstatic d_ioctl_t gdcioctl; 104260684Skaiwstatic d_mmap_t gdcmmap; 105260684Skaiw 106260684Skaiwstatic struct cdevsw gdc_cdevsw = { 107260684Skaiw .d_version = D_VERSION, 108260684Skaiw .d_flags = D_NEEDGIANT, 109260684Skaiw .d_open = gdcopen, 110260684Skaiw .d_close = gdcclose, 111260684Skaiw .d_read = gdcread, 112260684Skaiw .d_write = gdcwrite, 113260684Skaiw .d_ioctl = gdcioctl, 114260684Skaiw .d_mmap = gdcmmap, 115260684Skaiw .d_name = DRIVER_NAME, 116260684Skaiw}; 117260684Skaiw 118260684Skaiw#endif /* FB_INSTALL_CDEV */ 119260684Skaiw 120260684Skaiwstatic void 121260684Skaiwgdc_identify(driver_t *driver, device_t parent) 122260684Skaiw{ 123260684Skaiw BUS_ADD_CHILD(parent, ISA_ORDER_SPECULATIVE, DRIVER_NAME, 0); 124260684Skaiw} 125260684Skaiw 126260684Skaiwstatic int 127260684Skaiwgdcprobe(device_t dev) 128260684Skaiw{ 129260684Skaiw int error; 130260684Skaiw 131260684Skaiw /* Check isapnp ids */ 132260684Skaiw if (isa_get_vendorid(dev)) 133260684Skaiw return (ENXIO); 134260684Skaiw 135260684Skaiw device_set_desc(dev, "Generic GDC"); 136260684Skaiw 137260684Skaiw error = gdc_alloc_resource(dev); 138260684Skaiw if (error) 139260684Skaiw return (error); 140260684Skaiw 141260684Skaiw error = gdc_probe_unit(device_get_unit(dev), 142260684Skaiw device_get_softc(dev), 143260684Skaiw device_get_flags(dev)); 144260684Skaiw 145260684Skaiw gdc_release_resource(dev); 146260684Skaiw 147260684Skaiw return (error); 148260684Skaiw} 149260684Skaiw 150260684Skaiwstatic int 151260684Skaiwgdc_attach(device_t dev) 152260684Skaiw{ 153260684Skaiw gdc_softc_t *sc; 154260684Skaiw int error; 155260684Skaiw 156260684Skaiw error = gdc_alloc_resource(dev); 157260684Skaiw if (error) 158260684Skaiw return (error); 159367466Sdim 160260684Skaiw sc = device_get_softc(dev); 161260684Skaiw error = gdc_attach_unit(device_get_unit(dev), 162260684Skaiw sc, 163260684Skaiw device_get_flags(dev)); 164260684Skaiw if (error) { 165260684Skaiw gdc_release_resource(dev); 166260684Skaiw return error; 167260684Skaiw } 168260684Skaiw 169260684Skaiw#ifdef FB_INSTALL_CDEV 170260684Skaiw /* attach a virtual frame buffer device */ 171260684Skaiw error = fb_attach(GDC_MKMINOR(device_get_unit(dev)), 172260684Skaiw sc->adp, &gdc_cdevsw); 173260684Skaiw if (error) { 174260684Skaiw gdc_release_resource(dev); 175367466Sdim return error; 176367466Sdim } 177260684Skaiw#endif /* FB_INSTALL_CDEV */ 178260684Skaiw 179260684Skaiw if (bootverbose) 180260684Skaiw vidd_diag(sc->adp, bootverbose); 181260684Skaiw 182260684Skaiw return 0; 183367466Sdim} 184367466Sdim 185367466Sdimstatic int 186367466Sdimgdc_probe_unit(int unit, gdc_softc_t *sc, int flags) 187367466Sdim{ 188367466Sdim video_switch_t *sw; 189367466Sdim 190367466Sdim sw = vid_get_switch(DRIVER_NAME); 191367466Sdim if (sw == NULL) 192367466Sdim return ENXIO; 193367466Sdim return (*sw->probe)(unit, &sc->adp, NULL, flags); 194367466Sdim} 195367466Sdim 196367466Sdimstatic int 197367466Sdimgdc_attach_unit(int unit, gdc_softc_t *sc, int flags) 198367466Sdim{ 199367466Sdim video_switch_t *sw; 200367466Sdim 201367466Sdim sw = vid_get_switch(DRIVER_NAME); 202367466Sdim if (sw == NULL) 203367466Sdim return ENXIO; 204367466Sdim return (*sw->init)(unit, sc->adp, flags); 205367466Sdim} 206367466Sdim 207367466Sdim 208367466Sdimstatic int 209367466Sdimgdc_alloc_resource(device_t dev) 210260684Skaiw{ 211260684Skaiw int rid; 212260684Skaiw gdc_softc_t *sc; 213260684Skaiw 214260684Skaiw sc = device_get_softc(dev); 215260684Skaiw 216260684Skaiw /* TEXT GDC */ 217260684Skaiw rid = 0; 218260684Skaiw bus_set_resource(dev, SYS_RES_IOPORT, rid, TEXT_GDC, 1); 219260684Skaiw sc->res_tgdc = isa_alloc_resourcev(dev, SYS_RES_IOPORT, &rid, 220260684Skaiw gdc_iat, 8, RF_ACTIVE); 221260684Skaiw if (sc->res_tgdc == NULL) { 222260684Skaiw gdc_release_resource(dev); 223260684Skaiw return (ENXIO); 224260684Skaiw } 225260684Skaiw isa_load_resourcev(sc->res_tgdc, gdc_iat, 8); 226260684Skaiw 227260684Skaiw /* GRAPHIC GDC */ 228260684Skaiw rid = 8; 229260684Skaiw bus_set_resource(dev, SYS_RES_IOPORT, rid, GRAPHIC_GDC, 1); 230260684Skaiw sc->res_ggdc = isa_alloc_resourcev(dev, SYS_RES_IOPORT, &rid, 231260684Skaiw gdc_iat, 8, RF_ACTIVE); 232260684Skaiw if (sc->res_ggdc == NULL) { 233260684Skaiw gdc_release_resource(dev); 234260684Skaiw return (ENXIO); 235260684Skaiw } 236260684Skaiw isa_load_resourcev(sc->res_ggdc, gdc_iat, 8); 237260684Skaiw 238260684Skaiw /* EGC */ 239260684Skaiw rid = 16; 240260684Skaiw bus_set_resource(dev, SYS_RES_IOPORT, rid, 0x4a0, 1); 241260684Skaiw sc->res_egc = isa_alloc_resourcev(dev, SYS_RES_IOPORT, &rid, 242260684Skaiw gdc_iat, 8, RF_ACTIVE); 243260684Skaiw if (sc->res_egc == NULL) { 244260684Skaiw gdc_release_resource(dev); 245260684Skaiw return (ENXIO); 246260684Skaiw } 247260684Skaiw isa_load_resourcev(sc->res_egc, gdc_iat, 8); 248260684Skaiw 249260684Skaiw /* PEGC */ 250260684Skaiw rid = 24; 251260684Skaiw bus_set_resource(dev, SYS_RES_IOPORT, rid, 0x9a0, 1); 252260684Skaiw sc->res_pegc = isa_alloc_resourcev(dev, SYS_RES_IOPORT, &rid, 253260684Skaiw gdc_iat, 8, RF_ACTIVE); 254260684Skaiw if (sc->res_pegc == NULL) { 255260684Skaiw gdc_release_resource(dev); 256260684Skaiw return (ENXIO); 257260684Skaiw } 258260684Skaiw isa_load_resourcev(sc->res_pegc, gdc_iat, 8); 259260684Skaiw 260260684Skaiw /* CRTC/GRCG */ 261260684Skaiw rid = 32; 262260684Skaiw bus_set_resource(dev, SYS_RES_IOPORT, rid, 0x70, 1); 263260684Skaiw sc->res_grcg = isa_alloc_resourcev(dev, SYS_RES_IOPORT, &rid, 264260684Skaiw gdc_iat, 8, RF_ACTIVE); 265260684Skaiw if (sc->res_grcg == NULL) { 266260684Skaiw gdc_release_resource(dev); 267260684Skaiw return (ENXIO); 268260684Skaiw } 269260684Skaiw isa_load_resourcev(sc->res_grcg, gdc_iat, 8); 270260684Skaiw 271260684Skaiw /* KCG */ 272260684Skaiw rid = 40; 273260684Skaiw bus_set_resource(dev, SYS_RES_IOPORT, rid, 0xa1, 1); 274260684Skaiw sc->res_kcg = isa_alloc_resourcev(dev, SYS_RES_IOPORT, &rid, 275260684Skaiw gdc_iat, 8, RF_ACTIVE); 276260684Skaiw if (sc->res_kcg == NULL) { 277260684Skaiw gdc_release_resource(dev); 278 return (ENXIO); 279 } 280 isa_load_resourcev(sc->res_kcg, gdc_iat, 8); 281 282 283 /* TEXT Memory */ 284 rid = 0; 285 sc->res_tmem = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, 286 0xa0000, 0xa4fff, 0x5000, RF_ACTIVE); 287 if (sc->res_tmem == NULL) { 288 gdc_release_resource(dev); 289 return (ENXIO); 290 } 291 292 /* GRAPHIC Memory */ 293 rid = 1; 294 sc->res_gmem1 = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, 295 0xa8000, 0xbffff, 0x18000, 296 RF_ACTIVE); 297 if (sc->res_gmem1 == NULL) { 298 gdc_release_resource(dev); 299 return (ENXIO); 300 } 301 rid = 2; 302 sc->res_gmem2 = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, 303 0xe0000, 0xe7fff, 0x8000, 304 RF_ACTIVE); 305 if (sc->res_gmem2 == NULL) { 306 gdc_release_resource(dev); 307 return (ENXIO); 308 } 309 310 return (0); 311} 312 313static int 314gdc_release_resource(device_t dev) 315{ 316 gdc_softc_t *sc; 317 318 sc = device_get_softc(dev); 319 320 if (sc->res_tgdc) 321 bus_release_resource(dev, SYS_RES_IOPORT, 0, sc->res_tgdc); 322 if (sc->res_ggdc) 323 bus_release_resource(dev, SYS_RES_IOPORT, 8, sc->res_ggdc); 324 if (sc->res_egc) 325 bus_release_resource(dev, SYS_RES_IOPORT, 16, sc->res_egc); 326 if (sc->res_pegc) 327 bus_release_resource(dev, SYS_RES_IOPORT, 24, sc->res_pegc); 328 if (sc->res_grcg) 329 bus_release_resource(dev, SYS_RES_IOPORT, 32, sc->res_grcg); 330 if (sc->res_kcg) 331 bus_release_resource(dev, SYS_RES_IOPORT, 40, sc->res_kcg); 332 333 if (sc->res_tmem) 334 bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->res_tmem); 335 if (sc->res_gmem1) 336 bus_release_resource(dev, SYS_RES_MEMORY, 1, sc->res_gmem1); 337 if (sc->res_gmem2) 338 bus_release_resource(dev, SYS_RES_MEMORY, 2, sc->res_gmem2); 339 340 return (0); 341} 342 343/* cdev driver functions */ 344 345#ifdef FB_INSTALL_CDEV 346 347static int 348gdcopen(struct cdev *dev, int flag, int mode, struct thread *td) 349{ 350 gdc_softc_t *sc; 351 352 sc = GDC_SOFTC(GDC_UNIT(dev)); 353 if (sc == NULL) 354 return ENXIO; 355 if (mode & (O_CREAT | O_APPEND | O_TRUNC)) 356 return ENODEV; 357 358 return genfbopen(&sc->gensc, sc->adp, flag, mode, td); 359} 360 361static int 362gdcclose(struct cdev *dev, int flag, int mode, struct thread *td) 363{ 364 gdc_softc_t *sc; 365 366 sc = GDC_SOFTC(GDC_UNIT(dev)); 367 return genfbclose(&sc->gensc, sc->adp, flag, mode, td); 368} 369 370static int 371gdcread(struct cdev *dev, struct uio *uio, int flag) 372{ 373 gdc_softc_t *sc; 374 375 sc = GDC_SOFTC(GDC_UNIT(dev)); 376 return genfbread(&sc->gensc, sc->adp, uio, flag); 377} 378 379static int 380gdcwrite(struct cdev *dev, struct uio *uio, int flag) 381{ 382 gdc_softc_t *sc; 383 384 sc = GDC_SOFTC(GDC_UNIT(dev)); 385 return genfbread(&sc->gensc, sc->adp, uio, flag); 386} 387 388static int 389gdcioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, struct thread *td) 390{ 391 gdc_softc_t *sc; 392 393 sc = GDC_SOFTC(GDC_UNIT(dev)); 394 return genfbioctl(&sc->gensc, sc->adp, cmd, arg, flag, td); 395} 396 397static int 398gdcmmap(struct cdev *dev, vm_ooffset_t offset, vm_paddr_t *paddr, 399 int prot, vm_memattr_t *memattr) 400{ 401 gdc_softc_t *sc; 402 403 sc = GDC_SOFTC(GDC_UNIT(dev)); 404 return genfbmmap(&sc->gensc, sc->adp, offset, paddr, prot, memattr); 405} 406 407#endif /* FB_INSTALL_CDEV */ 408 409static device_method_t gdc_methods[] = { 410 DEVMETHOD(device_identify, gdc_identify), 411 DEVMETHOD(device_probe, gdcprobe), 412 DEVMETHOD(device_attach, gdc_attach), 413 { 0, 0 } 414}; 415 416static driver_t gdcdriver = { 417 DRIVER_NAME, 418 gdc_methods, 419 sizeof(gdc_softc_t), 420}; 421 422DRIVER_MODULE(gdc, isa, gdcdriver, gdc_devclass, 0, 0); 423 424/* LOW-LEVEL */ 425 426 427#include <pc98/cbus/30line.h> 428 429#define TEXT_BUF_BASE 0x000a0000 430#define TEXT_BUF_SIZE 0x00008000 431#define GRAPHICS_BUF_BASE 0x000a8000 432#define GRAPHICS_BUF_SIZE 0x00040000 433#define VIDEO_BUF_BASE 0x000a0000 434#define VIDEO_BUF_SIZE 0x00048000 435 436#define probe_done(adp) ((adp)->va_flags & V_ADP_PROBED) 437#define init_done(adp) ((adp)->va_flags & V_ADP_INITIALIZED) 438#define config_done(adp) ((adp)->va_flags & V_ADP_REGISTERED) 439 440/* 441 * NOTE: `va_window' should have a virtual address, but is initialized 442 * with a physical address in the following table, they will be 443 * converted at run-time. 444 */ 445static video_adapter_t adapter_init_value[] = { 446 { 0, 447 KD_PC98, "gdc", /* va_type, va_name */ 448 0, 0, /* va_unit, va_minor */ 449 V_ADP_COLOR | V_ADP_MODECHANGE | V_ADP_BORDER, 450 TEXT_GDC, 16, TEXT_GDC, /* va_io*, XXX */ 451 VIDEO_BUF_BASE, VIDEO_BUF_SIZE, /* va_mem* */ 452 TEXT_BUF_BASE, TEXT_BUF_SIZE, TEXT_BUF_SIZE, 0, /* va_window* */ 453 0, 0, /* va_buffer, va_buffer_size */ 454 0, M_PC98_80x25, 0, /* va_*mode* */ 455 }, 456}; 457 458static video_adapter_t biosadapter[1]; 459 460/* video driver declarations */ 461static int gdc_configure(int flags); 462static int gdc_err(video_adapter_t *adp, ...); 463static vi_probe_t gdc_probe; 464static vi_init_t gdc_init; 465static vi_get_info_t gdc_get_info; 466static vi_query_mode_t gdc_query_mode; 467static vi_set_mode_t gdc_set_mode; 468static vi_set_border_t gdc_set_border; 469static vi_save_state_t gdc_save_state; 470static vi_load_state_t gdc_load_state; 471static vi_read_hw_cursor_t gdc_read_hw_cursor; 472static vi_set_hw_cursor_t gdc_set_hw_cursor; 473static vi_set_hw_cursor_shape_t gdc_set_hw_cursor_shape; 474static vi_blank_display_t gdc_blank_display; 475static vi_mmap_t gdc_mmap_buf; 476static vi_ioctl_t gdc_dev_ioctl; 477static vi_clear_t gdc_clear; 478static vi_fill_rect_t gdc_fill_rect; 479static vi_bitblt_t gdc_bitblt; 480static vi_diag_t gdc_diag; 481static vi_save_palette_t gdc_save_palette; 482static vi_load_palette_t gdc_load_palette; 483static vi_set_win_org_t gdc_set_origin; 484 485static video_switch_t gdcvidsw = { 486 gdc_probe, 487 gdc_init, 488 gdc_get_info, 489 gdc_query_mode, 490 gdc_set_mode, 491 (vi_save_font_t *)gdc_err, 492 (vi_load_font_t *)gdc_err, 493 (vi_show_font_t *)gdc_err, 494 gdc_save_palette, 495 gdc_load_palette, 496 gdc_set_border, 497 gdc_save_state, 498 gdc_load_state, 499 gdc_set_origin, 500 gdc_read_hw_cursor, 501 gdc_set_hw_cursor, 502 gdc_set_hw_cursor_shape, 503 gdc_blank_display, 504 gdc_mmap_buf, 505 gdc_dev_ioctl, 506 gdc_clear, 507 gdc_fill_rect, 508 gdc_bitblt, 509 (int (*)(void))gdc_err, 510 (int (*)(void))gdc_err, 511 gdc_diag, 512}; 513 514VIDEO_DRIVER(gdc, gdcvidsw, gdc_configure); 515 516/* GDC BIOS standard video modes */ 517#define EOT (-1) 518#define NA (-2) 519 520static video_info_t bios_vmode[] = { 521 { M_PC98_80x25, V_INFO_COLOR, 80, 25, 8, 16, 4, 1, 522 TEXT_BUF_BASE, TEXT_BUF_SIZE, TEXT_BUF_SIZE, 0, 0, V_INFO_MM_TEXT }, 523#ifdef LINE30 524 { M_PC98_80x30, V_INFO_COLOR, 80, 30, 8, 16, 4, 1, 525 TEXT_BUF_BASE, TEXT_BUF_SIZE, TEXT_BUF_SIZE, 0, 0, V_INFO_MM_TEXT }, 526#endif 527#ifndef GDC_NOGRAPHICS 528 { M_PC98_EGC640x400, V_INFO_COLOR | V_INFO_GRAPHICS, 529 640, 400, 8, 16, 4, 4, 530 GRAPHICS_BUF_BASE, GRAPHICS_BUF_SIZE, GRAPHICS_BUF_SIZE, 0, 0, 531 V_INFO_MM_PLANAR }, 532 { M_PC98_PEGC640x400, V_INFO_COLOR | V_INFO_GRAPHICS | V_INFO_VESA, 533 640, 400, 8, 16, 8, 1, 534 GRAPHICS_BUF_BASE, 0x00008000, 0x00008000, 0, 0, 535 V_INFO_MM_PACKED, 1 }, 536#ifdef LINE30 537 { M_PC98_PEGC640x480, V_INFO_COLOR | V_INFO_GRAPHICS | V_INFO_VESA, 538 640, 480, 8, 16, 8, 1, 539 GRAPHICS_BUF_BASE, 0x00008000, 0x00008000, 0, 0, 540 V_INFO_MM_PACKED, 1 }, 541#endif 542#endif 543 { EOT }, 544}; 545 546static int gdc_init_done = FALSE; 547 548/* local functions */ 549static int map_gen_mode_num(int type, int color, int mode); 550static int probe_adapters(void); 551 552#define prologue(adp, flag, err) \ 553 if (!gdc_init_done || !((adp)->va_flags & (flag))) \ 554 return (err) 555 556/* a backdoor for the console driver */ 557static int 558gdc_configure(int flags) 559{ 560 probe_adapters(); 561 biosadapter[0].va_flags |= V_ADP_INITIALIZED; 562 if (!config_done(&biosadapter[0])) { 563 if (vid_register(&biosadapter[0]) < 0) 564 return 1; 565 biosadapter[0].va_flags |= V_ADP_REGISTERED; 566 } 567 568 return 1; 569} 570 571/* local subroutines */ 572 573/* map a generic video mode to a known mode number */ 574static int 575map_gen_mode_num(int type, int color, int mode) 576{ 577 static struct { 578 int from; 579 int to; 580 } mode_map[] = { 581 { M_TEXT_80x25, M_PC98_80x25, }, 582#ifdef LINE30 583 { M_TEXT_80x30, M_PC98_80x30, }, 584#endif 585 }; 586 int i; 587 588 for (i = 0; i < nitems(mode_map); ++i) { 589 if (mode_map[i].from == mode) 590 return mode_map[i].to; 591 } 592 return mode; 593} 594 595static int 596verify_adapter(video_adapter_t *adp) 597{ 598#ifndef GDC_NOGRAPHICS 599 int i; 600 601 if (PC98_SYSTEM_PARAMETER(0x45c) & 0x40) { /* PEGC exists */ 602 adp->va_flags |= V_ADP_VESA; /* XXX */ 603 } else { 604 for (i = 0; bios_vmode[i].vi_mode != EOT; ++i) { 605 if (bios_vmode[i].vi_flags & V_INFO_VESA) 606 bios_vmode[i].vi_mode = NA; 607 } 608 } 609#endif 610 return 0; 611} 612 613/* probe video adapters and return the number of detected adapters */ 614static int 615probe_adapters(void) 616{ 617 video_info_t info; 618 619 /* do this test only once */ 620 if (gdc_init_done) 621 return 1; 622 gdc_init_done = TRUE; 623 624 biosadapter[0] = adapter_init_value[0]; 625 biosadapter[0].va_flags |= V_ADP_PROBED; 626 biosadapter[0].va_mode = 627 biosadapter[0].va_initial_mode = biosadapter[0].va_initial_bios_mode; 628 629 if ((PC98_SYSTEM_PARAMETER(0x597) & 0x80) || 630 (PC98_SYSTEM_PARAMETER(0x458) & 0x80)) { 631 gdc_FH = (inb(0x9a8) & 1) ? _31KHZ : _24KHZ; 632 } else { 633 gdc_FH = _24KHZ; 634 } 635 636 gdc_get_info(&biosadapter[0], biosadapter[0].va_initial_mode, &info); 637 initialize_gdc(T25_G400, info.vi_flags & V_INFO_GRAPHICS); 638 639 biosadapter[0].va_window = BIOS_PADDRTOVADDR(info.vi_window); 640 biosadapter[0].va_window_size = info.vi_window_size; 641 biosadapter[0].va_window_gran = info.vi_window_gran; 642 biosadapter[0].va_buffer = 0; 643 biosadapter[0].va_buffer_size = 0; 644 if (info.vi_flags & V_INFO_GRAPHICS) { 645 switch (info.vi_depth/info.vi_planes) { 646 case 1: 647 biosadapter[0].va_line_width = info.vi_width/8; 648 break; 649 case 2: 650 biosadapter[0].va_line_width = info.vi_width/4; 651 break; 652 case 4: 653 biosadapter[0].va_line_width = info.vi_width/2; 654 break; 655 case 8: 656 default: /* shouldn't happen */ 657 biosadapter[0].va_line_width = info.vi_width; 658 break; 659 } 660 } else { 661 biosadapter[0].va_line_width = info.vi_width; 662 } 663 bcopy(&info, &biosadapter[0].va_info, sizeof(info)); 664 665 verify_adapter(&biosadapter[0]); 666 667 return 1; 668} 669 670static void master_gdc_cmd(unsigned int cmd) 671{ 672 while ( (inb(TEXT_GDC) & 2) != 0); 673 outb(TEXT_GDC+2, cmd); 674} 675 676static void master_gdc_prm(unsigned int pmtr) 677{ 678 while ( (inb(TEXT_GDC) & 2) != 0); 679 outb(TEXT_GDC, pmtr); 680} 681 682static void master_gdc_word_prm(unsigned int wpmtr) 683{ 684 master_gdc_prm(wpmtr & 0x00ff); 685 master_gdc_prm((wpmtr >> 8) & 0x00ff); 686} 687 688#ifdef LINE30 689static void master_gdc_fifo_empty(void) 690{ 691 while ( (inb(TEXT_GDC) & 4) == 0); 692} 693#endif 694 695static void master_gdc_wait_vsync(void) 696{ 697 while ( (inb(TEXT_GDC) & 0x20) != 0); 698 while ( (inb(TEXT_GDC) & 0x20) == 0); 699} 700 701static void gdc_cmd(unsigned int cmd) 702{ 703 while ( (inb(GRAPHIC_GDC) & 2) != 0); 704 outb( GRAPHIC_GDC+2, cmd); 705} 706 707#ifdef LINE30 708static void gdc_prm(unsigned int pmtr) 709{ 710 while ( (inb(GRAPHIC_GDC) & 2) != 0); 711 outb( GRAPHIC_GDC, pmtr); 712} 713 714static void gdc_word_prm(unsigned int wpmtr) 715{ 716 gdc_prm(wpmtr & 0x00ff); 717 gdc_prm((wpmtr >> 8) & 0x00ff); 718} 719 720static void gdc_fifo_empty(void) 721{ 722 while ( (inb(GRAPHIC_GDC) & 0x04) == 0); 723} 724#endif 725 726static void gdc_wait_vsync(void) 727{ 728 while ( (inb(GRAPHIC_GDC) & 0x20) != 0); 729 while ( (inb(GRAPHIC_GDC) & 0x20) == 0); 730} 731 732#ifdef LINE30 733static int check_gdc_clock(void) 734{ 735 if ((inb(IO_SYSPORT) & 0x80) == 0){ 736 return _5MHZ; 737 } else { 738 return _2_5MHZ; 739 } 740} 741#endif 742 743static void initialize_gdc(unsigned int mode, int isGraph) 744{ 745#ifdef LINE30 746 /* start 30line initialize */ 747 int m_mode, s_mode, gdc_clock, hsync_clock; 748 749 gdc_clock = check_gdc_clock(); 750 m_mode = (mode == T25_G400) ? _25L : _30L; 751 s_mode = 2*mode+gdc_clock; 752 gdc_INFO = m_mode; 753 754 master_gdc_wait_vsync(); 755 756 if ((PC98_SYSTEM_PARAMETER(0x597) & 0x80) || 757 (PC98_SYSTEM_PARAMETER(0x458) & 0x80)) { 758 if (PC98_SYSTEM_PARAMETER(0x481) & 0x08) { 759 hsync_clock = (m_mode == _25L) ? gdc_FH : _31KHZ; 760 outb(0x9a8, (hsync_clock == _31KHZ) ? 1 : 0); 761 } else { 762 hsync_clock = gdc_FH; 763 } 764 } else { 765 hsync_clock = _24KHZ; 766 } 767 768 if ((gdc_clock == _2_5MHZ) && 769 (slave_param[hsync_clock][s_mode][GDC_LF] > 400)) { 770 outb(0x6a, 0x83); 771 outb(0x6a, 0x85); 772 gdc_clock = _5MHZ; 773 s_mode = 2*mode+gdc_clock; 774 } 775 776 master_gdc_cmd(_GDC_RESET); 777 master_gdc_cmd(_GDC_MASTER); 778 gdc_cmd(_GDC_RESET); 779 gdc_cmd(_GDC_SLAVE); 780 781 /* GDC Master */ 782 master_gdc_cmd(_GDC_SYNC); 783 master_gdc_prm(0x00); /* flush less */ /* text & graph */ 784 master_gdc_prm(master_param[hsync_clock][m_mode][GDC_CR]); 785 master_gdc_word_prm(((master_param[hsync_clock][m_mode][GDC_HFP] << 10) 786 + (master_param[hsync_clock][m_mode][GDC_VS] << 5) 787 + master_param[hsync_clock][m_mode][GDC_HS])); 788 master_gdc_prm(master_param[hsync_clock][m_mode][GDC_HBP]); 789 master_gdc_prm(master_param[hsync_clock][m_mode][GDC_VFP]); 790 master_gdc_word_prm(((master_param[hsync_clock][m_mode][GDC_VBP] << 10) 791 + (master_param[hsync_clock][m_mode][GDC_LF]))); 792 master_gdc_fifo_empty(); 793 master_gdc_cmd(_GDC_PITCH); 794 master_gdc_prm(MasterPCH); 795 master_gdc_fifo_empty(); 796 797 /* GDC slave */ 798 gdc_cmd(_GDC_SYNC); 799 gdc_prm(0x06); 800 gdc_prm(slave_param[hsync_clock][s_mode][GDC_CR]); 801 gdc_word_prm((slave_param[hsync_clock][s_mode][GDC_HFP] << 10) 802 + (slave_param[hsync_clock][s_mode][GDC_VS] << 5) 803 + (slave_param[hsync_clock][s_mode][GDC_HS])); 804 gdc_prm(slave_param[hsync_clock][s_mode][GDC_HBP]); 805 gdc_prm(slave_param[hsync_clock][s_mode][GDC_VFP]); 806 gdc_word_prm((slave_param[hsync_clock][s_mode][GDC_VBP] << 10) 807 + (slave_param[hsync_clock][s_mode][GDC_LF])); 808 gdc_fifo_empty(); 809 gdc_cmd(_GDC_PITCH); 810 gdc_prm(SlavePCH[gdc_clock]); 811 gdc_fifo_empty(); 812 813 /* set Master GDC scroll param */ 814 master_gdc_wait_vsync(); 815 master_gdc_wait_vsync(); 816 master_gdc_wait_vsync(); 817 master_gdc_cmd(_GDC_SCROLL); 818 master_gdc_word_prm(0); 819 master_gdc_word_prm((master_param[hsync_clock][m_mode][GDC_LF] << 4) 820 | 0x0000); 821 master_gdc_fifo_empty(); 822 823 /* set Slave GDC scroll param */ 824 gdc_wait_vsync(); 825 gdc_cmd(_GDC_SCROLL); 826 gdc_word_prm(0); 827 if (gdc_clock == _5MHZ) { 828 gdc_word_prm((SlaveScrlLF[mode] << 4) | 0x4000); 829 } else { 830 gdc_word_prm(SlaveScrlLF[mode] << 4); 831 } 832 gdc_fifo_empty(); 833 834 gdc_word_prm(0); 835 if (gdc_clock == _5MHZ) { 836 gdc_word_prm((SlaveScrlLF[mode] << 4) | 0x4000); 837 } else { 838 gdc_word_prm(SlaveScrlLF[mode] << 4); 839 } 840 gdc_fifo_empty(); 841 842 /* sync start */ 843 gdc_cmd(isGraph ? _GDC_START : _GDC_STOP); 844 845 gdc_wait_vsync(); 846 gdc_wait_vsync(); 847 gdc_wait_vsync(); 848 849 master_gdc_cmd(isGraph ? _GDC_STOP : _GDC_START); 850#else 851 master_gdc_wait_vsync(); 852 master_gdc_cmd(isGraph ? _GDC_STOP : _GDC_START); /* text */ 853 gdc_wait_vsync(); 854 gdc_cmd(isGraph ? _GDC_START : _GDC_STOP); /* graphics */ 855#endif 856} 857 858#ifndef GDC_NOGRAPHICS 859static u_char b_palette[] = { 860 /* R G B */ 861 0x00, 0x00, 0x00, /* 0 */ 862 0x00, 0x00, 0x7f, /* 1 */ 863 0x7f, 0x00, 0x00, /* 2 */ 864 0x7f, 0x00, 0x7f, /* 3 */ 865 0x00, 0x7f, 0x00, /* 4 */ 866 0x00, 0x7f, 0x7f, /* 5 */ 867 0x7f, 0x7f, 0x00, /* 6 */ 868 0x7f, 0x7f, 0x7f, /* 7 */ 869 0x40, 0x40, 0x40, /* 8 */ 870 0x00, 0x00, 0xff, /* 9 */ 871 0xff, 0x00, 0x00, /* 10 */ 872 0xff, 0x00, 0xff, /* 11 */ 873 0x00, 0xff, 0x00, /* 12 */ 874 0x00, 0xff, 0xff, /* 13 */ 875 0xff, 0xff, 0x00, /* 14 */ 876 0xff, 0xff, 0xff, /* 15 */ 877}; 878#endif 879 880static int 881gdc_load_palette(video_adapter_t *adp, u_char *palette) 882{ 883#ifndef GDC_NOGRAPHICS 884 int i; 885 886 if (adp->va_info.vi_flags & V_INFO_VESA) { 887 gdc_wait_vsync(); 888 for (i = 0; i < 256; ++i) { 889 outb(0xa8, i); 890 outb(0xac, *palette++); /* R */ 891 outb(0xaa, *palette++); /* G */ 892 outb(0xae, *palette++); /* B */ 893 } 894 } else { 895 /* 896 * XXX - Even though PC-98 text color is independent of palette, 897 * we should set palette in text mode. 898 * Because the background color of text mode is palette 0's one. 899 */ 900 outb(0x6a, 1); /* 16 colors mode */ 901 bcopy(palette, b_palette, sizeof(b_palette)); 902 903 gdc_wait_vsync(); 904 for (i = 0; i < 16; ++i) { 905 outb(0xa8, i); 906 outb(0xac, *palette++ >> 4); /* R */ 907 outb(0xaa, *palette++ >> 4); /* G */ 908 outb(0xae, *palette++ >> 4); /* B */ 909 } 910 } 911#endif 912 return 0; 913} 914 915static int 916gdc_save_palette(video_adapter_t *adp, u_char *palette) 917{ 918#ifndef GDC_NOGRAPHICS 919 int i; 920 921 if (adp->va_info.vi_flags & V_INFO_VESA) { 922 for (i = 0; i < 256; ++i) { 923 outb(0xa8, i); 924 *palette++ = inb(0xac); /* R */ 925 *palette++ = inb(0xaa); /* G */ 926 *palette++ = inb(0xae); /* B */ 927 } 928 } else { 929 bcopy(b_palette, palette, sizeof(b_palette)); 930 } 931#endif 932 return 0; 933} 934 935static int 936gdc_set_origin(video_adapter_t *adp, off_t offset) 937{ 938#ifndef GDC_NOGRAPHICS 939 if (adp->va_info.vi_flags & V_INFO_VESA) { 940 writew(BIOS_PADDRTOVADDR(0x000e0004), offset >> 15); 941 } 942#endif 943 return 0; 944} 945 946/* entry points */ 947 948static int 949gdc_err(video_adapter_t *adp, ...) 950{ 951 return ENODEV; 952} 953 954static int 955gdc_probe(int unit, video_adapter_t **adpp, void *arg, int flags) 956{ 957 probe_adapters(); 958 if (unit >= 1) 959 return ENXIO; 960 961 *adpp = &biosadapter[unit]; 962 963 return 0; 964} 965 966static int 967gdc_init(int unit, video_adapter_t *adp, int flags) 968{ 969 if ((unit >= 1) || (adp == NULL) || !probe_done(adp)) 970 return ENXIO; 971 972 if (!init_done(adp)) { 973 /* nothing to do really... */ 974 adp->va_flags |= V_ADP_INITIALIZED; 975 } 976 977 if (!config_done(adp)) { 978 if (vid_register(adp) < 0) 979 return ENXIO; 980 adp->va_flags |= V_ADP_REGISTERED; 981 } 982 983 return 0; 984} 985 986/* 987 * get_info(): 988 * Return the video_info structure of the requested video mode. 989 */ 990static int 991gdc_get_info(video_adapter_t *adp, int mode, video_info_t *info) 992{ 993 int i; 994 995 if (!gdc_init_done) 996 return ENXIO; 997 998 mode = map_gen_mode_num(adp->va_type, adp->va_flags & V_ADP_COLOR, mode); 999 for (i = 0; bios_vmode[i].vi_mode != EOT; ++i) { 1000 if (bios_vmode[i].vi_mode == NA) 1001 continue; 1002 if (mode == bios_vmode[i].vi_mode) { 1003 *info = bios_vmode[i]; 1004 info->vi_buffer_size = info->vi_window_size*info->vi_planes; 1005 return 0; 1006 } 1007 } 1008 return EINVAL; 1009} 1010 1011/* 1012 * query_mode(): 1013 * Find a video mode matching the requested parameters. 1014 * Fields filled with 0 are considered "don't care" fields and 1015 * match any modes. 1016 */ 1017static int 1018gdc_query_mode(video_adapter_t *adp, video_info_t *info) 1019{ 1020 int i; 1021 1022 if (!gdc_init_done) 1023 return ENXIO; 1024 1025 for (i = 0; bios_vmode[i].vi_mode != EOT; ++i) { 1026 if (bios_vmode[i].vi_mode == NA) 1027 continue; 1028 1029 if ((info->vi_width != 0) 1030 && (info->vi_width != bios_vmode[i].vi_width)) 1031 continue; 1032 if ((info->vi_height != 0) 1033 && (info->vi_height != bios_vmode[i].vi_height)) 1034 continue; 1035 if ((info->vi_cwidth != 0) 1036 && (info->vi_cwidth != bios_vmode[i].vi_cwidth)) 1037 continue; 1038 if ((info->vi_cheight != 0) 1039 && (info->vi_cheight != bios_vmode[i].vi_cheight)) 1040 continue; 1041 if ((info->vi_depth != 0) 1042 && (info->vi_depth != bios_vmode[i].vi_depth)) 1043 continue; 1044 if ((info->vi_planes != 0) 1045 && (info->vi_planes != bios_vmode[i].vi_planes)) 1046 continue; 1047 /* XXX: should check pixel format, memory model */ 1048 if ((info->vi_flags != 0) 1049 && (info->vi_flags != bios_vmode[i].vi_flags)) 1050 continue; 1051 1052 /* verify if this mode is supported on this adapter */ 1053 if (gdc_get_info(adp, bios_vmode[i].vi_mode, info)) 1054 continue; 1055 return 0; 1056 } 1057 return ENODEV; 1058} 1059 1060/* 1061 * set_mode(): 1062 * Change the video mode. 1063 */ 1064static int 1065gdc_set_mode(video_adapter_t *adp, int mode) 1066{ 1067 video_info_t info; 1068 1069 prologue(adp, V_ADP_MODECHANGE, ENODEV); 1070 1071 mode = map_gen_mode_num(adp->va_type, 1072 adp->va_flags & V_ADP_COLOR, mode); 1073 if (gdc_get_info(adp, mode, &info)) 1074 return EINVAL; 1075 1076 switch (info.vi_mode) { 1077#ifndef GDC_NOGRAPHICS 1078 case M_PC98_PEGC640x480: /* PEGC 640x480 */ 1079 initialize_gdc(T30_G480, info.vi_flags & V_INFO_GRAPHICS); 1080 break; 1081 case M_PC98_PEGC640x400: /* PEGC 640x400 */ 1082 case M_PC98_EGC640x400: /* EGC GRAPHICS */ 1083#endif 1084 case M_PC98_80x25: /* VGA TEXT */ 1085 initialize_gdc(T25_G400, info.vi_flags & V_INFO_GRAPHICS); 1086 break; 1087 case M_PC98_80x30: /* VGA TEXT */ 1088 initialize_gdc(T30_G400, info.vi_flags & V_INFO_GRAPHICS); 1089 break; 1090 default: 1091 break; 1092 } 1093 1094#ifndef GDC_NOGRAPHICS 1095 if (info.vi_flags & V_INFO_VESA) { 1096 outb(0x6a, 0x07); /* enable mode F/F change */ 1097 outb(0x6a, 0x21); /* enhanced graphics */ 1098 if (info.vi_height > 400) 1099 outb(0x6a, 0x69); /* 800 lines */ 1100 writeb(BIOS_PADDRTOVADDR(0x000e0100), 0); /* packed pixel */ 1101 } else { 1102 if (adp->va_flags & V_ADP_VESA) { 1103 outb(0x6a, 0x07); /* enable mode F/F change */ 1104 outb(0x6a, 0x20); /* normal graphics */ 1105 outb(0x6a, 0x68); /* 400 lines */ 1106 } 1107 outb(0x6a, 1); /* 16 colors */ 1108 } 1109#endif 1110 1111 adp->va_mode = mode; 1112 adp->va_flags &= ~V_ADP_COLOR; 1113 adp->va_flags |= 1114 (info.vi_flags & V_INFO_COLOR) ? V_ADP_COLOR : 0; 1115#if 0 1116 adp->va_crtc_addr = 1117 (adp->va_flags & V_ADP_COLOR) ? COLOR_CRTC : MONO_CRTC; 1118#endif 1119 adp->va_window = BIOS_PADDRTOVADDR(info.vi_window); 1120 adp->va_window_size = info.vi_window_size; 1121 adp->va_window_gran = info.vi_window_gran; 1122 if (info.vi_buffer_size == 0) { 1123 adp->va_buffer = 0; 1124 adp->va_buffer_size = 0; 1125 } else { 1126 adp->va_buffer = BIOS_PADDRTOVADDR(info.vi_buffer); 1127 adp->va_buffer_size = info.vi_buffer_size; 1128 } 1129 if (info.vi_flags & V_INFO_GRAPHICS) { 1130 switch (info.vi_depth/info.vi_planes) { 1131 case 1: 1132 adp->va_line_width = info.vi_width/8; 1133 break; 1134 case 2: 1135 adp->va_line_width = info.vi_width/4; 1136 break; 1137 case 4: 1138 adp->va_line_width = info.vi_width/2; 1139 break; 1140 case 8: 1141 default: /* shouldn't happen */ 1142 adp->va_line_width = info.vi_width; 1143 break; 1144 } 1145 } else { 1146 adp->va_line_width = info.vi_width; 1147 } 1148 bcopy(&info, &adp->va_info, sizeof(info)); 1149 1150 /* move hardware cursor out of the way */ 1151 vidd_set_hw_cursor(adp, -1, -1); 1152 1153 return 0; 1154} 1155 1156/* 1157 * set_border(): 1158 * Change the border color. 1159 */ 1160static int 1161gdc_set_border(video_adapter_t *adp, int color) 1162{ 1163 outb(0x6c, color << 4); 1164 return 0; 1165} 1166 1167/* 1168 * save_state(): 1169 * Read video card register values. 1170 */ 1171static int 1172gdc_save_state(video_adapter_t *adp, void *p, size_t size) 1173{ 1174 return ENODEV; 1175} 1176 1177/* 1178 * load_state(): 1179 * Set video card registers at once. 1180 */ 1181static int 1182gdc_load_state(video_adapter_t *adp, void *p) 1183{ 1184 return ENODEV; 1185} 1186 1187/* 1188 * read_hw_cursor(): 1189 * Read the position of the hardware text cursor. 1190 */ 1191static int 1192gdc_read_hw_cursor(video_adapter_t *adp, int *col, int *row) 1193{ 1194 u_int16_t off; 1195 int s; 1196 1197 if (!gdc_init_done) 1198 return ENXIO; 1199 1200 if (adp->va_info.vi_flags & V_INFO_GRAPHICS) 1201 return ENODEV; 1202 1203 s = spltty(); 1204 master_gdc_cmd(0xe0); /* _GDC_CSRR */ 1205 while((inb(TEXT_GDC + 0) & 0x1) == 0) {} /* GDC wait */ 1206 off = inb(TEXT_GDC + 2); /* EADl */ 1207 off |= (inb(TEXT_GDC + 2) << 8); /* EADh */ 1208 inb(TEXT_GDC + 2); /* dummy */ 1209 inb(TEXT_GDC + 2); /* dummy */ 1210 inb(TEXT_GDC + 2); /* dummy */ 1211 splx(s); 1212 1213 if (off >= ROW*COL) 1214 off = 0; 1215 *row = off / adp->va_info.vi_width; 1216 *col = off % adp->va_info.vi_width; 1217 1218 return 0; 1219} 1220 1221/* 1222 * set_hw_cursor(): 1223 * Move the hardware text cursor. If col and row are both -1, 1224 * the cursor won't be shown. 1225 */ 1226static int 1227gdc_set_hw_cursor(video_adapter_t *adp, int col, int row) 1228{ 1229 u_int16_t off; 1230 int s; 1231 1232 if (!gdc_init_done) 1233 return ENXIO; 1234 1235 if ((col == -1) && (row == -1)) { 1236 off = -1; 1237 } else { 1238 if (adp->va_info.vi_flags & V_INFO_GRAPHICS) 1239 return ENODEV; 1240 off = row*adp->va_info.vi_width + col; 1241 } 1242 1243 s = spltty(); 1244 master_gdc_cmd(0x49); /* _GDC_CSRW */ 1245 master_gdc_word_prm(off); 1246 splx(s); 1247 1248 return 0; 1249} 1250 1251/* 1252 * set_hw_cursor_shape(): 1253 * Change the shape of the hardware text cursor. If the height is zero 1254 * or negative, the cursor won't be shown. 1255 */ 1256static int 1257gdc_set_hw_cursor_shape(video_adapter_t *adp, int base, int height, 1258 int celsize, int blink) 1259{ 1260 int start; 1261 int end; 1262 int s; 1263 1264 if (!gdc_init_done) 1265 return ENXIO; 1266 1267 start = celsize - (base + height); 1268 end = celsize - base - 1; 1269 1270#if 0 1271 /* 1272 * muPD7220 GDC has anomaly that if end == celsize - 1 then start 1273 * must be 0, otherwise the cursor won't be correctly shown 1274 * in the first row in the screen. We shall set end to celsize - 2; 1275 * if end == celsize -1 && start > 0. XXX 1276 */ 1277 if ((end == celsize - 1) && (start > 0) && (start < end)) 1278 --end; 1279#endif 1280 1281 s = spltty(); 1282 master_gdc_cmd(0x4b); /* _GDC_CSRFORM */ 1283 master_gdc_prm(((height > 0) ? 0x80 : 0) /* cursor on/off */ 1284 | ((celsize - 1) & 0x1f)); /* cel size */ 1285 master_gdc_word_prm(((end & 0x1f) << 11) /* end line */ 1286 | (12 << 6) /* blink rate */ 1287 | (blink ? 0 : 0x20) /* blink on/off */ 1288 | (start & 0x1f)); /* start line */ 1289 splx(s); 1290 1291 return 0; 1292} 1293 1294/* 1295 * blank_display() 1296 * Put the display in power save/power off mode. 1297 */ 1298static int 1299gdc_blank_display(video_adapter_t *adp, int mode) 1300{ 1301 int s; 1302 static int standby = 0; 1303 1304 if (!gdc_init_done) 1305 return ENXIO; 1306 1307 s = splhigh(); 1308 switch (mode) { 1309 case V_DISPLAY_SUSPEND: 1310 case V_DISPLAY_STAND_BY: 1311 outb(0x09a2, 0x80 | 0x40); /* V/H-SYNC mask */ 1312 if (inb(0x09a2) == (0x80 | 0x40)) 1313 standby = 1; 1314 /* FALLTHROUGH */ 1315 1316 case V_DISPLAY_BLANK: 1317 while (!(inb(TEXT_GDC) & 0x20)) /* V-SYNC wait */ 1318 ; 1319 outb(TEXT_GDC + 8, 0x0e); /* DISP off */ 1320 break; 1321 1322 case V_DISPLAY_ON: 1323 while (!(inb(TEXT_GDC) & 0x20)) /* V-SYNC wait */ 1324 ; 1325 outb(TEXT_GDC + 8, 0x0f); /* DISP on */ 1326 if (standby) { 1327 outb(0x09a2, 0x00); /* V/H-SYNC unmask */ 1328 standby = 0; 1329 } 1330 break; 1331 } 1332 splx(s); 1333 return 0; 1334} 1335 1336/* 1337 * mmap(): 1338 * Mmap frame buffer. 1339 */ 1340static int 1341gdc_mmap_buf(video_adapter_t *adp, vm_ooffset_t offset, vm_offset_t *paddr, 1342 int prot, vm_memattr_t *memattr) 1343{ 1344 /* FIXME: is this correct? XXX */ 1345 if (offset > VIDEO_BUF_SIZE - PAGE_SIZE) 1346 return -1; 1347 *paddr = adp->va_info.vi_window + offset; 1348 return 0; 1349} 1350 1351#ifndef GDC_NOGRAPHICS 1352static void 1353planar_fill(video_adapter_t *adp, int val) 1354{ 1355 1356 outb(0x7c, 0x80); /* GRCG on & TDW mode */ 1357 outb(0x7e, 0); /* tile B */ 1358 outb(0x7e, 0); /* tile R */ 1359 outb(0x7e, 0); /* tile G */ 1360 outb(0x7e, 0); /* tile I */ 1361 1362 fillw_io(0, adp->va_window, 0x8000 / 2); /* XXX */ 1363 1364 outb(0x7c, 0); /* GRCG off */ 1365} 1366 1367static void 1368packed_fill(video_adapter_t *adp, int val) 1369{ 1370 int length; 1371 int at; /* position in the frame buffer */ 1372 int l; 1373 1374 at = 0; 1375 length = adp->va_line_width*adp->va_info.vi_height; 1376 while (length > 0) { 1377 l = imin(length, adp->va_window_size); 1378 vidd_set_win_org(adp, at); 1379 bzero_io(adp->va_window, l); 1380 length -= l; 1381 at += l; 1382 } 1383} 1384 1385static int 1386gdc_clear(video_adapter_t *adp) 1387{ 1388 1389 switch (adp->va_info.vi_mem_model) { 1390 case V_INFO_MM_TEXT: 1391 /* do nothing? XXX */ 1392 break; 1393 case V_INFO_MM_PLANAR: 1394 planar_fill(adp, 0); 1395 break; 1396 case V_INFO_MM_PACKED: 1397 packed_fill(adp, 0); 1398 break; 1399 } 1400 1401 return 0; 1402} 1403#else /* GDC_NOGRAPHICS */ 1404static int 1405gdc_clear(video_adapter_t *adp) 1406{ 1407 1408 return 0; 1409} 1410#endif /* GDC_NOGRAPHICS */ 1411 1412static int 1413gdc_fill_rect(video_adapter_t *adp, int val, int x, int y, int cx, int cy) 1414{ 1415 return ENODEV; 1416} 1417 1418static int 1419gdc_bitblt(video_adapter_t *adp,...) 1420{ 1421 /* FIXME */ 1422 return ENODEV; 1423} 1424 1425static int 1426gdc_dev_ioctl(video_adapter_t *adp, u_long cmd, caddr_t arg) 1427{ 1428 switch (cmd) { 1429 case FBIO_GETWINORG: /* get frame buffer window origin */ 1430 *(u_int *)arg = 0; 1431 return 0; 1432 1433 case FBIO_SETWINORG: /* set frame buffer window origin */ 1434 case FBIO_SETDISPSTART: /* set display start address */ 1435 case FBIO_SETLINEWIDTH: /* set scan line length in pixel */ 1436 case FBIO_GETPALETTE: /* get color palette */ 1437 case FBIO_SETPALETTE: /* set color palette */ 1438 case FBIOGETCMAP: /* get color palette */ 1439 case FBIOPUTCMAP: /* set color palette */ 1440 return ENODEV; 1441 1442 case FBIOGTYPE: /* get frame buffer type info. */ 1443 ((struct fbtype *)arg)->fb_type = fb_type(adp->va_type); 1444 ((struct fbtype *)arg)->fb_height = adp->va_info.vi_height; 1445 ((struct fbtype *)arg)->fb_width = adp->va_info.vi_width; 1446 ((struct fbtype *)arg)->fb_depth = adp->va_info.vi_depth; 1447 if ((adp->va_info.vi_depth <= 1) || (adp->va_info.vi_depth > 8)) 1448 ((struct fbtype *)arg)->fb_cmsize = 0; 1449 else 1450 ((struct fbtype *)arg)->fb_cmsize = 1 << adp->va_info.vi_depth; 1451 ((struct fbtype *)arg)->fb_size = adp->va_buffer_size; 1452 return 0; 1453 1454 default: 1455 return fb_commonioctl(adp, cmd, arg); 1456 } 1457} 1458 1459/* 1460 * diag(): 1461 * Print some information about the video adapter and video modes, 1462 * with requested level of details. 1463 */ 1464static int 1465gdc_diag(video_adapter_t *adp, int level) 1466{ 1467#if defined(FB_DEBUG) && FB_DEBUG > 1 1468 int i; 1469#endif 1470 1471 if (!gdc_init_done) 1472 return ENXIO; 1473 1474 fb_dump_adp_info(DRIVER_NAME, adp, level); 1475 1476#if defined(FB_DEBUG) && FB_DEBUG > 1 1477 for (i = 0; bios_vmode[i].vi_mode != EOT; ++i) { 1478 if (bios_vmode[i].vi_mode == NA) 1479 continue; 1480 if (get_mode_param(bios_vmode[i].vi_mode) == NULL) 1481 continue; 1482 fb_dump_mode_info(DRIVER_NAME, adp, &bios_vmode[i], level); 1483 } 1484#endif 1485 1486 return 0; 1487} 1488