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