1139825Simp/*-
242805Skato * Copyright (c) 1999 FreeBSD(98) port team.
342805Skato * All rights reserved.
442805Skato *
542805Skato * Redistribution and use in source and binary forms, with or without
642805Skato * modification, are permitted provided that the following conditions
742805Skato * are met:
842805Skato * 1. Redistributions of source code must retain the above copyright
942805Skato *    notice, this list of conditions and the following disclaimer as
1042805Skato *    the first lines of this file unmodified.
1142805Skato * 2. Redistributions in binary form must reproduce the above copyright
1242805Skato *    notice, this list of conditions and the following disclaimer in the
1342805Skato *    documentation and/or other materials provided with the distribution.
1442805Skato * 3. The name of the author may not be used to endorse or promote products
1542805Skato *    derived from this software without specific prior written permission.
1642805Skato *
1742805Skato * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1842805Skato * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1942805Skato * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2042805Skato * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2142805Skato * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2242805Skato * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2342805Skato * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2442805Skato * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2542805Skato * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2642805Skato * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2742805Skato *
2850477Speter * $FreeBSD$
2942795Skato */
3042795Skato
3142795Skato#include "opt_gdc.h"
3242795Skato#include "opt_fb.h"
3342795Skato#include "opt_syscons.h"
3442795Skato
3542795Skato#include <sys/param.h>
3642795Skato#include <sys/systm.h>
3742795Skato#include <sys/kernel.h>
38130174Sphk#include <sys/module.h>
39111311Snyan#include <sys/conf.h>
4042795Skato#include <sys/bus.h>
4183547Snyan#include <machine/bus.h>
4283547Snyan#include <sys/rman.h>
4383547Snyan#include <machine/resource.h>
4442795Skato
4567142Snyan#include <sys/fbio.h>
46111311Snyan#include <sys/fcntl.h>
4767142Snyan
4842795Skato#include <vm/vm.h>
4942795Skato#include <vm/pmap.h>
50130431Simp#include <vm/vm_param.h>
5142795Skato
5242795Skato#include <machine/md_var.h>
5342795Skato#include <machine/pc/bios.h>
5442795Skato
5542795Skato#include <dev/fb/fbreg.h>
5642795Skato
57139946Simp#ifdef LINE30
58146049Snyan#include <pc98/cbus/cbus.h>
59139946Simp#endif
6042795Skato#include <pc98/pc98/pc98_machdep.h>
6145783Skato#include <isa/isavar.h>
6242795Skato
6383547Snyan#define	TEXT_GDC	0x60
6483547Snyan#define	GRAPHIC_GDC	0xa0
6542805Skato#define	ROW		25
6642805Skato#define	COL		80
6742805Skato
6842795Skato#define DRIVER_NAME	"gdc"
6942795Skato
7042795Skato/* cdev driver declaration */
7142795Skato
72183397Sed#define GDC_UNIT(dev)	dev2unit(dev)
7342795Skato#define GDC_MKMINOR(unit) (unit)
7442795Skato
7545783Skatotypedef struct gdc_softc {
7645783Skato	video_adapter_t	*adp;
7783547Snyan	struct resource *res_tgdc, *res_ggdc;
7883547Snyan	struct resource *res_egc, *res_pegc, *res_grcg, *res_kcg;
7983547Snyan	struct resource *res_tmem, *res_gmem1, *res_gmem2;
80111311Snyan#ifdef FB_INSTALL_CDEV
81111311Snyan	genfb_softc_t gensc;
82111311Snyan#endif
8345783Skato} gdc_softc_t;
8442795Skato
8545783Skato#define GDC_SOFTC(unit)	\
8645783Skato	((gdc_softc_t *)devclass_get_softc(gdc_devclass, unit))
8745783Skato
8883547Snyanstatic bus_addr_t	gdc_iat[] = {0, 2, 4, 6, 8, 10, 12, 14};
8983547Snyan
9048187Skatostatic devclass_t	gdc_devclass;
9145783Skato
9242795Skatostatic int		gdc_probe_unit(int unit, gdc_softc_t *sc, int flags);
9342795Skatostatic int		gdc_attach_unit(int unit, gdc_softc_t *sc, int flags);
9483547Snyanstatic int		gdc_alloc_resource(device_t dev);
9583547Snyanstatic int		gdc_release_resource(device_t dev);
9642795Skato
97153165Sru#ifdef FB_INSTALL_CDEV
9842795Skato
9942795Skatostatic d_open_t		gdcopen;
10042795Skatostatic d_close_t	gdcclose;
10142795Skatostatic d_read_t		gdcread;
10248187Skatostatic d_write_t	gdcwrite;
10342795Skatostatic d_ioctl_t	gdcioctl;
10448187Skatostatic d_mmap_t		gdcmmap;
10542795Skato
10659689Snyanstatic struct cdevsw gdc_cdevsw = {
107126080Sphk	.d_version =	D_VERSION,
108126080Sphk	.d_flags =	D_NEEDGIANT,
109111815Sphk	.d_open =	gdcopen,
110111815Sphk	.d_close =	gdcclose,
111111815Sphk	.d_read =	gdcread,
112111815Sphk	.d_write =	gdcwrite,
113111815Sphk	.d_ioctl =	gdcioctl,
114111815Sphk	.d_mmap =	gdcmmap,
115111815Sphk	.d_name =	DRIVER_NAME,
11642795Skato};
11742795Skato
11842795Skato#endif /* FB_INSTALL_CDEV */
11942795Skato
12062952Snyanstatic void
12162952Snyangdc_identify(driver_t *driver, device_t parent)
12262952Snyan{
12362952Snyan	BUS_ADD_CHILD(parent, ISA_ORDER_SPECULATIVE, DRIVER_NAME, 0);
12462952Snyan}
12562952Snyan
12642795Skatostatic int
12763011Snyangdcprobe(device_t dev)
12842795Skato{
12983547Snyan	int error;
13042795Skato
13151276Snyan	/* Check isapnp ids */
13251276Snyan	if (isa_get_vendorid(dev))
13351276Snyan		return (ENXIO);
13451276Snyan
13545783Skato	device_set_desc(dev, "Generic GDC");
13683547Snyan
13783547Snyan	error = gdc_alloc_resource(dev);
13883547Snyan	if (error)
13983547Snyan		return (error);
14083547Snyan
14183547Snyan	error = gdc_probe_unit(device_get_unit(dev),
14283547Snyan			       device_get_softc(dev),
14383547Snyan			       device_get_flags(dev));
14483547Snyan
14583547Snyan	gdc_release_resource(dev);
14683547Snyan
14783547Snyan	return (error);
14842795Skato}
14942795Skato
15042795Skatostatic int
15145783Skatogdc_attach(device_t dev)
15242795Skato{
15342795Skato	gdc_softc_t *sc;
15448187Skato	int error;
15542795Skato
15683547Snyan	error = gdc_alloc_resource(dev);
15783547Snyan	if (error)
15883547Snyan		return (error);
15983547Snyan
16045783Skato	sc = device_get_softc(dev);
16183547Snyan	error = gdc_attach_unit(device_get_unit(dev),
16283547Snyan				sc,
16383547Snyan				device_get_flags(dev));
16483547Snyan	if (error) {
16583547Snyan		gdc_release_resource(dev);
16648187Skato		return error;
16783547Snyan	}
16848187Skato
16948187Skato#ifdef FB_INSTALL_CDEV
17048187Skato	/* attach a virtual frame buffer device */
171120472Sphk	error = fb_attach(GDC_MKMINOR(device_get_unit(dev)),
172111311Snyan				  sc->adp, &gdc_cdevsw);
17383547Snyan	if (error) {
17483547Snyan		gdc_release_resource(dev);
17548187Skato		return error;
17683547Snyan	}
17748187Skato#endif /* FB_INSTALL_CDEV */
17848187Skato
17948187Skato	if (bootverbose)
180174985Swkoszek		vidd_diag(sc->adp, bootverbose);
18148187Skato
18248187Skato	return 0;
18342795Skato}
18442795Skato
18542795Skatostatic int
18642795Skatogdc_probe_unit(int unit, gdc_softc_t *sc, int flags)
18742795Skato{
18842795Skato	video_switch_t *sw;
18942795Skato
19042795Skato	sw = vid_get_switch(DRIVER_NAME);
19142795Skato	if (sw == NULL)
19248187Skato		return ENXIO;
19342795Skato	return (*sw->probe)(unit, &sc->adp, NULL, flags);
19442795Skato}
19542795Skato
19642795Skatostatic int
19742795Skatogdc_attach_unit(int unit, gdc_softc_t *sc, int flags)
19842795Skato{
19942795Skato	video_switch_t *sw;
20042795Skato
20142795Skato	sw = vid_get_switch(DRIVER_NAME);
20242795Skato	if (sw == NULL)
20342795Skato		return ENXIO;
20448187Skato	return (*sw->init)(unit, sc->adp, flags);
20548187Skato}
20642795Skato
20783547Snyan
20883547Snyanstatic int
20983547Snyangdc_alloc_resource(device_t dev)
21083547Snyan{
21183547Snyan	int rid;
21283547Snyan	gdc_softc_t *sc;
21383547Snyan
21483547Snyan	sc = device_get_softc(dev);
21583547Snyan
21683547Snyan	/* TEXT GDC */
21783547Snyan	rid = 0;
21883547Snyan	bus_set_resource(dev, SYS_RES_IOPORT, rid, TEXT_GDC, 1);
21983547Snyan	sc->res_tgdc = isa_alloc_resourcev(dev, SYS_RES_IOPORT, &rid,
22083547Snyan					   gdc_iat, 8, RF_ACTIVE);
22183547Snyan	if (sc->res_tgdc == NULL) {
22283547Snyan		gdc_release_resource(dev);
22383547Snyan		return (ENXIO);
22483547Snyan	}
22583547Snyan	isa_load_resourcev(sc->res_tgdc, gdc_iat, 8);
22683547Snyan
22783547Snyan	/* GRAPHIC GDC */
22883547Snyan	rid = 8;
22983547Snyan	bus_set_resource(dev, SYS_RES_IOPORT, rid, GRAPHIC_GDC, 1);
23083547Snyan	sc->res_ggdc = isa_alloc_resourcev(dev, SYS_RES_IOPORT, &rid,
23183547Snyan					   gdc_iat, 8, RF_ACTIVE);
23283547Snyan	if (sc->res_ggdc == NULL) {
23383547Snyan		gdc_release_resource(dev);
23483547Snyan		return (ENXIO);
23583547Snyan	}
23683547Snyan	isa_load_resourcev(sc->res_ggdc, gdc_iat, 8);
23783547Snyan
23883547Snyan	/* EGC */
23983547Snyan	rid = 16;
24083547Snyan	bus_set_resource(dev, SYS_RES_IOPORT, rid, 0x4a0, 1);
24183547Snyan	sc->res_egc = isa_alloc_resourcev(dev, SYS_RES_IOPORT, &rid,
24283547Snyan					   gdc_iat, 8, RF_ACTIVE);
24383547Snyan	if (sc->res_egc == NULL) {
24483547Snyan		gdc_release_resource(dev);
24583547Snyan		return (ENXIO);
24683547Snyan	}
24783547Snyan	isa_load_resourcev(sc->res_egc, gdc_iat, 8);
24883547Snyan
24983547Snyan	/* PEGC */
25083547Snyan	rid = 24;
25183547Snyan	bus_set_resource(dev, SYS_RES_IOPORT, rid, 0x9a0, 1);
25283547Snyan	sc->res_pegc = isa_alloc_resourcev(dev, SYS_RES_IOPORT, &rid,
25383547Snyan					   gdc_iat, 8, RF_ACTIVE);
25483547Snyan	if (sc->res_pegc == NULL) {
25583547Snyan		gdc_release_resource(dev);
25683547Snyan		return (ENXIO);
25783547Snyan	}
25883547Snyan	isa_load_resourcev(sc->res_pegc, gdc_iat, 8);
25983547Snyan
26083547Snyan	/* CRTC/GRCG */
26183547Snyan	rid = 32;
26283547Snyan	bus_set_resource(dev, SYS_RES_IOPORT, rid, 0x70, 1);
26383547Snyan	sc->res_grcg = isa_alloc_resourcev(dev, SYS_RES_IOPORT, &rid,
26483547Snyan					   gdc_iat, 8, RF_ACTIVE);
26583547Snyan	if (sc->res_grcg == NULL) {
26683547Snyan		gdc_release_resource(dev);
26783547Snyan		return (ENXIO);
26883547Snyan	}
26983547Snyan	isa_load_resourcev(sc->res_grcg, gdc_iat, 8);
27083547Snyan
27183547Snyan	/* KCG */
27283547Snyan	rid = 40;
27383547Snyan	bus_set_resource(dev, SYS_RES_IOPORT, rid, 0xa1, 1);
27483547Snyan	sc->res_kcg = isa_alloc_resourcev(dev, SYS_RES_IOPORT, &rid,
27583547Snyan					  gdc_iat, 8, RF_ACTIVE);
27683547Snyan	if (sc->res_kcg == NULL) {
27783547Snyan		gdc_release_resource(dev);
27883547Snyan		return (ENXIO);
27983547Snyan	}
28083547Snyan	isa_load_resourcev(sc->res_kcg, gdc_iat, 8);
28183547Snyan
28283547Snyan
28383547Snyan	/* TEXT Memory */
28483547Snyan	rid = 0;
28583547Snyan	sc->res_tmem = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid,
28683547Snyan					  0xa0000, 0xa4fff, 0x5000, RF_ACTIVE);
28783547Snyan	if (sc->res_tmem == NULL) {
28883547Snyan		gdc_release_resource(dev);
28983547Snyan		return (ENXIO);
29083547Snyan	}
29183547Snyan
29283547Snyan	/* GRAPHIC Memory */
29383547Snyan	rid = 1;
29483547Snyan	sc->res_gmem1 = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid,
29583547Snyan					   0xa8000, 0xbffff, 0x18000,
29683547Snyan					   RF_ACTIVE);
29783547Snyan	if (sc->res_gmem1 == NULL) {
29883547Snyan		gdc_release_resource(dev);
29983547Snyan		return (ENXIO);
30083547Snyan	}
30183547Snyan	rid = 2;
30283547Snyan	sc->res_gmem2 = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid,
30383547Snyan					   0xe0000, 0xe7fff, 0x8000,
30483547Snyan					   RF_ACTIVE);
30583547Snyan	if (sc->res_gmem2 == NULL) {
30683547Snyan		gdc_release_resource(dev);
30783547Snyan		return (ENXIO);
30883547Snyan	}
30983547Snyan
31083547Snyan	return (0);
31183547Snyan}
31283547Snyan
31383547Snyanstatic int
31483547Snyangdc_release_resource(device_t dev)
31583547Snyan{
31683547Snyan	gdc_softc_t *sc;
31783547Snyan
31883547Snyan	sc = device_get_softc(dev);
31983547Snyan
32083547Snyan	if (sc->res_tgdc)
32183547Snyan		bus_release_resource(dev, SYS_RES_IOPORT,  0, sc->res_tgdc);
32283547Snyan	if (sc->res_ggdc)
32383547Snyan		bus_release_resource(dev, SYS_RES_IOPORT,  8, sc->res_ggdc);
32483547Snyan	if (sc->res_egc)
32583547Snyan		bus_release_resource(dev, SYS_RES_IOPORT, 16, sc->res_egc);
32683547Snyan	if (sc->res_pegc)
32783547Snyan		bus_release_resource(dev, SYS_RES_IOPORT, 24, sc->res_pegc);
32883547Snyan	if (sc->res_grcg)
32983547Snyan		bus_release_resource(dev, SYS_RES_IOPORT, 32, sc->res_grcg);
33083547Snyan	if (sc->res_kcg)
33183547Snyan		bus_release_resource(dev, SYS_RES_IOPORT, 40, sc->res_kcg);
33283547Snyan
33383547Snyan	if (sc->res_tmem)
33483547Snyan		bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->res_tmem);
33583547Snyan	if (sc->res_gmem1)
33683547Snyan		bus_release_resource(dev, SYS_RES_MEMORY, 1, sc->res_gmem1);
33783547Snyan	if (sc->res_gmem2)
33883547Snyan		bus_release_resource(dev, SYS_RES_MEMORY, 2, sc->res_gmem2);
33983547Snyan
34083547Snyan	return (0);
34183547Snyan}
34283547Snyan
34348187Skato/* cdev driver functions */
34442795Skato
34542795Skato#ifdef FB_INSTALL_CDEV
34642795Skato
34748187Skatostatic int
348130585Sphkgdcopen(struct cdev *dev, int flag, int mode, struct thread *td)
34948187Skato{
35048187Skato    gdc_softc_t *sc;
35142795Skato
35248187Skato    sc = GDC_SOFTC(GDC_UNIT(dev));
35348187Skato    if (sc == NULL)
35448187Skato	return ENXIO;
35548187Skato    if (mode & (O_CREAT | O_APPEND | O_TRUNC))
35648187Skato	return ENODEV;
35748187Skato
358111311Snyan    return genfbopen(&sc->gensc, sc->adp, flag, mode, td);
35942795Skato}
36042795Skato
36148187Skatostatic int
362130585Sphkgdcclose(struct cdev *dev, int flag, int mode, struct thread *td)
36348187Skato{
36448187Skato    gdc_softc_t *sc;
36548187Skato
36648187Skato    sc = GDC_SOFTC(GDC_UNIT(dev));
367111311Snyan    return genfbclose(&sc->gensc, sc->adp, flag, mode, td);
36848187Skato}
36948187Skato
37048187Skatostatic int
371130585Sphkgdcread(struct cdev *dev, struct uio *uio, int flag)
37248187Skato{
37348187Skato    gdc_softc_t *sc;
37448187Skato
37548187Skato    sc = GDC_SOFTC(GDC_UNIT(dev));
37648187Skato    return genfbread(&sc->gensc, sc->adp, uio, flag);
37748187Skato}
37848187Skato
37948187Skatostatic int
380130585Sphkgdcwrite(struct cdev *dev, struct uio *uio, int flag)
38148187Skato{
38248187Skato    gdc_softc_t *sc;
38348187Skato
38448187Skato    sc = GDC_SOFTC(GDC_UNIT(dev));
38548187Skato    return genfbread(&sc->gensc, sc->adp, uio, flag);
38648187Skato}
38748187Skato
38848187Skatostatic int
389130585Sphkgdcioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, struct thread *td)
39048187Skato{
39148187Skato    gdc_softc_t *sc;
39248187Skato
39348187Skato    sc = GDC_SOFTC(GDC_UNIT(dev));
394111311Snyan    return genfbioctl(&sc->gensc, sc->adp, cmd, arg, flag, td);
39548187Skato}
39648187Skato
39748187Skatostatic int
398201223Srnolandgdcmmap(struct cdev *dev, vm_ooffset_t offset, vm_paddr_t *paddr,
399201223Srnoland    int prot, vm_memattr_t *memattr)
40048187Skato{
40148187Skato    gdc_softc_t *sc;
40248187Skato
40348187Skato    sc = GDC_SOFTC(GDC_UNIT(dev));
404201223Srnoland    return genfbmmap(&sc->gensc, sc->adp, offset, paddr, prot, memattr);
40548187Skato}
40648187Skato
40748187Skato#endif /* FB_INSTALL_CDEV */
40848187Skato
40962952Snyanstatic device_method_t gdc_methods[] = {
41062952Snyan	DEVMETHOD(device_identify,	gdc_identify),
41163011Snyan	DEVMETHOD(device_probe,		gdcprobe),
41262952Snyan	DEVMETHOD(device_attach,	gdc_attach),
41362952Snyan	{ 0, 0 }
41462952Snyan};
41562952Snyan
41662952Snyanstatic driver_t gdcdriver = {
41762952Snyan	DRIVER_NAME,
41862952Snyan	gdc_methods,
41962952Snyan	sizeof(gdc_softc_t),
42062952Snyan};
42162952Snyan
42262952SnyanDRIVER_MODULE(gdc, isa, gdcdriver, gdc_devclass, 0, 0);
42362952Snyan
42442795Skato/* LOW-LEVEL */
42542795Skato
42642795Skato
427146049Snyan#include <pc98/cbus/30line.h>
42842795Skato
42942795Skato#define TEXT_BUF_BASE		0x000a0000
43042795Skato#define TEXT_BUF_SIZE		0x00008000
43142795Skato#define GRAPHICS_BUF_BASE	0x000a8000
43242795Skato#define GRAPHICS_BUF_SIZE	0x00040000
43342795Skato#define VIDEO_BUF_BASE		0x000a0000
43442795Skato#define VIDEO_BUF_SIZE		0x00048000
43542795Skato
43642795Skato#define probe_done(adp)		((adp)->va_flags & V_ADP_PROBED)
43742795Skato#define init_done(adp)		((adp)->va_flags & V_ADP_INITIALIZED)
43842795Skato#define config_done(adp)	((adp)->va_flags & V_ADP_REGISTERED)
43942795Skato
44042795Skato/*
44142795Skato * NOTE: `va_window' should have a virtual address, but is initialized
44242795Skato * with a physical address in the following table, they will be
44342795Skato * converted at run-time.
44442795Skato */
44542795Skatostatic video_adapter_t adapter_init_value[] = {
44642795Skato    { 0,
44742795Skato      KD_PC98, "gdc",			/* va_type, va_name */
44842795Skato      0, 0, 				/* va_unit, va_minor */
44942795Skato      V_ADP_COLOR | V_ADP_MODECHANGE | V_ADP_BORDER,
45083547Snyan      TEXT_GDC, 16, TEXT_GDC,		/* va_io*, XXX */
45142795Skato      VIDEO_BUF_BASE, VIDEO_BUF_SIZE,	/* va_mem* */
45248187Skato      TEXT_BUF_BASE, TEXT_BUF_SIZE, TEXT_BUF_SIZE, 0, /* va_window* */
45342795Skato      0, 0, 				/* va_buffer, va_buffer_size */
45443709Skato      0, M_PC98_80x25, 0, 		/* va_*mode* */
45543709Skato    },
45642795Skato};
45742795Skato
45842795Skatostatic video_adapter_t	biosadapter[1];
45942795Skato
46042795Skato/* video driver declarations */
46142795Skatostatic int			gdc_configure(int flags);
46248187Skatostatic int			gdc_err(video_adapter_t *adp, ...);
46342795Skatostatic vi_probe_t		gdc_probe;
46442795Skatostatic vi_init_t		gdc_init;
46542795Skatostatic vi_get_info_t		gdc_get_info;
46642795Skatostatic vi_query_mode_t		gdc_query_mode;
46742795Skatostatic vi_set_mode_t		gdc_set_mode;
46842795Skatostatic vi_set_border_t		gdc_set_border;
46942795Skatostatic vi_save_state_t		gdc_save_state;
47042795Skatostatic vi_load_state_t		gdc_load_state;
47142795Skatostatic vi_read_hw_cursor_t	gdc_read_hw_cursor;
47242795Skatostatic vi_set_hw_cursor_t	gdc_set_hw_cursor;
47342795Skatostatic vi_set_hw_cursor_shape_t	gdc_set_hw_cursor_shape;
47448187Skatostatic vi_blank_display_t	gdc_blank_display;
47548187Skatostatic vi_mmap_t		gdc_mmap_buf;
47648187Skatostatic vi_ioctl_t		gdc_dev_ioctl;
47759689Snyanstatic vi_clear_t		gdc_clear;
47859689Snyanstatic vi_fill_rect_t		gdc_fill_rect;
47959689Snyanstatic vi_bitblt_t		gdc_bitblt;
48042795Skatostatic vi_diag_t		gdc_diag;
48159689Snyanstatic vi_save_palette_t	gdc_save_palette;
48259689Snyanstatic vi_load_palette_t	gdc_load_palette;
48359689Snyanstatic vi_set_win_org_t		gdc_set_origin;
48442795Skato
48542795Skatostatic video_switch_t gdcvidsw = {
48642795Skato	gdc_probe,
48742795Skato	gdc_init,
48842795Skato	gdc_get_info,
48942795Skato	gdc_query_mode,
49042795Skato	gdc_set_mode,
49142795Skato	(vi_save_font_t *)gdc_err,
49242795Skato	(vi_load_font_t *)gdc_err,
49342795Skato	(vi_show_font_t *)gdc_err,
49459689Snyan	gdc_save_palette,
49559689Snyan	gdc_load_palette,
49642795Skato	gdc_set_border,
49742795Skato	gdc_save_state,
49842795Skato	gdc_load_state,
49959689Snyan	gdc_set_origin,
50042795Skato	gdc_read_hw_cursor,
50142795Skato	gdc_set_hw_cursor,
50242795Skato	gdc_set_hw_cursor_shape,
50348187Skato	gdc_blank_display,
50448187Skato	gdc_mmap_buf,
50548187Skato	gdc_dev_ioctl,
50659689Snyan	gdc_clear,
50759689Snyan	gdc_fill_rect,
50859689Snyan	gdc_bitblt,
50948187Skato	(int (*)(void))gdc_err,
51048187Skato	(int (*)(void))gdc_err,
51142795Skato	gdc_diag,
51242795Skato};
51342795Skato
51442795SkatoVIDEO_DRIVER(gdc, gdcvidsw, gdc_configure);
51542795Skato
51642795Skato/* GDC BIOS standard video modes */
51742795Skato#define EOT		(-1)
51842795Skato#define NA		(-2)
51942795Skato
52042795Skatostatic video_info_t bios_vmode[] = {
52142795Skato    { M_PC98_80x25, V_INFO_COLOR, 80, 25, 8, 16, 4, 1,
52248187Skato      TEXT_BUF_BASE, TEXT_BUF_SIZE, TEXT_BUF_SIZE, 0, 0, V_INFO_MM_TEXT },
523139946Simp#ifdef LINE30
52442795Skato    { M_PC98_80x30, V_INFO_COLOR, 80, 30, 8, 16, 4, 1,
52548187Skato      TEXT_BUF_BASE, TEXT_BUF_SIZE, TEXT_BUF_SIZE, 0, 0, V_INFO_MM_TEXT },
526139946Simp#endif
52759689Snyan#ifndef GDC_NOGRAPHICS
52859689Snyan    { M_PC98_EGC640x400, V_INFO_COLOR | V_INFO_GRAPHICS,
52959689Snyan      640, 400, 8, 16, 4, 4,
53059689Snyan      GRAPHICS_BUF_BASE, GRAPHICS_BUF_SIZE, GRAPHICS_BUF_SIZE, 0, 0,
531117832Snyan      V_INFO_MM_PLANAR },
53259689Snyan    { M_PC98_PEGC640x400, V_INFO_COLOR | V_INFO_GRAPHICS | V_INFO_VESA,
53359689Snyan      640, 400, 8, 16, 8, 1,
53459689Snyan      GRAPHICS_BUF_BASE, 0x00008000, 0x00008000, 0, 0,
53559689Snyan      V_INFO_MM_PACKED, 1 },
536139946Simp#ifdef LINE30
53759689Snyan    { M_PC98_PEGC640x480, V_INFO_COLOR | V_INFO_GRAPHICS | V_INFO_VESA,
53859689Snyan      640, 480, 8, 16, 8, 1,
53959689Snyan      GRAPHICS_BUF_BASE, 0x00008000, 0x00008000, 0, 0,
54059689Snyan      V_INFO_MM_PACKED, 1 },
54159689Snyan#endif
542139946Simp#endif
54342795Skato    { EOT },
54442795Skato};
54542795Skato
54648187Skatostatic int		gdc_init_done = FALSE;
54742795Skato
54842795Skato/* local functions */
54942795Skatostatic int map_gen_mode_num(int type, int color, int mode);
55042795Skatostatic int probe_adapters(void);
55142795Skato
55242795Skato#define	prologue(adp, flag, err)			\
55348187Skato	if (!gdc_init_done || !((adp)->va_flags & (flag)))	\
55442795Skato	    return (err)
55542795Skato
55642795Skato/* a backdoor for the console driver */
55742795Skatostatic int
55842795Skatogdc_configure(int flags)
55942795Skato{
56042795Skato    probe_adapters();
56142795Skato    biosadapter[0].va_flags |= V_ADP_INITIALIZED;
56242795Skato    if (!config_done(&biosadapter[0])) {
56342795Skato	if (vid_register(&biosadapter[0]) < 0)
56442795Skato	    return 1;
56542795Skato	biosadapter[0].va_flags |= V_ADP_REGISTERED;
56642795Skato    }
56742795Skato
56842795Skato    return 1;
56942795Skato}
57042795Skato
57142795Skato/* local subroutines */
57242795Skato
57342795Skato/* map a generic video mode to a known mode number */
57442795Skatostatic int
57542795Skatomap_gen_mode_num(int type, int color, int mode)
57642795Skato{
57742795Skato    static struct {
57842795Skato	int from;
57942795Skato	int to;
58042795Skato    } mode_map[] = {
58142795Skato	{ M_TEXT_80x25,	M_PC98_80x25, },
582139946Simp#ifdef LINE30
58342795Skato	{ M_TEXT_80x30,	M_PC98_80x30, },
584139946Simp#endif
58542795Skato    };
58642795Skato    int i;
58742795Skato
58842795Skato    for (i = 0; i < sizeof(mode_map)/sizeof(mode_map[0]); ++i) {
58942795Skato        if (mode_map[i].from == mode)
59042795Skato            return mode_map[i].to;
59142795Skato    }
59242795Skato    return mode;
59342795Skato}
59442795Skato
59559689Snyanstatic int
59659689Snyanverify_adapter(video_adapter_t *adp)
59759689Snyan{
59859689Snyan#ifndef GDC_NOGRAPHICS
59959689Snyan    int i;
60059689Snyan
60159689Snyan    if (PC98_SYSTEM_PARAMETER(0x45c) & 0x40) {		/* PEGC exists */
60259689Snyan	adp->va_flags |= V_ADP_VESA;			/* XXX */
60359689Snyan    } else {
60459689Snyan	for (i = 0; bios_vmode[i].vi_mode != EOT; ++i) {
60559689Snyan	    if (bios_vmode[i].vi_flags & V_INFO_VESA)
60659689Snyan		bios_vmode[i].vi_mode = NA;
60759689Snyan	}
60859689Snyan    }
60959689Snyan#endif
61059689Snyan    return 0;
61159689Snyan}
61259689Snyan
61342795Skato/* probe video adapters and return the number of detected adapters */
61442795Skatostatic int
61542795Skatoprobe_adapters(void)
61642795Skato{
61742795Skato    video_info_t info;
61842795Skato
61942795Skato    /* do this test only once */
62048187Skato    if (gdc_init_done)
62142795Skato	return 1;
62248187Skato    gdc_init_done = TRUE;
62342795Skato
62442795Skato    biosadapter[0] = adapter_init_value[0];
62542795Skato    biosadapter[0].va_flags |= V_ADP_PROBED;
62642803Skato    biosadapter[0].va_mode =
62742803Skato	biosadapter[0].va_initial_mode = biosadapter[0].va_initial_bios_mode;
62842795Skato
62964392Snyan    if ((PC98_SYSTEM_PARAMETER(0x597) & 0x80) ||
63064392Snyan	(PC98_SYSTEM_PARAMETER(0x458) & 0x80)) {
63164392Snyan	gdc_FH = (inb(0x9a8) & 1) ? _31KHZ : _24KHZ;
63264392Snyan    } else {
63364392Snyan	gdc_FH = _24KHZ;
63464392Snyan    }
63564392Snyan
63659689Snyan    gdc_get_info(&biosadapter[0], biosadapter[0].va_initial_mode, &info);
63759689Snyan    initialize_gdc(T25_G400, info.vi_flags & V_INFO_GRAPHICS);
63842795Skato
63942795Skato    biosadapter[0].va_window = BIOS_PADDRTOVADDR(info.vi_window);
64042795Skato    biosadapter[0].va_window_size = info.vi_window_size;
64142795Skato    biosadapter[0].va_window_gran = info.vi_window_gran;
64242795Skato    biosadapter[0].va_buffer = 0;
64342795Skato    biosadapter[0].va_buffer_size = 0;
64443709Skato    if (info.vi_flags & V_INFO_GRAPHICS) {
64543709Skato	switch (info.vi_depth/info.vi_planes) {
64643709Skato	case 1:
64743709Skato	    biosadapter[0].va_line_width = info.vi_width/8;
64843709Skato	    break;
64943709Skato	case 2:
65043709Skato	    biosadapter[0].va_line_width = info.vi_width/4;
65143709Skato	    break;
65243709Skato	case 4:
65343709Skato	    biosadapter[0].va_line_width = info.vi_width/2;
65443709Skato	    break;
65543709Skato	case 8:
65643709Skato	default: /* shouldn't happen */
65743709Skato	    biosadapter[0].va_line_width = info.vi_width;
65843709Skato	    break;
65943709Skato	}
66043709Skato    } else {
66143709Skato	biosadapter[0].va_line_width = info.vi_width;
66243709Skato    }
66343709Skato    bcopy(&info, &biosadapter[0].va_info, sizeof(info));
66442795Skato
66559689Snyan    verify_adapter(&biosadapter[0]);
66659689Snyan
66742795Skato    return 1;
66842795Skato}
66942795Skato
67042795Skatostatic void master_gdc_cmd(unsigned int cmd)
67142795Skato{
67283547Snyan    while ( (inb(TEXT_GDC) & 2) != 0);
67383547Snyan    outb(TEXT_GDC+2, cmd);
67442795Skato}
67542795Skato
67642795Skatostatic void master_gdc_prm(unsigned int pmtr)
67742795Skato{
67883547Snyan    while ( (inb(TEXT_GDC) & 2) != 0);
67983547Snyan    outb(TEXT_GDC, pmtr);
68042795Skato}
68142795Skato
68242795Skatostatic void master_gdc_word_prm(unsigned int wpmtr)
68342795Skato{
68442795Skato    master_gdc_prm(wpmtr & 0x00ff);
68542795Skato    master_gdc_prm((wpmtr >> 8) & 0x00ff);
68642795Skato}
68742795Skato
688139946Simp#ifdef LINE30
68942795Skatostatic void master_gdc_fifo_empty(void)
69042795Skato{
69183547Snyan    while ( (inb(TEXT_GDC) & 4) == 0);
69242795Skato}
693139946Simp#endif
69442795Skato
69542795Skatostatic void master_gdc_wait_vsync(void)
69642795Skato{
69783547Snyan    while ( (inb(TEXT_GDC) & 0x20) != 0);
69883547Snyan    while ( (inb(TEXT_GDC) & 0x20) == 0);
69942795Skato}
70042795Skato
70142795Skatostatic void gdc_cmd(unsigned int cmd)
70242795Skato{
70383547Snyan    while ( (inb(GRAPHIC_GDC) & 2) != 0);
70483547Snyan    outb( GRAPHIC_GDC+2, cmd);
70542795Skato}
70642795Skato
707139946Simp#ifdef LINE30
70842795Skatostatic void gdc_prm(unsigned int pmtr)
70942795Skato{
71083547Snyan    while ( (inb(GRAPHIC_GDC) & 2) != 0);
71183547Snyan    outb( GRAPHIC_GDC, pmtr);
71242795Skato}
71342795Skato
71442795Skatostatic void gdc_word_prm(unsigned int wpmtr)
71542795Skato{
71642795Skato    gdc_prm(wpmtr & 0x00ff);
71742795Skato    gdc_prm((wpmtr >> 8) & 0x00ff);
71842795Skato}
71942795Skato
72042795Skatostatic void gdc_fifo_empty(void)
72142795Skato{
72283547Snyan    while ( (inb(GRAPHIC_GDC) & 0x04) == 0);
72342795Skato}
724139946Simp#endif
72542795Skato
72642795Skatostatic void gdc_wait_vsync(void)
72742795Skato{
72883547Snyan    while ( (inb(GRAPHIC_GDC) & 0x20) != 0);
72983547Snyan    while ( (inb(GRAPHIC_GDC) & 0x20) == 0);
73042795Skato}
73142795Skato
732139946Simp#ifdef LINE30
73342795Skatostatic int check_gdc_clock(void)
73442795Skato{
73542795Skato    if ((inb(IO_SYSPORT) & 0x80) == 0){
73642795Skato       	return _5MHZ;
73742795Skato    } else {
73842795Skato       	return _2_5MHZ;
73942795Skato    }
74042795Skato}
741139946Simp#endif
74242795Skato
74359689Snyanstatic void initialize_gdc(unsigned int mode, int isGraph)
74442795Skato{
745139946Simp#ifdef LINE30
74642795Skato    /* start 30line initialize */
74759689Snyan    int m_mode, s_mode, gdc_clock, hsync_clock;
74859689Snyan
74942795Skato    gdc_clock = check_gdc_clock();
75059689Snyan    m_mode = (mode == T25_G400) ? _25L : _30L;
75159689Snyan    s_mode = 2*mode+gdc_clock;
75259689Snyan    gdc_INFO = m_mode;
75342795Skato
75464392Snyan    master_gdc_wait_vsync();
75564392Snyan
75659689Snyan    if ((PC98_SYSTEM_PARAMETER(0x597) & 0x80) ||
75759689Snyan	(PC98_SYSTEM_PARAMETER(0x458) & 0x80)) {
75864392Snyan	if (PC98_SYSTEM_PARAMETER(0x481) & 0x08) {
75967788Snyan	    hsync_clock = (m_mode == _25L) ? gdc_FH : _31KHZ;
76064392Snyan	    outb(0x9a8, (hsync_clock == _31KHZ) ? 1 : 0);
76164392Snyan	} else {
76264392Snyan	    hsync_clock = gdc_FH;
76364392Snyan	}
76459689Snyan    } else {
76559689Snyan	hsync_clock = _24KHZ;
76642795Skato    }
76742795Skato
76859689Snyan    if ((gdc_clock == _2_5MHZ) &&
76959689Snyan	(slave_param[hsync_clock][s_mode][GDC_LF] > 400)) {
77059689Snyan	outb(0x6a, 0x83);
77159689Snyan	outb(0x6a, 0x85);
77259689Snyan	gdc_clock = _5MHZ;
77359689Snyan	s_mode = 2*mode+gdc_clock;
77459689Snyan    }
77542795Skato
77642795Skato    master_gdc_cmd(_GDC_RESET);
77742795Skato    master_gdc_cmd(_GDC_MASTER);
77842795Skato    gdc_cmd(_GDC_RESET);
77942795Skato    gdc_cmd(_GDC_SLAVE);
78042795Skato
78142795Skato    /* GDC Master */
78242795Skato    master_gdc_cmd(_GDC_SYNC);
78342795Skato    master_gdc_prm(0x00);	/* flush less */ /* text & graph */
78459689Snyan    master_gdc_prm(master_param[hsync_clock][m_mode][GDC_CR]);
78559689Snyan    master_gdc_word_prm(((master_param[hsync_clock][m_mode][GDC_HFP] << 10)
78659689Snyan		     + (master_param[hsync_clock][m_mode][GDC_VS] << 5)
78759689Snyan		     + master_param[hsync_clock][m_mode][GDC_HS]));
78859689Snyan    master_gdc_prm(master_param[hsync_clock][m_mode][GDC_HBP]);
78959689Snyan    master_gdc_prm(master_param[hsync_clock][m_mode][GDC_VFP]);
79059689Snyan    master_gdc_word_prm(((master_param[hsync_clock][m_mode][GDC_VBP] << 10)
79159689Snyan       		     + (master_param[hsync_clock][m_mode][GDC_LF])));
79242795Skato    master_gdc_fifo_empty();
79342795Skato    master_gdc_cmd(_GDC_PITCH);
79442795Skato    master_gdc_prm(MasterPCH);
79542795Skato    master_gdc_fifo_empty();
79642795Skato
79742795Skato    /* GDC slave */
79842795Skato    gdc_cmd(_GDC_SYNC);
79942795Skato    gdc_prm(0x06);
80059689Snyan    gdc_prm(slave_param[hsync_clock][s_mode][GDC_CR]);
80159689Snyan    gdc_word_prm((slave_param[hsync_clock][s_mode][GDC_HFP] << 10)
80259689Snyan		+ (slave_param[hsync_clock][s_mode][GDC_VS] << 5)
80359689Snyan		+ (slave_param[hsync_clock][s_mode][GDC_HS]));
80459689Snyan    gdc_prm(slave_param[hsync_clock][s_mode][GDC_HBP]);
80559689Snyan    gdc_prm(slave_param[hsync_clock][s_mode][GDC_VFP]);
80659689Snyan    gdc_word_prm((slave_param[hsync_clock][s_mode][GDC_VBP] << 10)
80759689Snyan		+ (slave_param[hsync_clock][s_mode][GDC_LF]));
80842795Skato    gdc_fifo_empty();
80942795Skato    gdc_cmd(_GDC_PITCH);
81042795Skato    gdc_prm(SlavePCH[gdc_clock]);
81142795Skato    gdc_fifo_empty();
81242795Skato
81342795Skato    /* set Master GDC scroll param */
81442795Skato    master_gdc_wait_vsync();
81542795Skato    master_gdc_wait_vsync();
81642795Skato    master_gdc_wait_vsync();
81742795Skato    master_gdc_cmd(_GDC_SCROLL);
81842795Skato    master_gdc_word_prm(0);
81959689Snyan    master_gdc_word_prm((master_param[hsync_clock][m_mode][GDC_LF] << 4)
82059689Snyan			| 0x0000);
82142795Skato    master_gdc_fifo_empty();
82242795Skato
82342795Skato    /* set Slave GDC scroll param */
82442795Skato    gdc_wait_vsync();
82542795Skato    gdc_cmd(_GDC_SCROLL);
82642795Skato    gdc_word_prm(0);
82759689Snyan    if (gdc_clock == _5MHZ) {
82842795Skato	gdc_word_prm((SlaveScrlLF[mode] << 4)  | 0x4000);
82959689Snyan    } else {
83042795Skato	gdc_word_prm(SlaveScrlLF[mode] << 4);
83142795Skato    }
83242795Skato    gdc_fifo_empty();
83342795Skato
83442795Skato    gdc_word_prm(0);
83559689Snyan    if (gdc_clock == _5MHZ) {
83642795Skato	gdc_word_prm((SlaveScrlLF[mode] << 4)  | 0x4000);
83759689Snyan    } else {
83842795Skato	gdc_word_prm(SlaveScrlLF[mode] << 4);
83942795Skato    }
84042795Skato    gdc_fifo_empty();
84142795Skato
84242795Skato    /* sync start */
84359689Snyan    gdc_cmd(isGraph ? _GDC_START : _GDC_STOP);
84442795Skato
84542795Skato    gdc_wait_vsync();
84642795Skato    gdc_wait_vsync();
84742795Skato    gdc_wait_vsync();
84842795Skato
84959689Snyan    master_gdc_cmd(isGraph ? _GDC_STOP : _GDC_START);
850139946Simp#else
851139946Simp    master_gdc_wait_vsync();
852139946Simp    master_gdc_cmd(isGraph ? _GDC_STOP : _GDC_START);	/* text */
853139946Simp    gdc_wait_vsync();
854139946Simp    gdc_cmd(isGraph ? _GDC_START : _GDC_STOP);		/* graphics */
855139946Simp#endif
85642795Skato}
85742795Skato
85859689Snyan#ifndef GDC_NOGRAPHICS
85959689Snyanstatic u_char b_palette[] = {
86059689Snyan    /* R     G     B */
86159689Snyan    0x00, 0x00, 0x00,	/* 0 */
86259689Snyan    0x00, 0x00, 0x7f,	/* 1 */
86359689Snyan    0x7f, 0x00, 0x00,	/* 2 */
86459689Snyan    0x7f, 0x00, 0x7f,	/* 3 */
86559689Snyan    0x00, 0x7f, 0x00,	/* 4 */
86659689Snyan    0x00, 0x7f, 0x7f,	/* 5 */
86759689Snyan    0x7f, 0x7f, 0x00,	/* 6 */
86859689Snyan    0x7f, 0x7f, 0x7f,	/* 7 */
86959689Snyan    0x40, 0x40, 0x40,	/* 8 */
87059689Snyan    0x00, 0x00, 0xff,	/* 9 */
87159689Snyan    0xff, 0x00, 0x00,	/* 10 */
87259689Snyan    0xff, 0x00, 0xff,	/* 11 */
87359689Snyan    0x00, 0xff, 0x00,	/* 12 */
87459689Snyan    0x00, 0xff, 0xff,	/* 13 */
87559689Snyan    0xff, 0xff, 0x00,	/* 14 */
87659689Snyan    0xff, 0xff, 0xff,	/* 15 */
87759689Snyan};
87859689Snyan#endif
87942795Skato
88042795Skatostatic int
88159689Snyangdc_load_palette(video_adapter_t *adp, u_char *palette)
88259689Snyan{
88359689Snyan#ifndef GDC_NOGRAPHICS
88459689Snyan    int i;
88559689Snyan
88659689Snyan    if (adp->va_info.vi_flags & V_INFO_VESA) {
88759689Snyan	gdc_wait_vsync();
88859689Snyan	for (i = 0; i < 256; ++i) {
88959689Snyan	    outb(0xa8, i);
89059689Snyan	    outb(0xac, *palette++);	/* R */
89159689Snyan	    outb(0xaa, *palette++);	/* G */
89259689Snyan	    outb(0xae, *palette++);	/* B */
89359689Snyan	}
89459689Snyan    } else {
89559689Snyan	/*
89659689Snyan	 * XXX - Even though PC-98 text color is independent of palette,
89759689Snyan	 * we should set palette in text mode.
89859689Snyan	 * Because the background color of text mode is palette 0's one.
89959689Snyan	 */
90059689Snyan	outb(0x6a, 1);		/* 16 colors mode */
90159689Snyan	bcopy(palette, b_palette, sizeof(b_palette));
90259689Snyan
90359689Snyan	gdc_wait_vsync();
90459689Snyan	for (i = 0; i < 16; ++i) {
90559689Snyan	    outb(0xa8, i);
90659689Snyan	    outb(0xac, *palette++ >> 4);	/* R */
90759689Snyan	    outb(0xaa, *palette++ >> 4);	/* G */
90859689Snyan	    outb(0xae, *palette++ >> 4);	/* B */
90959689Snyan	}
91059689Snyan    }
91159689Snyan#endif
91259689Snyan    return 0;
91359689Snyan}
91459689Snyan
91559689Snyanstatic int
91659689Snyangdc_save_palette(video_adapter_t *adp, u_char *palette)
91759689Snyan{
91859689Snyan#ifndef GDC_NOGRAPHICS
91959689Snyan    int i;
92059689Snyan
92159689Snyan    if (adp->va_info.vi_flags & V_INFO_VESA) {
92259689Snyan	for (i = 0; i < 256; ++i) {
92359689Snyan	    outb(0xa8, i);
92459689Snyan	    *palette++ = inb(0xac);	/* R */
92559689Snyan	    *palette++ = inb(0xaa);	/* G */
92659689Snyan	    *palette++ = inb(0xae);	/* B */
92759689Snyan	}
92859689Snyan    } else {
92959689Snyan	bcopy(b_palette, palette, sizeof(b_palette));
93059689Snyan    }
93159689Snyan#endif
93259689Snyan    return 0;
93359689Snyan}
93459689Snyan
93559689Snyanstatic int
93659689Snyangdc_set_origin(video_adapter_t *adp, off_t offset)
93759689Snyan{
93859689Snyan#ifndef GDC_NOGRAPHICS
93959689Snyan    if (adp->va_info.vi_flags & V_INFO_VESA) {
94059689Snyan	writew(BIOS_PADDRTOVADDR(0x000e0004), offset >> 15);
94159689Snyan    }
94259689Snyan#endif
94359689Snyan    return 0;
94459689Snyan}
94559689Snyan
94659689Snyan/* entry points */
94759689Snyan
94842795Skatostatic int
94948187Skatogdc_err(video_adapter_t *adp, ...)
95048187Skato{
95148187Skato    return ENODEV;
95248187Skato}
95348187Skato
95448187Skatostatic int
95542795Skatogdc_probe(int unit, video_adapter_t **adpp, void *arg, int flags)
95642795Skato{
95742795Skato    probe_adapters();
95842795Skato    if (unit >= 1)
95942795Skato	return ENXIO;
96042795Skato
96142795Skato    *adpp = &biosadapter[unit];
96242795Skato
96342795Skato    return 0;
96442795Skato}
96542795Skato
96642795Skatostatic int
96742795Skatogdc_init(int unit, video_adapter_t *adp, int flags)
96842795Skato{
96942795Skato    if ((unit >= 1) || (adp == NULL) || !probe_done(adp))
97042795Skato	return ENXIO;
97142795Skato
97242795Skato    if (!init_done(adp)) {
97342795Skato	/* nothing to do really... */
97442795Skato	adp->va_flags |= V_ADP_INITIALIZED;
97542795Skato    }
97642795Skato
97742795Skato    if (!config_done(adp)) {
97842795Skato	if (vid_register(adp) < 0)
97942795Skato		return ENXIO;
98042795Skato	adp->va_flags |= V_ADP_REGISTERED;
98142795Skato    }
98242795Skato
98342795Skato    return 0;
98442795Skato}
98542795Skato
98642795Skato/*
98742795Skato * get_info():
98842795Skato * Return the video_info structure of the requested video mode.
98942795Skato */
99042795Skatostatic int
99142795Skatogdc_get_info(video_adapter_t *adp, int mode, video_info_t *info)
99242795Skato{
99342795Skato    int i;
99442795Skato
99548187Skato    if (!gdc_init_done)
99648187Skato	return ENXIO;
99742795Skato
99842795Skato    mode = map_gen_mode_num(adp->va_type, adp->va_flags & V_ADP_COLOR, mode);
99942795Skato    for (i = 0; bios_vmode[i].vi_mode != EOT; ++i) {
100042795Skato	if (bios_vmode[i].vi_mode == NA)
100142795Skato	    continue;
100242795Skato	if (mode == bios_vmode[i].vi_mode) {
100342795Skato	    *info = bios_vmode[i];
100448187Skato	    info->vi_buffer_size = info->vi_window_size*info->vi_planes;
100542795Skato	    return 0;
100642795Skato	}
100742795Skato    }
100848187Skato    return EINVAL;
100942795Skato}
101042795Skato
101142795Skato/*
101242795Skato * query_mode():
101342795Skato * Find a video mode matching the requested parameters.
101442795Skato * Fields filled with 0 are considered "don't care" fields and
101542795Skato * match any modes.
101642795Skato */
101742795Skatostatic int
101842795Skatogdc_query_mode(video_adapter_t *adp, video_info_t *info)
101942795Skato{
102042795Skato    int i;
102142795Skato
102248187Skato    if (!gdc_init_done)
102354358Skato	return ENXIO;
102442795Skato
102542795Skato    for (i = 0; bios_vmode[i].vi_mode != EOT; ++i) {
102642795Skato	if (bios_vmode[i].vi_mode == NA)
102742795Skato	    continue;
102842795Skato
102942795Skato	if ((info->vi_width != 0)
103042795Skato	    && (info->vi_width != bios_vmode[i].vi_width))
103142795Skato		continue;
103242795Skato	if ((info->vi_height != 0)
103342795Skato	    && (info->vi_height != bios_vmode[i].vi_height))
103442795Skato		continue;
103542795Skato	if ((info->vi_cwidth != 0)
103642795Skato	    && (info->vi_cwidth != bios_vmode[i].vi_cwidth))
103742795Skato		continue;
103842795Skato	if ((info->vi_cheight != 0)
103942795Skato	    && (info->vi_cheight != bios_vmode[i].vi_cheight))
104042795Skato		continue;
104142795Skato	if ((info->vi_depth != 0)
104242795Skato	    && (info->vi_depth != bios_vmode[i].vi_depth))
104342795Skato		continue;
104442795Skato	if ((info->vi_planes != 0)
104542795Skato	    && (info->vi_planes != bios_vmode[i].vi_planes))
104642795Skato		continue;
104742795Skato	/* XXX: should check pixel format, memory model */
104842795Skato	if ((info->vi_flags != 0)
104942795Skato	    && (info->vi_flags != bios_vmode[i].vi_flags))
105042795Skato		continue;
105142795Skato
105242795Skato	/* verify if this mode is supported on this adapter */
105354358Skato	if (gdc_get_info(adp, bios_vmode[i].vi_mode, info))
105442795Skato		continue;
105554358Skato	return 0;
105642795Skato    }
105754358Skato    return ENODEV;
105842795Skato}
105942795Skato
106042795Skato/*
106142795Skato * set_mode():
106242795Skato * Change the video mode.
106342795Skato */
106442795Skatostatic int
106542795Skatogdc_set_mode(video_adapter_t *adp, int mode)
106642795Skato{
106742795Skato    video_info_t info;
106842795Skato
106948187Skato    prologue(adp, V_ADP_MODECHANGE, ENODEV);
107042795Skato
107142795Skato    mode = map_gen_mode_num(adp->va_type,
107242795Skato			    adp->va_flags & V_ADP_COLOR, mode);
107342795Skato    if (gdc_get_info(adp, mode, &info))
107448187Skato	return EINVAL;
107542795Skato
107644421Skato    switch (info.vi_mode) {
107759689Snyan#ifndef GDC_NOGRAPHICS
107859689Snyan	case M_PC98_PEGC640x480:	/* PEGC 640x480 */
107959689Snyan	    initialize_gdc(T30_G480, info.vi_flags & V_INFO_GRAPHICS);
108059689Snyan	    break;
108159689Snyan	case M_PC98_PEGC640x400:	/* PEGC 640x400 */
108259689Snyan	case M_PC98_EGC640x400:		/* EGC GRAPHICS */
108359689Snyan#endif
108459689Snyan	case M_PC98_80x25:		/* VGA TEXT */
108559689Snyan	    initialize_gdc(T25_G400, info.vi_flags & V_INFO_GRAPHICS);
108659689Snyan	    break;
108759689Snyan	case M_PC98_80x30:		/* VGA TEXT */
108859689Snyan	    initialize_gdc(T30_G400, info.vi_flags & V_INFO_GRAPHICS);
108959689Snyan	    break;
109042795Skato	default:
109159689Snyan	    break;
109242795Skato    }
109359689Snyan
109459689Snyan#ifndef GDC_NOGRAPHICS
109559689Snyan    if (info.vi_flags & V_INFO_VESA) {
109659689Snyan	outb(0x6a, 0x07);		/* enable mode F/F change */
109759689Snyan	outb(0x6a, 0x21);		/* enhanced graphics */
109859689Snyan	if (info.vi_height > 400)
109959689Snyan	    outb(0x6a, 0x69);		/* 800 lines */
110059689Snyan	writeb(BIOS_PADDRTOVADDR(0x000e0100), 0);	/* packed pixel */
110159689Snyan    } else {
110259689Snyan	if (adp->va_flags & V_ADP_VESA) {
110359689Snyan	    outb(0x6a, 0x07);		/* enable mode F/F change */
110459689Snyan	    outb(0x6a, 0x20);		/* normal graphics */
110559689Snyan	    outb(0x6a, 0x68);		/* 400 lines */
110659689Snyan	}
110759689Snyan	outb(0x6a, 1);			/* 16 colors */
110859689Snyan    }
110942795Skato#endif
111042795Skato
111142795Skato    adp->va_mode = mode;
111242795Skato    adp->va_flags &= ~V_ADP_COLOR;
111342795Skato    adp->va_flags |=
111442795Skato	(info.vi_flags & V_INFO_COLOR) ? V_ADP_COLOR : 0;
111542795Skato#if 0
111642795Skato    adp->va_crtc_addr =
111742795Skato	(adp->va_flags & V_ADP_COLOR) ? COLOR_CRTC : MONO_CRTC;
111842795Skato#endif
111942795Skato    adp->va_window = BIOS_PADDRTOVADDR(info.vi_window);
112042795Skato    adp->va_window_size = info.vi_window_size;
112142795Skato    adp->va_window_gran = info.vi_window_gran;
112242795Skato    if (info.vi_buffer_size == 0) {
112342795Skato    	adp->va_buffer = 0;
112442795Skato    	adp->va_buffer_size = 0;
112542795Skato    } else {
112642795Skato    	adp->va_buffer = BIOS_PADDRTOVADDR(info.vi_buffer);
112742795Skato    	adp->va_buffer_size = info.vi_buffer_size;
112842795Skato    }
112943709Skato    if (info.vi_flags & V_INFO_GRAPHICS) {
113043709Skato	switch (info.vi_depth/info.vi_planes) {
113143709Skato	case 1:
113243709Skato	    adp->va_line_width = info.vi_width/8;
113343709Skato	    break;
113443709Skato	case 2:
113543709Skato	    adp->va_line_width = info.vi_width/4;
113643709Skato	    break;
113743709Skato	case 4:
113843709Skato	    adp->va_line_width = info.vi_width/2;
113943709Skato	    break;
114043709Skato	case 8:
114143709Skato	default: /* shouldn't happen */
114243709Skato	    adp->va_line_width = info.vi_width;
114343709Skato	    break;
114443709Skato	}
114543709Skato    } else {
114643709Skato	adp->va_line_width = info.vi_width;
114743709Skato    }
114843709Skato    bcopy(&info, &adp->va_info, sizeof(info));
114942795Skato
115042795Skato    /* move hardware cursor out of the way */
1151174985Swkoszek    vidd_set_hw_cursor(adp, -1, -1);
115242795Skato
115342795Skato    return 0;
115442795Skato}
115542795Skato
115642795Skato/*
115742795Skato * set_border():
115842795Skato * Change the border color.
115942795Skato */
116042795Skatostatic int
116142795Skatogdc_set_border(video_adapter_t *adp, int color)
116242795Skato{
116342795Skato    outb(0x6c, color << 4);
116442795Skato    return 0;
116542795Skato}
116642795Skato
116742795Skato/*
116842795Skato * save_state():
116942795Skato * Read video card register values.
117042795Skato */
117142795Skatostatic int
117242795Skatogdc_save_state(video_adapter_t *adp, void *p, size_t size)
117342795Skato{
117448187Skato    return ENODEV;
117542795Skato}
117642795Skato
117742795Skato/*
117842795Skato * load_state():
117942795Skato * Set video card registers at once.
118042795Skato */
118142795Skatostatic int
118242795Skatogdc_load_state(video_adapter_t *adp, void *p)
118342795Skato{
118448187Skato    return ENODEV;
118542795Skato}
118642795Skato
118742795Skato/*
118842795Skato * read_hw_cursor():
118942795Skato * Read the position of the hardware text cursor.
119042795Skato */
119142795Skatostatic int
119242795Skatogdc_read_hw_cursor(video_adapter_t *adp, int *col, int *row)
119342795Skato{
119442795Skato    u_int16_t off;
119542795Skato    int s;
119642795Skato
119748187Skato    if (!gdc_init_done)
119848187Skato	return ENXIO;
119942795Skato
120043709Skato    if (adp->va_info.vi_flags & V_INFO_GRAPHICS)
120148187Skato	return ENODEV;
120242795Skato
120342795Skato    s = spltty();
120442795Skato    master_gdc_cmd(0xe0);	/* _GDC_CSRR */
120542795Skato    while((inb(TEXT_GDC + 0) & 0x1) == 0) {}	/* GDC wait */
120642795Skato    off = inb(TEXT_GDC + 2);			/* EADl */
120742795Skato    off |= (inb(TEXT_GDC + 2) << 8);		/* EADh */
120842795Skato    inb(TEXT_GDC + 2);				/* dummy */
120942795Skato    inb(TEXT_GDC + 2);				/* dummy */
121042795Skato    inb(TEXT_GDC + 2);				/* dummy */
121142795Skato    splx(s);
121242795Skato
121342795Skato    if (off >= ROW*COL)
121442795Skato	off = 0;
121543709Skato    *row = off / adp->va_info.vi_width;
121643709Skato    *col = off % adp->va_info.vi_width;
121742795Skato
121842795Skato    return 0;
121942795Skato}
122042795Skato
122142795Skato/*
122242795Skato * set_hw_cursor():
122342795Skato * Move the hardware text cursor.  If col and row are both -1,
122442795Skato * the cursor won't be shown.
122542795Skato */
122642795Skatostatic int
122742795Skatogdc_set_hw_cursor(video_adapter_t *adp, int col, int row)
122842795Skato{
122942795Skato    u_int16_t off;
123042795Skato    int s;
123142795Skato
123248187Skato    if (!gdc_init_done)
123348187Skato	return ENXIO;
123442795Skato
123542795Skato    if ((col == -1) && (row == -1)) {
123642795Skato	off = -1;
123742795Skato    } else {
123843709Skato	if (adp->va_info.vi_flags & V_INFO_GRAPHICS)
123948187Skato	    return ENODEV;
124043709Skato	off = row*adp->va_info.vi_width + col;
124142795Skato    }
124242795Skato
124342795Skato    s = spltty();
124442795Skato    master_gdc_cmd(0x49);	/* _GDC_CSRW */
124542795Skato    master_gdc_word_prm(off);
124642795Skato    splx(s);
124742795Skato
124842795Skato    return 0;
124942795Skato}
125042795Skato
125142795Skato/*
125242795Skato * set_hw_cursor_shape():
125342795Skato * Change the shape of the hardware text cursor.  If the height is zero
125442795Skato * or negative, the cursor won't be shown.
125542795Skato */
125642795Skatostatic int
125742795Skatogdc_set_hw_cursor_shape(video_adapter_t *adp, int base, int height,
125842795Skato			int celsize, int blink)
125942795Skato{
126042795Skato    int start;
126142795Skato    int end;
126242795Skato    int s;
126342795Skato
126448187Skato    if (!gdc_init_done)
126548187Skato	return ENXIO;
126648187Skato
126742795Skato    start = celsize - (base + height);
126842795Skato    end = celsize - base - 1;
126964394Snyan
127064394Snyan#if 0
127142795Skato    /*
127242795Skato     * muPD7220 GDC has anomaly that if end == celsize - 1 then start
127342795Skato     * must be 0, otherwise the cursor won't be correctly shown
127442795Skato     * in the first row in the screen.  We shall set end to celsize - 2;
127542795Skato     * if end == celsize -1 && start > 0. XXX
127642795Skato     */
127764394Snyan    if ((end == celsize - 1) && (start > 0) && (start < end))
127842795Skato	--end;
127964394Snyan#endif
128042795Skato
128142795Skato    s = spltty();
128242795Skato    master_gdc_cmd(0x4b);			/* _GDC_CSRFORM */
128342795Skato    master_gdc_prm(((height > 0) ? 0x80 : 0)	/* cursor on/off */
128448187Skato	| ((celsize - 1) & 0x1f));		/* cel size */
128542795Skato    master_gdc_word_prm(((end & 0x1f) << 11)	/* end line */
128642795Skato	| (12 << 6)				/* blink rate */
128764394Snyan	| (blink ? 0 : 0x20)			/* blink on/off */
128842795Skato	| (start & 0x1f));			/* start line */
128942795Skato    splx(s);
129042795Skato
129148187Skato    return 0;
129242795Skato}
129342795Skato
129448187Skato/*
129548187Skato * blank_display()
129648187Skato * Put the display in power save/power off mode.
129748187Skato */
129848187Skatostatic int
129948187Skatogdc_blank_display(video_adapter_t *adp, int mode)
130042795Skato{
130148187Skato    int s;
130258780Snyan    static int standby = 0;
130342795Skato
130448187Skato    if (!gdc_init_done)
130548187Skato	return ENXIO;
130648187Skato
130748187Skato    s = splhigh();
130848187Skato    switch (mode) {
130948187Skato    case V_DISPLAY_SUSPEND:
131048187Skato    case V_DISPLAY_STAND_BY:
131158780Snyan	outb(0x09a2, 0x80 | 0x40);		/* V/H-SYNC mask */
131258780Snyan	if (inb(0x09a2) == (0x80 | 0x40))
131358780Snyan	    standby = 1;
1314102412Scharnier	/* FALLTHROUGH */
131548187Skato
131648187Skato    case V_DISPLAY_BLANK:
1317150127Snyan	while (!(inb(TEXT_GDC) & 0x20))		/* V-SYNC wait */
1318150127Snyan	    ;
1319150127Snyan	outb(TEXT_GDC + 8, 0x0e);		/* DISP off */
132048187Skato	break;
132148187Skato
132248187Skato    case V_DISPLAY_ON:
1323150127Snyan	while (!(inb(TEXT_GDC) & 0x20))		/* V-SYNC wait */
1324150127Snyan	    ;
1325150127Snyan	outb(TEXT_GDC + 8, 0x0f);		/* DISP on */
132658780Snyan	if (standby) {
132758780Snyan	    outb(0x09a2, 0x00);			/* V/H-SYNC unmask */
132858780Snyan	    standby = 0;
132958780Snyan	}
133048187Skato	break;
133142795Skato    }
133248187Skato    splx(s);
133348187Skato    return 0;
133442795Skato}
133542795Skato
133642795Skato/*
133742795Skato * mmap():
133842795Skato * Mmap frame buffer.
133942795Skato */
134042795Skatostatic int
1341201223Srnolandgdc_mmap_buf(video_adapter_t *adp, vm_ooffset_t offset, vm_offset_t *paddr,
1342201223Srnoland	     int prot, vm_memattr_t *memattr)
134342795Skato{
134448187Skato    /* FIXME: is this correct? XXX */
134548187Skato    if (offset > VIDEO_BUF_SIZE - PAGE_SIZE)
134642795Skato	return -1;
1347111481Smux    *paddr = adp->va_info.vi_window + offset;
1348111481Smux    return 0;
134942795Skato}
135042795Skato
1351117832Snyan#ifndef GDC_NOGRAPHICS
1352117832Snyanstatic void
1353117832Snyanplanar_fill(video_adapter_t *adp, int val)
1354117832Snyan{
1355117832Snyan
1356117832Snyan    outb(0x7c, 0x80);				/* GRCG on & TDW mode */
1357117832Snyan    outb(0x7e, 0);				/* tile B */
1358117832Snyan    outb(0x7e, 0);				/* tile R */
1359117832Snyan    outb(0x7e, 0);				/* tile G */
1360117832Snyan    outb(0x7e, 0);				/* tile I */
1361117832Snyan
1362117832Snyan    fillw_io(0, adp->va_window, 0x8000 / 2);	/* XXX */
1363117832Snyan
1364117832Snyan    outb(0x7c, 0);				/* GRCG off */
1365117832Snyan}
1366117832Snyan
1367117832Snyanstatic void
1368117832Snyanpacked_fill(video_adapter_t *adp, int val)
1369117832Snyan{
1370117832Snyan    int length;
1371117832Snyan    int at;			/* position in the frame buffer */
1372117832Snyan    int l;
1373117832Snyan
1374117832Snyan    at = 0;
1375117832Snyan    length = adp->va_line_width*adp->va_info.vi_height;
1376117832Snyan    while (length > 0) {
1377117832Snyan	l = imin(length, adp->va_window_size);
1378174985Swkoszek	vidd_set_win_org(adp, at);
1379117832Snyan	bzero_io(adp->va_window, l);
1380117832Snyan	length -= l;
1381117832Snyan	at += l;
1382117832Snyan    }
1383117832Snyan}
1384117832Snyan
138548187Skatostatic int
138659689Snyangdc_clear(video_adapter_t *adp)
138759689Snyan{
1388117832Snyan
1389117832Snyan    switch (adp->va_info.vi_mem_model) {
1390117832Snyan    case V_INFO_MM_TEXT:
1391117832Snyan	/* do nothing? XXX */
1392117832Snyan	break;
1393117832Snyan    case V_INFO_MM_PLANAR:
1394117832Snyan	planar_fill(adp, 0);
1395117832Snyan	break;
1396117832Snyan    case V_INFO_MM_PACKED:
1397117832Snyan	packed_fill(adp, 0);
1398117832Snyan	break;
1399117832Snyan    }
1400117832Snyan
1401117832Snyan    return 0;
140259689Snyan}
1403117832Snyan#else /* GDC_NOGRAPHICS */
1404117832Snyanstatic int
1405117832Snyangdc_clear(video_adapter_t *adp)
1406117832Snyan{
140759689Snyan
1408117832Snyan    return 0;
1409117832Snyan}
1410117832Snyan#endif /* GDC_NOGRAPHICS */
1411117832Snyan
141259689Snyanstatic int
141359689Snyangdc_fill_rect(video_adapter_t *adp, int val, int x, int y, int cx, int cy)
141459689Snyan{
141559689Snyan    return ENODEV;
141659689Snyan}
141759689Snyan
141859689Snyanstatic int
141959689Snyangdc_bitblt(video_adapter_t *adp,...)
142059689Snyan{
142159689Snyan    /* FIXME */
142259689Snyan    return ENODEV;
142359689Snyan}
142459689Snyan
142559689Snyanstatic int
142648187Skatogdc_dev_ioctl(video_adapter_t *adp, u_long cmd, caddr_t arg)
142748187Skato{
142848187Skato    switch (cmd) {
142948187Skato    case FBIO_GETWINORG:	/* get frame buffer window origin */
143048187Skato	*(u_int *)arg = 0;
143148187Skato	return 0;
143248187Skato
143348187Skato    case FBIO_SETWINORG:	/* set frame buffer window origin */
143448187Skato    case FBIO_SETDISPSTART:	/* set display start address */
143548187Skato    case FBIO_SETLINEWIDTH:	/* set scan line length in pixel */
143648187Skato    case FBIO_GETPALETTE:	/* get color palette */
143748187Skato    case FBIO_SETPALETTE:	/* set color palette */
143848187Skato    case FBIOGETCMAP:		/* get color palette */
143948187Skato    case FBIOPUTCMAP:		/* set color palette */
144048187Skato	return ENODEV;
144148187Skato
144248187Skato    case FBIOGTYPE:		/* get frame buffer type info. */
144348187Skato	((struct fbtype *)arg)->fb_type = fb_type(adp->va_type);
144448187Skato	((struct fbtype *)arg)->fb_height = adp->va_info.vi_height;
144548187Skato	((struct fbtype *)arg)->fb_width = adp->va_info.vi_width;
144648187Skato	((struct fbtype *)arg)->fb_depth = adp->va_info.vi_depth;
144748187Skato	if ((adp->va_info.vi_depth <= 1) || (adp->va_info.vi_depth > 8))
144848187Skato	    ((struct fbtype *)arg)->fb_cmsize = 0;
144948187Skato	else
145048187Skato	    ((struct fbtype *)arg)->fb_cmsize = 1 << adp->va_info.vi_depth;
145148187Skato	((struct fbtype *)arg)->fb_size = adp->va_buffer_size;
145248187Skato	return 0;
145348187Skato
145448187Skato    default:
145548187Skato	return fb_commonioctl(adp, cmd, arg);
145648187Skato    }
145748187Skato}
145848187Skato
145942795Skato/*
146042795Skato * diag():
146142795Skato * Print some information about the video adapter and video modes,
146242795Skato * with requested level of details.
146342795Skato */
146442795Skatostatic int
146542795Skatogdc_diag(video_adapter_t *adp, int level)
146642795Skato{
1467153165Sru#if defined(FB_DEBUG) && FB_DEBUG > 1
146842795Skato    int i;
146943338Skato#endif
147042795Skato
147148187Skato    if (!gdc_init_done)
147248187Skato	return ENXIO;
147342795Skato
147442795Skato    fb_dump_adp_info(DRIVER_NAME, adp, level);
147542795Skato
1476153165Sru#if defined(FB_DEBUG) && FB_DEBUG > 1
147742795Skato    for (i = 0; bios_vmode[i].vi_mode != EOT; ++i) {
147842795Skato	 if (bios_vmode[i].vi_mode == NA)
147942795Skato	    continue;
148042795Skato	 if (get_mode_param(bios_vmode[i].vi_mode) == NULL)
148142795Skato	    continue;
148242795Skato	 fb_dump_mode_info(DRIVER_NAME, adp, &bios_vmode[i], level);
148342795Skato    }
148442795Skato#endif
148542795Skato
148642795Skato    return 0;
148742795Skato}
1488