Home | History | Annotate | Line # | Download | only in rasops
      1 /*	 $NetBSD: rasops.c,v 1.129 2025/11/02 22:16:24 nia Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 1999 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      7  * This code is derived from software contributed to The NetBSD Foundation
      8  * by Andrew Doran.
      9  *
     10  * Redistribution and use in source and binary forms, with or without
     11  * modification, are permitted provided that the following conditions
     12  * are met:
     13  * 1. Redistributions of source code must retain the above copyright
     14  *    notice, this list of conditions and the following disclaimer.
     15  * 2. Redistributions in binary form must reproduce the above copyright
     16  *    notice, this list of conditions and the following disclaimer in the
     17  *    documentation and/or other materials provided with the distribution.
     18  *
     19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     29  * POSSIBILITY OF SUCH DAMAGE.
     30  */
     31 
     32 #include <sys/cdefs.h>
     33 __KERNEL_RCSID(0, "$NetBSD: rasops.c,v 1.129 2025/11/02 22:16:24 nia Exp $");
     34 
     35 #ifdef _KERNEL_OPT
     36 #include "opt_rasops.h"
     37 #include "opt_wsmsgattrs.h"
     38 #include "rasops_glue.h"
     39 #endif
     40 
     41 #include <sys/param.h>
     42 #include <sys/bswap.h>
     43 #include <sys/kmem.h>
     44 
     45 #include <machine/endian.h>
     46 
     47 #include <dev/wscons/wsdisplayvar.h>
     48 #include <dev/wscons/wsconsio.h>
     49 #include <dev/wsfont/wsfont.h>
     50 
     51 #define	_RASOPS_PRIVATE
     52 #include <dev/rasops/rasops.h>
     53 #include <dev/rasops/rasops_masks.h>	/* XXX for MBE */
     54 
     55 #ifndef _KERNEL
     56 #include <errno.h>
     57 #endif
     58 
     59 #ifdef RASOPS_DEBUG
     60 #define DPRINTF(...) aprint_error(...)
     61 #else
     62 #define DPRINTF(...) __nothing
     63 #endif
     64 
     65 struct rasops_matchdata {
     66 	struct rasops_info *ri;
     67 	int wantcols, wantrows;
     68 	int bestscore;
     69 	struct wsdisplay_font *pick;
     70 	int ident;
     71 };
     72 
     73 static const uint32_t rasops_lmask32[4 + 1] = {
     74 	MBE(0x00000000), MBE(0x00ffffff), MBE(0x0000ffff), MBE(0x000000ff),
     75 	MBE(0x00000000),
     76 };
     77 
     78 static const uint32_t rasops_rmask32[4 + 1] = {
     79 	MBE(0x00000000), MBE(0xff000000), MBE(0xffff0000), MBE(0xffffff00),
     80 	MBE(0xffffffff),
     81 };
     82 
     83 uint8_t rasops_ecmap[256 * 3];
     84 
     85 /* ANSI colormap (R,G,B). Upper 8 are high-intensity */
     86 const uint8_t rasops_cmap[256 * 3] = {
     87 	0x00, 0x00, 0x00, /* black */
     88 	0x7f, 0x00, 0x00, /* red */
     89 	0x00, 0x7f, 0x00, /* green */
     90 	0x7f, 0x7f, 0x00, /* brown */
     91 	0x00, 0x00, 0x7f, /* blue */
     92 	0x7f, 0x00, 0x7f, /* magenta */
     93 	0x00, 0x7f, 0x7f, /* cyan */
     94 	0xc7, 0xc7, 0xc7, /* white - XXX too dim? */
     95 
     96 	0x7f, 0x7f, 0x7f, /* black */
     97 	0xff, 0x00, 0x00, /* red */
     98 	0x00, 0xff, 0x00, /* green */
     99 	0xff, 0xff, 0x00, /* brown */
    100 	0x00, 0x00, 0xff, /* blue */
    101 	0xff, 0x00, 0xff, /* magenta */
    102 	0x00, 0xff, 0xff, /* cyan */
    103 	0xff, 0xff, 0xff, /* white */
    104 
    105 	/*
    106 	 * For the cursor, we need at least the last (255th)
    107 	 * color to be white. Fill up white completely for
    108 	 * simplicity.
    109 	 */
    110 #define _CMWHITE 0xff, 0xff, 0xff,
    111 #define _CMWHITE16	_CMWHITE _CMWHITE _CMWHITE _CMWHITE \
    112 			_CMWHITE _CMWHITE _CMWHITE _CMWHITE \
    113 			_CMWHITE _CMWHITE _CMWHITE _CMWHITE \
    114 			_CMWHITE _CMWHITE _CMWHITE _CMWHITE
    115 	_CMWHITE16 _CMWHITE16 _CMWHITE16 _CMWHITE16 _CMWHITE16
    116 	_CMWHITE16 _CMWHITE16 _CMWHITE16 _CMWHITE16 _CMWHITE16
    117 	_CMWHITE16 _CMWHITE16 _CMWHITE16 _CMWHITE16 /* but not the last one */
    118 #undef _CMWHITE16
    119 #undef _CMWHITE
    120 
    121 	/*
    122 	 * For the cursor the fg/bg indices are bit inverted, so
    123 	 * provide complimentary colors in the upper 16 entries.
    124 	 */
    125 	0x7f, 0x7f, 0x7f, /* black */
    126 	0xff, 0x00, 0x00, /* red */
    127 	0x00, 0xff, 0x00, /* green */
    128 	0xff, 0xff, 0x00, /* brown */
    129 	0x00, 0x00, 0xff, /* blue */
    130 	0xff, 0x00, 0xff, /* magenta */
    131 	0x00, 0xff, 0xff, /* cyan */
    132 	0xff, 0xff, 0xff, /* white */
    133 
    134 	0x00, 0x00, 0x00, /* black */
    135 	0x7f, 0x00, 0x00, /* red */
    136 	0x00, 0x7f, 0x00, /* green */
    137 	0x7f, 0x7f, 0x00, /* brown */
    138 	0x00, 0x00, 0x7f, /* blue */
    139 	0x7f, 0x00, 0x7f, /* magenta */
    140 	0x00, 0x7f, 0x7f, /* cyan */
    141 	0xc7, 0xc7, 0xc7, /* white - XXX too dim? */
    142 };
    143 
    144 /* True if color is gray */
    145 static const uint8_t rasops_isgray[256] = {
    146 	1, 0, 0, 0, 0, 0, 0, 1,
    147 	1, 0, 0, 0, 0, 0, 0, 1,
    148 	0, 0, 0, 0, 0, 0, 0, 0,
    149 	0, 0, 0, 0, 0, 0, 0, 0,
    150 	0, 0, 0, 0, 0, 0, 0, 0,
    151 	0, 0, 0, 0, 0, 0, 0, 0,
    152 	0, 0, 0, 0, 0, 0, 0, 0,
    153 	0, 0, 0, 0, 0, 0, 0, 0,
    154 	0, 0, 0, 0, 0, 0, 0, 0,
    155 	0, 0, 0, 0, 0, 0, 0, 0,
    156 	0, 0, 0, 0, 0, 0, 0, 0,
    157 	0, 0, 0, 0, 0, 0, 0, 0,
    158 	0, 0, 0, 0, 0, 0, 0, 0,
    159 	0, 0, 0, 0, 0, 0, 0, 0,
    160 	0, 0, 0, 0, 0, 0, 0, 0,
    161 	0, 0, 0, 0, 0, 0, 0, 0,
    162 	0, 0, 0, 0, 0, 0, 0, 0,
    163 	0, 0, 0, 0, 0, 0, 0, 0,
    164 	0, 0, 0, 0, 0, 0, 0, 0,
    165 	0, 0, 0, 0, 0, 0, 0, 0,
    166 	0, 0, 0, 0, 0, 0, 0, 0,
    167 	0, 0, 0, 0, 0, 0, 0, 0,
    168 	0, 0, 0, 0, 0, 0, 0, 0,
    169 	0, 0, 0, 0, 0, 0, 0, 0,
    170 	0, 0, 0, 0, 0, 0, 0, 0,
    171 	0, 0, 0, 0, 0, 0, 0, 0,
    172 	0, 0, 0, 0, 0, 0, 0, 0,
    173 	0, 0, 0, 0, 0, 0, 0, 0,
    174 	0, 0, 0, 0, 0, 0, 0, 0,
    175 	1, 1, 1, 1, 1, 1, 1, 1,
    176 	1, 1, 1, 1, 1, 1, 1, 1,
    177 	1, 1, 1, 1, 1, 1, 1, 1,
    178 };
    179 
    180 #ifdef RASOPS_APPLE_PALETTE
    181 /*
    182  * Approximate ANSI colormap for legacy Apple color palettes
    183  */
    184 static const uint8_t apple8_devcmap[16] = {
    185 	0xff,	/* black	0x00, 0x00, 0x00 */
    186 	0x6b,	/* red		0x99, 0x00, 0x00 */
    187 	0xc5,	/* green	0x00, 0x99, 0x00 */
    188 	0x59,	/* yellow	0x99, 0x99, 0x00 */
    189 	0xd4,	/* blue		0x00, 0x00, 0x99 */
    190 	0x68,	/* magenta	0x99, 0x00, 0x99 */
    191 	0xc2,	/* cyan		0x00, 0x99, 0x99 */
    192 	0x2b,	/* white	0xcc, 0xcc, 0xcc */
    193 
    194 	0x56,	/* black	0x99, 0x99, 0x99 */
    195 	0x23,	/* red		0xff, 0x00, 0x00 */
    196 	0xb9,	/* green	0x00, 0xff, 0x00 */
    197 	0x05,	/* yellow	0xff, 0xff, 0x00 */
    198 	0xd2,	/* blue		0x00, 0x00, 0xff */
    199 	0x1e,	/* magenta	0xff, 0x00, 0xff */
    200 	0xb4,	/* cyan		0x00, 0xff, 0xff */
    201 	0x00,	/* white	0xff, 0xff, 0xff */
    202 };
    203 
    204 static const uint8_t apple4_devcmap[16] = {
    205 	15,	/* black	*/
    206 	 3,	/* red		*/
    207 	 9,	/* dark green	*/
    208 	 1,	/* yellow	*/
    209 	 6,	/* blue		*/
    210 	 4,	/* magenta	*/
    211 	 7,	/* cyan		*/
    212 	12,	/* light grey	*/
    213 
    214 	13,	/* medium grey	*/
    215 	 3,	/* red		*/
    216 	 9,	/* dark green	*/
    217 	 1,	/* yellow	*/
    218 	 6,	/* blue		*/
    219 	 4,	/* magenta	*/
    220 	 7,	/* cyan		*/
    221 	 0,	/* white	*/
    222 };
    223 #endif
    224 
    225 /* Generic functions */
    226 static void	rasops_copyrows(void *, int, int, int);
    227 static void	rasops_copycols(void *, int, int, int, int);
    228 static int	rasops_mapchar(void *, int, u_int *);
    229 static void	rasops_cursor(void *, int, int, int);
    230 static int	rasops_allocattr_color(void *, int, int, int, long *);
    231 static int	rasops_allocattr_mono(void *, int, int, int, long *);
    232 static void	rasops_do_cursor(struct rasops_info *);
    233 static void	rasops_init_devcmap(struct rasops_info *);
    234 static void	rasops_make_box_chars_8(struct rasops_info *);
    235 static void	rasops_make_box_chars_16(struct rasops_info *);
    236 static void	rasops_make_box_chars_32(struct rasops_info *);
    237 static void	rasops_make_box_chars_alpha(struct rasops_info *);
    238 
    239 #if NRASOPS_ROTATION > 0
    240 static void	rasops_rotate_font(int *, int);
    241 static void	rasops_copychar(void *, int, int, int, int);
    242 
    243 /* rotate clockwise */
    244 static void	rasops_copycols_rotated_cw(void *, int, int, int, int);
    245 static void	rasops_copyrows_rotated_cw(void *, int, int, int);
    246 static void	rasops_erasecols_rotated_cw(void *, int, int, int, long);
    247 static void	rasops_eraserows_rotated_cw(void *, int, int, long);
    248 static void	rasops_putchar_rotated_cw(void *, int, int, u_int, long);
    249 
    250 /* rotate counter-clockwise */
    251 static void	rasops_copychar_ccw(void *, int, int, int, int);
    252 static void	rasops_copycols_rotated_ccw(void *, int, int, int, int);
    253 static void	rasops_copyrows_rotated_ccw(void *, int, int, int);
    254 #define rasops_erasecols_rotated_ccw rasops_erasecols_rotated_cw
    255 #define rasops_eraserows_rotated_ccw rasops_eraserows_rotated_cw
    256 static void	rasops_putchar_rotated_ccw(void *, int, int, u_int, long);
    257 
    258 /*
    259  * List of all rotated fonts
    260  */
    261 SLIST_HEAD(, rotatedfont) rotatedfonts = SLIST_HEAD_INITIALIZER(rotatedfonts);
    262 struct rotatedfont {
    263 	SLIST_ENTRY(rotatedfont) rf_next;
    264 	int rf_cookie;
    265 	int rf_rotated;
    266 };
    267 #endif	/* NRASOPS_ROTATION > 0 */
    268 
    269 /*
    270  * Initialize a 'rasops_info' descriptor.
    271  */
    272 int
    273 rasops_init(struct rasops_info *ri, int wantrows, int wantcols)
    274 {
    275 
    276 	memset(&ri->ri_optfont, 0, sizeof(ri->ri_optfont));
    277 #ifdef _KERNEL
    278 	/* Select a font if the caller doesn't care */
    279 	if (ri->ri_font == NULL) {
    280 		int cookie = -1;
    281 		int flags;
    282 
    283 		wsfont_init();
    284 
    285 		/*
    286 		 * first, try to find something that's as close as possible
    287 		 * to the caller's requested terminal size
    288 		 */
    289 		if (wantrows == 0)
    290 			wantrows = RASOPS_DEFAULT_HEIGHT;
    291 		if (wantcols == 0)
    292 			wantcols = RASOPS_DEFAULT_WIDTH;
    293 
    294 		flags = WSFONT_FIND_BESTWIDTH | WSFONT_FIND_BITMAP;
    295 		if ((ri->ri_flg & RI_ENABLE_ALPHA) != 0)
    296 			flags |= WSFONT_FIND_ALPHA;
    297 		if ((ri->ri_flg & RI_PREFER_ALPHA) != 0)
    298 			flags |= WSFONT_PREFER_ALPHA;
    299 		if ((ri->ri_flg & RI_PREFER_WIDEFONT) != 0)
    300 			flags |= WSFONT_PREFER_WIDE;
    301 		cookie = wsfont_find(NULL,
    302 			ri->ri_width / wantcols,
    303 			0,
    304 			0,
    305 			WSDISPLAY_FONTORDER_L2R,
    306 			WSDISPLAY_FONTORDER_L2R,
    307 			flags);
    308 
    309 		/*
    310 		 * this means there is no supported font in the list
    311 		 */
    312 		if (cookie <= 0) {
    313 			aprint_error("%s: font table is empty\n", __func__);
    314 			return -1;
    315 		}
    316 
    317 #if NRASOPS_ROTATION > 0
    318 		/*
    319 		 * Pick the rotated version of this font. This will create it
    320 		 * if necessary.
    321 		 */
    322 		if (ri->ri_flg & RI_ROTATE_MASK) {
    323 			if (ri->ri_flg & RI_ROTATE_CW)
    324 				rasops_rotate_font(&cookie, WSFONT_ROTATE_CW);
    325 			else if (ri->ri_flg & RI_ROTATE_CCW)
    326 				rasops_rotate_font(&cookie, WSFONT_ROTATE_CCW);
    327 		}
    328 #endif
    329 
    330 		if (wsfont_lock(cookie, &ri->ri_font)) {
    331 			aprint_error("%s: couldn't lock font\n", __func__);
    332 			return -1;
    333 		}
    334 
    335 		ri->ri_wsfcookie = cookie;
    336 	}
    337 #endif
    338 
    339 	/* This should never happen in reality... */
    340 	if ((uintptr_t)ri->ri_bits & 3) {
    341 		aprint_error("%s: bits not aligned on 32-bit boundary\n",
    342 		    __func__);
    343 		return -1;
    344 	}
    345 
    346 	if (ri->ri_stride & 3) {
    347 		aprint_error("%s: stride not aligned on 32-bit boundary\n",
    348 		    __func__);
    349 		return -1;
    350 	}
    351 
    352 	if (rasops_reconfig(ri, wantrows, wantcols))
    353 		return -1;
    354 
    355 	rasops_init_devcmap(ri);
    356 	return 0;
    357 }
    358 
    359 /*
    360  * Reconfigure (because parameters have changed in some way).
    361  */
    362 int
    363 rasops_reconfig(struct rasops_info *ri, int wantrows, int wantcols)
    364 {
    365 	int bpp, height, s;
    366 	size_t len;
    367 
    368 	s = splhigh();
    369 
    370 	if (wantrows == 0)
    371 		wantrows = RASOPS_DEFAULT_HEIGHT;
    372 	if (wantcols == 0)
    373 		wantcols = RASOPS_DEFAULT_WIDTH;
    374 
    375 	/* throw away old line drawing character bitmaps, if we have any */
    376 	if (ri->ri_optfont.data != NULL) {
    377 		kmem_free(ri->ri_optfont.data, ri->ri_optfont.stride *
    378 		    ri->ri_optfont.fontheight * ri->ri_optfont.numchars);
    379 		ri->ri_optfont.data = NULL;
    380 	}
    381 
    382 	/* autogenerate box drawing characters */
    383 	ri->ri_optfont.firstchar = WSFONT_FLAG_OPT;
    384 	ri->ri_optfont.numchars = 16;
    385 	ri->ri_optfont.fontwidth = ri->ri_font->fontwidth;
    386 	ri->ri_optfont.fontheight = ri->ri_font->fontheight;
    387 	ri->ri_optfont.stride = ri->ri_font->stride;
    388 	len = ri->ri_optfont.fontheight * ri->ri_optfont.stride *
    389 	    ri->ri_optfont.numchars;
    390 
    391 	if (ri->ri_font->fontwidth > 32 || ri->ri_font->fontwidth < 4) {
    392 		aprint_error("%s: fontwidth assumptions botched", __func__);
    393 		splx(s);
    394 		return -1;
    395 	}
    396 
    397 	if ((ri->ri_flg & RI_NO_AUTO) == 0) {
    398 		ri->ri_optfont.data = kmem_zalloc(len, KM_SLEEP);
    399 		if (FONT_IS_ALPHA(&ri->ri_optfont))
    400 			rasops_make_box_chars_alpha(ri);
    401 		else {
    402 			switch (ri->ri_optfont.stride) {
    403 			case 1:
    404 				rasops_make_box_chars_8(ri);
    405 				break;
    406 			case 2:
    407 				rasops_make_box_chars_16(ri);
    408 				break;
    409 			case 4:
    410 				rasops_make_box_chars_32(ri);
    411 				break;
    412 			default:
    413 				kmem_free(ri->ri_optfont.data, len);
    414 				ri->ri_optfont.data = NULL;
    415 				aprint_verbose(
    416 				    "%s: font stride assumptions botched",
    417 				    __func__);
    418 				break;
    419 			}
    420 		}
    421 	} else
    422 		memset(&ri->ri_optfont, 0, sizeof(ri->ri_optfont));
    423 
    424 	/* Need this to frob the setup below */
    425 	bpp = (ri->ri_depth == 15 ? 16 : ri->ri_depth);
    426 
    427 	if ((ri->ri_flg & RI_CFGDONE) != 0) {
    428 		ri->ri_bits = ri->ri_origbits;
    429 		ri->ri_hwbits = ri->ri_hworigbits;
    430 	}
    431 
    432 	/* Don't care if the caller wants a hideously small console */
    433 	if (wantrows < 10)
    434 		wantrows = 10;
    435 
    436 	if (wantcols < 20)
    437 		wantcols = 20;
    438 
    439 	/* Now constrain what they get */
    440 	ri->ri_emuwidth = ri->ri_font->fontwidth * wantcols;
    441 	ri->ri_emuheight = ri->ri_font->fontheight * wantrows;
    442 
    443 	if (ri->ri_emuwidth > ri->ri_width)
    444 		ri->ri_emuwidth = ri->ri_width;
    445 
    446 	if (ri->ri_emuheight > ri->ri_height)
    447 		ri->ri_emuheight = ri->ri_height;
    448 
    449 	/* Reduce width until aligned on a 32-bit boundary */
    450 	while ((ri->ri_emuwidth * bpp & 31) != 0)
    451 		ri->ri_emuwidth--;
    452 
    453 #if NRASOPS_ROTATION > 0
    454 	if (ri->ri_flg & (RI_ROTATE_CW|RI_ROTATE_CCW)) {
    455 		ri->ri_rows = ri->ri_emuwidth / ri->ri_font->fontwidth;
    456 		ri->ri_cols = ri->ri_emuheight / ri->ri_font->fontheight;
    457 	} else
    458 #endif
    459 	{
    460 		ri->ri_cols = ri->ri_emuwidth / ri->ri_font->fontwidth;
    461 		ri->ri_rows = ri->ri_emuheight / ri->ri_font->fontheight;
    462 	}
    463 	ri->ri_emustride = ri->ri_emuwidth * bpp >> 3;
    464 	ri->ri_ccol = 0;
    465 	ri->ri_crow = 0;
    466 	ri->ri_pelbytes = bpp >> 3;
    467 
    468 	ri->ri_xscale = (ri->ri_font->fontwidth * bpp) >> 3;
    469 	ri->ri_yscale = ri->ri_font->fontheight * ri->ri_stride;
    470 	ri->ri_fontscale = ri->ri_font->fontheight * ri->ri_font->stride;
    471 
    472 	ri->ri_origbits = ri->ri_bits;
    473 	ri->ri_hworigbits = ri->ri_hwbits;
    474 
    475 	/* Clear the entire display */
    476 	if ((ri->ri_flg & RI_CLEAR) != 0) {
    477 		rasops_memset32(ri->ri_bits, 0, ri->ri_stride * ri->ri_height);
    478 		if (ri->ri_hwbits)
    479 			rasops_memset32(ri->ri_hwbits, 0,
    480 			    ri->ri_stride * ri->ri_height);
    481 	}
    482 
    483 	/* Now centre our window if needs be */
    484 	if ((ri->ri_flg & RI_CENTER) != 0) {
    485 		uint32_t xoff, yoff;
    486 
    487 		xoff = ((ri->ri_width * bpp >> 3) - ri->ri_emustride) >> 1;
    488 		if (ri->ri_depth != 24) {
    489 			/*
    490 			 * Truncate to word boundary.
    491 			 */
    492 			xoff &= ~3;
    493 		} else {
    494 			/*
    495 			 * Truncate to both word and 24-bit color boundary.
    496 			 */
    497 			xoff -= xoff % 12;
    498 		}
    499 
    500 		yoff = ((ri->ri_height - ri->ri_emuheight) >> 1) *
    501 		    ri->ri_stride;
    502 
    503 		ri->ri_bits += xoff;
    504 		ri->ri_bits += yoff;
    505 		if (ri->ri_hwbits != NULL) {
    506 			ri->ri_hwbits += xoff;
    507 			ri->ri_hwbits += yoff;
    508 		}
    509 
    510 		ri->ri_yorigin = (int)(ri->ri_bits - ri->ri_origbits) /
    511 		    ri->ri_stride;
    512 		ri->ri_xorigin = (((int)(ri->ri_bits - ri->ri_origbits) %
    513 		    ri->ri_stride) * 8 / bpp);
    514 	} else
    515 		ri->ri_xorigin = ri->ri_yorigin = 0;
    516 
    517 	/* Scaling underline by font height */
    518 	height = ri->ri_font->fontheight;
    519 	ri->ri_ul.off = rounddown(height, 16) / 16;	/* offset from bottom */
    520 	ri->ri_ul.height = roundup(height, 16) / 16;	/* height */
    521 
    522 	/*
    523 	 * Fill in defaults for operations set.  XXX this nukes private
    524 	 * routines used by accelerated fb drivers.
    525 	 */
    526 	ri->ri_ops.mapchar = rasops_mapchar;
    527 	ri->ri_ops.copyrows = rasops_copyrows;
    528 	ri->ri_ops.copycols = rasops_copycols;
    529 	ri->ri_ops.erasecols = rasops_erasecols;
    530 	ri->ri_ops.eraserows = rasops_eraserows;
    531 	ri->ri_ops.cursor = rasops_cursor;
    532 	ri->ri_do_cursor = rasops_do_cursor;
    533 
    534 	ri->ri_caps &= ~(WSSCREEN_UNDERLINE | WSSCREEN_HILIT |
    535 		    WSSCREEN_WSCOLORS | WSSCREEN_REVERSE);
    536 
    537 	if ((ri->ri_flg & RI_FORCEMONO) != 0 ||
    538 #ifndef RASOPS_APPLE_PALETTE
    539 	    ri->ri_depth < 8
    540 #else
    541 	    ri->ri_depth < 4
    542 #endif
    543 	) {
    544 		ri->ri_ops.allocattr = rasops_allocattr_mono;
    545 		ri->ri_caps |= WSSCREEN_UNDERLINE | WSSCREEN_REVERSE;
    546 	} else {
    547 		ri->ri_ops.allocattr = rasops_allocattr_color;
    548 		ri->ri_caps |= WSSCREEN_UNDERLINE | WSSCREEN_HILIT |
    549 		    WSSCREEN_WSCOLORS | WSSCREEN_REVERSE;
    550 	}
    551 
    552 	switch (ri->ri_depth) {
    553 #if NRASOPS1 > 0
    554 	case 1:
    555 		rasops1_init(ri);
    556 		break;
    557 #endif
    558 #if NRASOPS2 > 0
    559 	case 2:
    560 		rasops2_init(ri);
    561 		break;
    562 #endif
    563 #if NRASOPS4 > 0
    564 	case 4:
    565 		rasops4_init(ri);
    566 		break;
    567 #endif
    568 #if NRASOPS8 > 0
    569 	case 8:
    570 		rasops8_init(ri);
    571 		break;
    572 #endif
    573 #if (NRASOPS15 + NRASOPS16) > 0
    574 	case 15:
    575 	case 16:
    576 		ri->ri_caps |= WSSCREEN_256COL;
    577 		rasops15_init(ri);
    578 		break;
    579 #endif
    580 #if NRASOPS24 > 0
    581 	case 24:
    582 		ri->ri_caps |= WSSCREEN_256COL;
    583 		rasops24_init(ri);
    584 		break;
    585 #endif
    586 #if NRASOPS32 > 0
    587 	case 32:
    588 		ri->ri_caps |= WSSCREEN_256COL;
    589 		rasops32_init(ri);
    590 		break;
    591 #endif
    592 	default:
    593 		ri->ri_flg &= ~RI_CFGDONE;
    594 		aprint_error("%s: depth not supported\n", __func__);
    595 		splx(s);
    596 		return -1;
    597 	}
    598 
    599 #if NRASOPS_ROTATION > 0
    600 	if (ri->ri_flg & RI_ROTATE_MASK) {
    601 		if (ri->ri_flg & RI_ROTATE_CW) {
    602 			ri->ri_real_ops = ri->ri_ops;
    603 			ri->ri_ops.copycols = rasops_copycols_rotated_cw;
    604 			ri->ri_ops.copyrows = rasops_copyrows_rotated_cw;
    605 			ri->ri_ops.erasecols = rasops_erasecols_rotated_cw;
    606 			ri->ri_ops.eraserows = rasops_eraserows_rotated_cw;
    607 			ri->ri_ops.putchar = rasops_putchar_rotated_cw;
    608 		} else if (ri->ri_flg & RI_ROTATE_CCW) {
    609 			ri->ri_real_ops = ri->ri_ops;
    610 			ri->ri_ops.copycols = rasops_copycols_rotated_ccw;
    611 			ri->ri_ops.copyrows = rasops_copyrows_rotated_ccw;
    612 			ri->ri_ops.erasecols = rasops_erasecols_rotated_ccw;
    613 			ri->ri_ops.eraserows = rasops_eraserows_rotated_ccw;
    614 			ri->ri_ops.putchar = rasops_putchar_rotated_ccw;
    615 		}
    616 	}
    617 #endif
    618 
    619 	ri->ri_flg |= RI_CFGDONE;
    620 	splx(s);
    621 	return 0;
    622 }
    623 
    624 /*
    625  * Map a character.
    626  */
    627 static int
    628 rasops_mapchar(void *cookie, int c, u_int *cp)
    629 {
    630 	struct rasops_info *ri = (struct rasops_info *)cookie;
    631 
    632 	KASSERT(ri->ri_font != NULL);
    633 
    634 	int glyph = wsfont_map_unichar(ri->ri_font, c);
    635 	if (glyph < 0 || !CHAR_IN_FONT(glyph, PICK_FONT(ri, glyph))) {
    636 		*cp = ' ';
    637 		return 0;
    638 	}
    639 
    640 	*cp = glyph;
    641 	return 5;
    642 }
    643 
    644 /*
    645  * Allocate a color attribute.
    646  */
    647 static int
    648 rasops_allocattr_color(void *cookie, int fg0, int bg0, int flg, long *attr)
    649 {
    650 	uint32_t fg = fg0, bg = bg0;
    651 
    652 	if (__predict_false(fg >= sizeof(rasops_isgray) ||
    653 	    bg >= sizeof(rasops_isgray)))
    654 		return EINVAL;
    655 
    656 #ifdef RASOPS_CLIPPING
    657 	fg &= 0xff;
    658 	bg &= 0xff;
    659 #endif
    660 
    661 	if ((flg & WSATTR_BLINK) != 0)
    662 		return EINVAL;
    663 
    664 	if ((flg & WSATTR_WSCOLORS) == 0) {
    665 #ifdef WS_DEFAULT_FG
    666 		fg = WS_DEFAULT_FG;
    667 #else
    668 		fg = WSCOL_WHITE;
    669 #endif
    670 #ifdef WS_DEFAULT_BG
    671 		bg = WS_DEFAULT_BG;
    672 #else
    673 		bg = WSCOL_BLACK;
    674 #endif
    675 	}
    676 
    677 	if ((flg & WSATTR_HILIT) != 0 && fg < 8)
    678 		fg += 8;
    679 
    680 	if ((flg & WSATTR_REVERSE) != 0) {
    681 		uint32_t swap = fg;
    682 		fg = bg;
    683 		bg = swap;
    684 	}
    685 
    686 	flg &= WSATTR_USERMASK;
    687 
    688 	if (rasops_isgray[fg])
    689 		flg |= WSATTR_PRIVATE1;
    690 
    691 	if (rasops_isgray[bg])
    692 		flg |= WSATTR_PRIVATE2;
    693 
    694 	*attr = (bg << 16) | (fg << 24) | flg;
    695 	return 0;
    696 }
    697 
    698 /*
    699  * Allocate a mono attribute.
    700  */
    701 static int
    702 rasops_allocattr_mono(void *cookie, int fg0, int bg0, int flg, long *attr)
    703 {
    704 	uint32_t fg = fg0, bg = bg0;
    705 
    706 	if ((flg & (WSATTR_BLINK | WSATTR_HILIT | WSATTR_WSCOLORS)) != 0)
    707 		return EINVAL;
    708 
    709 	fg = 0xff;
    710 	bg = 0;
    711 
    712 	if ((flg & WSATTR_REVERSE) != 0) {
    713 		uint32_t swap = fg;
    714 		fg = bg;
    715 		bg = swap;
    716 	}
    717 
    718 	*attr = (bg << 16) | (fg << 24) | flg;
    719 	return 0;
    720 }
    721 
    722 /*
    723  * Copy rows.
    724  */
    725 static void
    726 rasops_copyrows(void *cookie, int src, int dst, int num)
    727 {
    728 	struct rasops_info *ri = (struct rasops_info *)cookie;
    729 	int stride;
    730 	uint8_t *sp, *dp, *hp;
    731 
    732 	hp = NULL;	/* XXX GCC */
    733 
    734 	if (__predict_false(dst == src))
    735 		return;
    736 
    737 #ifdef RASOPS_CLIPPING
    738 	if (src < 0) {
    739 		num += src;
    740 		src = 0;
    741 	}
    742 
    743 	if (src + num > ri->ri_rows)
    744 		num = ri->ri_rows - src;
    745 
    746 	if (dst < 0) {
    747 		num += dst;
    748 		dst = 0;
    749 	}
    750 
    751 	if (dst + num > ri->ri_rows)
    752 		num = ri->ri_rows - dst;
    753 
    754 	if (num <= 0)
    755 		return;
    756 #endif
    757 
    758 	src *= ri->ri_yscale;
    759 	dst *= ri->ri_yscale;
    760 	num *= ri->ri_font->fontheight;
    761 	stride = ri->ri_stride;
    762 
    763 	if (src < dst) {
    764 		/* backward copy */
    765 		src += (num - 1) * stride;
    766 		dst += (num - 1) * stride;
    767 		stride *= -1;
    768 	}
    769 
    770 	sp = ri->ri_bits + src;
    771 	dp = ri->ri_bits + dst;
    772 	if (ri->ri_hwbits)
    773 		hp = ri->ri_hwbits + dst;
    774 
    775 	while (num--) {
    776 		memcpy(dp, sp, ri->ri_emustride);
    777 		if (ri->ri_hwbits) {
    778 			memcpy(hp, dp, ri->ri_emustride);
    779 			hp += stride;
    780 		}
    781 		sp += stride;
    782 		dp += stride;
    783 	}
    784 }
    785 
    786 /*
    787  * Copy columns. This is slow, and hard to optimize due to alignment,
    788  * and the fact that we have to copy both left->right and right->left.
    789  * We simply cop-out here and use memmove(), since it handles all of
    790  * these cases anyway.
    791  */
    792 static void
    793 rasops_copycols(void *cookie, int row, int src, int dst, int num)
    794 {
    795 	struct rasops_info *ri = (struct rasops_info *)cookie;
    796 	int height;
    797 	uint8_t *sp, *dp, *hp;
    798 
    799 	hp = NULL;	/* XXX GCC */
    800 
    801 	if (__predict_false(dst == src))
    802 		return;
    803 
    804 #ifdef RASOPS_CLIPPING
    805 	/* Catches < 0 case too */
    806 	if ((unsigned)row >= (unsigned)ri->ri_rows)
    807 		return;
    808 
    809 	if (src < 0) {
    810 		num += src;
    811 		src = 0;
    812 	}
    813 
    814 	if (src + num > ri->ri_cols)
    815 		num = ri->ri_cols - src;
    816 
    817 	if (dst < 0) {
    818 		num += dst;
    819 		dst = 0;
    820 	}
    821 
    822 	if (dst + num > ri->ri_cols)
    823 		num = ri->ri_cols - dst;
    824 
    825 	if (num <= 0)
    826 		return;
    827 #endif
    828 
    829 	height = ri->ri_font->fontheight;
    830 	row *= ri->ri_yscale;
    831 	num *= ri->ri_xscale;
    832 
    833 	sp = ri->ri_bits + row + src * ri->ri_xscale;
    834 	dp = ri->ri_bits + row + dst * ri->ri_xscale;
    835 	if (ri->ri_hwbits)
    836 		hp = ri->ri_hwbits + row + dst * ri->ri_xscale;
    837 
    838 	while (height--) {
    839 		memmove(dp, sp, num);
    840 		if (ri->ri_hwbits) {
    841 			memcpy(hp, dp, num);
    842 			hp += ri->ri_stride;
    843 		}
    844 		sp += ri->ri_stride;
    845 		dp += ri->ri_stride;
    846 	}
    847 }
    848 
    849 /*
    850  * Turn cursor off/on.
    851  */
    852 static void
    853 rasops_cursor(void *cookie, int on, int row, int col)
    854 {
    855 	struct rasops_info *ri = (struct rasops_info *)cookie;
    856 
    857 	/* Turn old cursor off */
    858 	if ((ri->ri_flg & RI_CURSOR) != 0)
    859 #ifdef RASOPS_CLIPPING
    860 		if ((ri->ri_flg & RI_CURSORCLIP) == 0)
    861 #endif
    862 			ri->ri_do_cursor(ri);
    863 
    864 	/* Select new cursor */
    865 	ri->ri_crow = row;
    866 	ri->ri_ccol = col;
    867 
    868 #ifdef RASOPS_CLIPPING
    869 	ri->ri_flg &= ~RI_CURSORCLIP;
    870 	if (row < 0 || row >= ri->ri_rows)
    871 		ri->ri_flg |= RI_CURSORCLIP;
    872 	else if (col < 0 || col >= ri->ri_cols)
    873 		ri->ri_flg |= RI_CURSORCLIP;
    874 #endif
    875 
    876 	if (on) {
    877 		ri->ri_flg |= RI_CURSOR;
    878 #ifdef RASOPS_CLIPPING
    879 		if ((ri->ri_flg & RI_CURSORCLIP) == 0)
    880 #endif
    881 			ri->ri_do_cursor(ri);
    882 	} else
    883 		ri->ri_flg &= ~RI_CURSOR;
    884 }
    885 
    886 /*
    887  * Make the device colormap
    888  */
    889 static void
    890 rasops_init_devcmap(struct rasops_info *ri)
    891 {
    892 	int i;
    893 	uint32_t c;
    894 	const uint8_t *p;
    895 
    896 	switch (ri->ri_depth) {
    897 	case 1:
    898 		ri->ri_devcmap[0] = 0;
    899 		for (i = 1; i < 16; i++)
    900 			ri->ri_devcmap[i] = -1;
    901 		return;
    902 
    903 	case 2:
    904 		for (i = 1; i < 15; i++)
    905 			ri->ri_devcmap[i] = 0xaaaaaaaa;
    906 
    907 		ri->ri_devcmap[0] = 0;
    908 		ri->ri_devcmap[8] = 0x55555555;
    909 		ri->ri_devcmap[15] = -1;
    910 		return;
    911 
    912 	case 4:
    913 		for (i = 0; i < 16; i++) {
    914 #ifdef RASOPS_APPLE_PALETTE
    915 			c = apple4_devcmap[i];
    916 #else
    917 			c = i;
    918 #endif
    919 			ri->ri_devcmap[i] =
    920 			    (c <<  0) | (c <<  4) | (c <<  8) | (c << 12) |
    921 			    (c << 16) | (c << 20) | (c << 24) | (c << 28);
    922 		}
    923 		return;
    924 
    925 	case 8:
    926 		if ((ri->ri_flg & RI_8BIT_IS_RGB) == 0) {
    927 			for (i = 0; i < 16; i++) {
    928 #ifdef RASOPS_APPLE_PALETTE
    929 				c = apple8_devcmap[i];
    930 #else
    931 				c = i;
    932 #endif
    933 				ri->ri_devcmap[i] =
    934 				    c | (c << 8) | (c << 16) | (c << 24);
    935 			}
    936 			return;
    937 		}
    938 	}
    939 
    940 	p = rasops_cmap;
    941 
    942 	for (i = 0; i < ((ri->ri_caps & WSSCREEN_256COL) ? 256 : 16); i++) {
    943 		if (ri->ri_rnum <= 8)
    944 			c = (uint32_t)(*p >> (8 - ri->ri_rnum)) << ri->ri_rpos;
    945 		else
    946 			c = (uint32_t)(*p << (ri->ri_rnum - 8)) << ri->ri_rpos;
    947 		p++;
    948 
    949 		if (ri->ri_gnum <= 8)
    950 			c |= (uint32_t)(*p >> (8 - ri->ri_gnum)) << ri->ri_gpos;
    951 		else
    952 			c |= (uint32_t)(*p << (ri->ri_gnum - 8)) << ri->ri_gpos;
    953 		p++;
    954 
    955 		if (ri->ri_bnum <= 8)
    956 			c |= (uint32_t)(*p >> (8 - ri->ri_bnum)) << ri->ri_bpos;
    957 		else
    958 			c |= (uint32_t)(*p << (ri->ri_bnum - 8)) << ri->ri_bpos;
    959 		p++;
    960 
    961 #define EP_BLUE_RAW(x) (48 * ((x - 16) % 6))
    962 #define EP_GREEN_RAW(x) (48 * (((x - 16)/6) % 6))
    963 #define EP_RED_RAW(x) (48 * (((x - 16)/36) % 6))
    964 #define EP_BLUE(x) ((EP_BLUE_RAW(x) >> (8 - ri->ri_bnum)) << ri->ri_bpos)
    965 #define EP_GREEN(x) ((EP_GREEN_RAW(x) >> (8 - ri->ri_gnum)) << ri->ri_gpos)
    966 #define EP_RED(x) ((EP_RED_RAW(x) >> (8 - ri->ri_rnum)) << ri->ri_rpos)
    967 #define EP_COL(x) EP_RED(x) | EP_GREEN(x) | EP_BLUE(x)
    968 #define EP_GREY_BYTE(x) (1 + ((x - 232) * 11))
    969 #define GREYSCALE_BLUE(x) ((EP_GREY_BYTE(x) >> (8 - ri->ri_bnum)) << ri->ri_bpos)
    970 #define GREYSCALE_GREEN(x) ((EP_GREY_BYTE(x) >> (8 - ri->ri_gnum)) << ri->ri_gpos)
    971 #define GREYSCALE_RED(x) ((EP_GREY_BYTE(x) >> (8 - ri->ri_rnum)) << ri->ri_rpos)
    972 #define EP_GREY(x) GREYSCALE_RED(x) | GREYSCALE_GREEN(x) | GREYSCALE_BLUE(x)
    973 		if (i >= 16) {
    974 			rasops_ecmap[i * 3] =
    975 			    (i < 232 ? EP_RED_RAW(i) : EP_GREY_BYTE(i));
    976 			rasops_ecmap[i * 3 + 1] =
    977 			    (i < 232 ? EP_GREEN_RAW(i) : EP_GREY_BYTE(i));
    978 			rasops_ecmap[i * 3 + 2] =
    979 			    (i < 232 ? EP_BLUE_RAW(i) : EP_GREY_BYTE(i));
    980 			c = (i < 232 ? EP_COL(i) : EP_GREY(i));
    981 		} else {
    982 			rasops_ecmap[i * 3] = rasops_cmap[i * 3];
    983 			rasops_ecmap[i * 3 + 1] = rasops_cmap[i * 3 + 1];
    984 			rasops_ecmap[i * 3 + 2] = rasops_cmap[i * 3 + 2];
    985 		}
    986 
    987 		/*
    988 		 * Swap byte order if necessary. Then, fill the word for
    989 		 * generic routines, which want this.
    990 		 */
    991 		switch (ri->ri_depth) {
    992 		case 8:
    993 			c |= c << 8;
    994 			c |= c << 16;
    995 			break;
    996 		case 15:
    997 		case 16:
    998 			if ((ri->ri_flg & RI_BSWAP) != 0)
    999 				c = bswap16(c);
   1000 			c |= c << 16;
   1001 			break;
   1002 		case 24:
   1003 #if BYTE_ORDER == LITTLE_ENDIAN
   1004 			if ((ri->ri_flg & RI_BSWAP) == 0)
   1005 #else
   1006 			if ((ri->ri_flg & RI_BSWAP) != 0)
   1007 #endif
   1008 			{
   1009 				/*
   1010 				 * Convert to ``big endian'' if not RI_BSWAP.
   1011 				 */
   1012 				c = (c & 0x0000ff) << 16|
   1013 				    (c & 0x00ff00) |
   1014 				    (c & 0xff0000) >> 16;
   1015 			}
   1016 			/*
   1017 			 * No worries, we use generic routines only for
   1018 			 * gray colors, where all 3 bytes are same.
   1019 			 */
   1020 			c |= (c & 0xff) << 24;
   1021 			break;
   1022 		case 32:
   1023 			if ((ri->ri_flg & RI_BSWAP) != 0)
   1024 				c = bswap32(c);
   1025 			break;
   1026 		}
   1027 
   1028 		ri->ri_devcmap[i] = c;
   1029 	}
   1030 }
   1031 
   1032 /*
   1033  * Unpack a rasops attribute
   1034  */
   1035 void
   1036 rasops_unpack_attr(long attr, int *fg, int *bg, int *underline)
   1037 {
   1038 
   1039 	*fg = ((uint32_t)attr >> 24) & 0xff;
   1040 	*bg = ((uint32_t)attr >> 16) & 0xff;
   1041 	if (underline != NULL)
   1042 		*underline = (uint32_t)attr & WSATTR_UNDERLINE;
   1043 }
   1044 
   1045 /*
   1046  * Erase rows. This isn't static, since 24-bpp uses it in special cases.
   1047  */
   1048 void
   1049 rasops_eraserows(void *cookie, int row, int num, long attr)
   1050 {
   1051 	struct rasops_info *ri = (struct rasops_info *)cookie;
   1052 	int bytes;
   1053 	uint32_t bg, *rp, *hp;
   1054 
   1055 	hp = NULL;	/* XXX GCC */
   1056 
   1057 #ifdef RASOPS_CLIPPING
   1058 	if (row < 0) {
   1059 		num += row;
   1060 		row = 0;
   1061 	}
   1062 
   1063 	if (row + num > ri->ri_rows)
   1064 		num = ri->ri_rows - row;
   1065 
   1066 	if (num <= 0)
   1067 		return;
   1068 #endif
   1069 
   1070 	/*
   1071 	 * XXX The wsdisplay_emulops interface seems a little deficient in
   1072 	 * that there is no way to clear the *entire* screen. We provide a
   1073 	 * workaround here: if the entire console area is being cleared, and
   1074 	 * the RI_FULLCLEAR flag is set, clear the entire display.
   1075 	 */
   1076 	if (num == ri->ri_rows && (ri->ri_flg & RI_FULLCLEAR) != 0) {
   1077 		bytes = ri->ri_stride;
   1078 		num = ri->ri_height;
   1079 		rp = (uint32_t *)ri->ri_origbits;
   1080 		if (ri->ri_hwbits)
   1081 			hp = (uint32_t *)ri->ri_hworigbits;
   1082 	} else {
   1083 		bytes = ri->ri_emustride;
   1084 		num *= ri->ri_font->fontheight;
   1085 		rp = (uint32_t *)(ri->ri_bits + row * ri->ri_yscale);
   1086 		if (ri->ri_hwbits)
   1087 			hp = (uint32_t *)(ri->ri_hwbits + row * ri->ri_yscale);
   1088 	}
   1089 
   1090 	bg = ATTR_BG(ri, attr);
   1091 
   1092 	while (num--) {
   1093 		rasops_memset32(rp, bg, bytes);
   1094 		if (ri->ri_hwbits) {
   1095 			memcpy(hp, rp, bytes);
   1096 			DELTA(hp, ri->ri_stride, uint32_t *);
   1097 		}
   1098 		DELTA(rp, ri->ri_stride, uint32_t *);
   1099 	}
   1100 }
   1101 
   1102 /*
   1103  * Actually turn the cursor on or off. This does the dirty work for
   1104  * rasops_cursor().
   1105  */
   1106 static void
   1107 rasops_do_cursor(struct rasops_info *ri)
   1108 {
   1109 	int row, col, height, slop1, slop2, full, cnt;
   1110 	uint32_t mask1, mask2, *dp;
   1111 	uint8_t tmp, *rp, *hp;
   1112 
   1113 	hp = NULL;	/* XXX GCC */
   1114 
   1115 #if NRASOPS_ROTATION > 0
   1116 	if (ri->ri_flg & RI_ROTATE_MASK) {
   1117 		if (ri->ri_flg & RI_ROTATE_CW) {
   1118 			/* Rotate rows/columns */
   1119 			row = ri->ri_ccol;
   1120 			col = ri->ri_rows - ri->ri_crow - 1;
   1121 		} else if (ri->ri_flg & RI_ROTATE_CCW) {
   1122 			/* Rotate rows/columns */
   1123 			row = ri->ri_cols - ri->ri_ccol - 1;
   1124 			col = ri->ri_crow;
   1125 		} else {	/* upside-down */
   1126 			row = ri->ri_crow;
   1127 			col = ri->ri_ccol;
   1128 		}
   1129 	} else
   1130 #endif
   1131 	{
   1132 		row = ri->ri_crow;
   1133 		col = ri->ri_ccol;
   1134 	}
   1135 
   1136 	height = ri->ri_font->fontheight;
   1137 
   1138 	rp = ri->ri_bits + FBOFFSET(ri, row, col);
   1139 	if (ri->ri_hwbits)
   1140 		hp = ri->ri_hwbits + FBOFFSET(ri, row, col);
   1141 
   1142 	/*
   1143 	 * For ri_xscale = 1:
   1144 	 *
   1145 	 * Logic below does not work for ri_xscale = 1, e.g.,
   1146 	 * fontwidth = 8 and bpp = 1. So we take care of it.
   1147 	 */
   1148 	if (ri->ri_xscale == 1) {
   1149 		while (height--) {
   1150 			tmp = ~*rp;
   1151 			*rp = tmp;
   1152 			if (ri->ri_hwbits) {
   1153 				*hp = tmp;
   1154 				hp += ri->ri_stride;
   1155 			}
   1156 			rp += ri->ri_stride;
   1157 		}
   1158 		return;
   1159 	}
   1160 
   1161 	/*
   1162 	 * For ri_xscale = 2, 3, 4, ...:
   1163 	 *
   1164 	 * Note that siop1 <= ri_xscale even for ri_xscale = 2,
   1165 	 * since rp % 3 = 0 or 2 (ri_stride % 4 = 0).
   1166 	 */
   1167 	slop1 = (4 - ((uintptr_t)rp & 3)) & 3;
   1168 	slop2 = (ri->ri_xscale - slop1) & 3;
   1169 	full = (ri->ri_xscale - slop1 /* - slop2 */) >> 2;
   1170 
   1171 	rp = (uint8_t *)((uintptr_t)rp & ~3);
   1172 	hp = (uint8_t *)((uintptr_t)hp & ~3);
   1173 
   1174 	mask1 = rasops_lmask32[4 - slop1];
   1175 	mask2 = rasops_rmask32[slop2];
   1176 
   1177 	while (height--) {
   1178 		dp = (uint32_t *)rp;
   1179 
   1180 		if (slop1) {
   1181 			*dp = *dp ^ mask1;
   1182 			dp++;
   1183 		}
   1184 
   1185 		for (cnt = full; cnt; cnt--) {
   1186 			*dp = ~*dp;
   1187 			dp++;
   1188 		}
   1189 
   1190 		if (slop2)
   1191 			*dp = *dp ^ mask2;
   1192 
   1193 		if (ri->ri_hwbits) {
   1194 			memcpy(hp, rp, ((slop1 != 0) + full +
   1195 			    (slop2 != 0)) << 2);
   1196 			hp += ri->ri_stride;
   1197 		}
   1198 		rp += ri->ri_stride;
   1199 	}
   1200 }
   1201 
   1202 /*
   1203  * Erase columns.
   1204  */
   1205 void
   1206 rasops_erasecols(void *cookie, int row, int col, int num, long attr)
   1207 {
   1208 	struct rasops_info *ri = (struct rasops_info *)cookie;
   1209 	int height;
   1210 	uint32_t bg, *rp, *hp;
   1211 
   1212 	hp = NULL;	/* XXX GCC */
   1213 
   1214 #ifdef RASOPS_CLIPPING
   1215 	if ((unsigned)row >= (unsigned)ri->ri_rows)
   1216 		return;
   1217 
   1218 	if (col < 0) {
   1219 		num += col;
   1220 		col = 0;
   1221 	}
   1222 
   1223 	if (col + num > ri->ri_cols)
   1224 		num = ri->ri_cols - col;
   1225 
   1226 	if (num <= 0)
   1227 		return;
   1228 #endif
   1229 
   1230 	height = ri->ri_font->fontheight;
   1231 	num *= ri->ri_xscale;
   1232 
   1233 	rp = (uint32_t *)(ri->ri_bits + FBOFFSET(ri, row, col));
   1234 	if (ri->ri_hwbits)
   1235 		hp = (uint32_t *)(ri->ri_hwbits + FBOFFSET(ri, row, col));
   1236 
   1237 	bg = ATTR_BG(ri, attr);
   1238 
   1239 	while (height--) {
   1240 		rasops_memset32(rp, bg, num);
   1241 		if (ri->ri_hwbits) {
   1242 			memcpy(hp, rp, num);
   1243 			DELTA(hp, ri->ri_stride, uint32_t *);
   1244 		}
   1245 		DELTA(rp, ri->ri_stride, uint32_t *);
   1246 	}
   1247 }
   1248 
   1249 void
   1250 rasops_make_box_chars_16(struct rasops_info *ri)
   1251 {
   1252 	int c, i, mid;
   1253 	uint16_t vert_mask, hmask_left, hmask_right;
   1254 	uint16_t *data = (uint16_t *)ri->ri_optfont.data;
   1255 
   1256 	vert_mask = 0xc000U >> ((ri->ri_font->fontwidth >> 1) - 1);
   1257 	hmask_left = 0xff00U << (8 - (ri->ri_font->fontwidth >> 1));
   1258 	hmask_right = hmask_left >> ((ri->ri_font->fontwidth + 1) >> 1);
   1259 
   1260 	vert_mask = htobe16(vert_mask);
   1261 	hmask_left = htobe16(hmask_left);
   1262 	hmask_right = htobe16(hmask_right);
   1263 
   1264 	mid = (ri->ri_font->fontheight + 1) >> 1;
   1265 
   1266 	/* 0x00 would be empty anyway so don't bother */
   1267 	for (c = 1; c < 16; c++) {
   1268 		data += ri->ri_font->fontheight;
   1269 		if (c & 1) {
   1270 			/* upper segment */
   1271 			for (i = 0; i < mid; i++)
   1272 				data[i] = vert_mask;
   1273 		}
   1274 		if (c & 4) {
   1275 			/* lower segment */
   1276 			for (i = mid; i < ri->ri_font->fontheight; i++)
   1277 				data[i] = vert_mask;
   1278 		}
   1279 		if (c & 2) {
   1280 			/* right segment */
   1281 			i = ri->ri_font->fontheight >> 1;
   1282 			data[mid - 1] |= hmask_right;
   1283 			data[mid] |= hmask_right;
   1284 		}
   1285 		if (c & 8) {
   1286 			/* left segment */
   1287 			data[mid - 1] |= hmask_left;
   1288 			data[mid] |= hmask_left;
   1289 		}
   1290 	}
   1291 }
   1292 
   1293 void
   1294 rasops_make_box_chars_8(struct rasops_info *ri)
   1295 {
   1296 	int c, i, mid;
   1297 	uint8_t vert_mask, hmask_left, hmask_right;
   1298 	uint8_t *data = (uint8_t *)ri->ri_optfont.data;
   1299 
   1300 	vert_mask = 0xc0U >> ((ri->ri_font->fontwidth >> 1) - 1);
   1301 	hmask_left = 0xf0U << (4 - (ri->ri_font->fontwidth >> 1));
   1302 	hmask_right = hmask_left >> ((ri->ri_font->fontwidth + 1) >> 1);
   1303 
   1304 	mid = (ri->ri_font->fontheight + 1) >> 1;
   1305 
   1306 	/* 0x00 would be empty anyway so don't bother */
   1307 	for (c = 1; c < 16; c++) {
   1308 		data += ri->ri_font->fontheight;
   1309 		if (c & 1) {
   1310 			/* upper segment */
   1311 			for (i = 0; i < mid; i++)
   1312 				data[i] = vert_mask;
   1313 		}
   1314 		if (c & 4) {
   1315 			/* lower segment */
   1316 			for (i = mid; i < ri->ri_font->fontheight; i++)
   1317 				data[i] = vert_mask;
   1318 		}
   1319 		if (c & 2) {
   1320 			/* right segment */
   1321 			i = ri->ri_font->fontheight >> 1;
   1322 			data[mid - 1] |= hmask_right;
   1323 			data[mid] |= hmask_right;
   1324 		}
   1325 		if (c & 8) {
   1326 			/* left segment */
   1327 			data[mid - 1] |= hmask_left;
   1328 			data[mid] |= hmask_left;
   1329 		}
   1330 	}
   1331 }
   1332 
   1333 void
   1334 rasops_make_box_chars_32(struct rasops_info *ri)
   1335 {
   1336 	int c, i, mid;
   1337 	uint32_t vert_mask, hmask_left, hmask_right;
   1338 	uint32_t *data = (uint32_t *)ri->ri_optfont.data;
   1339 
   1340 	vert_mask = 0xc0000000U >> ((ri->ri_font->fontwidth >> 1) - 1);
   1341 	hmask_left = 0xffff0000U << (16 - (ri->ri_font->fontwidth >> 1));
   1342 	hmask_right = hmask_left >> ((ri->ri_font->fontwidth + 1) >> 1);
   1343 
   1344 	vert_mask = htobe32(vert_mask);
   1345 	hmask_left = htobe32(hmask_left);
   1346 	hmask_right = htobe32(hmask_right);
   1347 
   1348 	mid = (ri->ri_font->fontheight + 1) >> 1;
   1349 
   1350 	/* 0x00 would be empty anyway so don't bother */
   1351 	for (c = 1; c < 16; c++) {
   1352 		data += ri->ri_font->fontheight;
   1353 		if (c & 1) {
   1354 			/* upper segment */
   1355 			for (i = 0; i < mid; i++)
   1356 				data[i] = vert_mask;
   1357 		}
   1358 		if (c & 4) {
   1359 			/* lower segment */
   1360 			for (i = mid; i < ri->ri_font->fontheight; i++)
   1361 				data[i] = vert_mask;
   1362 		}
   1363 		if (c & 2) {
   1364 			/* right segment */
   1365 			i = ri->ri_font->fontheight >> 1;
   1366 			data[mid - 1] |= hmask_right;
   1367 			data[mid] |= hmask_right;
   1368 		}
   1369 		if (c & 8) {
   1370 			/* left segment */
   1371 			data[mid - 1] |= hmask_left;
   1372 			data[mid] |= hmask_left;
   1373 		}
   1374 	}
   1375 }
   1376 
   1377 void
   1378 rasops_make_box_chars_alpha(struct rasops_info *ri)
   1379 {
   1380 	int c, i, hmid, vmid, wi, he;
   1381 	uint8_t *data = (uint8_t *)ri->ri_optfont.data;
   1382 	uint8_t *ddata;
   1383 
   1384 	he = ri->ri_font->fontheight;
   1385 	wi = ri->ri_font->fontwidth;
   1386 
   1387 	vmid = (he + 1) >> 1;
   1388 	hmid = (wi + 1) >> 1;
   1389 
   1390 	/* 0x00 would be empty anyway so don't bother */
   1391 	for (c = 1; c < 16; c++) {
   1392 		data += ri->ri_fontscale;
   1393 		if (c & 1) {
   1394 			/* upper segment */
   1395 			ddata = data + hmid;
   1396 			for (i = 0; i <= vmid; i++) {
   1397 				*ddata = 0xff;
   1398 				ddata += wi;
   1399 			}
   1400 		}
   1401 		if (c & 4) {
   1402 			/* lower segment */
   1403 			ddata = data + wi * vmid + hmid;
   1404 			for (i = vmid; i < he; i++) {
   1405 				*ddata = 0xff;
   1406 				ddata += wi;
   1407 			}
   1408 		}
   1409 		if (c & 2) {
   1410 			/* right segment */
   1411 			ddata = data + wi * vmid + hmid;
   1412 			for (i = hmid; i < wi; i++) {
   1413 				*ddata = 0xff;
   1414 				ddata++;
   1415 			}
   1416 		}
   1417 		if (c & 8) {
   1418 			/* left segment */
   1419 			ddata = data + wi * vmid;
   1420 			for (i = 0; i <= hmid; i++) {
   1421 				*ddata = 0xff;
   1422 				ddata++;
   1423 			}
   1424 		}
   1425 	}
   1426 }
   1427 
   1428 /*
   1429  * Return a colour map appropriate for the given struct rasops_info in the
   1430  * same form used by rasops_cmap[]
   1431  * For now this is either a copy of rasops_cmap[] or an R3G3B2 map, it should
   1432  * probably be a linear ( or gamma corrected? ) ramp for higher depths.
   1433  */
   1434 int
   1435 rasops_get_cmap(struct rasops_info *ri, uint8_t *palette, size_t bytes)
   1436 {
   1437 
   1438 	if ((ri->ri_depth == 8) && ((ri->ri_flg & RI_8BIT_IS_RGB) != 0)) {
   1439 		/* generate an R3G3B2 palette */
   1440 		int i, idx = 0;
   1441 		uint8_t tmp;
   1442 
   1443 		if (bytes < 256 * 3)
   1444 			return EINVAL;
   1445 		for (i = 0; i < 256; i++) {
   1446 			tmp = i & 0xe0;
   1447 			/*
   1448 			 * replicate bits so 0xe0 maps to a red value of 0xff
   1449 			 * in order to make white look actually white
   1450 			 */
   1451 			tmp |= (tmp >> 3) | (tmp >> 6);
   1452 			palette[idx] = tmp;
   1453 			idx++;
   1454 
   1455 			tmp = (i & 0x1c) << 3;
   1456 			tmp |= (tmp >> 3) | (tmp >> 6);
   1457 			palette[idx] = tmp;
   1458 			idx++;
   1459 
   1460 			tmp = (i & 0x03) << 6;
   1461 			tmp |= tmp >> 2;
   1462 			tmp |= tmp >> 4;
   1463 			palette[idx] = tmp;
   1464 			idx++;
   1465 		}
   1466 	} else
   1467 		memcpy(palette, rasops_cmap, uimin(bytes, sizeof(rasops_cmap)));
   1468 
   1469 	return 0;
   1470 }
   1471 
   1472 #if NRASOPS_ROTATION > 0
   1473 /*
   1474  * Quarter clockwise rotation routines (originally intended for the
   1475  * built-in Zaurus C3x00 display in 16bpp).
   1476  */
   1477 
   1478 static void
   1479 rasops_rotate_font(int *cookie, int rotate)
   1480 {
   1481 	struct rotatedfont *f;
   1482 	int ncookie;
   1483 
   1484 	SLIST_FOREACH(f, &rotatedfonts, rf_next) {
   1485 		if (f->rf_cookie == *cookie) {
   1486 			*cookie = f->rf_rotated;
   1487 			return;
   1488 		}
   1489 	}
   1490 
   1491 	/*
   1492 	 * We did not find a rotated version of this font. Ask the wsfont
   1493 	 * code to compute one for us.
   1494 	 */
   1495 
   1496 	f = kmem_alloc(sizeof(*f), KM_SLEEP);
   1497 
   1498 	if ((ncookie = wsfont_rotate(*cookie, rotate)) == -1)
   1499 		goto fail;
   1500 
   1501 	f->rf_cookie = *cookie;
   1502 	f->rf_rotated = ncookie;
   1503 	SLIST_INSERT_HEAD(&rotatedfonts, f, rf_next);
   1504 
   1505 	*cookie = ncookie;
   1506 	return;
   1507 
   1508 fail:	kmem_free(f, sizeof(*f));
   1509 	return;
   1510 }
   1511 
   1512 static void
   1513 rasops_copychar(void *cookie, int srcrow, int dstrow, int srccol, int dstcol)
   1514 {
   1515 	struct rasops_info *ri = (struct rasops_info *)cookie;
   1516 	int r_srcrow, r_dstrow, r_srccol, r_dstcol, height;
   1517 	uint8_t *sp, *dp;
   1518 
   1519 	r_srcrow = srccol;
   1520 	r_dstrow = dstcol;
   1521 	r_srccol = ri->ri_rows - srcrow - 1;
   1522 	r_dstcol = ri->ri_rows - dstrow - 1;
   1523 
   1524 	r_srcrow *= ri->ri_yscale;
   1525 	r_dstrow *= ri->ri_yscale;
   1526 	height = ri->ri_font->fontheight;
   1527 
   1528 	sp = ri->ri_bits + r_srcrow + r_srccol * ri->ri_xscale;
   1529 	dp = ri->ri_bits + r_dstrow + r_dstcol * ri->ri_xscale;
   1530 
   1531 	while (height--) {
   1532 		memmove(dp, sp, ri->ri_xscale);
   1533 		dp += ri->ri_stride;
   1534 		sp += ri->ri_stride;
   1535 	}
   1536 }
   1537 
   1538 static void
   1539 rasops_putchar_rotated_cw(void *cookie, int row, int col, u_int uc, long attr)
   1540 {
   1541 	struct rasops_info *ri = (struct rasops_info *)cookie;
   1542 	int height;
   1543 	uint16_t fg, *rp;
   1544 
   1545 	if (__predict_false((unsigned int)row > ri->ri_rows ||
   1546 	    (unsigned int)col > ri->ri_cols))
   1547 		return;
   1548 
   1549 	/* Avoid underflow */
   1550 	if (ri->ri_rows - row - 1 < 0)
   1551 		return;
   1552 
   1553 	/* Do rotated char sans (side)underline */
   1554 	ri->ri_real_ops.putchar(cookie, col, ri->ri_rows - row - 1, uc,
   1555 	    attr & ~WSATTR_UNDERLINE);
   1556 
   1557 	/*
   1558 	 * Do rotated underline
   1559 	 * XXX this assumes 16-bit color depth
   1560 	 */
   1561 	if ((attr & WSATTR_UNDERLINE) != 0) {
   1562 		height = ri->ri_font->fontheight;
   1563 
   1564 		rp = (uint16_t *)(ri->ri_bits + col * ri->ri_yscale +
   1565 		    (ri->ri_rows - row - 1) * ri->ri_xscale);
   1566 
   1567 		fg = (uint16_t)ATTR_FG(ri, attr);
   1568 
   1569 		while (height--) {
   1570 			*rp = fg;
   1571 			DELTA(rp, ri->ri_stride, uint16_t *);
   1572 		}
   1573 	}
   1574 }
   1575 
   1576 static void
   1577 rasops_erasecols_rotated_cw(void *cookie, int row, int col, int num, long attr)
   1578 {
   1579 	struct rasops_info *ri = (struct rasops_info *)cookie;
   1580 	int i;
   1581 
   1582 	for (i = col; i < col + num; i++)
   1583 		ri->ri_ops.putchar(cookie, row, i, ' ', attr);
   1584 }
   1585 
   1586 /* XXX: these could likely be optimised somewhat. */
   1587 static void
   1588 rasops_copyrows_rotated_cw(void *cookie, int src, int dst, int num)
   1589 {
   1590 	struct rasops_info *ri = (struct rasops_info *)cookie;
   1591 	int col, roff;
   1592 
   1593 	if (src > dst)
   1594 		for (roff = 0; roff < num; roff++)
   1595 			for (col = 0; col < ri->ri_cols; col++)
   1596 				rasops_copychar(cookie, src + roff, dst + roff,
   1597 				    col, col);
   1598 	else
   1599 		for (roff = num - 1; roff >= 0; roff--)
   1600 			for (col = 0; col < ri->ri_cols; col++)
   1601 				rasops_copychar(cookie, src + roff, dst + roff,
   1602 				    col, col);
   1603 }
   1604 
   1605 static void
   1606 rasops_copycols_rotated_cw(void *cookie, int row, int src, int dst, int num)
   1607 {
   1608 	int coff;
   1609 
   1610 	if (src > dst)
   1611 		for (coff = 0; coff < num; coff++)
   1612 			rasops_copychar(cookie, row, row, src + coff,
   1613 			    dst + coff);
   1614 	else
   1615 		for (coff = num - 1; coff >= 0; coff--)
   1616 			rasops_copychar(cookie, row, row, src + coff,
   1617 			    dst + coff);
   1618 }
   1619 
   1620 static void
   1621 rasops_eraserows_rotated_cw(void *cookie, int row, int num, long attr)
   1622 {
   1623 	struct rasops_info *ri = (struct rasops_info *)cookie;
   1624 	int col, rn;
   1625 
   1626 	for (rn = row; rn < row + num; rn++)
   1627 		for (col = 0; col < ri->ri_cols; col++)
   1628 			ri->ri_ops.putchar(cookie, rn, col, ' ', attr);
   1629 }
   1630 
   1631 /*
   1632  * Quarter counter-clockwise rotation routines (originally intended for the
   1633  * built-in Sharp W-ZERO3 display in 16bpp).
   1634  */
   1635 static void
   1636 rasops_copychar_ccw(void *cookie, int srcrow, int dstrow, int srccol,
   1637     int dstcol)
   1638 {
   1639 	struct rasops_info *ri = (struct rasops_info *)cookie;
   1640 	int r_srcrow, r_dstrow, r_srccol, r_dstcol, height;
   1641 	uint8_t *sp, *dp;
   1642 
   1643 	r_srcrow = ri->ri_cols - srccol - 1;
   1644 	r_dstrow = ri->ri_cols - dstcol - 1;
   1645 	r_srccol = srcrow;
   1646 	r_dstcol = dstrow;
   1647 
   1648 	r_srcrow *= ri->ri_yscale;
   1649 	r_dstrow *= ri->ri_yscale;
   1650 	height = ri->ri_font->fontheight;
   1651 
   1652 	sp = ri->ri_bits + r_srcrow + r_srccol * ri->ri_xscale;
   1653 	dp = ri->ri_bits + r_dstrow + r_dstcol * ri->ri_xscale;
   1654 
   1655 	while (height--) {
   1656 		memmove(dp, sp, ri->ri_xscale);
   1657 		dp += ri->ri_stride;
   1658 		sp += ri->ri_stride;
   1659 	}
   1660 }
   1661 
   1662 static void
   1663 rasops_putchar_rotated_ccw(void *cookie, int row, int col, u_int uc, long attr)
   1664 {
   1665 	struct rasops_info *ri = (struct rasops_info *)cookie;
   1666 	int height;
   1667 	uint16_t fg, *rp;
   1668 
   1669 	if (__predict_false((unsigned int)row > ri->ri_rows ||
   1670 	    (unsigned int)col > ri->ri_cols))
   1671 		return;
   1672 
   1673 	/* Avoid underflow */
   1674 	if (ri->ri_cols - col - 1 < 0)
   1675 		return;
   1676 
   1677 	/* Do rotated char sans (side)underline */
   1678 	ri->ri_real_ops.putchar(cookie, ri->ri_cols - col - 1, row, uc,
   1679 	    attr & ~WSATTR_UNDERLINE);
   1680 
   1681 	/*
   1682 	 * Do rotated underline
   1683 	 * XXX this assumes 16-bit color depth
   1684 	 */
   1685 	if ((attr & WSATTR_UNDERLINE) != 0) {
   1686 		height = ri->ri_font->fontheight;
   1687 
   1688 		rp = (uint16_t *)(ri->ri_bits +
   1689 		    (ri->ri_cols - col - 1) * ri->ri_yscale +
   1690 		    row * ri->ri_xscale +
   1691 		    (ri->ri_font->fontwidth - 1) * ri->ri_pelbytes);
   1692 
   1693 		fg = (uint16_t)ATTR_FG(ri, attr);
   1694 
   1695 		while (height--) {
   1696 			*rp = fg;
   1697 			DELTA(rp, ri->ri_stride, uint16_t *);
   1698 		}
   1699 	}
   1700 }
   1701 
   1702 /* XXX: these could likely be optimised somewhat. */
   1703 static void
   1704 rasops_copyrows_rotated_ccw(void *cookie, int src, int dst, int num)
   1705 {
   1706 	struct rasops_info *ri = (struct rasops_info *)cookie;
   1707 	int col, roff;
   1708 
   1709 	if (src > dst)
   1710 		for (roff = 0; roff < num; roff++)
   1711 			for (col = 0; col < ri->ri_cols; col++)
   1712 				rasops_copychar_ccw(cookie,
   1713 				    src + roff, dst + roff, col, col);
   1714 	else
   1715 		for (roff = num - 1; roff >= 0; roff--)
   1716 			for (col = 0; col < ri->ri_cols; col++)
   1717 				rasops_copychar_ccw(cookie,
   1718 				    src + roff, dst + roff, col, col);
   1719 }
   1720 
   1721 static void
   1722 rasops_copycols_rotated_ccw(void *cookie, int row, int src, int dst, int num)
   1723 {
   1724 	int coff;
   1725 
   1726 	if (src > dst)
   1727 		for (coff = 0; coff < num; coff++)
   1728 			rasops_copychar_ccw(cookie, row, row,
   1729 			    src + coff, dst + coff);
   1730 	else
   1731 		for (coff = num - 1; coff >= 0; coff--)
   1732 			rasops_copychar_ccw(cookie, row, row,
   1733 			    src + coff, dst + coff);
   1734 }
   1735 #endif	/* NRASOPS_ROTATION */
   1736