xref: /openbsd/sys/dev/rasops/rasops.c (revision 68cc3983)
1 /*	$OpenBSD: rasops.c,v 1.71 2023/04/13 02:19:05 jsg 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/malloc.h>
35 #include <sys/systm.h>
36 #include <sys/time.h>
37 #include <sys/task.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 struct rasops_screen {
126 	LIST_ENTRY(rasops_screen) rs_next;
127 	struct rasops_info *rs_ri;
128 
129 	struct wsdisplay_charcell *rs_bs;
130 	int rs_visible;
131 	int rs_crow;
132 	int rs_ccol;
133 	uint32_t rs_defattr;
134 
135 	int rs_sbscreens;
136 #define RS_SCROLLBACK_SCREENS 5
137 	int rs_dispoffset;	/* rs_bs index, start of our actual screen */
138 	int rs_visibleoffset;	/* rs_bs index, current scrollback screen */
139 };
140 
141 /* Generic functions */
142 int	rasops_copycols(void *, int, int, int, int);
143 int	rasops_copyrows(void *, int, int, int);
144 int	rasops_mapchar(void *, int, u_int *);
145 int	rasops_cursor(void *, int, int, int);
146 int	rasops_pack_cattr(void *, int, int, int, uint32_t *);
147 int	rasops_pack_mattr(void *, int, int, int, uint32_t *);
148 int	rasops_do_cursor(struct rasops_info *);
149 void	rasops_init_devcmap(struct rasops_info *);
150 void	rasops_unpack_attr(void *, uint32_t, int *, int *, int *);
151 #if NRASOPS_BSWAP > 0
152 static void slow_bcopy(void *, void *, size_t);
153 #endif
154 #if NRASOPS_ROTATION > 0
155 void	rasops_copychar(void *, int, int, int, int);
156 int	rasops_copycols_rotated(void *, int, int, int, int);
157 int	rasops_copyrows_rotated(void *, int, int, int);
158 int	rasops_erasecols_rotated(void *, int, int, int, uint32_t);
159 int	rasops_eraserows_rotated(void *, int, int, uint32_t);
160 int	rasops_putchar_rotated(void *, int, int, u_int, uint32_t);
161 void	rasops_rotate_font(int *, int);
162 
163 /*
164  * List of all rotated fonts
165  */
166 SLIST_HEAD(, rotatedfont) rotatedfonts = SLIST_HEAD_INITIALIZER(rotatedfonts);
167 struct	rotatedfont {
168 	SLIST_ENTRY(rotatedfont) rf_next;
169 	int rf_cookie;
170 	int rf_rotated;
171 };
172 #endif
173 
174 void	rasops_doswitch(void *);
175 int	rasops_vcons_cursor(void *, int, int, int);
176 int	rasops_vcons_mapchar(void *, int, u_int *);
177 int	rasops_vcons_putchar(void *, int, int, u_int, uint32_t);
178 int	rasops_vcons_copycols(void *, int, int, int, int);
179 int	rasops_vcons_erasecols(void *, int, int, int, uint32_t);
180 int	rasops_vcons_copyrows(void *, int, int, int);
181 int	rasops_vcons_eraserows(void *, int, int, uint32_t);
182 int	rasops_vcons_pack_attr(void *, int, int, int, uint32_t *);
183 void	rasops_vcons_unpack_attr(void *, uint32_t, int *, int *, int *);
184 
185 int	rasops_wronly_putchar(void *, int, int, u_int, uint32_t);
186 int	rasops_wronly_copycols(void *, int, int, int, int);
187 int	rasops_wronly_erasecols(void *, int, int, int, uint32_t);
188 int	rasops_wronly_copyrows(void *, int, int, int);
189 int	rasops_wronly_eraserows(void *, int, int, uint32_t);
190 int	rasops_wronly_do_cursor(struct rasops_info *);
191 
192 int	rasops_add_font(struct rasops_info *, struct wsdisplay_font *);
193 int	rasops_use_font(struct rasops_info *, struct wsdisplay_font *);
194 int	rasops_list_font_cb(void *, struct wsdisplay_font *);
195 
196 /*
197  * Initialize a 'rasops_info' descriptor.
198  */
199 int
rasops_init(struct rasops_info * ri,int wantrows,int wantcols)200 rasops_init(struct rasops_info *ri, int wantrows, int wantcols)
201 {
202 
203 #ifdef _KERNEL
204 	/* Select a font if the caller doesn't care */
205 	if (ri->ri_font == NULL) {
206 		int cookie = -1;
207 
208 		wsfont_init();
209 
210 		if (ri->ri_width >= 120 * 32)
211 			/* Screen width of at least 3840px, 32px wide font */
212 			cookie = wsfont_find(NULL, 32, 0, 0);
213 
214 		if (cookie <= 0 && ri->ri_width >= 120 * 16)
215 			/* Screen width of at least 1920px, 16px wide font */
216 			cookie = wsfont_find(NULL, 16, 0, 0);
217 
218 		if (cookie <= 0 && ri->ri_width > 80 * 12)
219 			/* Screen width larger than 960px, 12px wide font */
220 			cookie = wsfont_find(NULL, 12, 0, 0);
221 
222 		if (cookie <= 0)
223 			/* Lower resolution, choose a 8px wide font */
224 			cookie = wsfont_find(NULL, 8, 0, 0);
225 
226 		if (cookie <= 0)
227 			cookie = wsfont_find(NULL, 0, 0, 0);
228 
229 		if (cookie <= 0) {
230 			printf("rasops_init: font table is empty\n");
231 			return (-1);
232 		}
233 
234 #if NRASOPS_ROTATION > 0
235 		/*
236 		 * Pick the rotated version of this font. This will create it
237 		 * if necessary.
238 		 */
239 		if (ri->ri_flg & (RI_ROTATE_CW | RI_ROTATE_CCW))
240 			rasops_rotate_font(&cookie,
241 			    ISSET(ri->ri_flg, RI_ROTATE_CCW));
242 #endif
243 
244 		if (wsfont_lock(cookie, &ri->ri_font,
245 		    WSDISPLAY_FONTORDER_L2R, WSDISPLAY_FONTORDER_L2R) <= 0) {
246 			printf("rasops_init: couldn't lock font\n");
247 			return (-1);
248 		}
249 
250 		ri->ri_wsfcookie = cookie;
251 	}
252 #endif
253 
254 	/* This should never happen in reality... */
255 #ifdef DEBUG
256 	if ((long)ri->ri_bits & 3) {
257 		printf("rasops_init: bits not aligned on 32-bit boundary\n");
258 		return (-1);
259 	}
260 
261 	if ((int)ri->ri_stride & 3) {
262 		printf("rasops_init: stride not aligned on 32-bit boundary\n");
263 		return (-1);
264 	}
265 #endif
266 
267 	if (rasops_reconfig(ri, wantrows, wantcols))
268 		return (-1);
269 
270 	LIST_INIT(&ri->ri_screens);
271 	ri->ri_nscreens = 0;
272 
273 	ri->ri_putchar = ri->ri_ops.putchar;
274 	ri->ri_copycols = ri->ri_ops.copycols;
275 	ri->ri_erasecols = ri->ri_ops.erasecols;
276 	ri->ri_copyrows = ri->ri_ops.copyrows;
277 	ri->ri_eraserows = ri->ri_ops.eraserows;
278 	ri->ri_pack_attr = ri->ri_ops.pack_attr;
279 
280 	if (ri->ri_flg & RI_VCONS) {
281 		void *cookie;
282 		int curx, cury;
283 		uint32_t attr;
284 
285 		if (rasops_alloc_screen(ri, &cookie, &curx, &cury, &attr))
286 			return (-1);
287 
288 		ri->ri_active = cookie;
289 		ri->ri_bs =
290 		    &ri->ri_active->rs_bs[ri->ri_active->rs_dispoffset];
291 
292 		ri->ri_ops.cursor = rasops_vcons_cursor;
293 		ri->ri_ops.mapchar = rasops_vcons_mapchar;
294 		ri->ri_ops.putchar = rasops_vcons_putchar;
295 		ri->ri_ops.copycols = rasops_vcons_copycols;
296 		ri->ri_ops.erasecols = rasops_vcons_erasecols;
297 		ri->ri_ops.copyrows = rasops_vcons_copyrows;
298 		ri->ri_ops.eraserows = rasops_vcons_eraserows;
299 		ri->ri_ops.pack_attr = rasops_vcons_pack_attr;
300 		ri->ri_ops.unpack_attr = rasops_vcons_unpack_attr;
301 		ri->ri_do_cursor = rasops_wronly_do_cursor;
302 	} else if ((ri->ri_flg & RI_WRONLY) && ri->ri_bs != NULL) {
303 		uint32_t attr;
304 		int i;
305 
306 		ri->ri_ops.putchar = rasops_wronly_putchar;
307 		ri->ri_ops.copycols = rasops_wronly_copycols;
308 		ri->ri_ops.erasecols = rasops_wronly_erasecols;
309 		ri->ri_ops.copyrows = rasops_wronly_copyrows;
310 		ri->ri_ops.eraserows = rasops_wronly_eraserows;
311 		ri->ri_do_cursor = rasops_wronly_do_cursor;
312 
313 		if (ri->ri_flg & RI_CLEAR) {
314 			ri->ri_pack_attr(ri, 0, 0, 0, &attr);
315 			for (i = 0; i < ri->ri_rows * ri->ri_cols; i++) {
316 				ri->ri_bs[i].uc = ' ';
317 				ri->ri_bs[i].attr = attr;
318 			}
319 		}
320 	}
321 
322 	task_set(&ri->ri_switchtask, rasops_doswitch, ri);
323 
324 	rasops_init_devcmap(ri);
325 	return (0);
326 }
327 
328 /*
329  * Reconfigure (because parameters have changed in some way).
330  */
331 int
rasops_reconfig(struct rasops_info * ri,int wantrows,int wantcols)332 rasops_reconfig(struct rasops_info *ri, int wantrows, int wantcols)
333 {
334 	int l, bpp, s;
335 
336 	s = splhigh();
337 
338 	if (ri->ri_font->fontwidth > 32 || ri->ri_font->fontwidth < 4)
339 		panic("rasops_init: fontwidth assumptions botched!");
340 
341 	/* Need this to frob the setup below */
342 	bpp = (ri->ri_depth == 15 ? 16 : ri->ri_depth);
343 
344 	if ((ri->ri_flg & RI_CFGDONE) != 0)
345 		ri->ri_bits = ri->ri_origbits;
346 
347 	/* Don't care if the caller wants a hideously small console */
348 	if (wantrows < 10)
349 		wantrows = 10;
350 
351 	if (wantcols < 20)
352 		wantcols = 20;
353 
354 	/* Now constrain what they get */
355 	ri->ri_emuwidth = ri->ri_font->fontwidth * wantcols;
356 	ri->ri_emuheight = ri->ri_font->fontheight * wantrows;
357 
358 	if (ri->ri_emuwidth > ri->ri_width)
359 		ri->ri_emuwidth = ri->ri_width;
360 
361 	if (ri->ri_emuheight > ri->ri_height)
362 		ri->ri_emuheight = ri->ri_height;
363 
364 	/* Reduce width until aligned on a 32-bit boundary */
365 	while ((ri->ri_emuwidth * bpp & 31) != 0)
366 		ri->ri_emuwidth--;
367 
368 #if NRASOPS_ROTATION > 0
369 	if (ri->ri_flg & (RI_ROTATE_CW | RI_ROTATE_CCW)) {
370 		ri->ri_rows = ri->ri_emuwidth / ri->ri_font->fontwidth;
371 		ri->ri_cols = ri->ri_emuheight / ri->ri_font->fontheight;
372 	} else
373 #endif
374 	{
375 		ri->ri_cols = ri->ri_emuwidth / ri->ri_font->fontwidth;
376 		ri->ri_rows = ri->ri_emuheight / ri->ri_font->fontheight;
377 	}
378 	ri->ri_emustride = ri->ri_emuwidth * bpp >> 3;
379 	ri->ri_delta = ri->ri_stride - ri->ri_emustride;
380 	ri->ri_ccol = 0;
381 	ri->ri_crow = 0;
382 	ri->ri_pelbytes = bpp >> 3;
383 
384 	ri->ri_xscale = (ri->ri_font->fontwidth * bpp) >> 3;
385 	ri->ri_yscale = ri->ri_font->fontheight * ri->ri_stride;
386 	ri->ri_fontscale = ri->ri_font->fontheight * ri->ri_font->stride;
387 
388 #ifdef DEBUG
389 	if ((ri->ri_delta & 3) != 0)
390 		panic("rasops_init: ri_delta not aligned on 32-bit boundary");
391 #endif
392 	/* Clear the entire display */
393 	if ((ri->ri_flg & RI_CLEAR) != 0) {
394 		memset(ri->ri_bits, 0, ri->ri_stride * ri->ri_height);
395 		ri->ri_flg &= ~RI_CLEARMARGINS;
396 	}
397 
398 	/* Now centre our window if needs be */
399 	ri->ri_origbits = ri->ri_bits;
400 
401 	if ((ri->ri_flg & RI_CENTER) != 0) {
402 		ri->ri_bits += (((ri->ri_width * bpp >> 3) -
403 		    ri->ri_emustride) >> 1) & ~3;
404 		ri->ri_bits += ((ri->ri_height - ri->ri_emuheight) >> 1) *
405 		    ri->ri_stride;
406 
407 		ri->ri_yorigin = (int)(ri->ri_bits - ri->ri_origbits)
408 		   / ri->ri_stride;
409 		ri->ri_xorigin = (((int)(ri->ri_bits - ri->ri_origbits)
410 		   % ri->ri_stride) * 8 / bpp);
411 	} else
412 		ri->ri_xorigin = ri->ri_yorigin = 0;
413 
414 	/* Clear the margins */
415 	if ((ri->ri_flg & RI_CLEARMARGINS) != 0) {
416 		memset(ri->ri_origbits, 0, ri->ri_bits - ri->ri_origbits);
417 		for (l = 0; l < ri->ri_emuheight; l++)
418 			memset(ri->ri_bits + ri->ri_emustride +
419 			    l * ri->ri_stride, 0,
420 			    ri->ri_stride - ri->ri_emustride);
421 		memset(ri->ri_bits + ri->ri_emuheight * ri->ri_stride, 0,
422 		    (ri->ri_origbits + ri->ri_height * ri->ri_stride) -
423 		    (ri->ri_bits + ri->ri_emuheight * ri->ri_stride));
424 	}
425 
426 	/*
427 	 * Fill in defaults for operations set.  XXX this nukes private
428 	 * routines used by accelerated fb drivers.
429 	 */
430 	ri->ri_ops.mapchar = rasops_mapchar;
431 	ri->ri_ops.copyrows = rasops_copyrows;
432 	ri->ri_ops.copycols = rasops_copycols;
433 	ri->ri_ops.erasecols = rasops_erasecols;
434 	ri->ri_ops.eraserows = rasops_eraserows;
435 	ri->ri_ops.cursor = rasops_cursor;
436 	ri->ri_ops.unpack_attr = rasops_unpack_attr;
437 	ri->ri_do_cursor = rasops_do_cursor;
438 	ri->ri_updatecursor = NULL;
439 
440 	if (ri->ri_depth < 8 || (ri->ri_flg & RI_FORCEMONO) != 0) {
441 		ri->ri_ops.pack_attr = rasops_pack_mattr;
442 		ri->ri_caps = WSSCREEN_UNDERLINE | WSSCREEN_REVERSE;
443 	} else {
444 		ri->ri_ops.pack_attr = rasops_pack_cattr;
445 		ri->ri_caps = WSSCREEN_UNDERLINE | WSSCREEN_HILIT |
446 		    WSSCREEN_WSCOLORS | WSSCREEN_REVERSE;
447 	}
448 
449 	switch (ri->ri_depth) {
450 #if NRASOPS1 > 0
451 	case 1:
452 		rasops1_init(ri);
453 		break;
454 #endif
455 #if NRASOPS4 > 0
456 	case 4:
457 		rasops4_init(ri);
458 		break;
459 #endif
460 #if NRASOPS8 > 0
461 	case 8:
462 		rasops8_init(ri);
463 		break;
464 #endif
465 #if NRASOPS15 > 0 || NRASOPS16 > 0
466 	case 15:
467 	case 16:
468 		rasops15_init(ri);
469 		break;
470 #endif
471 #if NRASOPS24 > 0
472 	case 24:
473 		rasops24_init(ri);
474 		break;
475 #endif
476 #if NRASOPS32 > 0
477 	case 32:
478 		rasops32_init(ri);
479 		break;
480 #endif
481 	default:
482 		ri->ri_flg &= ~RI_CFGDONE;
483 		splx(s);
484 		return (-1);
485 	}
486 
487 #if NRASOPS_ROTATION > 0
488 	if (ri->ri_flg & (RI_ROTATE_CW | RI_ROTATE_CCW)) {
489 		ri->ri_real_ops = ri->ri_ops;
490 		ri->ri_ops.copycols = rasops_copycols_rotated;
491 		ri->ri_ops.copyrows = rasops_copyrows_rotated;
492 		ri->ri_ops.erasecols = rasops_erasecols_rotated;
493 		ri->ri_ops.eraserows = rasops_eraserows_rotated;
494 		ri->ri_ops.putchar = rasops_putchar_rotated;
495 	}
496 #endif
497 
498 	ri->ri_flg |= RI_CFGDONE;
499 	splx(s);
500 	return (0);
501 }
502 
503 /*
504  * Map a character.
505  */
506 int
rasops_mapchar(void * cookie,int c,u_int * cp)507 rasops_mapchar(void *cookie, int c, u_int *cp)
508 {
509 	struct rasops_info *ri;
510 
511 	ri = (struct rasops_info *)cookie;
512 
513 #ifdef DIAGNOSTIC
514 	if (ri->ri_font == NULL)
515 		panic("rasops_mapchar: no font selected");
516 #endif
517 	if (ri->ri_font->encoding != WSDISPLAY_FONTENC_ISO) {
518 		if ((c = wsfont_map_unichar(ri->ri_font, c)) < 0) {
519 			*cp = '?';
520 			return (0);
521 		}
522 	}
523 
524 	if (c < ri->ri_font->firstchar ||
525 	    c - ri->ri_font->firstchar >= ri->ri_font->numchars) {
526 		*cp = '?';
527 		return (0);
528 	}
529 
530 	*cp = c;
531 	return (5);
532 }
533 
534 /*
535  * Pack a color attribute.
536  */
537 int
rasops_pack_cattr(void * cookie,int fg,int bg,int flg,uint32_t * attr)538 rasops_pack_cattr(void *cookie, int fg, int bg, int flg, uint32_t *attr)
539 {
540 	int swap;
541 
542 	if ((flg & WSATTR_BLINK) != 0)
543 		return (EINVAL);
544 
545 	if ((flg & WSATTR_WSCOLORS) == 0) {
546 		fg = WS_DEFAULT_FG;
547 		bg = WS_DEFAULT_BG;
548 	}
549 
550 	if ((flg & WSATTR_REVERSE) != 0) {
551 		swap = fg;
552 		fg = bg;
553 		bg = swap;
554 	}
555 
556 	/* Bold is only supported for ANSI colors 0 - 7. */
557 	if ((flg & WSATTR_HILIT) != 0 && fg < 8)
558 		fg += 8;
559 
560 	*attr = (bg << 16) | (fg << 24) | (flg & WSATTR_UNDERLINE);
561 	return (0);
562 }
563 
564 /*
565  * Pack a mono attribute.
566  */
567 int
rasops_pack_mattr(void * cookie,int fg,int bg,int flg,uint32_t * attr)568 rasops_pack_mattr(void *cookie, int fg, int bg, int flg, uint32_t *attr)
569 {
570 	int swap;
571 
572 	if ((flg & (WSATTR_BLINK | WSATTR_HILIT | WSATTR_WSCOLORS)) != 0)
573 		return (EINVAL);
574 
575 	fg = 1;
576 	bg = 0;
577 
578 	if ((flg & WSATTR_REVERSE) != 0) {
579 		swap = fg;
580 		fg = bg;
581 		bg = swap;
582 	}
583 
584 	*attr = (bg << 16) | (fg << 24) | (flg & WSATTR_UNDERLINE);
585 	return (0);
586 }
587 
588 /*
589  * Copy rows.
590  */
591 int
rasops_copyrows(void * cookie,int src,int dst,int num)592 rasops_copyrows(void *cookie, int src, int dst, int num)
593 {
594 	int32_t *sp, *dp, *srp, *drp;
595 	struct rasops_info *ri;
596 	int n8, n1, cnt, delta;
597 
598 	ri = (struct rasops_info *)cookie;
599 
600 #ifdef RASOPS_CLIPPING
601 	if (dst == src)
602 		return 0;
603 
604 	if (src < 0) {
605 		num += src;
606 		src = 0;
607 	}
608 
609 	if ((src + num) > ri->ri_rows)
610 		num = ri->ri_rows - src;
611 
612 	if (dst < 0) {
613 		num += dst;
614 		dst = 0;
615 	}
616 
617 	if ((dst + num) > ri->ri_rows)
618 		num = ri->ri_rows - dst;
619 
620 	if (num <= 0)
621 		return 0;
622 #endif
623 
624 	num *= ri->ri_font->fontheight;
625 	n8 = ri->ri_emustride >> 5;
626 	n1 = (ri->ri_emustride >> 2) & 7;
627 
628 	if (dst < src) {
629 		srp = (int32_t *)(ri->ri_bits + src * ri->ri_yscale);
630 		drp = (int32_t *)(ri->ri_bits + dst * ri->ri_yscale);
631 		delta = ri->ri_stride;
632 	} else {
633 		src = ri->ri_font->fontheight * src + num - 1;
634 		dst = ri->ri_font->fontheight * dst + num - 1;
635 		srp = (int32_t *)(ri->ri_bits + src * ri->ri_stride);
636 		drp = (int32_t *)(ri->ri_bits + dst * ri->ri_stride);
637 		delta = -ri->ri_stride;
638 	}
639 
640 	while (num--) {
641 		dp = drp;
642 		sp = srp;
643 		DELTA(drp, delta, int32_t *);
644 		DELTA(srp, delta, int32_t *);
645 
646 		for (cnt = n8; cnt; cnt--) {
647 			dp[0] = sp[0];
648 			dp[1] = sp[1];
649 			dp[2] = sp[2];
650 			dp[3] = sp[3];
651 			dp[4] = sp[4];
652 			dp[5] = sp[5];
653 			dp[6] = sp[6];
654 			dp[7] = sp[7];
655 			dp += 8;
656 			sp += 8;
657 		}
658 
659 		for (cnt = n1; cnt; cnt--)
660 			*dp++ = *sp++;
661 	}
662 
663 	return 0;
664 }
665 
666 /*
667  * Copy columns. This is slow, and hard to optimize due to alignment,
668  * and the fact that we have to copy both left->right and right->left.
669  * We simply cop-out here and use either memmove() or slow_bcopy(),
670  * since they handle all of these cases anyway.
671  */
672 int
rasops_copycols(void * cookie,int row,int src,int dst,int num)673 rasops_copycols(void *cookie, int row, int src, int dst, int num)
674 {
675 	struct rasops_info *ri;
676 	u_char *sp, *dp;
677 	int height;
678 
679 	ri = (struct rasops_info *)cookie;
680 
681 #ifdef RASOPS_CLIPPING
682 	if (dst == src)
683 		return 0;
684 
685 	/* Catches < 0 case too */
686 	if ((unsigned)row >= (unsigned)ri->ri_rows)
687 		return 0;
688 
689 	if (src < 0) {
690 		num += src;
691 		src = 0;
692 	}
693 
694 	if ((src + num) > ri->ri_cols)
695 		num = ri->ri_cols - src;
696 
697 	if (dst < 0) {
698 		num += dst;
699 		dst = 0;
700 	}
701 
702 	if ((dst + num) > ri->ri_cols)
703 		num = ri->ri_cols - dst;
704 
705 	if (num <= 0)
706 		return 0;
707 #endif
708 
709 	num *= ri->ri_xscale;
710 	row *= ri->ri_yscale;
711 	height = ri->ri_font->fontheight;
712 
713 	sp = ri->ri_bits + row + src * ri->ri_xscale;
714 	dp = ri->ri_bits + row + dst * ri->ri_xscale;
715 
716 #if NRASOPS_BSWAP > 0
717 	if (ri->ri_flg & RI_BSWAP) {
718 		while (height--) {
719 			slow_bcopy(sp, dp, num);
720 			dp += ri->ri_stride;
721 			sp += ri->ri_stride;
722 		}
723 	} else
724 #endif
725 	{
726 		while (height--) {
727 			memmove(dp, sp, num);
728 			dp += ri->ri_stride;
729 			sp += ri->ri_stride;
730 		}
731 	}
732 
733 	return 0;
734 }
735 
736 /*
737  * Turn cursor off/on.
738  */
739 int
rasops_cursor(void * cookie,int on,int row,int col)740 rasops_cursor(void *cookie, int on, int row, int col)
741 {
742 	struct rasops_info *ri;
743 	int rc;
744 
745 	ri = (struct rasops_info *)cookie;
746 
747 	/* Turn old cursor off */
748 	if ((ri->ri_flg & RI_CURSOR) != 0) {
749 #ifdef RASOPS_CLIPPING
750 		if ((ri->ri_flg & RI_CURSORCLIP) == 0)
751 #endif
752 			if ((rc = ri->ri_do_cursor(ri)) != 0)
753 				return rc;
754 		ri->ri_flg &= ~RI_CURSOR;
755 	}
756 
757 	/* Select new cursor */
758 #ifdef RASOPS_CLIPPING
759 	ri->ri_flg &= ~RI_CURSORCLIP;
760 
761 	if (row < 0 || row >= ri->ri_rows)
762 		ri->ri_flg |= RI_CURSORCLIP;
763 	else if (col < 0 || col >= ri->ri_cols)
764 		ri->ri_flg |= RI_CURSORCLIP;
765 #endif
766 	ri->ri_crow = row;
767 	ri->ri_ccol = col;
768 
769 	if (ri->ri_updatecursor != NULL)
770 		ri->ri_updatecursor(ri);
771 
772 	if (on) {
773 #ifdef RASOPS_CLIPPING
774 		if ((ri->ri_flg & RI_CURSORCLIP) == 0)
775 #endif
776 			if ((rc = ri->ri_do_cursor(ri)) != 0)
777 				return rc;
778 		ri->ri_flg |= RI_CURSOR;
779 	}
780 
781 	return 0;
782 }
783 
784 /*
785  * Make the device colormap
786  */
787 void
rasops_init_devcmap(struct rasops_info * ri)788 rasops_init_devcmap(struct rasops_info *ri)
789 {
790 	int i;
791 #if NRASOPS15 > 0 || NRASOPS16 > 0 || NRASOPS24 > 0 || NRASOPS32 > 0
792 	const u_char *p;
793 #endif
794 #if NRASOPS4 > 0 || NRASOPS15 > 0 || NRASOPS16 > 0 || NRASOPS24 > 0 || NRASOPS32 > 0
795 	int c;
796 #endif
797 
798 	if (ri->ri_depth == 1 || (ri->ri_flg & RI_FORCEMONO) != 0) {
799 		ri->ri_devcmap[0] = 0;
800 		for (i = 1; i < 16; i++)
801 			ri->ri_devcmap[i] = 0xffffffff;
802 		return;
803 	}
804 
805 	switch (ri->ri_depth) {
806 #if NRASOPS4 > 0
807 	case 4:
808 		for (i = 0; i < 16; i++) {
809 			c = i | (i << 4);
810 			ri->ri_devcmap[i] = c | (c<<8) | (c<<16) | (c<<24);
811 		}
812 		return;
813 #endif
814 #if NRASOPS8 > 0
815 	case 8:
816 		for (i = 0; i < 16; i++)
817 			ri->ri_devcmap[i] = i | (i<<8) | (i<<16) | (i<<24);
818 		return;
819 #endif
820 	default:
821 		break;
822 	}
823 
824 #if NRASOPS15 > 0 || NRASOPS16 > 0 || NRASOPS24 > 0 || NRASOPS32 > 0
825 	p = rasops_cmap;
826 
827 	for (i = 0; i < 16; i++) {
828 		if (ri->ri_rnum <= 8)
829 			c = (*p >> (8 - ri->ri_rnum)) << ri->ri_rpos;
830 		else
831 			c = (*p << (ri->ri_rnum - 8)) << ri->ri_rpos;
832 		p++;
833 
834 		if (ri->ri_gnum <= 8)
835 			c |= (*p >> (8 - ri->ri_gnum)) << ri->ri_gpos;
836 		else
837 			c |= (*p << (ri->ri_gnum - 8)) << ri->ri_gpos;
838 		p++;
839 
840 		if (ri->ri_bnum <= 8)
841 			c |= (*p >> (8 - ri->ri_bnum)) << ri->ri_bpos;
842 		else
843 			c |= (*p << (ri->ri_bnum - 8)) << ri->ri_bpos;
844 		p++;
845 
846 		/* Fill the word for generic routines, which want this */
847 		if (ri->ri_depth == 24)
848 			c = c | ((c & 0xff) << 24);
849 		else if (ri->ri_depth <= 16)
850 			c = c | (c << 16);
851 
852 		/* 24bpp does bswap on the fly. {32,16,15}bpp do it here. */
853 #if NRASOPS_BSWAP > 0
854 		if ((ri->ri_flg & RI_BSWAP) == 0)
855 			ri->ri_devcmap[i] = c;
856 		else if (ri->ri_depth == 32)
857 			ri->ri_devcmap[i] = swap32(c);
858 		else if (ri->ri_depth == 16 || ri->ri_depth == 15)
859 			ri->ri_devcmap[i] = swap16(c);
860 		else
861 			ri->ri_devcmap[i] = c;
862 #else
863 		ri->ri_devcmap[i] = c;
864 #endif
865 	}
866 #endif
867 }
868 
869 /*
870  * Unpack a rasops attribute
871  */
872 void
rasops_unpack_attr(void * cookie,uint32_t attr,int * fg,int * bg,int * underline)873 rasops_unpack_attr(void *cookie, uint32_t attr, int *fg, int *bg, int *underline)
874 {
875 	*fg = ((u_int)attr >> 24) & 0xf;
876 	*bg = ((u_int)attr >> 16) & 0xf;
877 	if (underline != NULL)
878 		*underline = (u_int)attr & WSATTR_UNDERLINE;
879 }
880 
881 /*
882  * Erase rows
883  */
884 int
rasops_eraserows(void * cookie,int row,int num,uint32_t attr)885 rasops_eraserows(void *cookie, int row, int num, uint32_t attr)
886 {
887 	struct rasops_info *ri;
888 	int np, nw, cnt, delta;
889 	int32_t *dp, clr;
890 
891 	ri = (struct rasops_info *)cookie;
892 
893 #ifdef RASOPS_CLIPPING
894 	if (row < 0) {
895 		num += row;
896 		row = 0;
897 	}
898 
899 	if ((row + num) > ri->ri_rows)
900 		num = ri->ri_rows - row;
901 
902 	if (num <= 0)
903 		return 0;
904 #endif
905 
906 	clr = ri->ri_devcmap[(attr >> 16) & 0xf];
907 
908 	/*
909 	 * XXX The wsdisplay_emulops interface seems a little deficient in
910 	 * that there is no way to clear the *entire* screen. We provide a
911 	 * workaround here: if the entire console area is being cleared, and
912 	 * the RI_FULLCLEAR flag is set, clear the entire display.
913 	 */
914 	if (num == ri->ri_rows && (ri->ri_flg & RI_FULLCLEAR) != 0) {
915 		np = ri->ri_stride >> 5;
916 		nw = (ri->ri_stride >> 2) & 7;
917 		num = ri->ri_height;
918 		dp = (int32_t *)ri->ri_origbits;
919 		delta = 0;
920 	} else {
921 		np = ri->ri_emustride >> 5;
922 		nw = (ri->ri_emustride >> 2) & 7;
923 		num *= ri->ri_font->fontheight;
924 		dp = (int32_t *)(ri->ri_bits + row * ri->ri_yscale);
925 		delta = ri->ri_delta;
926 	}
927 
928 	while (num--) {
929 		for (cnt = np; cnt; cnt--) {
930 			dp[0] = clr;
931 			dp[1] = clr;
932 			dp[2] = clr;
933 			dp[3] = clr;
934 			dp[4] = clr;
935 			dp[5] = clr;
936 			dp[6] = clr;
937 			dp[7] = clr;
938 			dp += 8;
939 		}
940 
941 		for (cnt = nw; cnt; cnt--) {
942 			*(int32_t *)dp = clr;
943 			DELTA(dp, 4, int32_t *);
944 		}
945 
946 		DELTA(dp, delta, int32_t *);
947 	}
948 
949 	return 0;
950 }
951 
952 /*
953  * Actually turn the cursor on or off. This does the dirty work for
954  * rasops_cursor().
955  */
956 int
rasops_do_cursor(struct rasops_info * ri)957 rasops_do_cursor(struct rasops_info *ri)
958 {
959 	int full1, height, cnt, slop1, slop2, row, col;
960 	u_char *dp, *rp;
961 
962 #if NRASOPS_ROTATION > 0
963 	if (ri->ri_flg & RI_ROTATE_CW) {
964 		/* Rotate rows/columns */
965 		row = ri->ri_ccol;
966 		col = ri->ri_rows - ri->ri_crow - 1;
967 	} else if (ri->ri_flg & RI_ROTATE_CCW) {
968 		/* Rotate rows/columns */
969 		row = ri->ri_cols - ri->ri_ccol - 1;
970 		col = ri->ri_crow;
971 	} else
972 #endif
973 	{
974 		row = ri->ri_crow;
975 		col = ri->ri_ccol;
976 	}
977 
978 	rp = ri->ri_bits + row * ri->ri_yscale + col * ri->ri_xscale;
979 	height = ri->ri_font->fontheight;
980 	slop1 = (4 - ((long)rp & 3)) & 3;
981 
982 	if (slop1 > ri->ri_xscale)
983 		slop1 = ri->ri_xscale;
984 
985 	slop2 = (ri->ri_xscale - slop1) & 3;
986 	full1 = (ri->ri_xscale - slop1 - slop2) >> 2;
987 
988 	if ((slop1 | slop2) == 0) {
989 		/* A common case */
990 		while (height--) {
991 			dp = rp;
992 			rp += ri->ri_stride;
993 
994 			for (cnt = full1; cnt; cnt--) {
995 				*(int32_t *)dp ^= ~0;
996 				dp += 4;
997 			}
998 		}
999 	} else {
1000 		/* XXX this is stupid.. use masks instead */
1001 		while (height--) {
1002 			dp = rp;
1003 			rp += ri->ri_stride;
1004 
1005 			if (slop1 & 1)
1006 				*dp++ ^= ~0;
1007 
1008 			if (slop1 & 2) {
1009 				*(int16_t *)dp ^= ~0;
1010 				dp += 2;
1011 			}
1012 
1013 			for (cnt = full1; cnt; cnt--) {
1014 				*(int32_t *)dp ^= ~0;
1015 				dp += 4;
1016 			}
1017 
1018 			if (slop2 & 1)
1019 				*dp++ ^= ~0;
1020 
1021 			if (slop2 & 2)
1022 				*(int16_t *)dp ^= ~0;
1023 		}
1024 	}
1025 
1026 	return 0;
1027 }
1028 
1029 /*
1030  * Erase columns.
1031  */
1032 int
rasops_erasecols(void * cookie,int row,int col,int num,uint32_t attr)1033 rasops_erasecols(void *cookie, int row, int col, int num, uint32_t attr)
1034 {
1035 	int n8, height, cnt, slop1, slop2, clr;
1036 	struct rasops_info *ri;
1037 	int32_t *rp, *dp;
1038 
1039 	ri = (struct rasops_info *)cookie;
1040 
1041 #ifdef RASOPS_CLIPPING
1042 	if ((unsigned)row >= (unsigned)ri->ri_rows)
1043 		return 0;
1044 
1045 	if (col < 0) {
1046 		num += col;
1047 		col = 0;
1048 	}
1049 
1050 	if ((col + num) > ri->ri_cols)
1051 		num = ri->ri_cols - col;
1052 
1053 	if (num <= 0)
1054 		return 0;
1055 #endif
1056 
1057 	num = num * ri->ri_xscale;
1058 	rp = (int32_t *)(ri->ri_bits + row*ri->ri_yscale + col*ri->ri_xscale);
1059 	height = ri->ri_font->fontheight;
1060 	clr = ri->ri_devcmap[(attr >> 16) & 0xf];
1061 
1062 	/* Don't bother using the full loop for <= 32 pels */
1063 	if (num <= 32) {
1064 		if (((num | ri->ri_xscale) & 3) == 0) {
1065 			/* Word aligned blt */
1066 			num >>= 2;
1067 
1068 			while (height--) {
1069 				dp = rp;
1070 				DELTA(rp, ri->ri_stride, int32_t *);
1071 
1072 				for (cnt = num; cnt; cnt--)
1073 					*dp++ = clr;
1074 			}
1075 		} else if (((num | ri->ri_xscale) & 1) == 0) {
1076 			/*
1077 			 * Halfword aligned blt. This is needed so the
1078 			 * 15/16 bit ops can use this function.
1079 			 */
1080 			num >>= 1;
1081 
1082 			while (height--) {
1083 				dp = rp;
1084 				DELTA(rp, ri->ri_stride, int32_t *);
1085 
1086 				for (cnt = num; cnt; cnt--) {
1087 					*(int16_t *)dp = clr;
1088 					DELTA(dp, 2, int32_t *);
1089 				}
1090 			}
1091 		} else {
1092 			while (height--) {
1093 				dp = rp;
1094 				DELTA(rp, ri->ri_stride, int32_t *);
1095 
1096 				for (cnt = num; cnt; cnt--) {
1097 					*(u_char *)dp = clr;
1098 					DELTA(dp, 1, int32_t *);
1099 				}
1100 			}
1101 		}
1102 
1103 		return 0;
1104 	}
1105 
1106 	slop1 = (4 - ((long)rp & 3)) & 3;
1107 	slop2 = (num - slop1) & 3;
1108 	num -= slop1 + slop2;
1109 	n8 = num >> 5;
1110 	num = (num >> 2) & 7;
1111 
1112 	while (height--) {
1113 		dp = rp;
1114 		DELTA(rp, ri->ri_stride, int32_t *);
1115 
1116 		/* Align span to 4 bytes */
1117 		if (slop1 & 1) {
1118 			*(u_char *)dp = clr;
1119 			DELTA(dp, 1, int32_t *);
1120 		}
1121 
1122 		if (slop1 & 2) {
1123 			*(int16_t *)dp = clr;
1124 			DELTA(dp, 2, int32_t *);
1125 		}
1126 
1127 		/* Write 32 bytes per loop */
1128 		for (cnt = n8; cnt; cnt--) {
1129 			dp[0] = clr;
1130 			dp[1] = clr;
1131 			dp[2] = clr;
1132 			dp[3] = clr;
1133 			dp[4] = clr;
1134 			dp[5] = clr;
1135 			dp[6] = clr;
1136 			dp[7] = clr;
1137 			dp += 8;
1138 		}
1139 
1140 		/* Write 4 bytes per loop */
1141 		for (cnt = num; cnt; cnt--)
1142 			*dp++ = clr;
1143 
1144 		/* Write unaligned trailing slop */
1145 		if (slop2 & 1) {
1146 			*(u_char *)dp = clr;
1147 			DELTA(dp, 1, int32_t *);
1148 		}
1149 
1150 		if (slop2 & 2)
1151 			*(int16_t *)dp = clr;
1152 	}
1153 
1154 	return 0;
1155 }
1156 
1157 #if NRASOPS_ROTATION > 0
1158 /*
1159  * Quarter clockwise rotation routines (originally intended for the
1160  * built-in Zaurus C3x00 display in 16bpp).
1161  */
1162 
1163 void
rasops_rotate_font(int * cookie,int ccw)1164 rasops_rotate_font(int *cookie, int ccw)
1165 {
1166 	struct rotatedfont *f;
1167 	int ncookie;
1168 
1169 	SLIST_FOREACH(f, &rotatedfonts, rf_next) {
1170 		if (f->rf_cookie == *cookie) {
1171 			*cookie = f->rf_rotated;
1172 			return;
1173 		}
1174 	}
1175 
1176 	/*
1177 	 * We did not find a rotated version of this font. Ask the wsfont
1178 	 * code to compute one for us.
1179 	 */
1180 	if ((ncookie = wsfont_rotate(*cookie, ccw)) == -1)
1181 		return;
1182 
1183 	f = malloc(sizeof(struct rotatedfont), M_DEVBUF, M_WAITOK);
1184 	f->rf_cookie = *cookie;
1185 	f->rf_rotated = ncookie;
1186 	SLIST_INSERT_HEAD(&rotatedfonts, f, rf_next);
1187 
1188 	*cookie = ncookie;
1189 }
1190 
1191 void
rasops_copychar(void * cookie,int srcrow,int dstrow,int srccol,int dstcol)1192 rasops_copychar(void *cookie, int srcrow, int dstrow, int srccol, int dstcol)
1193 {
1194 	struct rasops_info *ri;
1195 	u_char *sp, *dp;
1196 	int height;
1197 	int r_srcrow, r_dstrow, r_srccol, r_dstcol;
1198 
1199 	ri = (struct rasops_info *)cookie;
1200 
1201 	r_srcrow = srccol;
1202 	r_dstrow = dstcol;
1203 	r_srccol = ri->ri_rows - srcrow - 1;
1204 	r_dstcol = ri->ri_rows - dstrow - 1;
1205 
1206 	r_srcrow *= ri->ri_yscale;
1207 	r_dstrow *= ri->ri_yscale;
1208 	height = ri->ri_font->fontheight;
1209 
1210 	sp = ri->ri_bits + r_srcrow + r_srccol * ri->ri_xscale;
1211 	dp = ri->ri_bits + r_dstrow + r_dstcol * ri->ri_xscale;
1212 
1213 #if NRASOPS_BSWAP > 0
1214 	if (ri->ri_flg & RI_BSWAP) {
1215 		while (height--) {
1216 			slow_bcopy(sp, dp, ri->ri_xscale);
1217 			dp += ri->ri_stride;
1218 			sp += ri->ri_stride;
1219 		}
1220 	} else
1221 #endif
1222 	{
1223 		while (height--) {
1224 			memmove(dp, sp, ri->ri_xscale);
1225 			dp += ri->ri_stride;
1226 			sp += ri->ri_stride;
1227 		}
1228 	}
1229 }
1230 
1231 int
rasops_putchar_rotated(void * cookie,int row,int col,u_int uc,uint32_t attr)1232 rasops_putchar_rotated(void *cookie, int row, int col, u_int uc, uint32_t attr)
1233 {
1234 	struct rasops_info *ri;
1235 	u_char *rp;
1236 	int height;
1237 	int rc;
1238 
1239 	ri = (struct rasops_info *)cookie;
1240 
1241 	if (ri->ri_flg & RI_ROTATE_CW)
1242 		row = ri->ri_rows - row - 1;
1243 	else
1244 		col = ri->ri_cols - col - 1;
1245 
1246 	/* Do rotated char sans (side)underline */
1247 	rc = ri->ri_real_ops.putchar(cookie, col, row, uc,
1248 	    attr & ~WSATTR_UNDERLINE);
1249 	if (rc != 0)
1250 		return rc;
1251 
1252 	/* Do rotated underline */
1253 	rp = ri->ri_bits + col * ri->ri_yscale + row * ri->ri_xscale;
1254 	if (ri->ri_flg & RI_ROTATE_CCW)
1255 		rp += (ri->ri_font->fontwidth - 1) * ri->ri_pelbytes;
1256 	height = ri->ri_font->fontheight;
1257 
1258 	/* XXX this assumes 16-bit color depth */
1259 	if ((attr & WSATTR_UNDERLINE) != 0) {
1260 		int16_t c = (int16_t)ri->ri_devcmap[((u_int)attr >> 24) & 0xf];
1261 
1262 		while (height--) {
1263 			*(int16_t *)rp = c;
1264 			rp += ri->ri_stride;
1265 		}
1266 	}
1267 
1268 	return 0;
1269 }
1270 
1271 int
rasops_erasecols_rotated(void * cookie,int row,int col,int num,uint32_t attr)1272 rasops_erasecols_rotated(void *cookie, int row, int col, int num, uint32_t attr)
1273 {
1274 	int i;
1275 	int rc;
1276 
1277 	for (i = col; i < col + num; i++) {
1278 		rc = rasops_putchar_rotated(cookie, row, i, ' ', attr);
1279 		if (rc != 0)
1280 			return rc;
1281 	}
1282 
1283 	return 0;
1284 }
1285 
1286 /* XXX: these could likely be optimised somewhat. */
1287 int
rasops_copyrows_rotated(void * cookie,int src,int dst,int num)1288 rasops_copyrows_rotated(void *cookie, int src, int dst, int num)
1289 {
1290 	struct rasops_info *ri = (struct rasops_info *)cookie;
1291 	int col, roff;
1292 
1293 	if (src > dst) {
1294 		for (roff = 0; roff < num; roff++)
1295 			for (col = 0; col < ri->ri_cols; col++)
1296 				rasops_copychar(cookie, src + roff, dst + roff,
1297 				    col, col);
1298 	} else {
1299 		for (roff = num - 1; roff >= 0; roff--)
1300 			for (col = 0; col < ri->ri_cols; col++)
1301 				rasops_copychar(cookie, src + roff, dst + roff,
1302 				    col, col);
1303 	}
1304 
1305 	return 0;
1306 }
1307 
1308 int
rasops_copycols_rotated(void * cookie,int row,int src,int dst,int num)1309 rasops_copycols_rotated(void *cookie, int row, int src, int dst, int num)
1310 {
1311 	int coff;
1312 
1313 	if (src > dst) {
1314 		for (coff = 0; coff < num; coff++)
1315 			rasops_copychar(cookie, row, row, src + coff,
1316 			    dst + coff);
1317 	} else {
1318 		for (coff = num - 1; coff >= 0; coff--)
1319 			rasops_copychar(cookie, row, row, src + coff,
1320 			    dst + coff);
1321 	}
1322 
1323 	return 0;
1324 }
1325 
1326 int
rasops_eraserows_rotated(void * cookie,int row,int num,uint32_t attr)1327 rasops_eraserows_rotated(void *cookie, int row, int num, uint32_t attr)
1328 {
1329 	struct rasops_info *ri;
1330 	int col, rn;
1331 	int rc;
1332 
1333 	ri = (struct rasops_info *)cookie;
1334 
1335 	for (rn = row; rn < row + num; rn++)
1336 		for (col = 0; col < ri->ri_cols; col++) {
1337 			rc = rasops_putchar_rotated(cookie, rn, col, ' ', attr);
1338 			if (rc != 0)
1339 				return rc;
1340 		}
1341 
1342 	return 0;
1343 }
1344 #endif	/* NRASOPS_ROTATION */
1345 
1346 #if NRASOPS_BSWAP > 0
1347 /*
1348  * Strictly byte-only bcopy() version, to be used with RI_BSWAP, as the
1349  * regular bcopy() may want to optimize things by doing larger-than-byte
1350  * reads or write. This may confuse things if src and dst have different
1351  * alignments.
1352  */
1353 void
slow_bcopy(void * s,void * d,size_t len)1354 slow_bcopy(void *s, void *d, size_t len)
1355 {
1356 	u_int8_t *src = s;
1357 	u_int8_t *dst = d;
1358 
1359 	if ((vaddr_t)dst <= (vaddr_t)src) {
1360 		while (len-- != 0)
1361 			*dst++ = *src++;
1362 	} else {
1363 		src += len;
1364 		dst += len;
1365 		if (len != 0)
1366 			while (--len != 0)
1367 				*--dst = *--src;
1368 	}
1369 }
1370 #endif	/* NRASOPS_BSWAP */
1371 
1372 int
rasops_alloc_screen(void * v,void ** cookiep,int * curxp,int * curyp,uint32_t * attrp)1373 rasops_alloc_screen(void *v, void **cookiep,
1374     int *curxp, int *curyp, uint32_t *attrp)
1375 {
1376 	struct rasops_info *ri = v;
1377 	struct rasops_screen *scr;
1378 	int i;
1379 
1380 	scr = malloc(sizeof(*scr), M_DEVBUF, M_NOWAIT);
1381 	if (scr == NULL)
1382 		return (ENOMEM);
1383 
1384 	scr->rs_sbscreens = RS_SCROLLBACK_SCREENS;
1385 	scr->rs_bs = mallocarray(ri->ri_rows * (scr->rs_sbscreens + 1),
1386 	    ri->ri_cols * sizeof(struct wsdisplay_charcell), M_DEVBUF,
1387 	    M_NOWAIT);
1388 	if (scr->rs_bs == NULL) {
1389 		free(scr, M_DEVBUF, sizeof(*scr));
1390 		return (ENOMEM);
1391 	}
1392 	scr->rs_visibleoffset = scr->rs_dispoffset = ri->ri_rows *
1393 	    scr->rs_sbscreens * ri->ri_cols;
1394 
1395 	*cookiep = scr;
1396 	*curxp = 0;
1397 	*curyp = 0;
1398 	ri->ri_pack_attr(ri, 0, 0, 0, attrp);
1399 
1400 	scr->rs_ri = ri;
1401 	scr->rs_visible = (ri->ri_nscreens == 0);
1402 	scr->rs_crow = -1;
1403 	scr->rs_ccol = -1;
1404 	scr->rs_defattr = *attrp;
1405 
1406 	for (i = 0; i < scr->rs_dispoffset; i++) {
1407 		scr->rs_bs[i].uc = ' ';
1408 		scr->rs_bs[i].attr = scr->rs_defattr;
1409 	}
1410 
1411 	if (ri->ri_bs && scr->rs_visible) {
1412 		memcpy(scr->rs_bs + scr->rs_dispoffset, ri->ri_bs,
1413 		    ri->ri_rows * ri->ri_cols *
1414 		    sizeof(struct wsdisplay_charcell));
1415 	} else {
1416 		for (i = 0; i < ri->ri_rows * ri->ri_cols; i++) {
1417 			scr->rs_bs[scr->rs_dispoffset + i].uc = ' ';
1418 			scr->rs_bs[scr->rs_dispoffset + i].attr =
1419 			    scr->rs_defattr;
1420 		}
1421 	}
1422 
1423 	LIST_INSERT_HEAD(&ri->ri_screens, scr, rs_next);
1424 	ri->ri_nscreens++;
1425 
1426 	return (0);
1427 }
1428 
1429 void
rasops_free_screen(void * v,void * cookie)1430 rasops_free_screen(void *v, void *cookie)
1431 {
1432 	struct rasops_info *ri = v;
1433 	struct rasops_screen *scr = cookie;
1434 
1435 	LIST_REMOVE(scr, rs_next);
1436 	ri->ri_nscreens--;
1437 
1438 	free(scr->rs_bs, M_DEVBUF,
1439 	    ri->ri_rows * (scr->rs_sbscreens + 1) * ri->ri_cols *
1440 	    sizeof(struct wsdisplay_charcell));
1441 	free(scr, M_DEVBUF, sizeof(*scr));
1442 }
1443 
1444 int
rasops_show_screen(void * v,void * cookie,int waitok,void (* cb)(void *,int,int),void * cbarg)1445 rasops_show_screen(void *v, void *cookie, int waitok,
1446     void (*cb)(void *, int, int), void *cbarg)
1447 {
1448 	struct rasops_info *ri = v;
1449 
1450 	ri->ri_switchcookie = cookie;
1451 	if (cb) {
1452 		ri->ri_switchcb = cb;
1453 		ri->ri_switchcbarg = cbarg;
1454 		task_add(systq, &ri->ri_switchtask);
1455 		return (EAGAIN);
1456 	}
1457 
1458 	rasops_doswitch(ri);
1459 	return (0);
1460 }
1461 
1462 void
rasops_doswitch(void * v)1463 rasops_doswitch(void *v)
1464 {
1465 	struct rasops_info *ri = v;
1466 	struct rasops_screen *scr = ri->ri_switchcookie;
1467 	int row, col;
1468 
1469 	rasops_cursor(ri, 0, 0, 0);
1470 	ri->ri_active->rs_visible = 0;
1471 	ri->ri_eraserows(ri, 0, ri->ri_rows, scr->rs_defattr);
1472 	ri->ri_active = scr;
1473 	ri->ri_bs = &ri->ri_active->rs_bs[ri->ri_active->rs_dispoffset];
1474 	ri->ri_active->rs_visible = 1;
1475 	ri->ri_active->rs_visibleoffset = ri->ri_active->rs_dispoffset;
1476 	for (row = 0; row < ri->ri_rows; row++) {
1477 		for (col = 0; col < ri->ri_cols; col++) {
1478 			int off = row * scr->rs_ri->ri_cols + col +
1479 			    scr->rs_visibleoffset;
1480 
1481 			ri->ri_putchar(ri, row, col, scr->rs_bs[off].uc,
1482 			    scr->rs_bs[off].attr);
1483 		}
1484 	}
1485 	if (scr->rs_crow != -1)
1486 		rasops_cursor(ri, 1, scr->rs_crow, scr->rs_ccol);
1487 
1488 	if (ri->ri_switchcb)
1489 		(*ri->ri_switchcb)(ri->ri_switchcbarg, 0, 0);
1490 }
1491 
1492 int
rasops_getchar(void * v,int row,int col,struct wsdisplay_charcell * cell)1493 rasops_getchar(void *v, int row, int col, struct wsdisplay_charcell *cell)
1494 {
1495 	struct rasops_info *ri = v;
1496 	struct rasops_screen *scr = ri->ri_active;
1497 
1498 	if (scr == NULL || scr->rs_bs == NULL)
1499 		return (1);
1500 
1501 	*cell = scr->rs_bs[row * ri->ri_cols + col + scr->rs_dispoffset];
1502 	return (0);
1503 }
1504 
1505 int
rasops_vcons_cursor(void * cookie,int on,int row,int col)1506 rasops_vcons_cursor(void *cookie, int on, int row, int col)
1507 {
1508 	struct rasops_screen *scr = cookie;
1509 
1510 	scr->rs_crow = on ? row : -1;
1511 	scr->rs_ccol = on ? col : -1;
1512 
1513 	if (!scr->rs_visible)
1514 		return 0;
1515 
1516 	return rasops_cursor(scr->rs_ri, on, row, col);
1517 }
1518 
1519 int
rasops_vcons_mapchar(void * cookie,int c,u_int * cp)1520 rasops_vcons_mapchar(void *cookie, int c, u_int *cp)
1521 {
1522 	struct rasops_screen *scr = cookie;
1523 
1524 	return rasops_mapchar(scr->rs_ri, c, cp);
1525 }
1526 
1527 int
rasops_vcons_putchar(void * cookie,int row,int col,u_int uc,uint32_t attr)1528 rasops_vcons_putchar(void *cookie, int row, int col, u_int uc, uint32_t attr)
1529 {
1530 	struct rasops_screen *scr = cookie;
1531 	int off = row * scr->rs_ri->ri_cols + col + scr->rs_dispoffset;
1532 
1533 	if (scr->rs_visible && scr->rs_visibleoffset != scr->rs_dispoffset)
1534 		rasops_scrollback(scr->rs_ri, scr, 0);
1535 
1536 	scr->rs_bs[off].uc = uc;
1537 	scr->rs_bs[off].attr = attr;
1538 
1539 	if (!scr->rs_visible)
1540 		return 0;
1541 
1542 	return scr->rs_ri->ri_putchar(scr->rs_ri, row, col, uc, attr);
1543 }
1544 
1545 int
rasops_vcons_copycols(void * cookie,int row,int src,int dst,int num)1546 rasops_vcons_copycols(void *cookie, int row, int src, int dst, int num)
1547 {
1548 	struct rasops_screen *scr = cookie;
1549 	struct rasops_info *ri = scr->rs_ri;
1550 	int cols = scr->rs_ri->ri_cols;
1551 	int col, rc;
1552 
1553 	memmove(&scr->rs_bs[row * cols + dst + scr->rs_dispoffset],
1554 	    &scr->rs_bs[row * cols + src + scr->rs_dispoffset],
1555 	    num * sizeof(struct wsdisplay_charcell));
1556 
1557 	if (!scr->rs_visible)
1558 		return 0;
1559 
1560 	if ((ri->ri_flg & RI_WRONLY) == 0)
1561 		return ri->ri_copycols(ri, row, src, dst, num);
1562 
1563 	for (col = dst; col < dst + num; col++) {
1564 		int off = row * cols + col + scr->rs_dispoffset;
1565 
1566 		rc = ri->ri_putchar(ri, row, col,
1567 		    scr->rs_bs[off].uc, scr->rs_bs[off].attr);
1568 		if (rc != 0)
1569 			return rc;
1570 	}
1571 
1572 	return 0;
1573 }
1574 
1575 int
rasops_vcons_erasecols(void * cookie,int row,int col,int num,uint32_t attr)1576 rasops_vcons_erasecols(void *cookie, int row, int col, int num, uint32_t attr)
1577 {
1578 	struct rasops_screen *scr = cookie;
1579 	int cols = scr->rs_ri->ri_cols;
1580 	int i;
1581 
1582 	for (i = 0; i < num; i++) {
1583 		int off = row * cols + col + i + scr->rs_dispoffset;
1584 
1585 		scr->rs_bs[off].uc = ' ';
1586 		scr->rs_bs[off].attr = attr;
1587 	}
1588 
1589 	if (!scr->rs_visible)
1590 		return 0;
1591 
1592 	return scr->rs_ri->ri_erasecols(scr->rs_ri, row, col, num, attr);
1593 }
1594 
1595 int
rasops_vcons_copyrows(void * cookie,int src,int dst,int num)1596 rasops_vcons_copyrows(void *cookie, int src, int dst, int num)
1597 {
1598 	struct rasops_screen *scr = cookie;
1599 	struct rasops_info *ri = scr->rs_ri;
1600 	int cols = ri->ri_cols;
1601 	int row, col, rc;
1602 	int srcofs;
1603 	int move;
1604 
1605 	/* update the scrollback buffer if the entire screen is moving */
1606 	if (dst == 0 && (src + num == ri->ri_rows) && scr->rs_sbscreens > 0)
1607 		memmove(&scr->rs_bs[dst], &scr->rs_bs[src * cols],
1608 		    ri->ri_rows * scr->rs_sbscreens * cols
1609 		    * sizeof(struct wsdisplay_charcell));
1610 
1611 	/* copy everything */
1612 	if ((ri->ri_flg & RI_WRONLY) == 0 || !scr->rs_visible) {
1613 		memmove(&scr->rs_bs[dst * cols + scr->rs_dispoffset],
1614 		    &scr->rs_bs[src * cols + scr->rs_dispoffset],
1615 		    num * cols * sizeof(struct wsdisplay_charcell));
1616 
1617 		if (!scr->rs_visible)
1618 			return 0;
1619 
1620 		return ri->ri_copyrows(ri, src, dst, num);
1621 	}
1622 
1623 	/* smart update, only redraw characters that are different */
1624 	srcofs = (src - dst) * cols;
1625 
1626 	for (move = 0; move < num; move++) {
1627 		row = srcofs > 0 ? dst + move : dst + num - 1 - move;
1628 		for (col = 0; col < cols; col++) {
1629 			int off = row * cols + col + scr->rs_dispoffset;
1630 			int newc = scr->rs_bs[off+srcofs].uc;
1631 			int newa = scr->rs_bs[off+srcofs].attr;
1632 
1633 			if (scr->rs_bs[off].uc == newc &&
1634 			    scr->rs_bs[off].attr == newa)
1635 				continue;
1636 			scr->rs_bs[off].uc = newc;
1637 			scr->rs_bs[off].attr = newa;
1638 			rc = ri->ri_putchar(ri, row, col, newc, newa);
1639 			if (rc != 0)
1640 				return rc;
1641 		}
1642 	}
1643 
1644 	return 0;
1645 }
1646 
1647 int
rasops_vcons_eraserows(void * cookie,int row,int num,uint32_t attr)1648 rasops_vcons_eraserows(void *cookie, int row, int num, uint32_t attr)
1649 {
1650 	struct rasops_screen *scr = cookie;
1651 	int cols = scr->rs_ri->ri_cols;
1652 	int i;
1653 
1654 	for (i = 0; i < num * cols; i++) {
1655 		int off = row * cols + i + scr->rs_dispoffset;
1656 
1657 		scr->rs_bs[off].uc = ' ';
1658 		scr->rs_bs[off].attr = attr;
1659 	}
1660 
1661 	if (!scr->rs_visible)
1662 		return 0;
1663 
1664 	return scr->rs_ri->ri_eraserows(scr->rs_ri, row, num, attr);
1665 }
1666 
1667 int
rasops_vcons_pack_attr(void * cookie,int fg,int bg,int flg,uint32_t * attr)1668 rasops_vcons_pack_attr(void *cookie, int fg, int bg, int flg, uint32_t *attr)
1669 {
1670 	struct rasops_screen *scr = cookie;
1671 
1672 	return scr->rs_ri->ri_pack_attr(scr->rs_ri, fg, bg, flg, attr);
1673 }
1674 
1675 void
rasops_vcons_unpack_attr(void * cookie,uint32_t attr,int * fg,int * bg,int * underline)1676 rasops_vcons_unpack_attr(void *cookie, uint32_t attr, int *fg, int *bg,
1677     int *underline)
1678 {
1679 	struct rasops_screen *scr = cookie;
1680 
1681 	rasops_unpack_attr(scr->rs_ri, attr, fg, bg, underline);
1682 }
1683 
1684 int
rasops_wronly_putchar(void * cookie,int row,int col,u_int uc,uint32_t attr)1685 rasops_wronly_putchar(void *cookie, int row, int col, u_int uc, uint32_t attr)
1686 {
1687 	struct rasops_info *ri = cookie;
1688 	int off = row * ri->ri_cols + col;
1689 
1690 	ri->ri_bs[off].uc = uc;
1691 	ri->ri_bs[off].attr = attr;
1692 
1693 	return ri->ri_putchar(ri, row, col, uc, attr);
1694 }
1695 
1696 int
rasops_wronly_copycols(void * cookie,int row,int src,int dst,int num)1697 rasops_wronly_copycols(void *cookie, int row, int src, int dst, int num)
1698 {
1699 	struct rasops_info *ri = cookie;
1700 	int cols = ri->ri_cols;
1701 	int col, rc;
1702 
1703 	memmove(&ri->ri_bs[row * cols + dst], &ri->ri_bs[row * cols + src],
1704 	    num * sizeof(struct wsdisplay_charcell));
1705 
1706 	for (col = dst; col < dst + num; col++) {
1707 		int off = row * cols + col;
1708 
1709 		rc = ri->ri_putchar(ri, row, col,
1710 		    ri->ri_bs[off].uc, ri->ri_bs[off].attr);
1711 		if (rc != 0)
1712 			return rc;
1713 	}
1714 
1715 	return 0;
1716 }
1717 
1718 int
rasops_wronly_erasecols(void * cookie,int row,int col,int num,uint32_t attr)1719 rasops_wronly_erasecols(void *cookie, int row, int col, int num, uint32_t attr)
1720 {
1721 	struct rasops_info *ri = cookie;
1722 	int cols = ri->ri_cols;
1723 	int i;
1724 
1725 	for (i = 0; i < num; i++) {
1726 		int off = row * cols + col + i;
1727 
1728 		ri->ri_bs[off].uc = ' ';
1729 		ri->ri_bs[off].attr = attr;
1730 	}
1731 
1732 	return ri->ri_erasecols(ri, row, col, num, attr);
1733 }
1734 
1735 int
rasops_wronly_copyrows(void * cookie,int src,int dst,int num)1736 rasops_wronly_copyrows(void *cookie, int src, int dst, int num)
1737 {
1738 	struct rasops_info *ri = cookie;
1739 	int cols = ri->ri_cols;
1740 	int row, col, rc;
1741 
1742 	memmove(&ri->ri_bs[dst * cols], &ri->ri_bs[src * cols],
1743 	    num * cols * sizeof(struct wsdisplay_charcell));
1744 
1745 	for (row = dst; row < dst + num; row++) {
1746 		for (col = 0; col < cols; col++) {
1747 			int off = row * cols + col;
1748 
1749 			rc = ri->ri_putchar(ri, row, col,
1750 			    ri->ri_bs[off].uc, ri->ri_bs[off].attr);
1751 			if (rc != 0)
1752 				return rc;
1753 		}
1754 	}
1755 
1756 	return 0;
1757 }
1758 
1759 int
rasops_wronly_eraserows(void * cookie,int row,int num,uint32_t attr)1760 rasops_wronly_eraserows(void *cookie, int row, int num, uint32_t attr)
1761 {
1762 	struct rasops_info *ri = cookie;
1763 	int cols = ri->ri_cols;
1764 	int i;
1765 
1766 	for (i = 0; i < num * cols; i++) {
1767 		int off = row * cols + i;
1768 
1769 		ri->ri_bs[off].uc = ' ';
1770 		ri->ri_bs[off].attr = attr;
1771 	}
1772 
1773 	return ri->ri_eraserows(ri, row, num, attr);
1774 }
1775 
1776 int
rasops_wronly_do_cursor(struct rasops_info * ri)1777 rasops_wronly_do_cursor(struct rasops_info *ri)
1778 {
1779 	int off = ri->ri_crow * ri->ri_cols + ri->ri_ccol;
1780 	u_int uc;
1781 	uint32_t attr;
1782 	int fg, bg;
1783 
1784 	uc = ri->ri_bs[off].uc;
1785 	attr = ri->ri_bs[off].attr;
1786 
1787 	if ((ri->ri_flg & RI_CURSOR) == 0) {
1788 		fg = ((u_int)attr >> 24) & 0xf;
1789 		bg = ((u_int)attr >> 16) & 0xf;
1790 		attr &= ~0x0ffff0000;
1791 		attr |= (fg << 16) | (bg << 24);
1792 	}
1793 
1794 	return ri->ri_putchar(ri, ri->ri_crow, ri->ri_ccol, uc, attr);
1795 }
1796 
1797 /*
1798  * Font management.
1799  *
1800  * Fonts usable on raster frame buffers are managed by wsfont, and are not
1801  * tied to any particular display.
1802  */
1803 
1804 int
rasops_add_font(struct rasops_info * ri,struct wsdisplay_font * font)1805 rasops_add_font(struct rasops_info *ri, struct wsdisplay_font *font)
1806 {
1807 	/* only accept matching metrics */
1808 	if (font->fontwidth != ri->ri_font->fontwidth ||
1809 	    font->fontheight != ri->ri_font->fontheight)
1810 		return EINVAL;
1811 
1812 	/* for raster consoles, only accept ISO Latin-1 or Unicode encoding */
1813 	if (font->encoding != WSDISPLAY_FONTENC_ISO)
1814 		return EINVAL;
1815 
1816 	if (wsfont_add(font, 1) != 0)
1817 		return EEXIST;	/* name collision */
1818 
1819 	font->index = -1;	/* do not store in wsdisplay_softc */
1820 
1821 	return 0;
1822 }
1823 
1824 int
rasops_use_font(struct rasops_info * ri,struct wsdisplay_font * font)1825 rasops_use_font(struct rasops_info *ri, struct wsdisplay_font *font)
1826 {
1827 	int wsfcookie;
1828 	struct wsdisplay_font *wsf;
1829 	const char *name;
1830 
1831 	/* allow an empty font name to revert to the initial font choice */
1832 	name = font->name;
1833 	if (*name == '\0')
1834 		name = NULL;
1835 
1836 	wsfcookie = wsfont_find(name, ri->ri_font->fontwidth,
1837 	    ri->ri_font->fontheight, 0);
1838 	if (wsfcookie < 0) {
1839 		wsfcookie = wsfont_find(name, 0, 0, 0);
1840 		if (wsfcookie < 0)
1841 			return ENOENT;	/* font exist, but different metrics */
1842 		else
1843 			return EINVAL;
1844 	}
1845 	if (wsfont_lock(wsfcookie, &wsf, WSDISPLAY_FONTORDER_KNOWN,
1846 	    WSDISPLAY_FONTORDER_KNOWN) < 0)
1847 		return EINVAL;
1848 
1849 	wsfont_unlock(ri->ri_wsfcookie);
1850 	ri->ri_wsfcookie = wsfcookie;
1851 	ri->ri_font = wsf;
1852 	ri->ri_fontscale = ri->ri_font->fontheight * ri->ri_font->stride;
1853 
1854 	return 0;
1855 }
1856 
1857 int
rasops_load_font(void * v,void * cookie,struct wsdisplay_font * font)1858 rasops_load_font(void *v, void *cookie, struct wsdisplay_font *font)
1859 {
1860 	struct rasops_info *ri = v;
1861 
1862 	/*
1863 	 * For now, we want to only allow loading fonts of the same
1864 	 * metrics as the currently in-use font. This requires the
1865 	 * rasops struct to have been correctly configured, and a
1866 	 * font to have been selected.
1867 	 */
1868 	if ((ri->ri_flg & RI_CFGDONE) == 0 || ri->ri_font == NULL)
1869 		return EINVAL;
1870 
1871 	if (font->data != NULL)
1872 		return rasops_add_font(ri, font);
1873 	else
1874 		return rasops_use_font(ri, font);
1875 }
1876 
1877 struct rasops_list_font_ctx {
1878 	struct rasops_info *ri;
1879 	int cnt;
1880 	struct wsdisplay_font *font;
1881 };
1882 
1883 int
rasops_list_font_cb(void * cbarg,struct wsdisplay_font * font)1884 rasops_list_font_cb(void *cbarg, struct wsdisplay_font *font)
1885 {
1886 	struct rasops_list_font_ctx *ctx = cbarg;
1887 
1888 	if (ctx->cnt-- == 0) {
1889 		ctx->font = font;
1890 		return 1;
1891 	}
1892 
1893 	return 0;
1894 }
1895 
1896 int
rasops_list_font(void * v,struct wsdisplay_font * font)1897 rasops_list_font(void *v, struct wsdisplay_font *font)
1898 {
1899 	struct rasops_info *ri = v;
1900 	struct rasops_list_font_ctx ctx;
1901 	int idx;
1902 
1903 	if ((ri->ri_flg & RI_CFGDONE) == 0 || ri->ri_font == NULL)
1904 		return EINVAL;
1905 
1906 	if (font->index < 0)
1907 		return EINVAL;
1908 
1909 	ctx.ri = ri;
1910 	ctx.cnt = font->index;
1911 	ctx.font = NULL;
1912 	wsfont_enum(rasops_list_font_cb, &ctx);
1913 
1914 	if (ctx.font == NULL)
1915 		return EINVAL;
1916 
1917 	idx = font->index;
1918 	*font = *ctx.font;	/* struct copy */
1919 	font->index = idx;
1920 	font->cookie = font->data = NULL;	/* don't leak kernel pointers */
1921 	return 0;
1922 }
1923 
1924 void
rasops_scrollback(void * v,void * cookie,int lines)1925 rasops_scrollback(void *v, void *cookie, int lines)
1926 {
1927 	struct rasops_info *ri = v;
1928 	struct rasops_screen *scr = cookie;
1929 	int row, col, oldvoff;
1930 
1931 	oldvoff = scr->rs_visibleoffset;
1932 
1933 	if (lines == 0)
1934 		scr->rs_visibleoffset = scr->rs_dispoffset;
1935 	else {
1936 		int off = scr->rs_visibleoffset + (lines * ri->ri_cols);
1937 
1938 		if (off < 0)
1939 			off = 0;
1940 		else if (off > scr->rs_dispoffset)
1941 			off = scr->rs_dispoffset;
1942 
1943 		scr->rs_visibleoffset = off;
1944 	}
1945 
1946 	if (scr->rs_visibleoffset == oldvoff)
1947 		return;
1948 
1949 	rasops_cursor(ri, 0, 0, 0);
1950 	ri->ri_eraserows(ri, 0, ri->ri_rows, scr->rs_defattr);
1951 	for (row = 0; row < ri->ri_rows; row++) {
1952 		for (col = 0; col < ri->ri_cols; col++) {
1953 			int off = row * scr->rs_ri->ri_cols + col +
1954 			    scr->rs_visibleoffset;
1955 
1956 			ri->ri_putchar(ri, row, col, scr->rs_bs[off].uc,
1957 			    scr->rs_bs[off].attr);
1958 		}
1959 	}
1960 
1961 	if (scr->rs_crow != -1 && scr->rs_visibleoffset == scr->rs_dispoffset)
1962 		rasops_cursor(ri, 1, scr->rs_crow, scr->rs_ccol);
1963 }
1964 
1965 struct rasops_framebuffer {
1966 	SLIST_ENTRY(rasops_framebuffer)	rf_list;
1967 	paddr_t		rf_base;
1968 	psize_t		rf_size;
1969 	struct device	*rf_dev;
1970 };
1971 
1972 SLIST_HEAD(, rasops_framebuffer) rasops_framebuffers =
1973     SLIST_HEAD_INITIALIZER(&rasops_framebuffers);
1974 
1975 void
rasops_claim_framebuffer(paddr_t base,psize_t size,struct device * dev)1976 rasops_claim_framebuffer(paddr_t base, psize_t size, struct device *dev)
1977 {
1978 	struct rasops_framebuffer *rf;
1979 
1980 	rf = malloc(sizeof(*rf), M_DEVBUF, M_WAITOK);
1981 	rf->rf_base = base;
1982 	rf->rf_size = size;
1983 	rf->rf_dev = dev;
1984 
1985 	SLIST_INSERT_HEAD(&rasops_framebuffers, rf, rf_list);
1986 }
1987 
1988 int
rasops_check_framebuffer(paddr_t base)1989 rasops_check_framebuffer(paddr_t base)
1990 {
1991 	struct rasops_framebuffer *rf;
1992 
1993 	SLIST_FOREACH(rf, &rasops_framebuffers, rf_list) {
1994 		if (base >= rf->rf_base && base < rf->rf_base + rf->rf_size)
1995 			return 1;
1996 	}
1997 
1998 	return 0;
1999 }
2000