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