Home | History | Annotate | Line # | Download | only in sbus
      1 /*	$NetBSD: agten.c,v 1.34 2021/08/07 16:19:15 thorpej Exp $ */
      2 
      3 /*-
      4  * Copyright (c) 2007 Michael Lorenz
      5  * All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  * 2. Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in the
     14  *    documentation and/or other materials provided with the distribution.
     15  *
     16  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     17  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     18  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     19  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     20  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     21  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     22  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     23  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     24  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     25  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     26  * POSSIBILITY OF SUCH DAMAGE.
     27  */
     28 
     29 #include <sys/cdefs.h>
     30 __KERNEL_RCSID(0, "$NetBSD: agten.c,v 1.34 2021/08/07 16:19:15 thorpej Exp $");
     31 
     32 /*
     33  * a driver for the Fujitsu AG-10e SBus framebuffer
     34  *
     35  * this thing is Frankenstein's Monster among graphics boards.
     36  * it contains three graphics chips:
     37  * a GLint 300SX - 24bit stuff, double-buffered
     38  * an Imagine 128 which provides an 8bit overlay
     39  * a Weitek P9100 which provides WIDs
     40  * so here we need to mess only with the P9100 and the I128 - for X we just
     41  * hide the overlay and let the Xserver mess with the GLint
     42  */
     43 
     44 #include <sys/param.h>
     45 #include <sys/systm.h>
     46 #include <sys/kernel.h>
     47 #include <sys/device.h>
     48 #include <sys/proc.h>
     49 #include <sys/mutex.h>
     50 #include <sys/ioctl.h>
     51 #include <sys/kernel.h>
     52 #include <sys/systm.h>
     53 #include <sys/conf.h>
     54 
     55 #include <dev/sun/fbio.h>
     56 #include <dev/sun/fbvar.h>
     57 #include <dev/sun/btreg.h>
     58 #include <dev/sun/btvar.h>
     59 
     60 #include <sys/bus.h>
     61 #include <machine/autoconf.h>
     62 
     63 #include <dev/sbus/sbusvar.h>
     64 
     65 #include <dev/wscons/wsconsio.h>
     66 #include <dev/wscons/wsdisplayvar.h>
     67 #include <dev/rasops/rasops.h>
     68 #include <dev/wsfont/wsfont.h>
     69 
     70 #include <dev/wscons/wsdisplay_vconsvar.h>
     71 #include <dev/wscons/wsdisplay_glyphcachevar.h>
     72 
     73 #include <dev/sbus/p9100reg.h>
     74 #include <dev/ic/ibm561reg.h>
     75 #include <dev/ic/i128reg.h>
     76 #include <dev/ic/i128var.h>
     77 
     78 #include "opt_agten.h"
     79 #include "ioconf.h"
     80 
     81 static int	agten_match(device_t, cfdata_t, void *);
     82 static void	agten_attach(device_t, device_t, void *);
     83 
     84 static int	agten_ioctl(void *, void *, u_long, void *, int, struct lwp *);
     85 static paddr_t	agten_mmap(void *, void *, off_t, int);
     86 static void	agten_init_screen(void *, struct vcons_screen *, int, long *);
     87 
     88 struct agten_softc {
     89 	device_t	sc_dev;		/* base device */
     90 	struct fbdevice	sc_fb;		/* frame buffer device */
     91 
     92 	struct vcons_screen sc_console_screen;
     93 	struct wsscreen_descr sc_defaultscreen_descr;
     94 	const struct wsscreen_descr *sc_screens[1];
     95 	struct wsscreen_list sc_screenlist;
     96 
     97 	bus_space_tag_t	sc_bustag;
     98 
     99 	bus_space_handle_t 	sc_i128_fbh;
    100 	bus_size_t		sc_i128_fbsz;
    101 	bus_space_handle_t 	sc_i128_regh;
    102 	bus_space_handle_t 	sc_p9100_regh;
    103 	bus_addr_t		sc_glint_fb;
    104 	bus_addr_t		sc_glint_regs;
    105 	uint32_t		sc_glint_fbsz;
    106 
    107 	uint32_t	sc_width;
    108 	uint32_t	sc_height;	/* panel width / height */
    109 	uint32_t	sc_stride;
    110 	uint32_t	sc_depth;
    111 
    112 	int sc_cursor_x;
    113 	int sc_cursor_y;
    114 	int sc_video;			/* video output enabled */
    115 
    116 	/* some /dev/fb* stuff */
    117 	int sc_fb_is_open;
    118 
    119 	union	bt_cmap sc_cmap;	/* Brooktree color map */
    120 
    121 	int sc_mode;
    122 	uint32_t sc_bg;
    123 
    124 	void (*sc_putchar)(void *, int, int, u_int, long);
    125 
    126 	struct vcons_data vd;
    127 	glyphcache sc_gc;
    128 };
    129 
    130 CFATTACH_DECL_NEW(agten, sizeof(struct agten_softc),
    131     agten_match, agten_attach, NULL, NULL);
    132 
    133 
    134 static int	agten_putcmap(struct agten_softc *, struct wsdisplay_cmap *);
    135 static int 	agten_getcmap(struct agten_softc *, struct wsdisplay_cmap *);
    136 static int 	agten_putpalreg(struct agten_softc *, uint8_t, uint8_t,
    137 			    uint8_t, uint8_t);
    138 static void	agten_init(struct agten_softc *);
    139 static void	agten_init_cmap(struct agten_softc *, struct rasops_info *);
    140 static void	agten_gfx(struct agten_softc *);
    141 static void	agten_set_video(struct agten_softc *, int);
    142 static int	agten_get_video(struct agten_softc *);
    143 
    144 static void	agten_bitblt(void *, int, int, int, int, int, int, int);
    145 static void 	agten_rectfill(void *, int, int, int, int, long);
    146 
    147 static void	agten_putchar(void *, int, int, u_int, long);
    148 static void	agten_cursor(void *, int, int, int);
    149 static void	agten_copycols(void *, int, int, int, int);
    150 static void	agten_erasecols(void *, int, int, int, long);
    151 static void	agten_copyrows(void *, int, int, int);
    152 static void	agten_eraserows(void *, int, int, long);
    153 
    154 static void	agten_move_cursor(struct agten_softc *, int, int);
    155 static int	agten_do_cursor(struct agten_softc *sc,
    156 				struct wsdisplay_cursor *);
    157 static int	agten_do_sun_cursor(struct agten_softc *sc,
    158 				struct fbcursor *);
    159 
    160 static uint16_t util_interleave(uint8_t, uint8_t);
    161 static uint16_t util_interleave_lin(uint8_t, uint8_t);
    162 
    163 extern const u_char rasops_cmap[768];
    164 
    165 struct wsdisplay_accessops agten_accessops = {
    166 	agten_ioctl,
    167 	agten_mmap,
    168 	NULL,	/* alloc_screen */
    169 	NULL,	/* free_screen */
    170 	NULL,	/* show_screen */
    171 	NULL, 	/* load_font */
    172 	NULL,	/* pollc */
    173 	NULL	/* scroll */
    174 };
    175 
    176 /* /dev/fb* stuff */
    177 
    178 static int agten_fb_open(dev_t, int, int, struct lwp *);
    179 static int agten_fb_close(dev_t, int, int, struct lwp *);
    180 static int agten_fb_ioctl(dev_t, u_long, void *, int, struct lwp *);
    181 static paddr_t agten_fb_mmap(dev_t, off_t, int);
    182 static void agten_fb_unblank(device_t);
    183 
    184 static struct fbdriver agtenfbdriver = {
    185 	agten_fb_unblank, agten_fb_open, agten_fb_close, agten_fb_ioctl,
    186 	nopoll, agten_fb_mmap, nokqfilter
    187 };
    188 
    189 static inline void
    190 agten_write_dac(struct agten_softc *sc, int reg, uint8_t val)
    191 {
    192 	bus_space_write_4(sc->sc_bustag, sc->sc_p9100_regh,
    193 	    0x200 + (reg << 2), (uint32_t)val << 16);
    194 }
    195 
    196 static inline void
    197 agten_write_idx(struct agten_softc *sc, int offset)
    198 {
    199 	bus_space_write_4(sc->sc_bustag, sc->sc_p9100_regh,
    200 	    0x200 + (IBM561_ADDR_LOW << 2), (offset & 0xff) << 16);
    201 	bus_space_write_4(sc->sc_bustag, sc->sc_p9100_regh,
    202 	    0x200 + (IBM561_ADDR_HIGH << 2), ((offset >> 8) & 0xff) << 16);
    203 }
    204 
    205 static inline void
    206 agten_write_dac_10(struct agten_softc *sc, int reg, uint16_t val)
    207 {
    208 	agten_write_dac(sc, reg, (val >> 2) & 0xff);
    209 	agten_write_dac(sc, reg, (val & 0x3) << 6);
    210 }
    211 
    212 static int
    213 agten_match(device_t dev, cfdata_t cf, void *aux)
    214 {
    215 	struct sbus_attach_args *sa = aux;
    216 
    217 	if (strcmp("PFU,aga", sa->sa_name) == 0)
    218 		return 100;
    219 	return 0;
    220 }
    221 
    222 static void
    223 agten_attach(device_t parent, device_t dev, void *aux)
    224 {
    225 	struct agten_softc *sc = device_private(dev);
    226 	struct sbus_attach_args *sa = aux;
    227 	struct fbdevice *fb = &sc->sc_fb;
    228 	struct wsemuldisplaydev_attach_args aa;
    229 	struct rasops_info *ri;
    230 	long defattr;
    231 	uint32_t reg;
    232 	int node = sa->sa_node;
    233 	int console;
    234 
    235  	sc->sc_dev = dev;
    236 	sc->sc_defaultscreen_descr = (struct wsscreen_descr){
    237 		"default",
    238 		0, 0,
    239 		NULL,
    240 		8, 16,
    241 		WSSCREEN_WSCOLORS | WSSCREEN_HILIT,
    242 		NULL
    243 	};
    244 	sc->sc_screens[0] = &sc->sc_defaultscreen_descr;
    245 	sc->sc_screenlist = (struct wsscreen_list){1, sc->sc_screens};
    246 	sc->sc_mode = WSDISPLAYIO_MODE_EMUL;
    247 	sc->sc_fb_is_open = 0;
    248 	sc->sc_video = -1;
    249 	sc->sc_bustag = sa->sa_bustag;
    250 	sc->sc_putchar = NULL;
    251 
    252 	sc->sc_width = prom_getpropint(node, "ffb_width", 1152);
    253 	sc->sc_height = prom_getpropint(node, "ffb_height", 900);
    254 	sc->sc_depth = prom_getpropint(node, "ffb_depth", 8);
    255 	sc->sc_stride = sc->sc_width * (sc->sc_depth >> 3);
    256 
    257 	reg = prom_getpropint(node, "i128_fb_physaddr", -1);
    258 	sc->sc_i128_fbsz = prom_getpropint(node, "i128_fb_size", -1);
    259 	if (sbus_bus_map(sc->sc_bustag,
    260 	    sa->sa_reg[0].oa_space, sa->sa_reg[0].oa_base + reg,
    261 	    round_page(sc->sc_stride * sc->sc_height),
    262 	    BUS_SPACE_MAP_LINEAR | BUS_SPACE_MAP_LARGE,
    263 	    &sc->sc_i128_fbh) != 0) {
    264 
    265 		aprint_error_dev(dev, "unable to map the framebuffer\n");
    266 		return;
    267 	}
    268 	fb->fb_pixels = bus_space_vaddr(sc->sc_bustag, sc->sc_i128_fbh);
    269 
    270 	reg = prom_getpropint(node, "i128_reg_physaddr", -1);
    271 	if (sbus_bus_map(sc->sc_bustag,
    272 	    sa->sa_reg[0].oa_space, sa->sa_reg[0].oa_base + reg,
    273 	    0x10000, 0, &sc->sc_i128_regh) != 0) {
    274 
    275 		aprint_error_dev(dev, "unable to map I128 registers\n");
    276 		return;
    277 	}
    278 
    279 	reg = prom_getpropint(node, "p9100_reg_physaddr", -1);
    280 	if (sbus_bus_map(sc->sc_bustag,
    281 	    sa->sa_reg[0].oa_space, sa->sa_reg[0].oa_base + reg,
    282 	    0x8000, 0, &sc->sc_p9100_regh) != 0) {
    283 
    284 		aprint_error_dev(dev, "unable to map P9100 registers\n");
    285 		return;
    286 	}
    287 
    288 	reg = prom_getpropint(node, "glint_fb0_physaddr", -1);
    289 	sc->sc_glint_fb = sbus_bus_addr(sc->sc_bustag,
    290 	    sa->sa_reg[0].oa_space, sa->sa_reg[0].oa_base + reg);
    291 	sc->sc_glint_fbsz = prom_getpropint(node, "glint_lb_size", -1);
    292 	reg = prom_getpropint(node, "glint_reg_physaddr", -1);
    293 	sc->sc_glint_regs = sbus_bus_addr(sc->sc_bustag,
    294 	    sa->sa_reg[0].oa_space, sa->sa_reg[0].oa_base + reg);
    295 
    296 #if 0
    297 	bus_intr_establish(sc->sc_bustag, sa->sa_pri, IPL_BIO,
    298 	    agten_intr, sc);
    299 #endif
    300 
    301 	printf(": %dx%d\n", sc->sc_width, sc->sc_height);
    302 	agten_init(sc);
    303 
    304 	console = fb_is_console(node);
    305 
    306 	vcons_init(&sc->vd, sc, &sc->sc_defaultscreen_descr,
    307 	    &agten_accessops);
    308 	sc->vd.init_screen = agten_init_screen;
    309 
    310 	ri = &sc->sc_console_screen.scr_ri;
    311 
    312 	sc->sc_gc.gc_bitblt = agten_bitblt;
    313 	sc->sc_gc.gc_rectfill = agten_rectfill;
    314 	sc->sc_gc.gc_blitcookie = sc;
    315 	sc->sc_gc.gc_rop = CR_COPY;
    316 
    317 #if defined(AGTEN_DEBUG)
    318 	sc->sc_height -= 200;
    319 #endif
    320 
    321 	if (console) {
    322 		vcons_init_screen(&sc->vd, &sc->sc_console_screen, 1,
    323 		    &defattr);
    324 		sc->sc_console_screen.scr_flags |= VCONS_SCREEN_IS_STATIC;
    325 
    326 		sc->sc_defaultscreen_descr.textops = &ri->ri_ops;
    327 		sc->sc_defaultscreen_descr.capabilities = ri->ri_caps;
    328 		sc->sc_defaultscreen_descr.nrows = ri->ri_rows;
    329 		sc->sc_defaultscreen_descr.ncols = ri->ri_cols;
    330 		glyphcache_init(&sc->sc_gc,
    331 		    sc->sc_height + 5,
    332 		    (0x400000 / sc->sc_stride) - sc->sc_height - 5,
    333 		    sc->sc_width,
    334 		    ri->ri_font->fontwidth,
    335 		    ri->ri_font->fontheight,
    336 		    defattr);
    337 
    338 		wsdisplay_cnattach(&sc->sc_defaultscreen_descr, ri, 0, 0,
    339 		    defattr);
    340 		i128_rectfill(sc->sc_bustag, sc->sc_i128_regh, 0, 0,
    341 		    sc->sc_width, sc->sc_height,
    342 		    ri->ri_devcmap[(defattr >> 16) & 0xff]);
    343 		vcons_replay_msgbuf(&sc->sc_console_screen);
    344 	} else {
    345 		/*
    346 		 * since we're not the console we can postpone the rest
    347 		 * until someone actually allocates a screen for us
    348 		 */
    349 		if (sc->sc_console_screen.scr_ri.ri_rows == 0) {
    350 			/* do some minimal setup to avoid weirdnesses later */
    351 			vcons_init_screen(&sc->vd, &sc->sc_console_screen, 1,
    352 			    &defattr);
    353 		} else
    354 			(*ri->ri_ops.allocattr)(ri, 0, 0, 0, &defattr);
    355 
    356 		glyphcache_init(&sc->sc_gc,
    357 		    sc->sc_height + 5,
    358 		    (0x400000 / sc->sc_stride) - sc->sc_height - 5,
    359 		    sc->sc_width,
    360 		    ri->ri_font->fontwidth,
    361 		    ri->ri_font->fontheight,
    362 		    defattr);
    363 	}
    364 
    365 	/* Initialize the default color map. */
    366 	agten_init_cmap(sc, ri);
    367 
    368 	aa.console = console;
    369 	aa.scrdata = &sc->sc_screenlist;
    370 	aa.accessops = &agten_accessops;
    371 	aa.accesscookie = &sc->vd;
    372 
    373 	config_found(sc->sc_dev, &aa, wsemuldisplaydevprint, CFARGS_NONE);
    374 
    375 	fb->fb_driver = &agtenfbdriver;
    376 	fb->fb_device = sc->sc_dev;
    377 	fb->fb_flags = device_cfdata(sc->sc_dev)->cf_flags & FB_USERMASK;
    378 	fb->fb_type.fb_type = FBTYPE_AG10E;
    379 	fb->fb_type.fb_cmsize = 256;	/* doesn't matter, we're always 24bit */
    380 	fb->fb_type.fb_size = sc->sc_glint_fbsz;
    381 	fb->fb_type.fb_width = sc->sc_width;
    382 	fb->fb_type.fb_height = sc->sc_height;
    383 	fb->fb_type.fb_depth = 32;
    384 	fb->fb_linebytes = sc->sc_stride << 2;
    385 	fb_attach(fb, console);
    386 	agten_set_video(sc, 1);	/* make sure video's on */
    387 }
    388 
    389 static int
    390 agten_ioctl(void *v, void *vs, u_long cmd, void *data, int flag,
    391 	struct lwp *l)
    392 {
    393 	struct vcons_data *vd = v;
    394 	struct agten_softc *sc = vd->cookie;
    395 	struct wsdisplay_fbinfo *wdf;
    396 	struct vcons_screen *ms = vd->active;
    397 
    398 	switch (cmd) {
    399 
    400 		case WSDISPLAYIO_GTYPE:
    401 			*(u_int *)data = WSDISPLAY_TYPE_AG10;
    402 			return 0;
    403 
    404 		case WSDISPLAYIO_GINFO:
    405 			if (ms == NULL)
    406 				return ENODEV;
    407 			wdf = (void *)data;
    408 			wdf->height = ms->scr_ri.ri_height;
    409 			wdf->width = ms->scr_ri.ri_width;
    410 			wdf->depth = 32;
    411 			wdf->cmsize = 256;
    412 			return 0;
    413 
    414 		case WSDISPLAYIO_GVIDEO:
    415 			*(int *)data = sc->sc_video;
    416 			return 0;
    417 
    418 		case WSDISPLAYIO_SVIDEO:
    419 			agten_set_video(sc, *(int *)data);
    420 			return 0;
    421 
    422 		case WSDISPLAYIO_GETCMAP:
    423 			return agten_getcmap(sc,
    424 			    (struct wsdisplay_cmap *)data);
    425 
    426 		case WSDISPLAYIO_PUTCMAP:
    427 			return agten_putcmap(sc,
    428 			    (struct wsdisplay_cmap *)data);
    429 
    430 		case WSDISPLAYIO_LINEBYTES:
    431 			*(u_int *)data = sc->sc_stride << 2;
    432 			return 0;
    433 
    434 		case WSDISPLAYIO_SMODE:
    435 			{
    436 				int new_mode = *(int*)data;
    437 				if (new_mode != sc->sc_mode) {
    438 					sc->sc_mode = new_mode;
    439 					if(new_mode == WSDISPLAYIO_MODE_EMUL) {
    440 						agten_init(sc);
    441 						agten_init_cmap(sc,
    442 						    &ms->scr_ri);
    443 						vcons_redraw_screen(ms);
    444 					} else {
    445 						agten_gfx(sc);
    446 					}
    447 				}
    448 			}
    449 			return 0;
    450 
    451 		case WSDISPLAYIO_GCURPOS:
    452 			{
    453 				struct wsdisplay_curpos *cp = (void *)data;
    454 
    455 				cp->x = sc->sc_cursor_x;
    456 				cp->y = sc->sc_cursor_y;
    457 			}
    458 			return 0;
    459 
    460 		case WSDISPLAYIO_SCURPOS:
    461 			{
    462 				struct wsdisplay_curpos *cp = (void *)data;
    463 
    464 				agten_move_cursor(sc, cp->x, cp->y);
    465 			}
    466 			return 0;
    467 
    468 		case WSDISPLAYIO_GCURMAX:
    469 			{
    470 				struct wsdisplay_curpos *cp = (void *)data;
    471 
    472 				cp->x = 64;
    473 				cp->y = 64;
    474 			}
    475 			return 0;
    476 
    477 		case WSDISPLAYIO_SCURSOR:
    478 			{
    479 				struct wsdisplay_cursor *cursor = (void *)data;
    480 
    481 				return agten_do_cursor(sc, cursor);
    482 			}
    483 	}
    484 	return EPASSTHROUGH;
    485 }
    486 
    487 static paddr_t
    488 agten_mmap(void *v, void *vs, off_t offset, int prot)
    489 {
    490 	struct vcons_data *vd = v;
    491 	struct agten_softc *sc = vd->cookie;
    492 
    493 	if (offset < sc->sc_glint_fbsz)
    494 		return bus_space_mmap(sc->sc_bustag, sc->sc_glint_fb, offset,
    495 		    prot, BUS_SPACE_MAP_LINEAR);
    496 	return -1;
    497 }
    498 
    499 static void
    500 agten_init_screen(void *cookie, struct vcons_screen *scr,
    501     int existing, long *defattr)
    502 {
    503 	struct agten_softc *sc = cookie;
    504 	struct rasops_info *ri = &scr->scr_ri;
    505 
    506 	ri->ri_depth = sc->sc_depth;
    507 	ri->ri_width = sc->sc_width;
    508 	ri->ri_height = sc->sc_height;
    509 	ri->ri_stride = sc->sc_stride;
    510 	ri->ri_flg = RI_CENTER | RI_FULLCLEAR | RI_8BIT_IS_RGB | RI_ENABLE_ALPHA;
    511 
    512 	ri->ri_bits = (char *)sc->sc_fb.fb_pixels;
    513 
    514 	if (existing) {
    515 		ri->ri_flg |= RI_CLEAR;
    516 	}
    517 
    518 	rasops_init(ri, 0, 0);
    519 	sc->sc_putchar = ri->ri_ops.putchar;
    520 
    521 	ri->ri_caps = WSSCREEN_WSCOLORS;
    522 
    523 	rasops_reconfig(ri, sc->sc_height / ri->ri_font->fontheight,
    524 		    sc->sc_width / ri->ri_font->fontwidth);
    525 
    526 	ri->ri_hw = scr;
    527 	ri->ri_ops.putchar   = agten_putchar;
    528 	ri->ri_ops.cursor    = agten_cursor;
    529 	ri->ri_ops.copyrows  = agten_copyrows;
    530 	ri->ri_ops.eraserows = agten_eraserows;
    531 	ri->ri_ops.copycols  = agten_copycols;
    532 	ri->ri_ops.erasecols = agten_erasecols;
    533 
    534 }
    535 
    536 static int
    537 agten_putcmap(struct agten_softc *sc, struct wsdisplay_cmap *cm)
    538 {
    539 	u_int index = cm->index;
    540 	u_int count = cm->count;
    541 	int i, error;
    542 	u_char rbuf[256], gbuf[256], bbuf[256];
    543 	u_char *r, *g, *b;
    544 
    545 	if (cm->index >= 256 || cm->count > 256 ||
    546 	    (cm->index + cm->count) > 256)
    547 		return EINVAL;
    548 	error = copyin(cm->red, &rbuf[index], count);
    549 	if (error)
    550 		return error;
    551 	error = copyin(cm->green, &gbuf[index], count);
    552 	if (error)
    553 		return error;
    554 	error = copyin(cm->blue, &bbuf[index], count);
    555 	if (error)
    556 		return error;
    557 
    558 	r = &rbuf[index];
    559 	g = &gbuf[index];
    560 	b = &bbuf[index];
    561 
    562 	for (i = 0; i < count; i++) {
    563 		agten_putpalreg(sc, index, *r, *g, *b);
    564 		index++;
    565 		r++, g++, b++;
    566 	}
    567 	return 0;
    568 }
    569 
    570 static int
    571 agten_getcmap(struct agten_softc *sc, struct wsdisplay_cmap *cm)
    572 {
    573 	u_int index = cm->index;
    574 	u_int count = cm->count;
    575 	int error, i;
    576 	uint8_t red[256], green[256], blue[256];
    577 
    578 	if (index >= 255 || count > 256 || index + count > 256)
    579 		return EINVAL;
    580 
    581 	i = index;
    582 	while (i < (index + count)) {
    583 		red[i] = sc->sc_cmap.cm_map[i][0];
    584 		green[i] = sc->sc_cmap.cm_map[i][1];
    585 		blue[i] = sc->sc_cmap.cm_map[i][2];
    586 		i++;
    587 	}
    588 	error = copyout(&red[index],   cm->red,   count);
    589 	if (error)
    590 		return error;
    591 	error = copyout(&green[index], cm->green, count);
    592 	if (error)
    593 		return error;
    594 	error = copyout(&blue[index],  cm->blue,  count);
    595 	if (error)
    596 		return error;
    597 
    598 	return 0;
    599 }
    600 
    601 static int
    602 agten_putpalreg(struct agten_softc *sc, uint8_t idx, uint8_t r, uint8_t g,
    603     uint8_t b)
    604 {
    605 
    606 	sc->sc_cmap.cm_map[idx][0] = r;
    607 	sc->sc_cmap.cm_map[idx][1] = g;
    608 	sc->sc_cmap.cm_map[idx][2] = b;
    609 	agten_write_idx(sc, IBM561_CMAP_TABLE + idx);
    610 	agten_write_dac(sc, IBM561_CMD_CMAP, r);
    611 	agten_write_dac(sc, IBM561_CMD_CMAP, g);
    612 	agten_write_dac(sc, IBM561_CMD_CMAP, b);
    613 	return 0;
    614 }
    615 
    616 static void
    617 agten_init(struct agten_softc *sc)
    618 {
    619 	int i;
    620 	uint32_t src, srcw;
    621 
    622 	/* then we set up a linear LUT for 24bit colour */
    623 	agten_write_idx(sc, IBM561_CMAP_TABLE + 256);
    624 	for (i = 0; i < 256; i++) {
    625 		agten_write_dac(sc, IBM561_CMD_CMAP, i);
    626 		agten_write_dac(sc, IBM561_CMD_CMAP, i);
    627 		agten_write_dac(sc, IBM561_CMD_CMAP, i);
    628 	}
    629 
    630 	/* and the linear gamma maps */
    631 	agten_write_idx(sc, IBM561_RED_GAMMA_TABLE);
    632 	for (i = 0; i < 0x3ff; i+= 4)
    633 		agten_write_dac_10(sc, IBM561_CMD_GAMMA, i);
    634 	agten_write_idx(sc, IBM561_GREEN_GAMMA_TABLE);
    635 	for (i = 0; i < 0x3ff; i+= 4)
    636 		agten_write_dac_10(sc, IBM561_CMD_GAMMA, i);
    637 	agten_write_idx(sc, IBM561_BLUE_GAMMA_TABLE);
    638 	for (i = 0; i < 0x3ff; i+= 4)
    639 		agten_write_dac_10(sc, IBM561_CMD_GAMMA, i);
    640 
    641 	/* enable outputs, RGB mode */
    642 	agten_write_idx(sc, IBM561_CONFIG_REG3);
    643 	agten_write_dac(sc, IBM561_CMD, CR3_SERIAL_CLK_CTRL | CR3_RGB);
    644 
    645 	/* MUX 4:1 basic, 8bit overlay, 8bit WIDs */
    646 	agten_write_idx(sc, IBM561_CONFIG_REG1);
    647 	agten_write_dac(sc, IBM561_CMD, CR1_MODE_4_1_BASIC | CR1_OVL_8BPP |
    648 	    CR1_WID_8);
    649 
    650 	/* use external clock, enable video output */
    651 	agten_write_idx(sc, IBM561_CONFIG_REG2);
    652 	agten_write_dac(sc, IBM561_CMD, CR2_ENABLE_CLC | CR2_PLL_REF_SELECT |
    653 	    CR2_PIXEL_CLOCK_SELECT | CR2_ENABLE_RGB_OUTPUT);
    654 
    655 	/* now set up some window attributes */
    656 
    657 	/*
    658 	 * direct colour, 24 bit, transparency off, LUT from 0x100
    659 	 * we need to use direct colour and a linear LUT because for some
    660 	 * reason true color mode gives messed up colours
    661 	 */
    662 	agten_write_idx(sc, IBM561_FB_WINTYPE);
    663 	agten_write_dac_10(sc, IBM561_CMD_FB_WAT, 0x100 | FB_PIXEL_24BIT |
    664 	    FB_MODE_DIRECT);
    665 
    666 	/* use gamma LUTs, no crosshair, 0 is transparent */
    667 	agten_write_idx(sc, IBM561_AUXFB_WINTYPE);
    668 	agten_write_dac(sc, IBM561_CMD_FB_WAT, 0x0);
    669 
    670 	/* overlay is 8 bit, opaque */
    671 	agten_write_idx(sc, IBM561_OL_WINTYPE);
    672 	agten_write_dac_10(sc, IBM561_CMD_FB_WAT, 0x00);
    673 
    674 	/* now we fill the WID fb with zeroes */
    675 	src = 0;
    676 	srcw = sc->sc_width << 16 | sc->sc_height;
    677 	bus_space_write_4(sc->sc_bustag, sc->sc_p9100_regh, FOREGROUND_COLOR,
    678 	    0x0);
    679 	bus_space_write_4(sc->sc_bustag, sc->sc_p9100_regh, BACKGROUND_COLOR,
    680 	    0x0);
    681 	bus_space_write_4(sc->sc_bustag, sc->sc_p9100_regh, RASTER_OP, ROP_PAT);
    682 	bus_space_write_4(sc->sc_bustag, sc->sc_p9100_regh, COORD_INDEX, 0);
    683 	bus_space_write_4(sc->sc_bustag, sc->sc_p9100_regh, RECT_RTW_XY, src);
    684 	bus_space_write_4(sc->sc_bustag, sc->sc_p9100_regh, RECT_RTW_XY, srcw);
    685 	(void)bus_space_read_4(sc->sc_bustag, sc->sc_p9100_regh, COMMAND_QUAD);
    686 
    687 	/* initialize the cursor registers */
    688 
    689 	/* initialize the Imagine 128 */
    690 	i128_init(sc->sc_bustag, sc->sc_i128_regh, sc->sc_stride, 8);
    691 }
    692 
    693 static void
    694 agten_init_cmap(struct agten_softc *sc, struct rasops_info *ri)
    695 {
    696 	int i, j;
    697 	uint8_t cmap[768];
    698 
    699 	rasops_get_cmap(ri, cmap, 768);
    700 	j = 0;
    701 	for (i = 0; i < 256; i++) {
    702 
    703 		agten_putpalreg(sc, i, cmap[j], cmap[j + 1], cmap[j + 2]);
    704 		j += 3;
    705 	}
    706 }
    707 
    708 static void
    709 agten_gfx(struct agten_softc *sc)
    710 {
    711 	/* enable overlay transparency on colour 0x00 */
    712 	agten_write_idx(sc, IBM561_OL_WINTYPE);
    713 	agten_write_dac_10(sc, IBM561_CMD_FB_WAT, OL_MODE_TRANSP_ENABLE);
    714 
    715 	/* then blit the overlay full of 0x00 */
    716 	i128_rectfill(sc->sc_bustag, sc->sc_i128_regh, 0, 0, sc->sc_width,
    717 	    sc->sc_height, 0);
    718 
    719 	/* ... so we can see the 24bit framebuffer */
    720 }
    721 
    722 static void
    723 agten_set_video(struct agten_softc *sc, int flag)
    724 {
    725 	uint8_t reg =
    726 	    CR2_ENABLE_CLC | CR2_PLL_REF_SELECT | CR2_PIXEL_CLOCK_SELECT;
    727 
    728 	if (flag == sc->sc_video)
    729 		return;
    730 
    731 	agten_write_idx(sc, IBM561_CONFIG_REG2);
    732 	agten_write_dac(sc, IBM561_CMD, flag ? reg | CR2_ENABLE_RGB_OUTPUT :
    733 	    reg);
    734 
    735 	sc->sc_video = flag;
    736 }
    737 
    738 static int
    739 agten_get_video(struct agten_softc *sc)
    740 {
    741 
    742 	return sc->sc_video;
    743 }
    744 
    745 static void
    746 agten_bitblt(void *cookie, int xs, int ys, int xd, int yd, int wi, int he,
    747              int rop)
    748 {
    749 	struct agten_softc *sc = cookie;
    750 
    751 	i128_bitblt(sc->sc_bustag, sc->sc_i128_regh,
    752 	    xs, ys, xd, yd, wi, he, rop);
    753 }
    754 
    755 static void
    756 agten_rectfill(void *cookie, int x, int y, int wi, int he, long fg)
    757 {
    758 	struct agten_softc *sc = cookie;
    759 	struct vcons_screen *scr = sc->vd.active;
    760 	uint32_t col;
    761 
    762 	if (scr == NULL)
    763 		return;
    764 	col = scr->scr_ri.ri_devcmap[fg];
    765 	i128_rectfill(sc->sc_bustag, sc->sc_i128_regh, x, y, wi, he, col);
    766 }
    767 
    768 static void
    769 agten_putchar(void *cookie, int row, int col, u_int c, long attr)
    770 {
    771 	struct rasops_info *ri = cookie;
    772 	struct wsdisplay_font *font = PICK_FONT(ri, c);
    773 	struct vcons_screen *scr = ri->ri_hw;
    774 	struct agten_softc *sc = scr->scr_cookie;
    775 	uint32_t fg, bg;
    776 	int x, y, wi, he, rv;
    777 
    778 	wi = font->fontwidth;
    779 	he = font->fontheight;
    780 
    781 	bg = ri->ri_devcmap[(attr >> 16) & 0xf];
    782 	fg = ri->ri_devcmap[(attr >> 24) & 0xf];
    783 
    784 	x = ri->ri_xorigin + col * wi;
    785 	y = ri->ri_yorigin + row * he;
    786 
    787 	if (c == 0x20) {
    788 		i128_rectfill(sc->sc_bustag, sc->sc_i128_regh, x, y, wi, he,
    789 		    bg);
    790 		if (attr & 1)
    791 			i128_rectfill(sc->sc_bustag, sc->sc_i128_regh, x,
    792 			    y + he - 2, wi, 1, fg);
    793 		return;
    794 	}
    795 	rv = glyphcache_try(&sc->sc_gc, c, x, y, attr);
    796 	if (rv == GC_OK)
    797 		return;
    798 	i128_sync(sc->sc_bustag, sc->sc_i128_regh);
    799 	sc->sc_putchar(cookie, row, col, c, attr & ~1);
    800 
    801 	if (rv == GC_ADD) {
    802 		glyphcache_add(&sc->sc_gc, c, x, y);
    803 	} else {
    804 		if (attr & 1)
    805 			i128_rectfill(sc->sc_bustag, sc->sc_i128_regh, x,
    806 			    y + he - 2, wi, 1, fg);
    807 	}
    808 }
    809 
    810 static void
    811 agten_cursor(void *cookie, int on, int row, int col)
    812 {
    813 	struct rasops_info *ri = cookie;
    814 	struct vcons_screen *scr = ri->ri_hw;
    815 	struct agten_softc *sc = scr->scr_cookie;
    816 	int x, y, wi,he;
    817 
    818 	wi = ri->ri_font->fontwidth;
    819 	he = ri->ri_font->fontheight;
    820 
    821 	if (ri->ri_flg & RI_CURSOR) {
    822 		x = ri->ri_ccol * wi + ri->ri_xorigin;
    823 		y = ri->ri_crow * he + ri->ri_yorigin;
    824 		i128_bitblt(sc->sc_bustag, sc->sc_i128_regh, x, y, x, y, wi, he,
    825 		    CR_COPY_INV);
    826 		ri->ri_flg &= ~RI_CURSOR;
    827 	}
    828 
    829 	ri->ri_crow = row;
    830 	ri->ri_ccol = col;
    831 
    832 	if (on)
    833 	{
    834 		x = ri->ri_ccol * wi + ri->ri_xorigin;
    835 		y = ri->ri_crow * he + ri->ri_yorigin;
    836 		i128_bitblt(sc->sc_bustag, sc->sc_i128_regh, x, y, x, y, wi, he,
    837 		    CR_COPY_INV);
    838 		ri->ri_flg |= RI_CURSOR;
    839 	}
    840 }
    841 
    842 static void
    843 agten_copycols(void *cookie, int row, int srccol, int dstcol, int ncols)
    844 {
    845 	struct rasops_info *ri = cookie;
    846 	struct vcons_screen *scr = ri->ri_hw;
    847 	struct agten_softc *sc = scr->scr_cookie;
    848 	int32_t xs, xd, y, width, height;
    849 
    850 	xs = ri->ri_xorigin + ri->ri_font->fontwidth * srccol;
    851 	xd = ri->ri_xorigin + ri->ri_font->fontwidth * dstcol;
    852 	y = ri->ri_yorigin + ri->ri_font->fontheight * row;
    853 	width = ri->ri_font->fontwidth * ncols;
    854 	height = ri->ri_font->fontheight;
    855 	i128_bitblt(sc->sc_bustag, sc->sc_i128_regh, xs, y, xd, y, width,
    856 	    height, CR_COPY);
    857 }
    858 
    859 static void
    860 agten_erasecols(void *cookie, int row, int startcol, int ncols, long fillattr)
    861 {
    862 	struct rasops_info *ri = cookie;
    863 	struct vcons_screen *scr = ri->ri_hw;
    864 	struct agten_softc *sc = scr->scr_cookie;
    865 	int32_t x, y, width, height, bg;
    866 
    867 	x = ri->ri_xorigin + ri->ri_font->fontwidth * startcol;
    868 	y = ri->ri_yorigin + ri->ri_font->fontheight * row;
    869 	width = ri->ri_font->fontwidth * ncols;
    870 	height = ri->ri_font->fontheight;
    871 	bg = (uint32_t)ri->ri_devcmap[(fillattr >> 16) & 0xff];
    872 	i128_rectfill(sc->sc_bustag, sc->sc_i128_regh, x, y, width, height, bg);
    873 }
    874 
    875 static void
    876 agten_copyrows(void *cookie, int srcrow, int dstrow, int nrows)
    877 {
    878 	struct rasops_info *ri = cookie;
    879 	struct vcons_screen *scr = ri->ri_hw;
    880 	struct agten_softc *sc = scr->scr_cookie;
    881 	int32_t x, ys, yd, width, height;
    882 
    883 	x = ri->ri_xorigin;
    884 	ys = ri->ri_yorigin + ri->ri_font->fontheight * srcrow;
    885 	yd = ri->ri_yorigin + ri->ri_font->fontheight * dstrow;
    886 	width = ri->ri_emuwidth;
    887 	height = ri->ri_font->fontheight * nrows;
    888 	i128_bitblt(sc->sc_bustag, sc->sc_i128_regh, x, ys, x, yd, width,
    889 	    height, CR_COPY);
    890 }
    891 
    892 static void
    893 agten_eraserows(void *cookie, int row, int nrows, long fillattr)
    894 {
    895 	struct rasops_info *ri = cookie;
    896 	struct vcons_screen *scr = ri->ri_hw;
    897 	struct agten_softc *sc = scr->scr_cookie;
    898 	int32_t x, y, width, height, bg;
    899 
    900 	if ((row == 0) && (nrows == ri->ri_rows)) {
    901 		x = y = 0;
    902 		width = ri->ri_width;
    903 		height = ri->ri_height;
    904 	} else {
    905 		x = ri->ri_xorigin;
    906 		y = ri->ri_yorigin + ri->ri_font->fontheight * row;
    907 		width = ri->ri_emuwidth;
    908 		height = ri->ri_font->fontheight * nrows;
    909 	}
    910 	bg = (uint32_t)ri->ri_devcmap[(fillattr >> 16) & 0xff];
    911 	i128_rectfill(sc->sc_bustag, sc->sc_i128_regh, x, y, width, height, bg);
    912 }
    913 
    914 static void
    915 agten_move_cursor(struct agten_softc *sc, int x, int y)
    916 {
    917 
    918 	sc->sc_cursor_x = x;
    919 	sc->sc_cursor_y = y;
    920 	agten_write_idx(sc, IBM561_CURSOR_X_REG);
    921 	agten_write_dac(sc, IBM561_CMD, x & 0xff);
    922 	agten_write_dac(sc, IBM561_CMD, (x >> 8) & 0xff);
    923 	agten_write_dac(sc, IBM561_CMD, y & 0xff);
    924 	agten_write_dac(sc, IBM561_CMD, (y >> 8) & 0xff);
    925 }
    926 
    927 static int
    928 agten_do_cursor(struct agten_softc *sc, struct wsdisplay_cursor *cur)
    929 {
    930 	if (cur->which & WSDISPLAY_CURSOR_DOCUR) {
    931 
    932 		agten_write_idx(sc, IBM561_CURS_CNTL_REG);
    933 		agten_write_dac(sc, IBM561_CMD, cur->enable ?
    934 		    CURS_ENABLE : 0);
    935 	}
    936 	if (cur->which & WSDISPLAY_CURSOR_DOHOT) {
    937 
    938 		agten_write_idx(sc, IBM561_HOTSPOT_X_REG);
    939 		agten_write_dac(sc, IBM561_CMD, cur->hot.x);
    940 		agten_write_dac(sc, IBM561_CMD, cur->hot.y);
    941 	}
    942 	if (cur->which & WSDISPLAY_CURSOR_DOPOS) {
    943 
    944 		agten_move_cursor(sc, cur->pos.x, cur->pos.y);
    945 	}
    946 	if (cur->which & WSDISPLAY_CURSOR_DOCMAP) {
    947 		int i;
    948 
    949 		agten_write_idx(sc, IBM561_CURSOR_LUT + cur->cmap.index + 2);
    950 		for (i = 0; i < cur->cmap.count; i++) {
    951 			agten_write_dac(sc, IBM561_CMD_CMAP, cur->cmap.red[i]);
    952 			agten_write_dac(sc, IBM561_CMD_CMAP,
    953 			    cur->cmap.green[i]);
    954 			agten_write_dac(sc, IBM561_CMD_CMAP, cur->cmap.blue[i]);
    955 		}
    956 	}
    957 	if (cur->which & WSDISPLAY_CURSOR_DOSHAPE) {
    958 		int i;
    959 		uint16_t tmp;
    960 
    961 		agten_write_idx(sc, IBM561_CURSOR_BITMAP);
    962 		for (i = 0; i < 512; i++) {
    963 			tmp = util_interleave(cur->mask[i], cur->image[i]);
    964 			agten_write_dac(sc, IBM561_CMD, (tmp >> 8) & 0xff);
    965 			agten_write_dac(sc, IBM561_CMD, tmp & 0xff);
    966 		}
    967 	}
    968 	return 0;
    969 }
    970 
    971 static int
    972 agten_do_sun_cursor(struct agten_softc *sc, struct fbcursor *cur)
    973 {
    974 	if (cur->set & FB_CUR_SETCUR) {
    975 
    976 		agten_write_idx(sc, IBM561_CURS_CNTL_REG);
    977 		agten_write_dac(sc, IBM561_CMD, cur->enable ?
    978 		    CURS_ENABLE : 0);
    979 	}
    980 	if (cur->set & FB_CUR_SETHOT) {
    981 
    982 		agten_write_idx(sc, IBM561_HOTSPOT_X_REG);
    983 		agten_write_dac(sc, IBM561_CMD, cur->hot.x);
    984 		agten_write_dac(sc, IBM561_CMD, cur->hot.y);
    985 	}
    986 	if (cur->set & FB_CUR_SETPOS) {
    987 
    988 		agten_move_cursor(sc, cur->pos.x, cur->pos.y);
    989 	}
    990 	if (cur->set & FB_CUR_SETCMAP) {
    991 		int i;
    992 
    993 		agten_write_idx(sc, IBM561_CURSOR_LUT + cur->cmap.index + 2);
    994 		for (i = 0; i < cur->cmap.count; i++) {
    995 			agten_write_dac(sc, IBM561_CMD_CMAP, cur->cmap.red[i]);
    996 			agten_write_dac(sc, IBM561_CMD_CMAP,
    997 			    cur->cmap.green[i]);
    998 			agten_write_dac(sc, IBM561_CMD_CMAP, cur->cmap.blue[i]);
    999 		}
   1000 	}
   1001 	if (cur->set & FB_CUR_SETSHAPE) {
   1002 		int i;
   1003 		uint16_t tmp;
   1004 
   1005 		agten_write_idx(sc, IBM561_CURSOR_BITMAP);
   1006 		for (i = 0; i < 512; i++) {
   1007 			tmp = util_interleave_lin(cur->mask[i], cur->image[i]);
   1008 			agten_write_dac(sc, IBM561_CMD, (tmp >> 8) & 0xff);
   1009 			agten_write_dac(sc, IBM561_CMD, tmp & 0xff);
   1010 		}
   1011 	}
   1012 	return 0;
   1013 }
   1014 
   1015 uint16_t
   1016 util_interleave(uint8_t b1, uint8_t b2)
   1017 {
   1018 	int i;
   1019 	uint16_t ret = 0;
   1020 	uint16_t mask = 0x8000;
   1021 	uint8_t mask8 = 0x01;
   1022 
   1023 	for (i = 0; i < 8; i++) {
   1024 		if (b1 & mask8)
   1025 			ret |= mask;
   1026 		mask = mask >> 1;
   1027 		if (b2 & mask8)
   1028 			ret |= mask;
   1029 		mask = mask >> 1;
   1030 		mask8 = mask8 << 1;
   1031 	}
   1032 	return ret;
   1033 }
   1034 
   1035 uint16_t
   1036 util_interleave_lin(uint8_t b1, uint8_t b2)
   1037 {
   1038 	int i;
   1039 	uint16_t ret = 0;
   1040 	uint16_t mask = 0x8000;
   1041 	uint8_t mask8 = 0x80;
   1042 
   1043 	for (i = 0; i < 8; i++) {
   1044 		if (b1 & mask8)
   1045 			ret |= mask;
   1046 		mask = mask >> 1;
   1047 		if (b2 & mask8)
   1048 			ret |= mask;
   1049 		mask = mask >> 1;
   1050 		mask8 = mask8 >> 1;
   1051 	}
   1052 	return ret;
   1053 }
   1054 
   1055 /* and now the /dev/fb* stuff */
   1056 static void
   1057 agten_fb_unblank(device_t dev)
   1058 {
   1059 	struct agten_softc *sc = device_private(dev);
   1060 
   1061 	agten_init(sc);
   1062 	agten_set_video(sc, 1);
   1063 }
   1064 
   1065 static int
   1066 agten_fb_open(dev_t dev, int flags, int mode, struct lwp *l)
   1067 {
   1068 	struct agten_softc *sc;
   1069 
   1070 	sc = device_lookup_private(&agten_cd, minor(dev));
   1071 	if (sc == NULL)
   1072 		return (ENXIO);
   1073 	if (sc->sc_fb_is_open)
   1074 		return 0;
   1075 
   1076 	sc->sc_fb_is_open++;
   1077 	agten_gfx(sc);
   1078 
   1079 	return (0);
   1080 }
   1081 
   1082 static int
   1083 agten_fb_close(dev_t dev, int flags, int mode, struct lwp *l)
   1084 {
   1085 	struct agten_softc *sc;
   1086 
   1087 	sc = device_lookup_private(&agten_cd, minor(dev));
   1088 
   1089 	sc->sc_fb_is_open--;
   1090 	if (sc->sc_fb_is_open < 0)
   1091 		sc->sc_fb_is_open = 0;
   1092 
   1093 	if (sc->sc_fb_is_open == 0) {
   1094 		agten_init(sc);
   1095 		vcons_redraw_screen(sc->vd.active);
   1096 	}
   1097 
   1098 	return (0);
   1099 }
   1100 
   1101 static int
   1102 agten_fb_ioctl(dev_t dev, u_long cmd, void *data, int flags, struct lwp *l)
   1103 {
   1104 	struct agten_softc *sc = device_lookup_private(&agten_cd, minor(dev));
   1105 	struct fbgattr *fba;
   1106 	int error;
   1107 
   1108 	switch (cmd) {
   1109 
   1110 	case FBIOGTYPE:
   1111 		*(struct fbtype *)data = sc->sc_fb.fb_type;
   1112 		break;
   1113 
   1114 	case FBIOGATTR:
   1115 		fba = (struct fbgattr *)data;
   1116 		fba->real_type = sc->sc_fb.fb_type.fb_type;
   1117 		fba->owner = 0;		/* XXX ??? */
   1118 		fba->fbtype = sc->sc_fb.fb_type;
   1119 		fba->sattr.flags = 0;
   1120 		fba->sattr.emu_type = sc->sc_fb.fb_type.fb_type;
   1121 		fba->sattr.dev_specific[0] = -1;
   1122 		fba->emu_types[0] = sc->sc_fb.fb_type.fb_type;
   1123 		fba->emu_types[1] = -1;
   1124 		break;
   1125 
   1126 	case FBIOGETCMAP:
   1127 #define p ((struct fbcmap *)data)
   1128 		return (bt_getcmap(p, &sc->sc_cmap, 256, 1));
   1129 
   1130 	case FBIOPUTCMAP:
   1131 		/* copy to software map */
   1132 		error = bt_putcmap(p, &sc->sc_cmap, 256, 1);
   1133 		if (error)
   1134 			return (error);
   1135 		/* now blast them into the chip */
   1136 		/* don't bother - we're 24bit */
   1137 #undef p
   1138 		break;
   1139 
   1140 	case FBIOGVIDEO:
   1141 		*(int *)data = agten_get_video(sc);
   1142 		break;
   1143 
   1144 	case FBIOSVIDEO:
   1145 		agten_set_video(sc, *(int *)data);
   1146 		break;
   1147 
   1148 /* these are for both FBIOSCURSOR and FBIOGCURSOR */
   1149 #define p ((struct fbcursor *)data)
   1150 #define pc (&sc->sc_cursor)
   1151 
   1152 	case FBIOGCURSOR:
   1153 		/* does anyone use this ioctl?! */
   1154 		p->set = FB_CUR_SETALL;	/* close enough, anyway */
   1155 		p->enable = 1;
   1156 		p->pos.x = sc->sc_cursor_x;
   1157 		p->pos.y = sc->sc_cursor_y;
   1158 		p->size.x = 64;
   1159 		p->size.y = 64;
   1160 		break;
   1161 
   1162 	case FBIOSCURSOR:
   1163 		agten_do_sun_cursor(sc, p);
   1164 	break;
   1165 
   1166 #undef p
   1167 #undef cc
   1168 
   1169 	case FBIOGCURPOS:
   1170 	{
   1171 		struct fbcurpos *cp = (struct fbcurpos *)data;
   1172 		cp->x = sc->sc_cursor_x;
   1173 		cp->y = sc->sc_cursor_y;
   1174 	}
   1175 	break;
   1176 
   1177 	case FBIOSCURPOS:
   1178 	{
   1179 		struct fbcurpos *cp = (struct fbcurpos *)data;
   1180 		agten_move_cursor(sc, cp->x, cp->y);
   1181 	}
   1182 	break;
   1183 
   1184 	case FBIOGCURMAX:
   1185 		/* max cursor size is 64x64 */
   1186 		((struct fbcurpos *)data)->x = 64;
   1187 		((struct fbcurpos *)data)->y = 64;
   1188 		break;
   1189 
   1190 	default:
   1191 		return (ENOTTY);
   1192 	}
   1193 	return (0);
   1194 }
   1195 
   1196 static paddr_t
   1197 agten_fb_mmap(dev_t dev, off_t off, int prot)
   1198 {
   1199 	struct agten_softc *sc = device_lookup_private(&agten_cd, minor(dev));
   1200 
   1201 	/*
   1202 	 * mappings are subject to change
   1203 	 * for now we put the framebuffer at offset 0 and the GLint registers
   1204 	 * right after that. We may want to expose more register ranges and
   1205 	 * probably will want to map the 2nd framebuffer as well
   1206 	 */
   1207 
   1208 	if (off < 0)
   1209 		return EINVAL;
   1210 
   1211 	if (off >= sc->sc_glint_fbsz + 0x10000)
   1212 		return EINVAL;
   1213 
   1214 	if (off < sc->sc_glint_fbsz) {
   1215 		return (bus_space_mmap(sc->sc_bustag,
   1216 			sc->sc_glint_fb,
   1217 			off,
   1218 			prot,
   1219 			BUS_SPACE_MAP_LINEAR));
   1220 	}
   1221 
   1222 	off -= sc->sc_glint_fbsz;
   1223 	if (off < 0x10000) {
   1224 		return (bus_space_mmap(sc->sc_bustag,
   1225 			sc->sc_glint_regs,
   1226 			off,
   1227 			prot,
   1228 			BUS_SPACE_MAP_LINEAR));
   1229 	}
   1230 	return EINVAL;
   1231 }
   1232