Home | History | Annotate | Line # | Download | only in gio
light.c revision 1.9.8.1
      1  1.9.8.1   thorpej /*	$Id: light.c,v 1.9.8.1 2021/08/04 02:53:00 thorpej Exp $	*/
      2      1.1    rumble 
      3      1.1    rumble /*
      4      1.1    rumble  * Copyright (c) 2006 Stephen M. Rumble
      5      1.1    rumble  * Copyright (c) 2003 Ilpo Ruotsalainen
      6      1.1    rumble  * All rights reserved.
      7      1.1    rumble  *
      8      1.1    rumble  * Redistribution and use in source and binary forms, with or without
      9      1.1    rumble  * modification, are permitted provided that the following conditions
     10      1.1    rumble  * are met:
     11      1.1    rumble  * 1. Redistributions of source code must retain the above copyright
     12      1.1    rumble  *    notice, this list of conditions and the following disclaimer.
     13      1.1    rumble  * 2. Redistributions in binary form must reproduce the above copyright
     14      1.1    rumble  *    notice, this list of conditions and the following disclaimer in the
     15      1.1    rumble  *    documentation and/or other materials provided with the distribution.
     16      1.1    rumble  * 3. The name of the author may not be used to endorse or promote products
     17      1.1    rumble  *    derived from this software without specific prior written permission.
     18      1.1    rumble  *
     19      1.1    rumble  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     20      1.1    rumble  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     21      1.1    rumble  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     22      1.1    rumble  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     23      1.1    rumble  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     24      1.1    rumble  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     25      1.1    rumble  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     26      1.1    rumble  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     27      1.1    rumble  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     28      1.1    rumble  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     29      1.1    rumble  *
     30      1.1    rumble  * <<Id: LICENSE_GC,v 1.1 2001/10/01 23:24:05 cgd Exp>>
     31      1.1    rumble  */
     32      1.1    rumble 
     33      1.1    rumble /*
     34      1.1    rumble  * SGI "Light" graphics, a.k.a. "Entry", "Starter", "LG1", and "LG2".
     35      1.1    rumble  *
     36      1.1    rumble  * 1024x768 8bpp at 60Hz.
     37      1.1    rumble  *
     38      1.1    rumble  * This driver supports the boards found in Indigo R3k and R4k machines.
     39      1.1    rumble  * There is a Crimson variant, but the register offsets differ significantly.
     40      1.1    rumble  *
     41      1.2    rumble  * Light's REX chip is the precursor of the REX3 found in "newport", hence
     42      1.2    rumble  * much similarity exists.
     43      1.1    rumble  */
     44      1.1    rumble 
     45      1.1    rumble #include <sys/cdefs.h>
     46  1.9.8.1   thorpej __KERNEL_RCSID(0, "$NetBSD: light.c,v 1.9.8.1 2021/08/04 02:53:00 thorpej Exp $");
     47      1.1    rumble 
     48      1.1    rumble #include <sys/param.h>
     49      1.1    rumble #include <sys/systm.h>
     50      1.1    rumble #include <sys/device.h>
     51      1.8   thorpej #include <sys/kmem.h>
     52      1.1    rumble 
     53      1.4    rumble #include <machine/sysconf.h>
     54      1.4    rumble 
     55      1.1    rumble #include <dev/wscons/wsconsio.h>
     56      1.1    rumble #include <dev/wscons/wsdisplayvar.h>
     57      1.1    rumble #include <dev/wsfont/wsfont.h>
     58      1.1    rumble 
     59      1.1    rumble #include <sgimips/gio/giovar.h>
     60      1.1    rumble #include <sgimips/gio/lightvar.h>
     61      1.1    rumble #include <sgimips/gio/lightreg.h>
     62      1.1    rumble 
     63      1.1    rumble struct light_softc {
     64      1.1    rumble 	struct light_devconfig *sc_dc;
     65      1.1    rumble };
     66      1.1    rumble 
     67      1.1    rumble struct light_devconfig {
     68      1.1    rumble 	uint32_t		dc_addr;
     69      1.1    rumble 
     70      1.1    rumble 	bus_space_tag_t		dc_st;
     71      1.1    rumble 	bus_space_handle_t	dc_sh;
     72      1.1    rumble 
     73      1.1    rumble 	int			dc_boardrev;
     74      1.1    rumble 	int                     dc_font;
     75      1.1    rumble 	struct wsdisplay_font  *dc_fontdata;
     76      1.1    rumble };
     77      1.1    rumble 
     78      1.1    rumble /* always 1024x768x8 */
     79      1.1    rumble #define LIGHT_XRES	1024
     80      1.1    rumble #define LIGHT_YRES	768
     81      1.1    rumble #define LIGHT_DEPTH	8
     82      1.1    rumble 
     83      1.7       chs static int	light_match(device_t, cfdata_t, void *);
     84      1.7       chs static void	light_attach(device_t, device_t, void *);
     85      1.1    rumble 
     86      1.7       chs CFATTACH_DECL_NEW(light, sizeof(struct light_softc), light_match, light_attach,
     87      1.1    rumble     NULL, NULL);
     88      1.1    rumble 
     89      1.1    rumble /* wsdisplay_emulops */
     90      1.1    rumble static void	light_cursor(void *, int, int, int);
     91      1.1    rumble static int	light_mapchar(void *, int, unsigned int *);
     92      1.1    rumble static void	light_putchar(void *, int, int, u_int, long);
     93      1.1    rumble static void	light_copycols(void *, int, int, int, int);
     94      1.1    rumble static void	light_erasecols(void *, int, int, int, long);
     95      1.1    rumble static void	light_copyrows(void *, int, int, int);
     96      1.1    rumble static void	light_eraserows(void *, int, int, long);
     97      1.1    rumble static int	light_allocattr(void *, int, int, int, long *);
     98      1.1    rumble 
     99      1.1    rumble /* wsdisplay_accessops */
    100      1.5  christos static int	light_ioctl(void *, void *, u_long, void *, int, struct lwp *);
    101      1.1    rumble static paddr_t	light_mmap(void *, void *, off_t, int);
    102      1.1    rumble static int	light_alloc_screen(void *, const struct wsscreen_descr *,
    103      1.1    rumble     void **, int *, int *, long *);
    104      1.1    rumble static void	light_free_screen(void *, void *);
    105      1.1    rumble static int	light_show_screen(void *, void *, int,
    106      1.1    rumble     void (*)(void *, int, int), void *);
    107      1.1    rumble 
    108      1.1    rumble static const struct wsdisplay_accessops light_accessops = {
    109      1.1    rumble 	.ioctl		= light_ioctl,
    110      1.1    rumble 	.mmap		= light_mmap,
    111      1.1    rumble 	.alloc_screen	= light_alloc_screen,
    112      1.1    rumble 	.free_screen	= light_free_screen,
    113      1.1    rumble 	.show_screen	= light_show_screen,
    114      1.1    rumble 	.load_font	= NULL,
    115      1.1    rumble 	.pollc		= NULL,
    116      1.1    rumble 	.scroll		= NULL
    117      1.1    rumble };
    118      1.1    rumble 
    119      1.1    rumble static const struct wsdisplay_emulops light_emulops = {
    120      1.1    rumble 	.cursor		= light_cursor,
    121      1.1    rumble 	.mapchar	= light_mapchar,
    122      1.1    rumble 	.putchar	= light_putchar,
    123      1.1    rumble 	.copycols	= light_copycols,
    124      1.1    rumble 	.erasecols	= light_erasecols,
    125      1.1    rumble 	.copyrows	= light_copyrows,
    126      1.1    rumble 	.eraserows	= light_eraserows,
    127      1.1    rumble 	.allocattr	= light_allocattr,
    128      1.1    rumble 	.replaceattr	= NULL
    129      1.1    rumble };
    130      1.1    rumble 
    131      1.1    rumble static const struct wsscreen_descr light_screen = {
    132      1.1    rumble 	.name           = "1024x768",
    133      1.1    rumble 	.ncols          = 128,
    134      1.1    rumble 	.nrows          = 48,
    135      1.1    rumble 	.textops        = &light_emulops,
    136      1.1    rumble 	.fontwidth      = 8,
    137      1.1    rumble 	.fontheight     = 16,
    138      1.1    rumble 	.capabilities   = WSSCREEN_WSCOLORS | WSSCREEN_HILIT | WSSCREEN_REVERSE
    139      1.1    rumble };
    140      1.1    rumble 
    141      1.1    rumble const struct wsscreen_descr *_light_screenlist[] = {
    142      1.1    rumble 	&light_screen
    143      1.1    rumble };
    144      1.1    rumble 
    145      1.1    rumble static const struct wsscreen_list light_screenlist = {
    146      1.1    rumble 	sizeof(_light_screenlist) / sizeof(_light_screenlist[0]),
    147      1.1    rumble 	_light_screenlist
    148      1.1    rumble };
    149      1.1    rumble 
    150      1.1    rumble static struct light_devconfig	light_console_dc;
    151      1.1    rumble static int			light_is_console = 0;
    152      1.1    rumble 
    153      1.1    rumble #define LIGHT_ATTR_ENCODE(fg, bg)	(((fg << 8) & 0xff00) | (bg * 0x00ff))
    154      1.1    rumble #define LIGHT_ATTR_FG(attr)		((attr >> 8) & 0x00ff)
    155      1.1    rumble #define LIGHT_ATTR_BG(attr)		(attr & 0x00ff)
    156      1.1    rumble 
    157      1.1    rumble #define LIGHT_IS_LG1(_rev)		((_rev) < 2)	/* else LG2 */
    158      1.1    rumble 
    159      1.1    rumble /*******************************************************************************
    160      1.1    rumble  * REX routines and helper functions
    161      1.1    rumble  ******************************************************************************/
    162      1.1    rumble 
    163      1.1    rumble static uint32_t
    164      1.1    rumble rex_read(struct light_devconfig *dc, uint32_t rset, uint32_t r)
    165      1.1    rumble {
    166      1.1    rumble 
    167      1.1    rumble 	return (bus_space_read_4(dc->dc_st, dc->dc_sh, rset + r));
    168      1.1    rumble }
    169      1.1    rumble 
    170      1.1    rumble static void
    171      1.1    rumble rex_write(struct light_devconfig *dc, uint32_t rset, uint32_t r, uint32_t v)
    172      1.1    rumble {
    173      1.1    rumble 
    174      1.1    rumble 	bus_space_write_4(dc->dc_st, dc->dc_sh, rset + r, v);
    175      1.1    rumble }
    176      1.1    rumble 
    177      1.2    rumble static uint8_t
    178      1.2    rumble rex_vc1_read(struct light_devconfig *dc)
    179      1.2    rumble {
    180      1.2    rumble 
    181      1.2    rumble 	rex_write(dc, REX_PAGE1_GO, REX_P1REG_CFGSEL, REX_CFGSEL_VC1_SYSCTL);
    182      1.2    rumble 	rex_read(dc, REX_PAGE1_GO, REX_P1REG_VC1_ADDRDATA);
    183      1.2    rumble 	return (rex_read(dc, REX_PAGE1_SET, REX_P1REG_VC1_ADDRDATA));
    184      1.2    rumble }
    185      1.2    rumble 
    186      1.2    rumble static void
    187      1.2    rumble rex_vc1_write(struct light_devconfig *dc, uint8_t val)
    188      1.2    rumble {
    189      1.2    rumble 
    190      1.2    rumble 	rex_write(dc, REX_PAGE1_GO, REX_P1REG_CFGSEL, REX_CFGSEL_VC1_SYSCTL);
    191      1.2    rumble 	rex_write(dc, REX_PAGE1_SET, REX_P1REG_VC1_ADDRDATA, val);
    192      1.2    rumble 	rex_write(dc, REX_PAGE1_GO, REX_P1REG_VC1_ADDRDATA, val);
    193      1.2    rumble }
    194      1.2    rumble 
    195      1.1    rumble static void
    196      1.1    rumble rex_wait(struct light_devconfig *dc)
    197      1.1    rumble {
    198      1.1    rumble 
    199      1.2    rumble 	while (rex_read(dc, REX_PAGE1_SET,REX_P1REG_CFGMODE) & REX_CFGMODE_BUSY)
    200      1.1    rumble 		;
    201      1.1    rumble }
    202      1.1    rumble 
    203      1.1    rumble static int
    204      1.1    rumble rex_revision(struct light_devconfig *dc)
    205      1.1    rumble {
    206      1.1    rumble 
    207      1.2    rumble 	rex_write(dc, REX_PAGE1_SET, REX_P1REG_CFGSEL, REX_CFGSEL_VC1_LADDR);
    208      1.2    rumble 	rex_read(dc, REX_PAGE1_GO, REX_P1REG_WCLOCKREV);
    209      1.2    rumble 	return (rex_read(dc, REX_PAGE1_SET, REX_P1REG_WCLOCKREV) & 0x7);
    210      1.1    rumble }
    211      1.1    rumble 
    212      1.1    rumble static void
    213      1.1    rumble rex_copy_rect(struct light_devconfig *dc, int from_x, int from_y, int to_x,
    214      1.1    rumble     int to_y, int width, int height)
    215      1.1    rumble {
    216      1.1    rumble 	int dx, dy, ystarti, yendi;
    217      1.1    rumble 
    218      1.1    rumble 	dx = from_x - to_x;
    219      1.1    rumble 	dy = from_y - to_y;
    220      1.1    rumble 
    221      1.1    rumble 	/* adjust for y. NB: STOPONX, STOPONY are inclusive */
    222      1.1    rumble 	if (to_y > from_y) {
    223      1.1    rumble 		ystarti = to_y + height - 1;
    224      1.1    rumble 		yendi = to_y;
    225      1.1    rumble 	} else {
    226      1.1    rumble 		ystarti = to_y;
    227      1.1    rumble 		yendi = to_y + height - 1;
    228      1.1    rumble 	}
    229      1.1    rumble 
    230      1.1    rumble 	rex_wait(dc);
    231      1.1    rumble 
    232      1.2    rumble 	rex_write(dc, REX_PAGE0_SET, REX_P0REG_XSTARTI, to_x);
    233      1.2    rumble 	rex_write(dc, REX_PAGE0_SET, REX_P0REG_XENDI, to_x + width);
    234      1.2    rumble 	rex_write(dc, REX_PAGE0_SET, REX_P0REG_YSTARTI, ystarti);
    235      1.2    rumble 	rex_write(dc, REX_PAGE0_SET, REX_P0REG_YENDI, yendi);
    236      1.2    rumble 	rex_write(dc, REX_PAGE0_SET, REX_P0REG_COMMAND, REX_OP_DRAW |
    237      1.2    rumble 	    REX_LOGICOP_SRC | REX_OP_FLG_LOGICSRC | REX_OP_FLG_QUADMODE |
    238      1.2    rumble 	    REX_OP_FLG_BLOCK | REX_OP_FLG_STOPONX | REX_OP_FLG_STOPONY);
    239      1.2    rumble 	rex_write(dc, REX_PAGE0_GO, REX_P0REG_XYMOVE,
    240      1.1    rumble 	    ((dx << 16) & 0xffff0000) | (dy & 0x0000ffff));
    241      1.1    rumble }
    242      1.1    rumble 
    243      1.1    rumble static void
    244      1.1    rumble rex_fill_rect(struct light_devconfig *dc, int from_x, int from_y, int to_x,
    245      1.1    rumble     int to_y, long attr)
    246      1.1    rumble {
    247      1.1    rumble 
    248      1.1    rumble 	rex_wait(dc);
    249      1.1    rumble 
    250      1.2    rumble 	rex_write(dc, REX_PAGE0_SET, REX_P0REG_YSTARTI, from_y);
    251      1.2    rumble 	rex_write(dc, REX_PAGE0_SET, REX_P0REG_YENDI, to_y);
    252      1.2    rumble 	rex_write(dc, REX_PAGE0_SET, REX_P0REG_XSTARTI, from_x);
    253      1.2    rumble 	rex_write(dc, REX_PAGE0_SET, REX_P0REG_XENDI, to_x);
    254      1.2    rumble 	rex_write(dc, REX_PAGE0_SET, REX_P0REG_COLORREDI, LIGHT_ATTR_BG(attr));
    255      1.2    rumble 	rex_write(dc, REX_PAGE0_SET, REX_P0REG_COMMAND, REX_OP_DRAW |
    256      1.2    rumble 	    REX_LOGICOP_SRC | REX_OP_FLG_QUADMODE | REX_OP_FLG_BLOCK |
    257      1.2    rumble 	    REX_OP_FLG_STOPONX | REX_OP_FLG_STOPONY);
    258      1.2    rumble 	rex_read(dc, REX_PAGE0_GO, REX_P0REG_COMMAND);
    259      1.1    rumble }
    260      1.1    rumble 
    261      1.1    rumble /*******************************************************************************
    262      1.1    rumble  * match/attach functions
    263      1.1    rumble  ******************************************************************************/
    264      1.1    rumble 
    265      1.1    rumble static int
    266      1.7       chs light_match(device_t parent, cfdata_t cf, void *aux)
    267      1.1    rumble {
    268      1.1    rumble 	struct gio_attach_args *ga = aux;
    269      1.1    rumble 
    270      1.1    rumble 	if (ga->ga_addr != LIGHT_ADDR_0 && ga->ga_addr != LIGHT_ADDR_1)
    271      1.1    rumble 		return (0);
    272      1.1    rumble 
    273      1.4    rumble 	if (platform.badaddr(
    274      1.4    rumble 	    (void *)(ga->ga_ioh + REX_PAGE1_SET + REX_P1REG_XYOFFSET),
    275      1.3    rumble 	    sizeof(uint32_t)))
    276      1.3    rumble 		return (0);
    277      1.3    rumble 
    278      1.3    rumble 	if (bus_space_read_4(ga->ga_iot, ga->ga_ioh,
    279      1.3    rumble 	    REX_PAGE1_SET + REX_P1REG_XYOFFSET) != 0x08000800)
    280      1.3    rumble 		return (0);
    281      1.3    rumble 
    282      1.1    rumble 	return (1);
    283      1.1    rumble }
    284      1.1    rumble 
    285      1.1    rumble static void
    286      1.1    rumble light_attach_common(struct light_devconfig *dc, struct gio_attach_args *ga)
    287      1.1    rumble {
    288      1.1    rumble 
    289      1.1    rumble 	dc->dc_addr = ga->ga_addr;
    290      1.1    rumble 	dc->dc_st = ga->ga_iot;
    291      1.1    rumble 	dc->dc_sh = ga->ga_ioh;
    292      1.1    rumble 
    293      1.1    rumble 	dc->dc_boardrev = rex_revision(dc);
    294      1.1    rumble 
    295      1.1    rumble 	wsfont_init();
    296      1.1    rumble 
    297      1.1    rumble 	dc->dc_font = wsfont_find(NULL, 8, 16, 0, WSDISPLAY_FONTORDER_L2R,
    298      1.6  macallan 	    WSDISPLAY_FONTORDER_L2R, WSFONT_FIND_BITMAP);
    299      1.1    rumble 
    300      1.1    rumble 	if (dc->dc_font < 0)
    301      1.1    rumble 		panic("light_attach_common: no suitable fonts");
    302      1.1    rumble 
    303      1.1    rumble 	if (wsfont_lock(dc->dc_font, &dc->dc_fontdata))
    304      1.1    rumble 		panic("light_attach_common: unable to lock font data");
    305      1.1    rumble 
    306      1.2    rumble 	rex_vc1_write(dc, rex_vc1_read(dc) & ~(VC1_SYSCTL_CURSOR |
    307      1.2    rumble 	    VC1_SYSCTL_CURSOR_ON));
    308      1.1    rumble 	rex_fill_rect(dc, 0, 0, LIGHT_XRES - 1, LIGHT_YRES - 1, 0);
    309      1.1    rumble }
    310      1.1    rumble 
    311      1.1    rumble static void
    312      1.7       chs light_attach(device_t parent, device_t self, void *aux)
    313      1.1    rumble {
    314      1.1    rumble 	struct gio_attach_args *ga = aux;
    315      1.7       chs 	struct light_softc *sc = device_private(self);
    316      1.1    rumble 	struct wsemuldisplaydev_attach_args wa;
    317      1.1    rumble 
    318      1.1    rumble 	if (light_is_console && ga->ga_addr == light_console_dc.dc_addr) {
    319      1.1    rumble 		wa.console = 1;
    320      1.1    rumble 		sc->sc_dc = &light_console_dc;
    321      1.1    rumble 	} else {
    322      1.1    rumble 		wa.console = 0;
    323      1.8   thorpej 		sc->sc_dc = kmem_zalloc(sizeof(struct light_devconfig),
    324      1.8   thorpej 		    KM_SLEEP);
    325      1.1    rumble 
    326      1.1    rumble 		light_attach_common(sc->sc_dc, ga);
    327      1.1    rumble 	}
    328      1.1    rumble 
    329      1.1    rumble 	aprint_naive(": Display adapter\n");
    330      1.1    rumble 
    331      1.2    rumble 	aprint_normal(": SGI LG%d (board revision %d)\n",
    332      1.1    rumble 	    LIGHT_IS_LG1(sc->sc_dc->dc_boardrev) ? 1 : 2,
    333      1.1    rumble 	    sc->sc_dc->dc_boardrev);
    334      1.1    rumble 
    335      1.1    rumble 	wa.scrdata = &light_screenlist;
    336      1.1    rumble 	wa.accessops = &light_accessops;
    337      1.1    rumble 	wa.accesscookie = sc->sc_dc;
    338      1.1    rumble 
    339  1.9.8.1   thorpej 	config_found(self, &wa, wsemuldisplaydevprint, CFARGS_NONE);
    340      1.1    rumble }
    341      1.1    rumble 
    342      1.1    rumble int
    343      1.1    rumble light_cnattach(struct gio_attach_args *ga)
    344      1.1    rumble {
    345      1.1    rumble 
    346      1.1    rumble 	if (!light_match(NULL, NULL, ga))
    347      1.1    rumble 		return (ENXIO);
    348      1.1    rumble 
    349      1.1    rumble 	light_attach_common(&light_console_dc, ga);
    350      1.1    rumble 
    351      1.1    rumble 	wsdisplay_cnattach(&light_screen, &light_console_dc, 0, 0,
    352      1.1    rumble 	    LIGHT_ATTR_ENCODE(WSCOL_WHITE, WSCOL_BLACK));
    353      1.1    rumble 
    354      1.1    rumble 	light_is_console = 1;
    355      1.1    rumble 
    356      1.1    rumble 	return (0);
    357      1.1    rumble }
    358      1.1    rumble 
    359      1.1    rumble /*******************************************************************************
    360      1.1    rumble  * wsdisplay_emulops
    361      1.1    rumble  ******************************************************************************/
    362      1.1    rumble 
    363      1.1    rumble static void
    364      1.1    rumble light_cursor(void *c, int on, int row, int col)
    365      1.1    rumble {
    366      1.1    rumble 	/* XXX */
    367      1.1    rumble }
    368      1.1    rumble 
    369      1.1    rumble static int
    370      1.1    rumble light_mapchar(void *c, int ch, unsigned int *cp)
    371      1.1    rumble {
    372      1.1    rumble 	struct light_devconfig *dc = (void *)c;
    373      1.1    rumble 
    374      1.1    rumble 	if (dc->dc_fontdata->encoding != WSDISPLAY_FONTENC_ISO) {
    375      1.1    rumble 		ch = wsfont_map_unichar(dc->dc_fontdata, ch);
    376      1.1    rumble 
    377      1.1    rumble 		if (ch < 0)
    378      1.1    rumble 			goto fail;
    379      1.1    rumble 	}
    380      1.1    rumble 
    381      1.1    rumble 	if (ch < dc->dc_fontdata->firstchar ||
    382      1.1    rumble 	    ch >= dc->dc_fontdata->firstchar + dc->dc_fontdata->numchars)
    383      1.1    rumble 		goto fail;
    384      1.1    rumble 
    385      1.1    rumble 	*cp = ch;
    386      1.1    rumble 	return 5;
    387      1.1    rumble 
    388      1.1    rumble fail:
    389      1.1    rumble 	*cp = ' ';
    390      1.1    rumble 	return 0;
    391      1.1    rumble }
    392      1.1    rumble 
    393      1.1    rumble static void
    394      1.1    rumble light_putchar(void *c, int row, int col, u_int ch, long attr)
    395      1.1    rumble {
    396      1.1    rumble         struct light_devconfig *dc = c;
    397      1.1    rumble 	struct wsdisplay_font *font = dc->dc_fontdata;
    398      1.1    rumble 	uint8_t *bitmap;
    399      1.1    rumble 	uint32_t pattern;
    400      1.1    rumble 	int i, x, y;
    401      1.1    rumble 
    402      1.1    rumble 	bitmap = (u_int8_t *)font->data +
    403      1.1    rumble 	    ((ch - font->firstchar) * font->fontheight * font->stride);
    404      1.1    rumble 	x = col * font->fontwidth;
    405      1.1    rumble 	y = row * font->fontheight;
    406      1.1    rumble 
    407      1.1    rumble 	rex_wait(dc);
    408      1.1    rumble 
    409      1.2    rumble 	rex_write(dc, REX_PAGE0_SET, REX_P0REG_YSTARTI, y);
    410      1.2    rumble 	rex_write(dc, REX_PAGE0_SET, REX_P0REG_YENDI, y + font->fontheight - 1);
    411      1.2    rumble 	rex_write(dc, REX_PAGE0_SET, REX_P0REG_XSTARTI, x);
    412      1.2    rumble 	rex_write(dc, REX_PAGE0_SET, REX_P0REG_XENDI, x + font->fontwidth - 1);
    413      1.2    rumble 	rex_write(dc, REX_PAGE0_SET, REX_P0REG_COLORREDI, LIGHT_ATTR_FG(attr));
    414      1.2    rumble 	rex_write(dc, REX_PAGE0_SET, REX_P0REG_COLORBACK, LIGHT_ATTR_BG(attr));
    415      1.2    rumble 	rex_write(dc, REX_PAGE0_GO,  REX_P0REG_COMMAND, REX_OP_NOP);
    416      1.1    rumble 
    417      1.1    rumble 	rex_wait(dc);
    418      1.1    rumble 
    419      1.2    rumble 	rex_write(dc, REX_PAGE0_SET, REX_P0REG_COMMAND, REX_OP_DRAW |
    420      1.2    rumble 	    REX_LOGICOP_SRC | REX_OP_FLG_ENZPATTERN | REX_OP_FLG_QUADMODE |
    421      1.2    rumble 	    REX_OP_FLG_XYCONTINUE | REX_OP_FLG_STOPONX | REX_OP_FLG_BLOCK |
    422      1.2    rumble 	    REX_OP_FLG_LENGTH32 | REX_OP_FLG_ZOPAQUE);
    423      1.1    rumble 
    424      1.1    rumble 	for (i = 0; i < font->fontheight; i++) {
    425      1.1    rumble 		/* XXX assumes font->fontwidth == 8 */
    426      1.1    rumble 		pattern = *bitmap << 24;
    427      1.2    rumble 		rex_write(dc, REX_PAGE0_GO, REX_P0REG_ZPATTERN, pattern);
    428      1.1    rumble 		bitmap += font->stride;
    429      1.1    rumble 	}
    430      1.1    rumble }
    431      1.1    rumble 
    432      1.1    rumble /* copy set of columns within the same line */
    433      1.1    rumble static void
    434      1.1    rumble light_copycols(void *c, int row, int srccol, int dstcol, int ncols)
    435      1.1    rumble {
    436      1.1    rumble 	struct light_devconfig *dc = c;
    437      1.1    rumble 	struct wsdisplay_font *font = dc->dc_fontdata;
    438      1.1    rumble 	int from_x, from_y, to_x, to_y, width, height;
    439      1.1    rumble 
    440      1.1    rumble 	from_x	= srccol * font->fontwidth;
    441      1.1    rumble 	from_y	= row * font->fontheight;
    442      1.1    rumble 	to_x	= dstcol * font->fontwidth;
    443      1.1    rumble 	to_y	= from_y;
    444      1.1    rumble 	width	= ncols * font->fontwidth;
    445      1.1    rumble 	height	= font->fontheight;
    446      1.1    rumble 
    447      1.1    rumble 	rex_copy_rect(c, from_x, from_y, to_x, to_y, width, height);
    448      1.1    rumble }
    449      1.1    rumble 
    450      1.1    rumble /* erase a set of columns in the same line */
    451      1.1    rumble static void
    452      1.1    rumble light_erasecols(void *c, int row, int startcol, int ncols, long attr)
    453      1.1    rumble {
    454      1.1    rumble 	struct light_devconfig *dc = c;
    455      1.1    rumble 	struct wsdisplay_font *font = dc->dc_fontdata;
    456      1.1    rumble 	int from_x, from_y, to_x, to_y;
    457      1.1    rumble 
    458      1.1    rumble 	from_x	= startcol * font->fontwidth;
    459      1.1    rumble 	from_y	= row * font->fontheight;
    460      1.1    rumble 	to_x	= from_x + (ncols * font->fontwidth) - 1;
    461      1.1    rumble 	to_y	= from_y + font->fontheight - 1;
    462      1.1    rumble 
    463      1.1    rumble 	rex_fill_rect(c, from_x, from_y, to_x, to_y, attr);
    464      1.1    rumble }
    465      1.1    rumble 
    466      1.1    rumble /* copy a set of complete rows */
    467      1.1    rumble static void
    468      1.1    rumble light_copyrows(void *c, int srcrow, int dstrow, int nrows)
    469      1.1    rumble {
    470      1.1    rumble 	struct light_devconfig *dc = c;
    471      1.1    rumble 	struct wsdisplay_font *font = dc->dc_fontdata;
    472      1.1    rumble 	int from_x, from_y, to_x, to_y, width, height;
    473      1.1    rumble 
    474      1.1    rumble 	from_x	= 0;
    475      1.1    rumble 	from_y	= srcrow * font->fontheight;
    476      1.1    rumble 	to_x	= 0;
    477      1.1    rumble 	to_y	= dstrow * font->fontheight;
    478      1.1    rumble 	width	= LIGHT_XRES;
    479      1.1    rumble 	height	= nrows * font->fontheight;
    480      1.1    rumble 
    481      1.1    rumble 	rex_copy_rect(c, from_x, from_y, to_x, to_y, width, height);
    482      1.1    rumble }
    483      1.1    rumble 
    484      1.1    rumble /* erase a set of complete rows */
    485      1.1    rumble static void
    486      1.1    rumble light_eraserows(void *c, int row, int nrows, long attr)
    487      1.1    rumble {
    488      1.1    rumble 	struct light_devconfig *dc = c;
    489      1.1    rumble 	struct wsdisplay_font *font = dc->dc_fontdata;
    490      1.1    rumble 	int from_x, from_y, to_x, to_y;
    491      1.1    rumble 
    492      1.1    rumble 	from_x	= 0;
    493      1.1    rumble 	from_y	= row * font->fontheight;
    494      1.1    rumble 	to_x	= LIGHT_XRES - 1;
    495      1.1    rumble 	to_y	= from_y + (nrows * font->fontheight) - 1;
    496      1.1    rumble 
    497      1.1    rumble 	rex_fill_rect(c, from_x, from_y, to_x, to_y, attr);
    498      1.1    rumble }
    499      1.1    rumble 
    500      1.1    rumble static int
    501      1.1    rumble light_allocattr(void *c, int fg, int bg, int flags, long *attr)
    502      1.1    rumble {
    503      1.1    rumble 
    504      1.2    rumble 	if (flags & ~(WSATTR_WSCOLORS | WSATTR_HILIT | WSATTR_REVERSE))
    505      1.1    rumble 		return (EINVAL);
    506      1.1    rumble 
    507      1.1    rumble 	if ((flags & WSATTR_WSCOLORS) == 0) {
    508      1.1    rumble 		fg = WSCOL_WHITE;
    509      1.1    rumble 		bg = WSCOL_BLACK;
    510      1.1    rumble 	}
    511      1.1    rumble 
    512      1.1    rumble 	if (flags & WSATTR_HILIT)
    513      1.1    rumble 		fg += 8;
    514      1.1    rumble 
    515      1.1    rumble 	if (flags & WSATTR_REVERSE) {
    516      1.1    rumble 		int tmp = fg;
    517      1.1    rumble 		fg = bg;
    518      1.1    rumble 		bg = tmp;
    519      1.1    rumble 	}
    520      1.1    rumble 
    521      1.1    rumble 	*attr = LIGHT_ATTR_ENCODE(fg, bg);
    522      1.1    rumble 	return (0);
    523      1.1    rumble }
    524      1.1    rumble 
    525      1.1    rumble /*******************************************************************************
    526      1.1    rumble  * wsdisplay_accessops
    527      1.1    rumble  ******************************************************************************/
    528      1.1    rumble 
    529      1.1    rumble static int
    530      1.5  christos light_ioctl(void *c, void *vs, u_long cmd, void *data, int flag,
    531      1.1    rumble     struct lwp *l)
    532      1.1    rumble {
    533      1.1    rumble 	struct wsdisplay_fbinfo *fbinfo = (struct wsdisplay_fbinfo *)data;
    534      1.1    rumble 
    535      1.1    rumble 	switch (cmd) {
    536      1.1    rumble 	case WSDISPLAYIO_GINFO:
    537      1.1    rumble 		fbinfo->width	= LIGHT_XRES;
    538      1.1    rumble 		fbinfo->height	= LIGHT_YRES;
    539      1.1    rumble 		fbinfo->depth	= LIGHT_DEPTH;
    540      1.1    rumble 		fbinfo->cmsize	= 1 << LIGHT_DEPTH;
    541      1.1    rumble 		return (0);
    542      1.1    rumble 
    543      1.2    rumble 	case WSDISPLAYIO_GMODE:
    544      1.2    rumble 		*(u_int *)data = WSDISPLAYIO_MODE_EMUL;
    545      1.2    rumble 		break;
    546      1.2    rumble 
    547      1.1    rumble 	case WSDISPLAYIO_GTYPE:
    548      1.1    rumble 		*(u_int *)data = WSDISPLAY_TYPE_LIGHT;
    549      1.1    rumble 		return (0);
    550      1.2    rumble 
    551      1.2    rumble 	case WSDISPLAYIO_SVIDEO:
    552      1.2    rumble 		/*
    553      1.2    rumble 		 * Turning off VC1 will stop refreshing the video ram (or so I
    554      1.2    rumble 		 * suspect). We'll blank the screen after bringing it back up,
    555      1.2    rumble 		 * since that's nicer than displaying garbage.
    556      1.2    rumble 		 */
    557      1.2    rumble 		if (*(u_int *)data == WSDISPLAYIO_VIDEO_OFF)
    558      1.2    rumble 			rex_vc1_write(c,rex_vc1_read(c) & ~VC1_SYSCTL_VIDEO_ON);
    559      1.2    rumble 		else {
    560      1.2    rumble 			rex_vc1_write(c, rex_vc1_read(c) | VC1_SYSCTL_VIDEO_ON);
    561      1.2    rumble 			rex_fill_rect(c, 0, 0, LIGHT_XRES-1, LIGHT_YRES-1, 0);
    562      1.2    rumble 		}
    563      1.2    rumble 		return (0);
    564      1.1    rumble 	}
    565      1.1    rumble 
    566      1.1    rumble 	return (EPASSTHROUGH);
    567      1.1    rumble }
    568      1.1    rumble 
    569      1.1    rumble static paddr_t
    570      1.1    rumble light_mmap(void *c, void *vs, off_t off, int prot)
    571      1.1    rumble {
    572      1.2    rumble         struct light_devconfig *dc = c;
    573      1.2    rumble 
    574      1.2    rumble 	if (off >= 0x7fff)
    575      1.2    rumble 		return (-1);
    576      1.2    rumble 
    577      1.2    rumble 	return (mips_btop(dc->dc_addr + off));
    578      1.1    rumble }
    579      1.1    rumble 
    580      1.1    rumble static int
    581      1.1    rumble light_alloc_screen(void *c, const struct wsscreen_descr *type, void **cookiep,
    582      1.1    rumble     int *curxp, int *curyp, long *attr)
    583      1.1    rumble {
    584      1.1    rumble 
    585      1.1    rumble 	return (ENOMEM);
    586      1.1    rumble }
    587      1.1    rumble 
    588      1.1    rumble static void
    589      1.1    rumble light_free_screen(void *c, void *cookie)
    590      1.1    rumble {
    591      1.1    rumble 
    592      1.1    rumble 	panic("light_free_screen");
    593      1.1    rumble }
    594      1.1    rumble 
    595      1.1    rumble static int
    596      1.1    rumble light_show_screen(void *c, void *cookie, int waitok,
    597      1.1    rumble     void (*cb)(void *, int, int), void *cbarg)
    598      1.1    rumble {
    599      1.1    rumble 
    600      1.1    rumble 	return (0);
    601      1.1    rumble }
    602