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