xref: /openbsd-src/sys/dev/rasops/rasops.c (revision b2ea75c1b17e1a9a339660e7ed45cd24946b230e)
1 /*	$OpenBSD: rasops.c,v 1.1 2001/03/18 04:32:44 nate Exp $ */
2 /*	 $NetBSD: rasops.c,v 1.35 2001/02/02 06:01:01 marcus Exp $	*/
3 
4 /*-
5  * Copyright (c) 1999 The NetBSD Foundation, Inc.
6  * All rights reserved.
7  *
8  * This code is derived from software contributed to The NetBSD Foundation
9  * by Andrew Doran.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  * 3. All advertising materials mentioning features or use of this software
20  *    must display the following acknowledgement:
21  *	This product includes software developed by the NetBSD
22  *	Foundation, Inc. and its contributors.
23  * 4. Neither the name of The NetBSD Foundation nor the names of its
24  *    contributors may be used to endorse or promote products derived
25  *    from this software without specific prior written permission.
26  *
27  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
28  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
29  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
30  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
31  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37  * POSSIBILITY OF SUCH DAMAGE.
38  */
39 
40 #include <sys/cdefs.h>
41 //__KERNEL_RCSID(0, "$NetBSD: rasops.c,v 1.35 2001/02/02 06:01:01 marcus Exp $");
42 
43 #include "rasops_glue.h"
44 
45 #include <sys/types.h>
46 #include <sys/param.h>
47 #include <sys/systm.h>
48 #include <sys/time.h>
49 
50 /* #include <machine/bswap.h> */
51 #include <machine/endian.h>
52 
53 #include <dev/wscons/wsdisplayvar.h>
54 #include <dev/wscons/wsconsio.h>
55 #include <dev/wsfont/wsfont.h>
56 #include <dev/rasops/rasops.h>
57 
58 #ifndef _KERNEL
59 #include <errno.h>
60 #endif
61 
62 /* ANSI colormap (R,G,B). Upper 8 are high-intensity */
63 const u_char rasops_cmap[256*3] = {
64 	0x00, 0x00, 0x00, /* black */
65 	0x7f, 0x00, 0x00, /* red */
66 	0x00, 0x7f, 0x00, /* green */
67 	0x7f, 0x7f, 0x00, /* brown */
68 	0x00, 0x00, 0x7f, /* blue */
69 	0x7f, 0x00, 0x7f, /* magenta */
70 	0x00, 0x7f, 0x7f, /* cyan */
71 	0xc7, 0xc7, 0xc7, /* white - XXX too dim? */
72 
73 	0x7f, 0x7f, 0x7f, /* black */
74 	0xff, 0x00, 0x00, /* red */
75 	0x00, 0xff, 0x00, /* green */
76 	0xff, 0xff, 0x00, /* brown */
77 	0x00, 0x00, 0xff, /* blue */
78 	0xff, 0x00, 0xff, /* magenta */
79 	0x00, 0xff, 0xff, /* cyan */
80 	0xff, 0xff, 0xff, /* white */
81 
82 	/*
83 	 * For the cursor, we need at least the last (255th)
84 	 * color to be white. Fill up white completely for
85 	 * simplicity.
86 	 */
87 #define _CMWHITE 0xff, 0xff, 0xff,
88 #define _CMWHITE16	_CMWHITE _CMWHITE _CMWHITE _CMWHITE \
89 			_CMWHITE _CMWHITE _CMWHITE _CMWHITE \
90 			_CMWHITE _CMWHITE _CMWHITE _CMWHITE \
91 			_CMWHITE _CMWHITE _CMWHITE _CMWHITE
92 	_CMWHITE16 _CMWHITE16 _CMWHITE16 _CMWHITE16 _CMWHITE16
93 	_CMWHITE16 _CMWHITE16 _CMWHITE16 _CMWHITE16 _CMWHITE16
94 	_CMWHITE16 _CMWHITE16 _CMWHITE16 _CMWHITE16 _CMWHITE16
95 #undef _CMWHITE16
96 #undef _CMWHITE
97 };
98 
99 /* True if color is gray */
100 const u_char rasops_isgray[16] = {
101 	1, 0, 0, 0,
102 	0, 0, 0, 1,
103 	1, 0, 0, 0,
104 	0, 0, 0, 1
105 };
106 
107 /* Generic functions */
108 static void	rasops_copyrows __P((void *, int, int, int));
109 static int	rasops_mapchar __P((void *, int, u_int *));
110 static void	rasops_cursor __P((void *, int, int, int));
111 static int	rasops_alloc_cattr __P((void *, int, int, int, long *));
112 static int	rasops_alloc_mattr __P((void *, int, int, int, long *));
113 static void	rasops_do_cursor __P((struct rasops_info *));
114 static void	rasops_init_devcmap __P((struct rasops_info *));
115 
116 /*
117  * Initalize a 'rasops_info' descriptor.
118  */
119 int
120 rasops_init(ri, wantrows, wantcols)
121 	struct rasops_info *ri;
122 	int wantrows, wantcols;
123 {
124 
125 #ifdef _KERNEL
126 	/* Select a font if the caller doesn't care */
127 	if (ri->ri_font == NULL) {
128 		int cookie;
129 
130 		wsfont_init();
131 
132 		/* Want 8 pixel wide, don't care about aestethics */
133 		if ((cookie = wsfont_find(NULL, 8, 0, 0)) <= 0)
134 			cookie = wsfont_find(NULL, 0, 0, 0);
135 
136 		if (cookie <= 0) {
137 			printf("rasops_init: font table is empty\n");
138 			return (-1);
139 		}
140 
141 		if (wsfont_lock(cookie, &ri->ri_font,
142 		    WSDISPLAY_FONTORDER_L2R, WSDISPLAY_FONTORDER_L2R) <= 0) {
143 			printf("rasops_init: couldn't lock font\n");
144 			return (-1);
145 		}
146 
147 		ri->ri_wsfcookie = cookie;
148 	}
149 #endif
150 
151 	/* This should never happen in reality... */
152 #ifdef DEBUG
153 	if ((long)ri->ri_bits & 3) {
154 		printf("rasops_init: bits not aligned on 32-bit boundary\n");
155 		return (-1);
156 	}
157 
158 	if ((int)ri->ri_stride & 3) {
159 		printf("rasops_init: stride not aligned on 32-bit boundary\n");
160 		return (-1);
161 	}
162 #endif
163 
164 	if (rasops_reconfig(ri, wantrows, wantcols))
165 		return (-1);
166 
167 	rasops_init_devcmap(ri);
168 	return (0);
169 }
170 
171 /*
172  * Reconfigure (because parameters have changed in some way).
173  */
174 int
175 rasops_reconfig(ri, wantrows, wantcols)
176 	struct rasops_info *ri;
177 	int wantrows, wantcols;
178 {
179 	int bpp, s;
180 
181 	s = splhigh();
182 
183 	if (ri->ri_font->fontwidth > 32 || ri->ri_font->fontwidth < 4)
184 		panic("rasops_init: fontwidth assumptions botched!\n");
185 
186 	/* Need this to frob the setup below */
187 	bpp = (ri->ri_depth == 15 ? 16 : ri->ri_depth);
188 
189 	if ((ri->ri_flg & RI_CFGDONE) != 0)
190 		ri->ri_bits = ri->ri_origbits;
191 
192 	/* Don't care if the caller wants a hideously small console */
193 	if (wantrows < 10)
194 		wantrows = 10;
195 
196 	if (wantcols < 20)
197 		wantcols = 20;
198 
199 	/* Now constrain what they get */
200 	ri->ri_emuwidth = ri->ri_font->fontwidth * wantcols;
201 	ri->ri_emuheight = ri->ri_font->fontheight * wantrows;
202 
203 	if (ri->ri_emuwidth > ri->ri_width)
204 		ri->ri_emuwidth = ri->ri_width;
205 
206 	if (ri->ri_emuheight > ri->ri_height)
207 		ri->ri_emuheight = ri->ri_height;
208 
209 	/* Reduce width until aligned on a 32-bit boundary */
210 	while ((ri->ri_emuwidth * bpp & 31) != 0)
211 		ri->ri_emuwidth--;
212 
213 	ri->ri_cols = ri->ri_emuwidth / ri->ri_font->fontwidth;
214 	ri->ri_rows = ri->ri_emuheight / ri->ri_font->fontheight;
215 	ri->ri_emustride = ri->ri_emuwidth * bpp >> 3;
216 	ri->ri_delta = ri->ri_stride - ri->ri_emustride;
217 	ri->ri_ccol = 0;
218 	ri->ri_crow = 0;
219 	ri->ri_pelbytes = bpp >> 3;
220 
221 	ri->ri_xscale = (ri->ri_font->fontwidth * bpp) >> 3;
222 	ri->ri_yscale = ri->ri_font->fontheight * ri->ri_stride;
223 	ri->ri_fontscale = ri->ri_font->fontheight * ri->ri_font->stride;
224 
225 #ifdef DEBUG
226 	if ((ri->ri_delta & 3) != 0)
227 		panic("rasops_init: ri_delta not aligned on 32-bit boundary");
228 #endif
229 	/* Clear the entire display */
230 	if ((ri->ri_flg & RI_CLEAR) != 0)
231 		memset(ri->ri_bits, 0, ri->ri_stride * ri->ri_height);
232 
233 	/* Now centre our window if needs be */
234 	ri->ri_origbits = ri->ri_bits;
235 
236 	if ((ri->ri_flg & RI_CENTER) != 0) {
237 		ri->ri_bits += (((ri->ri_width * bpp >> 3) -
238 		    ri->ri_emustride) >> 1) & ~3;
239 		ri->ri_bits += ((ri->ri_height - ri->ri_emuheight) >> 1) *
240 		    ri->ri_stride;
241 
242 		ri->ri_yorigin = (int)(ri->ri_bits - ri->ri_origbits)
243 		   / ri->ri_stride;
244 		ri->ri_xorigin = (((int)(ri->ri_bits - ri->ri_origbits)
245 		   % ri->ri_stride) * 8 / bpp);
246 	} else
247 		ri->ri_xorigin = ri->ri_yorigin = 0;
248 
249 	/*
250 	 * Fill in defaults for operations set.  XXX this nukes private
251 	 * routines used by accelerated fb drivers.
252 	 */
253 	ri->ri_ops.mapchar = rasops_mapchar;
254 	ri->ri_ops.copyrows = rasops_copyrows;
255 	ri->ri_ops.copycols = rasops_copycols;
256 	ri->ri_ops.erasecols = rasops_erasecols;
257 	ri->ri_ops.eraserows = rasops_eraserows;
258 	ri->ri_ops.cursor = rasops_cursor;
259 	ri->ri_do_cursor = rasops_do_cursor;
260 
261 	if (ri->ri_depth < 8 || (ri->ri_flg & RI_FORCEMONO) != 0) {
262 		ri->ri_ops.alloc_attr = rasops_alloc_mattr;
263 		ri->ri_caps = WSSCREEN_UNDERLINE | WSSCREEN_REVERSE;
264 	} else {
265 		ri->ri_ops.alloc_attr = rasops_alloc_cattr;
266 		ri->ri_caps = WSSCREEN_UNDERLINE | WSSCREEN_HILIT |
267 		    WSSCREEN_WSCOLORS | WSSCREEN_REVERSE;
268 	}
269 
270 	switch (ri->ri_depth) {
271 #if NRASOPS1 > 0
272 	case 1:
273 		rasops1_init(ri);
274 		break;
275 #endif
276 #if NRASOPS2 > 0
277 	case 2:
278 		rasops2_init(ri);
279 		break;
280 #endif
281 #if NRASOPS4 > 0
282 	case 4:
283 		rasops4_init(ri);
284 		break;
285 #endif
286 #if NRASOPS8 > 0
287 	case 8:
288 		rasops8_init(ri);
289 		break;
290 #endif
291 #if NRASOPS15 > 0 || NRASOPS16 > 0
292 	case 15:
293 	case 16:
294 		rasops15_init(ri);
295 		break;
296 #endif
297 #if NRASOPS24 > 0
298 	case 24:
299 		rasops24_init(ri);
300 		break;
301 #endif
302 #if NRASOPS32 > 0
303 	case 32:
304 		rasops32_init(ri);
305 		break;
306 #endif
307 	default:
308 		ri->ri_flg &= ~RI_CFGDONE;
309 		splx(s);
310 		return (-1);
311 	}
312 
313 	ri->ri_flg |= RI_CFGDONE;
314 	splx(s);
315 	return (0);
316 }
317 
318 /*
319  * Map a character.
320  */
321 static int
322 rasops_mapchar(cookie, c, cp)
323 	void *cookie;
324 	int c;
325 	u_int *cp;
326 {
327 	struct rasops_info *ri;
328 
329 	ri = (struct rasops_info *)cookie;
330 
331 #ifdef DIAGNOSTIC
332 	if (ri->ri_font == NULL)
333 		panic("rasops_mapchar: no font selected\n");
334 #endif
335 	if (ri->ri_font->encoding != WSDISPLAY_FONTENC_ISO) {
336 
337 		if ( (c = wsfont_map_unichar(ri->ri_font, c)) < 0) {
338 
339 			*cp = ' ';
340 			return (0);
341 
342 		}
343 	}
344 
345 
346 	if (c < ri->ri_font->firstchar) {
347 		*cp = ' ';
348 		return (0);
349 	}
350 
351 	if (c - ri->ri_font->firstchar >= ri->ri_font->numchars) {
352 		*cp = ' ';
353 		return (0);
354 	}
355 
356 	*cp = c;
357 	return (5);
358 }
359 
360 /*
361  * Allocate a color attribute.
362  */
363 static int
364 rasops_alloc_cattr(cookie, fg, bg, flg, attr)
365 	void *cookie;
366 	int fg, bg, flg;
367 	long *attr;
368 {
369 	int swap;
370 
371 #ifdef RASOPS_CLIPPING
372 	fg &= 7;
373 	bg &= 7;
374 #endif
375 	if ((flg & WSATTR_BLINK) != 0)
376 		return (EINVAL);
377 
378 	if ((flg & WSATTR_WSCOLORS) == 0) {
379 		fg = WSCOL_WHITE;
380 		bg = WSCOL_BLACK;
381 	}
382 
383 	if ((flg & WSATTR_REVERSE) != 0) {
384 		swap = fg;
385 		fg = bg;
386 		bg = swap;
387 	}
388 
389 	if ((flg & WSATTR_HILIT) != 0)
390 		fg += 8;
391 
392 	flg = ((flg & WSATTR_UNDERLINE) ? 1 : 0);
393 
394 	if (rasops_isgray[fg])
395 		flg |= 2;
396 
397 	if (rasops_isgray[bg])
398 		flg |= 4;
399 
400 	*attr = (bg << 16) | (fg << 24) | flg;
401 	return (0);
402 }
403 
404 /*
405  * Allocate a mono attribute.
406  */
407 static int
408 rasops_alloc_mattr(cookie, fg, bg, flg, attr)
409 	void *cookie;
410 	int fg, bg, flg;
411 	long *attr;
412 {
413 	int swap;
414 
415 	if ((flg & (WSATTR_BLINK | WSATTR_HILIT | WSATTR_WSCOLORS)) != 0)
416 		return (EINVAL);
417 
418 	fg = 1;
419 	bg = 0;
420 
421 	if ((flg & WSATTR_REVERSE) != 0) {
422 		swap = fg;
423 		fg = bg;
424 		bg = swap;
425 	}
426 
427 	*attr = (bg << 16) | (fg << 24) | ((flg & WSATTR_UNDERLINE) ? 7 : 6);
428 	return (0);
429 }
430 
431 /*
432  * Copy rows.
433  */
434 static void
435 rasops_copyrows(cookie, src, dst, num)
436 	void *cookie;
437 	int src, dst, num;
438 {
439 	int32_t *sp, *dp, *srp, *drp;
440 	struct rasops_info *ri;
441 	int n8, n1, cnt, delta;
442 
443 	ri = (struct rasops_info *)cookie;
444 
445 #ifdef RASOPS_CLIPPING
446 	if (dst == src)
447 		return;
448 
449 	if (src < 0) {
450 		num += src;
451 		src = 0;
452 	}
453 
454 	if ((src + num) > ri->ri_rows)
455 		num = ri->ri_rows - src;
456 
457 	if (dst < 0) {
458 		num += dst;
459 		dst = 0;
460 	}
461 
462 	if ((dst + num) > ri->ri_rows)
463 		num = ri->ri_rows - dst;
464 
465 	if (num <= 0)
466 		return;
467 #endif
468 
469 	num *= ri->ri_font->fontheight;
470 	n8 = ri->ri_emustride >> 5;
471 	n1 = (ri->ri_emustride >> 2) & 7;
472 
473 	if (dst < src) {
474 		srp = (int32_t *)(ri->ri_bits + src * ri->ri_yscale);
475 		drp = (int32_t *)(ri->ri_bits + dst * ri->ri_yscale);
476 		delta = ri->ri_stride;
477 	} else {
478 		src = ri->ri_font->fontheight * src + num - 1;
479 		dst = ri->ri_font->fontheight * dst + num - 1;
480 		srp = (int32_t *)(ri->ri_bits + src * ri->ri_stride);
481 		drp = (int32_t *)(ri->ri_bits + dst * ri->ri_stride);
482 		delta = -ri->ri_stride;
483 	}
484 
485 	while (num--) {
486 		dp = drp;
487 		sp = srp;
488 		DELTA(drp, delta, int32_t *);
489 		DELTA(srp, delta, int32_t *);
490 
491 		for (cnt = n8; cnt; cnt--) {
492 			dp[0] = sp[0];
493 			dp[1] = sp[1];
494 			dp[2] = sp[2];
495 			dp[3] = sp[3];
496 			dp[4] = sp[4];
497 			dp[5] = sp[5];
498 			dp[6] = sp[6];
499 			dp[7] = sp[7];
500 			dp += 8;
501 			sp += 8;
502 		}
503 
504 		for (cnt = n1; cnt; cnt--)
505 			*dp++ = *sp++;
506 	}
507 }
508 
509 /*
510  * Copy columns. This is slow, and hard to optimize due to alignment,
511  * and the fact that we have to copy both left->right and right->left.
512  * We simply cop-out here and use bcopy(), since it handles all of
513  * these cases anyway.
514  */
515 void
516 rasops_copycols(cookie, row, src, dst, num)
517 	void *cookie;
518 	int row, src, dst, num;
519 {
520 	struct rasops_info *ri;
521 	u_char *sp, *dp;
522 	int height;
523 
524 	ri = (struct rasops_info *)cookie;
525 
526 #ifdef RASOPS_CLIPPING
527 	if (dst == src)
528 		return;
529 
530 	/* Catches < 0 case too */
531 	if ((unsigned)row >= (unsigned)ri->ri_rows)
532 		return;
533 
534 	if (src < 0) {
535 		num += src;
536 		src = 0;
537 	}
538 
539 	if ((src + num) > ri->ri_cols)
540 		num = ri->ri_cols - src;
541 
542 	if (dst < 0) {
543 		num += dst;
544 		dst = 0;
545 	}
546 
547 	if ((dst + num) > ri->ri_cols)
548 		num = ri->ri_cols - dst;
549 
550 	if (num <= 0)
551 		return;
552 #endif
553 
554 	num *= ri->ri_xscale;
555 	row *= ri->ri_yscale;
556 	height = ri->ri_font->fontheight;
557 
558 	sp = ri->ri_bits + row + src * ri->ri_xscale;
559 	dp = ri->ri_bits + row + dst * ri->ri_xscale;
560 
561 	while (height--) {
562 		bcopy(sp, dp, num);
563 		dp += ri->ri_stride;
564 		sp += ri->ri_stride;
565 	}
566 }
567 
568 /*
569  * Turn cursor off/on.
570  */
571 static void
572 rasops_cursor(cookie, on, row, col)
573 	void *cookie;
574 	int on, row, col;
575 {
576 	struct rasops_info *ri;
577 
578 	ri = (struct rasops_info *)cookie;
579 
580 	/* Turn old cursor off */
581 	if ((ri->ri_flg & RI_CURSOR) != 0)
582 #ifdef RASOPS_CLIPPING
583 		if ((ri->ri_flg & RI_CURSORCLIP) == 0)
584 #endif
585 			ri->ri_do_cursor(ri);
586 
587 	/* Select new cursor */
588 #ifdef RASOPS_CLIPPING
589 	ri->ri_flg &= ~RI_CURSORCLIP;
590 
591 	if (row < 0 || row >= ri->ri_rows)
592 		ri->ri_flg |= RI_CURSORCLIP;
593 	else if (col < 0 || col >= ri->ri_cols)
594 		ri->ri_flg |= RI_CURSORCLIP;
595 #endif
596 	ri->ri_crow = row;
597 	ri->ri_ccol = col;
598 
599 	if (on) {
600 		ri->ri_flg |= RI_CURSOR;
601 #ifdef RASOPS_CLIPPING
602 		if ((ri->ri_flg & RI_CURSORCLIP) == 0)
603 #endif
604 			ri->ri_do_cursor(ri);
605 	} else
606 		ri->ri_flg &= ~RI_CURSOR;
607 }
608 
609 /*
610  * Make the device colormap
611  */
612 static void
613 rasops_init_devcmap(ri)
614 	struct rasops_info *ri;
615 {
616 	const u_char *p;
617 	int i, c;
618 
619 	switch (ri->ri_depth) {
620 	case 1:
621 		ri->ri_devcmap[0] = 0;
622 		for (i = 1; i < 16; i++)
623 			ri->ri_devcmap[i] = -1;
624 		return;
625 
626 	case 2:
627 		for (i = 1; i < 15; i++)
628 			ri->ri_devcmap[i] = 0xaaaaaaaa;
629 
630 		ri->ri_devcmap[0] = 0;
631 		ri->ri_devcmap[8] = 0x55555555;
632 		ri->ri_devcmap[15] = -1;
633 		return;
634 
635 	case 8:
636 		for (i = 0; i < 16; i++)
637 			ri->ri_devcmap[i] = i | (i<<8) | (i<<16) | (i<<24);
638 		return;
639 	}
640 
641 	p = rasops_cmap;
642 
643 	for (i = 0; i < 16; i++) {
644 		if (ri->ri_rnum <= 8)
645 			c = (*p >> (8 - ri->ri_rnum)) << ri->ri_rpos;
646 		else
647 			c = (*p << (ri->ri_rnum - 8)) << ri->ri_rpos;
648 		p++;
649 
650 		if (ri->ri_gnum <= 8)
651 			c |= (*p >> (8 - ri->ri_gnum)) << ri->ri_gpos;
652 		else
653 			c |= (*p << (ri->ri_gnum - 8)) << ri->ri_gpos;
654 		p++;
655 
656 		if (ri->ri_bnum <= 8)
657 			c |= (*p >> (8 - ri->ri_bnum)) << ri->ri_bpos;
658 		else
659 			c |= (*p << (ri->ri_bnum - 8)) << ri->ri_bpos;
660 		p++;
661 
662 		/* Fill the word for generic routines, which want this */
663 		if (ri->ri_depth == 24)
664 			c = c | ((c & 0xff) << 24);
665 		else if (ri->ri_depth <= 16)
666 			c = c | (c << 16);
667 
668 		/* 24bpp does bswap on the fly. {32,16,15}bpp do it here. */
669 		if ((ri->ri_flg & RI_BSWAP) == 0)
670 			ri->ri_devcmap[i] = c;
671 		else if (ri->ri_depth == 32)
672 			ri->ri_devcmap[i] = swap32(c);
673 		else if (ri->ri_depth == 16 || ri->ri_depth == 15)
674 			ri->ri_devcmap[i] = swap16(c);
675 		else
676 			ri->ri_devcmap[i] = c;
677 	}
678 }
679 
680 /*
681  * Unpack a rasops attribute
682  */
683 void
684 rasops_unpack_attr(attr, fg, bg, underline)
685 	long attr;
686 	int *fg, *bg, *underline;
687 {
688 
689 	*fg = ((u_int)attr >> 24) & 0xf;
690 	*bg = ((u_int)attr >> 16) & 0xf;
691 	if (underline != NULL)
692 		*underline = (u_int)attr & 1;
693 }
694 
695 /*
696  * Erase rows. This isn't static, since 24-bpp uses it in special cases.
697  */
698 void
699 rasops_eraserows(cookie, row, num, attr)
700 	void *cookie;
701 	int row, num;
702 	long attr;
703 {
704 	struct rasops_info *ri;
705 	int np, nw, cnt, delta;
706 	int32_t *dp, clr;
707 
708 	ri = (struct rasops_info *)cookie;
709 
710 #ifdef RASOPS_CLIPPING
711 	if (row < 0) {
712 		num += row;
713 		row = 0;
714 	}
715 
716 	if ((row + num) > ri->ri_rows)
717 		num = ri->ri_rows - row;
718 
719 	if (num <= 0)
720 		return;
721 #endif
722 
723 	clr = ri->ri_devcmap[(attr >> 16) & 0xf];
724 
725 	/*
726 	 * XXX The wsdisplay_emulops interface seems a little deficient in
727 	 * that there is no way to clear the *entire* screen. We provide a
728 	 * workaround here: if the entire console area is being cleared, and
729 	 * the RI_FULLCLEAR flag is set, clear the entire display.
730 	 */
731 	if (num == ri->ri_rows && (ri->ri_flg & RI_FULLCLEAR) != 0) {
732 		np = ri->ri_stride >> 5;
733 		nw = (ri->ri_stride >> 2) & 7;
734 		num = ri->ri_height;
735 		dp = (int32_t *)ri->ri_origbits;
736 		delta = 0;
737 	} else {
738 		np = ri->ri_emustride >> 5;
739 		nw = (ri->ri_emustride >> 2) & 7;
740 		num *= ri->ri_font->fontheight;
741 		dp = (int32_t *)(ri->ri_bits + row * ri->ri_yscale);
742 		delta = ri->ri_delta;
743 	}
744 
745 	while (num--) {
746 		for (cnt = np; cnt; cnt--) {
747 			dp[0] = clr;
748 			dp[1] = clr;
749 			dp[2] = clr;
750 			dp[3] = clr;
751 			dp[4] = clr;
752 			dp[5] = clr;
753 			dp[6] = clr;
754 			dp[7] = clr;
755 			dp += 8;
756 		}
757 
758 		for (cnt = nw; cnt; cnt--) {
759 			*(int32_t *)dp = clr;
760 			DELTA(dp, 4, int32_t *);
761 		}
762 
763 		DELTA(dp, delta, int32_t *);
764 	}
765 }
766 
767 /*
768  * Actually turn the cursor on or off. This does the dirty work for
769  * rasops_cursor().
770  */
771 static void
772 rasops_do_cursor(ri)
773 	struct rasops_info *ri;
774 {
775 	int full1, height, cnt, slop1, slop2, row, col;
776 	u_char *dp, *rp;
777 
778 	row = ri->ri_crow;
779 	col = ri->ri_ccol;
780 
781 	rp = ri->ri_bits + row * ri->ri_yscale + col * ri->ri_xscale;
782 	height = ri->ri_font->fontheight;
783 	slop1 = (4 - ((long)rp & 3)) & 3;
784 
785 	if (slop1 > ri->ri_xscale)
786 		slop1 = ri->ri_xscale;
787 
788 	slop2 = (ri->ri_xscale - slop1) & 3;
789 	full1 = (ri->ri_xscale - slop1 - slop2) >> 2;
790 
791 	if ((slop1 | slop2) == 0) {
792 		/* A common case */
793 		while (height--) {
794 			dp = rp;
795 			rp += ri->ri_stride;
796 
797 			for (cnt = full1; cnt; cnt--) {
798 				*(int32_t *)dp ^= ~0;
799 				dp += 4;
800 			}
801 		}
802 	} else {
803 		/* XXX this is stupid.. use masks instead */
804 		while (height--) {
805 			dp = rp;
806 			rp += ri->ri_stride;
807 
808 			if (slop1 & 1)
809 				*dp++ ^= ~0;
810 
811 			if (slop1 & 2) {
812 				*(int16_t *)dp ^= ~0;
813 				dp += 2;
814 			}
815 
816 			for (cnt = full1; cnt; cnt--) {
817 				*(int32_t *)dp ^= ~0;
818 				dp += 4;
819 			}
820 
821 			if (slop2 & 1)
822 				*dp++ ^= ~0;
823 
824 			if (slop2 & 2)
825 				*(int16_t *)dp ^= ~0;
826 		}
827 	}
828 }
829 
830 /*
831  * Erase columns.
832  */
833 void
834 rasops_erasecols(cookie, row, col, num, attr)
835 	void *cookie;
836 	int row, col, num;
837 	long attr;
838 {
839 	int n8, height, cnt, slop1, slop2, clr;
840 	struct rasops_info *ri;
841 	int32_t *rp, *dp;
842 
843 	ri = (struct rasops_info *)cookie;
844 
845 #ifdef RASOPS_CLIPPING
846 	if ((unsigned)row >= (unsigned)ri->ri_rows)
847 		return;
848 
849 	if (col < 0) {
850 		num += col;
851 		col = 0;
852 	}
853 
854 	if ((col + num) > ri->ri_cols)
855 		num = ri->ri_cols - col;
856 
857 	if (num <= 0)
858 		return;
859 #endif
860 
861 	num = num * ri->ri_xscale;
862 	rp = (int32_t *)(ri->ri_bits + row*ri->ri_yscale + col*ri->ri_xscale);
863 	height = ri->ri_font->fontheight;
864 	clr = ri->ri_devcmap[(attr >> 16) & 0xf];
865 
866 	/* Don't bother using the full loop for <= 32 pels */
867 	if (num <= 32) {
868 		if (((num | ri->ri_xscale) & 3) == 0) {
869 			/* Word aligned blt */
870 			num >>= 2;
871 
872 			while (height--) {
873 				dp = rp;
874 				DELTA(rp, ri->ri_stride, int32_t *);
875 
876 				for (cnt = num; cnt; cnt--)
877 					*dp++ = clr;
878 			}
879 		} else if (((num | ri->ri_xscale) & 1) == 0) {
880 			/*
881 			 * Halfword aligned blt. This is needed so the
882 			 * 15/16 bit ops can use this function.
883 			 */
884 			num >>= 1;
885 
886 			while (height--) {
887 				dp = rp;
888 				DELTA(rp, ri->ri_stride, int32_t *);
889 
890 				for (cnt = num; cnt; cnt--) {
891 					*(int16_t *)dp = clr;
892 					DELTA(dp, 2, int32_t *);
893 				}
894 			}
895 		} else {
896 			while (height--) {
897 				dp = rp;
898 				DELTA(rp, ri->ri_stride, int32_t *);
899 
900 				for (cnt = num; cnt; cnt--) {
901 					*(u_char *)dp = clr;
902 					DELTA(dp, 1, int32_t *);
903 				}
904 			}
905 		}
906 
907 		return;
908 	}
909 
910 	slop1 = (4 - ((long)rp & 3)) & 3;
911 	slop2 = (num - slop1) & 3;
912 	num -= slop1 + slop2;
913 	n8 = num >> 5;
914 	num = (num >> 2) & 7;
915 
916 	while (height--) {
917 		dp = rp;
918 		DELTA(rp, ri->ri_stride, int32_t *);
919 
920 		/* Align span to 4 bytes */
921 		if (slop1 & 1) {
922 			*(u_char *)dp = clr;
923 			DELTA(dp, 1, int32_t *);
924 		}
925 
926 		if (slop1 & 2) {
927 			*(int16_t *)dp = clr;
928 			DELTA(dp, 2, int32_t *);
929 		}
930 
931 		/* Write 32 bytes per loop */
932 		for (cnt = n8; cnt; cnt--) {
933 			dp[0] = clr;
934 			dp[1] = clr;
935 			dp[2] = clr;
936 			dp[3] = clr;
937 			dp[4] = clr;
938 			dp[5] = clr;
939 			dp[6] = clr;
940 			dp[7] = clr;
941 			dp += 8;
942 		}
943 
944 		/* Write 4 bytes per loop */
945 		for (cnt = num; cnt; cnt--)
946 			*dp++ = clr;
947 
948 		/* Write unaligned trailing slop */
949 		if (slop2 & 1) {
950 			*(u_char *)dp = clr;
951 			DELTA(dp, 1, int32_t *);
952 		}
953 
954 		if (slop2 & 2)
955 			*(int16_t *)dp = clr;
956 	}
957 }
958