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