7ac40f5f59
branches: Initialize struct cdevsw using C99 sparse initializtion and remove all initializations to default values. This patch is automatically generated and has been tested by compiling LINT with all the fields in struct cdevsw in reverse order on alpha, sparc64 and i386. Approved by: re(scottl)
1444 lines
34 KiB
C
1444 lines
34 KiB
C
/*
|
|
* Copyright (c) 1999 FreeBSD(98) port team.
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer as
|
|
* the first lines of this file unmodified.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
* 3. The name of the author may not be used to endorse or promote products
|
|
* derived from this software without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
|
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*
|
|
* $FreeBSD$
|
|
*/
|
|
|
|
#include "opt_gdc.h"
|
|
#include "opt_fb.h"
|
|
#include "opt_syscons.h"
|
|
|
|
#include <sys/param.h>
|
|
#include <sys/systm.h>
|
|
#include <sys/kernel.h>
|
|
#include <sys/conf.h>
|
|
#include <sys/bus.h>
|
|
#include <machine/bus.h>
|
|
#include <sys/rman.h>
|
|
#include <machine/resource.h>
|
|
|
|
#include <sys/fbio.h>
|
|
#include <sys/fcntl.h>
|
|
|
|
#include <vm/vm.h>
|
|
#include <vm/pmap.h>
|
|
|
|
#include <machine/md_var.h>
|
|
#include <machine/pc/bios.h>
|
|
|
|
#include <dev/fb/fbreg.h>
|
|
|
|
#ifdef LINE30
|
|
#include <pc98/pc98/pc98.h>
|
|
#endif
|
|
#include <pc98/pc98/pc98_machdep.h>
|
|
#include <isa/isavar.h>
|
|
|
|
#define TEXT_GDC 0x60
|
|
#define GRAPHIC_GDC 0xa0
|
|
#define ROW 25
|
|
#define COL 80
|
|
|
|
#define DRIVER_NAME "gdc"
|
|
|
|
/* cdev driver declaration */
|
|
|
|
#define GDC_UNIT(dev) minor(dev)
|
|
#define GDC_MKMINOR(unit) (unit)
|
|
|
|
typedef struct gdc_softc {
|
|
video_adapter_t *adp;
|
|
struct resource *res_tgdc, *res_ggdc;
|
|
struct resource *res_egc, *res_pegc, *res_grcg, *res_kcg;
|
|
struct resource *res_tmem, *res_gmem1, *res_gmem2;
|
|
#ifdef FB_INSTALL_CDEV
|
|
genfb_softc_t gensc;
|
|
#endif
|
|
} gdc_softc_t;
|
|
|
|
#define GDC_SOFTC(unit) \
|
|
((gdc_softc_t *)devclass_get_softc(gdc_devclass, unit))
|
|
|
|
static bus_addr_t gdc_iat[] = {0, 2, 4, 6, 8, 10, 12, 14};
|
|
|
|
static devclass_t gdc_devclass;
|
|
|
|
static int gdc_probe_unit(int unit, gdc_softc_t *sc, int flags);
|
|
static int gdc_attach_unit(int unit, gdc_softc_t *sc, int flags);
|
|
static int gdc_alloc_resource(device_t dev);
|
|
static int gdc_release_resource(device_t dev);
|
|
|
|
#if FB_INSTALL_CDEV
|
|
|
|
static d_open_t gdcopen;
|
|
static d_close_t gdcclose;
|
|
static d_read_t gdcread;
|
|
static d_write_t gdcwrite;
|
|
static d_ioctl_t gdcioctl;
|
|
static d_mmap_t gdcmmap;
|
|
|
|
static struct cdevsw gdc_cdevsw = {
|
|
.d_open = gdcopen,
|
|
.d_close = gdcclose,
|
|
.d_read = gdcread,
|
|
.d_write = gdcwrite,
|
|
.d_ioctl = gdcioctl,
|
|
.d_mmap = gdcmmap,
|
|
.d_name = DRIVER_NAME,
|
|
.d_maj = -1,
|
|
};
|
|
|
|
#endif /* FB_INSTALL_CDEV */
|
|
|
|
static void
|
|
gdc_identify(driver_t *driver, device_t parent)
|
|
{
|
|
BUS_ADD_CHILD(parent, ISA_ORDER_SPECULATIVE, DRIVER_NAME, 0);
|
|
}
|
|
|
|
static int
|
|
gdcprobe(device_t dev)
|
|
{
|
|
int error;
|
|
|
|
/* Check isapnp ids */
|
|
if (isa_get_vendorid(dev))
|
|
return (ENXIO);
|
|
|
|
device_set_desc(dev, "Generic GDC");
|
|
|
|
error = gdc_alloc_resource(dev);
|
|
if (error)
|
|
return (error);
|
|
|
|
error = gdc_probe_unit(device_get_unit(dev),
|
|
device_get_softc(dev),
|
|
device_get_flags(dev));
|
|
|
|
gdc_release_resource(dev);
|
|
|
|
return (error);
|
|
}
|
|
|
|
static int
|
|
gdc_attach(device_t dev)
|
|
{
|
|
gdc_softc_t *sc;
|
|
int error;
|
|
|
|
error = gdc_alloc_resource(dev);
|
|
if (error)
|
|
return (error);
|
|
|
|
sc = device_get_softc(dev);
|
|
error = gdc_attach_unit(device_get_unit(dev),
|
|
sc,
|
|
device_get_flags(dev));
|
|
if (error) {
|
|
gdc_release_resource(dev);
|
|
return error;
|
|
}
|
|
|
|
#ifdef FB_INSTALL_CDEV
|
|
/* attach a virtual frame buffer device */
|
|
error = fb_attach(makedev(0, GDC_MKMINOR(device_get_unit(dev))),
|
|
sc->adp, &gdc_cdevsw);
|
|
if (error) {
|
|
gdc_release_resource(dev);
|
|
return error;
|
|
}
|
|
#endif /* FB_INSTALL_CDEV */
|
|
|
|
if (bootverbose)
|
|
(*vidsw[sc->adp->va_index]->diag)(sc->adp, bootverbose);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
gdc_probe_unit(int unit, gdc_softc_t *sc, int flags)
|
|
{
|
|
video_switch_t *sw;
|
|
|
|
sw = vid_get_switch(DRIVER_NAME);
|
|
if (sw == NULL)
|
|
return ENXIO;
|
|
return (*sw->probe)(unit, &sc->adp, NULL, flags);
|
|
}
|
|
|
|
static int
|
|
gdc_attach_unit(int unit, gdc_softc_t *sc, int flags)
|
|
{
|
|
video_switch_t *sw;
|
|
|
|
sw = vid_get_switch(DRIVER_NAME);
|
|
if (sw == NULL)
|
|
return ENXIO;
|
|
return (*sw->init)(unit, sc->adp, flags);
|
|
}
|
|
|
|
|
|
static int
|
|
gdc_alloc_resource(device_t dev)
|
|
{
|
|
int rid;
|
|
gdc_softc_t *sc;
|
|
|
|
sc = device_get_softc(dev);
|
|
|
|
/* TEXT GDC */
|
|
rid = 0;
|
|
bus_set_resource(dev, SYS_RES_IOPORT, rid, TEXT_GDC, 1);
|
|
sc->res_tgdc = isa_alloc_resourcev(dev, SYS_RES_IOPORT, &rid,
|
|
gdc_iat, 8, RF_ACTIVE);
|
|
if (sc->res_tgdc == NULL) {
|
|
gdc_release_resource(dev);
|
|
return (ENXIO);
|
|
}
|
|
isa_load_resourcev(sc->res_tgdc, gdc_iat, 8);
|
|
|
|
/* GRAPHIC GDC */
|
|
rid = 8;
|
|
bus_set_resource(dev, SYS_RES_IOPORT, rid, GRAPHIC_GDC, 1);
|
|
sc->res_ggdc = isa_alloc_resourcev(dev, SYS_RES_IOPORT, &rid,
|
|
gdc_iat, 8, RF_ACTIVE);
|
|
if (sc->res_ggdc == NULL) {
|
|
gdc_release_resource(dev);
|
|
return (ENXIO);
|
|
}
|
|
isa_load_resourcev(sc->res_ggdc, gdc_iat, 8);
|
|
|
|
/* EGC */
|
|
rid = 16;
|
|
bus_set_resource(dev, SYS_RES_IOPORT, rid, 0x4a0, 1);
|
|
sc->res_egc = isa_alloc_resourcev(dev, SYS_RES_IOPORT, &rid,
|
|
gdc_iat, 8, RF_ACTIVE);
|
|
if (sc->res_egc == NULL) {
|
|
gdc_release_resource(dev);
|
|
return (ENXIO);
|
|
}
|
|
isa_load_resourcev(sc->res_egc, gdc_iat, 8);
|
|
|
|
/* PEGC */
|
|
rid = 24;
|
|
bus_set_resource(dev, SYS_RES_IOPORT, rid, 0x9a0, 1);
|
|
sc->res_pegc = isa_alloc_resourcev(dev, SYS_RES_IOPORT, &rid,
|
|
gdc_iat, 8, RF_ACTIVE);
|
|
if (sc->res_pegc == NULL) {
|
|
gdc_release_resource(dev);
|
|
return (ENXIO);
|
|
}
|
|
isa_load_resourcev(sc->res_pegc, gdc_iat, 8);
|
|
|
|
/* CRTC/GRCG */
|
|
rid = 32;
|
|
bus_set_resource(dev, SYS_RES_IOPORT, rid, 0x70, 1);
|
|
sc->res_grcg = isa_alloc_resourcev(dev, SYS_RES_IOPORT, &rid,
|
|
gdc_iat, 8, RF_ACTIVE);
|
|
if (sc->res_grcg == NULL) {
|
|
gdc_release_resource(dev);
|
|
return (ENXIO);
|
|
}
|
|
isa_load_resourcev(sc->res_grcg, gdc_iat, 8);
|
|
|
|
/* KCG */
|
|
rid = 40;
|
|
bus_set_resource(dev, SYS_RES_IOPORT, rid, 0xa1, 1);
|
|
sc->res_kcg = isa_alloc_resourcev(dev, SYS_RES_IOPORT, &rid,
|
|
gdc_iat, 8, RF_ACTIVE);
|
|
if (sc->res_kcg == NULL) {
|
|
gdc_release_resource(dev);
|
|
return (ENXIO);
|
|
}
|
|
isa_load_resourcev(sc->res_kcg, gdc_iat, 8);
|
|
|
|
|
|
/* TEXT Memory */
|
|
rid = 0;
|
|
sc->res_tmem = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid,
|
|
0xa0000, 0xa4fff, 0x5000, RF_ACTIVE);
|
|
if (sc->res_tmem == NULL) {
|
|
gdc_release_resource(dev);
|
|
return (ENXIO);
|
|
}
|
|
|
|
/* GRAPHIC Memory */
|
|
rid = 1;
|
|
sc->res_gmem1 = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid,
|
|
0xa8000, 0xbffff, 0x18000,
|
|
RF_ACTIVE);
|
|
if (sc->res_gmem1 == NULL) {
|
|
gdc_release_resource(dev);
|
|
return (ENXIO);
|
|
}
|
|
rid = 2;
|
|
sc->res_gmem2 = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid,
|
|
0xe0000, 0xe7fff, 0x8000,
|
|
RF_ACTIVE);
|
|
if (sc->res_gmem2 == NULL) {
|
|
gdc_release_resource(dev);
|
|
return (ENXIO);
|
|
}
|
|
|
|
return (0);
|
|
}
|
|
|
|
static int
|
|
gdc_release_resource(device_t dev)
|
|
{
|
|
gdc_softc_t *sc;
|
|
|
|
sc = device_get_softc(dev);
|
|
|
|
if (sc->res_tgdc)
|
|
bus_release_resource(dev, SYS_RES_IOPORT, 0, sc->res_tgdc);
|
|
if (sc->res_ggdc)
|
|
bus_release_resource(dev, SYS_RES_IOPORT, 8, sc->res_ggdc);
|
|
if (sc->res_egc)
|
|
bus_release_resource(dev, SYS_RES_IOPORT, 16, sc->res_egc);
|
|
if (sc->res_pegc)
|
|
bus_release_resource(dev, SYS_RES_IOPORT, 24, sc->res_pegc);
|
|
if (sc->res_grcg)
|
|
bus_release_resource(dev, SYS_RES_IOPORT, 32, sc->res_grcg);
|
|
if (sc->res_kcg)
|
|
bus_release_resource(dev, SYS_RES_IOPORT, 40, sc->res_kcg);
|
|
|
|
if (sc->res_tmem)
|
|
bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->res_tmem);
|
|
if (sc->res_gmem1)
|
|
bus_release_resource(dev, SYS_RES_MEMORY, 1, sc->res_gmem1);
|
|
if (sc->res_gmem2)
|
|
bus_release_resource(dev, SYS_RES_MEMORY, 2, sc->res_gmem2);
|
|
|
|
return (0);
|
|
}
|
|
|
|
/* cdev driver functions */
|
|
|
|
#ifdef FB_INSTALL_CDEV
|
|
|
|
static int
|
|
gdcopen(dev_t dev, int flag, int mode, struct thread *td)
|
|
{
|
|
gdc_softc_t *sc;
|
|
|
|
sc = GDC_SOFTC(GDC_UNIT(dev));
|
|
if (sc == NULL)
|
|
return ENXIO;
|
|
if (mode & (O_CREAT | O_APPEND | O_TRUNC))
|
|
return ENODEV;
|
|
|
|
return genfbopen(&sc->gensc, sc->adp, flag, mode, td);
|
|
}
|
|
|
|
static int
|
|
gdcclose(dev_t dev, int flag, int mode, struct thread *td)
|
|
{
|
|
gdc_softc_t *sc;
|
|
|
|
sc = GDC_SOFTC(GDC_UNIT(dev));
|
|
return genfbclose(&sc->gensc, sc->adp, flag, mode, td);
|
|
}
|
|
|
|
static int
|
|
gdcread(dev_t dev, struct uio *uio, int flag)
|
|
{
|
|
gdc_softc_t *sc;
|
|
|
|
sc = GDC_SOFTC(GDC_UNIT(dev));
|
|
return genfbread(&sc->gensc, sc->adp, uio, flag);
|
|
}
|
|
|
|
static int
|
|
gdcwrite(dev_t dev, struct uio *uio, int flag)
|
|
{
|
|
gdc_softc_t *sc;
|
|
|
|
sc = GDC_SOFTC(GDC_UNIT(dev));
|
|
return genfbread(&sc->gensc, sc->adp, uio, flag);
|
|
}
|
|
|
|
static int
|
|
gdcioctl(dev_t dev, u_long cmd, caddr_t arg, int flag, struct thread *td)
|
|
{
|
|
gdc_softc_t *sc;
|
|
|
|
sc = GDC_SOFTC(GDC_UNIT(dev));
|
|
return genfbioctl(&sc->gensc, sc->adp, cmd, arg, flag, td);
|
|
}
|
|
|
|
static int
|
|
gdcmmap(dev_t dev, vm_offset_t offset, vm_offset_t *paddr, int prot)
|
|
{
|
|
gdc_softc_t *sc;
|
|
|
|
sc = GDC_SOFTC(GDC_UNIT(dev));
|
|
return genfbmmap(&sc->gensc, sc->adp, offset, paddr, prot);
|
|
}
|
|
|
|
#endif /* FB_INSTALL_CDEV */
|
|
|
|
static device_method_t gdc_methods[] = {
|
|
DEVMETHOD(device_identify, gdc_identify),
|
|
DEVMETHOD(device_probe, gdcprobe),
|
|
DEVMETHOD(device_attach, gdc_attach),
|
|
{ 0, 0 }
|
|
};
|
|
|
|
static driver_t gdcdriver = {
|
|
DRIVER_NAME,
|
|
gdc_methods,
|
|
sizeof(gdc_softc_t),
|
|
};
|
|
|
|
DRIVER_MODULE(gdc, isa, gdcdriver, gdc_devclass, 0, 0);
|
|
|
|
/* LOW-LEVEL */
|
|
|
|
|
|
#include <pc98/pc98/30line.h>
|
|
|
|
#define TEXT_BUF_BASE 0x000a0000
|
|
#define TEXT_BUF_SIZE 0x00008000
|
|
#define GRAPHICS_BUF_BASE 0x000a8000
|
|
#define GRAPHICS_BUF_SIZE 0x00040000
|
|
#define VIDEO_BUF_BASE 0x000a0000
|
|
#define VIDEO_BUF_SIZE 0x00048000
|
|
|
|
#define probe_done(adp) ((adp)->va_flags & V_ADP_PROBED)
|
|
#define init_done(adp) ((adp)->va_flags & V_ADP_INITIALIZED)
|
|
#define config_done(adp) ((adp)->va_flags & V_ADP_REGISTERED)
|
|
|
|
/*
|
|
* NOTE: `va_window' should have a virtual address, but is initialized
|
|
* with a physical address in the following table, they will be
|
|
* converted at run-time.
|
|
*/
|
|
static video_adapter_t adapter_init_value[] = {
|
|
{ 0,
|
|
KD_PC98, "gdc", /* va_type, va_name */
|
|
0, 0, /* va_unit, va_minor */
|
|
V_ADP_COLOR | V_ADP_MODECHANGE | V_ADP_BORDER,
|
|
TEXT_GDC, 16, TEXT_GDC, /* va_io*, XXX */
|
|
VIDEO_BUF_BASE, VIDEO_BUF_SIZE, /* va_mem* */
|
|
TEXT_BUF_BASE, TEXT_BUF_SIZE, TEXT_BUF_SIZE, 0, /* va_window* */
|
|
0, 0, /* va_buffer, va_buffer_size */
|
|
0, M_PC98_80x25, 0, /* va_*mode* */
|
|
},
|
|
};
|
|
|
|
static video_adapter_t biosadapter[1];
|
|
|
|
/* video driver declarations */
|
|
static int gdc_configure(int flags);
|
|
static int gdc_err(video_adapter_t *adp, ...);
|
|
static vi_probe_t gdc_probe;
|
|
static vi_init_t gdc_init;
|
|
static vi_get_info_t gdc_get_info;
|
|
static vi_query_mode_t gdc_query_mode;
|
|
static vi_set_mode_t gdc_set_mode;
|
|
static vi_set_border_t gdc_set_border;
|
|
static vi_save_state_t gdc_save_state;
|
|
static vi_load_state_t gdc_load_state;
|
|
static vi_read_hw_cursor_t gdc_read_hw_cursor;
|
|
static vi_set_hw_cursor_t gdc_set_hw_cursor;
|
|
static vi_set_hw_cursor_shape_t gdc_set_hw_cursor_shape;
|
|
static vi_blank_display_t gdc_blank_display;
|
|
static vi_mmap_t gdc_mmap_buf;
|
|
static vi_ioctl_t gdc_dev_ioctl;
|
|
static vi_clear_t gdc_clear;
|
|
static vi_fill_rect_t gdc_fill_rect;
|
|
static vi_bitblt_t gdc_bitblt;
|
|
static vi_diag_t gdc_diag;
|
|
static vi_save_palette_t gdc_save_palette;
|
|
static vi_load_palette_t gdc_load_palette;
|
|
static vi_set_win_org_t gdc_set_origin;
|
|
|
|
static video_switch_t gdcvidsw = {
|
|
gdc_probe,
|
|
gdc_init,
|
|
gdc_get_info,
|
|
gdc_query_mode,
|
|
gdc_set_mode,
|
|
(vi_save_font_t *)gdc_err,
|
|
(vi_load_font_t *)gdc_err,
|
|
(vi_show_font_t *)gdc_err,
|
|
gdc_save_palette,
|
|
gdc_load_palette,
|
|
gdc_set_border,
|
|
gdc_save_state,
|
|
gdc_load_state,
|
|
gdc_set_origin,
|
|
gdc_read_hw_cursor,
|
|
gdc_set_hw_cursor,
|
|
gdc_set_hw_cursor_shape,
|
|
gdc_blank_display,
|
|
gdc_mmap_buf,
|
|
gdc_dev_ioctl,
|
|
gdc_clear,
|
|
gdc_fill_rect,
|
|
gdc_bitblt,
|
|
(int (*)(void))gdc_err,
|
|
(int (*)(void))gdc_err,
|
|
gdc_diag,
|
|
};
|
|
|
|
VIDEO_DRIVER(gdc, gdcvidsw, gdc_configure);
|
|
|
|
/* GDC BIOS standard video modes */
|
|
#define EOT (-1)
|
|
#define NA (-2)
|
|
|
|
static video_info_t bios_vmode[] = {
|
|
{ M_PC98_80x25, V_INFO_COLOR, 80, 25, 8, 16, 4, 1,
|
|
TEXT_BUF_BASE, TEXT_BUF_SIZE, TEXT_BUF_SIZE, 0, 0, V_INFO_MM_TEXT },
|
|
#ifdef LINE30
|
|
{ M_PC98_80x30, V_INFO_COLOR, 80, 30, 8, 16, 4, 1,
|
|
TEXT_BUF_BASE, TEXT_BUF_SIZE, TEXT_BUF_SIZE, 0, 0, V_INFO_MM_TEXT },
|
|
#endif
|
|
#ifndef GDC_NOGRAPHICS
|
|
{ M_PC98_EGC640x400, V_INFO_COLOR | V_INFO_GRAPHICS,
|
|
640, 400, 8, 16, 4, 4,
|
|
GRAPHICS_BUF_BASE, GRAPHICS_BUF_SIZE, GRAPHICS_BUF_SIZE, 0, 0,
|
|
V_INFO_MM_OTHER },
|
|
{ M_PC98_PEGC640x400, V_INFO_COLOR | V_INFO_GRAPHICS | V_INFO_VESA,
|
|
640, 400, 8, 16, 8, 1,
|
|
GRAPHICS_BUF_BASE, 0x00008000, 0x00008000, 0, 0,
|
|
V_INFO_MM_PACKED, 1 },
|
|
#ifdef LINE30
|
|
{ M_PC98_PEGC640x480, V_INFO_COLOR | V_INFO_GRAPHICS | V_INFO_VESA,
|
|
640, 480, 8, 16, 8, 1,
|
|
GRAPHICS_BUF_BASE, 0x00008000, 0x00008000, 0, 0,
|
|
V_INFO_MM_PACKED, 1 },
|
|
#endif
|
|
#endif
|
|
{ EOT },
|
|
};
|
|
|
|
static int gdc_init_done = FALSE;
|
|
|
|
/* local functions */
|
|
static int map_gen_mode_num(int type, int color, int mode);
|
|
static int probe_adapters(void);
|
|
|
|
#define prologue(adp, flag, err) \
|
|
if (!gdc_init_done || !((adp)->va_flags & (flag))) \
|
|
return (err)
|
|
|
|
/* a backdoor for the console driver */
|
|
static int
|
|
gdc_configure(int flags)
|
|
{
|
|
probe_adapters();
|
|
biosadapter[0].va_flags |= V_ADP_INITIALIZED;
|
|
if (!config_done(&biosadapter[0])) {
|
|
if (vid_register(&biosadapter[0]) < 0)
|
|
return 1;
|
|
biosadapter[0].va_flags |= V_ADP_REGISTERED;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
/* local subroutines */
|
|
|
|
/* map a generic video mode to a known mode number */
|
|
static int
|
|
map_gen_mode_num(int type, int color, int mode)
|
|
{
|
|
static struct {
|
|
int from;
|
|
int to;
|
|
} mode_map[] = {
|
|
{ M_TEXT_80x25, M_PC98_80x25, },
|
|
#ifdef LINE30
|
|
{ M_TEXT_80x30, M_PC98_80x30, },
|
|
#endif
|
|
};
|
|
int i;
|
|
|
|
for (i = 0; i < sizeof(mode_map)/sizeof(mode_map[0]); ++i) {
|
|
if (mode_map[i].from == mode)
|
|
return mode_map[i].to;
|
|
}
|
|
return mode;
|
|
}
|
|
|
|
static int
|
|
verify_adapter(video_adapter_t *adp)
|
|
{
|
|
#ifndef GDC_NOGRAPHICS
|
|
int i;
|
|
|
|
if (PC98_SYSTEM_PARAMETER(0x45c) & 0x40) { /* PEGC exists */
|
|
adp->va_flags |= V_ADP_VESA; /* XXX */
|
|
} else {
|
|
for (i = 0; bios_vmode[i].vi_mode != EOT; ++i) {
|
|
if (bios_vmode[i].vi_flags & V_INFO_VESA)
|
|
bios_vmode[i].vi_mode = NA;
|
|
}
|
|
}
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
/* probe video adapters and return the number of detected adapters */
|
|
static int
|
|
probe_adapters(void)
|
|
{
|
|
video_info_t info;
|
|
|
|
/* do this test only once */
|
|
if (gdc_init_done)
|
|
return 1;
|
|
gdc_init_done = TRUE;
|
|
|
|
biosadapter[0] = adapter_init_value[0];
|
|
biosadapter[0].va_flags |= V_ADP_PROBED;
|
|
biosadapter[0].va_mode =
|
|
biosadapter[0].va_initial_mode = biosadapter[0].va_initial_bios_mode;
|
|
|
|
if ((PC98_SYSTEM_PARAMETER(0x597) & 0x80) ||
|
|
(PC98_SYSTEM_PARAMETER(0x458) & 0x80)) {
|
|
gdc_FH = (inb(0x9a8) & 1) ? _31KHZ : _24KHZ;
|
|
} else {
|
|
gdc_FH = _24KHZ;
|
|
}
|
|
|
|
gdc_get_info(&biosadapter[0], biosadapter[0].va_initial_mode, &info);
|
|
initialize_gdc(T25_G400, info.vi_flags & V_INFO_GRAPHICS);
|
|
|
|
biosadapter[0].va_window = BIOS_PADDRTOVADDR(info.vi_window);
|
|
biosadapter[0].va_window_size = info.vi_window_size;
|
|
biosadapter[0].va_window_gran = info.vi_window_gran;
|
|
biosadapter[0].va_buffer = 0;
|
|
biosadapter[0].va_buffer_size = 0;
|
|
if (info.vi_flags & V_INFO_GRAPHICS) {
|
|
switch (info.vi_depth/info.vi_planes) {
|
|
case 1:
|
|
biosadapter[0].va_line_width = info.vi_width/8;
|
|
break;
|
|
case 2:
|
|
biosadapter[0].va_line_width = info.vi_width/4;
|
|
break;
|
|
case 4:
|
|
biosadapter[0].va_line_width = info.vi_width/2;
|
|
break;
|
|
case 8:
|
|
default: /* shouldn't happen */
|
|
biosadapter[0].va_line_width = info.vi_width;
|
|
break;
|
|
}
|
|
} else {
|
|
biosadapter[0].va_line_width = info.vi_width;
|
|
}
|
|
bcopy(&info, &biosadapter[0].va_info, sizeof(info));
|
|
|
|
verify_adapter(&biosadapter[0]);
|
|
|
|
return 1;
|
|
}
|
|
|
|
static void master_gdc_cmd(unsigned int cmd)
|
|
{
|
|
while ( (inb(TEXT_GDC) & 2) != 0);
|
|
outb(TEXT_GDC+2, cmd);
|
|
}
|
|
|
|
static void master_gdc_prm(unsigned int pmtr)
|
|
{
|
|
while ( (inb(TEXT_GDC) & 2) != 0);
|
|
outb(TEXT_GDC, pmtr);
|
|
}
|
|
|
|
static void master_gdc_word_prm(unsigned int wpmtr)
|
|
{
|
|
master_gdc_prm(wpmtr & 0x00ff);
|
|
master_gdc_prm((wpmtr >> 8) & 0x00ff);
|
|
}
|
|
|
|
#ifdef LINE30
|
|
static void master_gdc_fifo_empty(void)
|
|
{
|
|
while ( (inb(TEXT_GDC) & 4) == 0);
|
|
}
|
|
#endif
|
|
|
|
static void master_gdc_wait_vsync(void)
|
|
{
|
|
while ( (inb(TEXT_GDC) & 0x20) != 0);
|
|
while ( (inb(TEXT_GDC) & 0x20) == 0);
|
|
}
|
|
|
|
static void gdc_cmd(unsigned int cmd)
|
|
{
|
|
while ( (inb(GRAPHIC_GDC) & 2) != 0);
|
|
outb( GRAPHIC_GDC+2, cmd);
|
|
}
|
|
|
|
#ifdef LINE30
|
|
static void gdc_prm(unsigned int pmtr)
|
|
{
|
|
while ( (inb(GRAPHIC_GDC) & 2) != 0);
|
|
outb( GRAPHIC_GDC, pmtr);
|
|
}
|
|
|
|
static void gdc_word_prm(unsigned int wpmtr)
|
|
{
|
|
gdc_prm(wpmtr & 0x00ff);
|
|
gdc_prm((wpmtr >> 8) & 0x00ff);
|
|
}
|
|
|
|
static void gdc_fifo_empty(void)
|
|
{
|
|
while ( (inb(GRAPHIC_GDC) & 0x04) == 0);
|
|
}
|
|
#endif
|
|
|
|
static void gdc_wait_vsync(void)
|
|
{
|
|
while ( (inb(GRAPHIC_GDC) & 0x20) != 0);
|
|
while ( (inb(GRAPHIC_GDC) & 0x20) == 0);
|
|
}
|
|
|
|
#ifdef LINE30
|
|
static int check_gdc_clock(void)
|
|
{
|
|
if ((inb(IO_SYSPORT) & 0x80) == 0){
|
|
return _5MHZ;
|
|
} else {
|
|
return _2_5MHZ;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
static void initialize_gdc(unsigned int mode, int isGraph)
|
|
{
|
|
#ifdef LINE30
|
|
/* start 30line initialize */
|
|
int m_mode, s_mode, gdc_clock, hsync_clock;
|
|
|
|
gdc_clock = check_gdc_clock();
|
|
m_mode = (mode == T25_G400) ? _25L : _30L;
|
|
s_mode = 2*mode+gdc_clock;
|
|
gdc_INFO = m_mode;
|
|
|
|
master_gdc_wait_vsync();
|
|
|
|
if ((PC98_SYSTEM_PARAMETER(0x597) & 0x80) ||
|
|
(PC98_SYSTEM_PARAMETER(0x458) & 0x80)) {
|
|
if (PC98_SYSTEM_PARAMETER(0x481) & 0x08) {
|
|
hsync_clock = (m_mode == _25L) ? gdc_FH : _31KHZ;
|
|
outb(0x9a8, (hsync_clock == _31KHZ) ? 1 : 0);
|
|
} else {
|
|
hsync_clock = gdc_FH;
|
|
}
|
|
} else {
|
|
hsync_clock = _24KHZ;
|
|
}
|
|
|
|
if ((gdc_clock == _2_5MHZ) &&
|
|
(slave_param[hsync_clock][s_mode][GDC_LF] > 400)) {
|
|
outb(0x6a, 0x83);
|
|
outb(0x6a, 0x85);
|
|
gdc_clock = _5MHZ;
|
|
s_mode = 2*mode+gdc_clock;
|
|
}
|
|
|
|
master_gdc_cmd(_GDC_RESET);
|
|
master_gdc_cmd(_GDC_MASTER);
|
|
gdc_cmd(_GDC_RESET);
|
|
gdc_cmd(_GDC_SLAVE);
|
|
|
|
/* GDC Master */
|
|
master_gdc_cmd(_GDC_SYNC);
|
|
master_gdc_prm(0x00); /* flush less */ /* text & graph */
|
|
master_gdc_prm(master_param[hsync_clock][m_mode][GDC_CR]);
|
|
master_gdc_word_prm(((master_param[hsync_clock][m_mode][GDC_HFP] << 10)
|
|
+ (master_param[hsync_clock][m_mode][GDC_VS] << 5)
|
|
+ master_param[hsync_clock][m_mode][GDC_HS]));
|
|
master_gdc_prm(master_param[hsync_clock][m_mode][GDC_HBP]);
|
|
master_gdc_prm(master_param[hsync_clock][m_mode][GDC_VFP]);
|
|
master_gdc_word_prm(((master_param[hsync_clock][m_mode][GDC_VBP] << 10)
|
|
+ (master_param[hsync_clock][m_mode][GDC_LF])));
|
|
master_gdc_fifo_empty();
|
|
master_gdc_cmd(_GDC_PITCH);
|
|
master_gdc_prm(MasterPCH);
|
|
master_gdc_fifo_empty();
|
|
|
|
/* GDC slave */
|
|
gdc_cmd(_GDC_SYNC);
|
|
gdc_prm(0x06);
|
|
gdc_prm(slave_param[hsync_clock][s_mode][GDC_CR]);
|
|
gdc_word_prm((slave_param[hsync_clock][s_mode][GDC_HFP] << 10)
|
|
+ (slave_param[hsync_clock][s_mode][GDC_VS] << 5)
|
|
+ (slave_param[hsync_clock][s_mode][GDC_HS]));
|
|
gdc_prm(slave_param[hsync_clock][s_mode][GDC_HBP]);
|
|
gdc_prm(slave_param[hsync_clock][s_mode][GDC_VFP]);
|
|
gdc_word_prm((slave_param[hsync_clock][s_mode][GDC_VBP] << 10)
|
|
+ (slave_param[hsync_clock][s_mode][GDC_LF]));
|
|
gdc_fifo_empty();
|
|
gdc_cmd(_GDC_PITCH);
|
|
gdc_prm(SlavePCH[gdc_clock]);
|
|
gdc_fifo_empty();
|
|
|
|
/* set Master GDC scroll param */
|
|
master_gdc_wait_vsync();
|
|
master_gdc_wait_vsync();
|
|
master_gdc_wait_vsync();
|
|
master_gdc_cmd(_GDC_SCROLL);
|
|
master_gdc_word_prm(0);
|
|
master_gdc_word_prm((master_param[hsync_clock][m_mode][GDC_LF] << 4)
|
|
| 0x0000);
|
|
master_gdc_fifo_empty();
|
|
|
|
/* set Slave GDC scroll param */
|
|
gdc_wait_vsync();
|
|
gdc_cmd(_GDC_SCROLL);
|
|
gdc_word_prm(0);
|
|
if (gdc_clock == _5MHZ) {
|
|
gdc_word_prm((SlaveScrlLF[mode] << 4) | 0x4000);
|
|
} else {
|
|
gdc_word_prm(SlaveScrlLF[mode] << 4);
|
|
}
|
|
gdc_fifo_empty();
|
|
|
|
gdc_word_prm(0);
|
|
if (gdc_clock == _5MHZ) {
|
|
gdc_word_prm((SlaveScrlLF[mode] << 4) | 0x4000);
|
|
} else {
|
|
gdc_word_prm(SlaveScrlLF[mode] << 4);
|
|
}
|
|
gdc_fifo_empty();
|
|
|
|
/* sync start */
|
|
gdc_cmd(isGraph ? _GDC_START : _GDC_STOP);
|
|
|
|
gdc_wait_vsync();
|
|
gdc_wait_vsync();
|
|
gdc_wait_vsync();
|
|
|
|
master_gdc_cmd(isGraph ? _GDC_STOP : _GDC_START);
|
|
#else
|
|
master_gdc_wait_vsync();
|
|
master_gdc_cmd(isGraph ? _GDC_STOP : _GDC_START); /* text */
|
|
gdc_wait_vsync();
|
|
gdc_cmd(isGraph ? _GDC_START : _GDC_STOP); /* graphics */
|
|
#endif
|
|
}
|
|
|
|
#ifndef GDC_NOGRAPHICS
|
|
static u_char b_palette[] = {
|
|
/* R G B */
|
|
0x00, 0x00, 0x00, /* 0 */
|
|
0x00, 0x00, 0x7f, /* 1 */
|
|
0x7f, 0x00, 0x00, /* 2 */
|
|
0x7f, 0x00, 0x7f, /* 3 */
|
|
0x00, 0x7f, 0x00, /* 4 */
|
|
0x00, 0x7f, 0x7f, /* 5 */
|
|
0x7f, 0x7f, 0x00, /* 6 */
|
|
0x7f, 0x7f, 0x7f, /* 7 */
|
|
0x40, 0x40, 0x40, /* 8 */
|
|
0x00, 0x00, 0xff, /* 9 */
|
|
0xff, 0x00, 0x00, /* 10 */
|
|
0xff, 0x00, 0xff, /* 11 */
|
|
0x00, 0xff, 0x00, /* 12 */
|
|
0x00, 0xff, 0xff, /* 13 */
|
|
0xff, 0xff, 0x00, /* 14 */
|
|
0xff, 0xff, 0xff, /* 15 */
|
|
};
|
|
#endif
|
|
|
|
static int
|
|
gdc_load_palette(video_adapter_t *adp, u_char *palette)
|
|
{
|
|
#ifndef GDC_NOGRAPHICS
|
|
int i;
|
|
|
|
if (adp->va_info.vi_flags & V_INFO_VESA) {
|
|
gdc_wait_vsync();
|
|
for (i = 0; i < 256; ++i) {
|
|
outb(0xa8, i);
|
|
outb(0xac, *palette++); /* R */
|
|
outb(0xaa, *palette++); /* G */
|
|
outb(0xae, *palette++); /* B */
|
|
}
|
|
} else {
|
|
/*
|
|
* XXX - Even though PC-98 text color is independent of palette,
|
|
* we should set palette in text mode.
|
|
* Because the background color of text mode is palette 0's one.
|
|
*/
|
|
outb(0x6a, 1); /* 16 colors mode */
|
|
bcopy(palette, b_palette, sizeof(b_palette));
|
|
|
|
gdc_wait_vsync();
|
|
for (i = 0; i < 16; ++i) {
|
|
outb(0xa8, i);
|
|
outb(0xac, *palette++ >> 4); /* R */
|
|
outb(0xaa, *palette++ >> 4); /* G */
|
|
outb(0xae, *palette++ >> 4); /* B */
|
|
}
|
|
}
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
gdc_save_palette(video_adapter_t *adp, u_char *palette)
|
|
{
|
|
#ifndef GDC_NOGRAPHICS
|
|
int i;
|
|
|
|
if (adp->va_info.vi_flags & V_INFO_VESA) {
|
|
for (i = 0; i < 256; ++i) {
|
|
outb(0xa8, i);
|
|
*palette++ = inb(0xac); /* R */
|
|
*palette++ = inb(0xaa); /* G */
|
|
*palette++ = inb(0xae); /* B */
|
|
}
|
|
} else {
|
|
bcopy(b_palette, palette, sizeof(b_palette));
|
|
}
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
gdc_set_origin(video_adapter_t *adp, off_t offset)
|
|
{
|
|
#ifndef GDC_NOGRAPHICS
|
|
if (adp->va_info.vi_flags & V_INFO_VESA) {
|
|
writew(BIOS_PADDRTOVADDR(0x000e0004), offset >> 15);
|
|
}
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
/* entry points */
|
|
|
|
static int
|
|
gdc_err(video_adapter_t *adp, ...)
|
|
{
|
|
return ENODEV;
|
|
}
|
|
|
|
static int
|
|
gdc_probe(int unit, video_adapter_t **adpp, void *arg, int flags)
|
|
{
|
|
probe_adapters();
|
|
if (unit >= 1)
|
|
return ENXIO;
|
|
|
|
*adpp = &biosadapter[unit];
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
gdc_init(int unit, video_adapter_t *adp, int flags)
|
|
{
|
|
if ((unit >= 1) || (adp == NULL) || !probe_done(adp))
|
|
return ENXIO;
|
|
|
|
if (!init_done(adp)) {
|
|
/* nothing to do really... */
|
|
adp->va_flags |= V_ADP_INITIALIZED;
|
|
}
|
|
|
|
if (!config_done(adp)) {
|
|
if (vid_register(adp) < 0)
|
|
return ENXIO;
|
|
adp->va_flags |= V_ADP_REGISTERED;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* get_info():
|
|
* Return the video_info structure of the requested video mode.
|
|
*/
|
|
static int
|
|
gdc_get_info(video_adapter_t *adp, int mode, video_info_t *info)
|
|
{
|
|
int i;
|
|
|
|
if (!gdc_init_done)
|
|
return ENXIO;
|
|
|
|
mode = map_gen_mode_num(adp->va_type, adp->va_flags & V_ADP_COLOR, mode);
|
|
for (i = 0; bios_vmode[i].vi_mode != EOT; ++i) {
|
|
if (bios_vmode[i].vi_mode == NA)
|
|
continue;
|
|
if (mode == bios_vmode[i].vi_mode) {
|
|
*info = bios_vmode[i];
|
|
info->vi_buffer_size = info->vi_window_size*info->vi_planes;
|
|
return 0;
|
|
}
|
|
}
|
|
return EINVAL;
|
|
}
|
|
|
|
/*
|
|
* query_mode():
|
|
* Find a video mode matching the requested parameters.
|
|
* Fields filled with 0 are considered "don't care" fields and
|
|
* match any modes.
|
|
*/
|
|
static int
|
|
gdc_query_mode(video_adapter_t *adp, video_info_t *info)
|
|
{
|
|
int i;
|
|
|
|
if (!gdc_init_done)
|
|
return ENXIO;
|
|
|
|
for (i = 0; bios_vmode[i].vi_mode != EOT; ++i) {
|
|
if (bios_vmode[i].vi_mode == NA)
|
|
continue;
|
|
|
|
if ((info->vi_width != 0)
|
|
&& (info->vi_width != bios_vmode[i].vi_width))
|
|
continue;
|
|
if ((info->vi_height != 0)
|
|
&& (info->vi_height != bios_vmode[i].vi_height))
|
|
continue;
|
|
if ((info->vi_cwidth != 0)
|
|
&& (info->vi_cwidth != bios_vmode[i].vi_cwidth))
|
|
continue;
|
|
if ((info->vi_cheight != 0)
|
|
&& (info->vi_cheight != bios_vmode[i].vi_cheight))
|
|
continue;
|
|
if ((info->vi_depth != 0)
|
|
&& (info->vi_depth != bios_vmode[i].vi_depth))
|
|
continue;
|
|
if ((info->vi_planes != 0)
|
|
&& (info->vi_planes != bios_vmode[i].vi_planes))
|
|
continue;
|
|
/* XXX: should check pixel format, memory model */
|
|
if ((info->vi_flags != 0)
|
|
&& (info->vi_flags != bios_vmode[i].vi_flags))
|
|
continue;
|
|
|
|
/* verify if this mode is supported on this adapter */
|
|
if (gdc_get_info(adp, bios_vmode[i].vi_mode, info))
|
|
continue;
|
|
return 0;
|
|
}
|
|
return ENODEV;
|
|
}
|
|
|
|
/*
|
|
* set_mode():
|
|
* Change the video mode.
|
|
*/
|
|
static int
|
|
gdc_set_mode(video_adapter_t *adp, int mode)
|
|
{
|
|
video_info_t info;
|
|
|
|
prologue(adp, V_ADP_MODECHANGE, ENODEV);
|
|
|
|
mode = map_gen_mode_num(adp->va_type,
|
|
adp->va_flags & V_ADP_COLOR, mode);
|
|
if (gdc_get_info(adp, mode, &info))
|
|
return EINVAL;
|
|
|
|
switch (info.vi_mode) {
|
|
#ifndef GDC_NOGRAPHICS
|
|
case M_PC98_PEGC640x480: /* PEGC 640x480 */
|
|
initialize_gdc(T30_G480, info.vi_flags & V_INFO_GRAPHICS);
|
|
break;
|
|
case M_PC98_PEGC640x400: /* PEGC 640x400 */
|
|
case M_PC98_EGC640x400: /* EGC GRAPHICS */
|
|
#endif
|
|
case M_PC98_80x25: /* VGA TEXT */
|
|
initialize_gdc(T25_G400, info.vi_flags & V_INFO_GRAPHICS);
|
|
break;
|
|
case M_PC98_80x30: /* VGA TEXT */
|
|
initialize_gdc(T30_G400, info.vi_flags & V_INFO_GRAPHICS);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
#ifndef GDC_NOGRAPHICS
|
|
if (info.vi_flags & V_INFO_VESA) {
|
|
outb(0x6a, 0x07); /* enable mode F/F change */
|
|
outb(0x6a, 0x21); /* enhanced graphics */
|
|
if (info.vi_height > 400)
|
|
outb(0x6a, 0x69); /* 800 lines */
|
|
writeb(BIOS_PADDRTOVADDR(0x000e0100), 0); /* packed pixel */
|
|
} else {
|
|
if (adp->va_flags & V_ADP_VESA) {
|
|
outb(0x6a, 0x07); /* enable mode F/F change */
|
|
outb(0x6a, 0x20); /* normal graphics */
|
|
outb(0x6a, 0x68); /* 400 lines */
|
|
}
|
|
outb(0x6a, 1); /* 16 colors */
|
|
}
|
|
#endif
|
|
|
|
adp->va_mode = mode;
|
|
adp->va_flags &= ~V_ADP_COLOR;
|
|
adp->va_flags |=
|
|
(info.vi_flags & V_INFO_COLOR) ? V_ADP_COLOR : 0;
|
|
#if 0
|
|
adp->va_crtc_addr =
|
|
(adp->va_flags & V_ADP_COLOR) ? COLOR_CRTC : MONO_CRTC;
|
|
#endif
|
|
adp->va_window = BIOS_PADDRTOVADDR(info.vi_window);
|
|
adp->va_window_size = info.vi_window_size;
|
|
adp->va_window_gran = info.vi_window_gran;
|
|
if (info.vi_buffer_size == 0) {
|
|
adp->va_buffer = 0;
|
|
adp->va_buffer_size = 0;
|
|
} else {
|
|
adp->va_buffer = BIOS_PADDRTOVADDR(info.vi_buffer);
|
|
adp->va_buffer_size = info.vi_buffer_size;
|
|
}
|
|
if (info.vi_flags & V_INFO_GRAPHICS) {
|
|
switch (info.vi_depth/info.vi_planes) {
|
|
case 1:
|
|
adp->va_line_width = info.vi_width/8;
|
|
break;
|
|
case 2:
|
|
adp->va_line_width = info.vi_width/4;
|
|
break;
|
|
case 4:
|
|
adp->va_line_width = info.vi_width/2;
|
|
break;
|
|
case 8:
|
|
default: /* shouldn't happen */
|
|
adp->va_line_width = info.vi_width;
|
|
break;
|
|
}
|
|
} else {
|
|
adp->va_line_width = info.vi_width;
|
|
}
|
|
bcopy(&info, &adp->va_info, sizeof(info));
|
|
|
|
/* move hardware cursor out of the way */
|
|
(*vidsw[adp->va_index]->set_hw_cursor)(adp, -1, -1);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* set_border():
|
|
* Change the border color.
|
|
*/
|
|
static int
|
|
gdc_set_border(video_adapter_t *adp, int color)
|
|
{
|
|
outb(0x6c, color << 4);
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* save_state():
|
|
* Read video card register values.
|
|
*/
|
|
static int
|
|
gdc_save_state(video_adapter_t *adp, void *p, size_t size)
|
|
{
|
|
return ENODEV;
|
|
}
|
|
|
|
/*
|
|
* load_state():
|
|
* Set video card registers at once.
|
|
*/
|
|
static int
|
|
gdc_load_state(video_adapter_t *adp, void *p)
|
|
{
|
|
return ENODEV;
|
|
}
|
|
|
|
/*
|
|
* read_hw_cursor():
|
|
* Read the position of the hardware text cursor.
|
|
*/
|
|
static int
|
|
gdc_read_hw_cursor(video_adapter_t *adp, int *col, int *row)
|
|
{
|
|
u_int16_t off;
|
|
int s;
|
|
|
|
if (!gdc_init_done)
|
|
return ENXIO;
|
|
|
|
if (adp->va_info.vi_flags & V_INFO_GRAPHICS)
|
|
return ENODEV;
|
|
|
|
s = spltty();
|
|
master_gdc_cmd(0xe0); /* _GDC_CSRR */
|
|
while((inb(TEXT_GDC + 0) & 0x1) == 0) {} /* GDC wait */
|
|
off = inb(TEXT_GDC + 2); /* EADl */
|
|
off |= (inb(TEXT_GDC + 2) << 8); /* EADh */
|
|
inb(TEXT_GDC + 2); /* dummy */
|
|
inb(TEXT_GDC + 2); /* dummy */
|
|
inb(TEXT_GDC + 2); /* dummy */
|
|
splx(s);
|
|
|
|
if (off >= ROW*COL)
|
|
off = 0;
|
|
*row = off / adp->va_info.vi_width;
|
|
*col = off % adp->va_info.vi_width;
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* set_hw_cursor():
|
|
* Move the hardware text cursor. If col and row are both -1,
|
|
* the cursor won't be shown.
|
|
*/
|
|
static int
|
|
gdc_set_hw_cursor(video_adapter_t *adp, int col, int row)
|
|
{
|
|
u_int16_t off;
|
|
int s;
|
|
|
|
if (!gdc_init_done)
|
|
return ENXIO;
|
|
|
|
if ((col == -1) && (row == -1)) {
|
|
off = -1;
|
|
} else {
|
|
if (adp->va_info.vi_flags & V_INFO_GRAPHICS)
|
|
return ENODEV;
|
|
off = row*adp->va_info.vi_width + col;
|
|
}
|
|
|
|
s = spltty();
|
|
master_gdc_cmd(0x49); /* _GDC_CSRW */
|
|
master_gdc_word_prm(off);
|
|
splx(s);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* set_hw_cursor_shape():
|
|
* Change the shape of the hardware text cursor. If the height is zero
|
|
* or negative, the cursor won't be shown.
|
|
*/
|
|
static int
|
|
gdc_set_hw_cursor_shape(video_adapter_t *adp, int base, int height,
|
|
int celsize, int blink)
|
|
{
|
|
int start;
|
|
int end;
|
|
int s;
|
|
|
|
if (!gdc_init_done)
|
|
return ENXIO;
|
|
|
|
start = celsize - (base + height);
|
|
end = celsize - base - 1;
|
|
|
|
#if 0
|
|
/*
|
|
* muPD7220 GDC has anomaly that if end == celsize - 1 then start
|
|
* must be 0, otherwise the cursor won't be correctly shown
|
|
* in the first row in the screen. We shall set end to celsize - 2;
|
|
* if end == celsize -1 && start > 0. XXX
|
|
*/
|
|
if ((end == celsize - 1) && (start > 0) && (start < end))
|
|
--end;
|
|
#endif
|
|
|
|
s = spltty();
|
|
master_gdc_cmd(0x4b); /* _GDC_CSRFORM */
|
|
master_gdc_prm(((height > 0) ? 0x80 : 0) /* cursor on/off */
|
|
| ((celsize - 1) & 0x1f)); /* cel size */
|
|
master_gdc_word_prm(((end & 0x1f) << 11) /* end line */
|
|
| (12 << 6) /* blink rate */
|
|
| (blink ? 0 : 0x20) /* blink on/off */
|
|
| (start & 0x1f)); /* start line */
|
|
splx(s);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* blank_display()
|
|
* Put the display in power save/power off mode.
|
|
*/
|
|
static int
|
|
gdc_blank_display(video_adapter_t *adp, int mode)
|
|
{
|
|
int s;
|
|
static int standby = 0;
|
|
|
|
if (!gdc_init_done)
|
|
return ENXIO;
|
|
|
|
s = splhigh();
|
|
switch (mode) {
|
|
case V_DISPLAY_SUSPEND:
|
|
case V_DISPLAY_STAND_BY:
|
|
outb(0x09a2, 0x80 | 0x40); /* V/H-SYNC mask */
|
|
if (inb(0x09a2) == (0x80 | 0x40))
|
|
standby = 1;
|
|
/* FALLTHROUGH */
|
|
|
|
case V_DISPLAY_BLANK:
|
|
if (epson_machine_id == 0x20) {
|
|
outb(0x43f, 0x42);
|
|
outb(0xc17, inb(0xc17) & ~0x08); /* turn off side light */
|
|
outb(0xc16, inb(0xc16) & ~0x02); /* turn off back light */
|
|
outb(0x43f, 0x40);
|
|
} else {
|
|
while (!(inb(TEXT_GDC) & 0x20)) /* V-SYNC wait */
|
|
;
|
|
outb(TEXT_GDC + 8, 0x0e); /* DISP off */
|
|
}
|
|
break;
|
|
|
|
case V_DISPLAY_ON:
|
|
if (epson_machine_id == 0x20) {
|
|
outb(0x43f, 0x42);
|
|
outb(0xc17, inb(0xc17) | 0x08);
|
|
outb(0xc16, inb(0xc16) | 0x02);
|
|
outb(0x43f, 0x40);
|
|
} else {
|
|
while (!(inb(TEXT_GDC) & 0x20)) /* V-SYNC wait */
|
|
;
|
|
outb(TEXT_GDC + 8, 0x0f); /* DISP on */
|
|
}
|
|
if (standby) {
|
|
outb(0x09a2, 0x00); /* V/H-SYNC unmask */
|
|
standby = 0;
|
|
}
|
|
break;
|
|
}
|
|
splx(s);
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* mmap():
|
|
* Mmap frame buffer.
|
|
*/
|
|
static int
|
|
gdc_mmap_buf(video_adapter_t *adp, vm_offset_t offset, vm_offset_t *paddr,
|
|
int prot)
|
|
{
|
|
/* FIXME: is this correct? XXX */
|
|
if (offset > VIDEO_BUF_SIZE - PAGE_SIZE)
|
|
return -1;
|
|
*paddr = adp->va_info.vi_window + offset;
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
gdc_clear(video_adapter_t *adp)
|
|
{
|
|
/* FIXME */
|
|
return ENODEV;
|
|
}
|
|
|
|
static int
|
|
gdc_fill_rect(video_adapter_t *adp, int val, int x, int y, int cx, int cy)
|
|
{
|
|
return ENODEV;
|
|
}
|
|
|
|
static int
|
|
gdc_bitblt(video_adapter_t *adp,...)
|
|
{
|
|
/* FIXME */
|
|
return ENODEV;
|
|
}
|
|
|
|
static int
|
|
gdc_dev_ioctl(video_adapter_t *adp, u_long cmd, caddr_t arg)
|
|
{
|
|
switch (cmd) {
|
|
case FBIO_GETWINORG: /* get frame buffer window origin */
|
|
*(u_int *)arg = 0;
|
|
return 0;
|
|
|
|
case FBIO_SETWINORG: /* set frame buffer window origin */
|
|
case FBIO_SETDISPSTART: /* set display start address */
|
|
case FBIO_SETLINEWIDTH: /* set scan line length in pixel */
|
|
case FBIO_GETPALETTE: /* get color palette */
|
|
case FBIO_SETPALETTE: /* set color palette */
|
|
case FBIOGETCMAP: /* get color palette */
|
|
case FBIOPUTCMAP: /* set color palette */
|
|
return ENODEV;
|
|
|
|
case FBIOGTYPE: /* get frame buffer type info. */
|
|
((struct fbtype *)arg)->fb_type = fb_type(adp->va_type);
|
|
((struct fbtype *)arg)->fb_height = adp->va_info.vi_height;
|
|
((struct fbtype *)arg)->fb_width = adp->va_info.vi_width;
|
|
((struct fbtype *)arg)->fb_depth = adp->va_info.vi_depth;
|
|
if ((adp->va_info.vi_depth <= 1) || (adp->va_info.vi_depth > 8))
|
|
((struct fbtype *)arg)->fb_cmsize = 0;
|
|
else
|
|
((struct fbtype *)arg)->fb_cmsize = 1 << adp->va_info.vi_depth;
|
|
((struct fbtype *)arg)->fb_size = adp->va_buffer_size;
|
|
return 0;
|
|
|
|
default:
|
|
return fb_commonioctl(adp, cmd, arg);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* diag():
|
|
* Print some information about the video adapter and video modes,
|
|
* with requested level of details.
|
|
*/
|
|
static int
|
|
gdc_diag(video_adapter_t *adp, int level)
|
|
{
|
|
#if FB_DEBUG > 1
|
|
int i;
|
|
#endif
|
|
|
|
if (!gdc_init_done)
|
|
return ENXIO;
|
|
|
|
fb_dump_adp_info(DRIVER_NAME, adp, level);
|
|
|
|
#if FB_DEBUG > 1
|
|
for (i = 0; bios_vmode[i].vi_mode != EOT; ++i) {
|
|
if (bios_vmode[i].vi_mode == NA)
|
|
continue;
|
|
if (get_mode_param(bios_vmode[i].vi_mode) == NULL)
|
|
continue;
|
|
fb_dump_mode_info(DRIVER_NAME, adp, &bios_vmode[i], level);
|
|
}
|
|
#endif
|
|
|
|
return 0;
|
|
}
|