rasops.c revision 1.58
1/*	 $NetBSD: rasops.c,v 1.58 2008/04/28 20:23:56 martin 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.58 2008/04/28 20:23:56 martin 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
43#include <sys/bswap.h>
44#include <machine/endian.h>
45
46#include <dev/wscons/wsdisplayvar.h>
47#include <dev/wscons/wsconsio.h>
48#include <dev/wsfont/wsfont.h>
49#include <dev/rasops/rasops.h>
50
51#ifndef _KERNEL
52#include <errno.h>
53#endif
54
55/* ANSI colormap (R,G,B). Upper 8 are high-intensity */
56const u_char rasops_cmap[256*3] = {
57	0x00, 0x00, 0x00, /* black */
58	0x7f, 0x00, 0x00, /* red */
59	0x00, 0x7f, 0x00, /* green */
60	0x7f, 0x7f, 0x00, /* brown */
61	0x00, 0x00, 0x7f, /* blue */
62	0x7f, 0x00, 0x7f, /* magenta */
63	0x00, 0x7f, 0x7f, /* cyan */
64	0xc7, 0xc7, 0xc7, /* white - XXX too dim? */
65
66	0x7f, 0x7f, 0x7f, /* black */
67	0xff, 0x00, 0x00, /* red */
68	0x00, 0xff, 0x00, /* green */
69	0xff, 0xff, 0x00, /* brown */
70	0x00, 0x00, 0xff, /* blue */
71	0xff, 0x00, 0xff, /* magenta */
72	0x00, 0xff, 0xff, /* cyan */
73	0xff, 0xff, 0xff, /* white */
74
75	/*
76	 * For the cursor, we need at least the last (255th)
77	 * color to be white. Fill up white completely for
78	 * simplicity.
79	 */
80#define _CMWHITE 0xff, 0xff, 0xff,
81#define _CMWHITE16	_CMWHITE _CMWHITE _CMWHITE _CMWHITE \
82			_CMWHITE _CMWHITE _CMWHITE _CMWHITE \
83			_CMWHITE _CMWHITE _CMWHITE _CMWHITE \
84			_CMWHITE _CMWHITE _CMWHITE _CMWHITE
85	_CMWHITE16 _CMWHITE16 _CMWHITE16 _CMWHITE16 _CMWHITE16
86	_CMWHITE16 _CMWHITE16 _CMWHITE16 _CMWHITE16 _CMWHITE16
87	_CMWHITE16 _CMWHITE16 _CMWHITE16 _CMWHITE16 /* but not the last one */
88#undef _CMWHITE16
89#undef _CMWHITE
90
91	/*
92	 * For the cursor the fg/bg indices are bit inverted, so
93	 * provide complimentary colors in the upper 16 entries.
94	 */
95	0x7f, 0x7f, 0x7f, /* black */
96	0xff, 0x00, 0x00, /* red */
97	0x00, 0xff, 0x00, /* green */
98	0xff, 0xff, 0x00, /* brown */
99	0x00, 0x00, 0xff, /* blue */
100	0xff, 0x00, 0xff, /* magenta */
101	0x00, 0xff, 0xff, /* cyan */
102	0xff, 0xff, 0xff, /* white */
103
104	0x00, 0x00, 0x00, /* black */
105	0x7f, 0x00, 0x00, /* red */
106	0x00, 0x7f, 0x00, /* green */
107	0x7f, 0x7f, 0x00, /* brown */
108	0x00, 0x00, 0x7f, /* blue */
109	0x7f, 0x00, 0x7f, /* magenta */
110	0x00, 0x7f, 0x7f, /* cyan */
111	0xc7, 0xc7, 0xc7, /* white - XXX too dim? */
112};
113
114/* True if color is gray */
115const u_char rasops_isgray[16] = {
116	1, 0, 0, 0,
117	0, 0, 0, 1,
118	1, 0, 0, 0,
119	0, 0, 0, 1
120};
121
122/* Generic functions */
123static void	rasops_copyrows(void *, int, int, int);
124static int	rasops_mapchar(void *, int, u_int *);
125static void	rasops_cursor(void *, int, int, int);
126static int	rasops_allocattr_color(void *, int, int, int, long *);
127static int	rasops_allocattr_mono(void *, int, int, int, long *);
128static void	rasops_do_cursor(struct rasops_info *);
129static void	rasops_init_devcmap(struct rasops_info *);
130
131#if NRASOPS_ROTATION > 0
132static void	rasops_copychar(void *, int, int, int, int);
133static void	rasops_copycols_rotated(void *, int, int, int, int);
134static void	rasops_copyrows_rotated(void *, int, int, int);
135static void	rasops_erasecols_rotated(void *, int, int, int, long);
136static void	rasops_eraserows_rotated(void *, int, int, long);
137static void	rasops_putchar_rotated(void *, int, int, u_int, long);
138static void	rasops_rotate_font(int *);
139
140/*
141 * List of all rotated fonts
142 */
143SLIST_HEAD(, rotatedfont) rotatedfonts = SLIST_HEAD_INITIALIZER(rotatedfonts);
144struct rotatedfont {
145	SLIST_ENTRY(rotatedfont) rf_next;
146	int rf_cookie;
147	int rf_rotated;
148};
149#endif	/* NRASOPS_ROTATION > 0 */
150
151/*
152 * Initialize a 'rasops_info' descriptor.
153 */
154int
155rasops_init(ri, wantrows, wantcols)
156	struct rasops_info *ri;
157	int wantrows, wantcols;
158{
159
160#ifdef _KERNEL
161	/* Select a font if the caller doesn't care */
162	if (ri->ri_font == NULL) {
163		int cookie;
164
165		wsfont_init();
166
167		/* Want 8 pixel wide, don't care about aestethics */
168		cookie = wsfont_find(NULL, 8, 0, 0, WSDISPLAY_FONTORDER_L2R,
169		    WSDISPLAY_FONTORDER_L2R);
170		if (cookie <= 0)
171			cookie = wsfont_find(NULL, 0, 0, 0,
172			    WSDISPLAY_FONTORDER_L2R, WSDISPLAY_FONTORDER_L2R);
173
174		if (cookie <= 0) {
175			printf("rasops_init: font table is empty\n");
176			return (-1);
177		}
178
179#if NRASOPS_ROTATION > 0
180		/*
181		 * Pick the rotated version of this font. This will create it
182		 * if necessary.
183		 */
184		if (ri->ri_flg & RI_ROTATE_CW)
185			rasops_rotate_font(&cookie);
186#endif
187
188		if (wsfont_lock(cookie, &ri->ri_font)) {
189			printf("rasops_init: couldn't lock font\n");
190			return (-1);
191		}
192
193		ri->ri_wsfcookie = cookie;
194	}
195#endif
196
197	/* This should never happen in reality... */
198#ifdef DEBUG
199	if ((long)ri->ri_bits & 3) {
200		printf("rasops_init: bits not aligned on 32-bit boundary\n");
201		return (-1);
202	}
203
204	if ((int)ri->ri_stride & 3) {
205		printf("rasops_init: stride not aligned on 32-bit boundary\n");
206		return (-1);
207	}
208#endif
209
210	if (rasops_reconfig(ri, wantrows, wantcols))
211		return (-1);
212
213	rasops_init_devcmap(ri);
214	return (0);
215}
216
217/*
218 * Reconfigure (because parameters have changed in some way).
219 */
220int
221rasops_reconfig(ri, wantrows, wantcols)
222	struct rasops_info *ri;
223	int wantrows, wantcols;
224{
225	int bpp, s;
226
227	s = splhigh();
228
229	if (ri->ri_font->fontwidth > 32 || ri->ri_font->fontwidth < 4)
230		panic("rasops_init: fontwidth assumptions botched!");
231
232	/* Need this to frob the setup below */
233	bpp = (ri->ri_depth == 15 ? 16 : ri->ri_depth);
234
235	if ((ri->ri_flg & RI_CFGDONE) != 0)
236		ri->ri_bits = ri->ri_origbits;
237
238	/* Don't care if the caller wants a hideously small console */
239	if (wantrows < 10)
240		wantrows = 10;
241
242	if (wantcols < 20)
243		wantcols = 20;
244
245	/* Now constrain what they get */
246	ri->ri_emuwidth = ri->ri_font->fontwidth * wantcols;
247	ri->ri_emuheight = ri->ri_font->fontheight * wantrows;
248
249	if (ri->ri_emuwidth > ri->ri_width)
250		ri->ri_emuwidth = ri->ri_width;
251
252	if (ri->ri_emuheight > ri->ri_height)
253		ri->ri_emuheight = ri->ri_height;
254
255	/* Reduce width until aligned on a 32-bit boundary */
256	while ((ri->ri_emuwidth * bpp & 31) != 0)
257		ri->ri_emuwidth--;
258
259#if NRASOPS_ROTATION > 0
260	if (ri->ri_flg & RI_ROTATE_CW) {
261		ri->ri_rows = ri->ri_emuwidth / ri->ri_font->fontwidth;
262		ri->ri_cols = ri->ri_emuheight / ri->ri_font->fontheight;
263	} else
264#endif
265	{
266
267		ri->ri_cols = ri->ri_emuwidth / ri->ri_font->fontwidth;
268		ri->ri_rows = ri->ri_emuheight / ri->ri_font->fontheight;
269	}
270	ri->ri_emustride = ri->ri_emuwidth * bpp >> 3;
271	ri->ri_delta = ri->ri_stride - ri->ri_emustride;
272	ri->ri_ccol = 0;
273	ri->ri_crow = 0;
274	ri->ri_pelbytes = bpp >> 3;
275
276	ri->ri_xscale = (ri->ri_font->fontwidth * bpp) >> 3;
277	ri->ri_yscale = ri->ri_font->fontheight * ri->ri_stride;
278	ri->ri_fontscale = ri->ri_font->fontheight * ri->ri_font->stride;
279
280#ifdef DEBUG
281	if ((ri->ri_delta & 3) != 0)
282		panic("rasops_init: ri_delta not aligned on 32-bit boundary");
283#endif
284	/* Clear the entire display */
285	if ((ri->ri_flg & RI_CLEAR) != 0)
286		memset(ri->ri_bits, 0, ri->ri_stride * ri->ri_height);
287
288	/* Now centre our window if needs be */
289	ri->ri_origbits = ri->ri_bits;
290
291	if ((ri->ri_flg & RI_CENTER) != 0) {
292		ri->ri_bits += (((ri->ri_width * bpp >> 3) -
293		    ri->ri_emustride) >> 1) & ~3;
294		ri->ri_bits += ((ri->ri_height - ri->ri_emuheight) >> 1) *
295		    ri->ri_stride;
296
297		ri->ri_yorigin = (int)(ri->ri_bits - ri->ri_origbits)
298		   / ri->ri_stride;
299		ri->ri_xorigin = (((int)(ri->ri_bits - ri->ri_origbits)
300		   % ri->ri_stride) * 8 / bpp);
301	} else
302		ri->ri_xorigin = ri->ri_yorigin = 0;
303
304	/*
305	 * Fill in defaults for operations set.  XXX this nukes private
306	 * routines used by accelerated fb drivers.
307	 */
308	ri->ri_ops.mapchar = rasops_mapchar;
309	ri->ri_ops.copyrows = rasops_copyrows;
310	ri->ri_ops.copycols = rasops_copycols;
311	ri->ri_ops.erasecols = rasops_erasecols;
312	ri->ri_ops.eraserows = rasops_eraserows;
313	ri->ri_ops.cursor = rasops_cursor;
314	ri->ri_do_cursor = rasops_do_cursor;
315
316	if (ri->ri_depth < 8 || (ri->ri_flg & RI_FORCEMONO) != 0) {
317		ri->ri_ops.allocattr = rasops_allocattr_mono;
318		ri->ri_caps = WSSCREEN_UNDERLINE | WSSCREEN_REVERSE;
319	} else {
320		ri->ri_ops.allocattr = rasops_allocattr_color;
321		ri->ri_caps = WSSCREEN_UNDERLINE | WSSCREEN_HILIT |
322		    WSSCREEN_WSCOLORS | WSSCREEN_REVERSE;
323	}
324
325	switch (ri->ri_depth) {
326#if NRASOPS1 > 0
327	case 1:
328		rasops1_init(ri);
329		break;
330#endif
331#if NRASOPS2 > 0
332	case 2:
333		rasops2_init(ri);
334		break;
335#endif
336#if NRASOPS4 > 0
337	case 4:
338		rasops4_init(ri);
339		break;
340#endif
341#if NRASOPS8 > 0
342	case 8:
343		rasops8_init(ri);
344		break;
345#endif
346#if NRASOPS15 > 0 || NRASOPS16 > 0
347	case 15:
348	case 16:
349		rasops15_init(ri);
350		break;
351#endif
352#if NRASOPS24 > 0
353	case 24:
354		rasops24_init(ri);
355		break;
356#endif
357#if NRASOPS32 > 0
358	case 32:
359		rasops32_init(ri);
360		break;
361#endif
362	default:
363		ri->ri_flg &= ~RI_CFGDONE;
364		splx(s);
365		return (-1);
366	}
367
368#if NRASOPS_ROTATION > 0
369	if (ri->ri_flg & RI_ROTATE_CW) {
370		ri->ri_real_ops = ri->ri_ops;
371		ri->ri_ops.copycols = rasops_copycols_rotated;
372		ri->ri_ops.copyrows = rasops_copyrows_rotated;
373		ri->ri_ops.erasecols = rasops_erasecols_rotated;
374		ri->ri_ops.eraserows = rasops_eraserows_rotated;
375		ri->ri_ops.putchar = rasops_putchar_rotated;
376	}
377#endif
378
379	ri->ri_flg |= RI_CFGDONE;
380	splx(s);
381	return (0);
382}
383
384/*
385 * Map a character.
386 */
387static int
388rasops_mapchar(cookie, c, cp)
389	void *cookie;
390	int c;
391	u_int *cp;
392{
393	struct rasops_info *ri;
394
395	ri = (struct rasops_info *)cookie;
396
397#ifdef DIAGNOSTIC
398	if (ri->ri_font == NULL)
399		panic("rasops_mapchar: no font selected");
400#endif
401
402	if (ri->ri_font->encoding != WSDISPLAY_FONTENC_ISO) {
403		if ( (c = wsfont_map_unichar(ri->ri_font, c)) < 0) {
404			*cp = ' ';
405			return (0);
406
407		}
408	}
409
410	if (c < ri->ri_font->firstchar) {
411		*cp = ' ';
412		return (0);
413	}
414
415	if (c - ri->ri_font->firstchar >= ri->ri_font->numchars) {
416		*cp = ' ';
417		return (0);
418	}
419
420	*cp = c;
421	return (5);
422}
423
424/*
425 * Allocate a color attribute.
426 */
427static int
428rasops_allocattr_color(void *cookie, int fg, int bg, int flg,
429    long *attr)
430{
431	int swap;
432
433	if (__predict_false((unsigned int)fg >= sizeof(rasops_isgray) ||
434	    (unsigned int)bg >= sizeof(rasops_isgray)))
435		return (EINVAL);
436
437#ifdef RASOPS_CLIPPING
438	fg &= 7;
439	bg &= 7;
440#endif
441	if ((flg & WSATTR_BLINK) != 0)
442		return (EINVAL);
443
444	if ((flg & WSATTR_WSCOLORS) == 0) {
445#ifdef WS_DEFAULT_FG
446		fg = WS_DEFAULT_FG;
447#else
448		fg = WSCOL_WHITE;
449#endif
450#ifdef WS_DEFAULT_BG
451		bg = WS_DEFAULT_BG;
452#else
453		bg = WSCOL_BLACK;
454#endif
455	}
456
457	if ((flg & WSATTR_REVERSE) != 0) {
458		swap = fg;
459		fg = bg;
460		bg = swap;
461	}
462
463	if ((flg & WSATTR_HILIT) != 0)
464		fg += 8;
465
466	flg = ((flg & WSATTR_UNDERLINE) ? 1 : 0);
467
468	if (rasops_isgray[fg])
469		flg |= 2;
470
471	if (rasops_isgray[bg])
472		flg |= 4;
473
474	*attr = (bg << 16) | (fg << 24) | flg;
475	return (0);
476}
477
478/*
479 * Allocate a mono attribute.
480 */
481static int
482rasops_allocattr_mono(void *cookie, int fg, int bg, int flg,
483    long *attr)
484{
485	int swap;
486
487	if ((flg & (WSATTR_BLINK | WSATTR_HILIT | WSATTR_WSCOLORS)) != 0)
488		return (EINVAL);
489
490	fg = 1;
491	bg = 0;
492
493	if ((flg & WSATTR_REVERSE) != 0) {
494		swap = fg;
495		fg = bg;
496		bg = swap;
497	}
498
499	*attr = (bg << 16) | (fg << 24) | ((flg & WSATTR_UNDERLINE) ? 7 : 6);
500	return (0);
501}
502
503/*
504 * Copy rows.
505 */
506static void
507rasops_copyrows(cookie, src, dst, num)
508	void *cookie;
509	int src, dst, num;
510{
511	int32_t *sp, *dp, *hp, *srp, *drp, *hrp;
512	struct rasops_info *ri;
513	int n8, n1, cnt, delta;
514
515	ri = (struct rasops_info *)cookie;
516	hp = hrp = NULL;
517
518#ifdef RASOPS_CLIPPING
519	if (dst == src)
520		return;
521
522	if (src < 0) {
523		num += src;
524		src = 0;
525	}
526
527	if ((src + num) > ri->ri_rows)
528		num = ri->ri_rows - src;
529
530	if (dst < 0) {
531		num += dst;
532		dst = 0;
533	}
534
535	if ((dst + num) > ri->ri_rows)
536		num = ri->ri_rows - dst;
537
538	if (num <= 0)
539		return;
540#endif
541
542	num *= ri->ri_font->fontheight;
543	n8 = ri->ri_emustride >> 5;
544	n1 = (ri->ri_emustride >> 2) & 7;
545
546	if (dst < src) {
547		srp = (int32_t *)(ri->ri_bits + src * ri->ri_yscale);
548		drp = (int32_t *)(ri->ri_bits + dst * ri->ri_yscale);
549		if (ri->ri_hwbits)
550			hrp = (int32_t *)(ri->ri_hwbits + dst *
551			    ri->ri_yscale);
552		delta = ri->ri_stride;
553	} else {
554		src = ri->ri_font->fontheight * src + num - 1;
555		dst = ri->ri_font->fontheight * dst + num - 1;
556		srp = (int32_t *)(ri->ri_bits + src * ri->ri_stride);
557		drp = (int32_t *)(ri->ri_bits + dst * ri->ri_stride);
558		if (ri->ri_hwbits)
559			hrp = (int32_t *)(ri->ri_hwbits + dst *
560			    ri->ri_stride);
561
562		delta = -ri->ri_stride;
563	}
564
565	while (num--) {
566		dp = drp;
567		sp = srp;
568		if (ri->ri_hwbits)
569			hp = hrp;
570
571		DELTA(drp, delta, int32_t *);
572		DELTA(srp, delta, int32_t *);
573		if (ri->ri_hwbits)
574			DELTA(hrp, delta, int32_t *);
575
576		for (cnt = n8; cnt; cnt--) {
577			dp[0] = sp[0];
578			dp[1] = sp[1];
579			dp[2] = sp[2];
580			dp[3] = sp[3];
581			dp[4] = sp[4];
582			dp[5] = sp[5];
583			dp[6] = sp[6];
584			dp[7] = sp[7];
585			dp += 8;
586			sp += 8;
587		}
588		if (ri->ri_hwbits) {
589			sp -= (8 * n8);
590			for (cnt = n8; cnt; cnt--) {
591				hp[0] = sp[0];
592				hp[1] = sp[1];
593				hp[2] = sp[2];
594				hp[3] = sp[3];
595				hp[4] = sp[4];
596				hp[5] = sp[5];
597				hp[6] = sp[6];
598				hp[7] = sp[7];
599				hp += 8;
600				sp += 8;
601			}
602		}
603
604		for (cnt = n1; cnt; cnt--) {
605			*dp++ = *sp++;
606			if (ri->ri_hwbits)
607				*hp++ = *(sp - 1);
608		}
609	}
610}
611
612/*
613 * Copy columns. This is slow, and hard to optimize due to alignment,
614 * and the fact that we have to copy both left->right and right->left.
615 * We simply cop-out here and use memmove(), since it handles all of
616 * these cases anyway.
617 */
618void
619rasops_copycols(cookie, row, src, dst, num)
620	void *cookie;
621	int row, src, dst, num;
622{
623	struct rasops_info *ri;
624	u_char *sp, *dp, *hp;
625	int height;
626
627	ri = (struct rasops_info *)cookie;
628	hp = NULL;
629
630#ifdef RASOPS_CLIPPING
631	if (dst == src)
632		return;
633
634	/* Catches < 0 case too */
635	if ((unsigned)row >= (unsigned)ri->ri_rows)
636		return;
637
638	if (src < 0) {
639		num += src;
640		src = 0;
641	}
642
643	if ((src + num) > ri->ri_cols)
644		num = ri->ri_cols - src;
645
646	if (dst < 0) {
647		num += dst;
648		dst = 0;
649	}
650
651	if ((dst + num) > ri->ri_cols)
652		num = ri->ri_cols - dst;
653
654	if (num <= 0)
655		return;
656#endif
657
658	num *= ri->ri_xscale;
659	row *= ri->ri_yscale;
660	height = ri->ri_font->fontheight;
661
662	sp = ri->ri_bits + row + src * ri->ri_xscale;
663	dp = ri->ri_bits + row + dst * ri->ri_xscale;
664	if (ri->ri_hwbits)
665		hp = ri->ri_hwbits + row + dst * ri->ri_xscale;
666
667	while (height--) {
668		memmove(dp, sp, num);
669		if (ri->ri_hwbits) {
670			memcpy(hp, sp, num);
671			hp += ri->ri_stride;
672		}
673		dp += ri->ri_stride;
674		sp += ri->ri_stride;
675	}
676}
677
678/*
679 * Turn cursor off/on.
680 */
681static void
682rasops_cursor(cookie, on, row, col)
683	void *cookie;
684	int on, row, col;
685{
686	struct rasops_info *ri;
687
688	ri = (struct rasops_info *)cookie;
689
690	/* Turn old cursor off */
691	if ((ri->ri_flg & RI_CURSOR) != 0)
692#ifdef RASOPS_CLIPPING
693		if ((ri->ri_flg & RI_CURSORCLIP) == 0)
694#endif
695			ri->ri_do_cursor(ri);
696
697	/* Select new cursor */
698#ifdef RASOPS_CLIPPING
699	ri->ri_flg &= ~RI_CURSORCLIP;
700
701	if (row < 0 || row >= ri->ri_rows)
702		ri->ri_flg |= RI_CURSORCLIP;
703	else if (col < 0 || col >= ri->ri_cols)
704		ri->ri_flg |= RI_CURSORCLIP;
705#endif
706	ri->ri_crow = row;
707	ri->ri_ccol = col;
708
709	if (on) {
710		ri->ri_flg |= RI_CURSOR;
711#ifdef RASOPS_CLIPPING
712		if ((ri->ri_flg & RI_CURSORCLIP) == 0)
713#endif
714			ri->ri_do_cursor(ri);
715	} else
716		ri->ri_flg &= ~RI_CURSOR;
717}
718
719/*
720 * Make the device colormap
721 */
722static void
723rasops_init_devcmap(ri)
724	struct rasops_info *ri;
725{
726	const u_char *p;
727	int i, c;
728
729	switch (ri->ri_depth) {
730	case 1:
731		ri->ri_devcmap[0] = 0;
732		for (i = 1; i < 16; i++)
733			ri->ri_devcmap[i] = -1;
734		return;
735
736	case 2:
737		for (i = 1; i < 15; i++)
738			ri->ri_devcmap[i] = 0xaaaaaaaa;
739
740		ri->ri_devcmap[0] = 0;
741		ri->ri_devcmap[8] = 0x55555555;
742		ri->ri_devcmap[15] = -1;
743		return;
744
745	case 8:
746		for (i = 0; i < 16; i++)
747			ri->ri_devcmap[i] = i | (i<<8) | (i<<16) | (i<<24);
748		return;
749	}
750
751	p = rasops_cmap;
752
753	for (i = 0; i < 16; i++) {
754		if (ri->ri_rnum <= 8)
755			c = (*p >> (8 - ri->ri_rnum)) << ri->ri_rpos;
756		else
757			c = (*p << (ri->ri_rnum - 8)) << ri->ri_rpos;
758		p++;
759
760		if (ri->ri_gnum <= 8)
761			c |= (*p >> (8 - ri->ri_gnum)) << ri->ri_gpos;
762		else
763			c |= (*p << (ri->ri_gnum - 8)) << ri->ri_gpos;
764		p++;
765
766		if (ri->ri_bnum <= 8)
767			c |= (*p >> (8 - ri->ri_bnum)) << ri->ri_bpos;
768		else
769			c |= (*p << (ri->ri_bnum - 8)) << ri->ri_bpos;
770		p++;
771
772		/* Fill the word for generic routines, which want this */
773		if (ri->ri_depth == 24)
774			c = c | ((c & 0xff) << 24);
775		else if (ri->ri_depth <= 16)
776			c = c | (c << 16);
777
778		/* 24bpp does bswap on the fly. {32,16,15}bpp do it here. */
779		if ((ri->ri_flg & RI_BSWAP) == 0)
780			ri->ri_devcmap[i] = c;
781		else if (ri->ri_depth == 32)
782			ri->ri_devcmap[i] = bswap32(c);
783		else if (ri->ri_depth == 16 || ri->ri_depth == 15)
784			ri->ri_devcmap[i] = bswap16(c);
785		else
786			ri->ri_devcmap[i] = c;
787	}
788}
789
790/*
791 * Unpack a rasops attribute
792 */
793void
794rasops_unpack_attr(attr, fg, bg, underline)
795	long attr;
796	int *fg, *bg, *underline;
797{
798
799	*fg = ((u_int)attr >> 24) & 0xf;
800	*bg = ((u_int)attr >> 16) & 0xf;
801	if (underline != NULL)
802		*underline = (u_int)attr & 1;
803}
804
805/*
806 * Erase rows. This isn't static, since 24-bpp uses it in special cases.
807 */
808void
809rasops_eraserows(cookie, row, num, attr)
810	void *cookie;
811	int row, num;
812	long attr;
813{
814	struct rasops_info *ri;
815	int np, nw, cnt, delta;
816	int32_t *dp, *hp, clr;
817	int i;
818
819	ri = (struct rasops_info *)cookie;
820	hp = NULL;
821
822#ifdef RASOPS_CLIPPING
823	if (row < 0) {
824		num += row;
825		row = 0;
826	}
827
828	if ((row + num) > ri->ri_rows)
829		num = ri->ri_rows - row;
830
831	if (num <= 0)
832		return;
833#endif
834
835	clr = ri->ri_devcmap[(attr >> 16) & 0xf];
836
837	/*
838	 * XXX The wsdisplay_emulops interface seems a little deficient in
839	 * that there is no way to clear the *entire* screen. We provide a
840	 * workaround here: if the entire console area is being cleared, and
841	 * the RI_FULLCLEAR flag is set, clear the entire display.
842	 */
843	if (num == ri->ri_rows && (ri->ri_flg & RI_FULLCLEAR) != 0) {
844		np = ri->ri_stride >> 5;
845		nw = (ri->ri_stride >> 2) & 7;
846		num = ri->ri_height;
847		dp = (int32_t *)ri->ri_origbits;
848		if (ri->ri_hwbits)
849			hp = (int32_t *)ri->ri_hwbits;
850		delta = 0;
851	} else {
852		np = ri->ri_emustride >> 5;
853		nw = (ri->ri_emustride >> 2) & 7;
854		num *= ri->ri_font->fontheight;
855		dp = (int32_t *)(ri->ri_bits + row * ri->ri_yscale);
856		if (ri->ri_hwbits)
857			hp = (int32_t *)(ri->ri_hwbits + row *
858			    ri->ri_yscale);
859		delta = ri->ri_delta;
860	}
861
862	while (num--) {
863		for (cnt = np; cnt; cnt--) {
864			for (i = 0; i < 8; i++) {
865				dp[i] = clr;
866				if (ri->ri_hwbits)
867					hp[i] = clr;
868			}
869			dp += 8;
870			if (ri->ri_hwbits)
871				hp += 8;
872		}
873
874		for (cnt = nw; cnt; cnt--) {
875			*(int32_t *)dp = clr;
876			DELTA(dp, 4, int32_t *);
877			if (ri->ri_hwbits) {
878				*(int32_t *)hp = clr;
879				DELTA(hp, 4, int32_t *);
880			}
881		}
882
883		DELTA(dp, delta, int32_t *);
884		if (ri->ri_hwbits)
885			DELTA(hp, delta, int32_t *);
886	}
887}
888
889/*
890 * Actually turn the cursor on or off. This does the dirty work for
891 * rasops_cursor().
892 */
893static void
894rasops_do_cursor(ri)
895	struct rasops_info *ri;
896{
897	int full1, height, cnt, slop1, slop2, row, col;
898	u_char *dp, *rp, *hrp, *hp;
899
900	hrp = hp = NULL;
901
902#if NRASOPS_ROTATION > 0
903	if (ri->ri_flg & RI_ROTATE_CW) {
904		/* Rotate rows/columns */
905		row = ri->ri_ccol;
906		col = ri->ri_rows - ri->ri_crow - 1;
907	} else
908#endif
909	{
910		row = ri->ri_crow;
911		col = ri->ri_ccol;
912	}
913
914	rp = ri->ri_bits + row * ri->ri_yscale + col * ri->ri_xscale;
915	if (ri->ri_hwbits)
916		hrp = ri->ri_hwbits + row * ri->ri_yscale + col
917		    * ri->ri_xscale;
918	height = ri->ri_font->fontheight;
919	slop1 = (4 - ((long)rp & 3)) & 3;
920
921	if (slop1 > ri->ri_xscale)
922		slop1 = ri->ri_xscale;
923
924	slop2 = (ri->ri_xscale - slop1) & 3;
925	full1 = (ri->ri_xscale - slop1 - slop2) >> 2;
926
927	if ((slop1 | slop2) == 0) {
928		/* A common case */
929		while (height--) {
930			dp = rp;
931			rp += ri->ri_stride;
932			if (ri->ri_hwbits) {
933				hp = hrp;
934				hrp += ri->ri_stride;
935			}
936
937			for (cnt = full1; cnt; cnt--) {
938				*(int32_t *)dp ^= ~0;
939				dp += 4;
940				if (ri->ri_hwbits) {
941					dp -= 4;
942					*(int32_t *)hp = *(int32_t *)dp;
943					hp += 4;
944					dp += 4;
945				}
946			}
947		}
948	} else {
949		/* XXX this is stupid.. use masks instead */
950		while (height--) {
951			dp = rp;
952			rp += ri->ri_stride;
953			if (ri->ri_hwbits) {
954				hp = hrp;
955				hrp += ri->ri_stride;
956			}
957
958			if (slop1 & 1) {
959				*dp++ ^= ~0;
960				if (ri->ri_hwbits) {
961					*hp++ = *(dp - 1);
962				}
963			}
964
965			if (slop1 & 2) {
966				*(int16_t *)dp ^= ~0;
967				dp += 2;
968				if (ri->ri_hwbits) {
969					dp -= 2;
970					*(int16_t *)hp = *(int16_t *)dp;
971					hp += 2;
972					dp += 2;
973				}
974			}
975
976			for (cnt = full1; cnt; cnt--) {
977				*(int32_t *)dp ^= ~0;
978				dp += 4;
979				if (ri->ri_hwbits) {
980					dp -= 4;
981					*(int32_t *)hp = *(int32_t *)dp;
982					hp += 4;
983					dp += 4;
984				}
985			}
986
987			if (slop2 & 1) {
988				*dp++ ^= ~0;
989				if (ri->ri_hwbits)
990					*hp++ = *(dp - 1);
991			}
992
993			if (slop2 & 2) {
994				*(int16_t *)dp ^= ~0;
995				if (ri->ri_hwbits)
996					*(int16_t *)hp = *(int16_t *)(dp - 2);
997			}
998		}
999	}
1000}
1001
1002/*
1003 * Erase columns.
1004 */
1005void
1006rasops_erasecols(cookie, row, col, num, attr)
1007	void *cookie;
1008	int row, col, num;
1009	long attr;
1010{
1011	int n8, height, cnt, slop1, slop2, clr;
1012	struct rasops_info *ri;
1013	int32_t *rp, *dp, *hrp, *hp;
1014	int i;
1015
1016	ri = (struct rasops_info *)cookie;
1017	hrp = hp = NULL;
1018
1019#ifdef RASOPS_CLIPPING
1020	if ((unsigned)row >= (unsigned)ri->ri_rows)
1021		return;
1022
1023	if (col < 0) {
1024		num += col;
1025		col = 0;
1026	}
1027
1028	if ((col + num) > ri->ri_cols)
1029		num = ri->ri_cols - col;
1030
1031	if (num <= 0)
1032		return;
1033#endif
1034
1035	num = num * ri->ri_xscale;
1036	rp = (int32_t *)(ri->ri_bits + row*ri->ri_yscale + col*ri->ri_xscale);
1037	if (ri->ri_hwbits)
1038		hrp = (int32_t *)(ri->ri_hwbits + row*ri->ri_yscale +
1039		    col*ri->ri_xscale);
1040	height = ri->ri_font->fontheight;
1041	clr = ri->ri_devcmap[(attr >> 16) & 0xf];
1042
1043	/* Don't bother using the full loop for <= 32 pels */
1044	if (num <= 32) {
1045		if (((num | ri->ri_xscale) & 3) == 0) {
1046			/* Word aligned blt */
1047			num >>= 2;
1048
1049			while (height--) {
1050				dp = rp;
1051				DELTA(rp, ri->ri_stride, int32_t *);
1052				if (ri->ri_hwbits) {
1053					hp = hrp;
1054					DELTA(hrp, ri->ri_stride, int32_t *);
1055				}
1056
1057				for (cnt = num; cnt; cnt--) {
1058					*dp++ = clr;
1059					if (ri->ri_hwbits)
1060						*hp++ = clr;
1061				}
1062			}
1063		} else if (((num | ri->ri_xscale) & 1) == 0) {
1064			/*
1065			 * Halfword aligned blt. This is needed so the
1066			 * 15/16 bit ops can use this function.
1067			 */
1068			num >>= 1;
1069
1070			while (height--) {
1071				dp = rp;
1072				DELTA(rp, ri->ri_stride, int32_t *);
1073				if (ri->ri_hwbits) {
1074					hp = hrp;
1075					DELTA(hrp, ri->ri_stride, int32_t *);
1076				}
1077
1078				for (cnt = num; cnt; cnt--) {
1079					*(int16_t *)dp = clr;
1080					DELTA(dp, 2, int32_t *);
1081					if (ri->ri_hwbits) {
1082						*(int16_t *)hp = clr;
1083						DELTA(hp, 2, int32_t *);
1084					}
1085				}
1086			}
1087		} else {
1088			while (height--) {
1089				dp = rp;
1090				DELTA(rp, ri->ri_stride, int32_t *);
1091				if (ri->ri_hwbits) {
1092					hp = hrp;
1093					DELTA(hrp, ri->ri_stride, int32_t *);
1094				}
1095
1096				for (cnt = num; cnt; cnt--) {
1097					*(u_char *)dp = clr;
1098					DELTA(dp, 1, int32_t *);
1099					if (ri->ri_hwbits) {
1100						*(u_char *)hp = clr;
1101						DELTA(hp, 1, int32_t *);
1102					}
1103				}
1104			}
1105		}
1106
1107		return;
1108	}
1109
1110	slop1 = (4 - ((long)rp & 3)) & 3;
1111	slop2 = (num - slop1) & 3;
1112	num -= slop1 + slop2;
1113	n8 = num >> 5;
1114	num = (num >> 2) & 7;
1115
1116	while (height--) {
1117		dp = rp;
1118		DELTA(rp, ri->ri_stride, int32_t *);
1119		if (ri->ri_hwbits) {
1120			hp = hrp;
1121			DELTA(hrp, ri->ri_stride, int32_t *);
1122		}
1123
1124		/* Align span to 4 bytes */
1125		if (slop1 & 1) {
1126			*(u_char *)dp = clr;
1127			DELTA(dp, 1, int32_t *);
1128			if (ri->ri_hwbits) {
1129				*(u_char *)hp = clr;
1130				DELTA(hp, 1, int32_t *);
1131			}
1132		}
1133
1134		if (slop1 & 2) {
1135			*(int16_t *)dp = clr;
1136			DELTA(dp, 2, int32_t *);
1137			if (ri->ri_hwbits) {
1138				*(int16_t *)hp = clr;
1139				DELTA(hp, 2, int32_t *);
1140			}
1141		}
1142
1143		/* Write 32 bytes per loop */
1144		for (cnt = n8; cnt; cnt--) {
1145			for (i = 0; i < 8; i++) {
1146				dp[i] = clr;
1147				if (ri->ri_hwbits)
1148					hp[i] = clr;
1149			}
1150			dp += 8;
1151			if (ri->ri_hwbits)
1152				hp += 8;
1153		}
1154
1155		/* Write 4 bytes per loop */
1156		for (cnt = num; cnt; cnt--) {
1157			*dp++ = clr;
1158			if (ri->ri_hwbits)
1159				*hp++ = clr;
1160		}
1161
1162		/* Write unaligned trailing slop */
1163		if (slop2 & 1) {
1164			*(u_char *)dp = clr;
1165			DELTA(dp, 1, int32_t *);
1166			if (ri->ri_hwbits) {
1167				*(u_char *)hp = clr;
1168				DELTA(hp, 1, int32_t *);
1169			}
1170		}
1171
1172		if (slop2 & 2) {
1173			*(int16_t *)dp = clr;
1174			if (ri->ri_hwbits)
1175				*(int16_t *)hp = clr;
1176		}
1177	}
1178}
1179
1180#if NRASOPS_ROTATION > 0
1181/*
1182 * Quarter clockwise rotation routines (originally intended for the
1183 * built-in Zaurus C3x00 display in 16bpp).
1184 */
1185
1186#include <sys/malloc.h>
1187
1188static void
1189rasops_rotate_font(int *cookie)
1190{
1191	struct rotatedfont *f;
1192	int ncookie;
1193
1194	SLIST_FOREACH(f, &rotatedfonts, rf_next) {
1195		if (f->rf_cookie == *cookie) {
1196			*cookie = f->rf_rotated;
1197			return;
1198		}
1199	}
1200
1201	/*
1202	 * We did not find a rotated version of this font. Ask the wsfont
1203	 * code to compute one for us.
1204	 */
1205
1206	f = malloc(sizeof(struct rotatedfont), M_DEVBUF, M_WAITOK);
1207	if (f == NULL)
1208		return;
1209
1210	if ((ncookie = wsfont_rotate(*cookie)) == -1)
1211		return;
1212
1213	f->rf_cookie = *cookie;
1214	f->rf_rotated = ncookie;
1215	SLIST_INSERT_HEAD(&rotatedfonts, f, rf_next);
1216
1217	*cookie = ncookie;
1218}
1219
1220static void
1221rasops_copychar(cookie, srcrow, dstrow, srccol, dstcol)
1222	void *cookie;
1223	int srcrow, dstrow, srccol, dstcol;
1224{
1225	struct rasops_info *ri;
1226	u_char *sp, *dp;
1227	int height;
1228	int r_srcrow, r_dstrow, r_srccol, r_dstcol;
1229
1230	ri = (struct rasops_info *)cookie;
1231
1232	r_srcrow = srccol;
1233	r_dstrow = dstcol;
1234	r_srccol = ri->ri_rows - srcrow - 1;
1235	r_dstcol = ri->ri_rows - dstrow - 1;
1236
1237	r_srcrow *= ri->ri_yscale;
1238	r_dstrow *= ri->ri_yscale;
1239	height = ri->ri_font->fontheight;
1240
1241	sp = ri->ri_bits + r_srcrow + r_srccol * ri->ri_xscale;
1242	dp = ri->ri_bits + r_dstrow + r_dstcol * ri->ri_xscale;
1243
1244	while (height--) {
1245		memmove(dp, sp, ri->ri_xscale);
1246		dp += ri->ri_stride;
1247		sp += ri->ri_stride;
1248	}
1249}
1250
1251static void
1252rasops_putchar_rotated(cookie, row, col, uc, attr)
1253	void *cookie;
1254	int row, col;
1255	u_int uc;
1256	long attr;
1257{
1258	struct rasops_info *ri;
1259	u_char *rp;
1260	int height;
1261
1262	ri = (struct rasops_info *)cookie;
1263
1264	if (__predict_false((unsigned int)row > ri->ri_rows ||
1265	    (unsigned int)col > ri->ri_cols))
1266		return;
1267
1268	/* Avoid underflow */
1269	if ((ri->ri_rows - row - 1) < 0)
1270		return;
1271
1272	/* Do rotated char sans (side)underline */
1273	ri->ri_real_ops.putchar(cookie, col, ri->ri_rows - row - 1, uc,
1274	    attr & ~1);
1275
1276	/* Do rotated underline */
1277	rp = ri->ri_bits + col * ri->ri_yscale + (ri->ri_rows - row - 1) *
1278	    ri->ri_xscale;
1279	height = ri->ri_font->fontheight;
1280
1281	/* XXX this assumes 16-bit color depth */
1282	if ((attr & 1) != 0) {
1283		int16_t c = (int16_t)ri->ri_devcmap[((u_int)attr >> 24) & 0xf];
1284
1285		while (height--) {
1286			*(int16_t *)rp = c;
1287			rp += ri->ri_stride;
1288		}
1289	}
1290}
1291
1292static void
1293rasops_erasecols_rotated(cookie, row, col, num, attr)
1294	void *cookie;
1295	int row, col, num;
1296	long attr;
1297{
1298	struct rasops_info *ri;
1299	int i;
1300
1301	ri = (struct rasops_info *)cookie;
1302
1303	for (i = col; i < col + num; i++)
1304		ri->ri_ops.putchar(cookie, row, i, ' ', attr);
1305}
1306
1307/* XXX: these could likely be optimised somewhat. */
1308static void
1309rasops_copyrows_rotated(cookie, src, dst, num)
1310	void *cookie;
1311	int src, dst, num;
1312{
1313	struct rasops_info *ri = (struct rasops_info *)cookie;
1314	int col, roff;
1315
1316	if (src > dst)
1317		for (roff = 0; roff < num; roff++)
1318			for (col = 0; col < ri->ri_cols; col++)
1319				rasops_copychar(cookie, src + roff, dst + roff,
1320				    col, col);
1321	else
1322		for (roff = num - 1; roff >= 0; roff--)
1323			for (col = 0; col < ri->ri_cols; col++)
1324				rasops_copychar(cookie, src + roff, dst + roff,
1325				    col, col);
1326}
1327
1328static void
1329rasops_copycols_rotated(cookie, row, src, dst, num)
1330	void *cookie;
1331	int row, src, dst, num;
1332{
1333	int coff;
1334
1335	if (src > dst)
1336		for (coff = 0; coff < num; coff++)
1337			rasops_copychar(cookie, row, row, src + coff, dst + coff);
1338	else
1339		for (coff = num - 1; coff >= 0; coff--)
1340			rasops_copychar(cookie, row, row, src + coff, dst + coff);
1341}
1342
1343static void
1344rasops_eraserows_rotated(cookie, row, num, attr)
1345	void *cookie;
1346	int row, num;
1347	long attr;
1348{
1349	struct rasops_info *ri;
1350	int col, rn;
1351
1352	ri = (struct rasops_info *)cookie;
1353
1354	for (rn = row; rn < row + num; rn++)
1355		for (col = 0; col < ri->ri_cols; col++)
1356			ri->ri_ops.putchar(cookie, rn, col, ' ', attr);
1357}
1358#endif	/* NRASOPS_ROTATION */
1359