xref: /openbsd-src/sys/dev/rasops/rasops.c (revision a28daedfc357b214be5c701aa8ba8adb29a7f1c2)
1 /*	$OpenBSD: rasops.c,v 1.19 2008/08/20 18:49:12 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 void	rasops_copycols(void *, int, int, int, int);
135 void	rasops_copyrows(void *, int, int, int);
136 int	rasops_mapchar(void *, int, u_int *);
137 void	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 void	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 void	rasops_copycols_rotated(void *, int, int, int, int);
149 void	rasops_copyrows_rotated(void *, int, int, int);
150 void	rasops_erasecols_rotated(void *, int, int, int, long);
151 void	rasops_eraserows_rotated(void *, int, int, long);
152 void	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 void
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;
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;
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 
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 ovbcopy(), since it handles all of
613  * these cases anyway.
614  */
615 void
616 rasops_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;
622 	int height;
623 
624 	ri = (struct rasops_info *)cookie;
625 
626 #ifdef RASOPS_CLIPPING
627 	if (dst == src)
628 		return;
629 
630 	/* Catches < 0 case too */
631 	if ((unsigned)row >= (unsigned)ri->ri_rows)
632 		return;
633 
634 	if (src < 0) {
635 		num += src;
636 		src = 0;
637 	}
638 
639 	if ((src + num) > ri->ri_cols)
640 		num = ri->ri_cols - src;
641 
642 	if (dst < 0) {
643 		num += dst;
644 		dst = 0;
645 	}
646 
647 	if ((dst + num) > ri->ri_cols)
648 		num = ri->ri_cols - dst;
649 
650 	if (num <= 0)
651 		return;
652 #endif
653 
654 	num *= ri->ri_xscale;
655 	row *= ri->ri_yscale;
656 	height = ri->ri_font->fontheight;
657 
658 	sp = ri->ri_bits + row + src * ri->ri_xscale;
659 	dp = ri->ri_bits + row + dst * ri->ri_xscale;
660 
661 #if NRASOPS_BSWAP > 0
662 	if (ri->ri_flg & RI_BSWAP) {
663 		while (height--) {
664 			slow_ovbcopy(sp, dp, num);
665 			dp += ri->ri_stride;
666 			sp += ri->ri_stride;
667 		}
668 	} else
669 #endif
670 	{
671 		while (height--) {
672 			ovbcopy(sp, dp, num);
673 			dp += ri->ri_stride;
674 			sp += ri->ri_stride;
675 		}
676 	}
677 }
678 
679 /*
680  * Turn cursor off/on.
681  */
682 void
683 rasops_cursor(cookie, on, row, col)
684 	void *cookie;
685 	int on, row, col;
686 {
687 	struct rasops_info *ri;
688 
689 	ri = (struct rasops_info *)cookie;
690 
691 	/* Turn old cursor off */
692 	if ((ri->ri_flg & RI_CURSOR) != 0)
693 #ifdef RASOPS_CLIPPING
694 		if ((ri->ri_flg & RI_CURSORCLIP) == 0)
695 #endif
696 			ri->ri_do_cursor(ri);
697 
698 	/* Select new cursor */
699 #ifdef RASOPS_CLIPPING
700 	ri->ri_flg &= ~RI_CURSORCLIP;
701 
702 	if (row < 0 || row >= ri->ri_rows)
703 		ri->ri_flg |= RI_CURSORCLIP;
704 	else if (col < 0 || col >= ri->ri_cols)
705 		ri->ri_flg |= RI_CURSORCLIP;
706 #endif
707 	ri->ri_crow = row;
708 	ri->ri_ccol = col;
709 
710 	if (ri->ri_updatecursor != NULL)
711 		ri->ri_updatecursor(ri);
712 
713 	if (on) {
714 		ri->ri_flg |= RI_CURSOR;
715 #ifdef RASOPS_CLIPPING
716 		if ((ri->ri_flg & RI_CURSORCLIP) == 0)
717 #endif
718 			ri->ri_do_cursor(ri);
719 	} else
720 		ri->ri_flg &= ~RI_CURSOR;
721 }
722 
723 /*
724  * Make the device colormap
725  */
726 void
727 rasops_init_devcmap(ri)
728 	struct rasops_info *ri;
729 {
730 	int i;
731 #if NRASOPS15 > 0 || NRASOPS16 > 0 || NRASOPS24 > 0 || NRASOPS32 > 0
732 	const u_char *p;
733 #endif
734 #if NRASOPS4 > 0 || NRASOPS15 > 0 || NRASOPS16 > 0 || NRASOPS24 > 0 || NRASOPS32 > 0
735 	int c;
736 #endif
737 
738 	if (ri->ri_depth == 1 || (ri->ri_flg & RI_FORCEMONO) != 0) {
739 		ri->ri_devcmap[0] = 0;
740 		for (i = 1; i < 16; i++)
741 			ri->ri_devcmap[i] = 0xffffffff;
742 		return;
743 	}
744 
745 	switch (ri->ri_depth) {
746 #if NRASOPS2 > 0
747 	case 2:
748 		for (i = 1; i < 15; i++)
749 			ri->ri_devcmap[i] = 0xaaaaaaaa;
750 
751 		ri->ri_devcmap[0] = 0;
752 		ri->ri_devcmap[8] = 0x55555555;
753 		ri->ri_devcmap[15] = 0xffffffff;
754 		return;
755 #endif
756 #if NRASOPS4 > 0
757 	case 4:
758 		for (i = 0; i < 16; i++) {
759 			c = i | (i << 4);
760 			ri->ri_devcmap[i] = c | (c<<8) | (c<<16) | (c<<24);
761 		}
762 		return;
763 #endif
764 #if NRASOPS8 > 0
765 	case 8:
766 		for (i = 0; i < 16; i++)
767 			ri->ri_devcmap[i] = i | (i<<8) | (i<<16) | (i<<24);
768 		return;
769 #endif
770 	default:
771 		break;
772 	}
773 
774 #if NRASOPS15 > 0 || NRASOPS16 > 0 || NRASOPS24 > 0 || NRASOPS32 > 0
775 	p = rasops_cmap;
776 
777 	for (i = 0; i < 16; i++) {
778 		if (ri->ri_rnum <= 8)
779 			c = (*p >> (8 - ri->ri_rnum)) << ri->ri_rpos;
780 		else
781 			c = (*p << (ri->ri_rnum - 8)) << ri->ri_rpos;
782 		p++;
783 
784 		if (ri->ri_gnum <= 8)
785 			c |= (*p >> (8 - ri->ri_gnum)) << ri->ri_gpos;
786 		else
787 			c |= (*p << (ri->ri_gnum - 8)) << ri->ri_gpos;
788 		p++;
789 
790 		if (ri->ri_bnum <= 8)
791 			c |= (*p >> (8 - ri->ri_bnum)) << ri->ri_bpos;
792 		else
793 			c |= (*p << (ri->ri_bnum - 8)) << ri->ri_bpos;
794 		p++;
795 
796 		/* Fill the word for generic routines, which want this */
797 		if (ri->ri_depth == 24)
798 			c = c | ((c & 0xff) << 24);
799 		else if (ri->ri_depth <= 16)
800 			c = c | (c << 16);
801 
802 		/* 24bpp does bswap on the fly. {32,16,15}bpp do it here. */
803 #if NRASOPS_BSWAP > 0
804 		if ((ri->ri_flg & RI_BSWAP) == 0)
805 			ri->ri_devcmap[i] = c;
806 		else if (ri->ri_depth == 32)
807 			ri->ri_devcmap[i] = swap32(c);
808 		else if (ri->ri_depth == 16 || ri->ri_depth == 15)
809 			ri->ri_devcmap[i] = swap16(c);
810 		else
811 			ri->ri_devcmap[i] = c;
812 #else
813 		ri->ri_devcmap[i] = c;
814 #endif
815 	}
816 #endif
817 }
818 
819 /*
820  * Unpack a rasops attribute
821  */
822 void
823 rasops_unpack_attr(cookie, attr, fg, bg, underline)
824 	void *cookie;
825 	long attr;
826 	int *fg, *bg, *underline;
827 {
828 	*fg = ((u_int)attr >> 24) & 0xf;
829 	*bg = ((u_int)attr >> 16) & 0xf;
830 	if (underline != NULL)
831 		*underline = (u_int)attr & 1;
832 }
833 
834 /*
835  * Erase rows
836  */
837 void
838 rasops_eraserows(cookie, row, num, attr)
839 	void *cookie;
840 	int row, num;
841 	long attr;
842 {
843 	struct rasops_info *ri;
844 	int np, nw, cnt, delta;
845 	int32_t *dp, clr;
846 
847 	ri = (struct rasops_info *)cookie;
848 
849 #ifdef RASOPS_CLIPPING
850 	if (row < 0) {
851 		num += row;
852 		row = 0;
853 	}
854 
855 	if ((row + num) > ri->ri_rows)
856 		num = ri->ri_rows - row;
857 
858 	if (num <= 0)
859 		return;
860 #endif
861 
862 	clr = ri->ri_devcmap[(attr >> 16) & 0xf];
863 
864 	/*
865 	 * XXX The wsdisplay_emulops interface seems a little deficient in
866 	 * that there is no way to clear the *entire* screen. We provide a
867 	 * workaround here: if the entire console area is being cleared, and
868 	 * the RI_FULLCLEAR flag is set, clear the entire display.
869 	 */
870 	if (num == ri->ri_rows && (ri->ri_flg & RI_FULLCLEAR) != 0) {
871 		np = ri->ri_stride >> 5;
872 		nw = (ri->ri_stride >> 2) & 7;
873 		num = ri->ri_height;
874 		dp = (int32_t *)ri->ri_origbits;
875 		delta = 0;
876 	} else {
877 		np = ri->ri_emustride >> 5;
878 		nw = (ri->ri_emustride >> 2) & 7;
879 		num *= ri->ri_font->fontheight;
880 		dp = (int32_t *)(ri->ri_bits + row * ri->ri_yscale);
881 		delta = ri->ri_delta;
882 	}
883 
884 	while (num--) {
885 		for (cnt = np; cnt; cnt--) {
886 			dp[0] = clr;
887 			dp[1] = clr;
888 			dp[2] = clr;
889 			dp[3] = clr;
890 			dp[4] = clr;
891 			dp[5] = clr;
892 			dp[6] = clr;
893 			dp[7] = clr;
894 			dp += 8;
895 		}
896 
897 		for (cnt = nw; cnt; cnt--) {
898 			*(int32_t *)dp = clr;
899 			DELTA(dp, 4, int32_t *);
900 		}
901 
902 		DELTA(dp, delta, int32_t *);
903 	}
904 }
905 
906 /*
907  * Actually turn the cursor on or off. This does the dirty work for
908  * rasops_cursor().
909  */
910 void
911 rasops_do_cursor(ri)
912 	struct rasops_info *ri;
913 {
914 	int full1, height, cnt, slop1, slop2, row, col;
915 	u_char *dp, *rp;
916 
917 #if NRASOPS_ROTATION > 0
918 	if (ri->ri_flg & RI_ROTATE_CW) {
919 		/* Rotate rows/columns */
920 		row = ri->ri_ccol;
921 		col = ri->ri_rows - ri->ri_crow - 1;
922 	} else
923 #endif
924 	{
925 		row = ri->ri_crow;
926 		col = ri->ri_ccol;
927 	}
928 
929 	rp = ri->ri_bits + row * ri->ri_yscale + col * ri->ri_xscale;
930 	height = ri->ri_font->fontheight;
931 	slop1 = (4 - ((long)rp & 3)) & 3;
932 
933 	if (slop1 > ri->ri_xscale)
934 		slop1 = ri->ri_xscale;
935 
936 	slop2 = (ri->ri_xscale - slop1) & 3;
937 	full1 = (ri->ri_xscale - slop1 - slop2) >> 2;
938 
939 	if ((slop1 | slop2) == 0) {
940 		/* A common case */
941 		while (height--) {
942 			dp = rp;
943 			rp += ri->ri_stride;
944 
945 			for (cnt = full1; cnt; cnt--) {
946 				*(int32_t *)dp ^= ~0;
947 				dp += 4;
948 			}
949 		}
950 	} else {
951 		/* XXX this is stupid.. use masks instead */
952 		while (height--) {
953 			dp = rp;
954 			rp += ri->ri_stride;
955 
956 			if (slop1 & 1)
957 				*dp++ ^= ~0;
958 
959 			if (slop1 & 2) {
960 				*(int16_t *)dp ^= ~0;
961 				dp += 2;
962 			}
963 
964 			for (cnt = full1; cnt; cnt--) {
965 				*(int32_t *)dp ^= ~0;
966 				dp += 4;
967 			}
968 
969 			if (slop2 & 1)
970 				*dp++ ^= ~0;
971 
972 			if (slop2 & 2)
973 				*(int16_t *)dp ^= ~0;
974 		}
975 	}
976 }
977 
978 /*
979  * Erase columns.
980  */
981 void
982 rasops_erasecols(cookie, row, col, num, attr)
983 	void *cookie;
984 	int row, col, num;
985 	long attr;
986 {
987 	int n8, height, cnt, slop1, slop2, clr;
988 	struct rasops_info *ri;
989 	int32_t *rp, *dp;
990 
991 	ri = (struct rasops_info *)cookie;
992 
993 #ifdef RASOPS_CLIPPING
994 	if ((unsigned)row >= (unsigned)ri->ri_rows)
995 		return;
996 
997 	if (col < 0) {
998 		num += col;
999 		col = 0;
1000 	}
1001 
1002 	if ((col + num) > ri->ri_cols)
1003 		num = ri->ri_cols - col;
1004 
1005 	if (num <= 0)
1006 		return;
1007 #endif
1008 
1009 	num = num * ri->ri_xscale;
1010 	rp = (int32_t *)(ri->ri_bits + row*ri->ri_yscale + col*ri->ri_xscale);
1011 	height = ri->ri_font->fontheight;
1012 	clr = ri->ri_devcmap[(attr >> 16) & 0xf];
1013 
1014 	/* Don't bother using the full loop for <= 32 pels */
1015 	if (num <= 32) {
1016 		if (((num | ri->ri_xscale) & 3) == 0) {
1017 			/* Word aligned blt */
1018 			num >>= 2;
1019 
1020 			while (height--) {
1021 				dp = rp;
1022 				DELTA(rp, ri->ri_stride, int32_t *);
1023 
1024 				for (cnt = num; cnt; cnt--)
1025 					*dp++ = clr;
1026 			}
1027 		} else if (((num | ri->ri_xscale) & 1) == 0) {
1028 			/*
1029 			 * Halfword aligned blt. This is needed so the
1030 			 * 15/16 bit ops can use this function.
1031 			 */
1032 			num >>= 1;
1033 
1034 			while (height--) {
1035 				dp = rp;
1036 				DELTA(rp, ri->ri_stride, int32_t *);
1037 
1038 				for (cnt = num; cnt; cnt--) {
1039 					*(int16_t *)dp = clr;
1040 					DELTA(dp, 2, int32_t *);
1041 				}
1042 			}
1043 		} else {
1044 			while (height--) {
1045 				dp = rp;
1046 				DELTA(rp, ri->ri_stride, int32_t *);
1047 
1048 				for (cnt = num; cnt; cnt--) {
1049 					*(u_char *)dp = clr;
1050 					DELTA(dp, 1, int32_t *);
1051 				}
1052 			}
1053 		}
1054 
1055 		return;
1056 	}
1057 
1058 	slop1 = (4 - ((long)rp & 3)) & 3;
1059 	slop2 = (num - slop1) & 3;
1060 	num -= slop1 + slop2;
1061 	n8 = num >> 5;
1062 	num = (num >> 2) & 7;
1063 
1064 	while (height--) {
1065 		dp = rp;
1066 		DELTA(rp, ri->ri_stride, int32_t *);
1067 
1068 		/* Align span to 4 bytes */
1069 		if (slop1 & 1) {
1070 			*(u_char *)dp = clr;
1071 			DELTA(dp, 1, int32_t *);
1072 		}
1073 
1074 		if (slop1 & 2) {
1075 			*(int16_t *)dp = clr;
1076 			DELTA(dp, 2, int32_t *);
1077 		}
1078 
1079 		/* Write 32 bytes per loop */
1080 		for (cnt = n8; cnt; cnt--) {
1081 			dp[0] = clr;
1082 			dp[1] = clr;
1083 			dp[2] = clr;
1084 			dp[3] = clr;
1085 			dp[4] = clr;
1086 			dp[5] = clr;
1087 			dp[6] = clr;
1088 			dp[7] = clr;
1089 			dp += 8;
1090 		}
1091 
1092 		/* Write 4 bytes per loop */
1093 		for (cnt = num; cnt; cnt--)
1094 			*dp++ = clr;
1095 
1096 		/* Write unaligned trailing slop */
1097 		if (slop2 & 1) {
1098 			*(u_char *)dp = clr;
1099 			DELTA(dp, 1, int32_t *);
1100 		}
1101 
1102 		if (slop2 & 2)
1103 			*(int16_t *)dp = clr;
1104 	}
1105 }
1106 
1107 #if NRASOPS_ROTATION > 0
1108 /*
1109  * Quarter clockwise rotation routines (originally intended for the
1110  * built-in Zaurus C3x00 display in 16bpp).
1111  */
1112 
1113 #include <sys/malloc.h>
1114 
1115 void
1116 rasops_rotate_font(int *cookie)
1117 {
1118 	struct rotatedfont *f;
1119 	int ncookie;
1120 
1121 	SLIST_FOREACH(f, &rotatedfonts, rf_next) {
1122 		if (f->rf_cookie == *cookie) {
1123 			*cookie = f->rf_rotated;
1124 			return;
1125 		}
1126 	}
1127 
1128 	/*
1129 	 * We did not find a rotated version of this font. Ask the wsfont
1130 	 * code to compute one for us.
1131 	 */
1132 
1133 	f = malloc(sizeof(struct rotatedfont), M_DEVBUF, M_WAITOK);
1134 	if (f == NULL)
1135 		return;
1136 
1137 	if ((ncookie = wsfont_rotate(*cookie)) == -1)
1138 		return;
1139 
1140 	f->rf_cookie = *cookie;
1141 	f->rf_rotated = ncookie;
1142 	SLIST_INSERT_HEAD(&rotatedfonts, f, rf_next);
1143 
1144 	*cookie = ncookie;
1145 }
1146 
1147 void
1148 rasops_copychar(cookie, srcrow, dstrow, srccol, dstcol)
1149 	void *cookie;
1150 	int srcrow, dstrow, srccol, dstcol;
1151 {
1152 	struct rasops_info *ri;
1153 	u_char *sp, *dp;
1154 	int height;
1155 	int r_srcrow, r_dstrow, r_srccol, r_dstcol;
1156 
1157 	ri = (struct rasops_info *)cookie;
1158 
1159 	r_srcrow = srccol;
1160 	r_dstrow = dstcol;
1161 	r_srccol = ri->ri_rows - srcrow - 1;
1162 	r_dstcol = ri->ri_rows - dstrow - 1;
1163 
1164 	r_srcrow *= ri->ri_yscale;
1165 	r_dstrow *= ri->ri_yscale;
1166 	height = ri->ri_font->fontheight;
1167 
1168 	sp = ri->ri_bits + r_srcrow + r_srccol * ri->ri_xscale;
1169 	dp = ri->ri_bits + r_dstrow + r_dstcol * ri->ri_xscale;
1170 
1171 #if NRASOPS_BSWAP > 0
1172 	if (ri->ri_flg & RI_BSWAP) {
1173 		while (height--) {
1174 			slow_ovbcopy(sp, dp, ri->ri_xscale);
1175 			dp += ri->ri_stride;
1176 			sp += ri->ri_stride;
1177 		}
1178 	} else
1179 #endif
1180 	{
1181 		while (height--) {
1182 			ovbcopy(sp, dp, ri->ri_xscale);
1183 			dp += ri->ri_stride;
1184 			sp += ri->ri_stride;
1185 		}
1186 	}
1187 }
1188 
1189 void
1190 rasops_putchar_rotated(cookie, row, col, uc, attr)
1191 	void *cookie;
1192 	int row, col;
1193 	u_int uc;
1194 	long attr;
1195 {
1196 	struct rasops_info *ri;
1197 	u_char *rp;
1198 	int height;
1199 
1200 	ri = (struct rasops_info *)cookie;
1201 
1202 	/* Do rotated char sans (side)underline */
1203 	ri->ri_real_ops.putchar(cookie, col, ri->ri_rows - row - 1, uc,
1204 	    attr & ~1);
1205 
1206 	/* Do rotated underline */
1207 	rp = ri->ri_bits + col * ri->ri_yscale + (ri->ri_rows - row - 1) *
1208 	    ri->ri_xscale;
1209 	height = ri->ri_font->fontheight;
1210 
1211 	/* XXX this assumes 16-bit color depth */
1212 	if ((attr & 1) != 0) {
1213 		int16_t c = (int16_t)ri->ri_devcmap[((u_int)attr >> 24) & 0xf];
1214 
1215 		while (height--) {
1216 			*(int16_t *)rp = c;
1217 			rp += ri->ri_stride;
1218 		}
1219 	}
1220 }
1221 
1222 void
1223 rasops_erasecols_rotated(cookie, row, col, num, attr)
1224 	void *cookie;
1225 	int row, col, num;
1226 	long attr;
1227 {
1228 	struct rasops_info *ri;
1229 	int i;
1230 
1231 	ri = (struct rasops_info *)cookie;
1232 
1233 	for (i = col; i < col + num; i++)
1234 		ri->ri_ops.putchar(cookie, row, i, ' ', attr);
1235 }
1236 
1237 /* XXX: these could likely be optimised somewhat. */
1238 void
1239 rasops_copyrows_rotated(cookie, src, dst, num)
1240 	void *cookie;
1241 	int src, dst, num;
1242 {
1243 	struct rasops_info *ri = (struct rasops_info *)cookie;
1244 	int col, roff;
1245 
1246 	if (src > dst)
1247 		for (roff = 0; roff < num; roff++)
1248 			for (col = 0; col < ri->ri_cols; col++)
1249 				rasops_copychar(cookie, src + roff, dst + roff,
1250 				    col, col);
1251 	else
1252 		for (roff = num - 1; roff >= 0; roff--)
1253 			for (col = 0; col < ri->ri_cols; col++)
1254 				rasops_copychar(cookie, src + roff, dst + roff,
1255 				    col, col);
1256 }
1257 
1258 void
1259 rasops_copycols_rotated(cookie, row, src, dst, num)
1260 	void *cookie;
1261 	int row, src, dst, num;
1262 {
1263 	int coff;
1264 
1265 	if (src > dst)
1266 		for (coff = 0; coff < num; coff++)
1267 			rasops_copychar(cookie, row, row, src + coff, dst + coff);
1268 	else
1269 		for (coff = num - 1; coff >= 0; coff--)
1270 			rasops_copychar(cookie, row, row, src + coff, dst + coff);
1271 }
1272 
1273 void
1274 rasops_eraserows_rotated(cookie, row, num, attr)
1275 	void *cookie;
1276 	int row, num;
1277 	long attr;
1278 {
1279 	struct rasops_info *ri;
1280 	int col, rn;
1281 
1282 	ri = (struct rasops_info *)cookie;
1283 
1284 	for (rn = row; rn < row + num; rn++)
1285 		for (col = 0; col < ri->ri_cols; col++)
1286 			ri->ri_ops.putchar(cookie, rn, col, ' ', attr);
1287 }
1288 #endif	/* NRASOPS_ROTATION */
1289 
1290 #if NRASOPS_BSWAP > 0
1291 /*
1292  * Strictly byte-only ovbcopy() version, to be used with RI_BSWAP, as the
1293  * regular ovbcopy() may want to optimize things by doing larger-than-byte
1294  * reads or write. This may confuse things if src and dst have different
1295  * alignments.
1296  */
1297 void
1298 slow_ovbcopy(void *s, void *d, size_t len)
1299 {
1300 	u_int8_t *src = s;
1301 	u_int8_t *dst = d;
1302 
1303 	if ((vaddr_t)dst <= (vaddr_t)src) {
1304 		while (len-- != 0)
1305 			*dst++ = *src++;
1306 	} else {
1307 		src += len;
1308 		dst += len;
1309 		if (len != 0)
1310 			while (--len != 0)
1311 				*--dst = *--src;
1312 	}
1313 }
1314 #endif	/* NRASOPS_BSWAP */
1315