rasops.c revision 1.59
1/*	 $NetBSD: rasops.c,v 1.59 2009/03/14 15:36:20 dsl 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.59 2009/03/14 15:36:20 dsl 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(void *cookie, int c, u_int *cp)
389{
390	struct rasops_info *ri;
391
392	ri = (struct rasops_info *)cookie;
393
394#ifdef DIAGNOSTIC
395	if (ri->ri_font == NULL)
396		panic("rasops_mapchar: no font selected");
397#endif
398
399	if (ri->ri_font->encoding != WSDISPLAY_FONTENC_ISO) {
400		if ( (c = wsfont_map_unichar(ri->ri_font, c)) < 0) {
401			*cp = ' ';
402			return (0);
403
404		}
405	}
406
407	if (c < ri->ri_font->firstchar) {
408		*cp = ' ';
409		return (0);
410	}
411
412	if (c - ri->ri_font->firstchar >= ri->ri_font->numchars) {
413		*cp = ' ';
414		return (0);
415	}
416
417	*cp = c;
418	return (5);
419}
420
421/*
422 * Allocate a color attribute.
423 */
424static int
425rasops_allocattr_color(void *cookie, int fg, int bg, int flg,
426    long *attr)
427{
428	int swap;
429
430	if (__predict_false((unsigned int)fg >= sizeof(rasops_isgray) ||
431	    (unsigned int)bg >= sizeof(rasops_isgray)))
432		return (EINVAL);
433
434#ifdef RASOPS_CLIPPING
435	fg &= 7;
436	bg &= 7;
437#endif
438	if ((flg & WSATTR_BLINK) != 0)
439		return (EINVAL);
440
441	if ((flg & WSATTR_WSCOLORS) == 0) {
442#ifdef WS_DEFAULT_FG
443		fg = WS_DEFAULT_FG;
444#else
445		fg = WSCOL_WHITE;
446#endif
447#ifdef WS_DEFAULT_BG
448		bg = WS_DEFAULT_BG;
449#else
450		bg = WSCOL_BLACK;
451#endif
452	}
453
454	if ((flg & WSATTR_REVERSE) != 0) {
455		swap = fg;
456		fg = bg;
457		bg = swap;
458	}
459
460	if ((flg & WSATTR_HILIT) != 0)
461		fg += 8;
462
463	flg = ((flg & WSATTR_UNDERLINE) ? 1 : 0);
464
465	if (rasops_isgray[fg])
466		flg |= 2;
467
468	if (rasops_isgray[bg])
469		flg |= 4;
470
471	*attr = (bg << 16) | (fg << 24) | flg;
472	return (0);
473}
474
475/*
476 * Allocate a mono attribute.
477 */
478static int
479rasops_allocattr_mono(void *cookie, int fg, int bg, int flg,
480    long *attr)
481{
482	int swap;
483
484	if ((flg & (WSATTR_BLINK | WSATTR_HILIT | WSATTR_WSCOLORS)) != 0)
485		return (EINVAL);
486
487	fg = 1;
488	bg = 0;
489
490	if ((flg & WSATTR_REVERSE) != 0) {
491		swap = fg;
492		fg = bg;
493		bg = swap;
494	}
495
496	*attr = (bg << 16) | (fg << 24) | ((flg & WSATTR_UNDERLINE) ? 7 : 6);
497	return (0);
498}
499
500/*
501 * Copy rows.
502 */
503static void
504rasops_copyrows(cookie, src, dst, num)
505	void *cookie;
506	int src, dst, num;
507{
508	int32_t *sp, *dp, *hp, *srp, *drp, *hrp;
509	struct rasops_info *ri;
510	int n8, n1, cnt, delta;
511
512	ri = (struct rasops_info *)cookie;
513	hp = hrp = NULL;
514
515#ifdef RASOPS_CLIPPING
516	if (dst == src)
517		return;
518
519	if (src < 0) {
520		num += src;
521		src = 0;
522	}
523
524	if ((src + num) > ri->ri_rows)
525		num = ri->ri_rows - src;
526
527	if (dst < 0) {
528		num += dst;
529		dst = 0;
530	}
531
532	if ((dst + num) > ri->ri_rows)
533		num = ri->ri_rows - dst;
534
535	if (num <= 0)
536		return;
537#endif
538
539	num *= ri->ri_font->fontheight;
540	n8 = ri->ri_emustride >> 5;
541	n1 = (ri->ri_emustride >> 2) & 7;
542
543	if (dst < src) {
544		srp = (int32_t *)(ri->ri_bits + src * ri->ri_yscale);
545		drp = (int32_t *)(ri->ri_bits + dst * ri->ri_yscale);
546		if (ri->ri_hwbits)
547			hrp = (int32_t *)(ri->ri_hwbits + dst *
548			    ri->ri_yscale);
549		delta = ri->ri_stride;
550	} else {
551		src = ri->ri_font->fontheight * src + num - 1;
552		dst = ri->ri_font->fontheight * dst + num - 1;
553		srp = (int32_t *)(ri->ri_bits + src * ri->ri_stride);
554		drp = (int32_t *)(ri->ri_bits + dst * ri->ri_stride);
555		if (ri->ri_hwbits)
556			hrp = (int32_t *)(ri->ri_hwbits + dst *
557			    ri->ri_stride);
558
559		delta = -ri->ri_stride;
560	}
561
562	while (num--) {
563		dp = drp;
564		sp = srp;
565		if (ri->ri_hwbits)
566			hp = hrp;
567
568		DELTA(drp, delta, int32_t *);
569		DELTA(srp, delta, int32_t *);
570		if (ri->ri_hwbits)
571			DELTA(hrp, delta, int32_t *);
572
573		for (cnt = n8; cnt; cnt--) {
574			dp[0] = sp[0];
575			dp[1] = sp[1];
576			dp[2] = sp[2];
577			dp[3] = sp[3];
578			dp[4] = sp[4];
579			dp[5] = sp[5];
580			dp[6] = sp[6];
581			dp[7] = sp[7];
582			dp += 8;
583			sp += 8;
584		}
585		if (ri->ri_hwbits) {
586			sp -= (8 * n8);
587			for (cnt = n8; cnt; cnt--) {
588				hp[0] = sp[0];
589				hp[1] = sp[1];
590				hp[2] = sp[2];
591				hp[3] = sp[3];
592				hp[4] = sp[4];
593				hp[5] = sp[5];
594				hp[6] = sp[6];
595				hp[7] = sp[7];
596				hp += 8;
597				sp += 8;
598			}
599		}
600
601		for (cnt = n1; cnt; cnt--) {
602			*dp++ = *sp++;
603			if (ri->ri_hwbits)
604				*hp++ = *(sp - 1);
605		}
606	}
607}
608
609/*
610 * Copy columns. This is slow, and hard to optimize due to alignment,
611 * and the fact that we have to copy both left->right and right->left.
612 * We simply cop-out here and use memmove(), since it handles all of
613 * these cases anyway.
614 */
615void
616rasops_copycols(cookie, row, src, dst, num)
617	void *cookie;
618	int row, src, dst, num;
619{
620	struct rasops_info *ri;
621	u_char *sp, *dp, *hp;
622	int height;
623
624	ri = (struct rasops_info *)cookie;
625	hp = NULL;
626
627#ifdef RASOPS_CLIPPING
628	if (dst == src)
629		return;
630
631	/* Catches < 0 case too */
632	if ((unsigned)row >= (unsigned)ri->ri_rows)
633		return;
634
635	if (src < 0) {
636		num += src;
637		src = 0;
638	}
639
640	if ((src + num) > ri->ri_cols)
641		num = ri->ri_cols - src;
642
643	if (dst < 0) {
644		num += dst;
645		dst = 0;
646	}
647
648	if ((dst + num) > ri->ri_cols)
649		num = ri->ri_cols - dst;
650
651	if (num <= 0)
652		return;
653#endif
654
655	num *= ri->ri_xscale;
656	row *= ri->ri_yscale;
657	height = ri->ri_font->fontheight;
658
659	sp = ri->ri_bits + row + src * ri->ri_xscale;
660	dp = ri->ri_bits + row + dst * ri->ri_xscale;
661	if (ri->ri_hwbits)
662		hp = ri->ri_hwbits + row + dst * ri->ri_xscale;
663
664	while (height--) {
665		memmove(dp, sp, num);
666		if (ri->ri_hwbits) {
667			memcpy(hp, sp, num);
668			hp += ri->ri_stride;
669		}
670		dp += ri->ri_stride;
671		sp += ri->ri_stride;
672	}
673}
674
675/*
676 * Turn cursor off/on.
677 */
678static void
679rasops_cursor(cookie, on, row, col)
680	void *cookie;
681	int on, row, col;
682{
683	struct rasops_info *ri;
684
685	ri = (struct rasops_info *)cookie;
686
687	/* Turn old cursor off */
688	if ((ri->ri_flg & RI_CURSOR) != 0)
689#ifdef RASOPS_CLIPPING
690		if ((ri->ri_flg & RI_CURSORCLIP) == 0)
691#endif
692			ri->ri_do_cursor(ri);
693
694	/* Select new cursor */
695#ifdef RASOPS_CLIPPING
696	ri->ri_flg &= ~RI_CURSORCLIP;
697
698	if (row < 0 || row >= ri->ri_rows)
699		ri->ri_flg |= RI_CURSORCLIP;
700	else if (col < 0 || col >= ri->ri_cols)
701		ri->ri_flg |= RI_CURSORCLIP;
702#endif
703	ri->ri_crow = row;
704	ri->ri_ccol = col;
705
706	if (on) {
707		ri->ri_flg |= RI_CURSOR;
708#ifdef RASOPS_CLIPPING
709		if ((ri->ri_flg & RI_CURSORCLIP) == 0)
710#endif
711			ri->ri_do_cursor(ri);
712	} else
713		ri->ri_flg &= ~RI_CURSOR;
714}
715
716/*
717 * Make the device colormap
718 */
719static void
720rasops_init_devcmap(struct rasops_info *ri)
721{
722	const u_char *p;
723	int i, c;
724
725	switch (ri->ri_depth) {
726	case 1:
727		ri->ri_devcmap[0] = 0;
728		for (i = 1; i < 16; i++)
729			ri->ri_devcmap[i] = -1;
730		return;
731
732	case 2:
733		for (i = 1; i < 15; i++)
734			ri->ri_devcmap[i] = 0xaaaaaaaa;
735
736		ri->ri_devcmap[0] = 0;
737		ri->ri_devcmap[8] = 0x55555555;
738		ri->ri_devcmap[15] = -1;
739		return;
740
741	case 8:
742		for (i = 0; i < 16; i++)
743			ri->ri_devcmap[i] = i | (i<<8) | (i<<16) | (i<<24);
744		return;
745	}
746
747	p = rasops_cmap;
748
749	for (i = 0; i < 16; i++) {
750		if (ri->ri_rnum <= 8)
751			c = (*p >> (8 - ri->ri_rnum)) << ri->ri_rpos;
752		else
753			c = (*p << (ri->ri_rnum - 8)) << ri->ri_rpos;
754		p++;
755
756		if (ri->ri_gnum <= 8)
757			c |= (*p >> (8 - ri->ri_gnum)) << ri->ri_gpos;
758		else
759			c |= (*p << (ri->ri_gnum - 8)) << ri->ri_gpos;
760		p++;
761
762		if (ri->ri_bnum <= 8)
763			c |= (*p >> (8 - ri->ri_bnum)) << ri->ri_bpos;
764		else
765			c |= (*p << (ri->ri_bnum - 8)) << ri->ri_bpos;
766		p++;
767
768		/* Fill the word for generic routines, which want this */
769		if (ri->ri_depth == 24)
770			c = c | ((c & 0xff) << 24);
771		else if (ri->ri_depth <= 16)
772			c = c | (c << 16);
773
774		/* 24bpp does bswap on the fly. {32,16,15}bpp do it here. */
775		if ((ri->ri_flg & RI_BSWAP) == 0)
776			ri->ri_devcmap[i] = c;
777		else if (ri->ri_depth == 32)
778			ri->ri_devcmap[i] = bswap32(c);
779		else if (ri->ri_depth == 16 || ri->ri_depth == 15)
780			ri->ri_devcmap[i] = bswap16(c);
781		else
782			ri->ri_devcmap[i] = c;
783	}
784}
785
786/*
787 * Unpack a rasops attribute
788 */
789void
790rasops_unpack_attr(attr, fg, bg, underline)
791	long attr;
792	int *fg, *bg, *underline;
793{
794
795	*fg = ((u_int)attr >> 24) & 0xf;
796	*bg = ((u_int)attr >> 16) & 0xf;
797	if (underline != NULL)
798		*underline = (u_int)attr & 1;
799}
800
801/*
802 * Erase rows. This isn't static, since 24-bpp uses it in special cases.
803 */
804void
805rasops_eraserows(cookie, row, num, attr)
806	void *cookie;
807	int row, num;
808	long attr;
809{
810	struct rasops_info *ri;
811	int np, nw, cnt, delta;
812	int32_t *dp, *hp, clr;
813	int i;
814
815	ri = (struct rasops_info *)cookie;
816	hp = NULL;
817
818#ifdef RASOPS_CLIPPING
819	if (row < 0) {
820		num += row;
821		row = 0;
822	}
823
824	if ((row + num) > ri->ri_rows)
825		num = ri->ri_rows - row;
826
827	if (num <= 0)
828		return;
829#endif
830
831	clr = ri->ri_devcmap[(attr >> 16) & 0xf];
832
833	/*
834	 * XXX The wsdisplay_emulops interface seems a little deficient in
835	 * that there is no way to clear the *entire* screen. We provide a
836	 * workaround here: if the entire console area is being cleared, and
837	 * the RI_FULLCLEAR flag is set, clear the entire display.
838	 */
839	if (num == ri->ri_rows && (ri->ri_flg & RI_FULLCLEAR) != 0) {
840		np = ri->ri_stride >> 5;
841		nw = (ri->ri_stride >> 2) & 7;
842		num = ri->ri_height;
843		dp = (int32_t *)ri->ri_origbits;
844		if (ri->ri_hwbits)
845			hp = (int32_t *)ri->ri_hwbits;
846		delta = 0;
847	} else {
848		np = ri->ri_emustride >> 5;
849		nw = (ri->ri_emustride >> 2) & 7;
850		num *= ri->ri_font->fontheight;
851		dp = (int32_t *)(ri->ri_bits + row * ri->ri_yscale);
852		if (ri->ri_hwbits)
853			hp = (int32_t *)(ri->ri_hwbits + row *
854			    ri->ri_yscale);
855		delta = ri->ri_delta;
856	}
857
858	while (num--) {
859		for (cnt = np; cnt; cnt--) {
860			for (i = 0; i < 8; i++) {
861				dp[i] = clr;
862				if (ri->ri_hwbits)
863					hp[i] = clr;
864			}
865			dp += 8;
866			if (ri->ri_hwbits)
867				hp += 8;
868		}
869
870		for (cnt = nw; cnt; cnt--) {
871			*(int32_t *)dp = clr;
872			DELTA(dp, 4, int32_t *);
873			if (ri->ri_hwbits) {
874				*(int32_t *)hp = clr;
875				DELTA(hp, 4, int32_t *);
876			}
877		}
878
879		DELTA(dp, delta, int32_t *);
880		if (ri->ri_hwbits)
881			DELTA(hp, delta, int32_t *);
882	}
883}
884
885/*
886 * Actually turn the cursor on or off. This does the dirty work for
887 * rasops_cursor().
888 */
889static void
890rasops_do_cursor(struct rasops_info *ri)
891{
892	int full1, height, cnt, slop1, slop2, row, col;
893	u_char *dp, *rp, *hrp, *hp;
894
895	hrp = hp = NULL;
896
897#if NRASOPS_ROTATION > 0
898	if (ri->ri_flg & RI_ROTATE_CW) {
899		/* Rotate rows/columns */
900		row = ri->ri_ccol;
901		col = ri->ri_rows - ri->ri_crow - 1;
902	} else
903#endif
904	{
905		row = ri->ri_crow;
906		col = ri->ri_ccol;
907	}
908
909	rp = ri->ri_bits + row * ri->ri_yscale + col * ri->ri_xscale;
910	if (ri->ri_hwbits)
911		hrp = ri->ri_hwbits + row * ri->ri_yscale + col
912		    * ri->ri_xscale;
913	height = ri->ri_font->fontheight;
914	slop1 = (4 - ((long)rp & 3)) & 3;
915
916	if (slop1 > ri->ri_xscale)
917		slop1 = ri->ri_xscale;
918
919	slop2 = (ri->ri_xscale - slop1) & 3;
920	full1 = (ri->ri_xscale - slop1 - slop2) >> 2;
921
922	if ((slop1 | slop2) == 0) {
923		/* A common case */
924		while (height--) {
925			dp = rp;
926			rp += ri->ri_stride;
927			if (ri->ri_hwbits) {
928				hp = hrp;
929				hrp += ri->ri_stride;
930			}
931
932			for (cnt = full1; cnt; cnt--) {
933				*(int32_t *)dp ^= ~0;
934				dp += 4;
935				if (ri->ri_hwbits) {
936					dp -= 4;
937					*(int32_t *)hp = *(int32_t *)dp;
938					hp += 4;
939					dp += 4;
940				}
941			}
942		}
943	} else {
944		/* XXX this is stupid.. use masks instead */
945		while (height--) {
946			dp = rp;
947			rp += ri->ri_stride;
948			if (ri->ri_hwbits) {
949				hp = hrp;
950				hrp += ri->ri_stride;
951			}
952
953			if (slop1 & 1) {
954				*dp++ ^= ~0;
955				if (ri->ri_hwbits) {
956					*hp++ = *(dp - 1);
957				}
958			}
959
960			if (slop1 & 2) {
961				*(int16_t *)dp ^= ~0;
962				dp += 2;
963				if (ri->ri_hwbits) {
964					dp -= 2;
965					*(int16_t *)hp = *(int16_t *)dp;
966					hp += 2;
967					dp += 2;
968				}
969			}
970
971			for (cnt = full1; cnt; cnt--) {
972				*(int32_t *)dp ^= ~0;
973				dp += 4;
974				if (ri->ri_hwbits) {
975					dp -= 4;
976					*(int32_t *)hp = *(int32_t *)dp;
977					hp += 4;
978					dp += 4;
979				}
980			}
981
982			if (slop2 & 1) {
983				*dp++ ^= ~0;
984				if (ri->ri_hwbits)
985					*hp++ = *(dp - 1);
986			}
987
988			if (slop2 & 2) {
989				*(int16_t *)dp ^= ~0;
990				if (ri->ri_hwbits)
991					*(int16_t *)hp = *(int16_t *)(dp - 2);
992			}
993		}
994	}
995}
996
997/*
998 * Erase columns.
999 */
1000void
1001rasops_erasecols(cookie, row, col, num, attr)
1002	void *cookie;
1003	int row, col, num;
1004	long attr;
1005{
1006	int n8, height, cnt, slop1, slop2, clr;
1007	struct rasops_info *ri;
1008	int32_t *rp, *dp, *hrp, *hp;
1009	int i;
1010
1011	ri = (struct rasops_info *)cookie;
1012	hrp = hp = NULL;
1013
1014#ifdef RASOPS_CLIPPING
1015	if ((unsigned)row >= (unsigned)ri->ri_rows)
1016		return;
1017
1018	if (col < 0) {
1019		num += col;
1020		col = 0;
1021	}
1022
1023	if ((col + num) > ri->ri_cols)
1024		num = ri->ri_cols - col;
1025
1026	if (num <= 0)
1027		return;
1028#endif
1029
1030	num = num * ri->ri_xscale;
1031	rp = (int32_t *)(ri->ri_bits + row*ri->ri_yscale + col*ri->ri_xscale);
1032	if (ri->ri_hwbits)
1033		hrp = (int32_t *)(ri->ri_hwbits + row*ri->ri_yscale +
1034		    col*ri->ri_xscale);
1035	height = ri->ri_font->fontheight;
1036	clr = ri->ri_devcmap[(attr >> 16) & 0xf];
1037
1038	/* Don't bother using the full loop for <= 32 pels */
1039	if (num <= 32) {
1040		if (((num | ri->ri_xscale) & 3) == 0) {
1041			/* Word aligned blt */
1042			num >>= 2;
1043
1044			while (height--) {
1045				dp = rp;
1046				DELTA(rp, ri->ri_stride, int32_t *);
1047				if (ri->ri_hwbits) {
1048					hp = hrp;
1049					DELTA(hrp, ri->ri_stride, int32_t *);
1050				}
1051
1052				for (cnt = num; cnt; cnt--) {
1053					*dp++ = clr;
1054					if (ri->ri_hwbits)
1055						*hp++ = clr;
1056				}
1057			}
1058		} else if (((num | ri->ri_xscale) & 1) == 0) {
1059			/*
1060			 * Halfword aligned blt. This is needed so the
1061			 * 15/16 bit ops can use this function.
1062			 */
1063			num >>= 1;
1064
1065			while (height--) {
1066				dp = rp;
1067				DELTA(rp, ri->ri_stride, int32_t *);
1068				if (ri->ri_hwbits) {
1069					hp = hrp;
1070					DELTA(hrp, ri->ri_stride, int32_t *);
1071				}
1072
1073				for (cnt = num; cnt; cnt--) {
1074					*(int16_t *)dp = clr;
1075					DELTA(dp, 2, int32_t *);
1076					if (ri->ri_hwbits) {
1077						*(int16_t *)hp = clr;
1078						DELTA(hp, 2, int32_t *);
1079					}
1080				}
1081			}
1082		} else {
1083			while (height--) {
1084				dp = rp;
1085				DELTA(rp, ri->ri_stride, int32_t *);
1086				if (ri->ri_hwbits) {
1087					hp = hrp;
1088					DELTA(hrp, ri->ri_stride, int32_t *);
1089				}
1090
1091				for (cnt = num; cnt; cnt--) {
1092					*(u_char *)dp = clr;
1093					DELTA(dp, 1, int32_t *);
1094					if (ri->ri_hwbits) {
1095						*(u_char *)hp = clr;
1096						DELTA(hp, 1, int32_t *);
1097					}
1098				}
1099			}
1100		}
1101
1102		return;
1103	}
1104
1105	slop1 = (4 - ((long)rp & 3)) & 3;
1106	slop2 = (num - slop1) & 3;
1107	num -= slop1 + slop2;
1108	n8 = num >> 5;
1109	num = (num >> 2) & 7;
1110
1111	while (height--) {
1112		dp = rp;
1113		DELTA(rp, ri->ri_stride, int32_t *);
1114		if (ri->ri_hwbits) {
1115			hp = hrp;
1116			DELTA(hrp, ri->ri_stride, int32_t *);
1117		}
1118
1119		/* Align span to 4 bytes */
1120		if (slop1 & 1) {
1121			*(u_char *)dp = clr;
1122			DELTA(dp, 1, int32_t *);
1123			if (ri->ri_hwbits) {
1124				*(u_char *)hp = clr;
1125				DELTA(hp, 1, int32_t *);
1126			}
1127		}
1128
1129		if (slop1 & 2) {
1130			*(int16_t *)dp = clr;
1131			DELTA(dp, 2, int32_t *);
1132			if (ri->ri_hwbits) {
1133				*(int16_t *)hp = clr;
1134				DELTA(hp, 2, int32_t *);
1135			}
1136		}
1137
1138		/* Write 32 bytes per loop */
1139		for (cnt = n8; cnt; cnt--) {
1140			for (i = 0; i < 8; i++) {
1141				dp[i] = clr;
1142				if (ri->ri_hwbits)
1143					hp[i] = clr;
1144			}
1145			dp += 8;
1146			if (ri->ri_hwbits)
1147				hp += 8;
1148		}
1149
1150		/* Write 4 bytes per loop */
1151		for (cnt = num; cnt; cnt--) {
1152			*dp++ = clr;
1153			if (ri->ri_hwbits)
1154				*hp++ = clr;
1155		}
1156
1157		/* Write unaligned trailing slop */
1158		if (slop2 & 1) {
1159			*(u_char *)dp = clr;
1160			DELTA(dp, 1, int32_t *);
1161			if (ri->ri_hwbits) {
1162				*(u_char *)hp = clr;
1163				DELTA(hp, 1, int32_t *);
1164			}
1165		}
1166
1167		if (slop2 & 2) {
1168			*(int16_t *)dp = clr;
1169			if (ri->ri_hwbits)
1170				*(int16_t *)hp = clr;
1171		}
1172	}
1173}
1174
1175#if NRASOPS_ROTATION > 0
1176/*
1177 * Quarter clockwise rotation routines (originally intended for the
1178 * built-in Zaurus C3x00 display in 16bpp).
1179 */
1180
1181#include <sys/malloc.h>
1182
1183static void
1184rasops_rotate_font(int *cookie)
1185{
1186	struct rotatedfont *f;
1187	int ncookie;
1188
1189	SLIST_FOREACH(f, &rotatedfonts, rf_next) {
1190		if (f->rf_cookie == *cookie) {
1191			*cookie = f->rf_rotated;
1192			return;
1193		}
1194	}
1195
1196	/*
1197	 * We did not find a rotated version of this font. Ask the wsfont
1198	 * code to compute one for us.
1199	 */
1200
1201	f = malloc(sizeof(struct rotatedfont), M_DEVBUF, M_WAITOK);
1202	if (f == NULL)
1203		return;
1204
1205	if ((ncookie = wsfont_rotate(*cookie)) == -1)
1206		return;
1207
1208	f->rf_cookie = *cookie;
1209	f->rf_rotated = ncookie;
1210	SLIST_INSERT_HEAD(&rotatedfonts, f, rf_next);
1211
1212	*cookie = ncookie;
1213}
1214
1215static void
1216rasops_copychar(cookie, srcrow, dstrow, srccol, dstcol)
1217	void *cookie;
1218	int srcrow, dstrow, srccol, dstcol;
1219{
1220	struct rasops_info *ri;
1221	u_char *sp, *dp;
1222	int height;
1223	int r_srcrow, r_dstrow, r_srccol, r_dstcol;
1224
1225	ri = (struct rasops_info *)cookie;
1226
1227	r_srcrow = srccol;
1228	r_dstrow = dstcol;
1229	r_srccol = ri->ri_rows - srcrow - 1;
1230	r_dstcol = ri->ri_rows - dstrow - 1;
1231
1232	r_srcrow *= ri->ri_yscale;
1233	r_dstrow *= ri->ri_yscale;
1234	height = ri->ri_font->fontheight;
1235
1236	sp = ri->ri_bits + r_srcrow + r_srccol * ri->ri_xscale;
1237	dp = ri->ri_bits + r_dstrow + r_dstcol * ri->ri_xscale;
1238
1239	while (height--) {
1240		memmove(dp, sp, ri->ri_xscale);
1241		dp += ri->ri_stride;
1242		sp += ri->ri_stride;
1243	}
1244}
1245
1246static void
1247rasops_putchar_rotated(cookie, row, col, uc, attr)
1248	void *cookie;
1249	int row, col;
1250	u_int uc;
1251	long attr;
1252{
1253	struct rasops_info *ri;
1254	u_char *rp;
1255	int height;
1256
1257	ri = (struct rasops_info *)cookie;
1258
1259	if (__predict_false((unsigned int)row > ri->ri_rows ||
1260	    (unsigned int)col > ri->ri_cols))
1261		return;
1262
1263	/* Avoid underflow */
1264	if ((ri->ri_rows - row - 1) < 0)
1265		return;
1266
1267	/* Do rotated char sans (side)underline */
1268	ri->ri_real_ops.putchar(cookie, col, ri->ri_rows - row - 1, uc,
1269	    attr & ~1);
1270
1271	/* Do rotated underline */
1272	rp = ri->ri_bits + col * ri->ri_yscale + (ri->ri_rows - row - 1) *
1273	    ri->ri_xscale;
1274	height = ri->ri_font->fontheight;
1275
1276	/* XXX this assumes 16-bit color depth */
1277	if ((attr & 1) != 0) {
1278		int16_t c = (int16_t)ri->ri_devcmap[((u_int)attr >> 24) & 0xf];
1279
1280		while (height--) {
1281			*(int16_t *)rp = c;
1282			rp += ri->ri_stride;
1283		}
1284	}
1285}
1286
1287static void
1288rasops_erasecols_rotated(cookie, row, col, num, attr)
1289	void *cookie;
1290	int row, col, num;
1291	long attr;
1292{
1293	struct rasops_info *ri;
1294	int i;
1295
1296	ri = (struct rasops_info *)cookie;
1297
1298	for (i = col; i < col + num; i++)
1299		ri->ri_ops.putchar(cookie, row, i, ' ', attr);
1300}
1301
1302/* XXX: these could likely be optimised somewhat. */
1303static void
1304rasops_copyrows_rotated(cookie, src, dst, num)
1305	void *cookie;
1306	int src, dst, num;
1307{
1308	struct rasops_info *ri = (struct rasops_info *)cookie;
1309	int col, roff;
1310
1311	if (src > dst)
1312		for (roff = 0; roff < num; roff++)
1313			for (col = 0; col < ri->ri_cols; col++)
1314				rasops_copychar(cookie, src + roff, dst + roff,
1315				    col, col);
1316	else
1317		for (roff = num - 1; roff >= 0; roff--)
1318			for (col = 0; col < ri->ri_cols; col++)
1319				rasops_copychar(cookie, src + roff, dst + roff,
1320				    col, col);
1321}
1322
1323static void
1324rasops_copycols_rotated(cookie, row, src, dst, num)
1325	void *cookie;
1326	int row, src, dst, num;
1327{
1328	int coff;
1329
1330	if (src > dst)
1331		for (coff = 0; coff < num; coff++)
1332			rasops_copychar(cookie, row, row, src + coff, dst + coff);
1333	else
1334		for (coff = num - 1; coff >= 0; coff--)
1335			rasops_copychar(cookie, row, row, src + coff, dst + coff);
1336}
1337
1338static void
1339rasops_eraserows_rotated(cookie, row, num, attr)
1340	void *cookie;
1341	int row, num;
1342	long attr;
1343{
1344	struct rasops_info *ri;
1345	int col, rn;
1346
1347	ri = (struct rasops_info *)cookie;
1348
1349	for (rn = row; rn < row + num; rn++)
1350		for (col = 0; col < ri->ri_cols; col++)
1351			ri->ri_ops.putchar(cookie, rn, col, ' ', attr);
1352}
1353#endif	/* NRASOPS_ROTATION */
1354