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